Java tutorial
/* * Copyright (c) 2010-2012 Research In Motion Limited. All rights reserved. * * This program and the accompanying materials are made available * under the terms of the Eclipse Public License, Version 1.0, * which accompanies this distribution and is available at * * http://www.eclipse.org/legal/epl-v10.html * */ package net.rim.ejde.internal.util; import java.io.File; import java.io.InputStream; import java.net.URL; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.LinkedList; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import net.rim.ejde.internal.core.ContextManager; import net.rim.ejde.internal.ui.dialogs.NewVersionDetectionDialog; import net.rim.ejde.internal.ui.preferences.PreferenceConstants; import org.apache.log4j.Logger; import org.eclipse.core.resources.WorkspaceJob; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IBundleGroup; import org.eclipse.core.runtime.IBundleGroupProvider; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.internal.about.AboutBundleGroupData; import org.osgi.framework.Bundle; import org.osgi.framework.Version; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /* * This class is used to reminder user to obtain latest version * of BlackBerry Web Plug-in when latest version is available on * BlackBerry WebSite. * * @author qxu */ public class UpgradingNotification extends WorkspaceJob { private static final String JOB_NAME = "Upgrading Notification"; private static SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy"); private static final String EJDE_CURRENTINFO_XML = "currentInfo.xml"; private static final String SAMPLE_CURRENTINFO_XML = "/templates/sample-currentInfo.xml"; private int _snoozeDays; private String _toolUpgradeUrl; private String _toolMessage; private boolean _snoozeBoolean; private boolean _initializedBoolean; private String _snoozeDate; private Version _currentToolVersion; private Version _latestToolVersion; private static final Logger _log = Logger.getLogger(UpgradingNotification.class); public UpgradingNotification() { super(JOB_NAME); } @Override public IStatus runInWorkspace(IProgressMonitor monitor) { init(); if (_snoozeBoolean == true) { if (checkSnoozeDate()) { checkToolVersion(); } } else { checkToolVersion(); } if (!_initializedBoolean) { final Display display = Display.getDefault(); if (display != null && !display.isDisposed()) { display.syncExec(new Runnable() { public void run() { if (!MessageDialog.openQuestion(display.getActiveShell(), Messages.UPGRADE_INITIALIZATION_TITLE, Messages.UPGRADE_INITIALIZATION_LABEL)) { _snoozeBoolean = true; _snoozeDays = 9999; } else { _snoozeBoolean = false; } _initializedBoolean = true; updateInfoFile(); } }); } } IStatus result = Status.OK_STATUS; return result; } /* * Initiating information of upgrade notification to create a XML file. */ private void init() { try { File currentInfoFile = getFile(); if (!currentInfoFile.exists()) { Bundle bundle = ContextManager.PLUGIN.getBundle(); IPath path = new Path(SAMPLE_CURRENTINFO_XML); InputStream is = FileLocator.openStream(bundle, path, false); DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = docBuilder.parse(is); XMLUtil.writeXmlFile(doc, currentInfoFile.getCanonicalPath(), "UTF-8", "no"); getVersionNumber(); updateInfoFile(); } else { getInfo(); } } catch (Exception ex) { _log.error("Error generating XML file", ex); } } /* * Getting current the version of tool and SDK */ private void getVersionNumber() { boolean internal = false; if (_currentToolVersion == null) { _currentToolVersion = getFeatureVersion(); } if (internal) { _currentToolVersion = handleVersion(_currentToolVersion.toString(), internal); } } @SuppressWarnings("restriction") private Version getFeatureVersion() { // create a descriptive object for each BundleGroup IBundleGroupProvider[] providers = Platform.getBundleGroupProviders(); LinkedList<AboutBundleGroupData> groups = new LinkedList<AboutBundleGroupData>(); if (providers != null) { for (int i = 0; i < providers.length; ++i) { IBundleGroup[] bundleGroups = providers[i].getBundleGroups(); _log.debug("PROVIDER NAME: " + providers[i].getName()); for (int j = 0; j < bundleGroups.length; ++j) { AboutBundleGroupData data = new AboutBundleGroupData(bundleGroups[j]); groups.add(data); if (data.getId().matches(Messages.EJDE_FEATURE_ID)) { _log.debug("Found ejde feature: " + data.getId() + " version " + data.getVersion()); return handleVersion(data.getVersion(), true); } } } } return ContextManager.PLUGIN.getBundle().getVersion(); } private Version handleVersion(String bundleVersion, boolean internal) { String[] bundleNumber = bundleVersion.split("\\-"); String[] bundleSeries = bundleVersion.split("\\."); String qualifier; int[] temp = new int[4]; for (int i = 0; i < bundleSeries.length - 1; i++) { temp[i] = Integer.parseInt(bundleSeries[i]); } if (internal) { qualifier = bundleNumber.length > 1 ? bundleNumber[1] : "0"; //current dev build do not have qualifier } else { qualifier = bundleSeries[3]; } _log.debug("qualifier: " + qualifier); return new Version(temp[0], temp[1], temp[2], qualifier); } /* * Getting all version information from internal XML file about current plug-in. */ private void getInfo() { try { File currentInfo = getFile(); if (currentInfo.exists() && currentInfo.isFile()) { Document xmlDoc = XMLUtil.openXmlFile(currentInfo, false); if (xmlDoc != null) { XPath xPath = XPathFactory.newInstance().newXPath(); _currentToolVersion = handleVersion(xPath.evaluate("/version/tool[1]/text()", xmlDoc), false); _initializedBoolean = Boolean .parseBoolean(xPath.evaluate("/version/initialized[1]/text()", xmlDoc)); _snoozeBoolean = Boolean .parseBoolean(xPath.evaluate("/version/snooze/boolean[1]/text()", xmlDoc)); if (_snoozeBoolean) { _snoozeDays = Integer.parseInt(xPath.evaluate("/version/snooze/days[1]/text()", xmlDoc)); _snoozeDate = xPath.evaluate("/version/snooze/date[1]/text()", xmlDoc); } } } } catch (Exception ex) { _log.error("Error loading file information", ex); } } /* * Checking whether the snooze days has been coming. * * @return */ private Boolean checkSnoozeDate() { try { Date currentDate = new Date(); Date pastDate = df.parse(_snoozeDate); int distance = Math.abs((int) ((currentDate.getTime() - pastDate.getTime()) / 24 / 60 / 60 / 1000)); if (distance >= _snoozeDays) { return true; } } catch (ParseException e) { e.printStackTrace(); } return false; } /* * Checking whether current plug-in version is lower than latest version on BlackBerry WebSite or equal to latest version * * @return */ private Boolean checkToolVersion() { retrieveXMLInfo(); getVersionNumber(); if (_latestToolVersion != null) { int result = resultFromDialog(_currentToolVersion, _latestToolVersion, _toolMessage, _toolUpgradeUrl, Messages.UPGRADE_NOTIFICATION_OF_EJDE_PLUGIN_TITLE); switch (result) { case 0: _snoozeBoolean = true; updateInfoFile(); break; case 1: _snoozeBoolean = false; _currentToolVersion = _latestToolVersion; updateInfoFile(); break; case 2: _snoozeBoolean = true; _snoozeDays = 9999; updateInfoFile(); break; default: return false; } return true; } else { _log.error("Upgrade ejde Plug-In version can't be found on BlackBerry Website for some reasons."); } return false; } /* * Retrieving all information of latest plug-in version from external XML file on BlackBerry WebSite. * * @param projectType */ private void retrieveXMLInfo() { try { // Notice: External url has to replace internal url when releasing. // this url only is for internal testing in tester team URL url; Document xmlDoc = null; String internalURL = ContextManager.PLUGIN.getPreferenceStore() .getString(PreferenceConstants.UPDATE_NOTIFY_URL); if (internalURL.isEmpty()) { // check internal url = new URL(Messages.INTERNAL_TESTING_URL); xmlDoc = XMLUtil.openXMLStream(url); // if does not find in internal, try the release version if (xmlDoc == null) { url = new URL(Messages.EXTERNAL_DEVZONE_URL); xmlDoc = XMLUtil.openXMLStream(url); } } else { // use for internal testing url = new URL(internalURL); xmlDoc = XMLUtil.openXMLStream(url); } if (xmlDoc != null) { XPathFactory factory = XPathFactory.newInstance(); XPath xPath = factory.newXPath(); NodeList nodeToolList = (NodeList) xPath.evaluate("/upgrade/software", xmlDoc, XPathConstants.NODESET); for (int i = 0; i < nodeToolList.getLength(); i++) { Node node = nodeToolList.item(i); if (node instanceof Element) { String toolID = ((Element) node).getAttribute(Messages.TOOL_ID); if (toolID.equals("eJDE")) { String toolVersionStr = ((Element) node).getAttribute(Messages.LATEST_VERSION); _latestToolVersion = handleVersion(toolVersionStr, false); _toolUpgradeUrl = ((Element) node).getAttribute(Messages.UPGRADE_URL); Element messageElmntLst = (Element) node; NodeList messageElmnt = messageElmntLst.getElementsByTagName("message"); NodeList messageNm = messageElmnt.item(0).getChildNodes(); _toolMessage = messageNm.item(0).getNodeValue(); } } } } else { // give up: cannot find the version file from: test, internal and external _log.debug("Cannot find the version xml file from host : " + url.getHost()); } } catch (Exception ex) { _log.error("Error retrieving upgrade version info.", ex); } } private Element constructPath(Document xmlDoc, XPath xPath, String path) throws XPathExpressionException { Element e = (Element) xPath.evaluate("/" + path + "[1]", xmlDoc, XPathConstants.NODE); if (e == null) { int i = path.lastIndexOf('/'); if (i < 0) { e = xmlDoc.createElement(path); xmlDoc.getDocumentElement().appendChild(e); } else { e = xmlDoc.createElement(path.substring(i + 1)); constructPath(xmlDoc, xPath, path.substring(0, i)).appendChild(e); } } return e; } /* * Updating information in the internal XML file */ private void updateInfoFile() { try { File currentInfo = getFile(); if (currentInfo.exists() && currentInfo.isFile()) { Document xmlDoc = XMLUtil.openXmlFile(currentInfo, false); if (xmlDoc != null) { XPath xPath = XPathFactory.newInstance().newXPath(); constructPath(xmlDoc, xPath, "version/tool").setTextContent(_currentToolVersion.toString()); constructPath(xmlDoc, xPath, "version/initialized") .setTextContent(Boolean.toString(_initializedBoolean)); constructPath(xmlDoc, xPath, "version/snooze/boolean") .setTextContent(Boolean.toString(_snoozeBoolean)); constructPath(xmlDoc, xPath, "version/snooze/days").setTextContent(_snoozeDays + ""); constructPath(xmlDoc, xPath, "version/snooze/date").setTextContent(df.format(new Date())); XMLUtil.writeXmlFile(xmlDoc, currentInfo.getCanonicalPath(), "UTF-8", "no"); } } } catch (Exception ex) { _log.error("Error updating file information", ex); } } /* * Check whether the internal XML is available in plug-in * * @return */ private File getFile() { try { IPath location = new Path(VMToolsUtils.getVMToolsFolderPath() + File.separator + EJDE_CURRENTINFO_XML); File currentInfoFile = location.toFile(); return currentInfoFile; } catch (Exception ex) { _log.error("Error generating XML file", ex); } return null; } /* * Showing up a dialog whether users are interesting in latest version of web plug-in * * @param current version, latest version, dialog message * * @return */ private int resultFromDialog(Version currentVersion, Version webVersion, String message, String upgradeUrl, String messageTitle) { String[] dialogButtonLabels = { Messages.SNOOZE_DAYS_BUTTON, Messages.IGNORE_UPDATE_BUTTON, Messages.IGNORE_ALL_UPDATES_BUTTON }; if (RIMVersionComparator.getInstance().compare(currentVersion, webVersion, RIMVersionComparator.VERSION_ALL) < 0) { DialogOutput dialog = openMessageDialog(messageTitle, message, upgradeUrl, dialogButtonLabels); _initializedBoolean = true; return dialog.getStatus(); } return -1; } /** * Help method for opening a dialog * * @param title * @param message * @param dialogButtonLabels * @return */ private DialogOutput openMessageDialog(final String title, final String message, final String upgradeUrl, final String[] dialogButtonLabels) { final DialogOutput result = new DialogOutput(); final Display display = Display.getDefault(); if (display != null && !display.isDisposed()) { display.syncExec(new Runnable() { public void run() { NewVersionDetectionDialog dialog = new NewVersionDetectionDialog(display.getActiveShell(), title, null, message, upgradeUrl, MessageDialog.INFORMATION, dialogButtonLabels, 0); result.setStatus(dialog.open()); _snoozeDays = dialog.getSnoozeDays(); } }); } return result; // return status of the dialog } /** * Stores dialog output after it has been exited * * @author hrevinskaya */ public static class DialogOutput { private int _status = Dialog.OK; private boolean _checkboxStatus = false; /** * Set return status * * @param status * return status of a dialog */ public void setStatus(int status) { _status = status; } /** * Set status of the dialog's checkbox * * @param checkboxStatus * true if checkbox was checked; false otherwise */ public void setCheckBoxStatus(boolean checkboxStatus) { _checkboxStatus = checkboxStatus; } /** * Get return status of the dialog * * @return status of the dialog */ public int getStatus() { return _status; } /** * Get checkbox status of the dialog * * @return true if the checkbox was checked when dialog was exited; false otherwise */ public boolean getCheckboxStatus() { return _checkboxStatus; } } }