Thu, 31 Aug 2017 15:18:52 +0800
merge
1 /*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 // AttributesImpl.java - default implementation of Attributes.
27 // http://www.saxproject.org
28 // Written by David Megginson
29 // NO WARRANTY! This class is in the public domain.
30 package com.sun.xml.internal.bind.util;
32 import org.xml.sax.Attributes;
35 /**
36 * Default implementation of the Attributes interface.
37 *
38 * <blockquote>
39 * <em>This module, both source code and documentation, is in the
40 * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
41 * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
42 * for further information.
43 * </blockquote>
44 *
45 * <p>This class provides a default implementation of the SAX2
46 * {@link org.xml.sax.Attributes Attributes} interface, with the
47 * addition of manipulators so that the list can be modified or
48 * reused.</p>
49 *
50 * <p>There are two typical uses of this class:</p>
51 *
52 * <ol>
53 * <li>to take a persistent snapshot of an Attributes object
54 * in a {@link org.xml.sax.ContentHandler#startElement startElement} event; or</li>
55 * <li>to construct or modify an Attributes object in a SAX2 driver or filter.</li>
56 * </ol>
57 *
58 * <p>This class replaces the now-deprecated SAX1 {@link
59 * org.xml.sax.helpers.AttributeListImpl AttributeListImpl}
60 * class; in addition to supporting the updated Attributes
61 * interface rather than the deprecated {@link org.xml.sax.AttributeList
62 * AttributeList} interface, it also includes a much more efficient
63 * implementation using a single array rather than a set of Vectors.</p>
64 *
65 * @since JAXB1.0
66 * @since SAX 2.0
67 * @author David Megginson
68 * @version 2.0.1 (sax2r2)
69 */
70 public class AttributesImpl implements Attributes
71 {
74 ////////////////////////////////////////////////////////////////////
75 // Constructors.
76 ////////////////////////////////////////////////////////////////////
79 /**
80 * Construct a new, empty AttributesImpl object.
81 */
82 public AttributesImpl ()
83 {
84 length = 0;
85 data = null;
86 }
89 /**
90 * Copy an existing Attributes object.
91 *
92 * <p>This constructor is especially useful inside a
93 * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
94 *
95 * @param atts The existing Attributes object.
96 */
97 public AttributesImpl (Attributes atts)
98 {
99 setAttributes(atts);
100 }
104 ////////////////////////////////////////////////////////////////////
105 // Implementation of org.xml.sax.Attributes.
106 ////////////////////////////////////////////////////////////////////
109 /**
110 * Return the number of attributes in the list.
111 *
112 * @return The number of attributes in the list.
113 * @see org.xml.sax.Attributes#getLength()
114 */
115 public int getLength ()
116 {
117 return length;
118 }
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 {
131 if (index >= 0 && index < length) {
132 return data[index*5];
133 } else {
134 return null;
135 }
136 }
139 /**
140 * Return an attribute's local name.
141 *
142 * @param index The attribute's index (zero-based).
143 * @return The attribute's local name, the empty string if
144 * none is available, or null if the index if out of range.
145 * @see org.xml.sax.Attributes#getLocalName(int)
146 */
147 public String getLocalName (int index)
148 {
149 if (index >= 0 && index < length) {
150 return data[index*5+1];
151 } else {
152 return null;
153 }
154 }
157 /**
158 * Return an attribute's qualified (prefixed) name.
159 *
160 * @param index The attribute's index (zero-based).
161 * @return The attribute's qualified name, the empty string if
162 * none is available, or null if the index is out of bounds.
163 * @see org.xml.sax.Attributes#getQName(int)
164 */
165 public String getQName (int index)
166 {
167 if (index >= 0 && index < length) {
168 return data[index*5+2];
169 } else {
170 return null;
171 }
172 }
175 /**
176 * Return an attribute's type by index.
177 *
178 * @param index The attribute's index (zero-based).
179 * @return The attribute's type, "CDATA" if the type is unknown, or null
180 * if the index is out of bounds.
181 * @see org.xml.sax.Attributes#getType(int)
182 */
183 public String getType (int index)
184 {
185 if (index >= 0 && index < length) {
186 return data[index*5+3];
187 } else {
188 return null;
189 }
190 }
193 /**
194 * Return an attribute's value by index.
195 *
196 * @param index The attribute's index (zero-based).
197 * @return The attribute's value or null if the index is out of bounds.
198 * @see org.xml.sax.Attributes#getValue(int)
199 */
200 public String getValue (int index)
201 {
202 if (index >= 0 && index < length) {
203 return data[index*5+4];
204 } else {
205 return null;
206 }
207 }
210 /**
211 * Look up an attribute's index by Namespace name.
212 *
213 * <p>In many cases, it will be more efficient to look up the name once and
214 * use the index query methods rather than using the name query methods
215 * repeatedly.</p>
216 *
217 * @param uri The attribute's Namespace URI, or the empty
218 * string if none is available.
219 * @param localName The attribute's local name.
220 * @return The attribute's index, or -1 if none matches.
221 * @see org.xml.sax.Attributes#getIndex(java.lang.String,java.lang.String)
222 */
223 public int getIndex (String uri, String localName)
224 {
225 int max = length * 5;
226 for (int i = 0; i < max; i += 5) {
227 if (data[i].equals(uri) && data[i+1].equals(localName)) {
228 return i / 5;
229 }
230 }
231 return -1;
232 }
234 /**
235 * Can be used if parameters are interned.
236 */
237 public int getIndexFast(String uri, String localName) {
238 for (int i = (length-1)*5; i>=0; i-=5) {
239 // local names tend to be different, so test it first
240 if (data[i + 1] == localName && data[i] == uri ) {
241 return i / 5;
242 }
243 }
244 return -1;
245 }
248 /**
249 * Look up an attribute's index by qualified (prefixed) name.
250 *
251 * @param qName The qualified name.
252 * @return The attribute's index, or -1 if none matches.
253 * @see org.xml.sax.Attributes#getIndex(java.lang.String)
254 */
255 public int getIndex (String qName)
256 {
257 int max = length * 5;
258 for (int i = 0; i < max; i += 5) {
259 if (data[i+2].equals(qName)) {
260 return i / 5;
261 }
262 }
263 return -1;
264 }
267 /**
268 * Look up an attribute's type by Namespace-qualified name.
269 *
270 * @param uri The Namespace URI, or the empty string for a name
271 * with no explicit Namespace URI.
272 * @param localName The local name.
273 * @return The attribute's type, or null if there is no
274 * matching attribute.
275 * @see org.xml.sax.Attributes#getType(java.lang.String,java.lang.String)
276 */
277 public String getType (String uri, String localName)
278 {
279 int max = length * 5;
280 for (int i = 0; i < max; i += 5) {
281 if (data[i].equals(uri) && data[i+1].equals(localName)) {
282 return data[i+3];
283 }
284 }
285 return null;
286 }
289 /**
290 * Look up an attribute's type by qualified (prefixed) name.
291 *
292 * @param qName The qualified name.
293 * @return The attribute's type, or null if there is no
294 * matching attribute.
295 * @see org.xml.sax.Attributes#getType(java.lang.String)
296 */
297 public String getType (String qName)
298 {
299 int max = length * 5;
300 for (int i = 0; i < max; i += 5) {
301 if (data[i+2].equals(qName)) {
302 return data[i+3];
303 }
304 }
305 return null;
306 }
309 /**
310 * Look up an attribute's value by Namespace-qualified name.
311 *
312 * @param uri The Namespace URI, or the empty string for a name
313 * with no explicit Namespace URI.
314 * @param localName The local 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,java.lang.String)
318 */
319 public String getValue (String uri, String localName)
320 {
321 int max = length * 5;
322 for (int i = 0; i < max; i += 5) {
323 if (data[i].equals(uri) && data[i+1].equals(localName)) {
324 return data[i+4];
325 }
326 }
327 return null;
328 }
331 /**
332 * Look up an attribute's value by qualified (prefixed) name.
333 *
334 * @param qName The qualified name.
335 * @return The attribute's value, or null if there is no
336 * matching attribute.
337 * @see org.xml.sax.Attributes#getValue(java.lang.String)
338 */
339 public String getValue (String qName)
340 {
341 int max = length * 5;
342 for (int i = 0; i < max; i += 5) {
343 if (data[i+2].equals(qName)) {
344 return data[i+4];
345 }
346 }
347 return null;
348 }
352 ////////////////////////////////////////////////////////////////////
353 // Manipulators.
354 ////////////////////////////////////////////////////////////////////
357 /**
358 * Clear the attribute list for reuse.
359 *
360 * <p>Note that little memory is freed by this call:
361 * the current array is kept so it can be
362 * reused.</p>
363 */
364 public void clear ()
365 {
366 if (data != null) {
367 for (int i = 0; i < (length * 5); i++)
368 data [i] = null;
369 }
370 length = 0;
371 }
374 /**
375 * Copy an entire Attributes object.
376 *
377 * <p>It may be more efficient to reuse an existing object
378 * rather than constantly allocating new ones.</p>
379 *
380 * @param atts The attributes to copy.
381 */
382 public void setAttributes (Attributes atts)
383 {
384 clear();
385 length = atts.getLength();
386 if (length > 0) {
387 data = new String[length*5];
388 for (int i = 0; i < length; i++) {
389 data[i*5] = atts.getURI(i);
390 data[i*5+1] = atts.getLocalName(i);
391 data[i*5+2] = atts.getQName(i);
392 data[i*5+3] = atts.getType(i);
393 data[i*5+4] = atts.getValue(i);
394 }
395 }
396 }
399 /**
400 * Add an attribute to the end of the list.
401 *
402 * <p>For the sake of speed, this method does no checking
403 * to see if the attribute is already in the list: that is
404 * the responsibility of the application.</p>
405 *
406 * @param uri The Namespace URI, or the empty string if
407 * none is available or Namespace processing is not
408 * being performed.
409 * @param localName The local name, or the empty string if
410 * Namespace processing is not being performed.
411 * @param qName The qualified (prefixed) name, or the empty string
412 * if qualified names are not available.
413 * @param type The attribute type as a string.
414 * @param value The attribute value.
415 */
416 public void addAttribute (String uri, String localName, String qName,
417 String type, String value)
418 {
419 ensureCapacity(length+1);
420 data[length*5] = uri;
421 data[length*5+1] = localName;
422 data[length*5+2] = qName;
423 data[length*5+3] = type;
424 data[length*5+4] = value;
425 length++;
426 }
429 /**
430 * Set an attribute in the list.
431 *
432 * <p>For the sake of speed, this method does no checking
433 * for name conflicts or well-formedness: such checks are the
434 * responsibility of the application.</p>
435 *
436 * @param index The index of the attribute (zero-based).
437 * @param uri The Namespace URI, or the empty string if
438 * none is available or Namespace processing is not
439 * being performed.
440 * @param localName The local name, or the empty string if
441 * Namespace processing is not being performed.
442 * @param qName The qualified name, or the empty string
443 * if qualified names are not available.
444 * @param type The attribute type as a string.
445 * @param value The attribute value.
446 * @exception java.lang.ArrayIndexOutOfBoundsException When the
447 * supplied index does not point to an attribute
448 * in the list.
449 */
450 public void setAttribute (int index, String uri, String localName,
451 String qName, String type, String value)
452 {
453 if (index >= 0 && index < length) {
454 data[index*5] = uri;
455 data[index*5+1] = localName;
456 data[index*5+2] = qName;
457 data[index*5+3] = type;
458 data[index*5+4] = value;
459 } else {
460 badIndex(index);
461 }
462 }
465 /**
466 * Remove an attribute from the list.
467 *
468 * @param index The index of the attribute (zero-based).
469 * @exception java.lang.ArrayIndexOutOfBoundsException When the
470 * supplied index does not point to an attribute
471 * in the list.
472 */
473 public void removeAttribute (int index)
474 {
475 if (index >= 0 && index < length) {
476 if (index < length - 1) {
477 System.arraycopy(data, (index+1)*5, data, index*5,
478 (length-index-1)*5);
479 }
480 index = (length - 1) * 5;
481 data [index++] = null;
482 data [index++] = null;
483 data [index++] = null;
484 data [index++] = null;
485 data [index] = null;
486 length--;
487 } else {
488 badIndex(index);
489 }
490 }
493 /**
494 * Set the Namespace URI of a specific attribute.
495 *
496 * @param index The index of the attribute (zero-based).
497 * @param uri The attribute's Namespace URI, or the empty
498 * string for none.
499 * @exception java.lang.ArrayIndexOutOfBoundsException When the
500 * supplied index does not point to an attribute
501 * in the list.
502 */
503 public void setURI (int index, String uri)
504 {
505 if (index >= 0 && index < length) {
506 data[index*5] = uri;
507 } else {
508 badIndex(index);
509 }
510 }
513 /**
514 * Set the local name of a specific attribute.
515 *
516 * @param index The index of the attribute (zero-based).
517 * @param localName The attribute's local name, or the empty
518 * string for none.
519 * @exception java.lang.ArrayIndexOutOfBoundsException When the
520 * supplied index does not point to an attribute
521 * in the list.
522 */
523 public void setLocalName (int index, String localName)
524 {
525 if (index >= 0 && index < length) {
526 data[index*5+1] = localName;
527 } else {
528 badIndex(index);
529 }
530 }
533 /**
534 * Set the qualified name of a specific attribute.
535 *
536 * @param index The index of the attribute (zero-based).
537 * @param qName The attribute's qualified name, or the empty
538 * string for none.
539 * @exception java.lang.ArrayIndexOutOfBoundsException When the
540 * supplied index does not point to an attribute
541 * in the list.
542 */
543 public void setQName (int index, String qName)
544 {
545 if (index >= 0 && index < length) {
546 data[index*5+2] = qName;
547 } else {
548 badIndex(index);
549 }
550 }
553 /**
554 * Set the type of a specific attribute.
555 *
556 * @param index The index of the attribute (zero-based).
557 * @param type The attribute's type.
558 * @exception java.lang.ArrayIndexOutOfBoundsException When the
559 * supplied index does not point to an attribute
560 * in the list.
561 */
562 public void setType (int index, String type)
563 {
564 if (index >= 0 && index < length) {
565 data[index*5+3] = type;
566 } else {
567 badIndex(index);
568 }
569 }
572 /**
573 * Set the value of a specific attribute.
574 *
575 * @param index The index of the attribute (zero-based).
576 * @param value The attribute's value.
577 * @exception java.lang.ArrayIndexOutOfBoundsException When the
578 * supplied index does not point to an attribute
579 * in the list.
580 */
581 public void setValue (int index, String value)
582 {
583 if (index >= 0 && index < length) {
584 data[index*5+4] = value;
585 } else {
586 badIndex(index);
587 }
588 }
592 ////////////////////////////////////////////////////////////////////
593 // Internal methods.
594 ////////////////////////////////////////////////////////////////////
597 /**
598 * Ensure the internal array's capacity.
599 *
600 * @param n The minimum number of attributes that the array must
601 * be able to hold.
602 */
603 private void ensureCapacity (int n) {
604 if (n <= 0) {
605 return;
606 }
607 int max;
608 if (data == null || data.length == 0) {
609 max = 25;
610 }
611 else if (data.length >= n * 5) {
612 return;
613 }
614 else {
615 max = data.length;
616 }
617 while (max < n * 5) {
618 max *= 2;
619 }
621 String newData[] = new String[max];
622 if (length > 0) {
623 System.arraycopy(data, 0, newData, 0, length*5);
624 }
625 data = newData;
626 }
629 /**
630 * Report a bad array index in a manipulator.
631 *
632 * @param index The index to report.
633 * @exception java.lang.ArrayIndexOutOfBoundsException Always.
634 */
635 private void badIndex (int index)
636 throws ArrayIndexOutOfBoundsException
637 {
638 String msg =
639 "Attempt to modify attribute at illegal index: " + index;
640 throw new ArrayIndexOutOfBoundsException(msg);
641 }
645 ////////////////////////////////////////////////////////////////////
646 // Internal state.
647 ////////////////////////////////////////////////////////////////////
649 int length;
650 String data [];
652 }
654 // end of AttributesImpl.java