PageRenderTime 43ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/core/petra/petra-io/src/test/java/com/liferay/petra/io/OutputStreamWriterTest.java

http://github.com/liferay/liferay-portal
Java | 822 lines | 554 code | 233 blank | 35 comment | 8 complexity | c35bf8de89cf010eb5186da87e23c53e MD5 | raw file
Possible License(s): LGPL-2.0
  1. /**
  2. * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
  3. *
  4. * This library is free software; you can redistribute it and/or modify it under
  5. * the terms of the GNU Lesser General Public License as published by the Free
  6. * Software Foundation; either version 2.1 of the License, or (at your option)
  7. * any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  12. * details.
  13. */
  14. package com.liferay.petra.io;
  15. import com.liferay.petra.io.unsync.UnsyncByteArrayOutputStream;
  16. import com.liferay.petra.reflect.ReflectionUtil;
  17. import com.liferay.petra.string.StringPool;
  18. import com.liferay.portal.kernel.test.ReflectionTestUtil;
  19. import com.liferay.portal.kernel.test.rule.AggregateTestRule;
  20. import com.liferay.portal.kernel.test.rule.CodeCoverageAssertor;
  21. import com.liferay.portal.test.rule.LiferayUnitTestRule;
  22. import java.io.IOException;
  23. import java.io.OutputStream;
  24. import java.nio.ByteBuffer;
  25. import java.nio.CharBuffer;
  26. import java.nio.charset.CharsetEncoder;
  27. import java.nio.charset.CoderResult;
  28. import java.nio.charset.CodingErrorAction;
  29. import java.nio.charset.MalformedInputException;
  30. import java.nio.charset.UnmappableCharacterException;
  31. import java.util.Arrays;
  32. import java.util.concurrent.atomic.AtomicBoolean;
  33. import java.util.concurrent.atomic.AtomicInteger;
  34. import org.junit.Assert;
  35. import org.junit.ClassRule;
  36. import org.junit.Rule;
  37. import org.junit.Test;
  38. /**
  39. * @author Shuyang Zhou
  40. */
  41. public class OutputStreamWriterTest {
  42. @ClassRule
  43. @Rule
  44. public static final AggregateTestRule aggregateTestRule =
  45. new AggregateTestRule(
  46. CodeCoverageAssertor.INSTANCE, LiferayUnitTestRule.INSTANCE);
  47. @Test
  48. public void testClose() throws IOException {
  49. // Normal close
  50. MarkerOutputStream markerOutputStream = new MarkerOutputStream();
  51. try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
  52. markerOutputStream)) {
  53. Assert.assertFalse(markerOutputStream._closed);
  54. outputStreamWriter.close();
  55. Assert.assertTrue(markerOutputStream._closed);
  56. markerOutputStream._closed = false;
  57. try {
  58. outputStreamWriter.write(0);
  59. Assert.fail();
  60. }
  61. catch (IOException ioException) {
  62. Assert.assertEquals("Stream closed", ioException.getMessage());
  63. }
  64. }
  65. Assert.assertFalse(markerOutputStream._closed);
  66. // Exception close
  67. final IOException ioException1 = new IOException();
  68. OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
  69. new UnsyncByteArrayOutputStream() {
  70. @Override
  71. public void close() throws IOException {
  72. throw ioException1;
  73. }
  74. });
  75. // First close
  76. try {
  77. outputStreamWriter.close();
  78. Assert.fail();
  79. }
  80. catch (IOException ioException2) {
  81. Assert.assertSame(ioException2, ioException1);
  82. }
  83. // Second close to check first close indeed changed the state
  84. outputStreamWriter.close();
  85. }
  86. @Test
  87. public void testConstructor() {
  88. DummyOutputStream dummyOutputStream = new DummyOutputStream();
  89. OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
  90. dummyOutputStream);
  91. Assert.assertSame(
  92. dummyOutputStream, _getOutputStream(outputStreamWriter));
  93. Assert.assertSame(
  94. StringPool.DEFAULT_CHARSET_NAME, outputStreamWriter.getEncoding());
  95. Assert.assertEquals(
  96. _getDefaultOutputBufferSize(),
  97. _getOutputBufferSize(outputStreamWriter));
  98. Assert.assertFalse(_isAutoFlush(outputStreamWriter));
  99. outputStreamWriter = new OutputStreamWriter(dummyOutputStream, null);
  100. Assert.assertSame(
  101. dummyOutputStream, _getOutputStream(outputStreamWriter));
  102. Assert.assertSame(
  103. StringPool.DEFAULT_CHARSET_NAME, outputStreamWriter.getEncoding());
  104. Assert.assertEquals(
  105. _getDefaultOutputBufferSize(),
  106. _getOutputBufferSize(outputStreamWriter));
  107. Assert.assertFalse(_isAutoFlush(outputStreamWriter));
  108. String encoding = "US-ASCII";
  109. outputStreamWriter = new OutputStreamWriter(
  110. dummyOutputStream, encoding);
  111. Assert.assertSame(
  112. dummyOutputStream, _getOutputStream(outputStreamWriter));
  113. Assert.assertSame(encoding, outputStreamWriter.getEncoding());
  114. Assert.assertEquals(
  115. _getDefaultOutputBufferSize(),
  116. _getOutputBufferSize(outputStreamWriter));
  117. Assert.assertFalse(_isAutoFlush(outputStreamWriter));
  118. outputStreamWriter = new OutputStreamWriter(
  119. dummyOutputStream, encoding, true);
  120. Assert.assertSame(
  121. dummyOutputStream, _getOutputStream(outputStreamWriter));
  122. Assert.assertSame(encoding, outputStreamWriter.getEncoding());
  123. Assert.assertEquals(
  124. _getDefaultOutputBufferSize(),
  125. _getOutputBufferSize(outputStreamWriter));
  126. Assert.assertTrue(_isAutoFlush(outputStreamWriter));
  127. outputStreamWriter = new OutputStreamWriter(
  128. dummyOutputStream, encoding, 32);
  129. Assert.assertSame(
  130. dummyOutputStream, _getOutputStream(outputStreamWriter));
  131. Assert.assertSame(encoding, outputStreamWriter.getEncoding());
  132. Assert.assertEquals(2, _getInputCharBufferSize(outputStreamWriter));
  133. Assert.assertEquals(32, _getOutputBufferSize(outputStreamWriter));
  134. Assert.assertFalse(_isAutoFlush(outputStreamWriter));
  135. outputStreamWriter = new OutputStreamWriter(
  136. dummyOutputStream, encoding, 32, true);
  137. Assert.assertSame(
  138. dummyOutputStream, _getOutputStream(outputStreamWriter));
  139. Assert.assertSame(encoding, outputStreamWriter.getEncoding());
  140. Assert.assertEquals(2, _getInputCharBufferSize(outputStreamWriter));
  141. Assert.assertEquals(32, _getOutputBufferSize(outputStreamWriter));
  142. Assert.assertTrue(_isAutoFlush(outputStreamWriter));
  143. try {
  144. new OutputStreamWriter(dummyOutputStream, encoding, 3, true);
  145. Assert.fail();
  146. }
  147. catch (IllegalArgumentException illegalArgumentException) {
  148. Assert.assertEquals(
  149. "Output buffer size 3 is less than 4",
  150. illegalArgumentException.getMessage());
  151. }
  152. }
  153. @Test
  154. public void testFlush() throws IOException {
  155. MarkerOutputStream markerOutputStream = new MarkerOutputStream();
  156. OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
  157. markerOutputStream);
  158. Assert.assertFalse(markerOutputStream._flushed);
  159. outputStreamWriter.flush();
  160. Assert.assertTrue(markerOutputStream._flushed);
  161. outputStreamWriter.write('a');
  162. outputStreamWriter.flush();
  163. Assert.assertTrue(markerOutputStream._flushed);
  164. }
  165. @Test
  166. public void testFlushEncoder() throws IOException {
  167. MarkerOutputStream markerOutputStream = new MarkerOutputStream();
  168. OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
  169. markerOutputStream);
  170. // Flush encoder overflow
  171. final AtomicInteger flushCounter = new AtomicInteger();
  172. ReflectionTestUtil.setFieldValue(
  173. outputStreamWriter, "_charsetEncoder",
  174. new CharsetEncoderWrapper(
  175. ReflectionTestUtil.getFieldValue(
  176. outputStreamWriter, "_charsetEncoder")) {
  177. @Override
  178. protected CoderResult implFlush(ByteBuffer out) {
  179. int count = flushCounter.getAndIncrement();
  180. if (count == 0) {
  181. return CoderResult.OVERFLOW;
  182. }
  183. return super.implFlush(out);
  184. }
  185. });
  186. outputStreamWriter.close();
  187. Assert.assertEquals(2, flushCounter.get());
  188. // Flush encoder error
  189. outputStreamWriter = new OutputStreamWriter(markerOutputStream);
  190. ReflectionTestUtil.setFieldValue(
  191. outputStreamWriter, "_charsetEncoder",
  192. new CharsetEncoderWrapper(
  193. ReflectionTestUtil.getFieldValue(
  194. outputStreamWriter, "_charsetEncoder")) {
  195. @Override
  196. protected CoderResult implFlush(ByteBuffer out) {
  197. return CoderResult.malformedForLength(1);
  198. }
  199. });
  200. try {
  201. outputStreamWriter.close();
  202. }
  203. catch (MalformedInputException malformedInputException) {
  204. Assert.assertEquals(1, malformedInputException.getInputLength());
  205. }
  206. }
  207. @Test
  208. public void testWriteCharArray() throws IOException {
  209. _testWriteCharArray(false);
  210. _testWriteCharArray(true);
  211. }
  212. @Test
  213. public void testWriteError() throws IOException {
  214. OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
  215. new DummyOutputStream(), "US-ASCII");
  216. CharsetEncoder charsetEncoder = ReflectionTestUtil.getFieldValue(
  217. outputStreamWriter, "_charsetEncoder");
  218. charsetEncoder.onUnmappableCharacter(CodingErrorAction.REPORT);
  219. try {
  220. outputStreamWriter.write("测试");
  221. Assert.fail();
  222. }
  223. catch (UnmappableCharacterException unmappableCharacterException) {
  224. Assert.assertEquals(
  225. 1, unmappableCharacterException.getInputLength());
  226. }
  227. }
  228. @Test
  229. public void testWriteInt() throws IOException {
  230. MarkerOutputStream markerOutputStream = new MarkerOutputStream();
  231. OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
  232. markerOutputStream);
  233. outputStreamWriter.write('a');
  234. outputStreamWriter.flush();
  235. Assert.assertEquals((byte)'a', markerOutputStream._bytes[0]);
  236. Assert.assertEquals(1, markerOutputStream._length);
  237. Assert.assertEquals(0, markerOutputStream._offset);
  238. }
  239. @Test
  240. public void testWriteIntUnicodeSurrogatePair() throws IOException {
  241. // writeInt + writeInt
  242. _testUnicodeSurrogatePair(
  243. (outputStreamWriter, surrogatePair) -> {
  244. outputStreamWriter.write(surrogatePair[0]);
  245. outputStreamWriter.write(surrogatePair[1]);
  246. });
  247. // writeInt + writeCharArray
  248. _testUnicodeSurrogatePair(
  249. (outputStreamWriter, surrogatePair) -> {
  250. outputStreamWriter.write(surrogatePair[0]);
  251. outputStreamWriter.write(new char[] {surrogatePair[1]});
  252. });
  253. // writeCharArray + writeInt
  254. _testUnicodeSurrogatePair(
  255. (outputStreamWriter, surrogatePair) -> {
  256. outputStreamWriter.write(new char[] {surrogatePair[0]});
  257. outputStreamWriter.write(surrogatePair[1]);
  258. });
  259. // writeCharArray + writeCharArray
  260. _testUnicodeSurrogatePair(
  261. (outputStreamWriter, surrogatePair) -> {
  262. outputStreamWriter.write(new char[] {surrogatePair[0]});
  263. outputStreamWriter.write(new char[] {surrogatePair[1]});
  264. });
  265. }
  266. @Test
  267. public void testWriteString() throws IOException {
  268. _testWriteString(false);
  269. _testWriteString(true);
  270. }
  271. @Test
  272. public void testWriteWithExceptionThrownFromOutputStream()
  273. throws IOException {
  274. IOException ioException1 = new IOException();
  275. AtomicBoolean throwIOException = new AtomicBoolean();
  276. UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
  277. new UnsyncByteArrayOutputStream() {
  278. @Override
  279. public void write(byte[] bytes, int offset, int length) {
  280. if (throwIOException.get()) {
  281. ReflectionUtil.throwException(ioException1);
  282. }
  283. super.write(bytes, offset, length);
  284. }
  285. };
  286. OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
  287. unsyncByteArrayOutputStream, "UTF-8", 4, true);
  288. // Fill up the ByteBuffer
  289. throwIOException.set(true);
  290. try {
  291. outputStreamWriter.write('a');
  292. Assert.fail();
  293. }
  294. catch (IOException ioException2) {
  295. Assert.assertSame(ioException1, ioException2);
  296. }
  297. try {
  298. outputStreamWriter.write('b');
  299. Assert.fail();
  300. }
  301. catch (IOException ioException2) {
  302. Assert.assertSame(ioException1, ioException2);
  303. }
  304. try {
  305. outputStreamWriter.write('c');
  306. Assert.fail();
  307. }
  308. catch (IOException ioException2) {
  309. Assert.assertSame(ioException1, ioException2);
  310. }
  311. try {
  312. outputStreamWriter.write('d');
  313. Assert.fail();
  314. }
  315. catch (IOException ioException2) {
  316. Assert.assertSame(ioException1, ioException2);
  317. }
  318. // Fill up the CharBuffer
  319. try {
  320. outputStreamWriter.write('e');
  321. Assert.fail();
  322. }
  323. catch (IOException ioException2) {
  324. Assert.assertSame(ioException1, ioException2);
  325. }
  326. try {
  327. outputStreamWriter.write('f');
  328. Assert.fail();
  329. }
  330. catch (IOException ioException2) {
  331. Assert.assertSame(ioException1, ioException2);
  332. }
  333. // No space in buffer, discard
  334. try {
  335. outputStreamWriter.write('g');
  336. Assert.fail();
  337. }
  338. catch (IOException ioException2) {
  339. Assert.assertSame(ioException1, ioException2);
  340. }
  341. try {
  342. outputStreamWriter.write('h');
  343. Assert.fail();
  344. }
  345. catch (IOException ioException2) {
  346. Assert.assertSame(ioException1, ioException2);
  347. }
  348. Assert.assertEquals("", unsyncByteArrayOutputStream.toString());
  349. try {
  350. outputStreamWriter.flush();
  351. Assert.fail();
  352. }
  353. catch (IOException ioException2) {
  354. Assert.assertSame(ioException1, ioException2);
  355. }
  356. Assert.assertEquals("", unsyncByteArrayOutputStream.toString());
  357. // Recovered, data within buffer size has been preserved
  358. throwIOException.set(false);
  359. outputStreamWriter.write('i');
  360. Assert.assertEquals("abcdefi", unsyncByteArrayOutputStream.toString());
  361. // Cut in between surrogate pair
  362. unsyncByteArrayOutputStream.reset();
  363. char[] surrogatePair = Character.toChars(0x2363A);
  364. Assert.assertEquals(
  365. Arrays.toString(surrogatePair), 2, surrogatePair.length);
  366. throwIOException.set(true);
  367. // Fill up the ByteBuffer
  368. try {
  369. outputStreamWriter.write("abcd".toCharArray());
  370. Assert.fail();
  371. }
  372. catch (IOException ioException2) {
  373. Assert.assertSame(ioException1, ioException2);
  374. }
  375. // Fill up the CharBuffer
  376. try {
  377. outputStreamWriter.write('e');
  378. Assert.fail();
  379. }
  380. catch (IOException ioException2) {
  381. Assert.assertSame(ioException1, ioException2);
  382. }
  383. try {
  384. outputStreamWriter.write(surrogatePair[0]);
  385. Assert.fail();
  386. }
  387. catch (IOException ioException2) {
  388. Assert.assertSame(ioException1, ioException2);
  389. }
  390. // No space in buffer, discard
  391. try {
  392. outputStreamWriter.write(surrogatePair[1]);
  393. Assert.fail();
  394. }
  395. catch (IOException ioException2) {
  396. Assert.assertSame(ioException1, ioException2);
  397. }
  398. throwIOException.set(false);
  399. // New write must discard leftover surrogate char
  400. outputStreamWriter.write('f');
  401. Assert.assertEquals("abcdef", unsyncByteArrayOutputStream.toString());
  402. }
  403. private int _getDefaultOutputBufferSize() {
  404. return ReflectionTestUtil.getFieldValue(
  405. OutputStreamWriter.class, "_DEFAULT_OUTPUT_BUFFER_SIZE");
  406. }
  407. private int _getInputCharBufferSize(OutputStreamWriter outputStreamWriter) {
  408. CharBuffer inputCharBuffer = ReflectionTestUtil.getFieldValue(
  409. outputStreamWriter, "_inputCharBuffer");
  410. return inputCharBuffer.capacity();
  411. }
  412. private int _getOutputBufferSize(OutputStreamWriter outputStreamWriter) {
  413. ByteBuffer outputBuffer = ReflectionTestUtil.getFieldValue(
  414. outputStreamWriter, "_outputByteBuffer");
  415. return outputBuffer.capacity();
  416. }
  417. private OutputStream _getOutputStream(
  418. OutputStreamWriter outputStreamWriter) {
  419. return ReflectionTestUtil.getFieldValue(
  420. outputStreamWriter, "_outputStream");
  421. }
  422. private boolean _isAutoFlush(OutputStreamWriter outputStreamWriter) {
  423. return ReflectionTestUtil.getFieldValue(
  424. outputStreamWriter, "_autoFlush");
  425. }
  426. private void _testUnicodeSurrogatePair(
  427. SurrogatePairConsumer surrogatePairConsumer)
  428. throws IOException {
  429. UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
  430. new UnsyncByteArrayOutputStream();
  431. OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
  432. unsyncByteArrayOutputStream, "UTF-8");
  433. char[] surrogatePair = Character.toChars(0x2363A);
  434. Assert.assertEquals(
  435. Arrays.toString(surrogatePair), 2, surrogatePair.length);
  436. surrogatePairConsumer.accept(outputStreamWriter, surrogatePair);
  437. outputStreamWriter.flush();
  438. String decodedString = new String(
  439. unsyncByteArrayOutputStream.toByteArray(), "UTF-8");
  440. Assert.assertArrayEquals(surrogatePair, decodedString.toCharArray());
  441. }
  442. private void _testWriteCharArray(boolean autoFlush) throws IOException {
  443. final AtomicBoolean flushed = new AtomicBoolean();
  444. UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
  445. new UnsyncByteArrayOutputStream() {
  446. @Override
  447. public void flush() {
  448. flushed.set(true);
  449. }
  450. };
  451. OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
  452. unsyncByteArrayOutputStream, "US-ASCII", 4, autoFlush);
  453. outputStreamWriter.write("abcdefg".toCharArray(), 1, 5);
  454. Assert.assertFalse(flushed.get());
  455. if (!autoFlush) {
  456. outputStreamWriter.flush();
  457. Assert.assertTrue(flushed.get());
  458. flushed.set(false);
  459. }
  460. Assert.assertArrayEquals(
  461. new byte[] {'b', 'c', 'd', 'e', 'f'},
  462. unsyncByteArrayOutputStream.toByteArray());
  463. unsyncByteArrayOutputStream.reset();
  464. outputStreamWriter = new OutputStreamWriter(
  465. unsyncByteArrayOutputStream, "US-ASCII", autoFlush);
  466. outputStreamWriter.write("abc".toCharArray());
  467. Assert.assertFalse(flushed.get());
  468. if (!autoFlush) {
  469. outputStreamWriter.flush();
  470. Assert.assertTrue(flushed.get());
  471. flushed.set(false);
  472. }
  473. Assert.assertArrayEquals(
  474. new byte[] {'a', 'b', 'c'},
  475. unsyncByteArrayOutputStream.toByteArray());
  476. }
  477. private void _testWriteString(boolean autoFlush) throws IOException {
  478. final AtomicBoolean flushed = new AtomicBoolean();
  479. UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
  480. new UnsyncByteArrayOutputStream() {
  481. @Override
  482. public void flush() {
  483. flushed.set(true);
  484. }
  485. };
  486. OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
  487. unsyncByteArrayOutputStream, "US-ASCII", 4, autoFlush);
  488. outputStreamWriter.write("abcdefg", 1, 5);
  489. Assert.assertFalse(flushed.get());
  490. if (!autoFlush) {
  491. outputStreamWriter.flush();
  492. Assert.assertTrue(flushed.get());
  493. flushed.set(false);
  494. }
  495. Assert.assertArrayEquals(
  496. new byte[] {'b', 'c', 'd', 'e', 'f'},
  497. unsyncByteArrayOutputStream.toByteArray());
  498. unsyncByteArrayOutputStream.reset();
  499. outputStreamWriter = new OutputStreamWriter(
  500. unsyncByteArrayOutputStream, "US-ASCII", 4, autoFlush);
  501. outputStreamWriter.write("abcdefg", 1, 5);
  502. Assert.assertFalse(flushed.get());
  503. if (!autoFlush) {
  504. outputStreamWriter.flush();
  505. Assert.assertTrue(flushed.get());
  506. flushed.set(false);
  507. }
  508. Assert.assertArrayEquals(
  509. new byte[] {'b', 'c', 'd', 'e', 'f'},
  510. unsyncByteArrayOutputStream.toByteArray());
  511. unsyncByteArrayOutputStream.reset();
  512. outputStreamWriter = new OutputStreamWriter(
  513. unsyncByteArrayOutputStream, "US-ASCII", autoFlush);
  514. outputStreamWriter.write("abc");
  515. Assert.assertFalse(flushed.get());
  516. if (!autoFlush) {
  517. outputStreamWriter.flush();
  518. Assert.assertTrue(flushed.get());
  519. flushed.set(false);
  520. }
  521. Assert.assertArrayEquals(
  522. new byte[] {'a', 'b', 'c'},
  523. unsyncByteArrayOutputStream.toByteArray());
  524. }
  525. private static class CharsetEncoderWrapper extends CharsetEncoder {
  526. @Override
  527. public boolean canEncode(char c) {
  528. return _charsetEncoder.canEncode(c);
  529. }
  530. @Override
  531. public boolean canEncode(CharSequence cs) {
  532. return _charsetEncoder.canEncode(cs);
  533. }
  534. @Override
  535. public boolean isLegalReplacement(byte[] replacement) {
  536. return true;
  537. }
  538. @Override
  539. public CodingErrorAction malformedInputAction() {
  540. return _charsetEncoder.malformedInputAction();
  541. }
  542. @Override
  543. public CodingErrorAction unmappableCharacterAction() {
  544. return _charsetEncoder.unmappableCharacterAction();
  545. }
  546. @Override
  547. protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
  548. return ReflectionTestUtil.invoke(
  549. _charsetEncoder, "encodeLoop",
  550. new Class<?>[] {CharBuffer.class, ByteBuffer.class}, in, out);
  551. }
  552. private CharsetEncoderWrapper(CharsetEncoder charsetEncoder) {
  553. super(
  554. charsetEncoder.charset(), charsetEncoder.averageBytesPerChar(),
  555. charsetEncoder.maxBytesPerChar(), charsetEncoder.replacement());
  556. _charsetEncoder = charsetEncoder;
  557. }
  558. private final CharsetEncoder _charsetEncoder;
  559. }
  560. private static class MarkerOutputStream extends OutputStream {
  561. @Override
  562. public void close() {
  563. _closed = true;
  564. }
  565. @Override
  566. public void flush() {
  567. _flushed = true;
  568. }
  569. @Override
  570. public void write(byte[] bytes, int offset, int length) {
  571. _bytes = bytes;
  572. _offset = offset;
  573. _length = length;
  574. }
  575. @Override
  576. public void write(int b) {
  577. }
  578. private byte[] _bytes;
  579. private boolean _closed;
  580. private boolean _flushed;
  581. private int _length;
  582. private int _offset;
  583. }
  584. private interface SurrogatePairConsumer {
  585. public void accept(
  586. OutputStreamWriter outputStreamWriter, char[] surrogatePair)
  587. throws IOException;
  588. }
  589. }