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.IOException;
10  
11  import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
12  import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicLong;
13  
14  import org.apache.commons.io.IOUtils;
15  import org.apache.commons.logging.Log;
16  import org.apache.commons.logging.LogFactory;
17  
18  /**
19   * An abstract implementation of {@link TransformPolicy}.
20   * 
21   * Subclasses must define the behavior of the copying {@link Thread}
22   */
23  public abstract class AbstractTransformPolicy implements TransformPolicy
24  {
25      protected static final Log logger = LogFactory.getLog(AbstractTransformPolicy.class);
26      
27      private AtomicBoolean startedCopying;
28      private Thread copyingThread;
29      private LazyTransformedInputStream inputStream;
30      protected volatile boolean isClosed;
31      private AtomicLong bytesRequested;
32  
33      public AbstractTransformPolicy()
34      {
35          this.startedCopying = new AtomicBoolean(false);
36          this.isClosed = false;
37          this.bytesRequested = new AtomicLong(0);
38      }
39      
40      /**
41       * {@inheritDoc}
42       */
43      public void initialize(LazyTransformedInputStream lazyTransformedInputStream) {
44          this.inputStream = lazyTransformedInputStream;
45      }
46      
47      /**
48       * {@inheritDoc}
49       */
50      public void readRequest(long length)
51      {
52          this.bytesRequested.addAndGet(length);
53          startCopyingThread();
54      }
55  
56      protected void startCopyingThread()
57      {
58          if (this.startedCopying.compareAndSet(false, true))
59          {
60              this.copyingThread = this.getCopyingThread();
61              this.copyingThread.start();
62          }
63      }
64  
65      /**
66       * {@inheritDoc}
67       */
68      public void release()
69      {
70          this.isClosed = true;
71          if (this.copyingThread != null)
72          {
73              synchronized (this.copyingThread)
74              {
75                  this.copyingThread.notifyAll();
76              }
77          }
78      }
79  
80      /**
81       * @return an instance of the copying {@link Thread}
82       */
83      protected abstract Thread getCopyingThread();
84  
85      protected StreamTransformer getTransformer()
86      {
87          return this.inputStream.getTransformer();
88      }
89  
90      protected LazyTransformedInputStream getInputStream()
91      {
92          return this.inputStream;
93      }
94      
95      protected AtomicLong getBytesRequested()
96      {
97          return bytesRequested;
98      }
99      
100     protected abstract class TransformerWork extends Thread
101     {
102         public synchronized void run()
103         {
104             try
105             {
106                 execute();
107                 IOUtils.closeQuietly(getInputStream().getOut());
108                 // keep the thread alive so that we don't break the pipe
109                 while (!isClosed)
110                 {
111                     try
112                     {
113                         this.wait();
114                     }
115                     catch (InterruptedException e)
116                     {
117                     }
118                 }
119             }
120             catch (Exception e)
121             {
122                 logger.error(e.getMessage(), e);
123                 /**
124                  * if an exception was thrown, the {@link PipedInputStream} may not even have a reference to this thread
125                  * and wait forever. Therefore, we write the message and finish so we break the pipe.
126                  */
127                 try
128                 {
129                     IOUtils.write(e.getMessage().toCharArray(), getInputStream().getOut());
130                 }
131                 catch (IOException exp)
132                 {
133                 }
134             }
135         }
136         
137         protected abstract void execute() throws Exception;
138     }
139 }