001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: // AttributesImpl.java - default implementation of Attributes.
038: // http://www.saxproject.org
039: // Written by David Megginson
040: // NO WARRANTY! This class is in the public domain.
041: // $Id: AttributesImpl.java,v 1.3.6.1 2007/05/31 21:58:57 ofung Exp $
042: package com.sun.xml.bind.util;
043:
044: import org.xml.sax.Attributes;
045:
046: /**
047: * Default implementation of the Attributes interface.
048: *
049: * <blockquote>
050: * <em>This module, both source code and documentation, is in the
051: * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
052: * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
053: * for further information.
054: * </blockquote>
055: *
056: * <p>This class provides a default implementation of the SAX2
057: * {@link org.xml.sax.Attributes Attributes} interface, with the
058: * addition of manipulators so that the list can be modified or
059: * reused.</p>
060: *
061: * <p>There are two typical uses of this class:</p>
062: *
063: * <ol>
064: * <li>to take a persistent snapshot of an Attributes object
065: * in a {@link org.xml.sax.ContentHandler#startElement startElement} event; or</li>
066: * <li>to construct or modify an Attributes object in a SAX2 driver or filter.</li>
067: * </ol>
068: *
069: * <p>This class replaces the now-deprecated SAX1 {@link
070: * org.xml.sax.helpers.AttributeListImpl AttributeListImpl}
071: * class; in addition to supporting the updated Attributes
072: * interface rather than the deprecated {@link org.xml.sax.AttributeList
073: * AttributeList} interface, it also includes a much more efficient
074: * implementation using a single array rather than a set of Vectors.</p>
075: *
076: * @since JAXB1.0
077: * @since SAX 2.0
078: * @author David Megginson
079: * @version 2.0.1 (sax2r2)
080: */
081: public class AttributesImpl implements Attributes {
082:
083: ////////////////////////////////////////////////////////////////////
084: // Constructors.
085: ////////////////////////////////////////////////////////////////////
086:
087: /**
088: * Construct a new, empty AttributesImpl object.
089: */
090: public AttributesImpl() {
091: length = 0;
092: data = null;
093: }
094:
095: /**
096: * Copy an existing Attributes object.
097: *
098: * <p>This constructor is especially useful inside a
099: * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
100: *
101: * @param atts The existing Attributes object.
102: */
103: public AttributesImpl(Attributes atts) {
104: setAttributes(atts);
105: }
106:
107: ////////////////////////////////////////////////////////////////////
108: // Implementation of org.xml.sax.Attributes.
109: ////////////////////////////////////////////////////////////////////
110:
111: /**
112: * Return the number of attributes in the list.
113: *
114: * @return The number of attributes in the list.
115: * @see org.xml.sax.Attributes#getLength()
116: */
117: public int getLength() {
118: return length;
119: }
120:
121: /**
122: * Return an attribute's Namespace URI.
123: *
124: * @param index The attribute's index (zero-based).
125: * @return The Namespace URI, the empty string if none is
126: * available, or null if the index is out of range.
127: * @see org.xml.sax.Attributes#getURI(int)
128: */
129: public String getURI(int index) {
130: if (index >= 0 && index < length) {
131: return data[index * 5];
132: } else {
133: return null;
134: }
135: }
136:
137: /**
138: * Return an attribute's local name.
139: *
140: * @param index The attribute's index (zero-based).
141: * @return The attribute's local name, the empty string if
142: * none is available, or null if the index if out of range.
143: * @see org.xml.sax.Attributes#getLocalName(int)
144: */
145: public String getLocalName(int index) {
146: if (index >= 0 && index < length) {
147: return data[index * 5 + 1];
148: } else {
149: return null;
150: }
151: }
152:
153: /**
154: * Return an attribute's qualified (prefixed) name.
155: *
156: * @param index The attribute's index (zero-based).
157: * @return The attribute's qualified name, the empty string if
158: * none is available, or null if the index is out of bounds.
159: * @see org.xml.sax.Attributes#getQName(int)
160: */
161: public String getQName(int index) {
162: if (index >= 0 && index < length) {
163: return data[index * 5 + 2];
164: } else {
165: return null;
166: }
167: }
168:
169: /**
170: * Return an attribute's type by index.
171: *
172: * @param index The attribute's index (zero-based).
173: * @return The attribute's type, "CDATA" if the type is unknown, or null
174: * if the index is out of bounds.
175: * @see org.xml.sax.Attributes#getType(int)
176: */
177: public String getType(int index) {
178: if (index >= 0 && index < length) {
179: return data[index * 5 + 3];
180: } else {
181: return null;
182: }
183: }
184:
185: /**
186: * Return an attribute's value by index.
187: *
188: * @param index The attribute's index (zero-based).
189: * @return The attribute's value or null if the index is out of bounds.
190: * @see org.xml.sax.Attributes#getValue(int)
191: */
192: public String getValue(int index) {
193: if (index >= 0 && index < length) {
194: return data[index * 5 + 4];
195: } else {
196: return null;
197: }
198: }
199:
200: /**
201: * Look up an attribute's index by Namespace name.
202: *
203: * <p>In many cases, it will be more efficient to look up the name once and
204: * use the index query methods rather than using the name query methods
205: * repeatedly.</p>
206: *
207: * @param uri The attribute's Namespace URI, or the empty
208: * string if none is available.
209: * @param localName The attribute's local name.
210: * @return The attribute's index, or -1 if none matches.
211: * @see org.xml.sax.Attributes#getIndex(java.lang.String,java.lang.String)
212: */
213: public int getIndex(String uri, String localName) {
214: int max = length * 5;
215: for (int i = 0; i < max; i += 5) {
216: if (data[i].equals(uri) && data[i + 1].equals(localName)) {
217: return i / 5;
218: }
219: }
220: return -1;
221: }
222:
223: /**
224: * Can be used if parameters are interned.
225: */
226: public int getIndexFast(String uri, String localName) {
227: for (int i = (length - 1) * 5; i >= 0; i -= 5) {
228: // local names tend to be different, so test it first
229: if (data[i + 1] == localName && data[i] == uri) {
230: return i / 5;
231: }
232: }
233: return -1;
234: }
235:
236: /**
237: * Look up an attribute's index by qualified (prefixed) name.
238: *
239: * @param qName The qualified name.
240: * @return The attribute's index, or -1 if none matches.
241: * @see org.xml.sax.Attributes#getIndex(java.lang.String)
242: */
243: public int getIndex(String qName) {
244: int max = length * 5;
245: for (int i = 0; i < max; i += 5) {
246: if (data[i + 2].equals(qName)) {
247: return i / 5;
248: }
249: }
250: return -1;
251: }
252:
253: /**
254: * Look up an attribute's type by Namespace-qualified name.
255: *
256: * @param uri The Namespace URI, or the empty string for a name
257: * with no explicit Namespace URI.
258: * @param localName The local name.
259: * @return The attribute's type, or null if there is no
260: * matching attribute.
261: * @see org.xml.sax.Attributes#getType(java.lang.String,java.lang.String)
262: */
263: public String getType(String uri, String localName) {
264: int max = length * 5;
265: for (int i = 0; i < max; i += 5) {
266: if (data[i].equals(uri) && data[i + 1].equals(localName)) {
267: return data[i + 3];
268: }
269: }
270: return null;
271: }
272:
273: /**
274: * Look up an attribute's type by qualified (prefixed) name.
275: *
276: * @param qName The qualified name.
277: * @return The attribute's type, or null if there is no
278: * matching attribute.
279: * @see org.xml.sax.Attributes#getType(java.lang.String)
280: */
281: public String getType(String qName) {
282: int max = length * 5;
283: for (int i = 0; i < max; i += 5) {
284: if (data[i + 2].equals(qName)) {
285: return data[i + 3];
286: }
287: }
288: return null;
289: }
290:
291: /**
292: * Look up an attribute's value by Namespace-qualified name.
293: *
294: * @param uri The Namespace URI, or the empty string for a name
295: * with no explicit Namespace URI.
296: * @param localName The local name.
297: * @return The attribute's value, or null if there is no
298: * matching attribute.
299: * @see org.xml.sax.Attributes#getValue(java.lang.String,java.lang.String)
300: */
301: public String getValue(String uri, String localName) {
302: int max = length * 5;
303: for (int i = 0; i < max; i += 5) {
304: if (data[i].equals(uri) && data[i + 1].equals(localName)) {
305: return data[i + 4];
306: }
307: }
308: return null;
309: }
310:
311: /**
312: * Look up an attribute's value by qualified (prefixed) name.
313: *
314: * @param qName The qualified name.
315: * @return The attribute's value, or null if there is no
316: * matching attribute.
317: * @see org.xml.sax.Attributes#getValue(java.lang.String)
318: */
319: public String getValue(String qName) {
320: int max = length * 5;
321: for (int i = 0; i < max; i += 5) {
322: if (data[i + 2].equals(qName)) {
323: return data[i + 4];
324: }
325: }
326: return null;
327: }
328:
329: ////////////////////////////////////////////////////////////////////
330: // Manipulators.
331: ////////////////////////////////////////////////////////////////////
332:
333: /**
334: * Clear the attribute list for reuse.
335: *
336: * <p>Note that little memory is freed by this call:
337: * the current array is kept so it can be
338: * reused.</p>
339: */
340: public void clear() {
341: if (data != null) {
342: for (int i = 0; i < (length * 5); i++)
343: data[i] = null;
344: }
345: length = 0;
346: }
347:
348: /**
349: * Copy an entire Attributes object.
350: *
351: * <p>It may be more efficient to reuse an existing object
352: * rather than constantly allocating new ones.</p>
353: *
354: * @param atts The attributes to copy.
355: */
356: public void setAttributes(Attributes atts) {
357: clear();
358: length = atts.getLength();
359: if (length > 0) {
360: data = new String[length * 5];
361: for (int i = 0; i < length; i++) {
362: data[i * 5] = atts.getURI(i);
363: data[i * 5 + 1] = atts.getLocalName(i);
364: data[i * 5 + 2] = atts.getQName(i);
365: data[i * 5 + 3] = atts.getType(i);
366: data[i * 5 + 4] = atts.getValue(i);
367: }
368: }
369: }
370:
371: /**
372: * Add an attribute to the end of the list.
373: *
374: * <p>For the sake of speed, this method does no checking
375: * to see if the attribute is already in the list: that is
376: * the responsibility of the application.</p>
377: *
378: * @param uri The Namespace URI, or the empty string if
379: * none is available or Namespace processing is not
380: * being performed.
381: * @param localName The local name, or the empty string if
382: * Namespace processing is not being performed.
383: * @param qName The qualified (prefixed) name, or the empty string
384: * if qualified names are not available.
385: * @param type The attribute type as a string.
386: * @param value The attribute value.
387: */
388: public void addAttribute(String uri, String localName,
389: String qName, String type, String value) {
390: ensureCapacity(length + 1);
391: data[length * 5] = uri;
392: data[length * 5 + 1] = localName;
393: data[length * 5 + 2] = qName;
394: data[length * 5 + 3] = type;
395: data[length * 5 + 4] = value;
396: length++;
397: }
398:
399: /**
400: * Set an attribute in the list.
401: *
402: * <p>For the sake of speed, this method does no checking
403: * for name conflicts or well-formedness: such checks are the
404: * responsibility of the application.</p>
405: *
406: * @param index The index of the attribute (zero-based).
407: * @param uri The Namespace URI, or the empty string if
408: * none is available or Namespace processing is not
409: * being performed.
410: * @param localName The local name, or the empty string if
411: * Namespace processing is not being performed.
412: * @param qName The qualified name, or the empty string
413: * if qualified names are not available.
414: * @param type The attribute type as a string.
415: * @param value The attribute value.
416: * @exception java.lang.ArrayIndexOutOfBoundsException When the
417: * supplied index does not point to an attribute
418: * in the list.
419: */
420: public void setAttribute(int index, String uri, String localName,
421: String qName, String type, String value) {
422: if (index >= 0 && index < length) {
423: data[index * 5] = uri;
424: data[index * 5 + 1] = localName;
425: data[index * 5 + 2] = qName;
426: data[index * 5 + 3] = type;
427: data[index * 5 + 4] = value;
428: } else {
429: badIndex(index);
430: }
431: }
432:
433: /**
434: * Remove an attribute from the list.
435: *
436: * @param index The index of the attribute (zero-based).
437: * @exception java.lang.ArrayIndexOutOfBoundsException When the
438: * supplied index does not point to an attribute
439: * in the list.
440: */
441: public void removeAttribute(int index) {
442: if (index >= 0 && index < length) {
443: if (index < length - 1) {
444: System.arraycopy(data, (index + 1) * 5, data,
445: index * 5, (length - index - 1) * 5);
446: }
447: index = (length - 1) * 5;
448: data[index++] = null;
449: data[index++] = null;
450: data[index++] = null;
451: data[index++] = null;
452: data[index] = null;
453: length--;
454: } else {
455: badIndex(index);
456: }
457: }
458:
459: /**
460: * Set the Namespace URI of a specific attribute.
461: *
462: * @param index The index of the attribute (zero-based).
463: * @param uri The attribute's Namespace URI, or the empty
464: * string for none.
465: * @exception java.lang.ArrayIndexOutOfBoundsException When the
466: * supplied index does not point to an attribute
467: * in the list.
468: */
469: public void setURI(int index, String uri) {
470: if (index >= 0 && index < length) {
471: data[index * 5] = uri;
472: } else {
473: badIndex(index);
474: }
475: }
476:
477: /**
478: * Set the local name of a specific attribute.
479: *
480: * @param index The index of the attribute (zero-based).
481: * @param localName The attribute's local name, or the empty
482: * string for none.
483: * @exception java.lang.ArrayIndexOutOfBoundsException When the
484: * supplied index does not point to an attribute
485: * in the list.
486: */
487: public void setLocalName(int index, String localName) {
488: if (index >= 0 && index < length) {
489: data[index * 5 + 1] = localName;
490: } else {
491: badIndex(index);
492: }
493: }
494:
495: /**
496: * Set the qualified name of a specific attribute.
497: *
498: * @param index The index of the attribute (zero-based).
499: * @param qName The attribute's qualified name, or the empty
500: * string for none.
501: * @exception java.lang.ArrayIndexOutOfBoundsException When the
502: * supplied index does not point to an attribute
503: * in the list.
504: */
505: public void setQName(int index, String qName) {
506: if (index >= 0 && index < length) {
507: data[index * 5 + 2] = qName;
508: } else {
509: badIndex(index);
510: }
511: }
512:
513: /**
514: * Set the type of a specific attribute.
515: *
516: * @param index The index of the attribute (zero-based).
517: * @param type The attribute's type.
518: * @exception java.lang.ArrayIndexOutOfBoundsException When the
519: * supplied index does not point to an attribute
520: * in the list.
521: */
522: public void setType(int index, String type) {
523: if (index >= 0 && index < length) {
524: data[index * 5 + 3] = type;
525: } else {
526: badIndex(index);
527: }
528: }
529:
530: /**
531: * Set the value of a specific attribute.
532: *
533: * @param index The index of the attribute (zero-based).
534: * @param value The attribute's value.
535: * @exception java.lang.ArrayIndexOutOfBoundsException When the
536: * supplied index does not point to an attribute
537: * in the list.
538: */
539: public void setValue(int index, String value) {
540: if (index >= 0 && index < length) {
541: data[index * 5 + 4] = value;
542: } else {
543: badIndex(index);
544: }
545: }
546:
547: ////////////////////////////////////////////////////////////////////
548: // Internal methods.
549: ////////////////////////////////////////////////////////////////////
550:
551: /**
552: * Ensure the internal array's capacity.
553: *
554: * @param n The minimum number of attributes that the array must
555: * be able to hold.
556: */
557: private void ensureCapacity(int n) {
558: if (n <= 0) {
559: return;
560: }
561: int max;
562: if (data == null || data.length == 0) {
563: max = 25;
564: } else if (data.length >= n * 5) {
565: return;
566: } else {
567: max = data.length;
568: }
569: while (max < n * 5) {
570: max *= 2;
571: }
572:
573: String newData[] = new String[max];
574: if (length > 0) {
575: System.arraycopy(data, 0, newData, 0, length * 5);
576: }
577: data = newData;
578: }
579:
580: /**
581: * Report a bad array index in a manipulator.
582: *
583: * @param index The index to report.
584: * @exception java.lang.ArrayIndexOutOfBoundsException Always.
585: */
586: private void badIndex(int index)
587: throws ArrayIndexOutOfBoundsException {
588: String msg = "Attempt to modify attribute at illegal index: "
589: + index;
590: throw new ArrayIndexOutOfBoundsException(msg);
591: }
592:
593: ////////////////////////////////////////////////////////////////////
594: // Internal state.
595: ////////////////////////////////////////////////////////////////////
596:
597: int length;
598: String data[];
599:
600: }
601:
602: // end of AttributesImpl.java
|