
net.sourceforge.squirrel_sql.client.update.UpdateControllerImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of squirrel-sql Show documentation
Show all versions of squirrel-sql Show documentation
This is the jar that contains the main application classes which are very specific to
SQuirreLSQL.
/*
* Copyright (C) 2007 Rob Manning
* [email protected]
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package net.sourceforge.squirrel_sql.client.update;
import static java.lang.System.currentTimeMillis;
import static net.sourceforge.squirrel_sql.client.update.UpdateUtil.RELEASE_XML_FILENAME;
import static net.sourceforge.squirrel_sql.fw.util.Utilities.checkNull;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import net.sourceforge.squirrel_sql.client.IApplication;
import net.sourceforge.squirrel_sql.client.plugin.IPluginManager;
import net.sourceforge.squirrel_sql.client.plugin.PluginInfo;
import net.sourceforge.squirrel_sql.client.preferences.GlobalPreferencesActionListener;
import net.sourceforge.squirrel_sql.client.preferences.GlobalPreferencesSheet;
import net.sourceforge.squirrel_sql.client.preferences.IUpdateSettings;
import net.sourceforge.squirrel_sql.client.preferences.UpdatePreferencesPanel;
import net.sourceforge.squirrel_sql.client.update.async.ReleaseFileUpdateCheckTask;
import net.sourceforge.squirrel_sql.client.update.async.UpdateCheckRunnableCallback;
import net.sourceforge.squirrel_sql.client.update.downloader.ArtifactDownloader;
import net.sourceforge.squirrel_sql.client.update.downloader.ArtifactDownloaderFactory;
import net.sourceforge.squirrel_sql.client.update.gui.ArtifactAction;
import net.sourceforge.squirrel_sql.client.update.gui.ArtifactStatus;
import net.sourceforge.squirrel_sql.client.update.gui.CheckUpdateListener;
import net.sourceforge.squirrel_sql.client.update.gui.UpdateManagerDialog;
import net.sourceforge.squirrel_sql.client.update.gui.UpdateSummaryDialog;
import net.sourceforge.squirrel_sql.client.update.xmlbeans.ChannelXmlBean;
import net.sourceforge.squirrel_sql.fw.gui.GUIUtils;
import net.sourceforge.squirrel_sql.fw.gui.IJOptionPaneService;
import net.sourceforge.squirrel_sql.fw.util.FileWrapper;
import net.sourceforge.squirrel_sql.fw.util.FileWrapperFactory;
import net.sourceforge.squirrel_sql.fw.util.StringManager;
import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
/**
* This class implements the business logic needed by the view (UpdateManagerDialog), to let the user install
* new or updated software (the model)
*
* @author manningr
*/
public class UpdateControllerImpl implements UpdateController, CheckUpdateListener
{
/** This is the pattern that all translation jars (i18n) begin with */
public static final String TRANSLATION_JAR_PREFIX = "squirrel-sql_";
/** Logger for this class. */
private static final ILogger s_log = LoggerController.createLogger(UpdateControllerImpl.class);
/** I18n strings for this class */
private static final StringManager s_stringMgr =
StringManagerFactory.getStringManager(UpdateControllerImpl.class);
/** the application and services it provides */
private IApplication _app = null;
/** utility class for low-level update routines */
private UpdateUtil _util = null;
/** the release that we downloaded when we last checked */
private ChannelXmlBean _currentChannelBean = null;
/** the release we had installed the last time we checked / updated */
private ChannelXmlBean _installedChannelBean = null;
/** Used to be able to bring the update dialog back up after re-config */
private static GlobalPrefsListener listener = null;
/** The class that we use which is responsible for downloading artifacts */
private ArtifactDownloader _downloader = null;
private ArtifactDownloaderFactory _downloaderFactory = null;
/** Service that allows this class to safely present informative JOptionPanes to the user */
private IJOptionPaneService _jOptionPaneService = null;
/** Factory for creating FileWrapper objects */
private FileWrapperFactory fileWrapperFactory = null;
static interface i18n
{
// i18n[UpdateControllerImpl.exceptionMsg=Exception was: ]
String EXCEPTION_MSG = s_stringMgr.getString("UpdateControllerImpl.exceptionMsg");
// i18n[UpdateControllerImpl.updateCheckFailedTitle=Update Check Failed]
String UPDATE_CHECK_FAILED_TITLE = s_stringMgr.getString("UpdateControllerImpl.updateCheckFailedTitle");
// i18n[UpdateControllerImpl.softwareVersionCurrentMsg=This software's version is the most recent]
String SOFTWARE_VERSION_CURRENT_MSG =
s_stringMgr.getString("UpdateControllerImpl.softwareVersionCurrentMsg");
// i18n[UpdateControllerImpl.updateCheckTitle=Update Check]
String UPDATE_CHECK_TITLE = s_stringMgr.getString("UpdateControllerImpl.updateCheckTitle");
// i18n[UpdateControllerImpl.changesRecordedTitle=Changes Recorded]
String CHANGES_RECORDED_TITLE = s_stringMgr.getString("UpdateControllerImpl.changesRecordedTitle");
// i18n[UpdateControllerImpl.changesRecordedMsg=Requested changes will be made when
// SQuirreL is restarted]
String CHANGES_RECORDED_MSG = s_stringMgr.getString("UpdateControllerImpl.changesRecordedMsg");
// i18n[UpdateControllerImpl.releaseFileDownloadFailedMsg=Release file couldn't be downloaded. Please
// check your settings.]
String RELEASE_FILE_DOWNLOAD_FAILED_MSG =
s_stringMgr.getString("UpdateControllerImpl.releaseFileDownloadFailedMsg");
// i18n[UpdateControllerImpl.promptToDownloadAvailableUpdatesMsg=There are updates available.
// Do you want to download them now?]
String PROMPT_TO_DOWNLOAD_AVAILABLE_UPDATES_MSG =
s_stringMgr.getString("UpdateControllerImpl.promptToDownloadAvailableUpdatesMsg");
// i18n[UpdateControllerImpl.promptToDownloadAvailableUpdatesTitle=Updates Available]
String PROMPT_TO_DOWNLOAD_AVAILABLE_UPDATES_TITLE =
s_stringMgr.getString("UpdateControllerImpl.promptToDownloadAvailableUpdatesTitle");
}
/**
* Constructor
*
* @param app
* the application and services it provides
*/
public UpdateControllerImpl(IApplication app)
{
_app = app;
if (listener == null)
{
listener = new GlobalPrefsListener();
GlobalPreferencesSheet.addGlobalPreferencesActionListener(listener);
}
}
/**
* @param factory
*/
public void setArtifactDownloaderFactory(ArtifactDownloaderFactory factory)
{
checkNull("setArtifactDownloaderFactory", "factory", factory);
this._downloaderFactory = factory;
}
/**
* Sets the utility class for low-level update routines
*
* @param util
* the Update utility class to use.
*/
public void setUpdateUtil(UpdateUtil util)
{
checkNull("setUpdateUtil","util", util);
this._util = util;
_util.setPluginManager(_app.getPluginManager());
}
/**
* Setter to allow injection of the service implementation.
*
* @param jOptionPaneService
* the non-static service that handles JOptionPane's static calls.
*/
public void setJOptionPaneService(IJOptionPaneService jOptionPaneService)
{
checkNull("setJOptionPaneService","jOptionPaneService", jOptionPaneService);
this._jOptionPaneService = jOptionPaneService;
}
/**
* @param fileWrapperFactory
* the fileFileWrapperFactory to set
*/
public void setFileWrapperFactory(FileWrapperFactory fileWrapperFactory)
{
checkNull("setFileWrapperFactory","fileWrapperFactory", fileWrapperFactory);
this.fileWrapperFactory = fileWrapperFactory;
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController#showUpdateDialog()
*/
public void showUpdateDialog()
{
final JFrame parent = _app.getMainFrame();
final IUpdateSettings settings = getUpdateSettings();
final boolean isRemoteUpdateSite = settings.isRemoteUpdateSite();
GUIUtils.processOnSwingEventThread(new Runnable()
{
@Override
public void run()
{
UpdateManagerDialog dialog = new UpdateManagerDialog(parent, isRemoteUpdateSite);
if (isRemoteUpdateSite)
{
dialog.setUpdateServerName(settings.getUpdateServer());
dialog.setUpdateServerPort(settings.getUpdateServerPort());
dialog.setUpdateServerPath(settings.getUpdateServerPath());
dialog.setUpdateServerChannel(settings.getUpdateServerChannel());
}
else
{
dialog.setLocalUpdatePath(settings.getFileSystemUpdatePath());
}
dialog.addCheckUpdateListener(UpdateControllerImpl.this);
dialog.setVisible(true);
}
});
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController#isUpToDate()
*/
public boolean isUpToDate() throws Exception
{
IUpdateSettings settings = getUpdateSettings();
// 1. Find the local release.xml file
String releaseFilename = _util.getLocalReleaseFile().getAbsolutePath();
// 2. Load the local release.xml file as a ChannelXmlBean.
_installedChannelBean = _util.getLocalReleaseInfo(releaseFilename);
// 4. Get the release.xml file as a ChannelXmlBean from the server or
// filesystem.
if (settings.isRemoteUpdateSite())
{
// 4a. Determine the channel that the user wants (stable or snapshot)
String channelName = getDesiredChannel(settings);
StringBuilder releasePath = new StringBuilder("/");
releasePath.append(getUpdateServerPath());
releasePath.append("/");
releasePath.append(channelName);
releasePath.append("/");
_currentChannelBean =
_util.downloadCurrentRelease(getUpdateServerName(), getUpdateServerPortAsInt(),
releasePath.toString(), RELEASE_XML_FILENAME, _app.getSquirrelPreferences().getProxySettings());
}
else
{
// 4b. Copy the release.xml file to the download directory then load the current release channel bean
FileWrapper updateSiteReleaseXmlFilePath =
fileWrapperFactory.create(settings.getFileSystemUpdatePath(), RELEASE_XML_FILENAME);
FileWrapper downloadReleaseXmlFile =
fileWrapperFactory.create(_util.getDownloadsDir(), RELEASE_XML_FILENAME);
_util.copyFile(updateSiteReleaseXmlFilePath, downloadReleaseXmlFile);
_currentChannelBean = _util.loadUpdateFromFileSystem(settings.getFileSystemUpdatePath());
}
settings.setLastUpdateCheckTimeMillis("" + currentTimeMillis());
saveUpdateSettings(settings);
// 5. Is it the same as the local copy, which was placed either by the
// installer or the last update?
return _currentChannelBean.equals(_installedChannelBean);
}
/**
* This method takes a look at preference for channel and the channel that the user currently has installed
* and logs an info if switching from one to channel to another.
*
* @return the name of the channel that the user wants.
*/
private String getDesiredChannel(final IUpdateSettings settings)
{
String desiredChannel = settings.getUpdateServerChannel().toLowerCase();
String currentChannelName = _installedChannelBean.getName();
if (!currentChannelName.equals(desiredChannel))
{
if (s_log.isInfoEnabled())
{
s_log.info("getDesiredChannel: User is switching distribution channel from "
+ "installed channel (" + currentChannelName + ") to new channel (" + desiredChannel + ")");
}
}
return desiredChannel;
}
/**
* Returns a set of plugins (internal names) of plugins that are currently installed (regardless of whether
* or not they are enabled).
*
* @return a set of plugin internal names
*/
public Set getInstalledPlugins()
{
Set result = new HashSet();
IPluginManager pmgr = _app.getPluginManager();
PluginInfo[] infos = pmgr.getPluginInformation();
for (PluginInfo info : infos)
{
result.add(info.getInternalName());
}
return result;
}
/**
* Go get the files that need to be updated. The specified list could have new files to get (INSTALL),
* existing files to remove (REMOVE). This method's only concern is with fetching the new artifacts to be
* installed.
*/
public void pullDownUpdateFiles(List artifactStatusList,
DownloadStatusEventHandler handler, boolean releaseVersionWillChange)
{
List newartifactsList = new ArrayList();
for (ArtifactStatus status : artifactStatusList)
{
if (status.getArtifactAction() == ArtifactAction.INSTALL)
{
newartifactsList.add(status);
}
}
if (newartifactsList.size() > 0)
{
_downloader = _downloaderFactory.create(newartifactsList);
_downloader.setUtil(_util);
_downloader.setProxySettings(_app.getSquirrelPreferences().getProxySettings());
_downloader.setIsRemoteUpdateSite(isRemoteUpdateSite());
_downloader.setHost(getUpdateServerName());
_downloader.setPort(Integer.parseInt(getUpdateServerPort()));
_downloader.setPath(getUpdateServerPath());
_downloader.setFileSystemUpdatePath(getUpdateSettings().getFileSystemUpdatePath());
_downloader.addDownloadStatusListener(handler);
_downloader.setReleaseVersionWillChange(releaseVersionWillChange);
handler.setDownloader(_downloader);
_downloader.setChannelName(getUpdateServerChannel().toLowerCase());
_downloader.start();
}
else
{
showMessage(i18n.CHANGES_RECORDED_TITLE, i18n.CHANGES_RECORDED_MSG);
}
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController#getUpdateServerChannel()
*/
public String getUpdateServerChannel()
{
return getUpdateSettings().getUpdateServerChannel();
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController#getUpdateServerName()
*/
public String getUpdateServerName()
{
return getUpdateSettings().getUpdateServer();
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController#isRemoteUpdateSite()
*/
public boolean isRemoteUpdateSite()
{
return getUpdateSettings().isRemoteUpdateSite();
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController#getUpdateServerPath()
*/
public String getUpdateServerPath()
{
return getUpdateSettings().getUpdateServerPath();
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController#getUpdateServerPort()
*/
public String getUpdateServerPort()
{
return getUpdateSettings().getUpdateServerPort();
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController#getUpdateServerPortAsInt()
*/
public int getUpdateServerPortAsInt()
{
return Integer.parseInt(getUpdateServerPort());
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController# showConfirmMessage(java.lang.String,
* java.lang.String)
*/
public boolean showConfirmMessage(String title, String msg)
{
int result =
_jOptionPaneService.showConfirmDialog(_app.getMainFrame(), msg, title, JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);
return (result == JOptionPane.YES_OPTION);
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController#showMessage(java.lang.String,
* java.lang.String)
*/
public void showMessage(String title, String msg)
{
_jOptionPaneService.showMessageDialog(_app.getMainFrame(), msg, title, JOptionPane.INFORMATION_MESSAGE);
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController#showErrorMessage(java.lang.String,
* java.lang.String)
*/
public void showErrorMessage(final String title, final String msg, final Exception e)
{
s_log.error(msg, e);
_jOptionPaneService.showMessageDialog(_app.getMainFrame(), msg, title, JOptionPane.ERROR_MESSAGE);
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController#showErrorMessage(java.lang.String,
* java.lang.String)
*/
public void showErrorMessage(String title, String msg)
{
showErrorMessage(title, msg, null);
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController#isTimeToCheckForUpdates()
*/
public boolean isTimeToCheckForUpdates()
{
IUpdateSettings settings = getUpdateSettings();
if (!settings.isEnableAutomaticUpdates()) { return false; }
long lastCheckTime = Long.parseLong(settings.getLastUpdateCheckTimeMillis());
long delta = currentTimeMillis() - lastCheckTime;
UpdateCheckFrequency updateCheckFrequency = _util.getUpdateCheckFrequency(settings);
return updateCheckFrequency.isTimeForUpdateCheck(delta);
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController#promptUserToDownloadAvailableUpdates()
*/
public void promptUserToDownloadAvailableUpdates()
{
boolean userSaidYes =
showConfirmMessage(i18n.PROMPT_TO_DOWNLOAD_AVAILABLE_UPDATES_TITLE,
i18n.PROMPT_TO_DOWNLOAD_AVAILABLE_UPDATES_MSG);
if (userSaidYes)
{
showUpdateDialog();
}
else
{
s_log.info("promptUserToDownloadAvailableUpdates: user decided not to download updates at "
+ "this time (currentTimeMillis=" + System.currentTimeMillis() + ")");
}
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController#checkUpToDate()
*/
public void checkUpToDate()
{
UpdateCheckRunnableCallback callback = new UpdateCheckRunnableCallback()
{
public void updateCheckComplete(final boolean isUpdateToDate,
final ChannelXmlBean installedChannelXmlBean, final ChannelXmlBean currentChannelXmlBean)
{
GUIUtils.processOnSwingEventThread(new Runnable()
{
public void run()
{
if (isUpdateToDate)
{
showMessage(i18n.UPDATE_CHECK_TITLE, i18n.SOFTWARE_VERSION_CURRENT_MSG);
}
// build data
_currentChannelBean = currentChannelXmlBean;
_installedChannelBean = installedChannelXmlBean;
List artifactStatusItems = _util.getArtifactStatus(_currentChannelBean);
String installedVersion = _installedChannelBean.getCurrentRelease().getVersion();
String currentVersion = _currentChannelBean.getCurrentRelease().getVersion();
// build ui
showUpdateSummaryDialog(artifactStatusItems, installedVersion, currentVersion);
}
});
}
public void updateCheckFailed(final Exception e)
{
if (e == null)
{
showErrorMessage(i18n.UPDATE_CHECK_FAILED_TITLE, i18n.RELEASE_FILE_DOWNLOAD_FAILED_MSG);
}
else if (e instanceof FileNotFoundException)
{
String msg =
s_stringMgr.getString("UpdateControllerImpl.localReleaseFileNotFound",
_util.getSquirrelHomeDir() + "/" + UpdateUtil.LOCAL_UPDATE_DIR_NAME + "/"
+ RELEASE_XML_FILENAME);
showErrorMessage(i18n.UPDATE_CHECK_FAILED_TITLE, msg);
}
else
{
showErrorMessage(i18n.UPDATE_CHECK_FAILED_TITLE, i18n.EXCEPTION_MSG + e.getClass().getName()
+ ":" + e.getMessage(), e);
}
}
};
ReleaseFileUpdateCheckTask runnable =
new ReleaseFileUpdateCheckTask(callback, getUpdateSettings(), _util, _app);
runnable.start();
}
private void showUpdateSummaryDialog(final List artifactStatusItems,
final String installedVersion, final String currentVersion)
{
GUIUtils.processOnSwingEventThread(new Runnable()
{
public void run()
{
UpdateSummaryDialog dialog =
new UpdateSummaryDialog(_app.getMainFrame(), artifactStatusItems, UpdateControllerImpl.this);
dialog.setInstalledVersion(installedVersion);
dialog.setAvailableVersion(currentVersion);
GUIUtils.centerWithinParent(_app.getMainFrame());
dialog.setVisible(true);
}
});
}
/**
* @see net.sourceforge.squirrel_sql.client.update.UpdateController#applyChanges(java.util.List, boolean)
*/
public void applyChanges(List artifactStatusList, boolean releaseVersionWillChange)
{
try
{
// Persists the change list to the update directory.
_util.saveChangeList(artifactStatusList);
// Kick off a thread to go and fetch the files one-by-one and register
// callback class - DownloadStatusEventHandler
pullDownUpdateFiles(artifactStatusList, new DownloadStatusEventHandler(this),
releaseVersionWillChange);
}
catch (Exception e)
{
showErrorMessage(i18n.UPDATE_CHECK_FAILED_TITLE, i18n.EXCEPTION_MSG + e.getClass().getName() + ":"
+ e.getMessage(), e);
}
}
/**
* @see net.sourceforge.squirrel_sql.client.update.gui.CheckUpdateListener#showPreferences()
*/
public void showPreferences()
{
// 1. Wait for user to click ok/close
listener.setWaitingForOk(true);
// 2. Display global preferences
GlobalPreferencesSheet.showSheet(_app, UpdatePreferencesPanel.class);
}
public JFrame getMainFrame()
{
return _app.getMainFrame();
}
/* Helper methods */
/**
* Returns the UpdateSettings from preferences.
*
* @return
*/
private IUpdateSettings getUpdateSettings()
{
return _app.getSquirrelPreferences().getUpdateSettings();
}
/**
* @param settings
*/
private void saveUpdateSettings(final IUpdateSettings settings)
{
_app.getSquirrelPreferences().setUpdateSettings(settings);
}
private class GlobalPrefsListener implements GlobalPreferencesActionListener
{
private boolean waitingForOk = false;
public void onDisplayGlobalPreferences()
{
}
public void onPerformClose()
{
showDialog();
}
public void onPerformOk()
{
showDialog();
}
/**
* Re-show the dialog if we were waiting for Ok/Close.
*/
private void showDialog()
{
// 2. When the user clicks ok, then display update dialog again.
if (waitingForOk)
{
waitingForOk = false;
showUpdateDialog();
}
}
/**
* @param waitingForOk
* the waitingForOk to set
*/
public void setWaitingForOk(boolean waitingForOk)
{
this.waitingForOk = waitingForOk;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy