View Javadoc

1   /*
2    * (C)opyright 2010, Nikolaos Georgosopoulos
3    *
4    * This file is part of URLChecker.
5    *
6    * URLChecker is free software: you can redistribute it and/or modify it under
7    * the terms of the Lesser General Public License as published by the Free
8    * Software Foundation, either version 3 of the License, or (at your option) any
9    * later version.
10   *
11   * URLChecker is distributed in the hope that it will be useful, but WITHOUT ANY
12   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14   *
15   * You should have received a copy of the Lesser General Public License along
16   * with URLChecker. If not, see <http://www.gnu.org/licenses/>.
17   */
18  package net.sf.urlchecker.commands;
19  
20  import java.util.ArrayList;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.concurrent.ExecutionException;
24  import java.util.concurrent.ExecutorService;
25  import java.util.concurrent.Executors;
26  import java.util.concurrent.Future;
27  import java.util.concurrent.TimeUnit;
28  
29  import net.sf.urlchecker.events.BasicChainEvent;
30  import net.sf.urlchecker.events.EventTypes;
31  
32  import org.apache.commons.configuration.ConfigurationException;
33  import org.apache.commons.httpclient.HttpClient;
34  import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
35  
36  /**
37   * The main Command of the URLChecker using the old httpClient from jakarta
38   * commons. If the context was initialized for multi-threaded use, this class
39   * will spawn one thread for each result. Each thread will use the
40   * {@link CheckUrlsProcess} which in turn will try to verify the availability of
41   * one URL.
42   * 
43   * <p>
44   * <b> $Id: CheckUrlsCommand.java 181 2010-12-12 23:39:00Z georgosn $</b>
45   * </p>
46   * 
47   * @author $LastChangedBy: georgosn $
48   * @version $LastChangedRevision: 181 $
49   */
50  public class CheckUrlsCommand extends CheckUrlsGeneric<HttpClient> {
51  
52      /**
53       * Instantiates a new check URLs command. The successor parameter can be
54       * null if no successor is needed.
55       * 
56       * @param successor
57       *            the successor command
58       * @param newClient
59       *            the client to be used
60       */
61      public CheckUrlsCommand(Command successor, HttpClient newClient) {
62          super(successor, newClient);
63      }
64  
65      /**
66       * {@inheritDoc}
67       * 
68       * Checks if is multithreaded.
69       */
70      @Override
71      public boolean isMultithreaded() {
72          return client.getHttpConnectionManager().getClass()
73                  .isAssignableFrom(MultiThreadedHttpConnectionManager.class);
74      }
75  
76      /**
77       * {@inheritDoc}
78       * 
79       * Spawns threads to check individual URLs.
80       */
81      @Override
82      protected void multithreadedExecution(final Context context,
83              Iterator<Result> iter) throws ConfigurationException {
84          final ExecutorService service = Executors.newFixedThreadPool(context
85                  .getResults().size());
86          final List<Future<CheckUrlsProcess>> tasks = new ArrayList<Future<CheckUrlsProcess>>();
87  
88          while (iter.hasNext()) {
89              fireEvent(new BasicChainEvent(this, context, EventTypes.FORK));
90              final CheckUrlsProcess process = new CheckUrlsProcess(client,
91                      iter.next());
92              final Future<CheckUrlsProcess> future = service.submit(process,
93                      process);
94              tasks.add(future);
95          }
96  
97          try {
98              for (final Future<CheckUrlsProcess> f : tasks) {
99                  final Result result = f.get().getResult();
100 
101                 if (LOGGER.isDebugEnabled()) {
102                     LOGGER.debug(result.getResult() + " for " + result.getURI()
103                             + " with " + result.getUserData());
104                 }
105             }
106 
107             service.shutdown();
108         } catch (final InterruptedException e) {
109             LOGGER.error(e);
110             fireEvent(new BasicChainEvent(this, context, EventTypes.EXCEPTION));
111         } catch (final ExecutionException e) {
112             LOGGER.error(e);
113             fireEvent(new BasicChainEvent(this, context, EventTypes.EXCEPTION));
114         } finally {
115             try {
116                 if (!service.isShutdown()) {
117                     service.awaitTermination(terminationTime, TimeUnit.SECONDS);
118                 }
119             } catch (final InterruptedException e) {
120                 LOGGER.error(e);
121                 fireEvent(new BasicChainEvent(this, context,
122                         EventTypes.EXCEPTION));
123             } finally {
124                 if (!service.isShutdown()) {
125                     service.shutdownNow();
126                 }
127             }
128         }
129     }
130 
131     /**
132      * {@inheritDoc}
133      * 
134      * Executes checking using one thread for all URLs to check.
135      */
136     @Override
137     protected void singlethreadedExecution(final Iterator<Result> iter)
138             throws ConfigurationException {
139 
140         while (iter.hasNext()) {
141             final CheckUrlsProcess process = new CheckUrlsProcess(client,
142                     iter.next());
143             process.run();
144         }
145     }
146 }