/*
* SoapUI, Copyright (C) 2004-2016 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.autoupdate;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.model.project.SaveStatus;
import com.eviware.soapui.monitor.TestMonitor;
import com.eviware.soapui.settings.VersionUpdateSettings;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.UISupport;
import com.eviware.x.dialogs.Worker;
import com.eviware.x.dialogs.XProgressDialog;
import com.eviware.x.dialogs.XProgressMonitor;
import com.install4j.api.context.UserCanceledException;
import com.install4j.api.launcher.ApplicationLauncher;
import com.install4j.api.update.ApplicationDisplayMode;
import com.install4j.api.update.UpdateChecker;
import com.install4j.api.update.UpdateDescriptor;
import com.install4j.api.update.UpdateDescriptorEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
public class Install4jSoapUIUpdateProvider extends Thread implements SoapUIUpdateProvider {
private final static String APPLICATION_SILENT_VERSION_CHECK_ID = SoapUISystemProperties.SOAP_UI_UPDATER_APP_ID;
private final static String APPLICATION_UPDATES_XML_URL = SoapUISystemProperties.SOAP_UI_UPDATE_URL;
private final static String DEFAULT_UNREACHABLE_VALUE_FOR_SKIPPED_VERSION = "-1";
private final String TERMINATED = "Terminated {EE9BF704-944A-43ae-8B53-7C9AE5SOAPUI}";
private final static Logger logger = LoggerFactory.getLogger(SoapUIUpdateProvider.class);
private final static String NEXT_AUTO_UPDATE_CHECK = "NextAU";//TODO: move to SoapUI settings
private final TestMonitor testMonitor;
private final String currentVersion;
private volatile boolean autoCheckCancelled = false;
private static class UpdateCheckResult {
public SoapUIVersionInfo version = null;
public String comments = null;
public String errorText = null;
private UpdateCheckResult() {
}
public static UpdateCheckResult error(String errorText) {
UpdateCheckResult result = new UpdateCheckResult();
result.errorText = errorText;
return result;
}
public static UpdateCheckResult found(SoapUIVersionInfo version, String comments) {
UpdateCheckResult result = new UpdateCheckResult();
result.version = version;
result.comments = comments;
return result;
}
public static UpdateCheckResult noUpdate() {
return new UpdateCheckResult();
}
}
public Install4jSoapUIUpdateProvider(String soapuiVersion, TestMonitor testMonitor) {
this.testMonitor = testMonitor;
this.currentVersion = soapuiVersion;
}
public void showUpdateStatus() {
autoCheckCancelled = true;
final XProgressDialog waitDialog = UISupport.getDialogs().createProgressDialog("Checking for update", 100, "Update is checking...", true);
try {
waitDialog.run(new Worker() {
private UpdateCheckResult result;
private boolean cancelled = false;
@Override
public Object construct(XProgressMonitor monitor) {
String error = checkURLisReachable(APPLICATION_UPDATES_XML_URL);
if (StringUtils.isNullOrEmpty(error) || cancelled) {
result = checkUpdate();
} else {
result = UpdateCheckResult.error(error);
}
return null;
}
@Override
public void finished() {
if (cancelled) {
return;
}
waitDialog.setVisible(false);
if (StringUtils.hasContent(result.errorText)) {
if (!TERMINATED.equals(result.errorText)) {
UISupport.showErrorMessage(result.errorText);
}
} else {
if (result.version == null) {
UISupport.showInfoMessage("You are using the latest accessible release of SoapUI");
} else {
if (!updatePostponedByUser(result.version, new SoapUIVersionInfo(currentVersion), result.comments)) {
update(false);
}
}
}
}
@Override
public boolean onCancel() {
cancelled = true;
waitDialog.setVisible(false);
return true;
}
});
} catch (Exception e) {
UISupport.showErrorMessage(e.getMessage());
}
}
private boolean update(boolean blocking) {
try {
ApplicationLauncher.launchApplication(APPLICATION_SILENT_VERSION_CHECK_ID, null, blocking,
new ApplicationLauncher.Callback() {
@Override
public void exited(int i) {
}
@Override
public void prepareShutdown() {
if (testMonitor.hasRunningTests()) {
testMonitor.cancelAllTests("Terminated because of auto-update.");
}
DoExit();
}
});
} catch (IOException exception) {
return false;
}
return true;
}
private void DoExit(){
try {
SoapUI.saveSettings();
SaveStatus saveStatus = SoapUI.getWorkspace().onClose();
if (saveStatus == SaveStatus.CANCELLED || saveStatus == SaveStatus.FAILED) {
return;
}
} catch (Exception e1) {
logger.error("Error saving settings during exit", e1);
}
SoapUI.shutdown();
}
@Override
public void run() {
Date now = new Date();
Date whenCheck = new Date(SoapUI.getSettings().getLong(NEXT_AUTO_UPDATE_CHECK, now.getTime()));
if (!now.before(whenCheck)) {
String error = checkURLisReachable(APPLICATION_UPDATES_XML_URL);
if (StringUtils.hasContent(error)) {
logger.info(error);
} else {
UpdateCheckResult checkResult = checkUpdate();
if (StringUtils.hasContent(checkResult.errorText)) {
logger.info(checkResult.errorText);
return;
}
if (checkResult.version != null){
String skippedVersion = SoapUI.getSettings().getString(NewSoapUIVersionAvailableDialog.SKIPPED_VERSION_SETTING, DEFAULT_UNREACHABLE_VALUE_FOR_SKIPPED_VERSION);
if (skippedVersion != null){
if (skippedVersion.equals(checkResult.version.toString())){
logger.info("Found new version (" + skippedVersion + ") but it was skipped according to previous user's choice.");
return;
}
}
}
if (checkResult.version != null && !autoCheckCancelled) {
if (!updatePostponedByUser(checkResult.version, new SoapUIVersionInfo(this.currentVersion), checkResult.comments)) {
update(true);
}
}
}
}
}
private NewSoapUIVersionAvailableDialog.ReadyApiUpdateDialogResult showUpdateIsAvailableDialog(SoapUIVersionInfo newVersion, SoapUIVersionInfo curVersion, String comments) {
NewSoapUIVersionAvailableDialog dialog = new NewSoapUIVersionAvailableDialog(newVersion, curVersion, comments);
return dialog.showDialog();
}
private boolean updatePostponedByUser(SoapUIVersionInfo newVersion, SoapUIVersionInfo curVersion, String comments) {
final long A_DAY = 24 * 60 * 60 * 1000;
boolean result = true;
Date nextCheck = null;
switch (showUpdateIsAvailableDialog(newVersion, curVersion, comments)) {
case Update:
if (SoapUI.getSettings().getBoolean(VersionUpdateSettings.AUTO_CHECK_VERSION_UPDATE)) {
nextCheck = new Date();
}
result = false;
break;
case Delay_1Day:
nextCheck = new Date(new Date().getTime() + A_DAY);
break;
case Delay_3Days:
nextCheck = new Date(new Date().getTime() + 3 * A_DAY);
break;
case Delay_7Days:
nextCheck = new Date(new Date().getTime() + 7 * A_DAY);
break;
case DoNotUpdate:
break;
case SkipThisVersion:
break;
}
if (nextCheck != null) {
SoapUI.getSettings().setLong(NEXT_AUTO_UPDATE_CHECK, nextCheck.getTime());
SoapUI.getSettings().setBoolean(VersionUpdateSettings.AUTO_CHECK_VERSION_UPDATE, true);
}
return result;
}
private String checkURLisReachable(String url) {
try {
int timeout = 10 * 1000;//10 seconds
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setConnectTimeout(timeout);
connection.setReadTimeout(timeout);
int responseCode = connection.getResponseCode();
if (200 <= responseCode && responseCode <= 399) {
return null;
}
return String.format("The update server is unreachable: The attempt to connect to the update server has resulted in %d code.", responseCode);
} catch (IOException exception) {
return String.format("The update server is unreachable: %s", exception.getMessage());
}
}
private UpdateCheckResult checkUpdate() {
String newVersion = null;
UpdateDescriptorEntry entry = null;
try {
UpdateDescriptor descriptor = getUpdateDescriptor();
if (descriptor != null) {
entry = descriptor.getPossibleUpdateEntry();
if (entry != null) {
newVersion = entry.getNewVersion();
}
}
} catch (UserCanceledException ex) {
return UpdateCheckResult.error(TERMINATED);
} catch (IOException ex) {
return UpdateCheckResult.error(ex.getMessage());
}
if (newVersion != null && newVersion.length() != 0) {
SoapUIVersionInfo newVersionObj = new SoapUIVersionInfo(newVersion);
SoapUIVersionInfo currentVersionObj = new SoapUIVersionInfo(currentVersion);
if (currentVersionObj.compare(currentVersionObj, newVersionObj) < 0) {
return UpdateCheckResult.found(newVersionObj, entry.getComment());
}
}
return UpdateCheckResult.noUpdate();
}
private UpdateDescriptor getUpdateDescriptor() throws UserCanceledException, IOException {
return UpdateChecker.getUpdateDescriptor(APPLICATION_UPDATES_XML_URL, ApplicationDisplayMode.GUI);
}
}