blob: 6735f3db8128e11d348e6ce0207a9e393993c889 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - Initial API and implementation
*******************************************************************************/
package org.eclipse.wst.server.discovery.internal;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.engine.IProfile;
import org.eclipse.equinox.p2.engine.IProfileRegistry;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.query.*;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.server.discovery.internal.model.Extension;
import org.eclipse.wst.server.discovery.internal.model.ExtensionUpdateSite;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
public class ExtensionUtility {
private static ExtensionUpdateSite[] getExtensionUpdateSites(URL url) throws CoreException {
InputStream in = null;
try {
in = url.openStream();
} catch (Exception e) {
Trace.trace(Trace.SEVERE, "Could not load URL " + url);
}
if (in == null)
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, "Could not load extensions", null));
try {
IMemento memento = XMLMemento.loadMemento(in);
IMemento children[] = memento.getChildren("site");
int size = children.length;
List<ExtensionUpdateSite> list = new ArrayList<ExtensionUpdateSite>(size);
for (int i = 0; i < size; i++) {
String url2 = children[i].getString("url");
ExtensionUpdateSite item = new ExtensionUpdateSite(url2, null, null);
list.add(item);
}
ExtensionUpdateSite[] items = new ExtensionUpdateSite[list.size()];
list.toArray(items);
return items;
} catch (Exception e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, e.getMessage(), e));
}
}
/**
* Returns an array of all known extension update sites.
* <p>
* A new array is returned on each call, so clients may store or modify the result.
* </p>
*
* @return the array of extensions items {@link ExtensionUpdateSite}
*/
private static ExtensionUpdateSite[] getExtensionUpdateSites() {
URL url = Activator.getDefault().getBundle().getEntry("serverAdapterSites.xml");
try {
return getExtensionUpdateSites(url);
} catch (CoreException ce) {
Trace.trace(Trace.SEVERE, "Could not get extension items");
return new ExtensionUpdateSite[0];
}
}
/**
* Return true if the new feature is already installed, or a newer one is.
*
* @param existing
* @param newFeature
* @return true if the new feature is already installed, or a newer one is.
*/
private static boolean alreadyExists(List<Extension> existing, Extension newFeature) {
if (existing.contains(newFeature))
return true;
Version newV = newFeature.getVersion();
Iterator<Extension> iterator = existing.iterator();
while (iterator.hasNext()) {
Extension feature = iterator.next();
if (feature.getId().equals(newFeature.getId())) {
if (feature.getVersion().compareTo(newV) >= 0)
return true;
}
}
return false;
}
private static void addExtension(List<Extension> list, List<Extension> existing, Extension newFeature, ExtensionListener listener) {
if (alreadyExists(existing, newFeature))
return;
synchronized (list) {
Version newV = newFeature.getVersion();
Extension remove = null;
Iterator<Extension> iterator = list.iterator();
while (iterator.hasNext()) {
Extension feature = iterator.next();
if (feature.getId().equals(newFeature.getId())) {
if (feature.getVersion().compareTo(newV) < 0) {
remove = feature;
} else
// new feature is older
return;
}
}
if (remove != null) {
list.remove(remove);
listener.extensionRemoved(remove);
}
list.add(newFeature);
}
listener.extensionFound(newFeature);
}
protected static void addExtensions(List<Extension> list, List<Extension> existing, List<Extension> newFeatures, ExtensionListener listener) {
Iterator<Extension> iterator = newFeatures.iterator();
while (iterator.hasNext())
addExtension(list, existing, iterator.next(), listener);
}
public interface ExtensionListener {
public void extensionFound(Extension extension);
public void extensionRemoved(Extension feature);
public void siteFailure(String host);
}
private static List<Extension> getExistingFeatures(IProgressMonitor monitor) throws CoreException {
monitor.beginTask(Messages.discoverLocalConfiguration, 100);
IProfileRegistry profileRegistry = (IProfileRegistry) getService(Activator.getDefault().getBundle().getBundleContext(), IProfileRegistry.class.getName());
IProfile[] profiles = profileRegistry.getProfiles();
IProfile profile = profileRegistry.getProfile(IProfileRegistry.SELF);
IQuery<IInstallableUnit> query = QueryUtil.createIUAnyQuery();
//Query query = new InstallableUnitQuery("org.eclipse.wst.server.core.serverAdapter");
//List<String> list2 = new ArrayList();
//Query query = new ExtensionInstallableUnitQuery(list2);
IQueryResult<IInstallableUnit> collector = profile.query(query, monitor);
List<Extension> list = new ArrayList<Extension>();
Iterator<IInstallableUnit> iter = collector.iterator();
while (iter.hasNext()) {
IInstallableUnit iu = iter.next();
if (!list.contains(iu))
list.add(new Extension(iu, null));
}
monitor.done();
return list;
}
public static Extension[] getAllExtensions(final String id, final ExtensionListener listener, IProgressMonitor monitor) throws CoreException {
monitor = ProgressUtil.getMonitorFor(monitor);
monitor.beginTask("", 1100);
monitor.subTask(Messages.discoverLocalConfiguration);
final List<Extension> existing = getExistingFeatures(ProgressUtil.getSubMonitorFor(monitor, 100));
final ExtensionUpdateSite[] items = getExtensionUpdateSites();
if (items == null || items.length == 0)
return new Extension[0];
final int x = 1000 / items.length;
monitor.worked(50);
final List<Extension> list = new ArrayList<Extension>();
int size = items.length;
Thread[] threads = new Thread[size];
for (int i = 0; i < size; i++) {
try {
if (monitor.isCanceled())
return null;
monitor.subTask(NLS.bind(Messages.discoverSearching, items[i].getUrl()));
final int ii = i;
final IProgressMonitor monitor2 = monitor;
threads[i] = new Thread("Extension Checker for " + items[i].getUrl()) {
public void run() {
try {
List<Extension> list2 = items[ii].getExtensions(ProgressUtil.getSubMonitorFor(monitor2, x));
addExtensions(list, existing, list2, listener);
} catch (CoreException ce) {
listener.siteFailure(ce.getLocalizedMessage());
Trace.trace(Trace.WARNING, "Error downloading extension info", ce);
}
}
};
threads[i].setDaemon(true);
threads[i].start();
} catch (Exception e) {
Trace.trace(Trace.WARNING, "Error downloading extension info 2", e);
}
}
for (int i = 0; i < size; i++) {
try {
if (monitor.isCanceled())
return null;
if (threads[i].isAlive())
threads[i].join();
} catch (Exception e) {
Trace.trace(Trace.WARNING, "Error downloading extension info 3", e);
}
}
Extension[] ef = new Extension[list.size()];
list.toArray(ef);
monitor.done();
return ef;
}
/**
* Returns the service described by the given arguments. Note that this is a helper class
* that <b>immediately</b> ungets the service reference. This results in a window where the
* system thinks the service is not in use but indeed the caller is about to use the returned
* service object.
* @param context
* @param name
* @return The requested service
*/
public static Object getService(BundleContext context, String name) {
ServiceReference reference = context.getServiceReference(IProvisioningAgent.SERVICE_NAME);
if (reference == null)
return null;
IProvisioningAgent result = getAgent(context);
if (result == null)
return null;
try {
return result.getService(name);
} finally {
context.ungetService(reference);
}
}
public static IProvisioningAgent getAgent(BundleContext context) {
ServiceReference reference = context.getServiceReference(IProvisioningAgent.SERVICE_NAME);
if (reference == null)
return null;
IProvisioningAgent result = (IProvisioningAgent) context.getService(reference);
return result;
}
}