Mon, 20 Apr 2009 15:14:39 -0700
6831313: update jaxws in OpenJDK7 to 2.1 plus bug fixes from OpenJDK 6
6672868: Package javax.xml.ws.wsaddressing not included in make/docs/CORE_PKGS.gmk
Reviewed-by: darcy
1 /*
2 * Copyright 2005-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25 package com.sun.xml.internal.bind.v2.runtime.output;
27 import java.io.IOException;
28 import java.io.OutputStream;
30 import javax.xml.stream.XMLStreamException;
32 import com.sun.xml.internal.bind.DatatypeConverterImpl;
33 import com.sun.xml.internal.bind.v2.runtime.Name;
34 import com.sun.xml.internal.bind.v2.runtime.XMLSerializer;
36 import org.xml.sax.SAXException;
38 /**
39 * {@link XmlOutput} implementation specialized for UTF-8.
40 *
41 * @author Kohsuke Kawaguchi
42 * @author Paul Sandoz
43 */
44 public class UTF8XmlOutput extends XmlOutputAbstractImpl {
45 protected final OutputStream out;
47 /** prefixes encoded. */
48 private Encoded[] prefixes = new Encoded[8];
50 /**
51 * Of the {@link #prefixes}, number of filled entries.
52 * This is almost the same as {@link NamespaceContextImpl#count()},
53 * except that it allows us to handle contextual in-scope namespace bindings correctly.
54 */
55 private int prefixCount;
57 /** local names encoded in UTF-8. All entries are pre-filled. */
58 private final Encoded[] localNames;
60 /** Temporary buffer used to encode text. */
61 /*
62 * TODO
63 * The textBuffer could write directly to the _octetBuffer
64 * when encoding a string if Encoder is modified.
65 * This will avoid an additional memory copy.
66 */
67 private final Encoded textBuffer = new Encoded();
69 /** Buffer of octets for writing. */
70 // TODO: Obtain buffer size from property on the JAXB context
71 protected final byte[] octetBuffer = new byte[1024];
73 /** Index in buffer to write to. */
74 protected int octetBufferIndex;
76 /**
77 * Set to true to indicate that we need to write '>'
78 * to close a start tag. Deferring the write of this char
79 * allows us to write "/>" for empty elements.
80 */
81 protected boolean closeStartTagPending = false;
83 /**
84 *
85 * @param localNames
86 * local names encoded in UTF-8.
87 */
88 public UTF8XmlOutput(OutputStream out, Encoded[] localNames) {
89 this.out = out;
90 this.localNames = localNames;
91 for( int i=0; i<prefixes.length; i++ )
92 prefixes[i] = new Encoded();
93 }
95 @Override
96 public void startDocument(XMLSerializer serializer, boolean fragment, int[] nsUriIndex2prefixIndex, NamespaceContextImpl nsContext) throws IOException, SAXException, XMLStreamException {
97 super.startDocument(serializer, fragment,nsUriIndex2prefixIndex,nsContext);
99 octetBufferIndex = 0;
100 if(!fragment) {
101 write(XML_DECL);
102 }
103 }
105 public void endDocument(boolean fragment) throws IOException, SAXException, XMLStreamException {
106 flushBuffer();
107 super.endDocument(fragment);
108 }
110 /**
111 * Writes '>' to close the start tag, if necessary.
112 */
113 protected final void closeStartTag() throws IOException {
114 if(closeStartTagPending) {
115 write('>');
116 closeStartTagPending = false;
117 }
118 }
120 public void beginStartTag(int prefix, String localName) throws IOException {
121 closeStartTag();
122 int base= pushNsDecls();
123 write('<');
124 writeName(prefix,localName);
125 writeNsDecls(base);
126 }
128 public void beginStartTag(Name name) throws IOException {
129 closeStartTag();
130 int base = pushNsDecls();
131 write('<');
132 writeName(name);
133 writeNsDecls(base);
134 }
136 private int pushNsDecls() {
137 int total = nsContext.count();
138 NamespaceContextImpl.Element ns = nsContext.getCurrent();
140 if(total > prefixes.length) {
141 // reallocate
142 int m = Math.max(total,prefixes.length*2);
143 Encoded[] buf = new Encoded[m];
144 System.arraycopy(prefixes,0,buf,0,prefixes.length);
145 for( int i=prefixes.length; i<buf.length; i++ )
146 buf[i] = new Encoded();
147 prefixes = buf;
148 }
150 int base = Math.min(prefixCount,ns.getBase());
151 int size = nsContext.count();
152 for( int i=base; i<size; i++ ) {
153 String p = nsContext.getPrefix(i);
155 Encoded e = prefixes[i];
157 if(p.length()==0) {
158 e.buf = EMPTY_BYTE_ARRAY;
159 e.len = 0;
160 } else {
161 e.set(p);
162 e.append(':');
163 }
164 }
165 prefixCount = size;
166 return base;
167 }
169 protected void writeNsDecls(int base) throws IOException {
170 NamespaceContextImpl.Element ns = nsContext.getCurrent();
171 int size = nsContext.count();
173 for( int i=ns.getBase(); i<size; i++ )
174 writeNsDecl(i);
175 }
177 /**
178 * Writes a single namespace declaration for the specified prefix.
179 */
180 protected final void writeNsDecl(int prefixIndex) throws IOException {
181 String p = nsContext.getPrefix(prefixIndex);
183 if(p.length()==0) {
184 if(nsContext.getCurrent().isRootElement()
185 && nsContext.getNamespaceURI(prefixIndex).length()==0)
186 return; // no point in declaring xmlns="" on the root element
187 write(XMLNS_EQUALS);
188 } else {
189 Encoded e = prefixes[prefixIndex];
190 write(XMLNS_COLON);
191 write(e.buf,0,e.len-1); // skip the trailing ':'
192 write(EQUALS);
193 }
194 doText(nsContext.getNamespaceURI(prefixIndex),true);
195 write('\"');
196 }
198 private void writePrefix(int prefix) throws IOException {
199 prefixes[prefix].write(this);
200 }
202 private void writeName(Name name) throws IOException {
203 writePrefix(nsUriIndex2prefixIndex[name.nsUriIndex]);
204 localNames[name.localNameIndex].write(this);
205 }
207 private void writeName(int prefix, String localName) throws IOException {
208 writePrefix(prefix);
209 textBuffer.set(localName);
210 textBuffer.write(this);
211 }
213 @Override
214 public void attribute(Name name, String value) throws IOException {
215 write(' ');
216 if(name.nsUriIndex==-1) {
217 localNames[name.localNameIndex].write(this);
218 } else
219 writeName(name);
220 write(EQUALS);
221 doText(value,true);
222 write('\"');
223 }
225 public void attribute(int prefix, String localName, String value) throws IOException {
226 write(' ');
227 if(prefix==-1) {
228 textBuffer.set(localName);
229 textBuffer.write(this);
230 } else
231 writeName(prefix,localName);
232 write(EQUALS);
233 doText(value,true);
234 write('\"');
235 }
237 public void endStartTag() throws IOException {
238 closeStartTagPending = true;
239 }
241 @Override
242 public void endTag(Name name) throws IOException {
243 if(closeStartTagPending) {
244 write(EMPTY_TAG);
245 closeStartTagPending = false;
246 } else {
247 write(CLOSE_TAG);
248 writeName(name);
249 write('>');
250 }
251 }
253 public void endTag(int prefix, String localName) throws IOException {
254 if(closeStartTagPending) {
255 write(EMPTY_TAG);
256 closeStartTagPending = false;
257 } else {
258 write(CLOSE_TAG);
259 writeName(prefix,localName);
260 write('>');
261 }
262 }
264 public void text(String value, boolean needSP) throws IOException {
265 closeStartTag();
266 if(needSP)
267 write(' ');
268 doText(value,false);
269 }
271 public void text(Pcdata value, boolean needSP) throws IOException {
272 closeStartTag();
273 if(needSP)
274 write(' ');
275 value.writeTo(this);
276 }
278 private void doText(String value,boolean isAttribute) throws IOException {
279 textBuffer.setEscape(value,isAttribute);
280 textBuffer.write(this);
281 }
283 public final void text(int value) throws IOException {
284 closeStartTag();
285 /*
286 * TODO
287 * Change to use the octet buffer directly
288 */
290 // max is -2147483648 and 11 digits
291 boolean minus = (value<0);
292 textBuffer.ensureSize(11);
293 byte[] buf = textBuffer.buf;
294 int idx = 11;
296 do {
297 int r = value%10;
298 if(r<0) r = -r;
299 buf[--idx] = (byte)('0'|r); // really measn 0x30+r but 0<=r<10, so bit-OR would do.
300 value /= 10;
301 } while(value!=0);
303 if(minus) buf[--idx] = (byte)'-';
305 write(buf,idx,11-idx);
306 }
308 /**
309 * Writes the given byte[] as base64 encoded binary to the output.
310 *
311 * <p>
312 * Being defined on this class allows this method to access the buffer directly,
313 * which translates to a better performance.
314 */
315 public void text(byte[] data, int dataLen) throws IOException {
316 closeStartTag();
318 int start = 0;
320 while(dataLen>0) {
321 // how many bytes (in data) can we write without overflowing the buffer?
322 int batchSize = Math.min(((octetBuffer.length-octetBufferIndex)/4)*3,dataLen);
324 // write the batch
325 octetBufferIndex = DatatypeConverterImpl._printBase64Binary(data,start,batchSize,octetBuffer,octetBufferIndex);
327 if(batchSize<dataLen)
328 flushBuffer();
330 start += batchSize;
331 dataLen -= batchSize;
333 }
334 }
336 //
337 //
338 // series of the write method that places bytes to the output
339 // (by doing some buffering internal to this class)
340 //
342 /**
343 * Writes one byte directly into the buffer.
344 *
345 * <p>
346 * This method can be used somewhat like the {@code text} method,
347 * but it doesn't perform character escaping.
348 */
349 public final void write(int i) throws IOException {
350 if (octetBufferIndex < octetBuffer.length) {
351 octetBuffer[octetBufferIndex++] = (byte)i;
352 } else {
353 out.write(octetBuffer);
354 octetBufferIndex = 1;
355 octetBuffer[0] = (byte)i;
356 }
357 }
359 protected final void write(byte[] b) throws IOException {
360 write(b, 0, b.length);
361 }
363 protected final void write(byte[] b, int start, int length) throws IOException {
364 if ((octetBufferIndex + length) < octetBuffer.length) {
365 System.arraycopy(b, start, octetBuffer, octetBufferIndex, length);
366 octetBufferIndex += length;
367 } else {
368 out.write(octetBuffer, 0, octetBufferIndex);
369 out.write(b, start, length);
370 octetBufferIndex = 0;
371 }
372 }
374 protected final void flushBuffer() throws IOException {
375 out.write(octetBuffer, 0, octetBufferIndex);
376 octetBufferIndex = 0;
377 }
379 static byte[] toBytes(String s) {
380 byte[] buf = new byte[s.length()];
381 for( int i=s.length()-1; i>=0; i-- )
382 buf[i] = (byte)s.charAt(i);
383 return buf;
384 }
386 private static final byte[] XMLNS_EQUALS = toBytes(" xmlns=\"");
387 private static final byte[] XMLNS_COLON = toBytes(" xmlns:");
388 private static final byte[] EQUALS = toBytes("=\"");
389 private static final byte[] CLOSE_TAG = toBytes("</");
390 private static final byte[] EMPTY_TAG = toBytes("/>");
391 private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
392 private static final byte[] XML_DECL = toBytes("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
393 }