PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/nars_lab/src/main/java/jhelp/util/io/pipe/PipeWriter.java

https://gitlab.com/opennars/opennars
Java | 211 lines | 112 code | 20 blank | 79 comment | 14 complexity | a3be41ad6a80e8df8df8e1f6e5bd5dc4 MD5 | raw file
Possible License(s): Apache-2.0, AGPL-3.0, GPL-3.0, LGPL-3.0
  1. package jhelp.util.io.pipe;
  2. import jhelp.util.Utilities;
  3. import jhelp.util.io.Binarizable;
  4. import jhelp.util.io.ByteArray;
  5. import jhelp.util.io.UtilIO;
  6. import java.io.File;
  7. import java.io.FileOutputStream;
  8. /**
  9. * Write messages in pipe<br>
  10. * <br>
  11. * 1) What is a pipe ?<br>
  12. * <br>
  13. * A pipe is a way to commuicate between two differents java application, that not neccessary use the same main process, but
  14. * runs on same computer, or two computer that shares a same shared directory.<br>
  15. * A pipe is here simply a one way communication theire a one, and only one, writer (The guys who write/send messages) and one,
  16. * and only one, reader (The guy who read/receive messages)<br>
  17. * For a two ways communication, have to create two pipes, one for A =&gt; B and one for B =&gt; A..<br>
  18. * The implementation here is 100% Java, and compatible in any system have file system with at least an area readable/writable
  19. * by the program.<br>
  20. * The implementation use a directory and temporary files for exchange message, so no need socket, and avoid in that way proxy
  21. * issue and other network issue.<br>
  22. * The security is the same as the security of the used directory for echange.<br>
  23. * <br>
  24. * 2) How to use pipes ? <br>
  25. * <br>
  26. * Choose a deticated directory, this directory will be change durring time, so don't use this directory for other stuff. Then
  27. * create the writer in application that will send messages, and reader in application that receive messages. <br>
  28. * If you create several readers (For same pipe), you will notice some lost messages (That why only one reader is highly
  29. * recommended) <br>
  30. * If you create several writers (For same pipe), you will notice some lost messages and/or some writing issue (That why only
  31. * one writer is highly recommended) <br>
  32. * You can transfer byte[] or Binarizable. You will find a helper for manage sending message in queue and one helper for receive
  33. * messages in listener.
  34. *
  35. * @author JHelp
  36. */
  37. public class PipeWriter
  38. extends PipeCommons
  39. {
  40. /** Indicates if writer still able to write */
  41. private boolean alive;
  42. /** Pipe directory */
  43. private final File pipeDirectory;
  44. /** Pipe size */
  45. private int pipeSize;
  46. /**
  47. * Create a new instance of PipeWriter with default size.<br>
  48. * Same as {@link PipeWriter#PipeWriter(File, int) PipeWriter(pipeDirectory, PipeCommons.DEFAULT_PIPE_ZIZE}
  49. *
  50. * @param pipeDirectory
  51. * Pipe directory
  52. */
  53. public PipeWriter(final File pipeDirectory)
  54. {
  55. this(pipeDirectory, PipeCommons.DEFAULT_PIPE_SIZE);
  56. }
  57. /**
  58. * Create a new instance of PipeWriter.<br>
  59. * The size is only use on first pipe writing, when pipe already exists, the size is ingored
  60. *
  61. * @param pipeDirectory
  62. * Pipe directory
  63. * @param pipeSize
  64. * Pipe size if pipe not already exists
  65. */
  66. public PipeWriter(final File pipeDirectory, final int pipeSize)
  67. {
  68. if(pipeDirectory == null)
  69. {
  70. throw new NullPointerException("pipeDirectory musn't be null");
  71. }
  72. this.alive = true;
  73. this.pipeDirectory = pipeDirectory;
  74. this.pipeSize = Math.max(PipeCommons.MINIMUM_PIPE_SIZE, pipeSize);
  75. }
  76. /**
  77. * Indicates if write is allowed.<br>
  78. * To allow writing, use {@link #restartWrite()}
  79. *
  80. * @return {@code true} if write is allow
  81. */
  82. public boolean readyToWrite()
  83. {
  84. return this.alive;
  85. }
  86. /**
  87. * Activate writing, do nothing if already active
  88. */
  89. public void restartWrite()
  90. {
  91. this.alive = true;
  92. }
  93. /**
  94. * Stop actual writing (if one) and dissalow future writing (To reactivate, call {@link #restartWrite()}
  95. */
  96. public void stopWrite()
  97. {
  98. this.alive = false;
  99. }
  100. /**
  101. * Write a binarizable in pipe
  102. *
  103. * @param <B>
  104. * Message type
  105. * @param binarizable
  106. * Message to write
  107. * @throws PipeException
  108. * On writing issue
  109. */
  110. public <B extends Binarizable> void write(final B binarizable) throws PipeException
  111. {
  112. final ByteArray byteArray = new ByteArray();
  113. byteArray.writeBinarizable(binarizable);
  114. this.write(byteArray.toArray());
  115. }
  116. /**
  117. * Write a message in the pipe. If the pipe is full, it will wait until reader free space.<br>
  118. * It possible to stop bruttaly the witing with {@link #stopWrite()}
  119. *
  120. * @param message
  121. * Message to write
  122. * @throws PipeException
  123. * On wrting issue
  124. */
  125. public synchronized void write(final byte[] message) throws PipeException
  126. {
  127. final File config = new File(this.pipeDirectory, PipeCommons.FILE_CONFIG);
  128. if(config.exists() == false)
  129. {
  130. PipeCommons.writeFileInteger(config, this.pipeSize);
  131. }
  132. else
  133. {
  134. this.pipeSize = PipeCommons.readFileInteger(config);
  135. }
  136. final File write = new File(this.pipeDirectory, PipeCommons.FILE_WRITE);
  137. int next = 0;
  138. if(write.exists() == true)
  139. {
  140. next = PipeCommons.readFileInteger(write) + 1;
  141. }
  142. if(next >= this.pipeSize)
  143. {
  144. next = 0;
  145. }
  146. final File file = new File(this.pipeDirectory, String.valueOf(next));
  147. while(file.exists() == true)
  148. {
  149. Utilities.sleep(128);
  150. if(this.alive == false)
  151. {
  152. return;
  153. }
  154. }
  155. if(UtilIO.createFile(file) == false)
  156. {
  157. throw new PipeException("Can't create file ", file.getAbsolutePath());
  158. }
  159. FileOutputStream fileOutputStream = null;
  160. try
  161. {
  162. fileOutputStream = new FileOutputStream(file);
  163. fileOutputStream.write(message);
  164. }
  165. catch(final Exception exception)
  166. {
  167. throw new PipeException(exception, "Can't create file ", file.getAbsolutePath());
  168. }
  169. finally
  170. {
  171. if(fileOutputStream != null)
  172. {
  173. try
  174. {
  175. fileOutputStream.flush();
  176. }
  177. catch(final Exception exception)
  178. {
  179. }
  180. try
  181. {
  182. fileOutputStream.close();
  183. }
  184. catch(final Exception exception)
  185. {
  186. }
  187. }
  188. }
  189. PipeCommons.writeFileInteger(write, next);
  190. }
  191. }