1 /*******************************************************************************
2  * Copyright (c) 2009, 2013 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.pde.api.tools.internal.search;
15 
16 import java.util.TreeSet;
17 
18 import org.eclipse.osgi.service.resolver.BundleDescription;
19 import org.eclipse.osgi.service.resolver.ResolverError;
20 import org.eclipse.osgi.service.resolver.VersionConstraint;
21 import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent;
22 import org.eclipse.pde.api.tools.internal.provisional.model.IApiElement;
23 
24 public class SkippedComponent implements IApiElement {
25 	/**
26 	 * the id of of the skipped component
27 	 */
28 	private String componentid;
29 	/**
30 	 * The version of the component
31 	 */
32 	private String version;
33 	/**
34 	 * the set of resolution errors barring the component from being scanned
35 	 */
36 	private ResolverError[] errors = null;
37 
38 	/**
39 	 * Constructor
40 	 *
41 	 * @param componentid
42 	 * @param version
43 	 * @param errors the {@link ResolverError}s, if any, that prevented this
44 	 *            component from being scanned
45 	 */
SkippedComponent(String componentid, String version, ResolverError[] errors)46 	public SkippedComponent(String componentid, String version, ResolverError[] errors) {
47 		this.componentid = componentid;
48 		this.version = version;
49 		this.errors = errors;
50 	}
51 
52 	@Override
equals(Object obj)53 	public boolean equals(Object obj) {
54 		if (obj instanceof SkippedComponent) {
55 			return this.componentid.equals(((SkippedComponent) obj).componentid);
56 		}
57 		return false;
58 	}
59 
60 	@Override
hashCode()61 	public int hashCode() {
62 		return this.componentid.hashCode();
63 	}
64 
65 	/**
66 	 * @return the component id of the skipped component
67 	 */
getComponentId()68 	public String getComponentId() {
69 		return this.componentid;
70 	}
71 
72 	/**
73 	 * @return true if the component was skipped because it appeared in an
74 	 *         exclude list
75 	 */
wasExcluded()76 	public boolean wasExcluded() {
77 		return this.errors == null;
78 	}
79 
80 	/**
81 	 * @return true if the the component had resolution errors
82 	 */
hasResolutionErrors()83 	public boolean hasResolutionErrors() {
84 		return this.errors != null;
85 	}
86 
87 	/**
88 	 * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiElement#getAncestor(int)
89 	 */
90 	@Override
getAncestor(int ancestorType)91 	public IApiElement getAncestor(int ancestorType) {
92 		return null;
93 	}
94 
95 	/**
96 	 * @return the version
97 	 */
getVersion()98 	public String getVersion() {
99 		return this.version;
100 	}
101 
102 	/**
103 	 * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiElement#getApiComponent()
104 	 */
105 	@Override
getApiComponent()106 	public IApiComponent getApiComponent() {
107 		return null;
108 	}
109 
110 	/**
111 	 * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiElement#getName()
112 	 */
113 	@Override
getName()114 	public String getName() {
115 		return this.componentid;
116 	}
117 
118 	/**
119 	 * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiElement#getParent()
120 	 */
121 	@Override
getParent()122 	public IApiElement getParent() {
123 		return null;
124 	}
125 
126 	/**
127 	 * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiElement#getType()
128 	 */
129 	@Override
getType()130 	public int getType() {
131 		return IApiElement.COMPONENT;
132 	}
133 
134 	/**
135 	 * @return the errors
136 	 */
getErrors()137 	public ResolverError[] getErrors() {
138 		return this.errors;
139 	}
140 
141 	/**
142 	 * Resolves the root errors for the given set of errors
143 	 *
144 	 * @param rerrors
145 	 * @param collector
146 	 * @return the resolved leaf set of problem messages
147 	 */
resolveRootErrors(ResolverError[] rerrors)148 	private String[] resolveRootErrors(ResolverError[] rerrors) {
149 		TreeSet<String> collector = new TreeSet<>((o1, o2) -> (o1).compareTo(o2));
150 		ResolverError error = null;
151 		VersionConstraint[] constraints = null;
152 		BundleDescription[] bundle = new BundleDescription[1];
153 		for (ResolverError rerror : rerrors) {
154 			error = rerror;
155 			if (error.getType() != ResolverError.MISSING_REQUIRE_BUNDLE) {
156 				collector.add(error.toString());
157 			}
158 			bundle[0] = error.getBundle();
159 			constraints = bundle[0].getContainingState().getStateHelper().getUnsatisfiedLeaves(bundle);
160 			if (constraints.length == 0) {
161 				collector.add(error.toString());
162 			}
163 			for (VersionConstraint constraint : constraints) {
164 				collector.add(constraint.toString());
165 			}
166 		}
167 		return collector.toArray(new String[collector.size()]);
168 	}
169 
170 	/**
171 	 * @return the formatted details of why the component was skipped
172 	 */
getErrorDetails()173 	public String getErrorDetails() {
174 		if (this.errors != null) {
175 			StringBuilder buffer = new StringBuilder();
176 			String[] problems = resolveRootErrors(this.errors);
177 			for (String problem : problems) {
178 				buffer.append(problem).append("<br/>"); //$NON-NLS-1$
179 			}
180 			return buffer.toString();
181 		}
182 		return SearchMessages.SkippedComponent_component_was_excluded;
183 	}
184 }