KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > filesystems > XMLMapAttr


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.openide.filesystems;
20
21 import org.openide.util.SharedClassObject;
22 import org.openide.util.Utilities;
23 import org.openide.util.io.NbMarshalledObject;
24 import org.openide.util.io.NbObjectInputStream;
25
26 import java.io.*;
27
28 import java.lang.reflect.*;
29
30 import java.net.URL JavaDoc;
31
32 import java.util.*;
33 import org.openide.util.Exceptions;
34
35
36 /**
37  *Holds in Map attributes: Map(String attrName,XMLMapAttr.Attr attribute). This map holds all atributes for one FileObject.
38  *<BR><BR>
39  *<H3>Detailed description</H3>
40  * Each file object (file or folder element) can have 0..* attributes.<BR> <BR>
41  * Each file object <I>atrribute</I> (attribute is here name of element) must have two attributes (here XML attribute).<BR>
42  * <OL>
43  * <LI>First attribute name is <I>id</I> , which is mandatory and value of this
44  * attribute serve as identifier to distinguish many attributes for one file object.
45  * Name of attribute can contain prefix <code>transient:</code>. Transient means that such
46  * marked attribute won`t be copied together with FileObject. Be aware that for:
47  * fo.setAttribute("transient:foo", "bar") is true that fo.getAttribute("foo").equals("bar")
48  * <LI> Second attribute is also mandatory, but you can choose such attribute name and
49  * attribute value, which correspond to desirable data type
50  * (e.g. <I>stringValue</I>, <I>boolValue</I> etc.).
51  * </OL>
52  * Desirable data type can be one of primitive data types or object data types.
53  * <BR>
54  * <BR>
55  * Moreover value of attribute can be passed:
56  * <OL>
57  * <LI><I>statically</I> - means that you would be able to use literal of primitive data types (e.g. <I>stringvalue</I>="This is a literal",<I>boolvalue</I>="true" etc.).
58  * If you want statically create instance of object data type you can use <I>serialValue</I>, which value is serialized byte stream (e.g.: <I>serialvalue</I>="092A54....").
59  * This should ensure back compatibility.
60  * <LI><I>dynamically</I> -means that instead of constant value (literal), you pass name of class including name of method, which will be used for dynamic creation of desirable object
61  * (e.g.: <I>methodvalue</I>="org.openide.mypackage.MyClass.myMethod"). For dynamic creation of primitive data types could be used methods that return wrapper objects.
62  * Implemetation of interface Attr will pass to method <I>myMethod</I> two parameters FileObject (file object which maintain this atrribute) and String (name of this attribute).
63  * So here is sugestion of declaration of such method: <I>public static Object myMethod(FileObject myFo,String myName)</I>.
64  *
65  * <A NAME="primitive"><H4>Primitive data types</H4>
66  * </A>
67  * Here is sugested list of attribute names for primitive data types
68  * (I expect that from the name is obvious which type of value is expected):
69  * <OL>
70  * <I>
71  * <LI> bytevalue
72  * <LI> shortvalue
73  * <LI> intvalue
74  * <LI> longvalue
75  * <LI> floatvalue
76  * <LI> doublevalue
77  * <LI> boolvalue
78  * <LI> charvalue
79  * </I>
80  * </OL>
81  * <BR><BR>
82  *<A NAME="object"><H4>Object data types</H4></A>
83  * <OL>
84  * <LI> <I>methodvalue</I> - dynamic creation (for primitive data could be returned wrapper objects)
85   <LI> <I>newvalue</I> - newInstance is called
86  * <LI> <I>serialValue</I> - static creation
87  *
88  * </OL>
89   <BR><BR>
90  * Attributes are stored in xml file, then there must be used encoding for not permitted
91  * chars. There are used Java-style <code>&#92;uXXXX</code> Unicode escapes for ISO control characters and
92  * minimal set of character entities <code>&lt;</code>, <code>&amp;</code>, <code>'</code>
93  * and <code>"</code>.
94  *
95  * @author rmatous
96  */

97 @SuppressWarnings JavaDoc("unchecked")
98 final class XMLMapAttr implements Map {
99     Map/*<String,Attr>*/ map;
100
101     /** Creates new XMLMapAttr and delegetaor is instanced */
102     public XMLMapAttr() {
103         this.map = new HashMap(5);
104     }
105
106     static Attr createAttributeAndDecode(String JavaDoc key, String JavaDoc value) {
107         if (Attr.isValid(key) == Attr.isValid("stringvalue")) { // NOI18N
108
value = Attr.decode(value);
109         }
110
111         return new Attr(key, value);
112     }
113
114     static Attr createAttribute(int index, String JavaDoc value) {
115         return new Attr(index, value);
116     }
117
118     /** According to name of attribute returns attribute as object
119     * @param p1 is name of attribute
120     * @return attribute, which is hold in XMLMapAttr.Attr or null if such attribute doesn`t exist or isn`t able to construct form String representation
121     */

122     public Object JavaDoc get(final Object JavaDoc p1) {
123         Object JavaDoc obj;
124
125         try {
126             obj = getAttribute(p1);
127         } catch (Exception JavaDoc e) {
128             obj = null;
129             ExternalUtil.exception(e);
130         }
131
132         return obj;
133     }
134
135     /** According to name of attribute returns attribute as object
136      * @param params has sense only for methodvalue invocation; and only 2 parametres will be used
137      * @return attribute, which is hold in XMLMapAttr.Attr or null if such attribute doesn`t exist or isn`t able to construct form String representation
138      */

139     public Object JavaDoc get(final Object JavaDoc p1, Object JavaDoc[] params) {
140         Object JavaDoc obj;
141
142         try {
143             obj = getAttribute(p1, params);
144         } catch (Exception JavaDoc e) {
145             obj = null;
146             ExternalUtil.exception(e);
147         }
148
149         return obj;
150     }
151
152     /** implementation of Map.get. But fires Exception to have chance in
153      * DefaultAttributes to catch and annotate*/

154     Object JavaDoc getAttribute(Object JavaDoc attrName) throws Exception JavaDoc {
155         return getAttribute(attrName, null);
156     }
157
158     private Object JavaDoc getAttribute(Object JavaDoc attrName, Object JavaDoc[] params)
159     throws Exception JavaDoc {
160         Attr attr;
161         String JavaDoc origAttrName = (String JavaDoc) attrName;
162         Object JavaDoc[] keyValuePair = ModifiedAttribute.translateInto((String JavaDoc) attrName, null);
163         attrName = (String JavaDoc) keyValuePair[0];
164
165         synchronized (this) {
166             attr = (Attr) map.get(attrName);
167         }
168
169         Object JavaDoc retVal = null;
170
171         try {
172             retVal = (attr == null) ? attr : attr.get(params);
173         } catch (Exception JavaDoc e) {
174             ExternalUtil.annotate(e, "attrName = " + attrName); //NOI18N
175
throw e;
176         }
177
178         if (retVal instanceof ModifiedAttribute) {
179             Object JavaDoc res = ((ModifiedAttribute) retVal).getValue(origAttrName);
180
181             if (res instanceof Attr) {
182                 return ((Attr) res).get(params);
183             } else {
184                 return res;
185             }
186         }
187
188         return retVal;
189     }
190
191     /**
192      * @param p1 is name of attribute
193      * @param p2 is attribute as object
194      * @return previous value associated with specified key, or null if there was no mapping for key.
195      * A null return can also indicate that the HashMap previously associated null with the specified key.
196      */

197     public synchronized Object JavaDoc put(final Object JavaDoc p1, final Object JavaDoc p2) {
198         return put(p1, p2, true);
199     }
200
201     synchronized Object JavaDoc put(final Object JavaDoc p1, final Object JavaDoc p2, boolean decode) {
202         if ((p1 == null) || !(p1 instanceof String JavaDoc)) {
203             return null;
204         }
205
206         Object JavaDoc[] keyValuePair = ModifiedAttribute.translateInto((String JavaDoc) p1, p2);
207         String JavaDoc key = (String JavaDoc) keyValuePair[0];
208         Object JavaDoc value = keyValuePair[1];
209         Object JavaDoc toStore = ((value == null) || value instanceof Attr) ? value : new Attr(value);
210
211         if (decode) {
212             key = Attr.decode(key).intern();
213         }
214
215         return map.put(key, toStore);
216     }
217
218     /**
219      * Writes heading to XML file
220      * @param pw where to write
221      */

222     public static void writeHeading(PrintWriter pw) {
223         pw.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); // NOI18N
224
pw.println(
225             "<!DOCTYPE attributes PUBLIC \"-//NetBeans//DTD DefaultAttributes 1.0//EN\" \"http://www.netbeans.org/dtds/attributes-1_0.dtd\">"
226         ); //NOI18N
227
pw.println("<attributes version=\"1.0\">"); // NOI18N
228
}
229
230     /**
231      * Writes ending to XML file
232      * @param pw where to write
233      */

234     public static void writeEnding(PrintWriter pw) {
235         pw.println("</attributes>"); // NOI18N
236
}
237
238     /**
239      * Writes all attributes for one FileObject with fileName
240      * @param pw where to write
241      * @param fileName
242      * @param blockPrefix is prefix which is used before each line
243      */

244     public synchronized void write(PrintWriter pw, final String JavaDoc fileName, String JavaDoc blockPrefix) {
245         boolean isHeadingWr = false;
246
247         if (isEmpty()) {
248             return;
249         }
250
251         //pw.println(blockPrefix+"<fileobject name=\""+fileName+"\">");// NOI18N
252
SortedSet<String JavaDoc> attrNames = new TreeSet<String JavaDoc>();
253         Iterator entryIter = map.entrySet().iterator();
254
255         while (entryIter.hasNext()) {
256             Map.Entry entry = (Map.Entry) entryIter.next();
257
258             String JavaDoc attrName = (String JavaDoc) entry.getKey();
259             Attr attr = (Attr) entry.getValue();
260
261             if ((attrName == null) || (attr == null) || (attrName.length() == 0) || (attr.isValid() == -1)) {
262                 if ((attrName != null) && (attrName.length() != 0) && ((attr == null) || (attr.isValid() == -1))) {
263                     entryIter.remove();
264                 }
265
266                 continue;
267             }
268
269             attrNames.add(attrName);
270         }
271
272         entryIter = attrNames.iterator();
273
274         while (entryIter.hasNext()) {
275             String JavaDoc attrName = (String JavaDoc) entryIter.next();
276             Attr attr = (Attr) map.get(attrName);
277
278             if (attr != null) {
279                 attr.transformMe();
280             }
281
282             if (!isHeadingWr) {
283                 isHeadingWr = true;
284
285                 String JavaDoc quotedFileName = fileName;
286
287                 try {
288                     quotedFileName = org.openide.xml.XMLUtil.toAttributeValue(fileName);
289                 } catch (IOException ignore) {
290                 }
291
292                 pw.println(blockPrefix + "<fileobject name=\"" + quotedFileName + "\">"); // NOI18N
293
}
294
295             pw.println(
296                 blockPrefix + blockPrefix + "<attr name=\"" + attr.getAttrNameForPrint(attrName) + "\" " +
297                 attr.getKeyForPrint() + "=\"" + attr.getValueForPrint() + "\"/>"
298             ); // NOI18N
299
attr.maybeAddSerValueComment(pw, blockPrefix + blockPrefix);
300         }
301
302         if (isHeadingWr) {
303             pw.println(blockPrefix + "</fileobject>"); // NOI18N
304
}
305     }
306
307     public synchronized void clear() {
308         map.clear();
309     }
310
311     public synchronized Object JavaDoc remove(Object JavaDoc p1) {
312         return map.remove(p1);
313     }
314
315     public synchronized boolean containsValue(Object JavaDoc p1) {
316         return map.containsValue(p1);
317     }
318
319     public synchronized int hashCode() {
320         return map.hashCode();
321     }
322
323     public synchronized java.util.Set JavaDoc<String JavaDoc> keySet() {
324         return map.keySet();
325     }
326
327     public synchronized java.util.Collection JavaDoc values() {
328         return map.values();
329     }
330
331     // XXX this is wrong - values not translated
332
public synchronized java.util.Set JavaDoc entrySet() {
333         return map.entrySet();
334     }
335
336     public synchronized void putAll(java.util.Map JavaDoc p1) {
337         map.putAll(p1);
338     }
339
340     public synchronized boolean containsKey(Object JavaDoc p1) {
341         return map.containsKey(p1);
342     }
343
344     public synchronized boolean isEmpty() {
345         return map.isEmpty();
346     }
347
348     public synchronized boolean equals(Object JavaDoc p1) {
349         return map.equals(p1);
350     }
351
352     public synchronized int size() {
353         return map.size();
354     }
355
356     /**
357      * Holds textual representation of one attribute. And on request construct new instance of
358      * attribute a returns it as Object. Each Attr contains pair key and value. Key is type. Value is real value (in textual form) of this type.
359      * Detailed describtion is in <A HREF="XMLMapAttr.html">XMLMapAttr<A>
360      */

361     final static class Attr extends java.lang.Object JavaDoc {
362         // static final long serialVersionUID = -62733358015297232L;
363
private static final String JavaDoc[] ALLOWED_ATTR_KEYS = {
364             "bytevalue", "shortvalue", "intvalue", "longvalue", "floatvalue", "doublevalue", "boolvalue", "charvalue",
365             "stringvalue", "methodvalue", "serialvalue", "urlvalue", "newvalue"
366         }; // NOI18N
367
private String JavaDoc value;
368         private int keyIndex;
369         private Object JavaDoc obj; //back compatibility
370

371         private Attr(Object JavaDoc obj) {
372             this.obj = obj;
373         }
374
375         private Attr(int index, String JavaDoc value) {
376             keyIndex = index;
377             this.value = (value != null) ? value.intern() : null;
378         }
379
380         /**
381          * @param key One of the possible keys:
382          * "bytevalue","shortvalue","intvalue","longvalue","floatvalue","doublevalue","boolvalue","charvalue","stringvalue","methodvalue","serialvalue","urlvalue"
383          * @param value Corresponding value to key in textual form.
384          */

385         private Attr(String JavaDoc key, String JavaDoc value) {
386             keyIndex = isValid(key);
387             this.value = value.intern();
388         }
389
390         /**
391          * @return array of Strings. Each String is textual form of allowed type of attribute - textual form of key
392          */

393         static String JavaDoc[] getAttrTypes() {
394             return ALLOWED_ATTR_KEYS;
395         }
396
397         /**
398          * Checks if key is valid and sets key and value
399          * @param key Key of attribute. Defines type of attribute in textual form.
400          * @param value Value of attribute. Defines value of attribute as literal or HEX expression of serialization.
401          */

402         private final void putEntry(String JavaDoc key, String JavaDoc value) {
403             this.keyIndex = isValid(key);
404             this.value = value.intern();
405         }
406
407         /**
408          * added for future use - convert NbMarshalledObject to primitive data types and other supported types (if possible)
409          */

410         static Object JavaDoc unMarshallObjectRecursively(Object JavaDoc mo) {
411             Object JavaDoc o = mo;
412
413             while (o instanceof NbMarshalledObject) {
414                 try {
415                     o = ((NbMarshalledObject) o).get();
416                 } catch (IOException e) {
417                     ExternalUtil.exception(e);
418
419                     return mo;
420                 } catch (ClassNotFoundException JavaDoc e) {
421                     ExternalUtil.exception(e);
422
423                     return mo;
424                 }
425             }
426
427             return (o == null) ? mo : o;
428         }
429
430         /**Method for back compatibility; called in write*/
431         private void transformMe() {
432             int objType;
433
434             if (obj == null) {
435                 return;
436             }
437
438             Object JavaDoc unObj = unMarshallObjectRecursively(obj);
439
440             if (unObj != null) {
441                 if ((objType = XMLMapAttr.Attr.distinguishObject(unObj)) != XMLMapAttr.Attr.isValid("SERIALVALUE")) { // NOI18N
442
obj = null;
443                     putEntry(ALLOWED_ATTR_KEYS[objType], unObj.toString());
444                 } else {
445                     String JavaDoc newValue;
446
447                     try {
448                         newValue = encodeValue(unObj);
449                     } catch (IOException iox) {
450                         return;
451                     }
452
453                     obj = null;
454                     putEntry(ALLOWED_ATTR_KEYS[objType], newValue);
455                 }
456             }
457         }
458
459         /**
460          * added for future use - convert NbMarshalledObject to primitive data types and other supported types (if possible)
461          */

462         static int distinguishObject(Object JavaDoc o) {
463             if (o instanceof Byte JavaDoc) {
464                 return isValid("BYTEVALUE"); // NOI18N
465
}
466
467             if (o instanceof Short JavaDoc) {
468                 return isValid("SHORTVALUE"); // NOI18N
469
}
470
471             if (o instanceof Integer JavaDoc) {
472                 return isValid("INTVALUE"); // NOI18N
473
}
474
475             if (o instanceof Long JavaDoc) {
476                 return isValid("LONGVALUE"); // NOI18N
477
}
478
479             if (o instanceof Float JavaDoc) {
480                 return isValid("FLOATVALUE"); // NOI18N
481
}
482
483             if (o instanceof Double JavaDoc) {
484                 return isValid("DOUBLEVALUE"); // NOI18N
485
}
486
487             if (o instanceof Boolean JavaDoc) {
488                 return isValid("BOOLVALUE"); // NOI18N
489
}
490
491             if (o instanceof Character JavaDoc) {
492                 return isValid("CHARVALUE"); // NOI18N
493
}
494
495             if (o instanceof String JavaDoc) {
496                 return isValid("STRINGVALUE"); // NOI18N
497
}
498
499             if (o instanceof URL JavaDoc) {
500                 return isValid("URLVALUE"); // NOI18N
501
}
502
503             return isValid("SERIALVALUE"); // NOI18N
504
}
505
506         static String JavaDoc encode(String JavaDoc inStr) {
507             try {
508                 inStr = org.openide.xml.XMLUtil.toAttributeValue(inStr);
509             } catch (Exception JavaDoc ignore) {
510             }
511
512             StringBuffer JavaDoc outStr = new StringBuffer JavaDoc(6 * inStr.length());
513
514             for (int i = 0; i < inStr.length(); i++) {
515                 if (Character.isISOControl(inStr.charAt(i)) || isEncodedChar(i, inStr)) {
516                     outStr.append(encodeChar(inStr.charAt(i)));
517
518                     continue;
519                 }
520
521                 outStr.append(inStr.charAt(i));
522             }
523
524             return outStr.toString();
525         }
526
527         static String JavaDoc encodeChar(char ch) {
528             String JavaDoc encChar = Integer.toString((int) ch, 16);
529
530             return "\\u" + "0000".substring(0, "0000".length() - encChar.length()).concat(encChar); // NOI18N
531
}
532
533         static String JavaDoc decode(final String JavaDoc inStr) {
534             StringBuffer JavaDoc outStr = new StringBuffer JavaDoc(inStr.length());
535
536             try {
537                 for (int i = 0; i < inStr.length(); i++) {
538                     if (isEncodedChar(i, inStr)) {
539                         String JavaDoc decChar = inStr.substring(i + 2, i + 6);
540                         outStr.append((char) Integer.parseInt(decChar, 16));
541                         i += 5;
542                     } else {
543                         outStr.append(inStr.charAt(i));
544                     }
545                 }
546             } catch (NumberFormatException JavaDoc e) {
547                 Exceptions.printStackTrace(e);
548
549                 return inStr;
550             }
551
552             return outStr.toString();
553         }
554
555         private static boolean isEncodedChar(final int currentPosition, final String JavaDoc inStr) {
556             boolean isEncodedChar = (currentPosition + 5) < inStr.length();
557
558             if (isEncodedChar) {
559                 isEncodedChar &= ((inStr.charAt(currentPosition) == '\\') &&
560                 (inStr.charAt(currentPosition + 1) == 'u'));
561
562                 for (int i = currentPosition + 2; isEncodedChar && (i < (currentPosition + 6)); i++) {
563                     char c = inStr.charAt(i);
564                     isEncodedChar &= (Character.digit(c, 16) != -1);
565                 }
566             }
567
568             return isEncodedChar;
569         }
570
571         /**
572         * Constructs new attribute as Object. Used for static creation from literal or serialValue.
573         * @return new attribute as Object
574         */

575         private Object JavaDoc get() throws Exception JavaDoc {
576             return getObject(null); //getObject is ready to aobtain null
577
}
578
579         /**
580          * Constructs new attribute as Object. Used for dynamic creation: methodvalue .
581          * @param objs has sense only for methodvalue invocation; and only 2 parametres will be used
582          *@return new attribute as Object
583          */

584         private Object JavaDoc get(Object JavaDoc[] objs) throws Exception JavaDoc {
585             return getObject(objs);
586         }
587
588         /**
589          * @return key. Key expresses type of this attribute (in textual form) or "" if internal error.
590          */

591         final String JavaDoc getKey() {
592             String JavaDoc[] keyArray = getAttrTypes();
593
594             if (obj != null) {
595                 return "serialvalue"; //back compatibility // NOI18N
596
}
597
598             if (isValid() == -1) {
599                 return ""; // NOI18N
600
}
601
602             return keyArray[keyIndex];
603         }
604
605         /**
606          * @return value in textual format or "" if internal error.
607          */

608         final String JavaDoc getValue() {
609             if (obj != null) {
610                 getValue(obj);
611             }
612
613             return (value != null) ? value : ""; // NOI18N
614
}
615
616         static final String JavaDoc getValue(Object JavaDoc obj) {
617             try {
618                 return encodeValue(obj); //back compatibility
619
} catch (IOException ioe) {
620                 return ""; // NOI18N
621
}
622         }
623
624         final String JavaDoc getValueForPrint() {
625             if (obj != null) {
626                 Attr modifAttr = null;
627
628                 if (obj instanceof ModifiedAttribute) {
629                     modifAttr = (Attr) ((ModifiedAttribute) obj).getValue();
630                 }
631
632                 return (modifAttr != null) ? encode(modifAttr.getValue()) : encode(getValue());
633             }
634
635             return (value != null) ? encode(value) : ""; // NOI18N
636
}
637
638         final String JavaDoc getKeyForPrint() {
639             if ((obj != null) && obj instanceof ModifiedAttribute) {
640                 Attr modifAttr = (Attr) ((ModifiedAttribute) obj).getValue();
641                 int keyIdx = Attr.isValid("SERIALVALUE"); //NOI18N
642

643                 if (modifAttr != null) {
644                     keyIdx = distinguishObject(modifAttr.getValue());
645                 }
646
647                 String JavaDoc[] keyArray = getAttrTypes();
648
649                 return keyArray[keyIdx];
650             }
651
652             return getKey();
653         }
654
655         final String JavaDoc getAttrNameForPrint(String JavaDoc attrName) {
656             if ((obj != null) && obj instanceof ModifiedAttribute) {
657                 Object JavaDoc[] retVal = ModifiedAttribute.revert(attrName, obj);
658
659                 return encode((String JavaDoc) retVal[0]);
660             }
661
662             return encode(attrName);
663         }
664
665         final void maybeAddSerValueComment(PrintWriter pw, String JavaDoc indent) {
666             if (obj != null) {
667                 Object JavaDoc modifObj = null;
668
669                 if (obj instanceof ModifiedAttribute) {
670                     modifObj = ((Attr) ((ModifiedAttribute) obj).getValue()).getValue();
671
672                     if (distinguishObject(modifObj) != Attr.isValid("SERIALVALUE")) { //NOI18N
673

674                         return;
675                     }
676                 }
677
678                 // Important for debugging to know what this stuff really is.
679
// Note this comment is only written to disk when the attr is
680
// first saved; after that successive saves will just know the
681
// ser value and will not print the comment. So look at .nbattrs
682
// immediately after setting something serialized. --jglick
683
pw.print(indent);
684                 pw.print("<!-- "); // NOI18N
685

686                 String JavaDoc s = (modifObj != null) ? modifObj.toString() : obj.toString();
687
688                 if (s.indexOf("--") != -1) { // NOI18N
689

690                     // XML comment no-no.
691
s = s.replace('-', '_'); // NOI18N
692
}
693
694                 pw.print(s);
695                 pw.println(" -->"); // NOI18N
696
}
697         }
698
699         /**
700          * Creates serialized object, which was encoded in HEX format
701          * @param value Encoded serialized object in HEX format
702          * @return Created object from encoded HEX format
703          * @throws IOException
704          */

705         static Object JavaDoc decodeValue(String JavaDoc value) throws IOException {
706             if ((value == null) || (value.length() == 0)) {
707                 return null;
708             }
709
710             byte[] bytes = new byte[value.length() / 2];
711             int tempI;
712             int count = 0;
713
714             for (int i = 0; i < value.length(); i += 2) {
715                 try {
716                     tempI = Integer.parseInt(value.substring(i, i + 2), 16);
717
718                     if (tempI > 127) {
719                         tempI -= 256;
720                     }
721
722                     bytes[count++] = (byte) tempI;
723                 } catch (NumberFormatException JavaDoc e) {
724                     throw (IOException) ExternalUtil.copyAnnotation(new IOException(), e);
725                 }
726             }
727
728             ByteArrayInputStream bis = new ByteArrayInputStream(bytes, 0, count);
729
730             try {
731                 ObjectInputStream ois = new NbObjectInputStream(bis);
732                 Object JavaDoc ret = ois.readObject();
733
734                 return ret;
735             } catch (Exception JavaDoc e) {
736                 throw (IOException) ExternalUtil.copyAnnotation(new IOException(), e);
737             }
738
739             /*unreachable code*/
740
741             //throw new InternalError ();
742
}
743
744         /**
745          * Encodes Object into String encoded in HEX format
746          * @param value Object, which will be encoded
747          * @return serialized Object in String encoded in HEX format
748          * @throws IOException
749          */

750         static String JavaDoc encodeValue(Object JavaDoc value) throws IOException {
751             ByteArrayOutputStream bos = new ByteArrayOutputStream();
752
753             try {
754                 ObjectOutputStream oos = new ObjectOutputStream(bos);
755                 oos.writeObject(value);
756                 oos.close();
757             } catch (Exception JavaDoc e) {
758                 throw (IOException) ExternalUtil.copyAnnotation(new IOException(), e);
759             }
760
761             byte[] bArray = bos.toByteArray();
762             StringBuffer JavaDoc strBuff = new StringBuffer JavaDoc(bArray.length * 2);
763
764             for (int i = 0; i < bArray.length; i++) {
765                 if ((bArray[i] < 16) && (bArray[i] >= 0)) {
766                     strBuff.append("0"); // NOI18N
767
}
768
769                 strBuff.append(Integer.toHexString((bArray[i] < 0) ? (bArray[i] + 256) : bArray[i]));
770             }
771
772             return strBuff.toString();
773         }
774
775         /**
776          * Encodes Object into String encoded in HEX format
777          * @param params Array (2 length) of objects ( Object[] o = {fo,name}). Attribute is assigned to some fo-FileObject and has its name-String.
778          * params can be null.
779          * @return Object or null
780          */

781         private Object JavaDoc getObject(Object JavaDoc[] params) throws Exception JavaDoc {
782             int index;
783
784             if (obj != null) {
785                 return obj; //back compatibility
786
}
787
788             if ((index = isValid()) != -1) {
789                 try {
790                     switch (index) {
791                     case 0:
792                         return new Byte JavaDoc(value);
793
794                     case 1:
795                         return new Short JavaDoc(value);
796
797                     case 2:
798                         return new Integer JavaDoc(value); //(objI);
799

800                     case 3:
801                         return new Long JavaDoc(value);
802
803                     case 4:
804                         return new Float JavaDoc(value);
805
806                     case 5:
807                         return new Double JavaDoc(value);
808
809                     case 6:
810                         return Boolean.valueOf(value);
811
812                     case 7:
813
814                         if (value.trim().length() != 1) {
815                             break;
816                         }
817
818                         return new Character JavaDoc(value.charAt(0));
819
820                     case 8:
821                         return value;
822
823                     case 9:
824                         return methodValue(value, params);
825
826                     case 10:
827                         return decodeValue(value);
828
829                     case 11:
830                         return new URL JavaDoc(value);
831
832                     case 12:
833
834                         // special support for singletons
835
Class JavaDoc cls = ExternalUtil.findClass(Utilities.translate(value));
836
837                         if (SharedClassObject.class.isAssignableFrom(cls)) {
838                             return SharedClassObject.findObject(cls, true);
839                         } else {
840                             return cls.newInstance();
841                         }
842                     }
843                 } catch (Exception JavaDoc exc) {
844                     ExternalUtil.annotate(exc, "value = " + value); //NOI18N
845
throw exc;
846                 } catch (LinkageError JavaDoc e) {
847                     throw (ClassNotFoundException JavaDoc) ExternalUtil.annotate(new ClassNotFoundException JavaDoc(value), e);
848                 }
849             }
850
851             throw new InstantiationException JavaDoc(value);
852         }
853
854         /** Constructs new attribute as Object. Used for dynamic creation: methodvalue .
855          * @param params only 2 parametres will be used
856          * @return Object or null
857          */

858         private final Object JavaDoc methodValue(String JavaDoc value, Object JavaDoc[] params)
859         throws Exception JavaDoc {
860             int sepIdx = value.lastIndexOf('.');
861
862             if (sepIdx != -1) {
863                 String JavaDoc methodName = value.substring(sepIdx + 1);
864                 Class JavaDoc cls = ExternalUtil.findClass(value.substring(0, sepIdx));
865                 FileObject fo = null;
866                 String JavaDoc attrName = null;
867
868                 for (int i = 0; i < params.length; i++) {
869                     if ((fo == null) && params[i] instanceof FileObject) {
870                         fo = (FileObject) params[i];
871                     }
872
873                     if ((attrName == null) && params[i] instanceof String JavaDoc) {
874                         attrName = (String JavaDoc) params[i];
875                     }
876                 }
877
878                 Object JavaDoc[] paramArray = new Object JavaDoc[] {
879                         new Class JavaDoc[] { FileObject.class, String JavaDoc.class }, new Class JavaDoc[] { String JavaDoc.class, FileObject.class },
880                         new Class JavaDoc[] { FileObject.class }, new Class JavaDoc[] { String JavaDoc.class }, new Class JavaDoc[] { },
881                         new Class JavaDoc[] { Map.class, String JavaDoc.class }, new Class JavaDoc[] { Map.class },
882                     };
883
884                 boolean both = ((fo != null) && (attrName != null));
885                 Object JavaDoc[] objectsList = new Object JavaDoc[7];
886                 objectsList[0] = (both) ? new Object JavaDoc[] { fo, attrName } : null;
887                 objectsList[1] = (both) ? new Object JavaDoc[] { attrName, fo } : null;
888                 objectsList[2] = (fo != null) ? new Object JavaDoc[] { fo } : null;
889                 objectsList[3] = (attrName != null) ? new Object JavaDoc[] { attrName } : null;
890                 objectsList[4] = new Object JavaDoc[] { };
891
892                 Map fileMap = wrapToMap(fo);
893                 objectsList[5] = attrName != null ? new Object JavaDoc[] { fileMap, attrName } : null;
894                 objectsList[6] = new Object JavaDoc[] { fileMap };
895
896                 for (int i = 0; i < paramArray.length; i++) {
897                     Object JavaDoc[] objArray = (Object JavaDoc[]) objectsList[i];
898
899                     if (objArray == null) {
900                         continue;
901                     }
902
903                     try {
904                         Method method = cls.getDeclaredMethod(methodName, (Class JavaDoc[]) paramArray[i]);
905
906                         if (method != null) {
907                             method.setAccessible(true);
908
909                             return method.invoke(null, objArray);
910                         }
911                     } catch (NoSuchMethodException JavaDoc nsmExc) {
912                         continue;
913                     }
914                 }
915             }
916
917             throw new InstantiationException JavaDoc(value);
918         }
919
920         static final Map wrapToMap(FileObject fo) {
921             return fo == null ? Collections.EMPTY_MAP : new FileMap(fo);
922         }
923
924         /**
925          * Checks if key is valid
926          * @return Index to array of allowed keys or -1 which means error.
927          */

928         final int isValid() {
929             String JavaDoc[] keyArray = getAttrTypes();
930
931             if (obj != null) {
932                 return isValid("SERIALVALUE"); //back compatibility // NOI18N
933
}
934
935             if ((keyIndex >= keyArray.length) || (keyIndex < 0)) {
936                 return -1;
937             }
938
939             return keyIndex;
940         }
941
942         /**
943          * Checks if key is valid
944          * @return Index to array of allowed keys or -1 which means error.
945          */

946         final static int isValid(String JavaDoc key) {
947             int index = -1;
948             int i;
949             String JavaDoc[] strArray = getAttrTypes();
950             String JavaDoc trimmedKey = key.trim();
951
952             for (i = 0; i < strArray.length; i++) {
953                 if (trimmedKey.equalsIgnoreCase(strArray[i]) == true) {
954                     index = i;
955
956                     break;
957                 }
958             }
959
960             return index;
961         }
962
963         public boolean equals(Object JavaDoc obj) {
964             if (obj instanceof Attr) {
965                 Attr other = (Attr)obj;
966                 
967                 if (other.keyIndex != keyIndex) {
968                     return false;
969                 }
970                 
971                 return other.value.equals(value);
972             }
973             return false;
974         }
975
976         public int hashCode() {
977             return 743 + keyIndex << 8 + value.hashCode();
978         }
979     }
980
981     /**
982      * Helper class for decorating attributes with modifiers.
983      * Object that is made persistent using setAttribute can contain also modifiers.
984      * This class is wrapper class that holds original object and its modifiers.
985      * Intended as replacer of original class in attributes.
986      * Currently exists only one modifier: tranisent.
987      * Transient modifier means that such attribute won`t be copied with FileObject.
988      */

989     static class ModifiedAttribute implements java.io.Serializable JavaDoc {
990         /** generated Serialized Version UID */
991         static final long serialVersionUID = 84214031923497718L;
992         private final static String JavaDoc[] fragments = new String JavaDoc[] { "transient:" }; //NOI18N
993
private int modifier = 0;
994         private Object JavaDoc origAttrValue = null;
995
996         /** Creates a new instance of AttributeFactory */
997         private ModifiedAttribute(Object JavaDoc origAttrValue) {
998             this.origAttrValue = origAttrValue;
999         }
1000
1001        /** This method looks for modifiers in attribute name (currently transient:).
1002         *
1003         * @param attrName original name of attribute
1004         * @param value original value - can be null
1005         * @return Object array with size 2.
1006         * If there are no modifiers in attribute name, then is returned Object array with
1007         * , where first is placed unchanged attribute name, and then uchanged value.
1008         * If there are modifiers in attribute name, then as attribute name is returned
1009         * stripped original attribute name (without modifiers) and ModifiedAttribute object,
1010         * that wraps original object and also contain modifiers.
1011         */

1012        static Object JavaDoc[] translateInto(String JavaDoc attrName, Object JavaDoc value) {
1013            String JavaDoc newAttrName = attrName;
1014            Object JavaDoc newValue = value;
1015            ModifiedAttribute attr = null;
1016
1017            for (int i = 0; i < fragments.length; i++) {
1018                String JavaDoc fragment = fragments[i];
1019                int idx = newAttrName.indexOf(fragment);
1020
1021                if (idx != -1) {
1022                    /** fragment is cleared away */
1023                    newAttrName = newAttrName.substring(0, idx) + newAttrName.substring(idx + fragment.length());
1024
1025                    if (attr == null) {
1026                        newValue = attr = new ModifiedAttribute(value);
1027                    }
1028
1029                    attr.modifier |= (1 << i); //set modifier
1030
}
1031            }
1032
1033            return new Object JavaDoc[] { newAttrName, newValue };
1034        }
1035
1036        /**
1037         * This method is opposite to method translateInto
1038         */

1039        static Object JavaDoc[] revert(String JavaDoc attrName, Object JavaDoc value) {
1040            if (!(value instanceof ModifiedAttribute) || (value == null)) {
1041                return new Object JavaDoc[] { attrName, value };
1042            }
1043
1044            ModifiedAttribute attr = (ModifiedAttribute) value;
1045            String JavaDoc newAttrName = attrName;
1046            Object JavaDoc newValue = attr;
1047
1048            for (int i = 0; i < fragments.length; i++) {
1049                String JavaDoc fragment = fragments[i];
1050
1051                if (((attr.modifier & (1 << i)) != 0) && (fragment != null)) {
1052                    /** fragment is cleared away */
1053                    newAttrName = fragment + newAttrName;
1054
1055                    if (newValue instanceof ModifiedAttribute) {
1056                        newValue = attr.origAttrValue;
1057                    }
1058                }
1059            }
1060
1061            return new Object JavaDoc[] { newAttrName, newValue };
1062        }
1063
1064        /** ModifiedAttribute holds original value + modifiers. This method returns original value.
1065         * @return If there are no modifiers in attribute name, then returns original value
1066         * If there are modifiers in attribute name, then returns current instance of
1067         * ModifiedAttribute.
1068         */

1069        Object JavaDoc getValue(String JavaDoc attrName) {
1070            for (int i = 0; i < fragments.length; i++) {
1071                String JavaDoc fragment = fragments[i];
1072                int idx = attrName.indexOf(fragment);
1073
1074                if (idx != -1) {
1075                    return this;
1076                }
1077            }
1078
1079            return origAttrValue;
1080        }
1081
1082        /** ModifiedAttribute holds original value + modifiers. This method returns original value.
1083         * @return then returns original value
1084         */

1085        Object JavaDoc getValue() {
1086            return getValue(""); //NOI18N
1087
}
1088
1089        /**
1090         * Decides if value stored in attributes is transient
1091         * @param fo fileobject where attribute is looked for
1092         * @param attrName name of attribute
1093         * @return true if transient
1094         */

1095        static boolean isTransient(FileObject fo, String JavaDoc attrName) {
1096            Object JavaDoc value = fo.getAttribute(fragments[0] + attrName);
1097
1098            if (value instanceof ModifiedAttribute) {
1099                return ((((ModifiedAttribute) value).modifier & (1 << 0)) == 0) ? false : true;
1100            }
1101
1102            return false;
1103        }
1104    }
1105    
1106    private static final class FileMap extends AbstractMap<String JavaDoc,Object JavaDoc> {
1107        private FileObject fo;
1108        
1109        private FileMap (FileObject fo) {
1110            this.fo = fo;
1111}
1112        
1113        public Set<Map.Entry<String JavaDoc,Object JavaDoc>> entrySet() {
1114            return new AttrFileSet(fo);
1115        }
1116
1117        public Object JavaDoc get(String JavaDoc key) {
1118            return fo.getAttribute(key);
1119        }
1120
1121        public Object JavaDoc remove(Object JavaDoc key) {
1122            throw new UnsupportedOperationException JavaDoc();
1123        }
1124
1125        public Object JavaDoc put(String JavaDoc key, Object JavaDoc value) {
1126            throw new UnsupportedOperationException JavaDoc();
1127        }
1128        
1129    }
1130    private static final class AttrFileSet extends AbstractSet<Map.Entry<String JavaDoc,Object JavaDoc>> {
1131        private FileObject fo;
1132        
1133        private AttrFileSet(FileObject fo) {
1134            this.fo = fo;
1135        }
1136        
1137        public Iterator<Map.Entry<String JavaDoc, Object JavaDoc>> iterator() {
1138            class Iter implements Iterator<Map.Entry<String JavaDoc, Object JavaDoc>> {
1139                Enumeration<String JavaDoc> attrs = fo.getAttributes();
1140                
1141                public boolean hasNext() {
1142                    return attrs.hasMoreElements();
1143                }
1144                
1145                public Map.Entry<String JavaDoc, Object JavaDoc> next() {
1146                    String JavaDoc s = attrs.nextElement();
1147                    return new FOEntry(fo, s);
1148                }
1149
1150                public void remove() {
1151                    throw new UnsupportedOperationException JavaDoc();
1152                }
1153            }
1154            return new Iter();
1155        }
1156
1157        public int size() {
1158            Enumeration<String JavaDoc> all = fo.getAttributes();
1159            int cnt = 0;
1160            while (all.hasMoreElements()) {
1161                cnt++;
1162                all.nextElement();
1163            }
1164            return cnt;
1165        }
1166
1167        public boolean remove(Object JavaDoc o) {
1168            throw new UnsupportedOperationException JavaDoc();
1169        }
1170    } // end of AttrFileSet
1171

1172    private static final class FOEntry implements Map.Entry<String JavaDoc, Object JavaDoc> {
1173        private FileObject fo;
1174        private String JavaDoc attr;
1175        
1176        private FOEntry(FileObject fo, String JavaDoc attr) {
1177            this.fo = fo;
1178            this.attr = attr;
1179        }
1180
1181        public String JavaDoc getKey() {
1182            return attr;
1183        }
1184
1185        public Object JavaDoc getValue() {
1186            return fo.getAttribute(attr);
1187        }
1188
1189        public Object JavaDoc setValue(Object JavaDoc value) {
1190            throw new UnsupportedOperationException JavaDoc();
1191        }
1192    } // end of FOEntry
1193
}
1194
Popular Tags