KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > runtime > adaptor > EclipseBundleData


1 /*******************************************************************************
2  * Copyright (c) 2003, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.runtime.adaptor;
12
13 import java.io.*;
14 import java.net.URL JavaDoc;
15 import java.util.*;
16 import org.eclipse.core.runtime.internal.adaptor.*;
17 import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor;
18 import org.eclipse.osgi.framework.adaptor.core.*;
19 import org.eclipse.osgi.framework.internal.core.Constants;
20 import org.eclipse.osgi.framework.log.FrameworkLogEntry;
21 import org.eclipse.osgi.framework.util.Headers;
22 import org.eclipse.osgi.service.datalocation.Location;
23 import org.eclipse.osgi.service.pluginconversion.PluginConversionException;
24 import org.eclipse.osgi.util.ManifestElement;
25 import org.eclipse.osgi.util.NLS;
26 import org.osgi.framework.BundleException;
27 import org.osgi.framework.Version;
28
29 /**
30  * The BundleData implementation used Eclipse.
31  * <p>
32  * Clients may extend this class.
33  * </p>
34  * @since 3.1
35  */

36 //Maybe for consistency should it be overriden to do nothing. See also EclipseAdaptor.saveMetadataFor(BundleData)
37
public class EclipseBundleData extends AbstractBundleData {
38     /** bundle manifest type unknown */
39     static public final byte MANIFEST_TYPE_UNKNOWN = 0x00;
40     /** bundle manifest type bundle (META-INF/MANIFEST.MF) */
41     static public final byte MANIFEST_TYPE_BUNDLE = 0x01;
42     /** bundle manifest type plugin (plugin.xml) */
43     static public final byte MANIFEST_TYPE_PLUGIN = 0x02;
44     /** bundle manifest type fragment (fragment.xml) */
45     static public final byte MANIFEST_TYPE_FRAGMENT = 0x04;
46     /** bundle manifest type jared bundle */
47     static public final byte MANIFEST_TYPE_JAR = 0x08;
48
49     private static String JavaDoc[] libraryVariants = null;
50
51     /** data to detect modification made in the manifest */
52     private long manifestTimeStamp = 0;
53     private byte manifestType = MANIFEST_TYPE_UNKNOWN;
54
55     // URL protocol designations
56
/** The platform protocol */
57     public static final String JavaDoc PROTOCOL = "platform"; //$NON-NLS-1$
58
/** The file protocol */
59     public static final String JavaDoc FILE = "file"; //$NON-NLS-1$
60

61     private static final String JavaDoc PROP_CHECK_CONFIG = "osgi.checkConfiguration"; //$NON-NLS-1$
62
/** the Plugin-Class header */
63     protected String JavaDoc pluginClass = null;
64     /** Eclipse-AutoStart header */
65     private boolean autoStart;
66     private String JavaDoc[] autoStartExceptions;
67     /** shortcut to know if a bundle has a buddy */
68     protected String JavaDoc buddyList;
69     /** shortcut to know if a bundle is a registrant to a registered policy */
70     protected String JavaDoc registeredBuddyList;
71     /** shortcut to know if the bundle manifest has package info */
72     protected boolean hasPackageInfo;
73
74     private static String JavaDoc[] buildLibraryVariants() {
75         ArrayList result = new ArrayList();
76         EclipseEnvironmentInfo info = EclipseEnvironmentInfo.getDefault();
77         result.add("ws/" + info.getWS() + "/"); //$NON-NLS-1$ //$NON-NLS-2$
78
result.add("os/" + info.getOS() + "/" + info.getOSArch() + "/"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
79
result.add("os/" + info.getOS() + "/"); //$NON-NLS-1$ //$NON-NLS-2$
80
String JavaDoc nl = info.getNL();
81         nl = nl.replace('_', '/');
82         while (nl.length() > 0) {
83             result.add("nl/" + nl + "/"); //$NON-NLS-1$ //$NON-NLS-2$
84
int i = nl.lastIndexOf('/');
85             nl = (i < 0) ? "" : nl.substring(0, i); //$NON-NLS-1$
86
}
87         result.add(""); //$NON-NLS-1$
88
return (String JavaDoc[]) result.toArray(new String JavaDoc[result.size()]);
89     }
90
91     /**
92      * Constructor for EclipseBundleData.
93      * @param adaptor The adaptor for this bundle data
94      * @param id The bundle id for this bundle data
95      */

96     public EclipseBundleData(AbstractFrameworkAdaptor adaptor, long id) {
97         super(adaptor, id);
98     }
99
100     /**
101      * Initialize an existing bundle
102      * @throws IOException if any error occurs loading the existing bundle
103      */

104     public void initializeExistingBundle() throws IOException {
105         createBaseBundleFile();
106         if (!checkManifestTimeStamp()) {
107             if (getBundleStoreDir().exists()) {
108                 /* create .delete */
109                 FileOutputStream out = new FileOutputStream(new File(getBundleStoreDir(), ".delete"));
110                 out.close();
111             }
112             throw new IOException();
113         }
114     }
115
116     private boolean checkManifestTimeStamp() {
117         if (!"true".equalsIgnoreCase(System.getProperty(PROP_CHECK_CONFIG))) //$NON-NLS-1$
118
return true;
119
120         if (PluginConverterImpl.getTimeStamp(getBaseFile(), getManifestType()) == getManifestTimeStamp()) {
121             if ((getManifestType() & (MANIFEST_TYPE_JAR | MANIFEST_TYPE_BUNDLE)) != 0)
122                 return true;
123             String JavaDoc cacheLocation = System.getProperty(LocationManager.PROP_MANIFEST_CACHE);
124             Location parentConfiguration = LocationManager.getConfigurationLocation().getParentLocation();
125             if (parentConfiguration != null) {
126                 try {
127                     return checkManifestAndParent(cacheLocation, getSymbolicName(), getVersion().toString(), getManifestType()) != null;
128                 } catch (BundleException e) {
129                     return false;
130                 }
131             }
132             File cacheFile = new File(cacheLocation, getSymbolicName() + '_' + getVersion() + ".MF"); //$NON-NLS-1$
133
if (cacheFile.isFile())
134                 return true;
135         }
136         return false;
137     }
138
139     /**
140      * Returns the absolute path name of a native library. The VM invokes this
141      * method to locate the native libraries that belong to classes loaded with
142      * this class loader. If this method returns <code>null</code>, the VM
143      * searches the library along the path specified as the <code>java.library.path</code>
144      * property.
145      *
146      * @param libName
147      * the library name
148      * @return the absolute path of the native library
149      */

150     public String JavaDoc findLibrary(String JavaDoc libName) {
151         // first do the standard OSGi lookup using the native clauses
152
// in the manifest. If that fails, do the legacy Eclipse lookup.
153
String JavaDoc result = super.findLibrary(libName);
154         if (result != null)
155             return result;
156         if (libraryVariants == null)
157             libraryVariants = buildLibraryVariants();
158         if (libName.length() == 0)
159             return null;
160         if (libName.charAt(0) == '/' || libName.charAt(0) == '\\')
161             libName = libName.substring(1);
162         libName = System.mapLibraryName(libName);
163
164         // if (DEBUG && DEBUG_SHOW_ACTIONS && debugNative(libName))
165
// debug("findLibrary(" + libName + ")"); //$NON-NLS-1$ //$NON-NLS-2$
166

167         return searchVariants(libraryVariants, libName);
168
169     }
170
171     private String JavaDoc searchVariants(String JavaDoc[] variants, String JavaDoc path) {
172         for (int i = 0; i < variants.length; i++) {
173             BundleEntry libEntry = baseBundleFile.getEntry(variants[i] + path);
174             if (libEntry == null) {
175                 // if (DEBUG && DEBUG_SHOW_FAILURE)
176
// debug("not found " + variants[i] + path);
177
// //$NON-NLS-1$
178
} else {
179                 // if (DEBUG && DEBUG_SHOW_SUCCESS)
180
// debug("found " + path + " as " +
181
// variants[i] + path); //$NON-NLS-1$ //$NON-NLS-2$
182
File libFile = baseBundleFile.getFile(variants[i] + path);
183                 if (libFile == null)
184                     return null;
185                 // see bug 88697 - HP requires libraries to have executable permissions
186
if (org.eclipse.osgi.service.environment.Constants.OS_HPUX.equals(EclipseEnvironmentInfo.getDefault().getOS())) {
187                     try {
188                         // use the string array method in case there is a space in the path
189
Runtime.getRuntime().exec(new String JavaDoc[] {"chmod", "755", libFile.getAbsolutePath()}).waitFor(); //$NON-NLS-1$ //$NON-NLS-2$
190
} catch (Exception JavaDoc e) {
191                         e.printStackTrace();
192                     }
193                 }
194                 return libFile.getAbsolutePath();
195             }
196         }
197         return null;
198     }
199
200     //TODO Unused method
201
private URL JavaDoc[] getSearchURLs(URL JavaDoc target) {
202         return new URL JavaDoc[] {target};
203     }
204
205     public synchronized Dictionary getManifest() throws BundleException {
206         return getManifest(false);
207     }
208
209     /**
210      * Gets the manifest for this bundle. If this is the first time the manifest is
211      * ever accessed then the manifest is loaded from the manifest file in the bundle;
212      * otherwise the manifest is loaded from cached data.
213      * @param first set to true if this is the first time the manifest is accessed
214      * for this bundle
215      * @return the manifest for this bundle
216      * @throws BundleException if any error occurs loading the manifest
217      */

218     public synchronized Dictionary getManifest(boolean first) throws BundleException {
219         if (manifest == null)
220             manifest = first ? loadManifest() : new CachedManifest(this);
221         return manifest;
222     }
223
224     private boolean isComplete(Dictionary manifest) {
225         // a manifest is complete if it has a Bundle-SymbolicName entry...
226
if (manifest.get(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME) != null)
227             return true;
228         // ...or it does not have a plugin/fragment manifest where to get the other entries from
229
return getEntry(PluginConverterImpl.PLUGIN_MANIFEST) == null && getEntry(PluginConverterImpl.FRAGMENT_MANIFEST) == null;
230     }
231
232     /**
233      * Loads the bundle manifest from the bundle.
234      * @return the bundle manifest
235      * @throws BundleException if an error occurs loading the bundle manifest
236      */

237     public synchronized Dictionary loadManifest() throws BundleException {
238         URL JavaDoc url = getEntry(Constants.OSGI_BUNDLE_MANIFEST);
239         if (url != null) {
240             // the bundle has a built-in manifest - we may not have to generate one
241
Dictionary builtIn = loadManifestFrom(url);
242             // if the manifest is not complete, add entries derived from plug-in/fragment manifest
243
if (!isComplete(builtIn)) {
244                 Dictionary generatedManifest = generateManifest(builtIn);
245                 if (generatedManifest != null)
246                     return generatedManifest;
247             }
248             // the manifest is complete or we could not complete it - take it as it is
249
manifestType = MANIFEST_TYPE_BUNDLE;
250             if (getBaseFile().isFile()) {
251                 manifestTimeStamp = getBaseFile().lastModified();
252                 manifestType |= MANIFEST_TYPE_JAR;
253             } else
254                 manifestTimeStamp = getBaseBundleFile().getEntry(Constants.OSGI_BUNDLE_MANIFEST).getTime();
255             return builtIn;
256         }
257         Dictionary result = generateManifest(null);
258         if (result == null)
259             throw new BundleException(NLS.bind(EclipseAdaptorMsg.ECLIPSE_DATA_MANIFEST_NOT_FOUND, getLocation()));
260         return result;
261     }
262
263     private Headers basicCheckManifest(String JavaDoc cacheLocation, String JavaDoc symbolicName, String JavaDoc version, byte inputType) throws BundleException {
264         File currentFile = new File(cacheLocation, symbolicName + '_' + version + ".MF"); //$NON-NLS-1$
265
if (PluginConverterImpl.upToDate(currentFile, getBaseFile(), inputType)) {
266             try {
267                 return Headers.parseManifest(new FileInputStream(currentFile));
268             } catch (FileNotFoundException e) {
269                 // do nothing.
270
}
271         }
272         return null;
273     }
274
275     private Headers checkManifestAndParent(String JavaDoc cacheLocation, String JavaDoc symbolicName, String JavaDoc version, byte inputType) throws BundleException {
276         Headers result = basicCheckManifest(cacheLocation, symbolicName, version, inputType);
277         if (result != null)
278             return result;
279
280         Location parentConfiguration = null;
281         if ((parentConfiguration = LocationManager.getConfigurationLocation().getParentLocation()) != null) {
282             result = basicCheckManifest(new File(parentConfiguration.getURL().getFile(), FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME + '/' + LocationManager.MANIFESTS_DIR).toString(), symbolicName, version, inputType);
283         }
284         return result;
285     }
286
287     private Dictionary generateManifest(Dictionary originalManifest) throws BundleException {
288         String JavaDoc cacheLocation = System.getProperty(LocationManager.PROP_MANIFEST_CACHE);
289         if (getSymbolicName() != null) {
290             Headers existingHeaders = checkManifestAndParent(cacheLocation, getSymbolicName(), getVersion().toString(), manifestType);
291             if (existingHeaders != null)
292                 return existingHeaders;
293         }
294
295         PluginConverterImpl converter = PluginConverterImpl.getDefault();
296
297         Dictionary generatedManifest;
298         try {
299             generatedManifest = converter.convertManifest(getBaseFile(), true, null, true, null);
300         } catch (PluginConversionException pce) {
301             String JavaDoc message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CONVERTER_ERROR_CONVERTING, getBaseFile()); //$NON-NLS-1$
302
throw new BundleException(message, pce); //$NON-NLS-1$
303
}
304
305         //Now we know the symbolicId and the version of the bundle, we check to see if don't have a manifest for it already
306
Version version = Version.parseVersion((String JavaDoc) generatedManifest.get(Constants.BUNDLE_VERSION));
307         String JavaDoc symbolicName = ManifestElement.parseHeader(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME, (String JavaDoc) generatedManifest.get(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME))[0].getValue();
308         ManifestElement generatedFrom = ManifestElement.parseHeader(PluginConverterImpl.GENERATED_FROM, (String JavaDoc) generatedManifest.get(PluginConverterImpl.GENERATED_FROM))[0];
309         Headers existingHeaders = checkManifestAndParent(cacheLocation, symbolicName, version.toString(), Byte.parseByte(generatedFrom.getAttribute(PluginConverterImpl.MANIFEST_TYPE_ATTRIBUTE)));
310         //We don't have a manifest.
311
setManifestTimeStamp(Long.parseLong(generatedFrom.getValue()));
312         setManifestType(Byte.parseByte(generatedFrom.getAttribute(PluginConverterImpl.MANIFEST_TYPE_ATTRIBUTE)));
313         if (!adaptor.canWrite() || existingHeaders != null)
314             return existingHeaders;
315
316         //merge the original manifest with the generated one
317
if (originalManifest != null) {
318             Enumeration keysEnum = originalManifest.keys();
319             while (keysEnum.hasMoreElements()) {
320                 Object JavaDoc key = keysEnum.nextElement();
321                 generatedManifest.put(key, originalManifest.get(key));
322             }
323         }
324
325         //write the generated manifest
326
File bundleManifestLocation = new File(cacheLocation, symbolicName + '_' + version.toString() + ".MF"); //$NON-NLS-1$
327
try {
328             converter.writeManifest(bundleManifestLocation, generatedManifest, true);
329         } catch (Exception JavaDoc e) {
330             //TODO Need to log
331
}
332         return generatedManifest;
333
334     }
335
336     private Dictionary loadManifestFrom(URL JavaDoc manifestURL) throws BundleException {
337         try {
338             return Headers.parseManifest(manifestURL.openStream());
339         } catch (IOException e) {
340             throw new BundleException(NLS.bind(EclipseAdaptorMsg.ECLIPSE_DATA_ERROR_READING_MANIFEST, getLocation()), e);
341         }
342     }
343
344     protected void loadFromManifest() throws BundleException {
345         getManifest(true);
346         super.loadFromManifest();
347         // manifest cannot ever be a cached one otherwise the lines below are bogus
348
if (manifest instanceof CachedManifest)
349             throw new IllegalStateException JavaDoc();
350         pluginClass = (String JavaDoc) manifest.get(EclipseAdaptor.PLUGIN_CLASS);
351         parseAutoStart((String JavaDoc) manifest.get(EclipseAdaptor.ECLIPSE_AUTOSTART));
352         buddyList = (String JavaDoc) manifest.get(Constants.BUDDY_LOADER);
353         registeredBuddyList = (String JavaDoc) manifest.get(Constants.REGISTERED_POLICY);
354         hasPackageInfo = hasPackageInfo(getEntry(Constants.OSGI_BUNDLE_MANIFEST));
355     }
356
357     // Used to check the bundle manifest file for any package information.
358
// This is used when '.' is on the Bundle-ClassPath to prevent reading
359
// the bundle manifest for pacakge information when loading classes.
360
private boolean hasPackageInfo(URL JavaDoc url) {
361         if (url == null)
362             return false;
363         BufferedReader br = null;
364         try {
365             br = new BufferedReader(new InputStreamReader(url.openStream()));
366             String JavaDoc line;
367             while ((line = br.readLine()) != null) {
368                 if (line.startsWith("Specification-Title: ") || line.startsWith("Specification-Version: ") || line.startsWith("Specification-Vendor: ") || line.startsWith("Implementation-Title: ") || line.startsWith("Implementation-Version: ") || line.startsWith("Implementation-Vendor: ")) //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
369
return true;
370             }
371         } catch (IOException ioe) {
372             // do nothing
373
} finally {
374             if (br != null)
375                 try {
376                     br.close();
377                 } catch (IOException e) {
378                     // do nothing
379
}
380         }
381         return false;
382     }
383
384     /**
385      * Returns the plugin class
386      * @return the plugin class
387      */

388     public String JavaDoc getPluginClass() {
389         return pluginClass;
390     }
391
392     /**
393      * Returns the buddy list for this bundle
394      * @return the buddy list for this bundle
395      */

396     public String JavaDoc getBuddyList() {
397         return buddyList;
398     }
399
400     /**
401      * Returns the registered buddy list for this bundle
402      * @return the registered buddy list for this bundle
403      */

404     public String JavaDoc getRegisteredBuddyList() {
405         return registeredBuddyList;
406     }
407
408     /**
409      * Sets the plugin class
410      * @param value the plugin class
411      */

412     public void setPluginClass(String JavaDoc value) {
413         pluginClass = value;
414     }
415
416     /**
417      * Returns the timestamp for the manifest file
418      * @return the timestamp for the manifest file
419      */

420     public long getManifestTimeStamp() {
421         return manifestTimeStamp;
422     }
423
424     /**
425      * Sets the manifest timestamp for this bundle
426      * @param stamp the manifest timestamp
427      */

428     public void setManifestTimeStamp(long stamp) {
429         manifestTimeStamp = stamp;
430     }
431
432     /**
433      * Returns the manifest type
434      * @return the manifest type
435      */

436     public byte getManifestType() {
437         return manifestType;
438     }
439
440     /**
441      * Sets the manifest type
442      * @param manifestType the manifest type
443      */

444     public void setManifestType(byte manifestType) {
445         this.manifestType = manifestType;
446     }
447
448     /**
449      * Sets the auto start flag
450      * @param value the auto start flag
451      */

452     public void setAutoStart(boolean value) {
453         autoStart = value;
454     }
455
456     /**
457      * Checks whether this bundle is auto started for all resource/class loads
458      * @return true if the bundle is auto started; false otherwise
459      */

460     public boolean isAutoStart() {
461         return autoStart;
462     }
463
464     /**
465      * Returns the status of this bundle which is persisted on shutdown. For bundles
466      * which are auto started the started state is removed to prevent the bundle from
467      * being started on the next startup.
468      * @return the status of this bundle which is persisted on shutdown
469      */

470     public int getPersistentStatus() {
471         // omit the active state if necessary
472
return isAutoStartable() ? (~Constants.BUNDLE_STARTED) & getStatus() : getStatus();
473     }
474
475     /**
476      * Sets the list of auto start exceptions for this bundle
477      * @param autoStartExceptions the list of auto start exceptions
478      */

479     public void setAutoStartExceptions(String JavaDoc[] autoStartExceptions) {
480         this.autoStartExceptions = autoStartExceptions;
481     }
482
483     /**
484      * Returns the auto start exception packages
485      * @return the auto start exception packages
486      */

487     public String JavaDoc[] getAutoStartExceptions() {
488         return autoStartExceptions;
489     }
490
491     private void parseAutoStart(String JavaDoc headerValue) {
492         autoStart = false;
493         autoStartExceptions = null;
494         ManifestElement[] allElements = null;
495         try {
496             allElements = ManifestElement.parseHeader(EclipseAdaptor.ECLIPSE_AUTOSTART, headerValue);
497         } catch (BundleException e) {
498             // just use the default settings (no auto activation)
499
String JavaDoc message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CLASSLOADER_CANNOT_GET_HEADERS, getLocation());
500             EclipseAdaptor.getDefault().getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, message, 0, e, null));
501         }
502         //Eclipse-AutoStart not found...
503
if (allElements == null)
504             return;
505         // the single value for this element should be true|false
506
autoStart = "true".equalsIgnoreCase(allElements[0].getValue()); //$NON-NLS-1$
507
// look for any exceptions (the attribute) to the autoActivate setting
508
String JavaDoc exceptionsValue = allElements[0].getAttribute(EclipseAdaptor.ECLIPSE_AUTOSTART_EXCEPTIONS);
509         if (exceptionsValue == null)
510             return;
511         StringTokenizer tokenizer = new StringTokenizer(exceptionsValue, ","); //$NON-NLS-1$
512
int numberOfTokens = tokenizer.countTokens();
513         autoStartExceptions = new String JavaDoc[numberOfTokens];
514         for (int i = 0; i < numberOfTokens; i++)
515             autoStartExceptions[i] = tokenizer.nextToken().trim();
516     }
517
518     /**
519      * Checks whether this bundle is auto started for all resource/class loads or only for a
520      * subset of resource/classloads
521      * @return true if the bundle is auto started; false otherwise
522      */

523     public boolean isAutoStartable() {
524         return autoStart || (autoStartExceptions != null && autoStartExceptions.length > 0);
525     }
526
527     /**
528      * Save the bundle data in the data file.
529      *
530      * @throws IOException if a write error occurs.
531      */

532     public synchronized void save() throws IOException {
533         if (adaptor.canWrite())
534             ((EclipseAdaptor) adaptor).saveMetaDataFor(this);
535     }
536
537     public String JavaDoc toString() {
538         return "BundleData for " + getSymbolicName() + " (" + id + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
539
}
540
541     public File getParentGenerationDir() {
542         Location parentConfiguration = null;
543         Location currentConfiguration = LocationManager.getConfigurationLocation();
544         if (currentConfiguration != null && (parentConfiguration = currentConfiguration.getParentLocation()) != null)
545             return new File(parentConfiguration.getURL().getFile(), FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME + '/' + LocationManager.BUNDLES_DIR + '/' + getBundleID() + '/' + getGeneration());
546         return null;
547     }
548 }
549
Popular Tags