1 /***
2 * Copyright 2003-2010 Terracotta, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package net.sf.ehcache.util;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.UnsupportedEncodingException;
22 import java.net.InetAddress;
23 import java.net.MalformedURLException;
24 import java.net.URL;
25 import java.net.URLConnection;
26 import java.net.URLEncoder;
27 import java.util.Properties;
28 import java.util.TimerTask;
29
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 /***
34 * Check for new Ehcache updates and alert users if an update is available
35 *
36 * @author Hung Huynh
37 */
38 public class UpdateChecker extends TimerTask {
39 private static final Logger LOG = LoggerFactory.getLogger(UpdateChecker.class.getName());
40 private static final long MILLIS_PER_SECOND = 1000L;
41 private static final int CONNECT_TIMEOUT = 3000;
42 private static final String NOT_AVAILABLE = "UNKNOWN";
43 private static final String UPDATE_CHECK_URL = "http://www.terracotta.org/kit/reflector?kitID=ehcache.default&pageID=update.properties";
44 private static final long START_TIME = System.currentTimeMillis();
45
46 /***
47 * Run the update check
48 */
49 @Override
50 public void run() {
51 checkForUpdate();
52 }
53
54 /***
55 * This method ensures that there will be no exception thrown.
56 */
57 public void checkForUpdate() {
58 try {
59 if (!Boolean.getBoolean("net.sf.ehcache.skipUpdateCheck")) {
60 doCheck();
61 }
62 } catch (Throwable t) {
63 LOG.debug("Update check failed: " + t.toString());
64 }
65 }
66
67 private void doCheck() throws IOException {
68 LOG.debug("Checking for update...");
69 URL updateUrl = buildUpdateCheckUrl();
70 Properties updateProps = getUpdateProperties(updateUrl);
71 String currentVersion = new ProductInfo().getVersion();
72 String propVal = updateProps.getProperty("general.notice");
73 if (notBlank(propVal)) {
74 LOG.info(propVal);
75 }
76 propVal = updateProps.getProperty(currentVersion + ".notice");
77 if (notBlank(propVal)) {
78 LOG.info(propVal);
79 }
80 propVal = updateProps.getProperty(currentVersion + ".updates");
81 if (notBlank(propVal)) {
82 StringBuilder sb = new StringBuilder();
83 String[] newVersions = propVal.split(",");
84 for (int i = 0; i < newVersions.length; i++) {
85 String newVersion = newVersions[i].trim();
86 if (i > 0) {
87 sb.append(", ");
88 }
89 sb.append(newVersion);
90 propVal = updateProps.getProperty(newVersion + ".release-notes");
91 if (notBlank(propVal)) {
92 sb.append(" [");
93 sb.append(propVal);
94 sb.append("]");
95 }
96 }
97 if (sb.length() > 0) {
98 LOG.info("New update(s) found: " + sb.toString() + ". Please check http://ehcache.org for the latest version.");
99 }
100 }
101 }
102
103 private Properties getUpdateProperties(URL updateUrl) throws IOException {
104 URLConnection connection = updateUrl.openConnection();
105 connection.setConnectTimeout(CONNECT_TIMEOUT);
106 InputStream in = connection.getInputStream();
107 try {
108 Properties props = new Properties();
109 props.load(connection.getInputStream());
110 return props;
111 } finally {
112 if (in != null) {
113 in.close();
114 }
115 }
116 }
117
118 private URL buildUpdateCheckUrl() throws MalformedURLException, UnsupportedEncodingException {
119 String url = System.getProperty("ehcache.update-check.url", UPDATE_CHECK_URL);
120 String connector = url.indexOf('?') > 0 ? "&" : "?";
121 return new URL(url + connector + buildParamsString());
122 }
123
124 private String buildParamsString() throws UnsupportedEncodingException {
125 ProductInfo productInfo = new ProductInfo();
126 StringBuilder sb = new StringBuilder();
127 sb.append("id=");
128 sb.append(getClientId());
129 sb.append("&os-name=");
130 sb.append(urlEncode(getProperty("os.name")));
131 sb.append("&jvm-name=");
132 sb.append(urlEncode(getProperty("java.vm.name")));
133 sb.append("&jvm-version=");
134 sb.append(urlEncode(getProperty("java.version")));
135 sb.append("&platform=");
136 sb.append(urlEncode(getProperty("os.arch")));
137 sb.append("&tc-version=");
138 sb.append(NOT_AVAILABLE);
139 sb.append("&tc-product=");
140 sb.append(urlEncode(productInfo.getName() + " " + productInfo.getVersion()));
141 sb.append("&source=");
142 sb.append(urlEncode(productInfo.getName()));
143 sb.append("&uptime-secs=");
144 sb.append(getUptimeInSeconds());
145 sb.append("&patch=");
146 sb.append(urlEncode(productInfo.getPatchLevel()));
147 return sb.toString();
148 }
149
150 private long getUptimeInSeconds() {
151 long uptime = System.currentTimeMillis() - START_TIME;
152 return uptime > 0 ? (uptime / MILLIS_PER_SECOND) : 0;
153 }
154
155 private int getClientId() {
156 try {
157 return InetAddress.getLocalHost().hashCode();
158 } catch (Throwable t) {
159 return 0;
160 }
161 }
162
163 private String urlEncode(String param) throws UnsupportedEncodingException {
164 return URLEncoder.encode(param, "UTF-8");
165 }
166
167 private String getProperty(String prop) {
168 return System.getProperty(prop, NOT_AVAILABLE);
169 }
170
171 private boolean notBlank(String s) {
172 return s != null && s.trim().length() > 0;
173 }
174 }