Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2')
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/AbstractCatalogSource.java45
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/AbstractDiscoveryStrategy.java79
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/Catalog.java334
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/DiscoveryCore.java41
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/Messages.java45
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/Policy.java42
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/messages.properties17
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/AbstractCatalogItem.java29
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/CatalogCategory.java153
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/CatalogItem.java369
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Certification.java102
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/FeatureFilter.java69
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Group.java51
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Icon.java74
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Messages.java56
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Overview.java85
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Tag.java106
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/ValidationException.java31
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/messages.properties23
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/util/CatalogCategoryComparator.java51
-rw-r--r--bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/util/CatalogItemComparator.java74
21 files changed, 1876 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/AbstractCatalogSource.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/AbstractCatalogSource.java
new file mode 100644
index 000000000..49bc9d9de
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/AbstractCatalogSource.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.discovery;
+
+import java.net.URL;
+
+
+/**
+ * @author David Green
+ */
+public abstract class AbstractCatalogSource {
+
+ private Policy policy = Policy.defaultPolicy();
+
+ /**
+ * an identifier that can be used to determine the origin of the source, typically for logging purposes.
+ */
+ public abstract Object getId();
+
+ /**
+ * get a resource by an URL relative to the root of the source.
+ *
+ * @param relativeUrl
+ * the relative resource name
+ * @return an URL to the resource, or null if it is known that the resource does not exist.
+ */
+ public abstract URL getResource(String resourceName);
+
+ public Policy getPolicy() {
+ return policy;
+ }
+
+ public void setPolicy(Policy policy) {
+ this.policy = policy;
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/AbstractDiscoveryStrategy.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/AbstractDiscoveryStrategy.java
new file mode 100644
index 000000000..6ea71cd57
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/AbstractDiscoveryStrategy.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.discovery;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.equinox.internal.p2.discovery.model.CatalogCategory;
+import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem;
+import org.eclipse.equinox.internal.p2.discovery.model.Certification;
+import org.eclipse.equinox.internal.p2.discovery.model.Tag;
+
+/**
+ * An abstraction of a strategy for discovering connectors and categories. Strategy design pattern. Note that strategies
+ * are not reusable and must be disposed.
+ *
+ * @author David Green
+ * @author Steffen Pingel
+ */
+public abstract class AbstractDiscoveryStrategy {
+
+ protected List<CatalogCategory> categories;
+
+ protected List<Certification> certifications;
+
+ protected List<CatalogItem> items;
+
+ protected List<Tag> tags;
+
+ public void dispose() {
+ }
+
+ public List<CatalogCategory> getCategories() {
+ return categories;
+ }
+
+ public List<Certification> getCertifications() {
+ return certifications;
+ }
+
+ public List<CatalogItem> getItems() {
+ return items;
+ }
+
+ public List<Tag> getTags() {
+ return tags;
+ }
+
+ /**
+ * Perform discovery and add discovered items to {@link #getCategories() categories} and {@link #getItems()}.
+ */
+ public abstract void performDiscovery(IProgressMonitor monitor) throws CoreException;
+
+ public void setCategories(List<CatalogCategory> categories) {
+ this.categories = categories;
+ }
+
+ public void setCertifications(List<Certification> certifications) {
+ this.certifications = certifications;
+ }
+
+ public void setItems(List<CatalogItem> connectors) {
+ this.items = connectors;
+ }
+
+ public void setTags(List<Tag> itemKinds) {
+ this.tags = itemKinds;
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/Catalog.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/Catalog.java
new file mode 100644
index 000000000..c95dad39c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/Catalog.java
@@ -0,0 +1,334 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.discovery;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IBundleGroup;
+import org.eclipse.core.runtime.IBundleGroupProvider;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.equinox.internal.p2.core.helpers.LogHelper;
+import org.eclipse.equinox.internal.p2.discovery.model.AbstractCatalogItem;
+import org.eclipse.equinox.internal.p2.discovery.model.CatalogCategory;
+import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem;
+import org.eclipse.equinox.internal.p2.discovery.model.Certification;
+import org.eclipse.equinox.internal.p2.discovery.model.FeatureFilter;
+import org.eclipse.equinox.internal.p2.discovery.model.Tag;
+import org.eclipse.osgi.service.resolver.VersionRange;
+import org.eclipse.osgi.util.NLS;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.Version;
+
+/**
+ * A means of discovering connectors.
+ *
+ * @author David Green
+ */
+public class Catalog {
+
+ private List<CatalogItem> items = Collections.emptyList();
+
+ private List<CatalogCategory> categories = Collections.emptyList();
+
+ private List<Certification> certifications = Collections.emptyList();
+
+ private List<CatalogItem> filteredItems = Collections.emptyList();
+
+ private final List<AbstractDiscoveryStrategy> discoveryStrategies = new ArrayList<AbstractDiscoveryStrategy>();
+
+ private List<Tag> tags = Collections.emptyList();
+
+ private Dictionary<Object, Object> environment = System.getProperties();
+
+ private boolean verifyUpdateSiteAvailability = false;
+
+ private Map<String, Version> featureToVersion = null;
+
+ public Catalog() {
+ }
+
+ /**
+ * get the discovery strategies to use.
+ */
+ public List<AbstractDiscoveryStrategy> getDiscoveryStrategies() {
+ return discoveryStrategies;
+ }
+
+ /**
+ * Initialize this by performing discovery. Discovery may take a long time as it involves network access.
+ * PRECONDITION: must add at least one {@link #getDiscoveryStrategies() discovery strategy} prior to calling.
+ *
+ * @return
+ */
+ public IStatus performDiscovery(IProgressMonitor monitor) {
+ MultiStatus status = new MultiStatus(DiscoveryCore.ID_PLUGIN, 0,
+ Messages.Catalog_Failed_to_discovery_all_Error, null);
+ if (discoveryStrategies.isEmpty()) {
+ throw new IllegalStateException();
+ }
+ items = new ArrayList<CatalogItem>();
+ filteredItems = new ArrayList<CatalogItem>();
+ categories = new ArrayList<CatalogCategory>();
+ certifications = new ArrayList<Certification>();
+
+ final int totalTicks = 100000;
+ final int discoveryTicks = totalTicks - (totalTicks / 10);
+ monitor.beginTask(Messages.Catalog_task_discovering_connectors, totalTicks);
+ try {
+ for (AbstractDiscoveryStrategy discoveryStrategy : discoveryStrategies) {
+ discoveryStrategy.setCategories(categories);
+ discoveryStrategy.setItems(items);
+ discoveryStrategy.setCertifications(certifications);
+ discoveryStrategy.setTags(tags);
+ try {
+ discoveryStrategy.performDiscovery(new SubProgressMonitor(monitor, discoveryTicks
+ / discoveryStrategies.size()));
+ } catch (CoreException e) {
+ status.add(new Status(IStatus.ERROR, DiscoveryCore.ID_PLUGIN, NLS.bind(
+ Messages.Catalog_Strategy_failed_Error, discoveryStrategy.getClass().getSimpleName()), e));
+ }
+ }
+
+ filterDescriptors();
+ connectCategoriesToDescriptors();
+ connectCertificationsToDescriptors();
+ } finally {
+ monitor.done();
+ }
+ return status;
+ }
+
+ /**
+ * get the top-level categories
+ *
+ * @return the categories, or an empty list if there are none.
+ */
+ public List<CatalogCategory> getCategories() {
+ return categories;
+ }
+
+ /**
+ * get the connectors that were discovered and not filtered
+ *
+ * @return the connectors, or an empty list if there are none.
+ */
+ public List<CatalogItem> getItems() {
+ return items;
+ }
+
+ public List<Tag> getTags() {
+ return tags;
+ }
+
+ /**
+ * get the connectors that were discovered but filtered
+ *
+ * @return the filtered connectors, or an empty list if there were none.
+ */
+ public List<CatalogItem> getFilteredItems() {
+ return filteredItems;
+ }
+
+ /**
+ * The environment used to resolve {@link AbstractCatalogItem#getPlatformFilter() platform filters}. Defaults to the
+ * current environment.
+ */
+ public Dictionary<Object, Object> getEnvironment() {
+ return environment;
+ }
+
+ /**
+ * The environment used to resolve {@link AbstractCatalogItem#getPlatformFilter() platform filters}. Defaults to the
+ * current environment.
+ */
+ public void setEnvironment(Dictionary<Object, Object> environment) {
+ if (environment == null) {
+ throw new IllegalArgumentException();
+ }
+ this.environment = environment;
+ }
+
+ /**
+ * indicate if update site availability should be verified. The default is false.
+ *
+ * @see CatalogItem#getAvailable()
+ * @see #verifySiteAvailability(IProgressMonitor)
+ */
+ public boolean isVerifyUpdateSiteAvailability() {
+ return verifyUpdateSiteAvailability;
+ }
+
+ /**
+ * indicate if update site availability should be verified. The default is false.
+ *
+ * @see CatalogItem#getAvailable()
+ * @see #verifySiteAvailability(IProgressMonitor)
+ */
+ public void setVerifyUpdateSiteAvailability(boolean verifyUpdateSiteAvailability) {
+ this.verifyUpdateSiteAvailability = verifyUpdateSiteAvailability;
+ }
+
+ /**
+ * <em>not for general use: public for testing purposes only</em> A map of installed features to their version. Used
+ * to resolve {@link AbstractCatalogItem#getFeatureFilter() feature filters}.
+ */
+ public Map<String, Version> getFeatureToVersion() {
+ return featureToVersion;
+ }
+
+ /**
+ * <em>not for general use: public for testing purposes only</em> A map of installed features to their version. Used
+ * to resolve {@link AbstractCatalogItem#getFeatureFilter() feature filters}.
+ */
+ public void setFeatureToVersion(Map<String, Version> featureToVersion) {
+ this.featureToVersion = featureToVersion;
+ }
+
+ private void connectCertificationsToDescriptors() {
+ Map<String, Certification> idToCertification = new HashMap<String, Certification>();
+ for (Certification certification : certifications) {
+ Certification previous = idToCertification.put(certification.getId(), certification);
+ if (previous != null) {
+ LogHelper.log(new Status(IStatus.ERROR, DiscoveryCore.ID_PLUGIN, NLS.bind(
+ "Duplicate certification id ''{0}'': declaring sources: {1}, {2}", //$NON-NLS-1$
+ new Object[] { certification.getId(), certification.getSource().getId(),
+ previous.getSource().getId() })));
+ }
+ }
+
+ for (CatalogItem connector : items) {
+ if (connector.getCertificationId() != null) {
+ Certification certification = idToCertification.get(connector.getCertificationId());
+ if (certification != null) {
+ connector.setCertification(certification);
+ } else {
+ LogHelper.log(new Status(IStatus.ERROR, DiscoveryCore.ID_PLUGIN, NLS.bind(
+ "Unknown category ''{0}'' referenced by connector ''{1}'' declared in {2}", new Object[] { //$NON-NLS-1$
+ connector.getCertificationId(), connector.getId(), connector.getSource().getId() })));
+ }
+ }
+ }
+ }
+
+ private void connectCategoriesToDescriptors() {
+ Map<String, CatalogCategory> idToCategory = new HashMap<String, CatalogCategory>();
+ for (CatalogCategory category : categories) {
+ CatalogCategory previous = idToCategory.put(category.getId(), category);
+ if (previous != null) {
+ LogHelper.log(new Status(IStatus.ERROR, DiscoveryCore.ID_PLUGIN, NLS.bind(
+ Messages.Catalog_duplicate_category_id, new Object[] { category.getId(),
+ category.getSource().getId(), previous.getSource().getId() })));
+ }
+ }
+
+ for (CatalogItem connector : items) {
+ CatalogCategory category = idToCategory.get(connector.getCategoryId());
+ if (category != null) {
+ category.getItems().add(connector);
+ connector.setCategory(category);
+ } else {
+ LogHelper.log(new Status(IStatus.ERROR, DiscoveryCore.ID_PLUGIN, NLS.bind(
+ Messages.Catalog_bundle_references_unknown_category, new Object[] { connector.getCategoryId(),
+ connector.getId(), connector.getSource().getId() })));
+ }
+ }
+ }
+
+ /**
+ * eliminate any connectors whose {@link AbstractCatalogItem#getPlatformFilter() platform filters} don't match
+ */
+ private void filterDescriptors() {
+ for (CatalogItem connector : new ArrayList<CatalogItem>(items)) {
+ if (connector.getPlatformFilter() != null && connector.getPlatformFilter().trim().length() > 0) {
+ boolean match = false;
+ try {
+ Filter filter = FrameworkUtil.createFilter(connector.getPlatformFilter());
+ match = filter.match(environment);
+ } catch (InvalidSyntaxException e) {
+ LogHelper.log(new Status(IStatus.ERROR, DiscoveryCore.ID_PLUGIN, NLS.bind(
+ Messages.Catalog_illegal_filter_syntax, new Object[] { connector.getPlatformFilter(),
+ connector.getId(), connector.getSource().getId() })));
+ }
+ if (!match) {
+ items.remove(connector);
+ filteredItems.add(connector);
+ }
+ }
+ for (FeatureFilter featureFilter : connector.getFeatureFilter()) {
+ if (featureToVersion == null) {
+ featureToVersion = computeFeatureToVersion();
+ }
+ boolean match = false;
+ Version version = featureToVersion.get(featureFilter.getFeatureId());
+ if (version != null) {
+ VersionRange versionRange = new VersionRange(featureFilter.getVersion());
+ if (versionRange.isIncluded(version)) {
+ match = true;
+ }
+ }
+ if (!match) {
+ items.remove(connector);
+ filteredItems.add(connector);
+ break;
+ }
+ }
+ }
+ }
+
+ private Map<String, Version> computeFeatureToVersion() {
+ Map<String, Version> featureToVersion = new HashMap<String, Version>();
+ for (IBundleGroupProvider provider : Platform.getBundleGroupProviders()) {
+ for (IBundleGroup bundleGroup : provider.getBundleGroups()) {
+ for (Bundle bundle : bundleGroup.getBundles()) {
+ featureToVersion.put(bundle.getSymbolicName(), bundle.getVersion());
+ }
+ }
+ }
+ return featureToVersion;
+ }
+
+ public void dispose() {
+ for (final AbstractDiscoveryStrategy strategy : discoveryStrategies) {
+ SafeRunner.run(new ISafeRunnable() {
+
+ public void run() throws Exception {
+ strategy.dispose();
+ }
+
+ public void handleException(Throwable exception) {
+ LogHelper.log(new Status(IStatus.ERROR, DiscoveryCore.ID_PLUGIN,
+ Messages.Catalog_exception_disposing + strategy.getClass().getName(), exception));
+ }
+ });
+ }
+ }
+
+ public void setTags(List<Tag> tags) {
+ this.tags = new ArrayList<Tag>(tags);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/DiscoveryCore.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/DiscoveryCore.java
new file mode 100644
index 000000000..bcc6db461
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/DiscoveryCore.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.discovery;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.eclipse.core.runtime.IProduct;
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * @author David Green
+ */
+public abstract class DiscoveryCore {
+
+ public static final String ID_PLUGIN = "org.eclipse.equinox.p2.discovery"; //$NON-NLS-1$
+
+ private DiscoveryCore() {
+ }
+
+ public static Dictionary<Object, Object> createEnvironment() {
+ Dictionary<Object, Object> environment = new Hashtable<Object, Object>(System.getProperties());
+ // add the installed Mylyn version to the environment so that we can
+ // have
+ // connectors that are filtered based on version of Mylyn
+ IProduct product = Platform.getProduct();
+ if (product != null) {
+ environment.put("org.eclipse.product.id", product.getId()); //$NON-NLS-1$
+ }
+ return environment;
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/Messages.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/Messages.java
new file mode 100644
index 000000000..a6bbe4fa4
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/Messages.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.equinox.internal.p2.discovery;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @author David Green
+ */
+class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.equinox.internal.p2.discovery.messages"; //$NON-NLS-1$
+
+ public static String Catalog_bundle_references_unknown_category;
+
+ public static String Catalog_duplicate_category_id;
+
+ public static String Catalog_exception_disposing;
+
+ public static String Catalog_Failed_to_discovery_all_Error;
+
+ public static String Catalog_illegal_filter_syntax;
+
+ public static String Catalog_Strategy_failed_Error;
+
+ public static String Catalog_task_discovering_connectors;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/Policy.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/Policy.java
new file mode 100644
index 000000000..63b3d64b1
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/Policy.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.equinox.internal.p2.discovery;
+
+/**
+ * A policy defines what is permitted.
+ *
+ * @author David Green
+ */
+public class Policy {
+
+ /**
+ * Define system property <code>org.eclipse.mylyn.internal.discovery.core.model.Policy.permissive=true</code> to
+ * allow for categories to be permitted by anyone. For testing purposes.
+ */
+ private static final boolean PERMISSIVE = Boolean.getBoolean(Policy.class.getName() + ".permissive"); //$NON-NLS-1$
+
+ private static final Policy DEFAULT = new Policy(false);
+
+ private final boolean permitCategories;
+
+ public Policy(boolean permitCategories) {
+ this.permitCategories = permitCategories;
+ }
+
+ public boolean isPermitCategories() {
+ return permitCategories || PERMISSIVE;
+ }
+
+ public static Policy defaultPolicy() {
+ return DEFAULT;
+ }
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/messages.properties b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/messages.properties
new file mode 100644
index 000000000..c0f5d077a
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/messages.properties
@@ -0,0 +1,17 @@
+###############################################################################
+# Copyright (c) 2009 Tasktop Technologies 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:
+# Tasktop Technologies - initial API and implementation
+###############################################################################
+Catalog_bundle_references_unknown_category=Unknown category ''{0}'' referenced by connector ''{1}'' declared in {2}
+Catalog_duplicate_category_id=Duplicate category id ''{0}'': declaring sources: {1}, {2}
+Catalog_exception_disposing=exception disposing
+Catalog_Failed_to_discovery_all_Error=Failed to discover all connectors.
+Catalog_illegal_filter_syntax=Illegal filter syntax ''{0}'' in connector ''{1}'' declared in {2}
+Catalog_Strategy_failed_Error={0} failed with an error
+Catalog_task_discovering_connectors=Retrieving listing
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/AbstractCatalogItem.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/AbstractCatalogItem.java
new file mode 100644
index 000000000..f70a962ad
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/AbstractCatalogItem.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.equinox.internal.p2.discovery.model;
+
+/**
+ * @author Steffen Pingel
+ */
+public class AbstractCatalogItem {
+
+ private Object data;
+
+ public Object getData() {
+ return data;
+ }
+
+ public void setData(Object data) {
+ this.data = data;
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/CatalogCategory.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/CatalogCategory.java
new file mode 100644
index 000000000..cf49711ea
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/CatalogCategory.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.discovery.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.equinox.internal.p2.discovery.AbstractCatalogSource;
+
+/**
+ * @author David Green
+ */
+public class CatalogCategory extends AbstractCatalogItem {
+
+ private AbstractCatalogSource source;
+
+ private final List<CatalogItem> items = new ArrayList<CatalogItem>();
+
+ protected String id;
+
+ protected String name;
+
+ protected String description;
+
+ protected String relevance;
+
+ protected Icon icon;
+
+ protected Overview overview;
+
+ protected java.util.List<Group> group = new java.util.ArrayList<Group>();
+
+ public List<CatalogItem> getItems() {
+ return items;
+ }
+
+ public AbstractCatalogSource getSource() {
+ return source;
+ }
+
+ public void setSource(AbstractCatalogSource source) {
+ this.source = source;
+ }
+
+ /**
+ * an id that uniquely identifies the category
+ */
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * the name of the category, as it is displayed in the ui.
+ */
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * A description of the category
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * A relevance, which is a number from 0 to 100. Categories with higher relevance are displayed with preference in
+ * the UI.
+ */
+ public String getRelevance() {
+ return relevance;
+ }
+
+ public void setRelevance(String relevance) {
+ this.relevance = relevance;
+ }
+
+ public Icon getIcon() {
+ return icon;
+ }
+
+ public void setIcon(Icon icon) {
+ this.icon = icon;
+ }
+
+ public Overview getOverview() {
+ return overview;
+ }
+
+ public void setOverview(Overview overview) {
+ this.overview = overview;
+ }
+
+ public java.util.List<Group> getGroup() {
+ return group;
+ }
+
+ public void setGroup(java.util.List<Group> group) {
+ this.group = group;
+ }
+
+ public void validate() throws ValidationException {
+ if (id == null || id.length() == 0) {
+ throw new ValidationException(Messages.CatalogCategory_must_specify_CatalogCategory_id);
+ }
+ if (name == null || name.length() == 0) {
+ throw new ValidationException(Messages.CatalogCategory_must_specify_CatalogCategory_name);
+ }
+ if (description == null || description.length() == 0) {
+ throw new ValidationException("Must specify connectorCategory/@description"); //$NON-NLS-1$
+ }
+ if (icon != null) {
+ icon.validate();
+ }
+ if (relevance != null) {
+ try {
+ int r = Integer.parseInt(relevance, 10);
+ if (r < 0 || r > 100) {
+ throw new NumberFormatException();
+ }
+ } catch (NumberFormatException e) {
+ throw new ValidationException(Messages.CatalogCategory_CatalogCategory_relevance_invalid);
+ }
+ }
+ if (overview != null) {
+ overview.validate();
+ }
+ for (Group groupItem : group) {
+ groupItem.validate();
+ }
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/CatalogItem.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/CatalogItem.java
new file mode 100644
index 000000000..a3738614e
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/CatalogItem.java
@@ -0,0 +1,369 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.discovery.model;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.net.MalformedURLException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.equinox.internal.p2.discovery.AbstractCatalogSource;
+
+/**
+ * @author David Green
+ */
+public class CatalogItem extends AbstractCatalogItem {
+
+ private AbstractCatalogSource source;
+
+ private CatalogCategory category;
+
+ private boolean selected;
+
+ private Boolean available;
+
+ private Certification certification;
+
+ private final PropertyChangeSupport changeSupport;
+
+ private boolean installed;
+
+ private Set<Tag> tags;
+
+ protected String name;
+
+ protected String provider;
+
+ protected String license;
+
+ protected String description;
+
+ protected String siteUrl;
+
+ protected String id;
+
+ protected String categoryId;
+
+ protected String platformFilter;
+
+ protected String groupId;
+
+ protected java.util.List<FeatureFilter> featureFilter = new java.util.ArrayList<FeatureFilter>();
+
+ protected java.util.List<String> installableUnits = new java.util.ArrayList<String>();
+
+ protected Icon icon;
+
+ protected Overview overview;
+
+ protected String certificationId;
+
+ public CatalogItem() {
+ changeSupport = new PropertyChangeSupport(this);
+ }
+
+ public CatalogCategory getCategory() {
+ return category;
+ }
+
+ public void setCategory(CatalogCategory category) {
+ this.category = category;
+ }
+
+ public AbstractCatalogSource getSource() {
+ return source;
+ }
+
+ public void setSource(AbstractCatalogSource source) {
+ this.source = source;
+ }
+
+ public Certification getCertification() {
+ return certification;
+ }
+
+ public void setCertification(Certification certification) {
+ this.certification = certification;
+ }
+
+ /**
+ * support selection
+ *
+ * @return true if the item is selected, otherwise false
+ */
+ public boolean isSelected() {
+ return selected;
+ }
+
+ /**
+ * support selection
+ *
+ * @param selected
+ * true if the item is selected, otherwise false
+ */
+ public void setSelected(boolean selected) {
+ this.selected = selected;
+ }
+
+ /**
+ * indicate if this connector is available
+ *
+ * @return true if available, false if not, or null if availability is unknown
+ */
+ public Boolean getAvailable() {
+ return available;
+ }
+
+ /**
+ * indicate if this connector is available
+ *
+ * @param available
+ * true if available, false if not, or null if availability is unknown
+ */
+ public void setAvailable(Boolean available) {
+ if (available != this.available || (available != null && !available.equals(this.available))) {
+ Boolean previous = this.available;
+ this.available = available;
+ changeSupport.firePropertyChange("available", previous, this.available); //$NON-NLS-1$
+ }
+ }
+
+ public void addPropertyChangeListener(PropertyChangeListener listener) {
+ changeSupport.addPropertyChangeListener(listener);
+ }
+
+ public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+ changeSupport.addPropertyChangeListener(propertyName, listener);
+ }
+
+ public void removePropertyChangeListener(PropertyChangeListener listener) {
+ changeSupport.removePropertyChangeListener(listener);
+ }
+
+ public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+ changeSupport.removePropertyChangeListener(propertyName, listener);
+ }
+
+ /**
+ * the name of the connector including the name of the organization that produces the repository if appropriate, for
+ * example 'Mozilla Bugzilla'.
+ */
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * The name of the organization that supplies the connector.
+ */
+ public String getProvider() {
+ return provider;
+ }
+
+ public void setProvider(String provider) {
+ this.provider = provider;
+ }
+
+ /**
+ * The short name of the license, for example 'EPL 1.0', 'GPL 2.0', or 'Commercial'.
+ */
+ public String getLicense() {
+ return license;
+ }
+
+ public void setLicense(String license) {
+ this.license = license;
+ }
+
+ /**
+ * A description of the connector. Plug-ins should provide a description, especially if the description is not
+ * self-evident from the @name and
+ *
+ * @organization.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * The URL of the update site containing the connector.
+ */
+ public String getSiteUrl() {
+ return siteUrl;
+ }
+
+ public void setSiteUrl(String siteUrl) {
+ this.siteUrl = siteUrl;
+ }
+
+ /**
+ * The id of the feature that installs this connector
+ */
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * the id of the connectorCategory in which this connector belongs
+ */
+ public String getCategoryId() {
+ return categoryId;
+ }
+
+ public void setCategoryId(String categoryId) {
+ this.categoryId = categoryId;
+ }
+
+ public String getCertificationId() {
+ return certificationId;
+ }
+
+ public void setCertificationId(String certificationId) {
+ this.certificationId = certificationId;
+ }
+
+ /**
+ * E.g., "(& (osgi.os=macosx) (osgi.ws=carbon))"
+ */
+ public String getPlatformFilter() {
+ return platformFilter;
+ }
+
+ public void setPlatformFilter(String platformFilter) {
+ this.platformFilter = platformFilter;
+ }
+
+ /**
+ * The id of the connectorCategory group. See group/@id for more details.
+ */
+ public String getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(String groupId) {
+ this.groupId = groupId;
+ }
+
+ public java.util.List<FeatureFilter> getFeatureFilter() {
+ return featureFilter;
+ }
+
+ public void setFeatureFilter(java.util.List<FeatureFilter> featureFilter) {
+ this.featureFilter = featureFilter;
+ }
+
+ public Icon getIcon() {
+ return icon;
+ }
+
+ public void setIcon(Icon icon) {
+ this.icon = icon;
+ }
+
+ public Overview getOverview() {
+ return overview;
+ }
+
+ public void setOverview(Overview overview) {
+ this.overview = overview;
+ }
+
+ public void validate() throws ValidationException {
+ if (name == null || name.length() == 0) {
+ throw new ValidationException(Messages.CatalogItem_must_specify_CatalogItem_name);
+ }
+ if (provider == null || provider.length() == 0) {
+ throw new ValidationException(Messages.CatalogItem_must_specify_CatalogItem_provider);
+ }
+ if (license == null || license.length() == 0) {
+ throw new ValidationException(Messages.CatalogItem_must_specify_CatalogItem_license);
+ }
+ if (siteUrl == null || siteUrl.length() == 0) {
+ throw new ValidationException(Messages.CatalogItem_must_specify_CatalogItem_siteUrl);
+ }
+ try {
+ new java.net.URL(siteUrl);
+ } catch (MalformedURLException e) {
+ throw new ValidationException(Messages.CatalogItem_invalid_CatalogItem_siteUrl);
+ }
+ if (id == null || id.length() == 0) {
+ throw new ValidationException(Messages.CatalogItem_must_specify_CatalogItem_id);
+ }
+ if (categoryId == null || categoryId.length() == 0) {
+ throw new ValidationException(Messages.CatalogItem_must_specify_CatalogItem_categoryId);
+ }
+ for (FeatureFilter featureFilterItem : featureFilter) {
+ featureFilterItem.validate();
+ }
+ if (icon != null) {
+ icon.validate();
+ }
+ if (overview != null) {
+ overview.validate();
+ }
+ }
+
+ public java.util.List<String> getInstallableUnits() {
+ return installableUnits;
+ }
+
+ public void setInstallableUnits(java.util.List<String> installableUnits) {
+ this.installableUnits = installableUnits;
+ }
+
+ public boolean isInstalled() {
+ return installed;
+ }
+
+ public void setInstalled(boolean installed) {
+ this.installed = installed;
+ }
+
+ public Set<Tag> getTags() {
+ if (tags == null) {
+ return Collections.emptySet();
+ } else {
+ return Collections.unmodifiableSet(tags);
+ }
+ }
+
+ public boolean hasTag(Tag tag) {
+ return tags == null ? false : tags.contains(tag);
+ }
+
+ public void addTag(Tag tag) {
+ if (tags == null) {
+ tags = new HashSet<Tag>();
+ }
+ tags.add(tag);
+ }
+
+ public boolean removeTag(Tag tag) {
+ if (tags == null) {
+ return false;
+ }
+ return tags.remove(tag);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Certification.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Certification.java
new file mode 100644
index 000000000..4122aa824
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Certification.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.equinox.internal.p2.discovery.model;
+
+import org.eclipse.equinox.internal.p2.discovery.AbstractCatalogSource;
+
+/**
+ * @author Steffen Pingel
+ */
+public class Certification {
+
+ private AbstractCatalogSource source;
+
+ protected String id;
+
+ protected String name;
+
+ protected String description;
+
+ protected Icon icon;
+
+ protected String url;
+
+ public AbstractCatalogSource getSource() {
+ return source;
+ }
+
+ public void setSource(AbstractCatalogSource source) {
+ this.source = source;
+ }
+
+ /**
+ * an id that uniquely identifies the category
+ */
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * the name of the category, as it is displayed in the ui.
+ */
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * A description of the category
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public Icon getIcon() {
+ return icon;
+ }
+
+ public void setIcon(Icon icon) {
+ this.icon = icon;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public void validate() throws ValidationException {
+ if (id == null || id.length() == 0) {
+ throw new ValidationException(Messages.CatalogCategory_must_specify_CatalogCategory_id);
+ }
+ if (name == null || name.length() == 0) {
+ throw new ValidationException(Messages.CatalogCategory_must_specify_CatalogCategory_name);
+ }
+ if (icon != null) {
+ icon.validate();
+ }
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/FeatureFilter.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/FeatureFilter.java
new file mode 100644
index 000000000..4e9d50b05
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/FeatureFilter.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.discovery.model;
+
+/**
+ * A means of specifying that a feature must be present in order for the connectorDescriptor to be presented to the
+ * user.
+ *
+ * @author David Green
+ */
+public class FeatureFilter {
+
+ protected String featureId;
+
+ protected String version;
+
+ protected CatalogItem item;
+
+ public FeatureFilter() {
+ }
+
+ /**
+ * The id of the feature to test
+ */
+ public String getFeatureId() {
+ return featureId;
+ }
+
+ public void setFeatureId(String featureId) {
+ this.featureId = featureId;
+ }
+
+ /**
+ * A version specifier, specified in the same manner as version dependencies are specified in an OSGi manifest. For
+ * example: "[3.0,4.0)"
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public CatalogItem getItem() {
+ return item;
+ }
+
+ public void setItem(CatalogItem catalogItem) {
+ this.item = catalogItem;
+ }
+
+ public void validate() throws ValidationException {
+ if (featureId == null || featureId.length() == 0) {
+ throw new ValidationException(Messages.FeatureFilter_must_specify_featureFilter_featureId);
+ }
+ if (version == null || version.length() == 0) {
+ throw new ValidationException(Messages.FeatureFilter_must_specify_featureFilter_version);
+ }
+ }
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Group.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Group.java
new file mode 100644
index 000000000..d59aa8e38
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Group.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Task top Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.discovery.model;
+
+/**
+ * groups provide a way to anchor connectors in a grouping with other like entries.
+ *
+ * @author David Green
+ */
+public class Group {
+
+ protected String id;
+
+ protected CatalogCategory category;
+
+ public Group() {
+ }
+
+ /**
+ * An identifier that identifies the group. Must be unique for a particular connectorCategory.
+ */
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public CatalogCategory getCategory() {
+ return category;
+ }
+
+ public void setCategory(CatalogCategory category) {
+ this.category = category;
+ }
+
+ public void validate() throws ValidationException {
+ if (id == null || id.length() == 0) {
+ throw new ValidationException(Messages.Group_must_specify_group_id);
+ }
+ }
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Icon.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Icon.java
new file mode 100644
index 000000000..dc3edb6ff
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Icon.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.discovery.model;
+
+/**
+ * @author David Green
+ */
+public class Icon {
+
+ protected String image16;
+
+ protected String image32;
+
+ protected String image48;
+
+ protected String image64;
+
+ protected String image128;
+
+ public Icon() {
+ }
+
+ public String getImage16() {
+ return image16;
+ }
+
+ public void setImage16(String image16) {
+ this.image16 = image16;
+ }
+
+ public String getImage32() {
+ return image32;
+ }
+
+ public void setImage32(String image32) {
+ this.image32 = image32;
+ }
+
+ public String getImage48() {
+ return image48;
+ }
+
+ public void setImage48(String image48) {
+ this.image48 = image48;
+ }
+
+ public String getImage64() {
+ return image64;
+ }
+
+ public void setImage64(String image64) {
+ this.image64 = image64;
+ }
+
+ public String getImage128() {
+ return image128;
+ }
+
+ public void setImage128(String image128) {
+ this.image128 = image128;
+ }
+
+ public void validate() throws ValidationException {
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Messages.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Messages.java
new file mode 100644
index 000000000..3446f4e04
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Messages.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.equinox.internal.p2.discovery.model;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @author David Green
+ */
+class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.equinox.internal.p2.discovery.model.messages"; //$NON-NLS-1$
+
+ public static String CatalogCategory_CatalogCategory_relevance_invalid;
+
+ public static String CatalogCategory_must_specify_CatalogCategory_id;
+
+ public static String CatalogCategory_must_specify_CatalogCategory_name;
+
+ public static String CatalogItem_invalid_CatalogItem_siteUrl;
+
+ public static String CatalogItem_must_specify_CatalogItem_categoryId;
+
+ public static String CatalogItem_must_specify_CatalogItem_id;
+
+ public static String CatalogItem_must_specify_CatalogItem_license;
+
+ public static String CatalogItem_must_specify_CatalogItem_name;
+
+ public static String CatalogItem_must_specify_CatalogItem_provider;
+
+ public static String CatalogItem_must_specify_CatalogItem_siteUrl;
+
+ public static String FeatureFilter_must_specify_featureFilter_featureId;
+
+ public static String FeatureFilter_must_specify_featureFilter_version;
+
+ public static String Group_must_specify_group_id;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Overview.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Overview.java
new file mode 100644
index 000000000..f1ab32c04
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Overview.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.discovery.model;
+
+/**
+ * @author David Green
+ */
+public class Overview {
+
+ protected String summary;
+
+ protected String url;
+
+ protected String screenshot;
+
+ protected CatalogItem item;
+
+ protected CatalogCategory category;
+
+ public Overview() {
+ }
+
+ /**
+ * A description providing detailed information about the item. Newlines can be used to format the text into
+ * multiple paragraphs if necessary. Text must fit into an area 320x240, otherwise it will be truncated in the UI.
+ * More lengthy descriptions can be provided on a web page if required, see @url.
+ */
+ public String getSummary() {
+ return summary;
+ }
+
+ public void setSummary(String summary) {
+ this.summary = summary;
+ }
+
+ /**
+ * An URL that points to a web page with more information relevant to the connector or category.
+ */
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ /**
+ * 320x240 PNG, JPEG or GIF
+ */
+ public String getScreenshot() {
+ return screenshot;
+ }
+
+ public void setScreenshot(String screenshot) {
+ this.screenshot = screenshot;
+ }
+
+ public CatalogItem getItem() {
+ return item;
+ }
+
+ public void setItem(CatalogItem item) {
+ this.item = item;
+ }
+
+ public CatalogCategory getCategory() {
+ return category;
+ }
+
+ public void setCategory(CatalogCategory category) {
+ this.category = category;
+ }
+
+ public void validate() throws ValidationException {
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Tag.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Tag.java
new file mode 100644
index 000000000..f4f1f8bc2
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/Tag.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.equinox.internal.p2.discovery.model;
+
+/**
+ * Provides means to tag items in the catalog.
+ *
+ * @author David Green
+ * @author Steffen Pingel
+ */
+public class Tag extends AbstractCatalogItem {
+
+ private final Object classifier;
+
+ private final String value;
+
+ private final String label;
+
+ public Tag(String value, String label) {
+ this(null, value, label);
+ }
+
+ public Tag(Object tagClassifier, String value, String label) {
+ this.classifier = tagClassifier;
+ this.value = value;
+ this.label = label;
+ }
+
+ /**
+ * the classifier, which places the tag in a logical category
+ *
+ * @return the classifier or null if this tag is not in any category
+ */
+ public Object getTagClassifier() {
+ return classifier;
+ }
+
+ /**
+ * Returns the value of the tag, not intended for display.
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Returns a short user-visible value that is used by the user to identify the tag.
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ @Override
+ public String toString() {
+ return "Tag [classifier=" + classifier + ", value=" + value + ", label=" + label + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+
+ @Override
+ public int hashCode() {
+ // we don't include the label here
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((classifier == null) ? 0 : classifier.hashCode());
+ result = prime * result + ((value == null) ? 0 : value.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ // we don't consider the label when comparing equality
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Tag other = (Tag) obj;
+ if (classifier == null) {
+ if (other.classifier != null) {
+ return false;
+ }
+ } else if (!classifier.equals(other.classifier)) {
+ return false;
+ }
+ if (value == null) {
+ if (other.value != null) {
+ return false;
+ }
+ } else if (!value.equals(other.value)) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/ValidationException.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/ValidationException.java
new file mode 100644
index 000000000..189970cae
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/ValidationException.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.discovery.model;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.equinox.internal.p2.discovery.DiscoveryCore;
+
+/**
+ * Indicate that a validation has occurred on the model.
+ *
+ * @author David Green
+ */
+public class ValidationException extends CoreException {
+
+ private static final long serialVersionUID = -7542361242327905294L;
+
+ public ValidationException(String message) {
+ super(new Status(IStatus.ERROR, DiscoveryCore.ID_PLUGIN, message));
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/messages.properties b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/messages.properties
new file mode 100644
index 000000000..8b0f42857
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/model/messages.properties
@@ -0,0 +1,23 @@
+###############################################################################
+# Copyright (c) 2009 Tasktop Technologies 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:
+# Tasktop Technologies - initial API and implementation
+###############################################################################
+CatalogCategory_CatalogCategory_relevance_invalid=connectorCategory/@relevance must be an integer >= 0 and <= 100
+CatalogCategory_must_specify_CatalogCategory_id=Must specify connectorCategory/@id
+CatalogCategory_must_specify_CatalogCategory_name=Must specify connectorCategory/@name
+CatalogItem_invalid_CatalogItem_siteUrl=Invalid connectorDescriptor/@siteUrl
+CatalogItem_must_specify_CatalogItem_categoryId=Must specify connectorDescriptor/@categoryId
+CatalogItem_must_specify_CatalogItem_id=Must specify connectorDescriptor/@id
+CatalogItem_must_specify_CatalogItem_license=Must specify connectorDescriptor/@license
+CatalogItem_must_specify_CatalogItem_name=Must specify connectorDescriptor/@name
+CatalogItem_must_specify_CatalogItem_provider=Must specify connectorDescriptor/@provider
+CatalogItem_must_specify_CatalogItem_siteUrl=Must specify connectorDescriptor/@siteUrl
+FeatureFilter_must_specify_featureFilter_featureId=Must specify featureFilter/@featureId
+FeatureFilter_must_specify_featureFilter_version=Must specify featureFilter/@version
+Group_must_specify_group_id=Must specify group/@id
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/util/CatalogCategoryComparator.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/util/CatalogCategoryComparator.java
new file mode 100644
index 000000000..14055bd39
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/util/CatalogCategoryComparator.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.discovery.util;
+
+import java.util.Comparator;
+
+import org.eclipse.equinox.internal.p2.discovery.model.CatalogCategory;
+
+/**
+ * A comparator that orders categories by relevance and name.
+ *
+ * @author David Green
+ * @author Steffen Pingel
+ */
+public class CatalogCategoryComparator implements Comparator<CatalogCategory> {
+
+ public int compare(CatalogCategory o1, CatalogCategory o2) {
+ if (o1 == o2) {
+ return 0;
+ }
+ String r1 = o1.getRelevance();
+ String r2 = o2.getRelevance();
+ int i = 0;
+ if (r1 != null && r2 != null) {
+ // don't have to worry about format, since they were already validated
+ // note that higher relevance appears first, thus the reverse order of
+ // the comparison.
+ i = new Integer(r2).compareTo(new Integer(r1));
+ } else if (r1 == null && r2 != null) {
+ return 1;
+ } else if (r2 == null && r1 != null) {
+ return -1;
+ }
+ if (i == 0) {
+ i = o1.getName().compareToIgnoreCase(o2.getName());
+ if (i == 0) {
+ i = o1.getId().compareTo(o2.getId());
+ }
+ }
+ return i;
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/util/CatalogItemComparator.java b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/util/CatalogItemComparator.java
new file mode 100644
index 000000000..ffffabe8f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.discovery/src/org/eclipse/equinox/internal/p2/discovery/util/CatalogItemComparator.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.equinox.internal.p2.discovery.util;
+
+import java.util.Comparator;
+
+import org.eclipse.equinox.internal.p2.discovery.model.CatalogCategory;
+import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem;
+import org.eclipse.equinox.internal.p2.discovery.model.Group;
+
+/**
+ * A comparator that orders connectors by group and alphabetically by their name.
+ *
+ * @author David Green
+ */
+public class CatalogItemComparator implements Comparator<CatalogItem> {
+
+ /**
+ * compute the index of the group id
+ *
+ * @param groupId
+ * the group id or null
+ * @return the index, or -1 if not found
+ */
+ private int computeGroupIndex(CatalogCategory category, String groupId) {
+ if (groupId != null) {
+ int index = -1;
+ for (Group group : category.getGroup()) {
+ ++index;
+ if (group.getId().equals(groupId)) {
+ return index;
+ }
+ }
+ }
+ return -1;
+ }
+
+ public int compare(CatalogItem o1, CatalogItem o2) {
+ if (o1.getCategory() != o2.getCategory()) {
+ throw new IllegalArgumentException();
+ }
+ if (o1 == o2) {
+ return 0;
+ }
+ int g1 = computeGroupIndex(o1.getCategory(), o1.getGroupId());
+ int g2 = computeGroupIndex(o2.getCategory(), o2.getGroupId());
+ int i;
+ if (g1 != g2) {
+ if (g1 == -1) {
+ i = 1;
+ } else if (g2 == -1) {
+ i = -1;
+ } else {
+ i = g1 - g2;
+ }
+ } else {
+ i = o1.getName().compareToIgnoreCase(o2.getName());
+ if (i == 0) {
+ i = o1.getId().compareTo(o2.getId());
+ }
+ }
+ return i;
+ }
+
+}

Back to the top