View Javadoc

1   /*
2    * $Id: AbstractTransformPolicy.java 22865 2011-09-05 17:23:45Z dfeist $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.module.pgp;
12  
13  import java.io.IOException;
14  import java.util.concurrent.atomic.AtomicBoolean;
15  import java.util.concurrent.atomic.AtomicLong;
16  
17  import org.apache.commons.io.IOUtils;
18  import org.apache.commons.logging.Log;
19  import org.apache.commons.logging.LogFactory;
20  
21  /**
22   * An abstract implementation of {@link TransformPolicy}.
23   *
24   * Subclasses must define the behavior of the copying {@link Thread}
25   */
26  public abstract class AbstractTransformPolicy implements TransformPolicy
27  {
28      protected static final Log logger = LogFactory.getLog(AbstractTransformPolicy.class);
29  
30      private AtomicBoolean startedCopying;
31      private Thread copyingThread;
32      private LazyTransformedInputStream inputStream;
33      protected volatile boolean isClosed;
34      private AtomicLong bytesRequested;
35  
36      public AbstractTransformPolicy()
37      {
38          this.startedCopying = new AtomicBoolean(false);
39          this.isClosed = false;
40          this.bytesRequested = new AtomicLong(0);
41      }
42  
43      /**
44       * {@inheritDoc}
45       */
46      @Override
47      public void initialize(LazyTransformedInputStream lazyTransformedInputStream) {
48          this.inputStream = lazyTransformedInputStream;
49      }
50  
51      /**
52       * {@inheritDoc}
53       */
54      @Override
55      public void readRequest(long length)
56      {
57          this.bytesRequested.addAndGet(length);
58          startCopyingThread();
59      }
60  
61      protected void startCopyingThread()
62      {
63          if (this.startedCopying.compareAndSet(false, true))
64          {
65              this.copyingThread = this.getCopyingThread();
66              this.copyingThread.start();
67          }
68      }
69  
70      /**
71       * {@inheritDoc}
72       */
73      @Override
74      public void release()
75      {
76          this.isClosed = true;
77          if (this.copyingThread != null)
78          {
79              synchronized (this.copyingThread)
80              {
81                  this.copyingThread.notifyAll();
82              }
83          }
84      }
85  
86      /**
87       * @return an instance of the copying {@link Thread}
88       */
89      protected abstract Thread getCopyingThread();
90  
91      protected StreamTransformer getTransformer()
92      {
93          return this.inputStream.getTransformer();
94      }
95  
96      protected LazyTransformedInputStream getInputStream()
97      {
98          return this.inputStream;
99      }
100 
101     protected AtomicLong getBytesRequested()
102     {
103         return bytesRequested;
104     }
105 
106     protected abstract class TransformerWork extends Thread
107     {
108         @Override
109         public synchronized void run()
110         {
111             try
112             {
113                 execute();
114                 IOUtils.closeQuietly(getInputStream().getOut());
115                 // keep the thread alive so that we don't break the pipe
116                 while (!isClosed)
117                 {
118                     try
119                     {
120                         this.wait();
121                     }
122                     catch (InterruptedException e)
123                     {
124                     }
125                 }
126             }
127             catch (Exception e)
128             {
129                 logger.error(e.getMessage(), e);
130                 /**
131                  * if an exception was thrown, the {@link PipedInputStream} may not even have a reference to this thread
132                  * and wait forever. Therefore, we write the message and finish so we break the pipe.
133                  */
134                 try
135                 {
136                     IOUtils.write(e.getMessage().toCharArray(), getInputStream().getOut());
137                 }
138                 catch (IOException exp)
139                 {
140                 }
141             }
142         }
143 
144         protected abstract void execute() throws Exception;
145     }
146 }