PageRenderTime 61ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/JAwaPI/src/org/zeromq/ZMQ.java

https://github.com/s-faychatelard/API
Java | 1600 lines | 630 code | 204 blank | 766 comment | 54 complexity | ec2cdc78a08f214eab6195fc9ad0379e MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. Copyright (c) 1991-2011 iMatix Corporation <www.imatix.com>
  3. Copyright other contributors as noted in the AUTHORS file.
  4. This file is part of 0MQ.
  5. 0MQ is free software; you can redistribute it and/or modify it under
  6. the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version.
  9. 0MQ is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. package org.zeromq;
  17. import java.nio.channels.SelectableChannel;
  18. import zmq.Ctx;
  19. import zmq.DecoderBase;
  20. import zmq.EncoderBase;
  21. import zmq.SocketBase;
  22. import zmq.ZError;
  23. public class ZMQ {
  24. /**
  25. * Socket flag to indicate that more message parts are coming.
  26. */
  27. public static final int SNDMORE = zmq.ZMQ.ZMQ_SNDMORE;
  28. // Values for flags in Socket's send and recv functions.
  29. /**
  30. * Socket flag to indicate a nonblocking send or recv mode.
  31. */
  32. public static final int DONTWAIT = zmq.ZMQ.ZMQ_DONTWAIT;
  33. public static final int NOBLOCK = zmq.ZMQ.ZMQ_DONTWAIT;
  34. // Socket types, used when creating a Socket.
  35. /**
  36. * Flag to specify a exclusive pair of sockets.
  37. */
  38. public static final int PAIR = zmq.ZMQ.ZMQ_PAIR;
  39. /**
  40. * Flag to specify a PUB socket, receiving side must be a SUB or XSUB.
  41. */
  42. public static final int PUB = zmq.ZMQ.ZMQ_PUB;
  43. /**
  44. * Flag to specify the receiving part of the PUB or XPUB socket.
  45. */
  46. public static final int SUB = zmq.ZMQ.ZMQ_SUB;
  47. /**
  48. * Flag to specify a REQ socket, receiving side must be a REP.
  49. */
  50. public static final int REQ = zmq.ZMQ.ZMQ_REQ;
  51. /**
  52. * Flag to specify the receiving part of a REQ socket.
  53. */
  54. public static final int REP = zmq.ZMQ.ZMQ_REP;
  55. /**
  56. * Flag to specify a DEALER socket (aka XREQ).
  57. * DEALER is really a combined ventilator / sink
  58. * that does load-balancing on output and fair-queuing on input
  59. * with no other semantics. It is the only socket type that lets
  60. * you shuffle messages out to N nodes and shuffle the replies
  61. * back, in a raw bidirectional asynch pattern.
  62. */
  63. public static final int DEALER = zmq.ZMQ.ZMQ_DEALER;
  64. /**
  65. * Old alias for DEALER flag.
  66. * Flag to specify a XREQ socket, receiving side must be a XREP.
  67. *
  68. * @deprecated As of release 3.0 of zeromq, replaced by {@link #DEALER}
  69. */
  70. public static final int XREQ = DEALER;
  71. /**
  72. * Flag to specify ROUTER socket (aka XREP).
  73. * ROUTER is the socket that creates and consumes request-reply
  74. * routing envelopes. It is the only socket type that lets you route
  75. * messages to specific connections if you know their identities.
  76. */
  77. public static final int ROUTER = zmq.ZMQ.ZMQ_ROUTER;
  78. /**
  79. * Old alias for ROUTER flag.
  80. * Flag to specify the receiving part of a XREQ socket.
  81. *
  82. * @deprecated As of release 3.0 of zeromq, replaced by {@link #ROUTER}
  83. */
  84. public static final int XREP = ROUTER;
  85. /**
  86. * Flag to specify the receiving part of a PUSH socket.
  87. */
  88. public static final int PULL = zmq.ZMQ.ZMQ_PULL;
  89. /**
  90. * Flag to specify a PUSH socket, receiving side must be a PULL.
  91. */
  92. public static final int PUSH = zmq.ZMQ.ZMQ_PUSH;
  93. /**
  94. * Flag to specify a XPUB socket, receiving side must be a SUB or XSUB.
  95. * Subscriptions can be received as a message. Subscriptions start with
  96. * a '1' byte. Unsubscriptions start with a '0' byte.
  97. */
  98. public static final int XPUB = zmq.ZMQ.ZMQ_XPUB;
  99. /**
  100. * Flag to specify the receiving part of the PUB or XPUB socket. Allows
  101. */
  102. public static final int XSUB = zmq.ZMQ.ZMQ_XSUB;
  103. /**
  104. * Flag to specify a STREAMER device.
  105. */
  106. public static final int STREAMER = zmq.ZMQ.ZMQ_STREAMER ;
  107. /**
  108. * Flag to specify a FORWARDER device.
  109. */
  110. public static final int FORWARDER = zmq.ZMQ.ZMQ_FORWARDER ;
  111. /**
  112. * Flag to specify a QUEUE device.
  113. */
  114. public static final int QUEUE = zmq.ZMQ.ZMQ_QUEUE ;
  115. /**
  116. * @see org.zeromq.ZMQ#PULL
  117. */
  118. @Deprecated
  119. public static final int UPSTREAM = PULL;
  120. /**
  121. * @see org.zeromq.ZMQ#PUSH
  122. */
  123. @Deprecated
  124. public static final int DOWNSTREAM = PUSH;
  125. /**
  126. * ZMQ Events
  127. */
  128. public static final int EVENT_CONNECTED = zmq.ZMQ.ZMQ_EVENT_CONNECTED;
  129. public static final int EVENT_DELAYED = zmq.ZMQ.ZMQ_EVENT_CONNECT_DELAYED;
  130. public static final int EVENT_RETRIED = zmq.ZMQ.ZMQ_EVENT_CONNECT_RETRIED;
  131. public static final int EVENT_CONNECT_FAILED = zmq.ZMQ.ZMQ_EVENT_CONNECT_FAILED;
  132. public static final int EVENT_LISTENING = zmq.ZMQ.ZMQ_EVENT_LISTENING;
  133. public static final int EVENT_BIND_FAILED = zmq.ZMQ.ZMQ_EVENT_BIND_FAILED;
  134. public static final int EVENT_ACCEPTED = zmq.ZMQ.ZMQ_EVENT_ACCEPTED;
  135. public static final int EVENT_ACCEPT_FAILED = zmq.ZMQ.ZMQ_EVENT_ACCEPT_FAILED;
  136. public static final int EVENT_CLOSED = zmq.ZMQ.ZMQ_EVENT_CLOSED;
  137. public static final int EVENT_CLOSE_FAILED = zmq.ZMQ.ZMQ_EVENT_CLOSE_FAILED;
  138. public static final int EVENT_DISCONNECTED = zmq.ZMQ.ZMQ_EVENT_DISCONNECTED;
  139. public static final int EVENT_ALL = zmq.ZMQ.ZMQ_EVENT_ALL;
  140. /**
  141. * Create a new Context.
  142. *
  143. * @param ioThreads
  144. * Number of threads to use, usually 1 is sufficient for most use cases.
  145. * @return the Context
  146. */
  147. public static Context context(int ioThreads) {
  148. return new Context(ioThreads);
  149. }
  150. public static class Context {
  151. private final Ctx ctx;
  152. /**
  153. * Class constructor.
  154. *
  155. * @param ioThreads
  156. * size of the threads pool to handle I/O operations.
  157. */
  158. protected Context(int ioThreads) {
  159. ctx = zmq.ZMQ.zmq_init(ioThreads);
  160. }
  161. /**
  162. * This is an explicit "destructor". It can be called to ensure the corresponding 0MQ
  163. * Context has been disposed of.
  164. */
  165. public void term() {
  166. ctx.terminate();
  167. }
  168. /**
  169. * Create a new Socket within this context.
  170. *
  171. * @param type
  172. * the socket type.
  173. * @return the newly created Socket.
  174. */
  175. public Socket socket(int type) {
  176. return new Socket(this, type);
  177. }
  178. /**
  179. * Create a new Poller within this context, with a default size.
  180. *
  181. * @return the newly created Poller.
  182. * @deprecated Use poller constructor
  183. */
  184. public Poller poller () {
  185. return new Poller (this);
  186. }
  187. /**
  188. * Create a new Poller within this context, with a specified initial size.
  189. *
  190. * @param size
  191. * the poller initial size.
  192. * @return the newly created Poller.
  193. * @deprecated Use poller constructor
  194. */
  195. public Poller poller (int size) {
  196. return new Poller (this, size);
  197. }
  198. }
  199. public static class Socket {
  200. // This port range is defined by IANA for dynamic or private ports
  201. // We use this when choosing a port for dynamic binding.
  202. private static final int DYNFROM = 0xc000;
  203. private static final int DYNTO = 0xffff;
  204. private final Ctx ctx;
  205. private final SocketBase base;
  206. /**
  207. * Class constructor.
  208. *
  209. * @param context
  210. * a 0MQ context previously created.
  211. * @param type
  212. * the socket type.
  213. */
  214. protected Socket(Context context, int type) {
  215. ctx = context.ctx;
  216. base = ctx.create_socket(type);
  217. mayRaise();
  218. }
  219. protected Socket(SocketBase base_) {
  220. ctx = null;
  221. base = base_;
  222. }
  223. protected SocketBase base() {
  224. return base;
  225. }
  226. private final static void mayRaise ()
  227. {
  228. if (!ZError.is (0) && !ZError.is (ZError.EAGAIN))
  229. throw new ZMQException (ZError.errno ());
  230. }
  231. private final static void mayRaiseNot (int codeToIgnore)
  232. {
  233. if (!ZError.is (codeToIgnore))
  234. mayRaise ();
  235. }
  236. /**
  237. * This is an explicit "destructor". It can be called to ensure the corresponding 0MQ Socket
  238. * has been disposed of.
  239. */
  240. public final void close() {
  241. base.close();
  242. }
  243. /**
  244. * The 'ZMQ_TYPE option shall retrieve the socket type for the specified
  245. * 'socket'. The socket type is specified at socket creation time and
  246. * cannot be modified afterwards.
  247. *
  248. * @return the socket type.
  249. */
  250. public final int getType () {
  251. return base.getsockopt(zmq.ZMQ.ZMQ_TYPE);
  252. }
  253. /**
  254. * @see #setLinger(long)
  255. *
  256. * @return the linger period.
  257. */
  258. public final long getLinger() {
  259. return base.getsockopt(zmq.ZMQ.ZMQ_LINGER);
  260. }
  261. /**
  262. * The 'ZMQ_LINGER' option shall retrieve the period for pending outbound
  263. * messages to linger in memory after closing the socket. Value of -1 means
  264. * infinite. Pending messages will be kept until they are fully transferred to
  265. * the peer. Value of 0 means that all the pending messages are dropped immediately
  266. * when socket is closed. Positive value means number of milliseconds to keep
  267. * trying to send the pending messages before discarding them.
  268. *
  269. * @param value
  270. * the linger period in milliseconds.
  271. */
  272. public final void setLinger (long value)
  273. {
  274. base.setsockopt (zmq.ZMQ.ZMQ_LINGER, (int) value);
  275. mayRaiseNot (ZError.ETERM);
  276. }
  277. /**
  278. * @see #setReconnectIVL(long)
  279. *
  280. * @return the reconnectIVL.
  281. */
  282. public final long getReconnectIVL() {
  283. return base.getsockopt(zmq.ZMQ.ZMQ_RECONNECT_IVL);
  284. }
  285. /**
  286. */
  287. public final void setReconnectIVL(long value) {
  288. base.setsockopt(zmq.ZMQ.ZMQ_RECONNECT_IVL, (int)value);
  289. mayRaiseNot (ZError.ETERM);
  290. }
  291. /**
  292. * @see #setBacklog(long)
  293. *
  294. * @return the backlog.
  295. */
  296. public final long getBacklog() {
  297. return base.getsockopt(zmq.ZMQ.ZMQ_BACKLOG);
  298. }
  299. /**
  300. */
  301. public final void setBacklog(long value) {
  302. base.setsockopt(zmq.ZMQ.ZMQ_BACKLOG, (int)value);
  303. mayRaiseNot (ZError.ETERM);
  304. }
  305. /**
  306. * @see #setReconnectIVLMax(long)
  307. *
  308. * @return the reconnectIVLMax.
  309. */
  310. public final long getReconnectIVLMax () {
  311. return base.getsockopt(zmq.ZMQ.ZMQ_RECONNECT_IVL_MAX);
  312. }
  313. /**
  314. */
  315. public final void setReconnectIVLMax (long value) {
  316. base.setsockopt(zmq.ZMQ.ZMQ_RECONNECT_IVL_MAX, (int)value);
  317. mayRaiseNot (ZError.ETERM);
  318. }
  319. /**
  320. * @see #setMaxMsgSize(long)
  321. *
  322. * @return the maxMsgSize.
  323. */
  324. public final long getMaxMsgSize() {
  325. return (Long)base.getsockoptx(zmq.ZMQ.ZMQ_MAXMSGSIZE);
  326. }
  327. /**
  328. */
  329. public final void setMaxMsgSize(long value) {
  330. base.setsockopt(zmq.ZMQ.ZMQ_MAXMSGSIZE, value);
  331. mayRaiseNot (ZError.ETERM);
  332. }
  333. /**
  334. * @see #setSndHWM(long)
  335. *
  336. * @return the SndHWM.
  337. */
  338. public final long getSndHWM() {
  339. return base.getsockopt(zmq.ZMQ.ZMQ_SNDHWM);
  340. }
  341. /**
  342. */
  343. public final void setSndHWM(long value) {
  344. base.setsockopt(zmq.ZMQ.ZMQ_SNDHWM, (int)value);
  345. mayRaiseNot (ZError.ETERM);
  346. }
  347. /**
  348. * @see #setRcvHWM(long)
  349. *
  350. * @return the recvHWM period.
  351. */
  352. public final long getRcvHWM() {
  353. return base.getsockopt(zmq.ZMQ.ZMQ_RCVHWM);
  354. }
  355. /**
  356. */
  357. public final void setRcvHWM(long value) {
  358. base.setsockopt(zmq.ZMQ.ZMQ_RCVHWM, (int)value);
  359. mayRaiseNot (ZError.ETERM);
  360. }
  361. /**
  362. * @see #setHWM(long)
  363. *
  364. * @return the High Water Mark.
  365. */
  366. @Deprecated
  367. public final long getHWM() {
  368. return -1;
  369. }
  370. /**
  371. * The 'ZMQ_HWM' option shall set the high water mark for the specified 'socket'. The high
  372. * water mark is a hard limit on the maximum number of outstanding messages 0MQ shall queue
  373. * in memory for any single peer that the specified 'socket' is communicating with.
  374. *
  375. * If this limit has been reached the socket shall enter an exceptional state and depending
  376. * on the socket type, 0MQ shall take appropriate action such as blocking or dropping sent
  377. * messages. Refer to the individual socket descriptions in the man page of zmq_socket[3] for
  378. * details on the exact action taken for each socket type.
  379. *
  380. * @param hwm
  381. * the number of messages to queue.
  382. */
  383. public final void setHWM(long hwm) {
  384. setSndHWM (hwm);
  385. setRcvHWM (hwm);
  386. }
  387. /**
  388. * @see #setSwap(long)
  389. *
  390. * @return the number of messages to swap at most.
  391. */
  392. @Deprecated
  393. public final long getSwap() {
  394. // not support at zeromq 3
  395. return -1L;
  396. }
  397. /**
  398. * Get the Swap. The 'ZMQ_SWAP' option shall set the disk offload (swap) size for the
  399. * specified 'socket'. A socket which has 'ZMQ_SWAP' set to a non-zero value may exceed its
  400. * high water mark; in this case outstanding messages shall be offloaded to storage on disk
  401. * rather than held in memory.
  402. *
  403. * @param value
  404. * The value of 'ZMQ_SWAP' defines the maximum size of the swap space in bytes.
  405. */
  406. @Deprecated
  407. public final void setSwap(long value) {
  408. throw new UnsupportedOperationException ();
  409. }
  410. /**
  411. * @see #setAffinity(long)
  412. *
  413. * @return the affinity.
  414. */
  415. public final long getAffinity() {
  416. return (Long)base.getsockoptx(zmq.ZMQ.ZMQ_AFFINITY);
  417. }
  418. /**
  419. * Get the Affinity. The 'ZMQ_AFFINITY' option shall set the I/O thread affinity for newly
  420. * created connections on the specified 'socket'.
  421. *
  422. * Affinity determines which threads from the 0MQ I/O thread pool associated with the
  423. * socket's _context_ shall handle newly created connections. A value of zero specifies no
  424. * affinity, meaning that work shall be distributed fairly among all 0MQ I/O threads in the
  425. * thread pool. For non-zero values, the lowest bit corresponds to thread 1, second lowest
  426. * bit to thread 2 and so on. For example, a value of 3 specifies that subsequent
  427. * connections on 'socket' shall be handled exclusively by I/O threads 1 and 2.
  428. *
  429. * See also in the man page of zmq_init[3] for details on allocating the number of I/O threads for a
  430. * specific _context_.
  431. *
  432. * @param value
  433. * the io_thread affinity.
  434. */
  435. public final void setAffinity (long value) {
  436. base.setsockopt(zmq.ZMQ.ZMQ_AFFINITY, value);
  437. mayRaiseNot (ZError.ETERM);
  438. }
  439. /**
  440. * @see #setIdentity(byte[])
  441. *
  442. * @return the Identitiy.
  443. */
  444. public final byte[] getIdentity() {
  445. return (byte[]) base.getsockoptx(zmq.ZMQ.ZMQ_IDENTITY);
  446. }
  447. /**
  448. * The 'ZMQ_IDENTITY' option shall set the identity of the specified 'socket'. Socket
  449. * identity determines if existing 0MQ infastructure (_message queues_, _forwarding
  450. * devices_) shall be identified with a specific application and persist across multiple
  451. * runs of the application.
  452. *
  453. * If the socket has no identity, each run of an application is completely separate from
  454. * other runs. However, with identity set the socket shall re-use any existing 0MQ
  455. * infrastructure configured by the previous run(s). Thus the application may receive
  456. * messages that were sent in the meantime, _message queue_ limits shall be shared with
  457. * previous run(s) and so on.
  458. *
  459. * Identity should be at least one byte and at most 255 bytes long. Identities starting with
  460. * binary zero are reserved for use by 0MQ infrastructure.
  461. *
  462. * @param identity
  463. */
  464. public final void setIdentity(byte[] identity) {
  465. base.setsockopt(zmq.ZMQ.ZMQ_IDENTITY, identity);
  466. mayRaiseNot (ZError.ETERM);
  467. }
  468. /**
  469. * @see #setRate(long)
  470. *
  471. * @return the Rate.
  472. */
  473. public final long getRate() {
  474. return base.getsockopt(zmq.ZMQ.ZMQ_RATE);
  475. }
  476. /**
  477. * The 'ZMQ_RATE' option shall set the maximum send or receive data rate for multicast
  478. * transports such as in the man page of zmq_pgm[7] using the specified 'socket'.
  479. *
  480. * @param value maximum send or receive data rate for multicast, default 100
  481. */
  482. public final void setRate (long value) {
  483. throw new UnsupportedOperationException ();
  484. }
  485. /**
  486. * @see #setRecoveryInterval(long)
  487. *
  488. * @return the RecoveryIntervall.
  489. */
  490. public final long getRecoveryInterval () {
  491. return base.getsockopt(zmq.ZMQ.ZMQ_RECOVERY_IVL);
  492. }
  493. /**
  494. * The 'ZMQ_RECOVERY_IVL' option shall set the recovery interval for multicast transports
  495. * using the specified 'socket'. The recovery interval determines the maximum time in
  496. * seconds that a receiver can be absent from a multicast group before unrecoverable data
  497. * loss will occur.
  498. *
  499. * CAUTION: Excersize care when setting large recovery intervals as the data needed for
  500. * recovery will be held in memory. For example, a 1 minute recovery interval at a data rate
  501. * of 1Gbps requires a 7GB in-memory buffer. {Purpose of this Method}
  502. *
  503. * @param value recovery interval for multicast in milliseconds, default 10000
  504. */
  505. public final void setRecoveryInterval (long value) {
  506. throw new UnsupportedOperationException ();
  507. }
  508. /**
  509. * @see #setMulticastLoop(boolean)
  510. *
  511. * @return the Multicast Loop.
  512. */
  513. @Deprecated
  514. public final boolean hasMulticastLoop () {
  515. return false;
  516. }
  517. /**
  518. * The 'ZMQ_MCAST_LOOP' option shall control whether data sent via multicast transports
  519. * using the specified 'socket' can also be received by the sending host via loopback. A
  520. * value of zero disables the loopback functionality, while the default value of 1 enables
  521. * the loopback functionality. Leaving multicast loopback enabled when it is not required
  522. * can have a negative impact on performance. Where possible, disable 'ZMQ_MCAST_LOOP' in
  523. * production environments.
  524. *
  525. * @param mcast_loop
  526. */
  527. @Deprecated
  528. public final void setMulticastLoop (boolean mcast_loop) {
  529. throw new UnsupportedOperationException ();
  530. }
  531. /**
  532. * @see #setMulticastHops(long)
  533. *
  534. * @return the Multicast Hops.
  535. */
  536. public final long getMulticastHops () {
  537. return base.getsockopt(zmq.ZMQ.ZMQ_MULTICAST_HOPS);
  538. }
  539. /**
  540. * Sets the time-to-live field in every multicast packet sent from this socket.
  541. * The default is 1 which means that the multicast packets don't leave the local
  542. * network.
  543. *
  544. * @param value time-to-live field in every multicast packet, default 1
  545. */
  546. public final void setMulticastHops (long value) {
  547. throw new UnsupportedOperationException ();
  548. }
  549. /**
  550. * @see #setReceiveTimeOut(int)
  551. *
  552. * @return the Receive Timeout in milliseconds.
  553. */
  554. public final int getReceiveTimeOut() {
  555. return base.getsockopt(zmq.ZMQ.ZMQ_RCVTIMEO);
  556. }
  557. /**
  558. * Sets the timeout for receive operation on the socket. If the value is 0, recv
  559. * will return immediately, with null if there is no message to receive.
  560. * If the value is -1, it will block until a message is available. For all other
  561. * values, it will wait for a message for that amount of time before returning with
  562. * a null and an EAGAIN error.
  563. *
  564. * @param value Timeout for receive operation in milliseconds. Default -1 (infinite)
  565. */
  566. public final void setReceiveTimeOut (int value) {
  567. base.setsockopt(zmq.ZMQ.ZMQ_RCVTIMEO, value);
  568. mayRaiseNot (ZError.ETERM);
  569. }
  570. /**
  571. * @see #setSendTimeOut(int)
  572. *
  573. * @return the Send Timeout in milliseconds.
  574. */
  575. public final int getSendTimeOut() {
  576. return (int)base.getsockopt(zmq.ZMQ.ZMQ_SNDTIMEO);
  577. }
  578. /**
  579. * Sets the timeout for send operation on the socket. If the value is 0, send
  580. * will return immediately, with a false if the message cannot be sent.
  581. * If the value is -1, it will block until the message is sent. For all other
  582. * values, it will try to send the message for that amount of time before
  583. * returning with false and an EAGAIN error.
  584. *
  585. * @param value Timeout for send operation in milliseconds. Default -1 (infinite)
  586. */
  587. public final void setSendTimeOut(int value) {
  588. base.setsockopt(zmq.ZMQ.ZMQ_SNDTIMEO, value);
  589. mayRaiseNot (ZError.ETERM);
  590. }
  591. /**
  592. * @see #setSendBufferSize(long)
  593. *
  594. * @return the kernel send buffer size.
  595. */
  596. public final long getSendBufferSize() {
  597. return base.getsockopt(zmq.ZMQ.ZMQ_SNDBUF);
  598. }
  599. /**
  600. * The 'ZMQ_SNDBUF' option shall set the underlying kernel transmit buffer size for the
  601. * 'socket' to the specified size in bytes. A value of zero means leave the OS default
  602. * unchanged. For details please refer to your operating system documentation for the
  603. * 'SO_SNDBUF' socket option.
  604. *
  605. * @param value underlying kernel transmit buffer size for the 'socket' in bytes
  606. * A value of zero means leave the OS default unchanged.
  607. */
  608. public final void setSendBufferSize(long value) {
  609. base.setsockopt(zmq.ZMQ.ZMQ_SNDBUF, (int)value);
  610. mayRaiseNot (ZError.ETERM);
  611. }
  612. /**
  613. * @see #setReceiveBufferSize(long)
  614. *
  615. * @return the kernel receive buffer size.
  616. */
  617. public final long getReceiveBufferSize() {
  618. return base.getsockopt(zmq.ZMQ.ZMQ_RCVBUF);
  619. }
  620. /**
  621. * The 'ZMQ_RCVBUF' option shall set the underlying kernel receive buffer size for the
  622. * 'socket' to the specified size in bytes.
  623. * For details refer to your operating system documentation for the 'SO_RCVBUF'
  624. * socket option.
  625. *
  626. * @param value Underlying kernel receive buffer size for the 'socket' in bytes.
  627. * A value of zero means leave the OS default unchanged.
  628. */
  629. public final void setReceiveBufferSize(long value) {
  630. base.setsockopt(zmq.ZMQ.ZMQ_RCVBUF, (int)value);
  631. mayRaiseNot (ZError.ETERM);
  632. }
  633. /**
  634. * The 'ZMQ_RCVMORE' option shall return a boolean value indicating if the multi-part
  635. * message currently being read from the specified 'socket' has more message parts to
  636. * follow. If there are no message parts to follow or if the message currently being read is
  637. * not a multi-part message a value of zero shall be returned. Otherwise, a value of 1 shall
  638. * be returned.
  639. *
  640. * @return true if there are more messages to receive.
  641. */
  642. public final boolean hasReceiveMore ()
  643. {
  644. return base.getsockopt (zmq.ZMQ.ZMQ_RCVMORE) == 1;
  645. }
  646. /**
  647. * The 'ZMQ_FD' option shall retrieve file descriptor associated with the 0MQ
  648. * socket. The descriptor can be used to integrate 0MQ socket into an existing
  649. * event loop. It should never be used for anything else than polling -- such as
  650. * reading or writing. The descriptor signals edge-triggered IN event when
  651. * something has happened within the 0MQ socket. It does not necessarily mean that
  652. * the messages can be read or written. Check ZMQ_EVENTS option to find out whether
  653. * the 0MQ socket is readable or writeable.
  654. *
  655. * @return the underlying file descriptor.
  656. */
  657. public final SelectableChannel getFD() {
  658. return (SelectableChannel)base.getsockoptx(zmq.ZMQ.ZMQ_FD);
  659. }
  660. /**
  661. * The 'ZMQ_EVENTS' option shall retrieve event flags for the specified socket.
  662. * If a message can be read from the socket ZMQ_POLLIN flag is set. If message can
  663. * be written to the socket ZMQ_POLLOUT flag is set.
  664. *
  665. * @return the mask of outstanding events.
  666. */
  667. public final int getEvents() {
  668. return base.getsockopt(zmq.ZMQ.ZMQ_EVENTS);
  669. }
  670. /**
  671. * The 'ZMQ_SUBSCRIBE' option shall establish a new message filter on a 'ZMQ_SUB' socket.
  672. * Newly created 'ZMQ_SUB' sockets shall filter out all incoming messages, therefore you
  673. * should call this option to establish an initial message filter.
  674. *
  675. * An empty 'option_value' of length zero shall subscribe to all incoming messages. A
  676. * non-empty 'option_value' shall subscribe to all messages beginning with the specified
  677. * prefix. Mutiple filters may be attached to a single 'ZMQ_SUB' socket, in which case a
  678. * message shall be accepted if it matches at least one filter.
  679. *
  680. * @param topic
  681. */
  682. public final void subscribe(byte[] topic) {
  683. base.setsockopt(zmq.ZMQ.ZMQ_SUBSCRIBE, topic);
  684. mayRaiseNot (ZError.ETERM);
  685. }
  686. /**
  687. * The 'ZMQ_UNSUBSCRIBE' option shall remove an existing message filter on a 'ZMQ_SUB'
  688. * socket. The filter specified must match an existing filter previously established with
  689. * the 'ZMQ_SUBSCRIBE' option. If the socket has several instances of the same filter
  690. * attached the 'ZMQ_UNSUBSCRIBE' option shall remove only one instance, leaving the rest in
  691. * place and functional.
  692. *
  693. * @param topic
  694. */
  695. public final void unsubscribe(byte[] topic) {
  696. base.setsockopt(zmq.ZMQ.ZMQ_UNSUBSCRIBE, topic);
  697. mayRaiseNot (ZError.ETERM);
  698. }
  699. /**
  700. * Set custom Encoder
  701. * @param cls
  702. */
  703. public final void setEncoder(Class<? extends EncoderBase> cls) {
  704. base.setsockopt(zmq.ZMQ.ZMQ_ENCODER, cls);
  705. }
  706. /**
  707. * Set custom Decoder
  708. * @param cls
  709. */
  710. public final void setDecoder(Class<? extends DecoderBase> cls) {
  711. base.setsockopt(zmq.ZMQ.ZMQ_DECODER, cls);
  712. }
  713. /**
  714. * Sets the ROUTER socket behavior when an unroutable message is encountered.
  715. *
  716. * @param mandatory A value of false is the default and discards the message silently when it cannot be routed.
  717. * A value of true returns an EHOSTUNREACH error code if the message cannot be routed.
  718. */
  719. public final void setRouterMandatory (boolean mandatory) {
  720. base.setsockopt (zmq.ZMQ.ZMQ_ROUTER_MANDATORY, mandatory ? 1 : 0);
  721. mayRaiseNot (ZError.ETERM);
  722. }
  723. /**
  724. * Sets the XPUB socket behavior on new subscriptions and unsubscriptions.
  725. *
  726. * @param verbose A value of false is the default and passes only new subscription messages to upstream.
  727. * A value of true passes all subscription messages upstream.
  728. */
  729. public final void setXpubVerbose(boolean verbose) {
  730. base.setsockopt(zmq.ZMQ.ZMQ_XPUB_VERBOSE, verbose ? 1 : 0);
  731. mayRaiseNot (ZError.ETERM);
  732. }
  733. /**
  734. * @see #setIPv4Only (boolean)
  735. *
  736. * @return the IPV4ONLY
  737. */
  738. public final boolean getIPv4Only () {
  739. return base.getsockopt (zmq.ZMQ.ZMQ_IPV4ONLY) == 1;
  740. }
  741. /**
  742. * The 'ZMQ_IPV4ONLY' option shall set the underlying native socket type.
  743. * An IPv6 socket lets applications connect to and accept connections from both IPv4 and IPv6 hosts.
  744. *
  745. * @param v4only A value of true will use IPv4 sockets, while the value of false will use IPv6 sockets
  746. */
  747. public void setIPv4Only (boolean v4only) {
  748. base.setsockopt (zmq.ZMQ.ZMQ_IPV4ONLY, v4only ? 1 : 0);
  749. mayRaiseNot (ZError.ETERM);
  750. }
  751. /**
  752. * @see #setTCPKeepAlive(int)
  753. *
  754. * @return the keep alive setting.
  755. */
  756. public int getTCPKeepAlive() {
  757. return base.getsockopt(zmq.ZMQ.ZMQ_TCP_KEEPALIVE);
  758. }
  759. /**
  760. * Override SO_KEEPALIVE socket option (where supported by OS) to enable keep-alive packets for a socket
  761. * connection. Possible values are -1, 0, 1. The default value -1 will skip all overrides and do the OS default.
  762. *
  763. * @param optVal The value of 'ZMQ_TCP_KEEPALIVE' to turn TCP keepalives on (1) or off (0).
  764. */
  765. public void setTCPKeepAlive(int optVal) {
  766. base.setsockopt(zmq.ZMQ.ZMQ_TCP_KEEPALIVE, (int)optVal);
  767. mayRaiseNot (ZError.ETERM);
  768. }
  769. /**
  770. * Bind to network interface. Start listening for new connections.
  771. *
  772. * @param addr
  773. * the endpoint to bind to.
  774. */
  775. public final int bind (String addr)
  776. {
  777. return bind (addr, DYNFROM, DYNTO);
  778. }
  779. /**
  780. * Bind to network interface. Start listening for new connections.
  781. *
  782. * @param addr
  783. * the endpoint to bind to.
  784. * @param min
  785. * The minimum port in the range of ports to try.
  786. * @param max
  787. * The maximum port in the range of ports to try.
  788. */
  789. private final int bind (String addr, int min, int max)
  790. {
  791. if (addr.endsWith (":*")) {
  792. int port = min;
  793. String prefix = addr.substring (0, addr.lastIndexOf (':') + 1);
  794. while (port <= max) {
  795. addr = prefix + port;
  796. // Try to bind on the next plausible port
  797. if (base.bind (addr))
  798. return port;
  799. port++;
  800. }
  801. } else {
  802. if (base.bind(addr)) {
  803. int port = 0;
  804. try {
  805. port = Integer.parseInt (
  806. addr.substring (addr.lastIndexOf (':') + 1));
  807. } catch (NumberFormatException e) {
  808. }
  809. return port;
  810. }
  811. }
  812. mayRaise ();
  813. return -1;
  814. }
  815. /**
  816. * Bind to network interface to a random port. Start listening for new
  817. * connections.
  818. *
  819. * @param addr
  820. * the endpoint to bind to.
  821. */
  822. public int bindToRandomPort (String addr)
  823. {
  824. return bind (addr + ":*", DYNFROM, DYNTO);
  825. }
  826. /**
  827. * Bind to network interface to a random port. Start listening for new
  828. * connections.
  829. *
  830. * @param addr
  831. * the endpoint to bind to.
  832. * @param min
  833. * The minimum port in the range of ports to try.
  834. * @param max
  835. * The maximum port in the range of ports to try.
  836. */
  837. public int bindToRandomPort (String addr, int min, int max)
  838. {
  839. return bind (addr + ":*", min, max);
  840. }
  841. /**
  842. * Connect to remote application.
  843. *
  844. * @param addr
  845. * the endpoint to connect to.
  846. */
  847. public final void connect (String addr) {
  848. base.connect (addr);
  849. mayRaise ();
  850. }
  851. /**
  852. * Disconnect to remote application.
  853. *
  854. * @param addr
  855. * the endpoint to disconnect to.
  856. */
  857. public final boolean disconnect (String addr) {
  858. boolean ret = base.term_endpoint (addr);
  859. mayRaise ();
  860. return ret;
  861. }
  862. public final boolean send (String data) {
  863. return send (data.getBytes (), 0);
  864. }
  865. public final boolean sendMore (String data) {
  866. return send(data.getBytes (), zmq.ZMQ.ZMQ_SNDMORE);
  867. }
  868. public final boolean send (String data, int flags) {
  869. return send(data.getBytes (), flags);
  870. }
  871. public final boolean send (byte[] data) {
  872. return send(data, 0);
  873. }
  874. public final boolean sendMore (byte[] data) {
  875. return send(data, zmq.ZMQ.ZMQ_SNDMORE);
  876. }
  877. public final boolean send (byte[] data, int flags) {
  878. zmq.Msg msg = new zmq.Msg(data);
  879. if (base.send(msg, flags))
  880. return true;
  881. mayRaise ();
  882. return false;
  883. }
  884. /**
  885. * Receive a message.
  886. *
  887. * @return the message received, as an array of bytes; null on error.
  888. */
  889. public final byte[] recv ()
  890. {
  891. return recv (0);
  892. }
  893. /**
  894. * Receive a message.
  895. *
  896. * @param flags
  897. * the flags to apply to the receive operation.
  898. * @return the message received, as an array of bytes; null on error.
  899. */
  900. public final byte[] recv (int flags)
  901. {
  902. zmq.Msg msg = base.recv(flags);
  903. if (msg != null) {
  904. return msg.data();
  905. }
  906. mayRaise ();
  907. return null;
  908. }
  909. /**
  910. * Receive a message in to a specified buffer.
  911. *
  912. * @param buffer
  913. * byte[] to copy zmq message payload in to.
  914. * @param offset
  915. * offset in buffer to write data
  916. * @param len
  917. * max bytes to write to buffer.
  918. * If len is smaller than the incoming message size,
  919. * the message will be truncated.
  920. * @param flags
  921. * the flags to apply to the receive operation.
  922. * @return the number of bytes read, -1 on error
  923. */
  924. public final int recv (byte[] buffer, int offset, int len, int flags)
  925. {
  926. zmq.Msg msg = base.recv (flags);
  927. if (msg != null) {
  928. int size = Math.min (msg.size (), len);
  929. System.arraycopy (msg.data (), 0, buffer, offset, size);
  930. return size;
  931. }
  932. mayRaise ();
  933. return -1;
  934. }
  935. /**
  936. *
  937. * @return the message received, as a String object; null on no message.
  938. */
  939. public final String recvStr () {
  940. return recvStr (0);
  941. }
  942. /**
  943. *
  944. * @param flags the flags to apply to the receive operation.
  945. * @return the message received, as a String object; null on no message.
  946. */
  947. public final String recvStr (int flags)
  948. {
  949. byte [] msg = recv(flags);
  950. if (msg != null) {
  951. return new String (msg);
  952. }
  953. return null;
  954. }
  955. public boolean monitor (String addr, int events)
  956. {
  957. return base.monitor (addr, events);
  958. }
  959. }
  960. public static class Poller {
  961. /**
  962. * These values can be ORed to specify what we want to poll for.
  963. */
  964. public static final int POLLIN = zmq.ZMQ.ZMQ_POLLIN;
  965. public static final int POLLOUT = zmq.ZMQ.ZMQ_POLLOUT;
  966. public static final int POLLERR = zmq.ZMQ.ZMQ_POLLERR;
  967. private static final int SIZE_DEFAULT = 32;
  968. private static final int SIZE_INCREMENT = 16;
  969. private PollItem [] items;
  970. private long timeout;
  971. private int next;
  972. public Poller (int size) {
  973. this (null, size);
  974. }
  975. /**
  976. * Class constructor.
  977. *
  978. * @param context
  979. * a 0MQ context previously created.
  980. * @param size
  981. * the number of Sockets this poller will contain.
  982. */
  983. protected Poller (Context context, int size) {
  984. items = new PollItem[size];
  985. timeout = -1L;
  986. next = 0;
  987. }
  988. /**
  989. * Class constructor.
  990. *
  991. * @param context
  992. * a 0MQ context previously created.
  993. */
  994. protected Poller (Context context) {
  995. this(context, SIZE_DEFAULT);
  996. }
  997. /**
  998. * Register a Socket for polling on all events.
  999. *
  1000. * @param socket
  1001. * the Socket we are registering.
  1002. * @return the index identifying this Socket in the poll set.
  1003. */
  1004. public int register (Socket socket) {
  1005. return register (socket, POLLIN | POLLOUT | POLLERR);
  1006. }
  1007. /**
  1008. * Register a Socket for polling on the specified events.
  1009. *
  1010. * Automatically grow the internal representation if needed.
  1011. *
  1012. * @param socket
  1013. * the Socket we are registering.
  1014. * @param events
  1015. * a mask composed by XORing POLLIN, POLLOUT and POLLERR.
  1016. * @return the index identifying this Socket in the poll set.
  1017. */
  1018. public int register (Socket socket, int events) {
  1019. return insert (new PollItem (socket, events));
  1020. }
  1021. /**
  1022. * Register a Socket for polling on the specified events.
  1023. *
  1024. * Automatically grow the internal representation if needed.
  1025. *
  1026. * @param channel
  1027. * the Channel we are registering.
  1028. * @param events
  1029. * a mask composed by XORing POLLIN, POLLOUT and POLLERR.
  1030. * @return the index identifying this Channel in the poll set.
  1031. */
  1032. public int register (SelectableChannel channel, int events) {
  1033. return insert (new PollItem (channel, events));
  1034. }
  1035. /**
  1036. * Register a Channel for polling on the specified events.
  1037. *
  1038. * Automatically grow the internal representation if needed.
  1039. *
  1040. * @param item
  1041. * the PollItem we are registering.
  1042. * @return the index identifying this Channel in the poll set.
  1043. */
  1044. public int register (PollItem item) {
  1045. return insert (item);
  1046. }
  1047. private int insert (PollItem item)
  1048. {
  1049. int pos = next++;
  1050. if (pos == items.length) {
  1051. PollItem[] nitems = new PollItem[items.length + SIZE_INCREMENT];
  1052. System.arraycopy (items, 0, nitems, 0, items.length);
  1053. items = nitems;
  1054. }
  1055. items [pos] = item;
  1056. return pos;
  1057. }
  1058. /**
  1059. * Unregister a Socket for polling on the specified events.
  1060. *
  1061. * @param socket
  1062. * the Socket to be unregistered
  1063. */
  1064. public void unregister (Socket socket) {
  1065. for (int pos = 0; pos < items.length ;pos++) {
  1066. PollItem item = items[pos];
  1067. if (item.getSocket () == socket) {
  1068. remove (pos);
  1069. break;
  1070. }
  1071. }
  1072. }
  1073. /**
  1074. * Unregister a Socket for polling on the specified events.
  1075. *
  1076. * @param channel
  1077. * the Socket to be unregistered
  1078. */
  1079. public void unregister (SelectableChannel channel) {
  1080. for (int pos = 0; pos < items.length ;pos++) {
  1081. PollItem item = items[pos];
  1082. if (item.getRawSocket () == channel) {
  1083. remove (pos);
  1084. break;
  1085. }
  1086. }
  1087. }
  1088. private void remove (int pos)
  1089. {
  1090. next--;
  1091. if (pos != next)
  1092. items [pos] = items [next];
  1093. items [next] = null;
  1094. }
  1095. /**
  1096. * Get the PollItem associated with an index.
  1097. *
  1098. * @param index
  1099. * the desired index.
  1100. * @return the PollItem associated with that index (or null).
  1101. */
  1102. public PollItem getItem (int index)
  1103. {
  1104. if (index < 0 || index >= this.next)
  1105. return null;
  1106. return this.items[index];
  1107. }
  1108. /**
  1109. * Get the socket associated with an index.
  1110. *
  1111. * @param index
  1112. * the desired index.
  1113. * @return the Socket associated with that index (or null).
  1114. */
  1115. public Socket getSocket (int index) {
  1116. if (index < 0 || index >= this.next)
  1117. return null;
  1118. return items[index].getSocket ();
  1119. }
  1120. /**
  1121. * Get the current poll timeout.
  1122. *
  1123. * @return the current poll timeout in milliseconds.
  1124. * @deprecated Timeout handling has been moved to the poll() methods.
  1125. */
  1126. public long getTimeout () {
  1127. return this.timeout;
  1128. }
  1129. /**
  1130. * Set the poll timeout.
  1131. *
  1132. * @param timeout
  1133. * the desired poll timeout in milliseconds.
  1134. * @deprecated Timeout handling has been moved to the poll() methods.
  1135. */
  1136. public void setTimeout (long timeout) {
  1137. if (timeout < -1)
  1138. return;
  1139. this.timeout = timeout;
  1140. }
  1141. /**
  1142. * Get the current poll set size.
  1143. *
  1144. * @return the current poll set size.
  1145. */
  1146. public int getSize () {
  1147. return items.length;
  1148. }
  1149. /**
  1150. * Get the index for the next position in the poll set size.
  1151. *
  1152. * @return the index for the next position in the poll set size.
  1153. */
  1154. public int getNext () {
  1155. return this.next;
  1156. }
  1157. /**
  1158. * Issue a poll call. If the poller's internal timeout value
  1159. * has been set, use that value as timeout; otherwise, block
  1160. * indefinitely.
  1161. *
  1162. * @return how many objects where signaled by poll ().
  1163. */
  1164. public int poll () {
  1165. long tout = -1L;
  1166. if (this.timeout > -1L) {
  1167. tout = this.timeout;
  1168. }
  1169. return poll(tout);
  1170. }
  1171. /**
  1172. * Issue a poll call, using the specified timeout value.
  1173. * <p>
  1174. * Since ZeroMQ 3.0, the timeout parameter is in <i>milliseconds<i>,
  1175. * but prior to this the unit was <i>microseconds</i>.
  1176. *
  1177. * @param tout
  1178. * the timeout, as per zmq_poll ();
  1179. * if -1, it will block indefinitely until an event
  1180. * happens; if 0, it will return immediately;
  1181. * otherwise, it will wait for at most that many
  1182. * milliseconds/microseconds (see above).
  1183. *
  1184. * @see "http://api.zeromq.org/3-0:zmq-poll"
  1185. *
  1186. * @return how many objects where signaled by poll ()
  1187. */
  1188. public int poll(long tout) {
  1189. zmq.PollItem[] pollItems = new zmq.PollItem[next];
  1190. for (int i = 0; i < next; i++)
  1191. pollItems[i] = items[i].base ();
  1192. return zmq.ZMQ.zmq_poll (pollItems, next, tout);
  1193. }
  1194. /**
  1195. * Check whether the specified element in the poll set was signaled for input.
  1196. *
  1197. * @param index
  1198. *
  1199. * @return true if the element was signaled.
  1200. */
  1201. public boolean pollin (int index) {
  1202. if (index < 0 || index >= this.next)
  1203. return false;
  1204. return items [index].isReadable();
  1205. }
  1206. /**
  1207. * Check whether the specified element in the poll set was signaled for output.
  1208. *
  1209. * @param index
  1210. *
  1211. * @return true if the element was signaled.
  1212. */
  1213. public boolean pollout (int index) {
  1214. if (index < 0 || index >= this.next)
  1215. return false;
  1216. return items [index].isWritable ();
  1217. }
  1218. /**
  1219. * Check whether the specified element in the poll set was signaled for error.
  1220. *
  1221. * @param index
  1222. *
  1223. * @return true if the element was signaled.
  1224. */
  1225. public boolean pollerr (int index) {
  1226. if (index < 0 || index >= this.next)
  1227. return false;
  1228. return items [index].isError();
  1229. }
  1230. }
  1231. public static class PollItem {
  1232. private final zmq.PollItem base;
  1233. private final Socket socket;
  1234. public PollItem (Socket socket, int ops) {
  1235. this.socket = socket;
  1236. base = new zmq.PollItem (socket.base, ops);
  1237. }
  1238. public PollItem (SelectableChannel channel, int ops) {
  1239. base = new zmq.PollItem (channel, ops);
  1240. socket = null;
  1241. }
  1242. protected final zmq.PollItem base() {
  1243. return base;
  1244. }
  1245. public final SelectableChannel getRawSocket () {
  1246. return base.getRawSocket ();
  1247. }
  1248. public final Socket getSocket() {
  1249. return socket;
  1250. }
  1251. public final boolean isReadable() {
  1252. return base.isReadable();
  1253. }
  1254. public final boolean isWritable() {
  1255. return base.isWritable ();
  1256. }
  1257. public final boolean isError () {
  1258. return base.isError ();
  1259. }
  1260. public final int readyOps () {
  1261. return base.readyOps ();
  1262. }
  1263. @Override
  1264. public boolean equals (Object obj)
  1265. {
  1266. if (!(obj instanceof PollItem))
  1267. return false;
  1268. PollItem target = (PollItem) obj;
  1269. if (socket != null && socket == target.socket)
  1270. return true;
  1271. if (getRawSocket () != null && getRawSocket () == target.getRawSocket ())
  1272. return true;
  1273. return false;
  1274. }
  1275. }
  1276. public enum Error {
  1277. ENOTSUP(ZError.ENOTSUP),
  1278. EPROTONOSUPPORT(ZError.EPROTONOSUPPORT),
  1279. ENOBUFS(ZError.ENOBUFS),
  1280. ENETDOWN(ZError.ENETDOWN),
  1281. EADDRINUSE(ZError.EADDRINUSE),
  1282. EADDRNOTAVAIL(ZError.EADDRNOTAVAIL),
  1283. ECONNREFUSED(ZError.ECONNREFUSED),
  1284. EINPROGRESS(ZError.EINPROGRESS),
  1285. EMTHREAD(ZError.EMTHREAD),
  1286. EFSM(ZError.EFSM),
  1287. ENOCOMPATPROTO(ZError.ENOCOMPATPROTO),
  1288. ETERM(ZError.ETERM);
  1289. private final long code;
  1290. Error(long code) {
  1291. this.code = code;
  1292. }
  1293. public long getCode() {
  1294. return code;
  1295. }
  1296. public static Error findByCode(int code) {
  1297. for (Error e : Error.class.getEnumConstants()) {
  1298. if (e.getCode() == code) {
  1299. return e;
  1300. }
  1301. }
  1302. throw new IllegalArgumentException("Unknown " + Error.class.getName() + " enum code:" + code);
  1303. }
  1304. }
  1305. @Deprecated
  1306. public static boolean device (int type_, Socket frontend, Socket backend)
  1307. {
  1308. return zmq.ZMQ.zmq_proxy (frontend.base, backend.base, null);
  1309. }
  1310. /**
  1311. * Starts the built-in ØM…

Large files files are truncated, but you can click here to view the full file