View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.module.pgp;
8   
9   import java.io.PipedOutputStream;
10  
11  import edu.emory.mathcs.backport.java.util.concurrent.Semaphore;
12  
13  /**
14   * A {@link TransformPolicy} that copies the requested transformed bytes in chunks
15   * into the {@link PipedOutputStream}.
16   */
17  public class TransformPerRequestInChunksPolicy extends AbstractTransformPolicy
18  {
19  
20      private Semaphore writeSemaphore;
21      private long chunkSize;
22      private long bytesActuallyRequested;
23  
24      public TransformPerRequestInChunksPolicy(long chunkSize)
25      {
26          this.writeSemaphore = new Semaphore(1);
27          this.chunkSize = chunkSize;
28          this.bytesActuallyRequested = 0;
29      }
30  
31      /**
32       * {@inheritDoc}
33       */
34      @Override
35      public void readRequest(long length)
36      {
37          this.bytesActuallyRequested = this.bytesActuallyRequested + length;
38          super.readRequest(length);
39          this.writeSemaphore.release();
40      }
41  
42      /**
43       * {@inheritDoc}
44       */
45      @Override
46      public void release()
47      {
48          this.writeSemaphore.release();
49          super.release();
50      }
51  
52      /**
53       * {@inheritDoc}
54       */
55      @Override
56      protected Thread getCopyingThread()
57      {
58          return new PerRequestWork();
59      }
60  
61      private class PerRequestWork extends TransformerWork
62      {
63          @Override
64          protected void execute() throws Exception
65          {
66              getTransformer().initialize(getInputStream().getOut());
67  
68              boolean finishWriting = false;
69              while (!finishWriting && !isClosed)
70              {
71                  writeSemaphore.acquire();
72                  
73                  /**
74                   * Assuming one thread is reading the input stream (which is reasonable)
75                   * and the state of the reading thread which should be delayed at this point
76                   * it is safe to manipulate getBytesRequested() as I'm the only thread accessing the object
77                   */
78                  long requested = bytesActuallyRequested;
79                  long updatedRequest = (long) (Math.ceil((double)requested / (double)chunkSize) * chunkSize);
80                  getBytesRequested().set(updatedRequest);
81                  
82                  finishWriting = getTransformer().write(getInputStream().getOut(), getBytesRequested());
83              }            
84          }
85      }
86  }