001package votorola.a.diff.harvest.run; // Copyright 2012. Christian Weilbach. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. 002 003import java.io.InputStream; 004import java.util.concurrent.atomic.AtomicInteger; 005import java.util.concurrent.atomic.AtomicReference; 006 007import votorola.a.diff.harvest.PipermailHarvester; 008 009/** 010 * Wrapper class around Runnable to work with asynchronous HTTP responses from 011 * {@linkplain HarvestRunner}. Implement this and then 012 * {@linkplain HarvestRunner#scheduleLast(Fetcher) schedule} it. Once the 013 * scheduler can fetch the URL it {@linkplain #setInputStream(InputStream) sets 014 * the input stream} and executes this job in its thread pool. 015 * 016 * All you have to care about is implementing {@linkplain Runnable#run()} 017 * properly and schedule cascading jobs from there in the same way. See 018 * {@linkplain PipermailHarvester} for reference. 019 */ 020public abstract class AbstractFetcher implements Fetcher { 021 022 /** 023 * Jobs are equal if and only if 024 * 025 * <pre *> 026 * this.url.equals(job.url) 027 * </pre> 028 * 029 * @return whether the jobs are equal 030 */ 031 @Override 032 public boolean equals(final Object o) { 033 return (o instanceof AbstractFetcher) 034 && ((AbstractFetcher) o).archiveUrl.equals(archiveUrl) 035 && ((AbstractFetcher) o).path.equals(path); 036 } 037 038 /** 039 * Obey equals contract. 040 */ 041 @Override 042 public int hashCode() { 043 int hash = archiveUrl.hashCode(); 044 hash = hash*37 + path.hashCode(); 045 return hash; 046 } 047 048 /** 049 * Constructor depending on split URL parameters. 050 * 051 * @param archiveUrl 052 * url of this archive, unique 053 * @param path 054 * path and query of this archive 055 */ 056 protected AbstractFetcher(final String archiveUrl, final String path) { 057 this.path = path; 058 this.archiveUrl = archiveUrl; 059 } 060 061 /** 062 * Access to the base-url of the archive. 063 * 064 * @return base-url 065 */ 066 public String archiveUrl() { 067 return archiveUrl; 068 } 069 070 private final String archiveUrl; 071 072 /** 073 * @return URL of this job. This is final and cannot change. 074 */ 075 public String path() { 076 return path; 077 } 078 079 private final String path; 080 081 /** 082 * Base-url and path combined to complete url. 083 * 084 * @return url 085 */ 086 public String url() { 087 return archiveUrl + path; 088 } 089 090 /** 091 * Supposed to be final after being set by HarvestRunner. 092 */ 093 private final AtomicReference<InputStream> inputStream = new AtomicReference<InputStream>(); 094 095 /** 096 * Used by {@linkplain HarvestRunner} to set the data stream returned by the 097 * request of the url. 098 */ 099 public void setInputStream(final InputStream is) { 100 inputStream.set(is); 101 } 102 103 /** 104 * @return Once the HTTP response is complete, use this 105 * {@linkplain InputStream} to read the response entity. 106 */ 107 protected InputStream getInputStream() { 108 return inputStream.get(); 109 } 110 111 private final AtomicInteger statusCode = new AtomicInteger(); 112 113 /** 114 * Set HTTP status code, e.g. 404 for not found. 115 * 116 * @param code 117 */ 118 public void setStatusCode(int code) { 119 statusCode.set(code); 120 } 121 122 /** 123 * Access HTTP error code, e.g. 404 for not found. 124 * 125 * @return code 126 */ 127 public int getStatusCode() { 128 return statusCode.get(); 129 } 130}