View Javadoc
1   package org.codehaus.mojo.webstart.dependency;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.codehaus.mojo.webstart.dependency.task.JnlpDependencyTask;
23  import org.codehaus.mojo.webstart.util.IOUtil;
24  import org.codehaus.plexus.component.annotations.Component;
25  import org.codehaus.plexus.component.annotations.Requirement;
26  import org.codehaus.plexus.logging.AbstractLogEnabled;
27  import org.codehaus.plexus.logging.Logger;
28  
29  import java.io.File;
30  import java.util.List;
31  import java.util.concurrent.LinkedBlockingQueue;
32  import java.util.concurrent.ThreadPoolExecutor;
33  import java.util.concurrent.TimeUnit;
34  
35  /**
36   * Created on 1/4/14.
37   *
38   * @author Tony Chemit <chemit@codelutin.com>
39   * @since 1.0-beta-5
40   */
41  @Component( role = JnlpDependencyRequestConsumer.class )
42  public class DefaultJnlpDependencyRequestConsumer
43      extends AbstractLogEnabled
44      implements JnlpDependencyRequestConsumer
45  {
46  
47      @Requirement
48      private IOUtil ioUtil;
49  
50      /**
51       * {@inheritDoc}
52       */
53      public JnlpDependencyResults execute( JnlpDependencyRequestConsumerConfig config, JnlpDependencyRequests requests )
54      {
55  
56          getLogger().info( "Process " + requests.getNbRequests() + " dependencies." );
57  
58          RequestExecutor executor = new RequestExecutor( getLogger(), ioUtil, config );
59  
60          executor.registerRequests( requests.getRequests() );
61  
62          JnlpDependencyResults results = executor.terminatesAndWaits();
63  
64          return results;
65      }
66  
67      private static class RequestExecutor
68          extends ThreadPoolExecutor
69      {
70  
71          private final JnlpDependencyRequestConsumerConfig config;
72  
73          private final Logger logger;
74  
75          private final IOUtil ioUtil;
76  
77          private final JnlpDependencyResults results;
78  
79          public RequestExecutor( Logger logger, IOUtil ioUtil, JnlpDependencyRequestConsumerConfig config )
80          {
81              super( config.getMaxThreads(), config.getMaxThreads(), 1L, TimeUnit.SECONDS,
82                     new LinkedBlockingQueue<Runnable>() );
83              this.logger = logger;
84              this.ioUtil = ioUtil;
85              this.config = config;
86              this.results = new JnlpDependencyResults();
87          }
88  
89  
90          @Override
91          protected void afterExecute( Runnable r, Throwable t )
92          {
93              super.afterExecute( r, t );
94              RequestTask task = (RequestTask) r;
95  
96              JnlpDependencyResult result = task.result;
97  
98              results.registerResult( task.request, result );
99  
100             boolean withError = t != null;
101 
102             if ( withError )
103             {
104                 result.setError( t );
105 
106                 if ( config.isFailFast() )
107                 {
108                     logger.warn( "Fail fast after first dependency processing error." );
109 
110                     //TODO Stop the executor
111                     shutdownNow();
112                 }
113             }
114 
115 
116         }
117 
118         /**
119          * Ask the thread to stop.
120          * <p/>
121          * It will finish all incoming files (but will not accept more files to
122          * parse)
123          * <p/>
124          * <b>Note:</b> The method does not return until all files are not consumed.
125          */
126         public JnlpDependencyResults terminatesAndWaits()
127         {
128             // ask executor to terminate
129             shutdown();
130 
131             try
132             {
133                 // wait until all submited jobs are terminated
134                 // i don't want timeout, i think 2 days is good :)
135                 awaitTermination( 2 * 60 * 60 * 24, TimeUnit.SECONDS );
136             }
137             catch ( InterruptedException e )
138             {
139                 logger.error( "Could not stop the executor after two days...", e );
140             }
141 
142             return results;
143         }
144 
145         public void registerRequests( List<JnlpDependencyRequest> dependencyRequests )
146         {
147 
148             for ( JnlpDependencyRequest dependencyRequest : dependencyRequests )
149             {
150                 RequestTask newtask = new RequestTask( logger, ioUtil, dependencyRequest );
151 
152                 JnlpDependencyResult result = newtask.result;
153                 if ( result.isUptodate() )
154                 {
155                     if ( config.isVerbose() )
156                     {
157                         logger.info(
158                             "Skip up-to-date dependency: " + dependencyRequest.getConfig().getArtifact().getId() );
159                     }
160                     results.registerResult( newtask.request, result );
161                 }
162                 else
163                 {
164                     if ( config.isVerbose() )
165                     {
166                         logger.info( "Process dependency: " + dependencyRequest.getConfig().getArtifact().getId() );
167                     }
168                     execute( newtask );
169                 }
170             }
171         }
172     }
173 
174 
175     private static class RequestTask
176         implements Runnable
177     {
178 
179         private final Logger logger;
180 
181         private final IOUtil ioUtil;
182 
183         private final JnlpDependencyRequest request;
184 
185         private JnlpDependencyResult result;
186 
187         private RequestTask( Logger logger, IOUtil ioUtil, JnlpDependencyRequest request )
188         {
189             this.logger = logger;
190             this.ioUtil = ioUtil;
191             this.request = request;
192             this.result = new JnlpDependencyResult( request );
193         }
194 
195         /**
196          * {@inheritDoc}
197          */
198         public void run()
199         {
200             JnlpDependencyConfig config = request.getConfig();
201 
202             File workingFile = request.getOriginalFile();
203 
204             try
205             {
206                 // copy artifact file to original file
207                 ioUtil.copyFile( config.getArtifact().getFile(), workingFile );
208 
209                 File workingDirectory = config.getWorkingDirectory();
210 
211                 JnlpDependencyTask[] tasks = request.getTasks();
212 
213                 for ( int i = 0, length = tasks.length; i < length; i++ )
214                 {
215 
216                     JnlpDependencyTask task = tasks[i];
217 
218                     // copy previous file to a new task isolated directory
219                     File newDirectory = new File( workingDirectory, i + "_" + task.getClass().getSimpleName() );
220                     ioUtil.copyFileToDirectoryIfNecessary( workingFile, newDirectory );
221 
222                     workingFile = new File( newDirectory, workingFile.getName() );
223 
224                     logger.debug( String.format( "[task %s] (%s): workingFile: %s", i, task, workingFile ) );
225 
226                     workingFile = task.execute( config, workingFile );
227                 }
228 
229                 // copy to final destination
230                 ioUtil.copyFile( workingFile, request.getFinalFile() );
231             }
232             catch ( Exception e )
233             {
234                 result.setError( e );
235             }
236 
237             logger.info( "Dependency " + config.getArtifact().getId() + " treated." );
238         }
239     }
240 }