001: /*
002: * Fast Infoset ver. 0.1 software ("Software")
003: *
004: * Copyright, 2004-2005 Sun Microsystems, Inc. All Rights Reserved.
005: *
006: * Software is licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License. You may
008: * obtain a copy of the License at:
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
014: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
015: * License for the specific language governing permissions and limitations.
016: *
017: * Sun supports and benefits from the global community of open source
018: * developers, and thanks the community for its important contributions and
019: * open standards-based technology, which Sun has adopted into many of its
020: * products.
021: *
022: * Please note that portions of Software may be provided with notices and
023: * open source licenses from such communities and third parties that govern the
024: * use of those portions, and any licenses granted hereunder do not alter any
025: * rights and obligations you may have under such open source licenses,
026: * however, the disclaimer of warranty and limitation of liability provisions
027: * in this License will apply to all Software in this distribution.
028: *
029: * You acknowledge that the Software is not designed, licensed or intended
030: * for use in the design, construction, operation or maintenance of any nuclear
031: * facility.
032: *
033: * Apache License
034: * Version 2.0, January 2004
035: * http://www.apache.org/licenses/
036: *
037: */
038: package org.jvnet.fastinfoset.sax.helpers;
039:
040: import com.sun.xml.fastinfoset.CommonResourceBundle;
041: import com.sun.xml.fastinfoset.EncodingConstants;
042: import com.sun.xml.fastinfoset.algorithm.BuiltInEncodingAlgorithmFactory;
043: import java.io.IOException;
044: import java.util.Map;
045: import org.jvnet.fastinfoset.EncodingAlgorithm;
046: import org.jvnet.fastinfoset.EncodingAlgorithmException;
047: import org.jvnet.fastinfoset.EncodingAlgorithmIndexes;
048: import org.jvnet.fastinfoset.FastInfosetException;
049: import org.jvnet.fastinfoset.sax.EncodingAlgorithmAttributes;
050: import org.xml.sax.Attributes;
051:
052: /**
053: * Default implementation of the {@link EncodingAlgorithmAttributes} interface.
054: *
055: * <p>This class provides a default implementation of the SAX2
056: * {@link EncodingAlgorithmAttributes} interface, with the
057: * addition of manipulators so that the list can be modified or
058: * reused.</p>
059: *
060: * <p>There are two typical uses of this class:</p>
061: *
062: * <ol>
063: * <li>to take a persistent snapshot of an EncodingAlgorithmAttributes object
064: * in a {@link org.xml.sax.ContentHandler#startElement startElement} event; or</li>
065: * <li>to construct or modify an EncodingAlgorithmAttributes object in a SAX2
066: * driver or filter.</li>
067: * </ol>
068: */
069: public class EncodingAlgorithmAttributesImpl implements
070: EncodingAlgorithmAttributes {
071: private static final int DEFAULT_CAPACITY = 8;
072:
073: private static final int URI_OFFSET = 0;
074: private static final int LOCALNAME_OFFSET = 1;
075: private static final int QNAME_OFFSET = 2;
076: private static final int TYPE_OFFSET = 3;
077: private static final int VALUE_OFFSET = 4;
078: private static final int ALGORITHMURI_OFFSET = 5;
079:
080: private static final int SIZE = 6;
081:
082: private Map _registeredEncodingAlgorithms;
083:
084: private int _length;
085:
086: private String[] _data;
087:
088: private int[] _algorithmIds;
089:
090: private Object[] _algorithmData;
091:
092: private String[] _alphabets;
093:
094: private boolean[] _toIndex;
095:
096: /**
097: * Construct a new, empty EncodingAlgorithmAttributesImpl object.
098: */
099: public EncodingAlgorithmAttributesImpl() {
100: this (null, null);
101: }
102:
103: /**
104: * Copy an existing Attributes object.
105: *
106: * <p>This constructor is especially useful inside a
107: * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
108: *
109: * @param attributes The existing Attributes object.
110: */
111: public EncodingAlgorithmAttributesImpl(Attributes attributes) {
112: this (null, attributes);
113: }
114:
115: /**
116: * Use registered encoding algorithms and copy an existing Attributes object.
117: *
118: * <p>This constructor is especially useful inside a
119: * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
120: *
121: * @param registeredEncodingAlgorithms
122: * The registeredEncodingAlgorithms encoding algorithms.
123: * @param attributes The existing Attributes object.
124: */
125: public EncodingAlgorithmAttributesImpl(
126: Map registeredEncodingAlgorithms, Attributes attributes) {
127: _data = new String[DEFAULT_CAPACITY * SIZE];
128: _algorithmIds = new int[DEFAULT_CAPACITY];
129: _algorithmData = new Object[DEFAULT_CAPACITY];
130: _alphabets = new String[DEFAULT_CAPACITY];
131: _toIndex = new boolean[DEFAULT_CAPACITY];
132:
133: _registeredEncodingAlgorithms = registeredEncodingAlgorithms;
134:
135: if (attributes != null) {
136: if (attributes instanceof EncodingAlgorithmAttributes) {
137: setAttributes((EncodingAlgorithmAttributes) attributes);
138: } else {
139: setAttributes(attributes);
140: }
141: }
142: }
143:
144: /**
145: * Clear the attribute list for reuse.
146: *
147: */
148: public final void clear() {
149: for (int i = 0; i < _length; i++) {
150: _data[i * SIZE + VALUE_OFFSET] = null;
151: _algorithmData[i] = null;
152: }
153: _length = 0;
154: }
155:
156: /**
157: * Add an attribute to the end of the list.
158: *
159: * <p>For the sake of speed, this method does no checking
160: * to see if the attribute is already in the list: that is
161: * the responsibility of the application.</p>
162: *
163: * @param uri The Namespace URI, or the empty string if
164: * none is available or Namespace processing is not
165: * being performed.
166: * @param localName The local name, or the empty string if
167: * Namespace processing is not being performed.
168: * @param qName The qualified (prefixed) name, or the empty string
169: * if qualified names are not available.
170: * @param type The attribute type as a string.
171: * @param value The attribute value.
172: */
173: public void addAttribute(String URI, String localName,
174: String qName, String type, String value) {
175: if (_length >= _algorithmData.length) {
176: resize();
177: }
178:
179: int i = _length * SIZE;
180: _data[i++] = replaceNull(URI);
181: _data[i++] = replaceNull(localName);
182: _data[i++] = replaceNull(qName);
183: _data[i++] = replaceNull(type);
184: _data[i++] = replaceNull(value);
185: _toIndex[_length] = false;
186: _alphabets[_length] = null;
187:
188: _length++;
189: }
190:
191: /**
192: * Add an attribute to the end of the list.
193: *
194: * <p>For the sake of speed, this method does no checking
195: * to see if the attribute is already in the list: that is
196: * the responsibility of the application.</p>
197: *
198: * @param uri The Namespace URI, or the empty string if
199: * none is available or Namespace processing is not
200: * being performed.
201: * @param localName The local name, or the empty string if
202: * Namespace processing is not being performed.
203: * @param qName The qualified (prefixed) name, or the empty string
204: * if qualified names are not available.
205: * @param type The attribute type as a string.
206: * @param value The attribute value.
207: * @param index True if attribute should be indexed.
208: * @param index The alphabet associated with the attribute value,
209: * may be null if there is no associated alphabet.
210: */
211: public void addAttribute(String URI, String localName,
212: String qName, String type, String value, boolean index,
213: String alphabet) {
214: if (_length >= _algorithmData.length) {
215: resize();
216: }
217:
218: int i = _length * SIZE;
219: _data[i++] = replaceNull(URI);
220: _data[i++] = replaceNull(localName);
221: _data[i++] = replaceNull(qName);
222: _data[i++] = replaceNull(type);
223: _data[i++] = replaceNull(value);
224: _toIndex[_length] = index;
225: _alphabets[_length] = alphabet;
226:
227: _length++;
228: }
229:
230: /**
231: * Add an attribute with built in algorithm data to the end of the list.
232: *
233: * <p>For the sake of speed, this method does no checking
234: * to see if the attribute is already in the list: that is
235: * the responsibility of the application.</p>
236: *
237: * @param uri The Namespace URI, or the empty string if
238: * none is available or Namespace processing is not
239: * being performed.
240: * @param localName The local name, or the empty string if
241: * Namespace processing is not being performed.
242: * @param qName The qualified (prefixed) name, or the empty string
243: * if qualified names are not available.
244: * @param builtInAlgorithmID The built in algorithm ID.
245: * @param algorithmData The built in algorithm data.
246: */
247: public void addAttributeWithBuiltInAlgorithmData(String URI,
248: String localName, String qName, int builtInAlgorithmID,
249: Object algorithmData) {
250: if (_length >= _algorithmData.length) {
251: resize();
252: }
253:
254: int i = _length * SIZE;
255: _data[i++] = replaceNull(URI);
256: _data[i++] = replaceNull(localName);
257: _data[i++] = replaceNull(qName);
258: _data[i++] = "CDATA";
259: _data[i++] = "";
260: _data[i++] = null;
261: _algorithmIds[_length] = builtInAlgorithmID;
262: _algorithmData[_length] = algorithmData;
263: _toIndex[_length] = false;
264: _alphabets[_length] = null;
265:
266: _length++;
267: }
268:
269: /**
270: * Add an attribute with algorithm data to the end of the list.
271: *
272: * <p>For the sake of speed, this method does no checking
273: * to see if the attribute is already in the list: that is
274: * the responsibility of the application.</p>
275: *
276: * @param uri The Namespace URI, or the empty string if
277: * none is available or Namespace processing is not
278: * being performed.
279: * @param localName The local name, or the empty string if
280: * Namespace processing is not being performed.
281: * @param qName The qualified (prefixed) name, or the empty string
282: * if qualified names are not available.
283: * @param algorithmURI The algorithm URI, or null if a built in algorithm
284: * @param algorithmID The algorithm ID.
285: * @param algorithmData The algorithm data.
286: */
287: public void addAttributeWithAlgorithmData(String URI,
288: String localName, String qName, String algorithmURI,
289: int algorithmID, Object algorithmData) {
290: if (_length >= _algorithmData.length) {
291: resize();
292: }
293:
294: int i = _length * SIZE;
295: _data[i++] = replaceNull(URI);
296: _data[i++] = replaceNull(localName);
297: _data[i++] = replaceNull(qName);
298: _data[i++] = "CDATA";
299: _data[i++] = "";
300: _data[i++] = algorithmURI;
301: _algorithmIds[_length] = algorithmID;
302: _algorithmData[_length] = algorithmData;
303: _toIndex[_length] = false;
304: _alphabets[_length] = null;
305:
306: _length++;
307: }
308:
309: /**
310: * Replace an attribute value with algorithm data.
311: *
312: * <p>For the sake of speed, this method does no checking
313: * to see if the attribute is already in the list: that is
314: * the responsibility of the application.</p>
315: *
316: * @param index The index of the attribute whose value is to be replaced
317: * @param algorithmURI The algorithm URI, or null if a built in algorithm
318: * @param algorithmID The algorithm ID.
319: * @param algorithmData The algorithm data.
320: */
321: public void replaceWithAttributeAlgorithmData(int index,
322: String algorithmURI, int algorithmID, Object algorithmData) {
323: if (index < 0 || index >= _length)
324: return;
325:
326: int i = index * SIZE;
327: _data[i + VALUE_OFFSET] = null;
328: _data[i + ALGORITHMURI_OFFSET] = algorithmURI;
329: _algorithmIds[index] = algorithmID;
330: _algorithmData[index] = algorithmData;
331: _toIndex[index] = false;
332: _alphabets[index] = null;
333: }
334:
335: /**
336: * Copy an entire Attributes object.
337: *
338: * @param atts The attributes to copy.
339: */
340: public void setAttributes(Attributes atts) {
341: _length = atts.getLength();
342: if (_length > 0) {
343:
344: if (_length >= _algorithmData.length) {
345: resizeNoCopy();
346: }
347:
348: int index = 0;
349: for (int i = 0; i < _length; i++) {
350: _data[index++] = atts.getURI(i);
351: _data[index++] = atts.getLocalName(i);
352: _data[index++] = atts.getQName(i);
353: _data[index++] = atts.getType(i);
354: _data[index++] = atts.getValue(i);
355: index++;
356: _toIndex[i] = false;
357: _alphabets[i] = null;
358: }
359: }
360: }
361:
362: /**
363: * Copy an entire EncodingAlgorithmAttributes object.
364: *
365: * @param atts The attributes to copy.
366: */
367: public void setAttributes(EncodingAlgorithmAttributes atts) {
368: _length = atts.getLength();
369: if (_length > 0) {
370:
371: if (_length >= _algorithmData.length) {
372: resizeNoCopy();
373: }
374:
375: int index = 0;
376: for (int i = 0; i < _length; i++) {
377: _data[index++] = atts.getURI(i);
378: _data[index++] = atts.getLocalName(i);
379: _data[index++] = atts.getQName(i);
380: _data[index++] = atts.getType(i);
381: _data[index++] = atts.getValue(i);
382: _data[index++] = atts.getAlgorithmURI(i);
383: _algorithmIds[i] = atts.getAlgorithmIndex(i);
384: _algorithmData[i] = atts.getAlgorithmData(i);
385: _toIndex[i] = false;
386: _alphabets[i] = null;
387: }
388: }
389: }
390:
391: // org.xml.sax.Attributes
392:
393: public final int getLength() {
394: return _length;
395: }
396:
397: public final String getLocalName(int index) {
398: if (index >= 0 && index < _length) {
399: return _data[index * SIZE + LOCALNAME_OFFSET];
400: } else {
401: return null;
402: }
403: }
404:
405: public final String getQName(int index) {
406: if (index >= 0 && index < _length) {
407: return _data[index * SIZE + QNAME_OFFSET];
408: } else {
409: return null;
410: }
411: }
412:
413: public final String getType(int index) {
414: if (index >= 0 && index < _length) {
415: return _data[index * SIZE + TYPE_OFFSET];
416: } else {
417: return null;
418: }
419: }
420:
421: public final String getURI(int index) {
422: if (index >= 0 && index < _length) {
423: return _data[index * SIZE + URI_OFFSET];
424: } else {
425: return null;
426: }
427: }
428:
429: public final String getValue(int index) {
430: if (index >= 0 && index < _length) {
431: final String value = _data[index * SIZE + VALUE_OFFSET];
432: if (value != null)
433: return value;
434: } else {
435: return null;
436: }
437:
438: if (_algorithmData[index] == null
439: || _registeredEncodingAlgorithms == null) {
440: return null;
441: }
442:
443: try {
444: return _data[index * SIZE + VALUE_OFFSET] = convertEncodingAlgorithmDataToString(
445: _algorithmIds[index],
446: _data[index * SIZE + ALGORITHMURI_OFFSET],
447: _algorithmData[index]).toString();
448: } catch (IOException e) {
449: return null;
450: } catch (FastInfosetException e) {
451: return null;
452: }
453: }
454:
455: public final int getIndex(String qName) {
456: for (int index = 0; index < _length; index++) {
457: if (qName.equals(_data[index * SIZE + QNAME_OFFSET])) {
458: return index;
459: }
460: }
461: return -1;
462: }
463:
464: public final String getType(String qName) {
465: int index = getIndex(qName);
466: if (index >= 0) {
467: return _data[index * SIZE + TYPE_OFFSET];
468: } else {
469: return null;
470: }
471: }
472:
473: public final String getValue(String qName) {
474: int index = getIndex(qName);
475: if (index >= 0) {
476: return getValue(index);
477: } else {
478: return null;
479: }
480: }
481:
482: public final int getIndex(String uri, String localName) {
483: for (int index = 0; index < _length; index++) {
484: if (localName
485: .equals(_data[index * SIZE + LOCALNAME_OFFSET])
486: && uri.equals(_data[index * SIZE + URI_OFFSET])) {
487: return index;
488: }
489: }
490: return -1;
491: }
492:
493: public final String getType(String uri, String localName) {
494: int index = getIndex(uri, localName);
495: if (index >= 0) {
496: return _data[index * SIZE + TYPE_OFFSET];
497: } else {
498: return null;
499: }
500: }
501:
502: public final String getValue(String uri, String localName) {
503: int index = getIndex(uri, localName);
504: if (index >= 0) {
505: return getValue(index);
506: } else {
507: return null;
508: }
509: }
510:
511: // EncodingAlgorithmAttributes
512:
513: public final String getAlgorithmURI(int index) {
514: if (index >= 0 && index < _length) {
515: return _data[index * SIZE + ALGORITHMURI_OFFSET];
516: } else {
517: return null;
518: }
519: }
520:
521: public final int getAlgorithmIndex(int index) {
522: if (index >= 0 && index < _length) {
523: return _algorithmIds[index];
524: } else {
525: return -1;
526: }
527: }
528:
529: public final Object getAlgorithmData(int index) {
530: if (index >= 0 && index < _length) {
531: return _algorithmData[index];
532: } else {
533: return null;
534: }
535: }
536:
537: // ExtendedAttributes
538:
539: public final String getAlpababet(int index) {
540: if (index >= 0 && index < _length) {
541: return _alphabets[index];
542: } else {
543: return null;
544: }
545: }
546:
547: public final boolean getToIndex(int index) {
548: if (index >= 0 && index < _length) {
549: return _toIndex[index];
550: } else {
551: return false;
552: }
553: }
554:
555: // -----
556:
557: private final String replaceNull(String s) {
558: return (s != null) ? s : "";
559: }
560:
561: private final void resizeNoCopy() {
562: final int newLength = _length * 3 / 2 + 1;
563:
564: _data = new String[newLength * SIZE];
565: _algorithmIds = new int[newLength];
566: _algorithmData = new Object[newLength];
567: }
568:
569: private final void resize() {
570: final int newLength = _length * 3 / 2 + 1;
571:
572: String[] data = new String[newLength * SIZE];
573: int[] algorithmIds = new int[newLength];
574: Object[] algorithmData = new Object[newLength];
575: String[] alphabets = new String[newLength];
576: boolean[] toIndex = new boolean[newLength];
577:
578: System.arraycopy(_data, 0, data, 0, _length * SIZE);
579: System.arraycopy(_algorithmIds, 0, algorithmIds, 0, _length);
580: System.arraycopy(_algorithmData, 0, algorithmData, 0, _length);
581: System.arraycopy(_alphabets, 0, alphabets, 0, _length);
582: System.arraycopy(_toIndex, 0, toIndex, 0, _length);
583:
584: _data = data;
585: _algorithmIds = algorithmIds;
586: _algorithmData = algorithmData;
587: _alphabets = alphabets;
588: _toIndex = toIndex;
589: }
590:
591: private final StringBuffer convertEncodingAlgorithmDataToString(
592: int identifier, String URI, Object data)
593: throws FastInfosetException, IOException {
594: EncodingAlgorithm ea = null;
595: if (identifier < EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) {
596: ea = BuiltInEncodingAlgorithmFactory.table[identifier];
597: } else if (identifier == EncodingAlgorithmIndexes.CDATA) {
598: throw new EncodingAlgorithmException(CommonResourceBundle
599: .getInstance().getString(
600: "message.CDATAAlgorithmNotSupported"));
601: } else if (identifier >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) {
602: if (URI == null) {
603: throw new EncodingAlgorithmException(
604: CommonResourceBundle.getInstance().getString(
605: "message.URINotPresent")
606: + identifier);
607: }
608:
609: ea = (EncodingAlgorithm) _registeredEncodingAlgorithms
610: .get(URI);
611: if (ea == null) {
612: throw new EncodingAlgorithmException(
613: CommonResourceBundle.getInstance().getString(
614: "message.algorithmNotRegistered")
615: + URI);
616: }
617: } else {
618: // Reserved built-in algorithms for future use
619: // TODO should use sax property to decide if event will be
620: // reported, allows for support through handler if required.
621: throw new EncodingAlgorithmException(CommonResourceBundle
622: .getInstance().getString(
623: "message.identifiers10to31Reserved"));
624: }
625:
626: final StringBuffer sb = new StringBuffer();
627: ea.convertToCharacters(data, sb);
628: return sb;
629: }
630: }
|