001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM - Initial API and implementation
010: *******************************************************************************/package org.eclipse.pde.internal.build.site;
011:
012: import java.io.*;
013: import java.net.MalformedURLException;
014: import java.net.URL;
015: import java.util.*;
016: import org.eclipse.core.runtime.*;
017: import org.eclipse.osgi.service.resolver.*;
018: import org.eclipse.osgi.util.NLS;
019: import org.eclipse.pde.internal.build.*;
020: import org.eclipse.update.core.*;
021: import org.osgi.framework.Version;
022:
023: /**
024: * This site represent a site at build time. A build time site is made of code
025: * to compile, and a potential installation of eclipse (or derived products)
026: * against which the code must be compiled. Moreover this site provide access to
027: * a pluginRegistry.
028: */
029: public class BuildTimeSite extends Site implements ISite,
030: IPDEBuildConstants, IXMLConstants {
031: private PDEState state;
032: private Properties repositoryVersions; //version for the features
033: private boolean reportResolutionErrors;
034: private Properties platformProperties;
035:
036: //Support for filtering what is added to the state
037: private List rootFeaturesForFilter;
038: private List rootPluginsForFiler;
039: private boolean filter = false;
040:
041: public void setReportResolutionErrors(boolean value) {
042: reportResolutionErrors = value;
043: }
044:
045: public void setPlatformPropeties(Properties platformProperties) {
046: this .platformProperties = platformProperties;
047: }
048:
049: public Properties getFeatureVersions() {
050: if (repositoryVersions == null) {
051: repositoryVersions = new Properties();
052: try {
053: InputStream input = new BufferedInputStream(
054: new FileInputStream(
055: AbstractScriptGenerator
056: .getWorkingDirectory()
057: + '/'
058: + DEFAULT_FEATURE_REPOTAG_FILENAME_DESCRIPTOR));
059: try {
060: repositoryVersions.load(input);
061: } finally {
062: input.close();
063: }
064: } catch (IOException e) {
065: //Ignore
066: }
067: }
068: return repositoryVersions;
069: }
070:
071: public PDEState getRegistry() throws CoreException {
072: if (state == null) {
073: // create the registry according to the site where the code to
074: // compile is, and a existing installation of eclipse
075: BuildTimeSiteContentProvider contentProvider = (BuildTimeSiteContentProvider) getSiteContentProvider();
076:
077: if (contentProvider.getInitialState() != null) {
078: state = new PDEState(contentProvider.getInitialState());
079: return state;
080: }
081:
082: if (AbstractScriptGenerator.isBuildingOSGi()) {
083: if (filter) {
084: state = new FilteringState();
085: ((FilteringState) state)
086: .setFilter(findAllReferencedPlugins());
087: } else {
088: state = new PDEState();
089: }
090: if (platformProperties != null)
091: state.setPlatformProperties(platformProperties);
092: } else {
093: state = new PluginRegistryConverter();
094: }
095: state.addBundles(contentProvider.getPluginPaths());
096:
097: //Once all the elements have been added to the state, the filter is removed to allow for the generated plug-ins to be added
098: if (state instanceof FilteringState) {
099: ((FilteringState) state).setFilter(null);
100: }
101: state.resolveState();
102: BundleDescription[] allBundles = state.getState()
103: .getBundles();
104: BundleDescription[] resolvedBundles = state.getState()
105: .getResolvedBundles();
106: if (allBundles.length == resolvedBundles.length)
107: return state;
108:
109: if (reportResolutionErrors) {
110: MultiStatus errors = new MultiStatus(
111: IPDEBuildConstants.PI_PDEBUILD, 1,
112: Messages.exception_registryResolution, null);
113: BundleDescription[] all = state.getState().getBundles();
114: StateHelper helper = Platform.getPlatformAdmin()
115: .getStateHelper();
116: for (int i = 0; i < all.length; i++) {
117: if (!all[i].isResolved()) {
118: ResolverError[] resolutionErrors = state
119: .getState().getResolverErrors(all[i]);
120: VersionConstraint[] versionErrors = helper
121: .getUnsatisfiedConstraints(all[i]);
122:
123: //ignore problems when they are caused by bundles not being built for the right config
124: if (isConfigError(all[i], resolutionErrors,
125: AbstractScriptGenerator
126: .getConfigInfos()))
127: continue;
128:
129: String errorMessage = "Bundle "
130: + all[i].getSymbolicName()
131: + ":\n"
132: + getResolutionErrorMessage(resolutionErrors);
133: for (int j = 0; j < versionErrors.length; j++) {
134: errorMessage += '\t' + getResolutionFailureMessage(versionErrors[j]) + '\n';
135: }
136: errors.add(new Status(IStatus.WARNING,
137: IPDEBuildConstants.PI_PDEBUILD,
138: IStatus.WARNING, errorMessage, null));
139: }
140: }
141: if (errors.getChildren().length > 0)
142: BundleHelper.getDefault().getLog().log(errors);
143: }
144: }
145: if (!state.getState().isResolved())
146: state.state.resolve(true);
147: return state;
148: }
149:
150: //Return whether the resolution error is caused because we are not building for the proper configurations.
151: private boolean isConfigError(BundleDescription bundle,
152: ResolverError[] errors, List configs) {
153: Dictionary environment = new Hashtable(3);
154: String filterSpec = bundle.getPlatformFilter();
155: if (hasPlatformFilterError(errors) != null) {
156: for (Iterator iter = configs.iterator(); iter.hasNext();) {
157: Config aConfig = (Config) iter.next();
158: environment.put("osgi.os", aConfig.getOs()); //$NON-NLS-1$
159: environment.put("osgi.ws", aConfig.getWs()); //$NON-NLS-1$
160: environment.put("osgi.arch", aConfig.getArch()); //$NON-NLS-1$
161: if (BundleHelper.getDefault().createFilter(filterSpec)
162: .match(environment)) {
163: return false;
164: }
165: }
166: return true;
167: }
168: return false;
169: }
170:
171: //Check if the set of errors contain a platform filter
172: private ResolverError hasPlatformFilterError(ResolverError[] errors) {
173: for (int i = 0; i < errors.length; i++) {
174: if ((errors[i].getType() & ResolverError.PLATFORM_FILTER) != 0)
175: return errors[i];
176: }
177: return null;
178: }
179:
180: private String getResolutionErrorMessage(ResolverError[] errors) {
181: String errorMessage = ""; //$NON-NLS-1$
182: for (int i = 0; i < errors.length; i++) {
183: if ((errors[i].getType() & (ResolverError.SINGLETON_SELECTION
184: | ResolverError.FRAGMENT_CONFLICT
185: | ResolverError.IMPORT_PACKAGE_USES_CONFLICT
186: | ResolverError.REQUIRE_BUNDLE_USES_CONFLICT | ResolverError.MISSING_EXECUTION_ENVIRONMENT)) != 0)
187: errorMessage += '\t' + errors[i].toString() + '\n';
188: }
189: return errorMessage;
190: }
191:
192: public String getResolutionFailureMessage(
193: VersionConstraint unsatisfied) {
194: if (unsatisfied.isResolved())
195: throw new IllegalArgumentException();
196: if (unsatisfied instanceof ImportPackageSpecification)
197: return NLS.bind(Messages.unsatisfied_import,
198: displayVersionConstraint(unsatisfied));
199: if (unsatisfied instanceof BundleSpecification) {
200: if (((BundleSpecification) unsatisfied).isOptional())
201: return NLS.bind(Messages.unsatisfied_optionalBundle,
202: displayVersionConstraint(unsatisfied));
203: return NLS.bind(Messages.unsatisfied_required,
204: displayVersionConstraint(unsatisfied));
205: }
206: return NLS.bind(Messages.unsatisfied_host,
207: displayVersionConstraint(unsatisfied));
208: }
209:
210: private String displayVersionConstraint(VersionConstraint constraint) {
211: VersionRange versionSpec = constraint.getVersionRange();
212: if (versionSpec == null)
213: return constraint.getName();
214: return constraint.getName() + '_' + versionSpec;
215: }
216:
217: public IFeature findFeature(String featureId, String versionId,
218: boolean throwsException) throws CoreException {
219: ISiteFeatureReference[] features = getFeatureReferences();
220: if (GENERIC_VERSION_NUMBER.equals(versionId))
221: versionId = null;
222: for (int i = 0; i < features.length; i++) {
223: IFeature verifiedFeature;
224: try {
225: verifiedFeature = features[i].getFeature(null);
226: } catch (CoreException e) {
227: String message = NLS.bind(
228: Messages.exception_featureParse, features[i]
229: .getURL());
230: throw new CoreException(new Status(IStatus.ERROR,
231: PI_PDEBUILD, EXCEPTION_FEATURE_MISSING,
232: message, null));
233: }
234: if (verifiedFeature.getVersionedIdentifier()
235: .getIdentifier().equals(featureId))
236: if (versionId == null
237: || features[i].getVersionedIdentifier()
238: .getVersion().equals(
239: new PluginVersionIdentifier(
240: versionId)))
241: return features[i].getFeature(null);
242: }
243: int qualifierIdx = -1;
244: if (versionId != null
245: && (((qualifierIdx = versionId
246: .indexOf('.' + IBuildPropertiesConstants.PROPERTY_QUALIFIER)) != -1) || ((qualifierIdx = versionId
247: .indexOf(IBuildPropertiesConstants.PROPERTY_QUALIFIER)) != -1))) {
248: Version versionToMatch = Version.parseVersion(versionId
249: .substring(0, qualifierIdx));
250: for (int i = 0; i < features.length; i++) {
251: Version featureVersion = Version
252: .parseVersion(features[i]
253: .getVersionedIdentifier().getVersion()
254: .toString());
255: if (features[i].getVersionedIdentifier()
256: .getIdentifier().equals(featureId)
257: && featureVersion.getMajor() == versionToMatch
258: .getMajor()
259: && featureVersion.getMinor() == versionToMatch
260: .getMinor()
261: && featureVersion.getMicro() >= versionToMatch
262: .getMicro()
263: && featureVersion.getQualifier().compareTo(
264: versionToMatch.getQualifier()) >= 0)
265: return features[i].getFeature(null);
266: }
267: }
268: if (throwsException) {
269: String message = NLS.bind(
270: Messages.exception_missingFeature, featureId);
271: throw new CoreException(new Status(IStatus.ERROR,
272: PI_PDEBUILD, EXCEPTION_FEATURE_MISSING, message,
273: null));
274: }
275: return null;
276: }
277:
278: public void addFeatureReferenceModel(File featureXML) {
279: URL featureURL;
280: SiteFeatureReferenceModel featureRef;
281: if (featureXML.exists()) {
282: // Here we could not use toURL() on currentFeatureDir, because the
283: // URL has a slash after the colons (file:/c:/foo) whereas the
284: // plugins don't
285: // have it (file:d:/eclipse/plugins) and this causes problems later
286: // to compare URLs... and compute relative paths
287: try {
288: featureURL = new URL(
289: "file:" + featureXML.getAbsolutePath() + '/'); //$NON-NLS-1$
290: featureRef = new SiteFeatureReference();
291: featureRef.setSiteModel(this );
292: featureRef.setURLString(featureURL.toExternalForm());
293: featureRef
294: .setType(BuildTimeFeatureFactory.BUILDTIME_FEATURE_FACTORY_ID);
295: addFeatureReferenceModel(featureRef);
296: } catch (MalformedURLException e) {
297: BundleHelper
298: .getDefault()
299: .getLog()
300: .log(
301: new Status(
302: IStatus.WARNING,
303: PI_PDEBUILD,
304: WARNING_MISSING_SOURCE,
305: NLS
306: .bind(
307: Messages.warning_cannotLocateSource,
308: featureXML
309: .getAbsolutePath()),
310: e));
311: }
312: }
313: }
314:
315: private SortedSet findAllReferencedPlugins() throws CoreException {
316: ArrayList rootFeatures = new ArrayList();
317: SortedSet allPlugins = new TreeSet();
318: for (Iterator iter = rootFeaturesForFilter.iterator(); iter
319: .hasNext();) {
320: IFeature correspondingFeature = findFeature((String) iter
321: .next(), null, true);
322: if (correspondingFeature == null)
323: return null;
324: rootFeatures.add(correspondingFeature);
325: }
326: for (Iterator iter = rootPluginsForFiler.iterator(); iter
327: .hasNext();) {
328: allPlugins.add(new ReachablePlugin((String) iter.next(),
329: ReachablePlugin.WIDEST_RANGE));
330: }
331: int it = 0;
332: while (it < rootFeatures.size()) {
333: IFeature toAnalyse = null;
334: try {
335: toAnalyse = (IFeature) rootFeatures.get(it++);
336: } catch (RuntimeException e) {
337: e.printStackTrace();
338: }
339: IIncludedFeatureReference[] includedRefs = toAnalyse
340: .getIncludedFeatureReferences();
341: for (int i = 0; i < includedRefs.length; i++) {
342: rootFeatures.add(findFeature(includedRefs[i]
343: .getVersionedIdentifier().getIdentifier(),
344: includedRefs[i].getVersionedIdentifier()
345: .getVersion().toString(), true));
346: }
347: IPluginEntry[] entries = toAnalyse.getPluginEntries();
348: for (int i = 0; i < entries.length; i++) {
349: allPlugins.add(new ReachablePlugin(entries[i]));
350: }
351: IImport[] imports = toAnalyse.getImports();
352: for (int i = 0; i < imports.length; i++) {
353: if (((Import) imports[i]).isFeatureImport()) {
354: VersionedIdentifier requiredFeature = imports[i]
355: .getVersionedIdentifier();
356: rootFeatures.add(findFeature(requiredFeature
357: .getIdentifier(), requiredFeature
358: .getVersion().toString(), true));
359: } else {
360: allPlugins.add(new ReachablePlugin(imports[i]));
361: }
362: }
363: }
364: return allPlugins;
365: }
366:
367: public void setFilter(boolean filter) {
368: this .filter = filter;
369: }
370:
371: public void setRootFeaturesForFilter(List rootFeaturesForFilter) {
372: this .rootFeaturesForFilter = rootFeaturesForFilter;
373: }
374:
375: public void setRootPluginsForFiler(List rootPluginsForFiler) {
376: this.rootPluginsForFiler = rootPluginsForFiler;
377: }
378: }
|