/*
* Copyright (c) 2012, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html
*
* 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.google.dart.tools.update.core;
import com.google.dart.tools.core.DartCore;
import com.google.dart.tools.core.DartCoreDebug;
import com.google.dart.tools.core.model.DartSdkManager;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.osgi.framework.BundleContext;
import org.osgi.service.prefs.BackingStoreException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.ResourceBundle;
import java.util.concurrent.TimeUnit;
/**
* The plugin activator for the com.google.dart.tools.update.core plugin.
*/
public class UpdateCore extends Plugin {
/**
* A temporary flag used to determine where update and install dirs should live when debugging
* locally.
*/
public static final boolean DEBUGGING_IN_RUNTIME_WS = System.getProperty("DEBUGGING_IN_RUNTIME_WS") != null;
/**
* The update dir name.
*/
private static final String UPDATES_DIR_NAME = "updates";
/**
* Auto download default in case unspecified by the user.
*/
private static final boolean AUTO_DOWNLOAD_DEFAULT = false;
/**
* Auto update checking default in case unspecified by the user.
*/
private static final boolean AUTO_UPDATE_CHECK_DEFAULT = true;
/**
* Key to fetch the update URL.
*/
private static final String UPDATE_URL_PROP_KEY = "updateUrl";
/**
* Environment variable key for user-specified update URLs.
*/
private static final String UPDATE_URL_ENV_VAR = DartSdkManager.UPDATE_URL_ENV_VAR;
/**
* The Update Core plugin id.
*/
private static final String PLUGIN_ID = "com.google.dart.tools.update.core";
/**
* Preference key for enabling auto download of updates.
*/
private static final String PREFS_AUTO_DOWNLOAD = "autoDownloadUpdates";
/**
* Preference key for auto checking for updates.
*/
private static final String PREFS_AUTO_UPDATE_CHECK = "autoCheckUpdates";
/**
* Preference key for last update check time.
*/
public static final String PREFS_LAST_UPDATE_CHECK = "lastUpdateCheck";
/**
* Default update check interval.
*/
private static final long DEFAULT_UPDATE_CHECK_INTERVAL = TimeUnit.HOURS.toMillis(24);
//The activated plugin
private static UpdateCore PLUGIN;
/**
* Create a Status object with the given message and this plugin's ID.
*/
public static IStatus createCancelStatus(String message) {
return new Status(IStatus.CANCEL, PLUGIN_ID, message);
}
/**
* Create a Status object with the given message and this plugin's ID.
*/
public static Status createErrorStatus(String message) {
return new Status(IStatus.ERROR, PLUGIN_ID, message);
}
/**
* Enable/disable auto download of updates.
*
* @param enable <code>true</code> to enable, <code>false</code> to disable
*/
public static void enableAutoDownload(boolean enable) {
try {
IEclipsePreferences preferences = PLUGIN.getPreferences();
preferences.putBoolean(PREFS_AUTO_DOWNLOAD, enable);
preferences.flush();
} catch (BackingStoreException exception) {
logError(exception);
}
}
/**
* Get the URL for the integration change log.
*
* @return the changelog url
*/
public static String getChangeLogUrl() {
return getUpdateUrl() + "latest/changelog.html";
}
/**
* Fetch the current editor initial revision.
*
* @return the current revision
*/
public static Revision getCurrentRevision() {
return Revision.forValue(DartCore.getBuildId());
}
/**
* Get the shared singleton instance.
*/
public static UpdateCore getInstance() {
return PLUGIN;
}
/**
* Returns the time in milliseconds after which an update check should be performed.
*
* @return the difference, measured in milliseconds, between the next update check time and
* midnight, January 1, 1970 UTC.
* @see java.util.Date
*/
public static long getNextUpdateTime() {
long lastUpdateCheck = PLUGIN.getPreferences().getLong(PREFS_LAST_UPDATE_CHECK, 0);
if (lastUpdateCheck == 0) {
return getTodayInMillis();
}
return lastUpdateCheck + DEFAULT_UPDATE_CHECK_INTERVAL;
}
/**
* Get the directory location for locally staging updates.
*/
public static IPath getUpdateDirPath() {
URL installLocation = Platform.getInstallLocation().getURL();
try {
return URIUtil.toPath(org.eclipse.core.runtime.URIUtil.toURI(installLocation)).append(
UPDATES_DIR_NAME);
} catch (URISyntaxException e) {
//not possible because we know the above URL is valid
return null;
}
}
/**
* Get the singleton update manager.
*/
public static UpdateManager getUpdateManager() {
return UpdateManager.getInstance();
}
/**
* Get the root URL for update checks. Custom URLs can be set via the
* "com.dart.tools.update.core.url" property. This property can be set in two ways:
* <ol>
* <li>via an environment variable (checked first), or</li>
* <li>via a user-defined property in the "editor.properties" file
* </ol>
* If the is no custom URL defined, lookup will default to a URL defined in plugin .options.
*
* @return the URL (or <code>null</code> if unset).
*/
public static String getUpdateUrl() {
String userSpecifiedURL = System.getProperty(UPDATE_URL_ENV_VAR);
if (userSpecifiedURL != null) {
return userSpecifiedURL;
}
userSpecifiedURL = DartCore.getUserDefinedProperty(UPDATE_URL_ENV_VAR);
if (userSpecifiedURL != null) {
return userSpecifiedURL;
}
ResourceBundle resourceBundle = getResourceBundle();
return (String) resourceBundle.getObject(UPDATE_URL_PROP_KEY);
}
/**
* Check if auto download of updates is enabled.
*
* @return <code>true</code> if enabled, <code>false</code> otherwise
*/
public static boolean isAutoDownloadEnabled() {
return PLUGIN.getPreferences().getBoolean(PREFS_AUTO_DOWNLOAD, AUTO_DOWNLOAD_DEFAULT);
}
/**
* Check if automatic checking for updates is enabled.
*
* @return <code>true</code> if enabled, <code>false</code> otherwise
*/
public static boolean isAutoUpdateCheckingEnabled() {
return PLUGIN.getPreferences().getBoolean(PREFS_AUTO_UPDATE_CHECK, AUTO_UPDATE_CHECK_DEFAULT);
}
/**
* Log the given message as an error to the Eclipse log.
*
* @param message the message
*/
public static void logError(String message) {
if (PLUGIN != null) {
PLUGIN.getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, message));
}
}
/**
* Log the given exception.
*
* @param message the message
* @param exception the exception
*/
public static void logError(String message, Throwable exception) {
if (PLUGIN != null) {
PLUGIN.getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, message, exception));
}
}
/**
* Log the given exception.
*
* @param exception the exception to log
*/
public static void logError(Throwable exception) {
if (PLUGIN != null) {
PLUGIN.getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, exception.getMessage(), exception));
}
}
/**
* Log the given informational message.
* <p>
* NOTE: in order for info messages to be logged, the trace option (<code>trace/update</code>)
* must be set to <code>true</code>.
*
* @see DartCoreDebug#TRACE_UPDATE
* @param message an informational message
*/
public static void logInfo(String message) {
logInfo(message, null);
}
/**
* Log the given exception as one representing an informational message. *
* <p>
* NOTE: in order for info messages to be logged, the trace option (<code>trace/update</code>)
* must be set to <code>true</code>.
*
* @see DartCoreDebug#TRACE_UPDATE
* @param message an explanation of why the error occurred or what it means
* @param exception the exception being logged
*/
public static void logInfo(String message, Throwable exception) {
if (PLUGIN != null && DartCoreDebug.TRACE_UPDATE) {
PLUGIN.getLog().log(new Status(Status.INFO, PLUGIN_ID, "INFO: " + message, exception));
}
}
/**
* Log the given message as a warning to the Eclipse log.
*
* @param message the message to log
*/
public static void logWarning(String message) {
if (PLUGIN != null) {
PLUGIN.getLog().log(new Status(IStatus.WARNING, PLUGIN_ID, message));
}
}
/**
* Log the given exception as a warning in the Eclipse log.
*
* @param message the message
* @param exception the exception
*/
public static void logWarning(String message, Throwable exception) {
if (PLUGIN != null) {
PLUGIN.getLog().log(new Status(IStatus.WARNING, PLUGIN_ID, message, exception));
}
}
/**
* Stop the update manager.
*/
public static void stopUpdateManager() {
// Don't try and stop before initialization (dartbug.com/17107)
if (PLUGIN != null) {
UpdateCore.getUpdateManager().stop();
}
}
/**
* Record the current day as the day that an update check was performed.
*/
public static void updateChecked() {
PLUGIN.getPreferences().putLong(PREFS_LAST_UPDATE_CHECK, getTodayInMillis());
}
private static ResourceBundle getResourceBundle() {
if (PLUGIN == null) {
throw new IllegalStateException("update checks are only valid post bundle activation");
}
return Platform.getResourceBundle(PLUGIN.getBundle());
}
/**
* Returns the time in milliseconds for the beginning of the current day.
*/
private static long getTodayInMillis() {
GregorianCalendar date = new GregorianCalendar();
date = new GregorianCalendar(
date.get(Calendar.YEAR),
date.get(Calendar.MONTH),
date.get(Calendar.DAY_OF_MONTH));
return date.getTimeInMillis();
}
private IEclipsePreferences preferences;
/**
* Return the preferences node that contains the preferences for the Update Core plugin.
*
* @return the node containing the plug-in preferences or <code>null</code>
*/
public IEclipsePreferences getPreferences() {
if (preferences == null) {
preferences = InstanceScope.INSTANCE.getNode(PLUGIN_ID);
}
return preferences;
}
@Override
public void start(BundleContext context) throws Exception {
PLUGIN = this;
super.start(context);
}
@Override
public void stop(BundleContext context) throws Exception {
super.stop(context);
PLUGIN = null;
}
}