Hessian2Output.java 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604
  1. /*
  2. * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
  3. *
  4. * The Apache Software License, Version 1.1
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. *
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. *
  18. * 3. The end-user documentation included with the redistribution, if
  19. * any, must include the following acknowlegement:
  20. * "This product includes software developed by the
  21. * Caucho Technology (http://www.caucho.com/)."
  22. * Alternately, this acknowlegement may appear in the software itself,
  23. * if and wherever such third-party acknowlegements normally appear.
  24. *
  25. * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
  26. * endorse or promote products derived from this software without prior
  27. * written permission. For written permission, please contact
  28. * info@caucho.com.
  29. *
  30. * 5. Products derived from this software may not be called "Resin"
  31. * nor may "Resin" appear in their names without prior written
  32. * permission of Caucho Technology.
  33. *
  34. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  35. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  36. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  37. * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
  38. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  39. * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
  40. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  41. * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  42. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  43. * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  44. * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  45. *
  46. * @author Scott Ferguson
  47. */
  48. package com.hmsoft.remote.caucho.hessian.io;
  49. import java.io.IOException;
  50. import java.io.OutputStream;
  51. import java.util.HashMap;
  52. import com.hmsoft.remote.caucho.hessian.util.IdentityIntMap;
  53. /**
  54. * Output stream for Hessian 2 requests.
  55. *
  56. * <p>Since HessianOutput does not depend on any classes other than
  57. * in the JDK, it can be extracted independently into a smaller package.
  58. *
  59. * <p>HessianOutput is unbuffered, so any client needs to provide
  60. * its own buffering.
  61. *
  62. * <pre>
  63. * OutputStream os = ...; // from http connection
  64. * Hessian2Output out = new Hessian2Output(os);
  65. * String value;
  66. *
  67. * out.startCall("hello", 1); // start hello call
  68. * out.writeString("arg1"); // write a string argument
  69. * out.completeCall(); // complete the call
  70. * </pre>
  71. */
  72. public class Hessian2Output
  73. extends AbstractHessianOutput
  74. implements Hessian2Constants
  75. {
  76. // the output stream/
  77. protected OutputStream _os;
  78. // map of references
  79. private IdentityIntMap _refs = new IdentityIntMap();
  80. private boolean _isCloseStreamOnClose;
  81. // map of classes
  82. private HashMap _classRefs;
  83. // map of types
  84. private HashMap _typeRefs;
  85. public final static int SIZE = 4096;
  86. private final byte []_buffer = new byte[SIZE];
  87. private int _offset;
  88. private boolean _isStreaming;
  89. /**
  90. * Creates a new Hessian output stream, initialized with an
  91. * underlying output stream.
  92. *
  93. * @param os the underlying output stream.
  94. */
  95. public Hessian2Output(OutputStream os)
  96. {
  97. _os = os;
  98. }
  99. public void setCloseStreamOnClose(boolean isClose)
  100. {
  101. _isCloseStreamOnClose = isClose;
  102. }
  103. public boolean isCloseStreamOnClose()
  104. {
  105. return _isCloseStreamOnClose;
  106. }
  107. /**
  108. * Writes a complete method call.
  109. */
  110. @Override
  111. public void call(String method, Object []args)
  112. throws IOException
  113. {
  114. int length = args != null ? args.length : 0;
  115. startCall(method, length);
  116. for (int i = 0; i < args.length; i++)
  117. writeObject(args[i]);
  118. completeCall();
  119. }
  120. /**
  121. * Starts the method call. Clients would use <code>startCall</code>
  122. * instead of <code>call</code> if they wanted finer control over
  123. * writing the arguments, or needed to write headers.
  124. *
  125. * <code><pre>
  126. * C
  127. * string # method name
  128. * int # arg count
  129. * </pre></code>
  130. *
  131. * @param method the method name to call.
  132. */
  133. public void startCall(String method, int length)
  134. throws IOException
  135. {
  136. int offset = _offset;
  137. if (SIZE < offset + 32) {
  138. flush();
  139. offset = _offset;
  140. }
  141. byte []buffer = _buffer;
  142. buffer[_offset++] = (byte) 'C';
  143. writeString(method);
  144. writeInt(length);
  145. }
  146. /**
  147. * Writes the call tag. This would be followed by the
  148. * method and the arguments
  149. *
  150. * <code><pre>
  151. * C
  152. * </pre></code>
  153. *
  154. * @param method the method name to call.
  155. */
  156. public void startCall()
  157. throws IOException
  158. {
  159. flushIfFull();
  160. _buffer[_offset++] = (byte) 'C';
  161. }
  162. /**
  163. * Starts an envelope.
  164. *
  165. * <code><pre>
  166. * E major minor
  167. * m b16 b8 method-name
  168. * </pre></code>
  169. *
  170. * @param method the method name to call.
  171. */
  172. public void startEnvelope(String method)
  173. throws IOException
  174. {
  175. int offset = _offset;
  176. if (SIZE < offset + 32) {
  177. flush();
  178. offset = _offset;
  179. }
  180. _buffer[_offset++] = (byte) 'E';
  181. writeString(method);
  182. }
  183. /**
  184. * Completes an envelope.
  185. *
  186. * <p>A successful completion will have a single value:
  187. *
  188. * <pre>
  189. * Z
  190. * </pre>
  191. */
  192. public void completeEnvelope()
  193. throws IOException
  194. {
  195. flushIfFull();
  196. _buffer[_offset++] = (byte) 'Z';
  197. }
  198. /**
  199. * Writes the method tag.
  200. *
  201. * <code><pre>
  202. * string
  203. * </pre></code>
  204. *
  205. * @param method the method name to call.
  206. */
  207. public void writeMethod(String method)
  208. throws IOException
  209. {
  210. writeString(method);
  211. }
  212. /**
  213. * Completes.
  214. *
  215. * <code><pre>
  216. * z
  217. * </pre></code>
  218. */
  219. public void completeCall()
  220. throws IOException
  221. {
  222. /*
  223. flushIfFull();
  224. _buffer[_offset++] = (byte) 'Z';
  225. */
  226. }
  227. /**
  228. * Starts the reply
  229. *
  230. * <p>A successful completion will have a single value:
  231. *
  232. * <pre>
  233. * R
  234. * </pre>
  235. */
  236. public void startReply()
  237. throws IOException
  238. {
  239. writeVersion();
  240. flushIfFull();
  241. _buffer[_offset++] = (byte) 'R';
  242. }
  243. public void writeVersion()
  244. throws IOException
  245. {
  246. flushIfFull();
  247. _buffer[_offset++] = (byte) 'H';
  248. _buffer[_offset++] = (byte) 2;
  249. _buffer[_offset++] = (byte) 0;
  250. }
  251. /**
  252. * Completes reading the reply
  253. *
  254. * <p>A successful completion will have a single value:
  255. *
  256. * <pre>
  257. * z
  258. * </pre>
  259. */
  260. public void completeReply()
  261. throws IOException
  262. {
  263. }
  264. /**
  265. * Starts a packet
  266. *
  267. * <p>A message contains several objects encapsulated by a length</p>
  268. *
  269. * <pre>
  270. * p x02 x00
  271. * </pre>
  272. */
  273. public void startMessage()
  274. throws IOException
  275. {
  276. flushIfFull();
  277. _buffer[_offset++] = (byte) 'p';
  278. _buffer[_offset++] = (byte) 2;
  279. _buffer[_offset++] = (byte) 0;
  280. }
  281. /**
  282. * Completes reading the message
  283. *
  284. * <p>A successful completion will have a single value:
  285. *
  286. * <pre>
  287. * z
  288. * </pre>
  289. */
  290. public void completeMessage()
  291. throws IOException
  292. {
  293. flushIfFull();
  294. _buffer[_offset++] = (byte) 'z';
  295. }
  296. /**
  297. * Writes a fault. The fault will be written
  298. * as a descriptive string followed by an object:
  299. *
  300. * <code><pre>
  301. * F map
  302. * </pre></code>
  303. *
  304. * <code><pre>
  305. * F H
  306. * \x04code
  307. * \x10the fault code
  308. *
  309. * \x07message
  310. * \x11the fault message
  311. *
  312. * \x06detail
  313. * M\xnnjavax.ejb.FinderException
  314. * ...
  315. * Z
  316. * Z
  317. * </pre></code>
  318. *
  319. * @param code the fault code, a three digit
  320. */
  321. public void writeFault(String code, String message, Object detail)
  322. throws IOException
  323. {
  324. flushIfFull();
  325. writeVersion();
  326. _buffer[_offset++] = (byte) 'F';
  327. _buffer[_offset++] = (byte) 'H';
  328. _refs.put(new HashMap(), _refs.size());
  329. writeString("code");
  330. writeString(code);
  331. writeString("message");
  332. writeString(message);
  333. if (detail != null) {
  334. writeString("detail");
  335. writeObject(detail);
  336. }
  337. flushIfFull();
  338. _buffer[_offset++] = (byte) 'Z';
  339. }
  340. /**
  341. * Writes any object to the output stream.
  342. */
  343. public void writeObject(Object object)
  344. throws IOException
  345. {
  346. if (object == null) {
  347. writeNull();
  348. return;
  349. }
  350. Serializer serializer;
  351. serializer = findSerializerFactory().getSerializer(object.getClass());
  352. serializer.writeObject(object, this);
  353. }
  354. /**
  355. * Writes the list header to the stream. List writers will call
  356. * <code>writeListBegin</code> followed by the list contents and then
  357. * call <code>writeListEnd</code>.
  358. *
  359. * <code><pre>
  360. * list ::= V type value* Z
  361. * ::= v type int value*
  362. * </pre></code>
  363. *
  364. * @return true for variable lists, false for fixed lists
  365. */
  366. public boolean writeListBegin(int length, String type)
  367. throws IOException
  368. {
  369. flushIfFull();
  370. if (length < 0) {
  371. if (type != null) {
  372. _buffer[_offset++] = (byte) BC_LIST_VARIABLE;
  373. writeType(type);
  374. }
  375. else
  376. _buffer[_offset++] = (byte) BC_LIST_VARIABLE_UNTYPED;
  377. return true;
  378. }
  379. else if (length <= LIST_DIRECT_MAX) {
  380. if (type != null) {
  381. _buffer[_offset++] = (byte) (BC_LIST_DIRECT + length);
  382. writeType(type);
  383. }
  384. else {
  385. _buffer[_offset++] = (byte) (BC_LIST_DIRECT_UNTYPED + length);
  386. }
  387. return false;
  388. }
  389. else {
  390. if (type != null) {
  391. _buffer[_offset++] = (byte) BC_LIST_FIXED;
  392. writeType(type);
  393. }
  394. else {
  395. _buffer[_offset++] = (byte) BC_LIST_FIXED_UNTYPED;
  396. }
  397. writeInt(length);
  398. return false;
  399. }
  400. }
  401. /**
  402. * Writes the tail of the list to the stream for a variable-length list.
  403. */
  404. public void writeListEnd()
  405. throws IOException
  406. {
  407. flushIfFull();
  408. _buffer[_offset++] = (byte) BC_END;
  409. }
  410. /**
  411. * Writes the map header to the stream. Map writers will call
  412. * <code>writeMapBegin</code> followed by the map contents and then
  413. * call <code>writeMapEnd</code>.
  414. *
  415. * <code><pre>
  416. * map ::= M type (<value> <value>)* Z
  417. * ::= H (<value> <value>)* Z
  418. * </pre></code>
  419. */
  420. public void writeMapBegin(String type)
  421. throws IOException
  422. {
  423. if (SIZE < _offset + 32)
  424. flush();
  425. if (type != null) {
  426. _buffer[_offset++] = BC_MAP;
  427. writeType(type);
  428. }
  429. else
  430. _buffer[_offset++] = BC_MAP_UNTYPED;
  431. }
  432. /**
  433. * Writes the tail of the map to the stream.
  434. */
  435. public void writeMapEnd()
  436. throws IOException
  437. {
  438. if (SIZE < _offset + 32)
  439. flush();
  440. _buffer[_offset++] = (byte) BC_END;
  441. }
  442. /**
  443. * Writes the object definition
  444. *
  445. * <code><pre>
  446. * C &lt;string> &lt;int> &lt;string>*
  447. * </pre></code>
  448. */
  449. public int writeObjectBegin(String type)
  450. throws IOException
  451. {
  452. if (_classRefs == null)
  453. _classRefs = new HashMap();
  454. Integer refV = (Integer) _classRefs.get(type);
  455. if (refV != null) {
  456. int ref = refV.intValue();
  457. if (SIZE < _offset + 32)
  458. flush();
  459. if (ref <= OBJECT_DIRECT_MAX) {
  460. _buffer[_offset++] = (byte) (BC_OBJECT_DIRECT + ref);
  461. }
  462. else {
  463. _buffer[_offset++] = (byte) 'O';
  464. writeInt(ref);
  465. }
  466. return ref;
  467. }
  468. else {
  469. int ref = _classRefs.size();
  470. _classRefs.put(type, Integer.valueOf(ref));
  471. if (SIZE < _offset + 32)
  472. flush();
  473. _buffer[_offset++] = (byte) 'C';
  474. writeString(type);
  475. return -1;
  476. }
  477. }
  478. /**
  479. * Writes the tail of the class definition to the stream.
  480. */
  481. public void writeClassFieldLength(int len)
  482. throws IOException
  483. {
  484. writeInt(len);
  485. }
  486. /**
  487. * Writes the tail of the object definition to the stream.
  488. */
  489. public void writeObjectEnd()
  490. throws IOException
  491. {
  492. }
  493. /**
  494. * <code><pre>
  495. * type ::= string
  496. * ::= int
  497. * </code></pre>
  498. */
  499. private void writeType(String type)
  500. throws IOException
  501. {
  502. flushIfFull();
  503. int len = type.length();
  504. if (len == 0) {
  505. throw new IllegalArgumentException("empty type is not allowed");
  506. }
  507. if (_typeRefs == null)
  508. _typeRefs = new HashMap();
  509. Integer typeRefV = (Integer) _typeRefs.get(type);
  510. if (typeRefV != null) {
  511. int typeRef = typeRefV.intValue();
  512. writeInt(typeRef);
  513. }
  514. else {
  515. _typeRefs.put(type, Integer.valueOf(_typeRefs.size()));
  516. writeString(type);
  517. }
  518. }
  519. /**
  520. * Writes a boolean value to the stream. The boolean will be written
  521. * with the following syntax:
  522. *
  523. * <code><pre>
  524. * T
  525. * F
  526. * </pre></code>
  527. *
  528. * @param value the boolean value to write.
  529. */
  530. public void writeBoolean(boolean value)
  531. throws IOException
  532. {
  533. if (SIZE < _offset + 16)
  534. flush();
  535. if (value)
  536. _buffer[_offset++] = (byte) 'T';
  537. else
  538. _buffer[_offset++] = (byte) 'F';
  539. }
  540. /**
  541. * Writes an integer value to the stream. The integer will be written
  542. * with the following syntax:
  543. *
  544. * <code><pre>
  545. * I b32 b24 b16 b8
  546. * </pre></code>
  547. *
  548. * @param value the integer value to write.
  549. */
  550. public void writeInt(int value)
  551. throws IOException
  552. {
  553. int offset = _offset;
  554. byte []buffer = _buffer;
  555. if (SIZE <= offset + 16) {
  556. flush();
  557. offset = _offset;
  558. }
  559. if (INT_DIRECT_MIN <= value && value <= INT_DIRECT_MAX)
  560. buffer[offset++] = (byte) (value + BC_INT_ZERO);
  561. else if (INT_BYTE_MIN <= value && value <= INT_BYTE_MAX) {
  562. buffer[offset++] = (byte) (BC_INT_BYTE_ZERO + (value >> 8));
  563. buffer[offset++] = (byte) (value);
  564. }
  565. else if (INT_SHORT_MIN <= value && value <= INT_SHORT_MAX) {
  566. buffer[offset++] = (byte) (BC_INT_SHORT_ZERO + (value >> 16));
  567. buffer[offset++] = (byte) (value >> 8);
  568. buffer[offset++] = (byte) (value);
  569. }
  570. else {
  571. buffer[offset++] = (byte) ('I');
  572. buffer[offset++] = (byte) (value >> 24);
  573. buffer[offset++] = (byte) (value >> 16);
  574. buffer[offset++] = (byte) (value >> 8);
  575. buffer[offset++] = (byte) (value);
  576. }
  577. _offset = offset;
  578. }
  579. /**
  580. * Writes a long value to the stream. The long will be written
  581. * with the following syntax:
  582. *
  583. * <code><pre>
  584. * L b64 b56 b48 b40 b32 b24 b16 b8
  585. * </pre></code>
  586. *
  587. * @param value the long value to write.
  588. */
  589. public void writeLong(long value)
  590. throws IOException
  591. {
  592. int offset = _offset;
  593. byte []buffer = _buffer;
  594. if (SIZE <= offset + 16) {
  595. flush();
  596. offset = _offset;
  597. }
  598. if (LONG_DIRECT_MIN <= value && value <= LONG_DIRECT_MAX) {
  599. buffer[offset++] = (byte) (value + BC_LONG_ZERO);
  600. }
  601. else if (LONG_BYTE_MIN <= value && value <= LONG_BYTE_MAX) {
  602. buffer[offset++] = (byte) (BC_LONG_BYTE_ZERO + (value >> 8));
  603. buffer[offset++] = (byte) (value);
  604. }
  605. else if (LONG_SHORT_MIN <= value && value <= LONG_SHORT_MAX) {
  606. buffer[offset++] = (byte) (BC_LONG_SHORT_ZERO + (value >> 16));
  607. buffer[offset++] = (byte) (value >> 8);
  608. buffer[offset++] = (byte) (value);
  609. }
  610. else if (-0x80000000L <= value && value <= 0x7fffffffL) {
  611. buffer[offset + 0] = (byte) BC_LONG_INT;
  612. buffer[offset + 1] = (byte) (value >> 24);
  613. buffer[offset + 2] = (byte) (value >> 16);
  614. buffer[offset + 3] = (byte) (value >> 8);
  615. buffer[offset + 4] = (byte) (value);
  616. offset += 5;
  617. }
  618. else {
  619. buffer[offset + 0] = (byte) 'L';
  620. buffer[offset + 1] = (byte) (value >> 56);
  621. buffer[offset + 2] = (byte) (value >> 48);
  622. buffer[offset + 3] = (byte) (value >> 40);
  623. buffer[offset + 4] = (byte) (value >> 32);
  624. buffer[offset + 5] = (byte) (value >> 24);
  625. buffer[offset + 6] = (byte) (value >> 16);
  626. buffer[offset + 7] = (byte) (value >> 8);
  627. buffer[offset + 8] = (byte) (value);
  628. offset += 9;
  629. }
  630. _offset = offset;
  631. }
  632. /**
  633. * Writes a double value to the stream. The double will be written
  634. * with the following syntax:
  635. *
  636. * <code><pre>
  637. * D b64 b56 b48 b40 b32 b24 b16 b8
  638. * </pre></code>
  639. *
  640. * @param value the double value to write.
  641. */
  642. public void writeDouble(double value)
  643. throws IOException
  644. {
  645. int offset = _offset;
  646. byte []buffer = _buffer;
  647. if (SIZE <= offset + 16) {
  648. flush();
  649. offset = _offset;
  650. }
  651. int intValue = (int) value;
  652. if (intValue == value) {
  653. if (intValue == 0) {
  654. buffer[offset++] = (byte) BC_DOUBLE_ZERO;
  655. _offset = offset;
  656. return;
  657. }
  658. else if (intValue == 1) {
  659. buffer[offset++] = (byte) BC_DOUBLE_ONE;
  660. _offset = offset;
  661. return;
  662. }
  663. else if (-0x80 <= intValue && intValue < 0x80) {
  664. buffer[offset++] = (byte) BC_DOUBLE_BYTE;
  665. buffer[offset++] = (byte) intValue;
  666. _offset = offset;
  667. return;
  668. }
  669. else if (-0x8000 <= intValue && intValue < 0x8000) {
  670. buffer[offset + 0] = (byte) BC_DOUBLE_SHORT;
  671. buffer[offset + 1] = (byte) (intValue >> 8);
  672. buffer[offset + 2] = (byte) intValue;
  673. _offset = offset + 3;
  674. return;
  675. }
  676. }
  677. int mills = (int) (value * 1000);
  678. if (0.001 * mills == value) {
  679. buffer[offset + 0] = (byte) (BC_DOUBLE_MILL);
  680. buffer[offset + 1] = (byte) (mills >> 24);
  681. buffer[offset + 2] = (byte) (mills >> 16);
  682. buffer[offset + 3] = (byte) (mills >> 8);
  683. buffer[offset + 4] = (byte) (mills);
  684. _offset = offset + 5;
  685. return;
  686. }
  687. long bits = Double.doubleToLongBits(value);
  688. buffer[offset + 0] = (byte) 'D';
  689. buffer[offset + 1] = (byte) (bits >> 56);
  690. buffer[offset + 2] = (byte) (bits >> 48);
  691. buffer[offset + 3] = (byte) (bits >> 40);
  692. buffer[offset + 4] = (byte) (bits >> 32);
  693. buffer[offset + 5] = (byte) (bits >> 24);
  694. buffer[offset + 6] = (byte) (bits >> 16);
  695. buffer[offset + 7] = (byte) (bits >> 8);
  696. buffer[offset + 8] = (byte) (bits);
  697. _offset = offset + 9;
  698. }
  699. /**
  700. * Writes a date to the stream.
  701. *
  702. * <code><pre>
  703. * date ::= d b7 b6 b5 b4 b3 b2 b1 b0
  704. * ::= x65 b3 b2 b1 b0
  705. * </pre></code>
  706. *
  707. * @param time the date in milliseconds from the epoch in UTC
  708. */
  709. public void writeUTCDate(long time)
  710. throws IOException
  711. {
  712. if (SIZE < _offset + 32)
  713. flush();
  714. int offset = _offset;
  715. byte []buffer = _buffer;
  716. if (time % 60000L == 0) {
  717. // compact date ::= x65 b3 b2 b1 b0
  718. long minutes = time / 60000L;
  719. if ((minutes >> 31) == 0 || (minutes >> 31) == -1) {
  720. buffer[offset++] = (byte) BC_DATE_MINUTE;
  721. buffer[offset++] = ((byte) (minutes >> 24));
  722. buffer[offset++] = ((byte) (minutes >> 16));
  723. buffer[offset++] = ((byte) (minutes >> 8));
  724. buffer[offset++] = ((byte) (minutes >> 0));
  725. _offset = offset;
  726. return;
  727. }
  728. }
  729. buffer[offset++] = (byte) BC_DATE;
  730. buffer[offset++] = ((byte) (time >> 56));
  731. buffer[offset++] = ((byte) (time >> 48));
  732. buffer[offset++] = ((byte) (time >> 40));
  733. buffer[offset++] = ((byte) (time >> 32));
  734. buffer[offset++] = ((byte) (time >> 24));
  735. buffer[offset++] = ((byte) (time >> 16));
  736. buffer[offset++] = ((byte) (time >> 8));
  737. buffer[offset++] = ((byte) (time));
  738. _offset = offset;
  739. }
  740. /**
  741. * Writes a null value to the stream.
  742. * The null will be written with the following syntax
  743. *
  744. * <code><pre>
  745. * N
  746. * </pre></code>
  747. *
  748. * @param value the string value to write.
  749. */
  750. public void writeNull()
  751. throws IOException
  752. {
  753. int offset = _offset;
  754. byte []buffer = _buffer;
  755. if (SIZE <= offset + 16) {
  756. flush();
  757. offset = _offset;
  758. }
  759. buffer[offset++] = 'N';
  760. _offset = offset;
  761. }
  762. /**
  763. * Writes a string value to the stream using UTF-8 encoding.
  764. * The string will be written with the following syntax:
  765. *
  766. * <code><pre>
  767. * S b16 b8 string-value
  768. * </pre></code>
  769. *
  770. * If the value is null, it will be written as
  771. *
  772. * <code><pre>
  773. * N
  774. * </pre></code>
  775. *
  776. * @param value the string value to write.
  777. */
  778. public void writeString(String value)
  779. throws IOException
  780. {
  781. int offset = _offset;
  782. byte []buffer = _buffer;
  783. if (SIZE <= offset + 16) {
  784. flush();
  785. offset = _offset;
  786. }
  787. if (value == null) {
  788. buffer[offset++] = (byte) 'N';
  789. _offset = offset;
  790. }
  791. else {
  792. int length = value.length();
  793. int strOffset = 0;
  794. while (length > 0x8000) {
  795. int sublen = 0x8000;
  796. offset = _offset;
  797. if (SIZE <= offset + 16) {
  798. flush();
  799. offset = _offset;
  800. }
  801. // chunk can't end in high surrogate
  802. char tail = value.charAt(strOffset + sublen - 1);
  803. if (0xd800 <= tail && tail <= 0xdbff)
  804. sublen--;
  805. buffer[offset + 0] = (byte) BC_STRING_CHUNK;
  806. buffer[offset + 1] = (byte) (sublen >> 8);
  807. buffer[offset + 2] = (byte) (sublen);
  808. _offset = offset + 3;
  809. printString(value, strOffset, sublen);
  810. length -= sublen;
  811. strOffset += sublen;
  812. }
  813. offset = _offset;
  814. if (SIZE <= offset + 16) {
  815. flush();
  816. offset = _offset;
  817. }
  818. if (length <= STRING_DIRECT_MAX) {
  819. buffer[offset++] = (byte) (BC_STRING_DIRECT + length);
  820. }
  821. else if (length <= STRING_SHORT_MAX) {
  822. buffer[offset++] = (byte) (BC_STRING_SHORT + (length >> 8));
  823. buffer[offset++] = (byte) (length);
  824. }
  825. else {
  826. buffer[offset++] = (byte) ('S');
  827. buffer[offset++] = (byte) (length >> 8);
  828. buffer[offset++] = (byte) (length);
  829. }
  830. _offset = offset;
  831. printString(value, strOffset, length);
  832. }
  833. }
  834. /**
  835. * Writes a string value to the stream using UTF-8 encoding.
  836. * The string will be written with the following syntax:
  837. *
  838. * <code><pre>
  839. * S b16 b8 string-value
  840. * </pre></code>
  841. *
  842. * If the value is null, it will be written as
  843. *
  844. * <code><pre>
  845. * N
  846. * </pre></code>
  847. *
  848. * @param value the string value to write.
  849. */
  850. public void writeString(char []buffer, int offset, int length)
  851. throws IOException
  852. {
  853. if (buffer == null) {
  854. if (SIZE < _offset + 16)
  855. flush();
  856. _buffer[_offset++] = (byte) ('N');
  857. }
  858. else {
  859. while (length > 0x8000) {
  860. int sublen = 0x8000;
  861. if (SIZE < _offset + 16)
  862. flush();
  863. // chunk can't end in high surrogate
  864. char tail = buffer[offset + sublen - 1];
  865. if (0xd800 <= tail && tail <= 0xdbff)
  866. sublen--;
  867. _buffer[_offset++] = (byte) BC_STRING_CHUNK;
  868. _buffer[_offset++] = (byte) (sublen >> 8);
  869. _buffer[_offset++] = (byte) (sublen);
  870. printString(buffer, offset, sublen);
  871. length -= sublen;
  872. offset += sublen;
  873. }
  874. if (SIZE < _offset + 16)
  875. flush();
  876. if (length <= STRING_DIRECT_MAX) {
  877. _buffer[_offset++] = (byte) (BC_STRING_DIRECT + length);
  878. }
  879. else if (length <= STRING_SHORT_MAX) {
  880. _buffer[_offset++] = (byte) (BC_STRING_SHORT + (length >> 8));
  881. _buffer[_offset++] = (byte) length;
  882. }
  883. else {
  884. _buffer[_offset++] = (byte) ('S');
  885. _buffer[_offset++] = (byte) (length >> 8);
  886. _buffer[_offset++] = (byte) (length);
  887. }
  888. printString(buffer, offset, length);
  889. }
  890. }
  891. /**
  892. * Writes a byte array to the stream.
  893. * The array will be written with the following syntax:
  894. *
  895. * <code><pre>
  896. * B b16 b18 bytes
  897. * </pre></code>
  898. *
  899. * If the value is null, it will be written as
  900. *
  901. * <code><pre>
  902. * N
  903. * </pre></code>
  904. *
  905. * @param value the string value to write.
  906. */
  907. public void writeBytes(byte []buffer)
  908. throws IOException
  909. {
  910. if (buffer == null) {
  911. if (SIZE < _offset + 16)
  912. flush();
  913. _buffer[_offset++] = 'N';
  914. }
  915. else
  916. writeBytes(buffer, 0, buffer.length);
  917. }
  918. /**
  919. * Writes a byte array to the stream.
  920. * The array will be written with the following syntax:
  921. *
  922. * <code><pre>
  923. * B b16 b18 bytes
  924. * </pre></code>
  925. *
  926. * If the value is null, it will be written as
  927. *
  928. * <code><pre>
  929. * N
  930. * </pre></code>
  931. *
  932. * @param value the string value to write.
  933. */
  934. public void writeBytes(byte []buffer, int offset, int length)
  935. throws IOException
  936. {
  937. if (buffer == null) {
  938. if (SIZE < _offset + 16)
  939. flushBuffer();
  940. _buffer[_offset++] = (byte) 'N';
  941. }
  942. else {
  943. flush();
  944. while (SIZE - _offset - 3 < length) {
  945. int sublen = SIZE - _offset - 3;
  946. if (sublen < 16) {
  947. flushBuffer();
  948. sublen = SIZE - _offset - 3;
  949. if (length < sublen)
  950. sublen = length;
  951. }
  952. _buffer[_offset++] = (byte) BC_BINARY_CHUNK;
  953. _buffer[_offset++] = (byte) (sublen >> 8);
  954. _buffer[_offset++] = (byte) sublen;
  955. System.arraycopy(buffer, offset, _buffer, _offset, sublen);
  956. _offset += sublen;
  957. length -= sublen;
  958. offset += sublen;
  959. flushBuffer();
  960. }
  961. if (SIZE < _offset + 16)
  962. flushBuffer();
  963. if (length <= BINARY_DIRECT_MAX) {
  964. _buffer[_offset++] = (byte) (BC_BINARY_DIRECT + length);
  965. }
  966. else if (length <= BINARY_SHORT_MAX) {
  967. _buffer[_offset++] = (byte) (BC_BINARY_SHORT + (length >> 8));
  968. _buffer[_offset++] = (byte) (length);
  969. }
  970. else {
  971. _buffer[_offset++] = (byte) 'B';
  972. _buffer[_offset++] = (byte) (length >> 8);
  973. _buffer[_offset++] = (byte) (length);
  974. }
  975. System.arraycopy(buffer, offset, _buffer, _offset, length);
  976. _offset += length;
  977. }
  978. }
  979. /**
  980. * Writes a byte buffer to the stream.
  981. *
  982. * <code><pre>
  983. * </pre></code>
  984. */
  985. public void writeByteBufferStart()
  986. throws IOException
  987. {
  988. }
  989. /**
  990. * Writes a byte buffer to the stream.
  991. *
  992. * <code><pre>
  993. * b b16 b18 bytes
  994. * </pre></code>
  995. */
  996. public void writeByteBufferPart(byte []buffer, int offset, int length)
  997. throws IOException
  998. {
  999. while (length > 0) {
  1000. int sublen = length;
  1001. if (0x8000 < sublen)
  1002. sublen = 0x8000;
  1003. flush(); // bypass buffer
  1004. _os.write(BC_BINARY_CHUNK);
  1005. _os.write(sublen >> 8);
  1006. _os.write(sublen);
  1007. _os.write(buffer, offset, sublen);
  1008. length -= sublen;
  1009. offset += sublen;
  1010. }
  1011. }
  1012. /**
  1013. * Writes a byte buffer to the stream.
  1014. *
  1015. * <code><pre>
  1016. * b b16 b18 bytes
  1017. * </pre></code>
  1018. */
  1019. public void writeByteBufferEnd(byte []buffer, int offset, int length)
  1020. throws IOException
  1021. {
  1022. writeBytes(buffer, offset, length);
  1023. }
  1024. /**
  1025. * Returns an output stream to write binary data.
  1026. */
  1027. public OutputStream getBytesOutputStream()
  1028. throws IOException
  1029. {
  1030. return new BytesOutputStream();
  1031. }
  1032. /**
  1033. * Writes a reference.
  1034. *
  1035. * <code><pre>
  1036. * x51 &lt;int>
  1037. * </pre></code>
  1038. *
  1039. * @param value the integer value to write.
  1040. */
  1041. @Override
  1042. protected void writeRef(int value)
  1043. throws IOException
  1044. {
  1045. if (SIZE < _offset + 16)
  1046. flush();
  1047. _buffer[_offset++] = (byte) BC_REF;
  1048. writeInt(value);
  1049. }
  1050. /**
  1051. * If the object has already been written, just write its ref.
  1052. *
  1053. * @return true if we're writing a ref.
  1054. */
  1055. public boolean addRef(Object object)
  1056. throws IOException
  1057. {
  1058. int ref = _refs.get(object);
  1059. if (ref >= 0) {
  1060. writeRef(ref);
  1061. return true;
  1062. }
  1063. else {
  1064. _refs.put(object, _refs.size());
  1065. return false;
  1066. }
  1067. }
  1068. /**
  1069. * Removes a reference.
  1070. */
  1071. public boolean removeRef(Object obj)
  1072. throws IOException
  1073. {
  1074. if (_refs != null) {
  1075. _refs.remove(obj);
  1076. return true;
  1077. }
  1078. else
  1079. return false;
  1080. }
  1081. /**
  1082. * Replaces a reference from one object to another.
  1083. */
  1084. public boolean replaceRef(Object oldRef, Object newRef)
  1085. throws IOException
  1086. {
  1087. Integer value = (Integer) _refs.remove(oldRef);
  1088. if (value != null) {
  1089. _refs.put(newRef, value);
  1090. return true;
  1091. }
  1092. else
  1093. return false;
  1094. }
  1095. /**
  1096. * Resets the references for streaming.
  1097. */
  1098. public void resetReferences()
  1099. {
  1100. if (_refs != null)
  1101. _refs.clear();
  1102. }
  1103. /**
  1104. * Starts the streaming message
  1105. *
  1106. * <p>A streaming message starts with 'P'</p>
  1107. *
  1108. * <pre>
  1109. * P x02 x00
  1110. * </pre>
  1111. */
  1112. public void writeStreamingObject(Object obj)
  1113. throws IOException
  1114. {
  1115. startStreamingPacket();
  1116. writeObject(obj);
  1117. endStreamingPacket();
  1118. }
  1119. /**
  1120. * Starts a streaming packet
  1121. *
  1122. * <p>A streaming message starts with 'P'</p>
  1123. *
  1124. * <pre>
  1125. * P x02 x00
  1126. * </pre>
  1127. */
  1128. public void startStreamingPacket()
  1129. throws IOException
  1130. {
  1131. if (_refs != null)
  1132. _refs.clear();
  1133. flush();
  1134. _isStreaming = true;
  1135. _offset = 3;
  1136. }
  1137. public void endStreamingPacket()
  1138. throws IOException
  1139. {
  1140. int len = _offset - 3;
  1141. _buffer[0] = (byte) 'P';
  1142. _buffer[1] = (byte) (len >> 8);
  1143. _buffer[2] = (byte) len;
  1144. _isStreaming = false;
  1145. flush();
  1146. }
  1147. /**
  1148. * Prints a string to the stream, encoded as UTF-8 with preceeding length
  1149. *
  1150. * @param v the string to print.
  1151. */
  1152. public void printLenString(String v)
  1153. throws IOException
  1154. {
  1155. if (SIZE < _offset + 16)
  1156. flush();
  1157. if (v == null) {
  1158. _buffer[_offset++] = (byte) (0);
  1159. _buffer[_offset++] = (byte) (0);
  1160. }
  1161. else {
  1162. int len = v.length();
  1163. _buffer[_offset++] = (byte) (len >> 8);
  1164. _buffer[_offset++] = (byte) (len);
  1165. printString(v, 0, len);
  1166. }
  1167. }
  1168. /**
  1169. * Prints a string to the stream, encoded as UTF-8
  1170. *
  1171. * @param v the string to print.
  1172. */
  1173. public void printString(String v)
  1174. throws IOException
  1175. {
  1176. printString(v, 0, v.length());
  1177. }
  1178. /**
  1179. * Prints a string to the stream, encoded as UTF-8
  1180. *
  1181. * @param v the string to print.
  1182. */
  1183. public void printString(String v, int strOffset, int length)
  1184. throws IOException
  1185. {
  1186. int offset = _offset;
  1187. byte []buffer = _buffer;
  1188. for (int i = 0; i < length; i++) {
  1189. if (SIZE <= offset + 16) {
  1190. _offset = offset;
  1191. flush();
  1192. offset = _offset;
  1193. }
  1194. char ch = v.charAt(i + strOffset);
  1195. if (ch < 0x80)
  1196. buffer[offset++] = (byte) (ch);
  1197. else if (ch < 0x800) {
  1198. buffer[offset++] = (byte) (0xc0 + ((ch >> 6) & 0x1f));
  1199. buffer[offset++] = (byte) (0x80 + (ch & 0x3f));
  1200. }
  1201. else {
  1202. buffer[offset++] = (byte) (0xe0 + ((ch >> 12) & 0xf));
  1203. buffer[offset++] = (byte) (0x80 + ((ch >> 6) & 0x3f));
  1204. buffer[offset++] = (byte) (0x80 + (ch & 0x3f));
  1205. }
  1206. }
  1207. _offset = offset;
  1208. }
  1209. /**
  1210. * Prints a string to the stream, encoded as UTF-8
  1211. *
  1212. * @param v the string to print.
  1213. */
  1214. public void printString(char []v, int strOffset, int length)
  1215. throws IOException
  1216. {
  1217. int offset = _offset;
  1218. byte []buffer = _buffer;
  1219. for (int i = 0; i < length; i++) {
  1220. if (SIZE <= offset + 16) {
  1221. _offset = offset;
  1222. flush();
  1223. offset = _offset;
  1224. }
  1225. char ch = v[i + strOffset];
  1226. if (ch < 0x80)
  1227. buffer[offset++] = (byte) (ch);
  1228. else if (ch < 0x800) {
  1229. buffer[offset++] = (byte) (0xc0 + ((ch >> 6) & 0x1f));
  1230. buffer[offset++] = (byte) (0x80 + (ch & 0x3f));
  1231. }
  1232. else {
  1233. buffer[offset++] = (byte) (0xe0 + ((ch >> 12) & 0xf));
  1234. buffer[offset++] = (byte) (0x80 + ((ch >> 6) & 0x3f));
  1235. buffer[offset++] = (byte) (0x80 + (ch & 0x3f));
  1236. }
  1237. }
  1238. _offset = offset;
  1239. }
  1240. private final void flushIfFull()
  1241. throws IOException
  1242. {
  1243. int offset = _offset;
  1244. if (SIZE < offset + 32) {
  1245. _offset = 0;
  1246. _os.write(_buffer, 0, offset);
  1247. }
  1248. }
  1249. public final void flush()
  1250. throws IOException
  1251. {
  1252. flushBuffer();
  1253. if (_os != null)
  1254. _os.flush();
  1255. }
  1256. public final void flushBuffer()
  1257. throws IOException
  1258. {
  1259. int offset = _offset;
  1260. if (! _isStreaming && offset > 0) {
  1261. _offset = 0;
  1262. _os.write(_buffer, 0, offset);
  1263. }
  1264. else if (_isStreaming && offset > 3) {
  1265. int len = offset - 3;
  1266. _buffer[0] = 'p';
  1267. _buffer[1] = (byte) (len >> 8);
  1268. _buffer[2] = (byte) len;
  1269. _offset = 3;
  1270. _os.write(_buffer, 0, offset);
  1271. }
  1272. }
  1273. public final void close()
  1274. throws IOException
  1275. {
  1276. // hessian/3a8c
  1277. flush();
  1278. OutputStream os = _os;
  1279. _os = null;
  1280. if (os != null) {
  1281. if (_isCloseStreamOnClose)
  1282. os.close();
  1283. }
  1284. }
  1285. class BytesOutputStream extends OutputStream {
  1286. private int _startOffset;
  1287. BytesOutputStream()
  1288. throws IOException
  1289. {
  1290. if (SIZE < _offset + 16) {
  1291. Hessian2Output.this.flush();
  1292. }
  1293. _startOffset = _offset;
  1294. _offset += 3; // skip 'b' xNN xNN
  1295. }
  1296. @Override
  1297. public void write(int ch)
  1298. throws IOException
  1299. {
  1300. if (SIZE <= _offset) {
  1301. int length = (_offset - _startOffset) - 3;
  1302. _buffer[_startOffset] = (byte) BC_BINARY_CHUNK;
  1303. _buffer[_startOffset + 1] = (byte) (length >> 8);
  1304. _buffer[_startOffset + 2] = (byte) (length);
  1305. Hessian2Output.this.flush();
  1306. _startOffset = _offset;
  1307. _offset += 3;
  1308. }
  1309. _buffer[_offset++] = (byte) ch;
  1310. }
  1311. @Override
  1312. public void write(byte []buffer, int offset, int length)
  1313. throws IOException
  1314. {
  1315. while (length > 0) {
  1316. int sublen = SIZE - _offset;
  1317. if (length < sublen)
  1318. sublen = length;
  1319. if (sublen > 0) {
  1320. System.arraycopy(buffer, offset, _buffer, _offset, sublen);
  1321. _offset += sublen;
  1322. }
  1323. length -= sublen;
  1324. offset += sublen;
  1325. if (SIZE <= _offset) {
  1326. int chunkLength = (_offset - _startOffset) - 3;
  1327. _buffer[_startOffset] = (byte) BC_BINARY_CHUNK;
  1328. _buffer[_startOffset + 1] = (byte) (chunkLength >> 8);
  1329. _buffer[_startOffset + 2] = (byte) (chunkLength);
  1330. Hessian2Output.this.flush();
  1331. _startOffset = _offset;
  1332. _offset += 3;
  1333. }
  1334. }
  1335. }
  1336. @Override
  1337. public void close()
  1338. throws IOException
  1339. {
  1340. int startOffset = _startOffset;
  1341. _startOffset = -1;
  1342. if (startOffset < 0)
  1343. return;
  1344. int length = (_offset - startOffset) - 3;
  1345. _buffer[startOffset] = (byte) 'B';
  1346. _buffer[startOffset + 1] = (byte) (length >> 8);
  1347. _buffer[startOffset + 2] = (byte) (length);
  1348. Hessian2Output.this.flush();
  1349. }
  1350. }
  1351. }