001: /*
002: * All content copyright (c) 2003-2007 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.server;
006:
007: import org.apache.commons.httpclient.HttpClient;
008: import org.apache.commons.httpclient.HttpStatus;
009: import org.apache.commons.httpclient.methods.GetMethod;
010: import org.apache.commons.io.IOUtils;
011: import org.apache.log4j.Level;
012: import org.apache.log4j.Logger;
013:
014: import com.tc.logging.CustomerLogging;
015: import com.tc.logging.TCLogger;
016: import com.tc.util.ProductInfo;
017:
018: import java.io.IOException;
019: import java.io.InputStream;
020: import java.net.ConnectException;
021: import java.net.InetAddress;
022: import java.net.MalformedURLException;
023: import java.net.URL;
024: import java.net.URLEncoder;
025: import java.net.UnknownHostException;
026: import java.util.Date;
027: import java.util.Properties;
028: import java.util.StringTokenizer;
029: import java.util.Timer;
030: import java.util.TimerTask;
031:
032: class UpdateCheckAction extends TimerTask {
033: private static final TCLogger consoleLogger = CustomerLogging
034: .getConsoleLogger();
035:
036: private static String UPDATE_PROPERTIES_URL = "http://www.terracotta.org/kit/reflector?kitID=default&pageID=update.properties";
037: private static ProductInfo productInfo = ProductInfo.getInstance();
038:
039: private TCServer server;
040: private long periodMillis;
041:
042: UpdateCheckAction(TCServer server, int periodDays) {
043: super ();
044: this .server = server;
045: periodMillis = checkPeriodMillis(periodDays);
046: silenceHttpClientLoggers();
047: }
048:
049: public static void start(TCServer server, int periodDays) {
050: UpdateCheckAction action = new UpdateCheckAction(server,
051: periodDays);
052: new Timer("Update Checker", true).schedule(action, 0, action
053: .getCheckPeriodMillis());
054: }
055:
056: public long getCheckPeriodMillis() {
057: return periodMillis;
058: }
059:
060: public static void silenceHttpClientLoggers() {
061: Logger.getLogger("org.apache.commons.httpclient.HttpClient")
062: .setLevel(Level.OFF);
063: Logger
064: .getLogger(
065: "org.apache.commons.httpclient.params.DefaultHttpParams")
066: .setLevel(Level.OFF);
067: Logger.getLogger(
068: "org.apache.commons.httpclient.methods.GetMethod")
069: .setLevel(Level.OFF);
070: Logger.getLogger(
071: "org.apache.commons.httpclient.HttpMethodDirector")
072: .setLevel(Level.OFF);
073: Logger
074: .getLogger(
075: "org.apache.commons.httpclient.HttpConnection")
076: .setLevel(Level.OFF);
077: Logger
078: .getLogger(
079: "org.apache.commons.httpclient.HttpMethodBase")
080: .setLevel(Level.OFF);
081: Logger.getLogger("org.apache.commons.httpclient.HttpState")
082: .setLevel(Level.OFF);
083: Logger.getLogger("org.apache.commons.httpclient.HttpParser")
084: .setLevel(Level.OFF);
085: Logger.getLogger(
086: "org.apache.commons.httpclient.cookie.CookieSpec")
087: .setLevel(Level.OFF);
088: Logger.getLogger("httpclient.wire.header").setLevel(Level.OFF);
089: Logger.getLogger("httpclient.wire.content").setLevel(Level.OFF);
090: }
091:
092: public URL constructCheckURL() throws MalformedURLException {
093: String propsUrl = System.getProperty(
094: "terracotta.update-checker.url", UPDATE_PROPERTIES_URL);
095: StringBuffer sb = new StringBuffer(propsUrl);
096:
097: sb.append(UPDATE_PROPERTIES_URL.equals(propsUrl) ? '&' : '?');
098:
099: sb.append("id=");
100: sb.append(URLEncoder.encode(Integer.toString(getIpAddress())));
101: sb.append("os-name=");
102: sb.append(URLEncoder.encode(System.getProperty("os.name")));
103: sb.append("&jvm-name=");
104: sb
105: .append(URLEncoder.encode(System
106: .getProperty("java.vm.name")));
107: sb.append("&jvm-version=");
108: sb.append(URLEncoder.encode(System
109: .getProperty("java.vm.version")));
110: sb.append("&platform=");
111: sb.append(URLEncoder.encode(System.getProperty("os.arch")));
112: sb.append("&tc-version=");
113: sb.append(URLEncoder.encode(productInfo.rawVersion()));
114: sb.append("&tc-product=");
115: sb.append(productInfo.edition().equals("opensource") ? "oss"
116: : "ee");
117: sb.append("&uptime-secs=");
118: sb
119: .append((System.currentTimeMillis() - server
120: .getStartTime()) / 1000);
121: sb.append("&source=server");
122:
123: return new URL(sb.toString());
124: }
125:
126: private static int getIpAddress() {
127: try {
128: return InetAddress.getLocalHost().hashCode();
129: } catch (UnknownHostException uhe) {
130: return 0;
131: }
132: }
133:
134: private void showMessage(String msg) {
135: consoleLogger.info(msg);
136: }
137:
138: public Properties getResponseBody(URL url, HttpClient client)
139: throws ConnectException, IOException {
140: GetMethod get = new GetMethod(url.toString());
141:
142: get.setFollowRedirects(true);
143: try {
144: int status = client.executeMethod(get);
145: if (status != HttpStatus.SC_OK) {
146: throw new ConnectException(
147: "The http client has encountered a status code other than ok for the url: "
148: + url + " status: "
149: + HttpStatus.getStatusText(status));
150: }
151: Properties props = new Properties();
152: props.load(get.getResponseBodyAsStream());
153: return props;
154: } finally {
155: get.releaseConnection();
156: }
157: }
158:
159: private void doUpdateCheck() {
160: showMessage("Update Checker: Checking...");
161:
162: InputStream is = null;
163: try {
164: StringBuffer sb = new StringBuffer();
165: String version = productInfo.rawVersion();
166: if (version.indexOf('.') != -1) {
167: URL url = constructCheckURL();
168: HttpClient httpClient = new HttpClient();
169: Properties props = getResponseBody(url, httpClient);
170:
171: String propVal = props.getProperty("general.notice");
172: if (propVal != null
173: && (propVal = propVal.trim()) != null
174: && propVal.length() > 0) {
175: showMessage("Update Checker: " + propVal);
176: }
177:
178: propVal = props.getProperty(version + ".notice");
179: if (propVal != null
180: && (propVal = propVal.trim()) != null
181: && propVal.length() > 0) {
182: showMessage("Update Checker: " + propVal);
183: }
184:
185: propVal = props.getProperty(version + ".updates");
186: if (propVal != null
187: && (propVal = propVal.trim()) != null
188: && propVal.length() > 0) {
189: StringTokenizer st = new StringTokenizer(propVal,
190: ",");
191: while (st.hasMoreElements()) {
192: String newVersion = st.nextToken();
193: sb.append(newVersion);
194:
195: propVal = props.getProperty(newVersion
196: + ".release-notes");
197: if (propVal != null
198: && (propVal = propVal.trim()) != null
199: && propVal.length() > 0) {
200: sb.append(" [");
201: sb.append(propVal);
202: sb.append("]");
203: }
204: }
205: }
206: }
207: if (sb.length() > 0) {
208: showMessage("Update Checker: Available updates:");
209: showMessage("Update Checker: * " + sb.toString());
210: } else {
211: showMessage("Update Checker: No updates found");
212: }
213: } catch (Exception e) {
214: consoleLogger.info("Update Checker: Check failed ("
215: + e.getClass().getName() + ": " + e.getMessage()
216: + ")");
217: } finally {
218: IOUtils.closeQuietly(is);
219: }
220:
221: showMessage("Update Checker: Next check at "
222: + new Date(System.currentTimeMillis() + periodMillis));
223: }
224:
225: public void run() {
226: doUpdateCheck();
227: }
228:
229: private static long checkPeriodMillis(int days) {
230: Long minutes = Long
231: .getLong("terracotta.update-checker.next-check-minutes");
232: long nextCheckTime;
233:
234: if (minutes != null) {
235: nextCheckTime = minutes.longValue() * 60 * 1000;
236: } else {
237: nextCheckTime = days * 24 * 60 * 60 * 1000;
238: }
239:
240: return nextCheckTime;
241: }
242: }
|