com.gwtplatform.common.rebind.VersionInspectorLinker Maven / Gradle / Ivy
/**
* Copyright 2014 ArcBees Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.gwtplatform.common.rebind;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.URL;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.gwt.core.ext.Linker;
import com.google.gwt.core.ext.LinkerContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.linker.ConfigurationProperty;
import com.google.gwt.core.ext.linker.LinkerOrder;
import com.google.gwt.core.ext.linker.LinkerOrder.Order;
import com.google.gwt.core.ext.linker.SelectionProperty;
import com.google.gwt.core.ext.linker.Shardable;
import static com.google.gwt.core.ext.TreeLogger.Type.DEBUG;
import static com.google.gwt.core.ext.TreeLogger.Type.ERROR;
@Shardable
@LinkerOrder(Order.POST)
public class VersionInspectorLinker extends Linker {
private static final int CHECK_TIMEOUT_MS = 5000;
private static final String MVP_EXIST_CLASS = "com.gwtplatform.mvp.client.gin.DefaultModule";
private static final String MVP_GROUP_ID = "com.gwtplatform";
private static final String MVP_ARTIFACT = "gwtp-mvp-client";
private static final Dependency MVP = new DependencyImpl(MVP_EXIST_CLASS, MVP_GROUP_ID, MVP_ARTIFACT);
private static final String RPC_EXIST_CLASS = "com.gwtplatform.dispatch.rpc.client.gin.RpcDispatchAsyncModule";
private static final String RPC_GROUP_ID = "com.gwtplatform";
private static final String RPC_ARTIFACT = "gwtp-dispatch-rpc-client";
private static final Dependency DISPATCH_RPC = new DependencyImpl(RPC_EXIST_CLASS, RPC_GROUP_ID, RPC_ARTIFACT);
private static final String REST_EXIST_CLASS = "com.gwtplatform.dispatch.rest.client.gin.RestDispatchAsyncModule";
private static final String REST_GROUP_ID = "com.gwtplatform";
private static final String REST_ARTIFACT = "gwtp-dispatch-rest";
private static final Dependency DISPATCH_REST = new DependencyImpl(REST_EXIST_CLASS, REST_GROUP_ID, REST_ARTIFACT);
private static final String API_SEARCH = "http://arcbees-stats-service.appspot.com/version";
private static final String GROUP_QUERY_PARAMETER = "groupid";
private static final String ARTIFACT_QUERY_PARAMETER = "artifactid";
private static final String VERSION_QUERY_PARAMETER = "version";
private static final String PROPERTY_VERIFY_NEWER_VERSION = "verifyNewerVersion";
private static final Pattern VERSION_PATTERN = Pattern.compile("\"version\":\\s*\"([0-9](?:\\.[0-9])*)\"");
private static final Pattern LATEST_PATTERN = Pattern.compile("\"latest\":([a-z]{1,4})");
private static final Pattern RESPONSE_CONTENT_PATTERN = Pattern.compile("^[^{]*(\\{.*\\})$");
private static final String HR = "------------------------------------------------------------";
private static final String NEW_VERSION_AVAILABLE = "A new version of %s is available!";
private static final String SEE_ARTIFACT_DETAILS = "See http://search.maven.org/#artifactdetails|%s|%s|%s|jar";
private static final String YOUR_VERSION = "Your version: %s";
private static final String LATEST_VERSION = "Latest version: %s";
private Logger logger;
public VersionInspectorLinker() {
}
@Override
public String getDescription() {
return "Verify the availability of a more recent version of GWTP.";
}
@Override
public ArtifactSet link(TreeLogger logger, LinkerContext context, ArtifactSet artifacts, boolean onePermutation)
throws UnableToCompleteException {
if (!onePermutation && !isSuperDevMode(context) && canVerifyNewerVersion(context)) {
checkLatestVersions(logger);
}
return artifacts;
}
private boolean isSuperDevMode(LinkerContext context) {
boolean isSdm = false;
for (SelectionProperty property : context.getProperties()) {
if ("superdevmode".equals(property.getName())) {
isSdm = "on".equals(property.tryGetValue());
break;
}
}
return isSdm;
}
private boolean canVerifyNewerVersion(LinkerContext context) {
boolean verifyNewerVersion = true;
for (ConfigurationProperty property : context.getConfigurationProperties()) {
if (PROPERTY_VERIFY_NEWER_VERSION.equals(property.getName())) {
List values = property.getValues();
verifyNewerVersion = !(!values.isEmpty() && "false".equals(values.get(0)));
break;
}
}
return verifyNewerVersion;
}
private void checkLatestVersions(TreeLogger logger) {
checkLatestVersionIfPresent(logger, MVP);
checkLatestVersionIfPresent(logger, DISPATCH_RPC);
checkLatestVersionIfPresent(logger, DISPATCH_REST);
}
private void checkLatestVersionIfPresent(TreeLogger baseLogger, Dependency dependency) {
if (dependency.isPresent()) {
String artifactId = dependency.getArtifactId();
logger = new Logger(baseLogger.branch(DEBUG, "Checking version information for " + artifactId));
logger.debug("You can disable this check by adding this line to your GWT module:");
logger.debug("");
checkLatestVersion(dependency);
}
}
private void checkLatestVersion(Dependency dependency) {
try {
String groupId = dependency.getGroupId();
String artifactId = dependency.getArtifactId();
String currentVersion = dependency.getVersion();
String json = fetchArtifactVersion(groupId, artifactId, currentVersion);
String latestVersion = extractVersion(json);
Boolean isLatest = extractIsLatest(json);
if (isLatest) {
logger.info("You are using the latest version of " + artifactId + "!");
} else {
warnVersion(groupId, artifactId, latestVersion, currentVersion);
}
} catch (Exception e) {
logger.getTreeLogger().log(ERROR, "Exception caught", e);
}
}
/**
* Calls the Arcbees Stats service to retrieve data about a GWTP artifact.
* Note: We would use URL.openConnection, but because this code may be used in a GAE environment with hosted mode,
* this will cause fallback to the URLFetch Service. Using a socket bypasses this.
*
* @return The resulting plain text response
*/
private String fetchArtifactVersion(String groupId, String artifactId, String version) throws IOException {
URL maven = new URL(buildUrl(groupId, artifactId, version));
Socket socket = new Socket(maven.getHost(), 80);
socket.setSoTimeout(CHECK_TIMEOUT_MS);
String response;
try {
PrintWriter output = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
output.println("GET " + maven.getFile() + " HTTP/1.1");
output.println("Host: " + maven.getHost());
output.println("Connection: close");
output.println();
output.flush();
response = readText(socket.getInputStream());
} finally {
socket.close();
}
return response;
}
private String readText(InputStream stream) throws IOException {
String response = "";
BufferedReader input = new BufferedReader(new InputStreamReader(stream));
String inputLine;
while ((inputLine = input.readLine()) != null) {
response += inputLine;
}
return extractResponseContent(response);
}
private String extractResponseContent(String response) {
Matcher matcher = RESPONSE_CONTENT_PATTERN.matcher(response);
return matcher.find() ? matcher.group(1) : "";
}
private String extractVersion(String versionResponse) {
Matcher matcher = VERSION_PATTERN.matcher(versionResponse);
return matcher.find() ? matcher.group(1) : "";
}
private Boolean extractIsLatest(String versionResponse) {
Matcher matcher = LATEST_PATTERN.matcher(versionResponse);
return matcher.find() && Boolean.valueOf(matcher.group(1));
}
private void warnVersion(String groupId, String artifactId, String latestVersion, String currentVersion) {
logger.warn(HR);
logger.warn(NEW_VERSION_AVAILABLE, artifactId);
logger.warn(YOUR_VERSION, currentVersion);
logger.warn(LATEST_VERSION, latestVersion);
logger.warn(SEE_ARTIFACT_DETAILS, groupId, artifactId, latestVersion);
logger.warn(HR);
}
private String buildUrl(String groupId, String artifactId, String version) {
StringBuilder queryString = new StringBuilder();
appendParameter(queryString, GROUP_QUERY_PARAMETER, groupId);
appendParameter(queryString, ARTIFACT_QUERY_PARAMETER, artifactId);
appendParameter(queryString, VERSION_QUERY_PARAMETER, version);
queryString.insert(0, API_SEARCH);
return queryString.toString();
}
private void appendParameter(StringBuilder stringBuilder, String key, String value) {
if (stringBuilder.length() == 0) {
stringBuilder.append("?").append(key).append("=").append(value);
} else {
stringBuilder.append("&").append(key).append("=").append(value);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy