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);
...@@ -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,23 +175,16 @@ public class UpdateManager extends BasicModule { ...@@ -157,23 +175,16 @@ 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
processUpdatesResponse(responseBody, notificationsEnabled); String responseBody = postMethod.getResponseBodyAsString();
processServerUpdateResponse(responseBody, notificationsEnabled);
}
} }
/** public synchronized void checkForPluginsUpdates(boolean notificationsEnabled) throws Exception {
* Returns the list of available (i.e. not installed) plugins as reported
* by jivesoftware.org.
*
* @return the alphabetically sorted list of available plugins as reported
* by jivesoftware.org.
*/
public List<AvailablePlugin> getAvailablePlugins() {
try {
// Get the XML request to include in the HTTP request // Get the XML request to include in the HTTP request
String requestXML = getAvailableRequest(); String requestXML = "<available/>";
// 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);
...@@ -182,15 +193,87 @@ public class UpdateManager extends BasicModule { ...@@ -182,15 +193,87 @@ 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
return processAvailableResponse(responseBody); String responseBody = postMethod.getResponseBodyAsString();
processAvailablePluginsResponse(responseBody, notificationsEnabled);
} }
catch (Exception e) {
Log.error("Error while getting list of available plugins", e);
} }
return Collections.emptyList();
/**
* Download and install latest version of plugin.
*
* @param url the URL of the latest version of the plugin.
* @return true if the plugin was successfully downloaded and installed.
*/
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 {
int statusCode = httpClient.executeMethod(getMethod);
if (statusCode == 200) {
//get the resonse as an InputStream
InputStream in = getMethod.getResponseBodyAsStream();
String pluginFilename = url.substring(url.lastIndexOf("/") + 1);
installed = XMPPServer.getInstance().getPluginManager()
.installPlugin(in, pluginFilename);
in.close();
if (installed) {
// Remove the plugin from the list of plugins to update
for (Update update : pluginUpdates) {
if (update.getURL().equals(url)) {
update.setDownloaded(true);
}
}
// Save response in a file for later retrieval
saveLatestServerInfo();
}
}
}
catch (IOException e) {
Log.warn("Error downloading new plugin version", e);
}
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,29 +343,13 @@ public class UpdateManager extends BasicModule { ...@@ -260,29 +343,13 @@ 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;
} }
/** /**
...@@ -293,7 +360,7 @@ public class UpdateManager extends BasicModule { ...@@ -293,7 +360,7 @@ public class UpdateManager extends BasicModule {
* @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();
}
private String getAvailableRequest() {
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(); return xmlRequest.asXML();
} }
/** private void processServerUpdateResponse(String response, boolean notificationsEnabled)
* 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); Element wildfire = xmlResponse.element("wildfire");
// Save response in a file for later retrieval if (wildfire != null) {
saveResponse(); // A new version of wildfire was found
String latestVersion = wildfire.attributeValue("latest");
String changelog = wildfire.attributeValue("changelog");
String url = wildfire.attributeValue("url");
// Keep information about the available server update
serverUpdate = new Update("Wildfire", latestVersion, changelog, url);
}
// Check if we need to send notifications to admins // Check if we need to send notifications to admins
if (notificationsEnabled && isNotificationEnabled() && !toUpdate.isEmpty()) { if (notificationsEnabled && isNotificationEnabled() && serverUpdate != null) {
Collection<JID> admins = XMPPServer.getInstance().getAdmins(); Collection<JID> admins = XMPPServer.getInstance().getAdmins();
for (Update update : toUpdate) {
Message notification = new Message(); Message notification = new Message();
notification.setFrom(serverName); notification.setFrom(serverName);
notification.setBody(getNotificationMessage() + " " + update.getComponentName() + notification.setBody(getNotificationMessage() + " " + serverUpdate.getComponentName() +
" " + update.getLatestVersion()); " " + serverUpdate.getLatestVersion());
for (JID jid : admins) { for (JID jid : admins) {
notification.setTo(jid); notification.setTo(jid);
router.route(notification); router.route(notification);
} }
} }
} // Save response in a file for later retrieval
saveLatestServerInfo();
} }
/** private void processAvailablePluginsResponse(String response, boolean notificationsEnabled)
* Parses the XML response from the server and generates {@link Update} objects. throws DocumentException {
* // Reset last known list of available plugins
* @param xmlResponse the XML response answered by the server. availablePlugins = new HashMap<String, AvailablePlugin>();
*/
private void parseResponse(Element xmlResponse) {
Element wildfire = xmlResponse.element("wildfire");
if (wildfire != null) {
// A new version of wildfire was found
String latestVersion = wildfire.attributeValue("latest");
String changelog = wildfire.attributeValue("changelog");
String url = wildfire.attributeValue("url");
Update update = new Update("Wildfire", latestVersion, changelog, url);
// Add component to the list of components that need to be updated
toUpdate.add(update);
}
Iterator plugins = xmlResponse.elementIterator("plugin");
while (plugins.hasNext()) {
// A new version of a plugin was found
Element plugin = (Element) plugins.next();
String pluginName = plugin.attributeValue("name");
String latestVersion = plugin.attributeValue("latest");
String changelog = plugin.attributeValue("changelog");
String url = plugin.attributeValue("url");
Update update = new Update(pluginName, latestVersion, changelog, url);
// Add component to the list of components that need to be updated
toUpdate.add(update);
}
}
private List<AvailablePlugin> processAvailableResponse(String response) throws DocumentException {
List<AvailablePlugin> answer = new ArrayList<AvailablePlugin>();
Element xmlResponse = new SAXReader().read(new StringReader(response)).getRootElement();
// 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);
}
// Figure out local plugins that need to be updated
buildPluginsUpdateList();
// 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);
}
}
}
// Save information of available plugins
saveAvailablePluginsInfo();
}
/**
* Recreate the list of plugins that need to be updated based on the list of
* available plugins at jivesoftware.org.
*/
private void buildPluginsUpdateList() {
// 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);
} }
// Sort answer alphabetically
Collections.sort(answer, new Comparator() {
public int compare(Object o1, Object o2) {
return ((AvailablePlugin)o1).getName().compareTo(((AvailablePlugin)o2).getName());
} }
});
return answer;
} }
/** /**
* Saves the XML response from the server to a file. The file is named conf/updates.xml. * Saves to conf/server-update.xml information about the latest Wildfire release that is
* Only not installed plugins will be saved. Each time a plugin is installed the * available for download.
* file will be saved again.
*/ */
private void saveResponse() { private void saveLatestServerInfo() {
// Recreate XML response based on non-installed updates
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());
} }
Element component; // Write data out to conf/server-update.xml file.
if (update.isServer()) { Writer writer = null;
component = xmlResponse.addElement("wildfire"); try {
// Create the conf folder if required
File file = new File(JiveGlobals.getHomeDirectory(), "conf");
if (!file.exists()) {
file.mkdir();
} }
else { file = new File(JiveGlobals.getHomeDirectory() + File.separator + "conf",
component = xmlResponse.addElement("plugin"); "server-update.xml");
component.addAttribute("name", update.getComponentName()); // Delete the old server-update.xml file if it exists
if (file.exists()) {
file.delete();
}
// Create new version.xml with returned data
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
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);
installed = XMPPServer.getInstance().getPluginManager()
.installPlugin(in, pluginFilename);
in.close();
if (installed) {
// Remove the plugin from the list of plugins to update
for (Update update : toUpdate) {
if (update.getURL().equals(url)) {
update.setDownloaded(true);
} }
catch (Exception e) {
Log.error("Error reading available-plugins.xml", e);
return;
} }
// Save response in a file for later retrieval finally {
saveResponse(); if (reader != null) {
try {
reader.close();
} }
catch (Exception e) {
// Do nothing
} }
} }
catch (IOException e) {
Log.warn("Error downloading new plugin version", e);
} }
return installed; // Parse info and recreate available plugins
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);
} }
/**
* 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