001: /*******************************************************************************
002: * Copyright (c) 2004, 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.URL;
014: import java.util.*;
015: import java.util.jar.JarFile;
016: import java.util.zip.ZipEntry;
017: import java.util.zip.ZipFile;
018: import org.eclipse.core.runtime.*;
019: import org.eclipse.osgi.service.pluginconversion.PluginConversionException;
020: import org.eclipse.osgi.service.pluginconversion.PluginConverter;
021: import org.eclipse.osgi.service.resolver.*;
022: import org.eclipse.osgi.util.ManifestElement;
023: import org.eclipse.osgi.util.NLS;
024: import org.eclipse.pde.internal.build.*;
025: import org.osgi.framework.*;
026:
027: // This class provides a higher level API on the state
028: public class PDEState implements IPDEBuildConstants,
029: IBuildPropertiesConstants {
030: private static final String PROFILE_EXTENSION = ".profile"; //$NON-NLS-1$
031: private static final String SYSTEM_PACKAGES = "org.osgi.framework.system.packages"; //$NON-NLS-1$
032:
033: private StateObjectFactory factory;
034: protected State state;
035: private long id;
036: private Properties repositoryVersions;
037: private HashMap bundleClasspaths;
038: private Map patchBundles;
039: private List addedBundle;
040: private List unqualifiedBundles; //All the bundle description objects that have .qualifier in them
041: private Dictionary platformProperties;
042: private List sortedBundles = null;
043: private long lastSortingDate = 0L;
044:
045: private String javaProfile;
046: private String[] javaProfiles;
047:
048: protected long getNextId() {
049: return ++id;
050: }
051:
052: public PDEState(PDEUIStateWrapper initialState) {
053: this ();
054: state = initialState.getState();
055: factory = state.getFactory();
056: id = initialState.getNextId();
057: bundleClasspaths = initialState.getClasspaths();
058: patchBundles = initialState.getPatchData();
059: addedBundle = new ArrayList();
060: unqualifiedBundles = new ArrayList();
061: forceQualifiers();
062: }
063:
064: public PDEState() {
065: factory = Platform.getPlatformAdmin().getFactory();
066: state = factory.createState();
067: state.setResolver(Platform.getPlatformAdmin().getResolver());
068: id = 0;
069: bundleClasspaths = new HashMap();
070: patchBundles = new HashMap();
071: loadPluginTagFile();
072: }
073:
074: public StateObjectFactory getFactory() {
075: return factory;
076: }
077:
078: public boolean addBundleDescription(BundleDescription toAdd) {
079: return state.addBundle(toAdd);
080: }
081:
082: private PluginConverter acquirePluginConverter() throws Exception {
083: return (PluginConverter) BundleHelper.getDefault()
084: .acquireService(PluginConverter.class.getName());
085: }
086:
087: //Add a bundle to the state, updating the version number
088: public boolean addBundle(Dictionary enhancedManifest,
089: File bundleLocation) {
090: updateVersionNumber(enhancedManifest);
091: try {
092: BundleDescription descriptor;
093: descriptor = factory.createBundleDescription(state,
094: enhancedManifest, bundleLocation.getAbsolutePath(),
095: getNextId());
096: bundleClasspaths.put(new Long(descriptor.getBundleId()),
097: getClasspath(enhancedManifest));
098: String patchValue = fillPatchData(enhancedManifest);
099: if (patchValue != null)
100: patchBundles.put(new Long(descriptor.getBundleId()),
101: patchValue);
102: rememberQualifierTagPresence(descriptor);
103: if (addBundleDescription(descriptor) == true
104: && addedBundle != null)
105: addedBundle.add(descriptor);
106: } catch (BundleException e) {
107: IStatus status = new Status(
108: IStatus.WARNING,
109: IPDEBuildConstants.PI_PDEBUILD,
110: EXCEPTION_STATE_PROBLEM,
111: NLS
112: .bind(Messages.exception_stateAddition,
113: enhancedManifest
114: .get(Constants.BUNDLE_NAME)),
115: e);
116: BundleHelper.getDefault().getLog().log(status);
117: return false;
118: }
119: return true;
120: }
121:
122: private void rememberQualifierTagPresence(
123: BundleDescription descriptor) {
124: Properties bundleProperties = null;
125: bundleProperties = (Properties) descriptor.getUserObject();
126: if (bundleProperties == null) {
127: bundleProperties = new Properties();
128: descriptor.setUserObject(bundleProperties);
129: }
130: bundleProperties.setProperty(PROPERTY_QUALIFIER, "marker"); //$NON-NLS-1$
131: }
132:
133: private void mapVersionReplacedBundle(BundleDescription oldBundle,
134: BundleDescription newBundle) {
135: Properties bundleProperties = null;
136: bundleProperties = (Properties) oldBundle.getUserObject();
137: if (bundleProperties == null) {
138: bundleProperties = new Properties();
139: oldBundle.setUserObject(bundleProperties);
140: }
141: bundleProperties.setProperty(PROPERTY_VERSION_REPLACEMENT,
142: String.valueOf(newBundle.getBundleId()));
143: }
144:
145: private String[] getClasspath(Dictionary manifest) {
146: String fullClasspath = (String) manifest
147: .get(Constants.BUNDLE_CLASSPATH);
148: String[] result = new String[0];
149: try {
150: if (fullClasspath != null) {
151: ManifestElement[] classpathEntries;
152: classpathEntries = ManifestElement.parseHeader(
153: Constants.BUNDLE_CLASSPATH, fullClasspath);
154: result = new String[classpathEntries.length];
155: for (int i = 0; i < classpathEntries.length; i++) {
156: result[i] = classpathEntries[i].getValue();
157: }
158: }
159: } catch (BundleException e) {
160: //Ignore
161: }
162: return result;
163: }
164:
165: private String fillPatchData(Dictionary manifest) {
166: if (manifest.get("Eclipse-ExtensibleAPI") != null) { //$NON-NLS-1$
167: return "Eclipse-ExtensibleAPI: true"; //$NON-NLS-1$
168: }
169:
170: if (manifest.get("Eclipse-PatchFragment") != null) { //$NON-NLS-1$
171: return "Eclipse-PatchFragment: true"; //$NON-NLS-1$
172: }
173: return null;
174: }
175:
176: private void loadPluginTagFile() {
177: repositoryVersions = new Properties();
178: try {
179: InputStream input = new BufferedInputStream(
180: new FileInputStream(
181: AbstractScriptGenerator
182: .getWorkingDirectory()
183: + '/'
184: + DEFAULT_PLUGIN_REPOTAG_FILENAME_DESCRIPTOR));
185: try {
186: repositoryVersions.load(input);
187: } finally {
188: input.close();
189: }
190: } catch (IOException e) {
191: //Ignore
192: }
193: }
194:
195: public boolean addBundle(File bundleLocation) {
196: Dictionary manifest;
197: manifest = loadManifest(bundleLocation);
198: if (manifest == null)
199: return false;
200: try {
201: hasQualifier(bundleLocation, manifest);
202: } catch (BundleException e) {
203: //should not happen since we know the header
204: }
205: return addBundle(manifest, bundleLocation);
206: }
207:
208: private void updateVersionNumber(Dictionary manifest) {
209: String newVersion = null;
210: try {
211: String symbolicName = (String) manifest
212: .get(Constants.BUNDLE_SYMBOLICNAME);
213: if (symbolicName == null)
214: return;
215:
216: symbolicName = ManifestElement.parseHeader(
217: Constants.BUNDLE_SYMBOLICNAME, symbolicName)[0]
218: .getValue();
219: newVersion = QualifierReplacer.replaceQualifierInVersion(
220: (String) manifest.get(Constants.BUNDLE_VERSION),
221: symbolicName, (String) manifest
222: .get(PROPERTY_QUALIFIER),
223: repositoryVersions);
224: } catch (BundleException e) {
225: //ignore
226: }
227: if (newVersion != null)
228: manifest.put(Constants.BUNDLE_VERSION, newVersion);
229: }
230:
231: /**
232: * @param bundleLocation
233: * @param manifest
234: * @throws BundleException
235: */
236: private void hasQualifier(File bundleLocation, Dictionary manifest)
237: throws BundleException {
238: ManifestElement[] versionInfo = ManifestElement.parseHeader(
239: Constants.BUNDLE_VERSION, (String) manifest
240: .get(Constants.BUNDLE_VERSION));
241: if (versionInfo != null) {
242: if (versionInfo[0].getValue().endsWith(PROPERTY_QUALIFIER)) {
243: manifest.put(PROPERTY_QUALIFIER,
244: getQualifierPropery(bundleLocation
245: .getAbsolutePath()));
246: }
247: }
248: }
249:
250: private String getQualifierPropery(String bundleLocation) {
251: String qualifierInfo = null;
252: try {
253: qualifierInfo = AbstractScriptGenerator.readProperties(
254: bundleLocation, IPDEBuildConstants.PROPERTIES_FILE,
255: IStatus.INFO).getProperty(PROPERTY_QUALIFIER);
256: } catch (CoreException e) {
257: //ignore
258: }
259: if (qualifierInfo == null)
260: qualifierInfo = PROPERTY_CONTEXT;
261: return qualifierInfo;
262: }
263:
264: //Return a dictionary representing a manifest. The data may result from plugin.xml conversion
265: private Dictionary basicLoadManifest(File bundleLocation) {
266: InputStream manifestStream = null;
267: ZipFile jarFile = null;
268: try {
269: if ("jar".equalsIgnoreCase(new Path(bundleLocation.getName()).getFileExtension()) && bundleLocation.isFile()) { //$NON-NLS-1$
270: jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ);
271: ZipEntry manifestEntry = jarFile
272: .getEntry(JarFile.MANIFEST_NAME);
273: if (manifestEntry != null) {
274: manifestStream = jarFile
275: .getInputStream(manifestEntry);
276: }
277: } else {
278: manifestStream = new BufferedInputStream(
279: new FileInputStream(new File(bundleLocation,
280: JarFile.MANIFEST_NAME)));
281: }
282: } catch (IOException e) {
283: //ignore
284: }
285:
286: //It is not a manifest, but a plugin or a fragment
287: if (manifestStream == null)
288: return convertPluginManifest(bundleLocation, true);
289:
290: try {
291: Hashtable result = new Hashtable();
292: result.putAll(ManifestElement.parseBundleManifest(
293: manifestStream, null));
294: return result;
295: } catch (IOException ioe) {
296: return null;
297: } catch (BundleException e) {
298: return null;
299: } finally {
300: try {
301: manifestStream.close();
302: } catch (IOException e1) {
303: //Ignore
304: }
305: try {
306: if (jarFile != null)
307: jarFile.close();
308: } catch (IOException e2) {
309: //Ignore
310: }
311: }
312: }
313:
314: private void enforceSymbolicName(File bundleLocation,
315: Dictionary initialManifest) {
316: if (initialManifest.get(Constants.BUNDLE_SYMBOLICNAME) != null)
317: return;
318:
319: Dictionary generatedManifest = convertPluginManifest(
320: bundleLocation, false);
321: if (generatedManifest == null)
322: return;
323:
324: //merge manifests. The values from the generated manifest are added to the initial one. Values from the initial one are not deleted
325: Enumeration enumeration = generatedManifest.keys();
326: while (enumeration.hasMoreElements()) {
327: Object key = enumeration.nextElement();
328: if (initialManifest.get(key) == null)
329: initialManifest.put(key, generatedManifest.get(key));
330: }
331: }
332:
333: private void enforceClasspath(Dictionary manifest) {
334: String classpath = (String) manifest
335: .get(Constants.BUNDLE_CLASSPATH);
336: if (classpath == null)
337: manifest.put(Constants.BUNDLE_CLASSPATH, "."); //$NON-NLS-1$
338: }
339:
340: private Dictionary loadManifest(File bundleLocation) {
341: Dictionary manifest = basicLoadManifest(bundleLocation);
342: if (manifest == null)
343: return null;
344:
345: enforceSymbolicName(bundleLocation, manifest);
346: enforceClasspath(manifest);
347: return manifest;
348: }
349:
350: private Dictionary convertPluginManifest(File bundleLocation,
351: boolean logConversionException) {
352: PluginConverter converter;
353: try {
354: converter = acquirePluginConverter();
355: return converter.convertManifest(bundleLocation, false,
356: AbstractScriptGenerator.isBuildingOSGi() ? null
357: : "2.1", false, null); //$NON-NLS-1$
358: } catch (PluginConversionException convertException) {
359: if (bundleLocation
360: .getName()
361: .equals(
362: org.eclipse.pde.build.Constants.FEATURE_FILENAME_DESCRIPTOR))
363: return null;
364: if (!new File(
365: bundleLocation,
366: org.eclipse.pde.build.Constants.PLUGIN_FILENAME_DESCRIPTOR)
367: .exists()
368: && !new File(
369: bundleLocation,
370: org.eclipse.pde.build.Constants.FRAGMENT_FILENAME_DESCRIPTOR)
371: .exists())
372: return null;
373: if (logConversionException) {
374: IStatus status = new Status(IStatus.WARNING,
375: PI_PDEBUILD, 0, NLS.bind(
376: Messages.exception_errorConverting,
377: bundleLocation.getAbsolutePath()),
378: convertException);
379: BundleHelper.getDefault().getLog().log(status);
380: }
381: return null;
382: } catch (Exception serviceException) {
383: IStatus status = new Status(IStatus.WARNING, PI_PDEBUILD,
384: 0, NLS.bind(
385: Messages.exception_cannotAcquireService,
386: "Plugin converter"), serviceException); //$NON-NLS-1$
387: BundleHelper.getDefault().getLog().log(status);
388: return null;
389: }
390: }
391:
392: public void addBundles(Collection bundles) {
393: for (Iterator iter = bundles.iterator(); iter.hasNext();) {
394: File bundle = (File) iter.next();
395: addBundle(bundle);
396: }
397: }
398:
399: public void resolveState() {
400: List configs = AbstractScriptGenerator.getConfigInfos();
401: Dictionary[] properties = new Dictionary[configs.size()];
402:
403: // Set the JRE profile
404: String systemPackages = null;
405: String ee = null;
406: if (javaProfile == null)
407: javaProfile = getDefaultJavaProfile();
408: Properties profileProps = getJavaProfileProperties();
409: if (profileProps != null) {
410: systemPackages = profileProps.getProperty(SYSTEM_PACKAGES);
411: ee = profileProps
412: .getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT);
413: }
414:
415: int i = 0;
416: for (Iterator iter = configs.iterator(); iter.hasNext(); i++) {
417: Config aConfig = (Config) iter.next();
418: Dictionary prop = new Hashtable();
419: if (AbstractScriptGenerator
420: .getPropertyAsBoolean(IBuildPropertiesConstants.RESOLVER_DEV_MODE))
421: prop.put(PROPERTY_RESOLVER_MODE, VALUE_DEVELOPMENT);
422: String os = aConfig.getOs();
423: String ws = aConfig.getWs();
424: String arch = aConfig.getArch();
425: if (Config.ANY.equalsIgnoreCase(os))
426: prop.put(OSGI_OS, CatchAllValue.singleton);
427: else
428: prop.put(OSGI_OS, os);
429:
430: if (Config.ANY.equalsIgnoreCase(ws))
431: prop.put(OSGI_WS, CatchAllValue.singleton);
432: else
433: prop.put(OSGI_WS, ws);
434:
435: if (Config.ANY.equalsIgnoreCase(arch))
436: prop.put(OSGI_ARCH, CatchAllValue.singleton);
437: else
438: prop.put(OSGI_ARCH, arch);
439:
440: // Set the JRE profile
441: if (systemPackages != null)
442: prop.put(SYSTEM_PACKAGES, systemPackages);
443: if (ee != null)
444: prop.put(Constants.FRAMEWORK_EXECUTIONENVIRONMENT, ee);
445:
446: // check the user-specified platform properties
447: if (platformProperties != null) {
448: for (Enumeration e = platformProperties.keys(); e
449: .hasMoreElements();) {
450: String key = (String) e.nextElement();
451: prop.put(key, platformProperties.get(key));
452: }
453: }
454:
455: properties[i] = prop;
456: }
457: state.setPlatformProperties(properties);
458: state.resolve(false);
459: }
460:
461: private String getDefaultJavaProfile() {
462: if (javaProfiles == null)
463: setJavaProfiles(getOSGiLocation());
464: if (javaProfiles != null && javaProfiles.length > 0)
465: return javaProfiles[0];
466: return null;
467: }
468:
469: public State getState() {
470: return state;
471: }
472:
473: public BundleDescription[] getDependentBundles(String bundleId,
474: Version version) {
475: BundleDescription root = state.getBundle(bundleId, version);
476: return getDependentBundles(root);
477: }
478:
479: /**
480: * This methods return the bundleDescriptions to which imports have been
481: * bound to.
482: *
483: * @param root
484: */
485: public static BundleDescription[] getImportedBundles(
486: BundleDescription root) {
487: if (root == null)
488: return new BundleDescription[0];
489: ExportPackageDescription[] packages = root.getResolvedImports();
490: ArrayList resolvedImports = new ArrayList(packages.length);
491: for (int i = 0; i < packages.length; i++)
492: if (!root.getLocation().equals(
493: packages[i].getExporter().getLocation())
494: && !resolvedImports.contains(packages[i]
495: .getExporter()))
496: resolvedImports.add(packages[i].getExporter());
497: return (BundleDescription[]) resolvedImports
498: .toArray(new BundleDescription[resolvedImports.size()]);
499: }
500:
501: /**
502: * This methods return the bundleDescriptions to which required bundles
503: * have been bound to.
504: *
505: * @param root
506: */
507: public static BundleDescription[] getRequiredBundles(
508: BundleDescription root) {
509: if (root == null)
510: return new BundleDescription[0];
511: return root.getResolvedRequires();
512: }
513:
514: public BundleDescription getResolvedBundle(String bundleId,
515: String version) {
516: return getBundle(bundleId, version, true);
517: }
518:
519: public BundleDescription getBundle(String bundleId, String version,
520: boolean resolved) {
521: if (IPDEBuildConstants.GENERIC_VERSION_NUMBER.equals(version)
522: || version == null) {
523: BundleDescription bundle = getResolvedBundle(bundleId);
524: if (bundle == null && !resolved)
525: bundle = getState().getBundle(bundleId, null);
526: return bundle;
527: }
528: Version parsedVersion = Version.parseVersion(version);
529: BundleDescription description = getState().getBundle(bundleId,
530: parsedVersion);
531: if (description != null
532: && (!resolved || description.isResolved()))
533: return description;
534:
535: int qualifierIdx = -1;
536: if ((qualifierIdx = parsedVersion.getQualifier().indexOf(
537: IBuildPropertiesConstants.PROPERTY_QUALIFIER)) != -1) {
538: BundleDescription[] bundles = getState().getBundles(
539: bundleId);
540:
541: String qualifierPrefix = qualifierIdx > 0 ? parsedVersion
542: .getQualifier().substring(0, qualifierIdx - 1) : ""; //$NON-NLS-1$
543:
544: for (int i = 0; i < bundles.length; i++) {
545: Version bundleVersion = bundles[i].getVersion();
546: if (bundleVersion.getMajor() == parsedVersion
547: .getMajor()
548: && bundleVersion.getMinor() == parsedVersion
549: .getMinor()
550: && bundleVersion.getMicro() == parsedVersion
551: .getMicro()
552: && bundleVersion.getQualifier().compareTo(
553: qualifierPrefix) >= 0)
554: return bundles[i];
555: }
556: }
557: return null;
558: }
559:
560: public BundleDescription getResolvedBundle(String bundleId) {
561: BundleDescription[] description = getState().getBundles(
562: bundleId);
563: if (description == null)
564: return null;
565: for (int i = 0; i < description.length; i++) {
566: if (description[i].isResolved())
567: return description[i];
568: }
569: return null;
570: }
571:
572: public static BundleDescription[] getDependentBundles(
573: BundleDescription root) {
574: BundleDescription[] imported = getImportedBundles(root);
575: BundleDescription[] required = getRequiredBundles(root);
576: BundleDescription[] dependents = new BundleDescription[imported.length
577: + required.length];
578: System.arraycopy(imported, 0, dependents, 0, imported.length);
579: System.arraycopy(required, 0, dependents, imported.length,
580: required.length);
581: return dependents;
582: }
583:
584: public static BundleDescription[] getDependentBundlesWithFragments(
585: BundleDescription root) {
586: BundleDescription[] imported = getImportedBundles(root);
587: BundleDescription[] importedByFragments = getImportedByFragments(root);
588: BundleDescription[] required = getRequiredBundles(root);
589: BundleDescription[] requiredByFragments = getRequiredByFragments(root);
590: BundleDescription[] dependents = new BundleDescription[imported.length
591: + importedByFragments.length
592: + required.length
593: + requiredByFragments.length];
594: System.arraycopy(imported, 0, dependents, 0, imported.length);
595: System.arraycopy(importedByFragments, 0, dependents,
596: imported.length, importedByFragments.length);
597: System.arraycopy(required, 0, dependents, imported.length
598: + importedByFragments.length, required.length);
599: System.arraycopy(requiredByFragments, 0, dependents,
600: imported.length + importedByFragments.length
601: + required.length, requiredByFragments.length);
602: return dependents;
603: }
604:
605: public static BundleDescription[] getImportedByFragments(
606: BundleDescription root) {
607: BundleDescription[] fragments = root.getFragments();
608: List importedByFragments = new ArrayList();
609: for (int i = 0; i < fragments.length; i++) {
610: if (!fragments[i].isResolved())
611: continue;
612: merge(importedByFragments, getImportedBundles(fragments[i]));
613: }
614: BundleDescription[] result = new BundleDescription[importedByFragments
615: .size()];
616: return (BundleDescription[]) importedByFragments
617: .toArray(result);
618: }
619:
620: public static BundleDescription[] getRequiredByFragments(
621: BundleDescription root) {
622: BundleDescription[] fragments = root.getFragments();
623: List importedByFragments = new ArrayList();
624: for (int i = 0; i < fragments.length; i++) {
625: if (!fragments[i].isResolved())
626: continue;
627: merge(importedByFragments, getRequiredBundles(fragments[i]));
628: }
629: BundleDescription[] result = new BundleDescription[importedByFragments
630: .size()];
631: return (BundleDescription[]) importedByFragments
632: .toArray(result);
633: }
634:
635: public static void merge(List source, BundleDescription[] toAdd) {
636: for (int i = 0; i < toAdd.length; i++) {
637: if (!source.contains(toAdd[i]))
638: source.add(toAdd[i]);
639: }
640: }
641:
642: public Properties loadPropertyFileIn(Map toMerge, File location) {
643: Properties result = new Properties();
644: result.putAll(toMerge);
645: try {
646: InputStream propertyStream = new BufferedInputStream(
647: new FileInputStream(new File(location,
648: PROPERTIES_FILE)));
649: try {
650: result.load(propertyStream);
651: } finally {
652: propertyStream.close();
653: }
654: } catch (Exception e) {
655: //ignore because compiled plug-ins do not have such files
656: }
657: return result;
658: }
659:
660: public HashMap getExtraData() {
661: return bundleClasspaths;
662: }
663:
664: public Map getPatchData() {
665: return patchBundles;
666: }
667:
668: public List getSortedBundles() {
669: if (lastSortingDate != getState().getTimeStamp()) {
670: lastSortingDate = getState().getTimeStamp();
671: BundleDescription[] toSort = getState()
672: .getResolvedBundles();
673: Platform.getPlatformAdmin().getStateHelper().sortBundles(
674: toSort);
675: sortedBundles = Arrays.asList(toSort);
676: }
677: return sortedBundles;
678: }
679:
680: public void cleanupOriginalState() {
681: if (addedBundle == null && unqualifiedBundles == null)
682: return;
683:
684: for (Iterator iter = addedBundle.iterator(); iter.hasNext();) {
685: BundleDescription added = (BundleDescription) iter.next();
686: state.removeBundle(added);
687: }
688:
689: for (Iterator iter = unqualifiedBundles.iterator(); iter
690: .hasNext();) {
691: BundleDescription toAddBack = (BundleDescription) iter
692: .next();
693: state.removeBundle(toAddBack.getBundleId());
694: addBundleDescription(toAddBack);
695: }
696:
697: BundleDescription[] allBundles = state.getBundles();
698: for (int i = 0; i < allBundles.length; i++) {
699: allBundles[i].setUserObject(null);
700: }
701: state.resolve();
702: }
703:
704: private File getOSGiLocation() {
705: BundleDescription osgiBundle = state.getBundle(
706: "org.eclipse.osgi", null); //$NON-NLS-1$
707: if (osgiBundle == null)
708: return null;
709: return new File(osgiBundle.getLocation());
710: }
711:
712: private void setJavaProfiles(File bundleLocation) {
713: String[] foundProfiles = null;
714: if (bundleLocation == null)
715: foundProfiles = getRuntimeJavaProfiles();
716: else if (bundleLocation.isDirectory())
717: foundProfiles = getDirJavaProfiles(bundleLocation);
718: else
719: foundProfiles = getJarJavaProfiles(bundleLocation);
720: javaProfiles = foundProfiles;
721: }
722:
723: private String[] getRuntimeJavaProfiles() {
724: BundleContext context = BundleHelper.getDefault().getBundle()
725: .getBundleContext();
726: Bundle systemBundle = context.getBundle(0);
727:
728: URL url = systemBundle.getEntry("profile.list"); //$NON-NLS-1$
729: if (url != null) {
730: try {
731: return getJavaProfiles(new BufferedInputStream(url
732: .openStream()));
733: } catch (IOException e) {
734: //no profile.list?
735: }
736: }
737:
738: ArrayList results = new ArrayList(6);
739: Enumeration entries = systemBundle.findEntries(
740: "/", "*.profile", false); //$NON-NLS-1$ //$NON-NLS-2$
741: while (entries.hasMoreElements()) {
742: URL entryUrl = (URL) entries.nextElement();
743: results.add(entryUrl.getFile().substring(1));
744: }
745:
746: return sortProfiles((String[]) results
747: .toArray(new String[results.size()]));
748: }
749:
750: private String[] getDirJavaProfiles(File bundleLocation) {
751: // try the profile list first
752: File profileList = new File(bundleLocation, "profile.list"); //$NON-NLS-1$
753: if (profileList.exists())
754: try {
755: return getJavaProfiles(new BufferedInputStream(
756: new FileInputStream(profileList)));
757: } catch (IOException e) {
758: // this should not happen because we just checked if the file exists
759: }
760: String[] profiles = bundleLocation.list(new FilenameFilter() {
761: public boolean accept(File dir, String name) {
762: return name.endsWith(PROFILE_EXTENSION);
763: }
764: });
765: return sortProfiles(profiles);
766: }
767:
768: private String[] getJarJavaProfiles(File bundleLocation) {
769: ZipFile zipFile = null;
770: ArrayList results = new ArrayList(6);
771: try {
772: zipFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ);
773: ZipEntry profileList = zipFile.getEntry("profile.list"); //$NON-NLS-1$
774: if (profileList != null)
775: try {
776: return getJavaProfiles(zipFile
777: .getInputStream(profileList));
778: } catch (IOException e) {
779: // this should not happen, just incase do the default
780: }
781:
782: Enumeration entries = zipFile.entries();
783: while (entries.hasMoreElements()) {
784: String entryName = ((ZipEntry) entries.nextElement())
785: .getName();
786: if (entryName.indexOf('/') < 0
787: && entryName.endsWith(PROFILE_EXTENSION))
788: results.add(entryName);
789: }
790: } catch (IOException e) {
791: // nothing to do
792: } finally {
793: if (zipFile != null)
794: try {
795: zipFile.close();
796: } catch (IOException e) {
797: // nothing to do
798: }
799: }
800: return sortProfiles((String[]) results
801: .toArray(new String[results.size()]));
802: }
803:
804: private String[] getJavaProfiles(InputStream is) throws IOException {
805: Properties props = new Properties();
806: props.load(is);
807: return ManifestElement.getArrayFromList(props
808: .getProperty("java.profiles"), ","); //$NON-NLS-1$ //$NON-NLS-2$
809: }
810:
811: private String[] sortProfiles(String[] profiles) {
812: Arrays.sort(profiles, new Comparator() {
813: public int compare(Object profile1, Object profile2) {
814: // need to make sure JavaSE, J2SE profiles are sorted ahead of all other profiles
815: String p1 = (String) profile1;
816: String p2 = (String) profile2;
817: if (p1.startsWith("JavaSE") && !p2.startsWith("JavaSE")) //$NON-NLS-1$ //$NON-NLS-2$
818: return -1;
819: if (!p1.startsWith("JavaSE") && p2.startsWith("JavaSE")) //$NON-NLS-1$ //$NON-NLS-2$
820: return 1;
821: if (p1.startsWith("J2SE") && !p2.startsWith("J2SE")) //$NON-NLS-1$ //$NON-NLS-2$
822: return -1;
823: if (!p1.startsWith("J2SE") && p2.startsWith("J2SE")) //$NON-NLS-1$ //$NON-NLS-2$
824: return 1;
825: return -p1.compareTo(p2);
826: }
827: });
828: return profiles;
829: }
830:
831: private Properties getJavaProfileProperties() {
832: if (javaProfile == null)
833: return null;
834: File location = getOSGiLocation();
835: InputStream is = null;
836: ZipFile zipFile = null;
837: try {
838: if (location == null) {
839: BundleContext context = BundleHelper.getDefault()
840: .getBundle().getBundleContext();
841: Bundle systemBundle = context.getBundle(0);
842:
843: URL url = systemBundle.getEntry(javaProfile);
844: is = new BufferedInputStream(url.openStream());
845: } else if (location.isDirectory()) {
846: is = new BufferedInputStream(new FileInputStream(
847: new File(location, javaProfile)));
848: } else {
849: zipFile = null;
850: try {
851: zipFile = new ZipFile(location, ZipFile.OPEN_READ);
852: ZipEntry entry = zipFile.getEntry(javaProfile);
853: if (entry != null)
854: is = zipFile.getInputStream(entry);
855: } catch (IOException e) {
856: // nothing to do
857: }
858: }
859: Properties profile = new Properties();
860: profile.load(is);
861: return profile;
862: } catch (IOException e) {
863: // nothing to do
864: } finally {
865: if (is != null)
866: try {
867: is.close();
868: } catch (IOException e) {
869: // nothing to do
870: }
871: if (zipFile != null)
872: try {
873: zipFile.close();
874: } catch (IOException e) {
875: // nothing to do
876: }
877: }
878: return null;
879: }
880:
881: //Replace the version numbers that ends with .qualifier
882: private void forceQualifiers() {
883: BundleDescription[] resolvedBundles = state
884: .getResolvedBundles(); //We only get the resolved bundles since, changing the qualifier should not change the resolution state
885: for (int i = 0; i < resolvedBundles.length; i++) {
886: if (resolvedBundles[i].getVersion().getQualifier()
887: .endsWith(PROPERTY_QUALIFIER)) {
888: BundleDescription b = resolvedBundles[i];
889: unqualifiedBundles.add(state.removeBundle(b
890: .getBundleId())); //We keep the removed bundle so we can reinsert it in the state when we are done
891: String newVersion = QualifierReplacer
892: .replaceQualifierInVersion(b.getVersion()
893: .toString(), b.getSymbolicName(),
894: getQualifierPropery(b.getLocation()),
895: null);
896:
897: //Here it is important to reuse the same bundle id than the bundle we are removing so that we don't loose the information about the classpath
898: BundleDescription newBundle = state.getFactory()
899: .createBundleDescription(b.getBundleId(),
900: b.getSymbolicName(),
901: new Version(newVersion),
902: b.getLocation(),
903: b.getRequiredBundles(), b.getHost(),
904: b.getImportPackages(),
905: b.getExportPackages(), b.isSingleton(),
906: b.attachFragments(),
907: b.dynamicFragments(),
908: b.getPlatformFilter(),
909: b.getExecutionEnvironments(),
910: b.getGenericRequires(),
911: b.getGenericCapabilities());
912: addBundleDescription(newBundle);
913: rememberQualifierTagPresence(newBundle);
914: mapVersionReplacedBundle(b, newBundle);
915: }
916: }
917: state.resolve();
918: }
919:
920: /*
921: * If this bundle had its qualifier version replaced, return the replacement bundle description
922: * return the original bundle if no replacement occurred
923: */
924: public BundleDescription getVersionReplacement(
925: BundleDescription bundle) {
926: Properties props = (Properties) bundle.getUserObject();
927: if (props == null)
928: return bundle;
929: String idString = props
930: .getProperty(PROPERTY_VERSION_REPLACEMENT);
931: if (idString == null)
932: return bundle;
933: try {
934: long newId = Long.parseLong(idString);
935: BundleDescription newBundle = state.getBundle(newId);
936: if (newBundle != null)
937: return newBundle;
938: } catch (NumberFormatException e) {
939: // fall through
940: }
941: return bundle;
942: }
943:
944: public void setPlatformProperties(Dictionary platformProperties) {
945: this.platformProperties = platformProperties;
946: }
947: }
|