Commit 0073a3f5 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

Refactoring work to reduce queries to jivesoftware.org and keep privacy of...

Refactoring work to reduce queries to jivesoftware.org and keep privacy of installed plugins. JM-715

git-svn-id: http://svn.igniterealtime.org/svn/repos/wildfire/trunk@3998 b35dd754-fafc-0310-a699-88a17e54d16e
parent 1fedf585
/**
* $RCSfile$
* $Revision: $
* $Date: $
*
* Copyright (C) 2006 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.update; package org.jivesoftware.wildfire.update;
/** /**
* Information about an available plugin (i.e. not installed). The information was obtained * Plugin available at jivesoftware.org. The plugin may or may not be locally installed.
* from jivesoftware.org after executing
* {@link org.jivesoftware.wildfire.update.UpdateManager#getAvailablePlugins()}.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
......
/**
* $RCSfile$
* $Revision: $
* $Date: $
*
* Copyright (C) 2006 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.update; package org.jivesoftware.wildfire.update;
/** /**
...@@ -77,16 +88,6 @@ public class Update { ...@@ -77,16 +88,6 @@ public class Update {
return url; return url;
} }
/**
* Returns true if this update means that the server needs to be updated. When false
* then it means that a plugin needs to be updated.
*
* @return true if this update means that the server needs to be updated.
*/
public boolean isServer() {
return "Wildfire".equals(componentName);
}
/** /**
* Returns true if the plugin was downloaded. Once a plugin has been downloaded * Returns true if the plugin was downloaded. Once a plugin has been downloaded
* it may take a couple of seconds to be installed. This flag only makes sense for * it may take a couple of seconds to be installed. This flag only makes sense for
......
/**
* $RCSfile$
* $Revision: $
* $Date: $
*
* Copyright (C) 2006 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.update; package org.jivesoftware.wildfire.update;
import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpClient;
...@@ -18,7 +29,6 @@ import org.jivesoftware.wildfire.MessageRouter; ...@@ -18,7 +29,6 @@ import org.jivesoftware.wildfire.MessageRouter;
import org.jivesoftware.wildfire.XMPPServer; import org.jivesoftware.wildfire.XMPPServer;
import org.jivesoftware.wildfire.container.BasicModule; import org.jivesoftware.wildfire.container.BasicModule;
import org.jivesoftware.wildfire.container.Plugin; import org.jivesoftware.wildfire.container.Plugin;
import org.jivesoftware.wildfire.container.PluginManager;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import org.xmpp.packet.Message; import org.xmpp.packet.Message;
...@@ -45,9 +55,19 @@ public class UpdateManager extends BasicModule { ...@@ -45,9 +55,19 @@ public class UpdateManager extends BasicModule {
private static String updateServiceURL = "http://www.jivesoftware.org/wildfire/versions.jsp"; private static String updateServiceURL = "http://www.jivesoftware.org/wildfire/versions.jsp";
/** /**
* List of components that need to be updated. * Information about the available server update.
*/
private Update serverUpdate;
/**
* List of plugins that need to be updated.
*/
private Collection<Update> pluginUpdates = new ArrayList<Update>();
/**
* List of plugins available at jivesoftware.org.
*/ */
private Collection<Update> toUpdate = new ArrayList<Update>(); private Map<String, AvailablePlugin> availablePlugins = new HashMap<String, AvailablePlugin>();
/** /**
* Thread that performs the periodic checks for updates. * Thread that performs the periodic checks for updates.
...@@ -82,20 +102,20 @@ public class UpdateManager extends BasicModule { ...@@ -82,20 +102,20 @@ public class UpdateManager extends BasicModule {
try { try {
// Sleep for 15 seconds before starting to work // Sleep for 15 seconds before starting to work
Thread.sleep(15000); Thread.sleep(15000);
// Load last saved response (if any) // Load last saved information (if any)
Element xmlResponse = loadResponse(); loadSavedInfo();
if (xmlResponse != null) {
// Parse response and recreate Update objects
parseResponse(xmlResponse);
// Check if components were manually updated
checkForManualUpdates();
}
while (isServiceEnabled()) { while (isServiceEnabled()) {
waitForNextChecking(); waitForNextChecking();
// Check if the service is still enabled // Check if the service is still enabled
if (isServiceEnabled()) { if (isServiceEnabled()) {
try { try {
checkForUpdates(true); // Check for server updates
checkForServerUpdate(true);
// Refresh list of available plugins and check for plugin updates
checkForPluginsUpdates(true);
// Keep track of the last time we checked for updates
JiveGlobals.setProperty("update.lastCheck",
String.valueOf(System.currentTimeMillis()));
} }
catch (Exception e) { catch (Exception e) {
Log.error("Error checking for updates", e); Log.error("Error checking for updates", e);
...@@ -118,7 +138,7 @@ public class UpdateManager extends BasicModule { ...@@ -118,7 +138,7 @@ public class UpdateManager extends BasicModule {
// This is the first time the server is used (since we added this feature) // This is the first time the server is used (since we added this feature)
Thread.sleep(45000); Thread.sleep(45000);
} }
else { else {
long elapsed = System.currentTimeMillis() - lastCheck; long elapsed = System.currentTimeMillis() - lastCheck;
int frequency = getCheckFrequency() * 60 * 60 * 1000; int frequency = getCheckFrequency() * 60 * 60 * 1000;
if (elapsed < frequency) { if (elapsed < frequency) {
...@@ -144,11 +164,9 @@ public class UpdateManager extends BasicModule { ...@@ -144,11 +164,9 @@ public class UpdateManager extends BasicModule {
* @param notificationsEnabled true if admins will be notified when new updates are found. * @param notificationsEnabled true if admins will be notified when new updates are found.
* @throws Exception if some error happens during the query. * @throws Exception if some error happens during the query.
*/ */
public synchronized void checkForUpdates(boolean notificationsEnabled) throws Exception { public synchronized void checkForServerUpdate(boolean notificationsEnabled) throws Exception {
// Keep track of the last time we checked for updates
JiveGlobals.setProperty("update.lastCheck", String.valueOf(System.currentTimeMillis()));
// Get the XML request to include in the HTTP request // Get the XML request to include in the HTTP request
String requestXML = getUpdatesRequest(); String requestXML = getServerUpdateRequest();
// Send the request to the server // Send the request to the server
HttpClient httpClient = new HttpClient(); HttpClient httpClient = new HttpClient();
PostMethod postMethod = new PostMethod(updateServiceURL); PostMethod postMethod = new PostMethod(updateServiceURL);
...@@ -157,40 +175,105 @@ public class UpdateManager extends BasicModule { ...@@ -157,40 +175,105 @@ public class UpdateManager extends BasicModule {
new NameValuePair("query", requestXML) new NameValuePair("query", requestXML)
}; };
postMethod.setRequestBody(data); postMethod.setRequestBody(data);
int responseCode = httpClient.executeMethod(postMethod); if (httpClient.executeMethod(postMethod) == 200) {
String responseBody = postMethod.getResponseBodyAsString(); // Process answer from the server
// Process answer from the server String responseBody = postMethod.getResponseBodyAsString();
processUpdatesResponse(responseBody, notificationsEnabled); processServerUpdateResponse(responseBody, notificationsEnabled);
}
}
public synchronized void checkForPluginsUpdates(boolean notificationsEnabled) throws Exception {
// Get the XML request to include in the HTTP request
String requestXML = "<available/>";
// Send the request to the server
HttpClient httpClient = new HttpClient();
PostMethod postMethod = new PostMethod(updateServiceURL);
NameValuePair[] data = {
new NameValuePair("type", "available"),
new NameValuePair("query", requestXML)
};
postMethod.setRequestBody(data);
if (httpClient.executeMethod(postMethod) == 200) {
// Process answer from the server
String responseBody = postMethod.getResponseBodyAsString();
processAvailablePluginsResponse(responseBody, notificationsEnabled);
}
} }
/** /**
* Returns the list of available (i.e. not installed) plugins as reported * Download and install latest version of plugin.
* by jivesoftware.org.
* *
* @return the alphabetically sorted list of available plugins as reported * @param url the URL of the latest version of the plugin.
* by jivesoftware.org. * @return true if the plugin was successfully downloaded and installed.
*/ */
public List<AvailablePlugin> getAvailablePlugins() { public boolean downloadPlugin(String url) {
boolean installed = false;
// Download and install new version of plugin
HttpClient httpClient = new HttpClient();
GetMethod getMethod = new GetMethod(url);
//execute the method
try { try {
// Get the XML request to include in the HTTP request int statusCode = httpClient.executeMethod(getMethod);
String requestXML = getAvailableRequest(); if (statusCode == 200) {
// Send the request to the server //get the resonse as an InputStream
HttpClient httpClient = new HttpClient(); InputStream in = getMethod.getResponseBodyAsStream();
PostMethod postMethod = new PostMethod(updateServiceURL); String pluginFilename = url.substring(url.lastIndexOf("/") + 1);
NameValuePair[] data = { installed = XMPPServer.getInstance().getPluginManager()
new NameValuePair("type", "available"), .installPlugin(in, pluginFilename);
new NameValuePair("query", requestXML) in.close();
}; if (installed) {
postMethod.setRequestBody(data); // Remove the plugin from the list of plugins to update
int responseCode = httpClient.executeMethod(postMethod); for (Update update : pluginUpdates) {
String responseBody = postMethod.getResponseBodyAsString(); if (update.getURL().equals(url)) {
// Process answer from the server update.setDownloaded(true);
return processAvailableResponse(responseBody); }
}
// Save response in a file for later retrieval
saveLatestServerInfo();
}
}
} }
catch (Exception e) { catch (IOException e) {
Log.error("Error while getting list of available plugins", e); Log.warn("Error downloading new plugin version", e);
} }
return Collections.emptyList(); return installed;
}
/**
* Returns true if the plugin downloaded from the specified URL has been downloaded. Plugins
* may be downloaded but not installed. The install process may take like 30 seconds to
* detect new plugins to install.
*
* @param url the URL of the latest version of the plugin.
* @return true if the plugin downloaded from the specified URL has been downloaded.
*/
public boolean isPluginDownloaded(String url) {
String pluginFilename = url.substring(url.lastIndexOf("/") + 1);
return XMPPServer.getInstance().getPluginManager().isPluginDownloaded(pluginFilename);
}
/**
* Returns the list of available plugins to install as reported by jivesoftware.org.
* Currently installed plugins will not be included.
*
* @return the list of available plugins to install as reported by jivesoftware.org.
*/
public List<AvailablePlugin> getNotInstalledPlugins() {
ArrayList<AvailablePlugin> plugins =
new ArrayList<AvailablePlugin>(availablePlugins.values());
XMPPServer server = XMPPServer.getInstance();
// Remove installed plugins from the list of available plugins
for (Plugin plugin : server.getPluginManager().getPlugins()) {
String pluginName = server.getPluginManager().getName(plugin);
for (Iterator<AvailablePlugin> it=plugins.iterator(); it.hasNext();) {
AvailablePlugin availablePlugin = it.next();
if (availablePlugin.getName().equals(pluginName)) {
it.remove();
break;
}
}
}
return plugins;
} }
/** /**
...@@ -260,40 +343,24 @@ public class UpdateManager extends BasicModule { ...@@ -260,40 +343,24 @@ public class UpdateManager extends BasicModule {
JiveGlobals.setProperty("update.frequency", Integer.toString(checkFrequency)); JiveGlobals.setProperty("update.frequency", Integer.toString(checkFrequency));
} }
/**
* Returns the list of components that need to be updated. The server and server plugins
* are considered components. The returned list belongs to the last time the check for
* updates process was executred.
*
* @return the list of components that need to be updated.
*/
public Collection<Update> getToUpdate() {
return toUpdate;
}
/** /**
* Returns the server update or <tt>null</tt> if the server is up to date. * Returns the server update or <tt>null</tt> if the server is up to date.
* *
* @return the server update or null if the server is up to date. * @return the server update or null if the server is up to date.
*/ */
public Update getServerUpdate() { public Update getServerUpdate() {
for (Update update : toUpdate) { return serverUpdate;
if (update.isServer()) {
return update;
}
}
return null;
} }
/** /**
* Returns the plugin update or <tt>null</tt> if the plugin is up to date. * Returns the plugin update or <tt>null</tt> if the plugin is up to date.
* *
* @param pluginName the name of the plugin (as described in the meta-data). * @param pluginName the name of the plugin (as described in the meta-data).
* @param currentVersion current version of the plugin that is installed. * @param currentVersion current version of the plugin that is installed.
* @return the plugin update or null if the plugin is up to date. * @return the plugin update or null if the plugin is up to date.
*/ */
public Update getPluginUpdate(String pluginName, String currentVersion) { public Update getPluginUpdate(String pluginName, String currentVersion) {
for (Update update : toUpdate) { for (Update update : pluginUpdates) {
// Check if this is the requested plugin // Check if this is the requested plugin
if (update.getComponentName().equals(pluginName)) { if (update.getComponentName().equals(pluginName)) {
// Check if the plugin version is right // Check if the plugin version is right
...@@ -305,129 +372,55 @@ public class UpdateManager extends BasicModule { ...@@ -305,129 +372,55 @@ public class UpdateManager extends BasicModule {
return null; return null;
} }
private String getUpdatesRequest() { private String getServerUpdateRequest() {
XMPPServer server = XMPPServer.getInstance(); XMPPServer server = XMPPServer.getInstance();
Element xmlRequest = docFactory.createDocument().addElement("version"); Element xmlRequest = docFactory.createDocument().addElement("version");
// Add current wildfire version // Add current wildfire version
Element wildfire = xmlRequest.addElement("wildfire"); Element wildfire = xmlRequest.addElement("wildfire");
wildfire.addAttribute("current", server.getServerInfo().getVersion().getVersionString()); wildfire.addAttribute("current", server.getServerInfo().getVersion().getVersionString());
// Add plugins information
for (Plugin plugin : server.getPluginManager().getPlugins()) {
Element pluginElement = xmlRequest.addElement("plugin");
pluginElement.addAttribute("name", server.getPluginManager().getName(plugin));
pluginElement.addAttribute("current", server.getPluginManager().getVersion(plugin));
}
return xmlRequest.asXML(); return xmlRequest.asXML();
} }
private String getAvailableRequest() { private void processServerUpdateResponse(String response, boolean notificationsEnabled)
XMPPServer server = XMPPServer.getInstance();
Element xmlRequest = docFactory.createDocument().addElement("available");
// Add information of currently installed plugins
for (Plugin plugin : server.getPluginManager().getPlugins()) {
Element pluginElement = xmlRequest.addElement("plugin");
pluginElement.addAttribute("name", server.getPluginManager().getName(plugin));
}
return xmlRequest.asXML();
}
/**
* Discards updates of components that were manually updated while the server was stopped.
*/
private void checkForManualUpdates() {
Collection<Update> toDelete = new ArrayList<Update>();
PluginManager pluginManager = XMPPServer.getInstance().getPluginManager();
for (Update update : toUpdate) {
String latestVersion = update.getLatestVersion();
if (update.isServer()) {
// Check if current server version is correct
String serverVersion =
XMPPServer.getInstance().getServerInfo().getVersion().getVersionString();
if (serverVersion.compareTo(latestVersion) >= 0) {
toDelete.add(update);
}
}
else {
// Check if current plugin version is correct
String pluginName = update.getURL().substring(update.getURL().lastIndexOf("/")+1);
Plugin plugin = pluginManager
.getPlugin(pluginName.substring(0, pluginName.length() - 4).toLowerCase());
if (plugin != null &&
pluginManager.getVersion(plugin).compareTo(latestVersion) >= 0) {
toDelete.add(update);
}
}
}
if (!toDelete.isEmpty()) {
// Remove old version of list of updates
toUpdate.removeAll(toDelete);
// Save response in a file for later retrieval
saveResponse();
}
}
private void processUpdatesResponse(String response, boolean notificationsEnabled)
throws DocumentException { throws DocumentException {
// Reset list of components that need to be updated // Reset last known update information
toUpdate = new ArrayList<Update>(); serverUpdate = null;
Element xmlResponse = new SAXReader().read(new StringReader(response)).getRootElement(); Element xmlResponse = new SAXReader().read(new StringReader(response)).getRootElement();
// Parse response and keep info as Update objects // Parse response and keep info as Update objects
parseResponse(xmlResponse);
// Save response in a file for later retrieval
saveResponse();
// Check if we need to send notifications to admins
if (notificationsEnabled && isNotificationEnabled() && !toUpdate.isEmpty()) {
Collection<JID> admins = XMPPServer.getInstance().getAdmins();
for (Update update : toUpdate) {
Message notification = new Message();
notification.setFrom(serverName);
notification.setBody(getNotificationMessage() + " " + update.getComponentName() +
" " + update.getLatestVersion());
for (JID jid : admins) {
notification.setTo(jid);
router.route(notification);
}
}
}
}
/**
* Parses the XML response from the server and generates {@link Update} objects.
*
* @param xmlResponse the XML response answered by the server.
*/
private void parseResponse(Element xmlResponse) {
Element wildfire = xmlResponse.element("wildfire"); Element wildfire = xmlResponse.element("wildfire");
if (wildfire != null) { if (wildfire != null) {
// A new version of wildfire was found // A new version of wildfire was found
String latestVersion = wildfire.attributeValue("latest"); String latestVersion = wildfire.attributeValue("latest");
String changelog = wildfire.attributeValue("changelog"); String changelog = wildfire.attributeValue("changelog");
String url = wildfire.attributeValue("url"); String url = wildfire.attributeValue("url");
Update update = new Update("Wildfire", latestVersion, changelog, url); // Keep information about the available server update
// Add component to the list of components that need to be updated serverUpdate = new Update("Wildfire", latestVersion, changelog, url);
toUpdate.add(update);
} }
Iterator plugins = xmlResponse.elementIterator("plugin"); // Check if we need to send notifications to admins
while (plugins.hasNext()) { if (notificationsEnabled && isNotificationEnabled() && serverUpdate != null) {
// A new version of a plugin was found Collection<JID> admins = XMPPServer.getInstance().getAdmins();
Element plugin = (Element) plugins.next(); Message notification = new Message();
String pluginName = plugin.attributeValue("name"); notification.setFrom(serverName);
String latestVersion = plugin.attributeValue("latest"); notification.setBody(getNotificationMessage() + " " + serverUpdate.getComponentName() +
String changelog = plugin.attributeValue("changelog"); " " + serverUpdate.getLatestVersion());
String url = plugin.attributeValue("url"); for (JID jid : admins) {
Update update = new Update(pluginName, latestVersion, changelog, url); notification.setTo(jid);
// Add component to the list of components that need to be updated router.route(notification);
toUpdate.add(update); }
} }
// Save response in a file for later retrieval
saveLatestServerInfo();
} }
private List<AvailablePlugin> processAvailableResponse(String response) throws DocumentException { private void processAvailablePluginsResponse(String response, boolean notificationsEnabled)
List<AvailablePlugin> answer = new ArrayList<AvailablePlugin>(); throws DocumentException {
Element xmlResponse = new SAXReader().read(new StringReader(response)).getRootElement(); // Reset last known list of available plugins
availablePlugins = new HashMap<String, AvailablePlugin>();
// Parse response and keep info as AvailablePlugin objects // Parse response and keep info as AvailablePlugin objects
Element xmlResponse = new SAXReader().read(new StringReader(response)).getRootElement();
Iterator plugins = xmlResponse.elementIterator("plugin"); Iterator plugins = xmlResponse.elementIterator("plugin");
while (plugins.hasNext()) { while (plugins.hasNext()) {
// A new version of a plugin was found
Element plugin = (Element) plugins.next(); Element plugin = (Element) plugins.next();
String pluginName = plugin.attributeValue("name"); String pluginName = plugin.attributeValue("name");
String latestVersion = plugin.attributeValue("latest"); String latestVersion = plugin.attributeValue("latest");
...@@ -441,43 +434,122 @@ public class UpdateManager extends BasicModule { ...@@ -441,43 +434,122 @@ public class UpdateManager extends BasicModule {
String minServerVersion = plugin.attributeValue("minServerVersion"); String minServerVersion = plugin.attributeValue("minServerVersion");
AvailablePlugin available = new AvailablePlugin(pluginName, description, latestVersion, AvailablePlugin available = new AvailablePlugin(pluginName, description, latestVersion,
author, icon, changelog, readme, isCommercial, minServerVersion, url); author, icon, changelog, readme, isCommercial, minServerVersion, url);
// Add component to the list of components that need to be updated // Add plugin to the list of available plugins at js.org
answer.add(available); availablePlugins.put(pluginName, available);
} }
// Sort answer alphabetically
Collections.sort(answer, new Comparator() { // Figure out local plugins that need to be updated
public int compare(Object o1, Object o2) { buildPluginsUpdateList();
return ((AvailablePlugin)o1).getName().compareTo(((AvailablePlugin)o2).getName());
// Check if we need to send notifications to admins
if (notificationsEnabled && isNotificationEnabled() && !pluginUpdates.isEmpty()) {
Collection<JID> admins = XMPPServer.getInstance().getAdmins();
for (Update update : pluginUpdates) {
Message notification = new Message();
notification.setFrom(serverName);
notification.setBody(getNotificationMessage() + " " + update.getComponentName() +
" " + update.getLatestVersion());
for (JID jid : admins) {
notification.setTo(jid);
router.route(notification);
}
} }
}); }
return answer;
// Save information of available plugins
saveAvailablePluginsInfo();
} }
/** /**
* Saves the XML response from the server to a file. The file is named conf/updates.xml. * Recreate the list of plugins that need to be updated based on the list of
* Only not installed plugins will be saved. Each time a plugin is installed the * available plugins at jivesoftware.org.
* file will be saved again.
*/ */
private void saveResponse() { private void buildPluginsUpdateList() {
// Recreate XML response based on non-installed updates // Reset list of plugins that need to be updated
pluginUpdates = new ArrayList<Update>();
XMPPServer server = XMPPServer.getInstance();
// Compare local plugins versions with latest ones
for (Plugin plugin : server.getPluginManager().getPlugins()) {
String pluginName = server.getPluginManager().getName(plugin);
AvailablePlugin latestPlugin = availablePlugins.get(pluginName);
String currentVersion = server.getPluginManager().getVersion(plugin);
if (latestPlugin != null &&
latestPlugin.getLatestVersion().compareTo(currentVersion) > 0) {
Update update = new Update(pluginName, latestPlugin.getLatestVersion(),
latestPlugin.getChangelog(), latestPlugin.getURL());
pluginUpdates.add(update);
}
}
}
/**
* Saves to conf/server-update.xml information about the latest Wildfire release that is
* available for download.
*/
private void saveLatestServerInfo() {
Element xmlResponse = docFactory.createDocument().addElement("version"); Element xmlResponse = docFactory.createDocument().addElement("version");
for (Update update : toUpdate) { if (serverUpdate != null) {
if (update.isDownloaded()) { Element component = xmlResponse.addElement("wildfire");
continue; component.addAttribute("latest", serverUpdate.getLatestVersion());
component.addAttribute("changelog", serverUpdate.getChangelog());
component.addAttribute("url", serverUpdate.getURL());
}
// Write data out to conf/server-update.xml file.
Writer writer = null;
try {
// Create the conf folder if required
File file = new File(JiveGlobals.getHomeDirectory(), "conf");
if (!file.exists()) {
file.mkdir();
} }
Element component; file = new File(JiveGlobals.getHomeDirectory() + File.separator + "conf",
if (update.isServer()) { "server-update.xml");
component = xmlResponse.addElement("wildfire"); // Delete the old server-update.xml file if it exists
if (file.exists()) {
file.delete();
} }
else { // Create new version.xml with returned data
component = xmlResponse.addElement("plugin"); writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
component.addAttribute("name", update.getComponentName()); OutputFormat prettyPrinter = OutputFormat.createPrettyPrint();
XMLWriter xmlWriter = new XMLWriter(writer, prettyPrinter);
xmlWriter.write(xmlResponse);
}
catch (Exception e) {
Log.error(e);
}
finally {
if (writer != null) {
try {
writer.close();
}
catch (IOException e1) {
Log.error(e1);
}
} }
component.addAttribute("latest", update.getLatestVersion());
component.addAttribute("changelog", update.getChangelog());
component.addAttribute("url", update.getURL());
} }
// Write data out to conf/updates.xml file. }
/**
* Saves to conf/available-plugins.xml the list of plugins that are available
* at jivesoftware.org.
*/
private void saveAvailablePluginsInfo() {
// XML to store in the file
Element xml = docFactory.createDocument().addElement("available");
for (AvailablePlugin plugin : availablePlugins.values()) {
Element component = xml.addElement("plugin");
component.addAttribute("name", plugin.getName());
component.addAttribute("latest", plugin.getLatestVersion());
component.addAttribute("changelog", plugin.getChangelog());
component.addAttribute("url", plugin.getURL());
component.addAttribute("author", plugin.getAuthor());
component.addAttribute("description", plugin.getDescription());
component.addAttribute("icon", plugin.getIcon());
component.addAttribute("minServerVersion", plugin.getMinServerVersion());
component.addAttribute("readme", plugin.getReadme());
component.addAttribute("commercial", Boolean.toString(plugin.isCommercial()));
}
// Write data out to conf/available-plugins.xml file.
Writer writer = null; Writer writer = null;
try { try {
// Create the conf folder if required // Create the conf folder if required
...@@ -486,7 +558,7 @@ public class UpdateManager extends BasicModule { ...@@ -486,7 +558,7 @@ public class UpdateManager extends BasicModule {
file.mkdir(); file.mkdir();
} }
file = new File(JiveGlobals.getHomeDirectory() + File.separator + "conf", file = new File(JiveGlobals.getHomeDirectory() + File.separator + "conf",
"updates.xml"); "available-plugins.xml");
// Delete the old version.xml file if it exists // Delete the old version.xml file if it exists
if (file.exists()) { if (file.exists()) {
file.delete(); file.delete();
...@@ -495,7 +567,7 @@ public class UpdateManager extends BasicModule { ...@@ -495,7 +567,7 @@ public class UpdateManager extends BasicModule {
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))); writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
OutputFormat prettyPrinter = OutputFormat.createPrettyPrint(); OutputFormat prettyPrinter = OutputFormat.createPrettyPrint();
XMLWriter xmlWriter = new XMLWriter(writer, prettyPrinter); XMLWriter xmlWriter = new XMLWriter(writer, prettyPrinter);
xmlWriter.write(xmlResponse); xmlWriter.write(xml);
} }
catch (Exception e) { catch (Exception e) {
Log.error(e); Log.error(e);
...@@ -513,22 +585,29 @@ public class UpdateManager extends BasicModule { ...@@ -513,22 +585,29 @@ public class UpdateManager extends BasicModule {
} }
/** /**
* Returns the last recieved XML response from the server or <tt>null</tt> if non was * Loads list of available plugins and latest available server version from
* ever saved before. * conf/available-plugins.xml and conf/server-update.xml respectively.
*
* @return the last recieved XML response from the server or null if non was found.
*/ */
private Element loadResponse() { private void loadSavedInfo() {
// Load server update information
loadLatestServerInfo();
// Load available plugins information
loadAvailablePluginsInfo();
// Recreate list of plugins to update
buildPluginsUpdateList();
}
private void loadLatestServerInfo() {
Document xmlResponse; Document xmlResponse;
File file = File file = new File(JiveGlobals.getHomeDirectory() + File.separator + "conf",
new File(JiveGlobals.getHomeDirectory() + File.separator + "conf", "updates.xml"); "server-update.xml");
if (!file.exists()) { if (!file.exists()) {
return null; return;
} }
// Check read privs. // Check read privs.
if (!file.canRead()) { if (!file.canRead()) {
Log.warn("Cannot retrieve available updates. File must be readable: " + file.getName()); Log.warn("Cannot retrieve server updates. File must be readable: " + file.getName());
return null; return;
} }
FileReader reader = null; FileReader reader = null;
try { try {
...@@ -537,8 +616,8 @@ public class UpdateManager extends BasicModule { ...@@ -537,8 +616,8 @@ public class UpdateManager extends BasicModule {
xmlResponse = xmlReader.read(reader); xmlResponse = xmlReader.read(reader);
} }
catch (Exception e) { catch (Exception e) {
Log.error("Error reading updates.xml", e); Log.error("Error reading server-update.xml", e);
return null; return;
} }
finally { finally {
if (reader != null) { if (reader != null) {
...@@ -550,58 +629,71 @@ public class UpdateManager extends BasicModule { ...@@ -550,58 +629,71 @@ public class UpdateManager extends BasicModule {
} }
} }
} }
return xmlResponse.getRootElement(); // Parse info and recreate update information (if still required)
Element wildfire = xmlResponse.getRootElement().element("wildfire");
if (wildfire != null) {
String latestVersion = wildfire.attributeValue("latest");
String changelog = wildfire.attributeValue("changelog");
String url = wildfire.attributeValue("url");
// Check if current server version is correct
String serverVersion =
XMPPServer.getInstance().getServerInfo().getVersion().getVersionString();
if (serverVersion.compareTo(latestVersion) < 0) {
serverUpdate = new Update("Wildfire", latestVersion, changelog, url);
}
}
} }
/** private void loadAvailablePluginsInfo() {
* Download and install latest version of plugin. Document xmlResponse;
* File file = new File(JiveGlobals.getHomeDirectory() + File.separator + "conf",
* @param url the URL of the latest version of the plugin. "available-plugins.xml");
* @return true if the plugin was successfully downloaded and installed. if (!file.exists()) {
*/ return;
public boolean downloadPlugin(String url) { }
boolean installed = false; // Check read privs.
// Download and install new version of plugin if (!file.canRead()) {
HttpClient httpClient = new HttpClient(); Log.warn("Cannot retrieve available plugins. File must be readable: " + file.getName());
GetMethod getMethod = new GetMethod(url); return;
//execute the method }
FileReader reader = null;
try { try {
int statusCode = httpClient.executeMethod(getMethod); reader = new FileReader(file);
if (statusCode == 200) { SAXReader xmlReader = new SAXReader();
//get the resonse as an InputStream xmlResponse = xmlReader.read(reader);
InputStream in = getMethod.getResponseBodyAsStream(); }
String pluginFilename = url.substring(url.lastIndexOf("/") + 1); catch (Exception e) {
installed = XMPPServer.getInstance().getPluginManager() Log.error("Error reading available-plugins.xml", e);
.installPlugin(in, pluginFilename); return;
in.close(); }
if (installed) { finally {
// Remove the plugin from the list of plugins to update if (reader != null) {
for (Update update : toUpdate) { try {
if (update.getURL().equals(url)) { reader.close();
update.setDownloaded(true); }
} catch (Exception e) {
} // Do nothing
// Save response in a file for later retrieval
saveResponse();
} }
} }
} }
catch (IOException e) { // Parse info and recreate available plugins
Log.warn("Error downloading new plugin version", e); Iterator it = xmlResponse.getRootElement().elementIterator("plugin");
while (it.hasNext()) {
Element plugin = (Element) it.next();
String pluginName = plugin.attributeValue("name");
String latestVersion = plugin.attributeValue("latest");
String icon = plugin.attributeValue("icon");
String readme = plugin.attributeValue("readme");
String changelog = plugin.attributeValue("changelog");
String url = plugin.attributeValue("url");
boolean isCommercial = "true".equals(plugin.attributeValue("commercial"));
String description = plugin.attributeValue("description");
String author = plugin.attributeValue("author");
String minServerVersion = plugin.attributeValue("minServerVersion");
AvailablePlugin available = new AvailablePlugin(pluginName, description, latestVersion,
author, icon, changelog, readme, isCommercial, minServerVersion, url);
// Add plugin to the list of available plugins at js.org
availablePlugins.put(pluginName, available);
} }
return installed;
}
/**
* Returns true if the plugin downloaded from the specified URL has been downloaded. Plugins
* may be downloaded but not installed. The install process may take like 30 seconds to
* detect new plugins to install.
*
* @param url the URL of the latest version of the plugin.
* @return true if the plugin downloaded from the specified URL has been downloaded.
*/
public boolean isPluginDownloaded(String url) {
String pluginFilename = url.substring(url.lastIndexOf("/") + 1);
return XMPPServer.getInstance().getPluginManager().isPluginDownloaded(pluginFilename);
} }
} }
...@@ -8,8 +8,10 @@ ...@@ -8,8 +8,10 @@
<%@ page import="org.jivesoftware.wildfire.XMPPServer, <%@ page import="org.jivesoftware.wildfire.XMPPServer,
org.jivesoftware.wildfire.update.AvailablePlugin, org.jivesoftware.wildfire.update.AvailablePlugin,
org.jivesoftware.wildfire.update.UpdateManager, org.jivesoftware.wildfire.update.UpdateManager,
java.util.List" java.util.Collections"
%> %>
<%@ page import="java.util.Comparator"%>
<%@ page import="java.util.List"%>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %> <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %> <%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>
...@@ -21,7 +23,14 @@ ...@@ -21,7 +23,14 @@
String url = request.getParameter("url"); String url = request.getParameter("url");
UpdateManager updateManager = XMPPServer.getInstance().getUpdateManager(); UpdateManager updateManager = XMPPServer.getInstance().getUpdateManager();
List<AvailablePlugin> plugins = updateManager.getAvailablePlugins(); List<AvailablePlugin> plugins = updateManager.getNotInstalledPlugins();
// Sort plugins alphabetically
Collections.sort(plugins, new Comparator() {
public int compare(Object o1, Object o2) {
return ((AvailablePlugin) o1).getName().compareTo(((AvailablePlugin) o2).getName());
}
});
if (downloadRequested) { if (downloadRequested) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment