Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDJ Houghton2003-11-25 16:25:02 -0500
committerDJ Houghton2003-11-25 16:25:02 -0500
commit09f3abf08ff6a6c3fe3b3aaf5a84c78d74a3e4b4 (patch)
treecd473298c7b959f300f8166cfdf5f29bbbf419d6
downloadrt.equinox.framework-09f3abf08ff6a6c3fe3b3aaf5a84c78d74a3e4b4.tar.gz
rt.equinox.framework-09f3abf08ff6a6c3fe3b3aaf5a84c78d74a3e4b4.tar.xz
rt.equinox.framework-09f3abf08ff6a6c3fe3b3aaf5a84c78d74a3e4b4.zip
Initial release.
-rw-r--r--bundles/org.eclipse.osgi.services/.classpath7
-rw-r--r--bundles/org.eclipse.osgi.services/.cvsignore1
-rw-r--r--bundles/org.eclipse.osgi.services/.project17
-rw-r--r--bundles/org.eclipse.osgi.services/META-INF/MANIFEST.MF20
-rw-r--r--bundles/org.eclipse.osgi.services/about.html30
-rw-r--r--bundles/org.eclipse.osgi.services/build.properties6
-rw-r--r--bundles/org.eclipse.osgi.services/plugin.xml13
-rw-r--r--bundles/org.eclipse.osgi.services/services.jarbin0 -> 32783 bytes
-rw-r--r--bundles/org.eclipse.osgi.services/servicessrc.zipbin0 -> 214094 bytes
-rw-r--r--bundles/org.eclipse.osgi.util/.classpath7
-rw-r--r--bundles/org.eclipse.osgi.util/.cvsignore1
-rw-r--r--bundles/org.eclipse.osgi.util/.project17
-rw-r--r--bundles/org.eclipse.osgi.util/META-INF/MANIFEST.MF17
-rw-r--r--bundles/org.eclipse.osgi.util/about.html30
-rw-r--r--bundles/org.eclipse.osgi.util/build.properties6
-rw-r--r--bundles/org.eclipse.osgi.util/plugin.xml13
-rw-r--r--bundles/org.eclipse.osgi.util/util.jarbin0 -> 15801 bytes
-rw-r--r--bundles/org.eclipse.osgi.util/utilsrc.zipbin0 -> 28293 bytes
-rw-r--r--bundles/org.eclipse.osgi/.classpath14
-rw-r--r--bundles/org.eclipse.osgi/.cvsignore9
-rw-r--r--bundles/org.eclipse.osgi/.project18
-rw-r--r--bundles/org.eclipse.osgi/build.properties13
-rw-r--r--bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/ConsoleMessages.properties148
-rw-r--r--bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/ConsoleMsg.java43
-rw-r--r--bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkCommandInterpreter.java529
-rw-r--r--bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkCommandProvider.java1636
-rw-r--r--bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkConsole.java497
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleClassLoader.java297
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleData.java160
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleOperation.java75
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ClassLoaderDelegate.java159
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/EventPublisher.java33
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/FrameworkAdaptor.java268
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/IBundleStats.java21
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ImportClassNotFoundException.java41
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ImportResourceNotFoundException.java41
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/PermissionStorage.java81
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ServiceRegistry.java72
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/Version.java521
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/core/AbstractBundleData.java91
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/core/AbstractFrameworkAdaptor.java264
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/core/ServiceRegistry.java224
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/Headers.java312
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/ManifestElement.java592
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/Tokenizer.java172
-rw-r--r--bundles/org.eclipse.osgi/core/framework/META-INF/SYSTEMBUNDLE.MF30
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/console/CommandInterpreter.java89
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/console/CommandProvider.java46
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/debug/Debug.java166
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/debug/DebugOptions.java123
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventListeners.java72
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventManager.java128
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventQueue.java115
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventSource.java44
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventThread.java190
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/ListenerList.java164
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/AliasMapper.java195
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Bundle.java1591
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleCombinedPermissions.java173
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleContext.java1629
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleFragment.java474
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleHost.java728
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoader.java1045
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoaderProxy.java155
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleNativeCode.java530
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundlePermissionCollection.java30
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundlePermissions.java344
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleRepository.java162
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleResourcePermission.java106
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleSource.java43
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Constants.java131
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/ExportedPackageImpl.java83
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/ExternalMessages.properties78
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Filter.java1837
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/FilteredServiceListener.java79
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Framework.java1859
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/KeyedElement.java17
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/KeyedHashSet.java375
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Msg.java41
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/MultiSourcePackage.java23
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/NothingToUpdateException.java22
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/NullPackageSource.java28
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/OSGi.java118
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/PackageAdmin.java896
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/PackageSource.java25
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/PermissionAdmin.java723
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/PermissionsHash.java112
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/ServiceReference.java232
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/ServiceRegistration.java779
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/ServiceUse.java333
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/SingleSourcePackage.java26
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/StartLevel.java216
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/StartLevelEvent.java100
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/StartLevelFactory.java68
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/StartLevelImpl.java487
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/StartLevelListener.java384
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/SystemBundle.java329
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/SystemBundleActivator.java124
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/SystemBundleData.java132
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/SystemBundleLoader.java121
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/UnresolvedPermission.java196
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/UnresolvedPermissionCollection.java100
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Util.java217
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/default.permissions25
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/implied.permissions48
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/osname.aliases35
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/processor.aliases23
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/protocol/ContentHandlerFactory.java123
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/protocol/ContentHandlerProxy.java186
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/protocol/NullURLStreamHandlerService.java135
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/protocol/ProtocolActivator.java22
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/protocol/StreamHandlerFactory.java160
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/protocol/URLStreamHandlerProxy.java287
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/protocol/URLStreamHandlerSetter.java57
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/launcher/EclipseLauncher.java733
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/launcher/Launcher.java423
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/msg/MessageFormat.java280
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/security/action/CreateThread.java35
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/security/action/GetProperty.java44
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/security/action/PermissionStorage.java98
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/tracker/ServiceTracker.java884
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/tracker/ServiceTrackerCustomizer.java74
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/AdaptorElementFactory.java32
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/AdaptorMsg.java43
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/BundleEntry.java215
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/BundleFile.java438
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/DefaultAdaptor.java1138
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/DefaultBundleData.java713
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/DefaultClassLoader.java567
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/ExternalMessages.properties25
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/MetaData.java166
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/PermissionStorage.java380
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/ReferenceInputStream.java42
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/protocol/bundle/BundleURLConnection.java242
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/protocol/bundle/Handler.java103
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/protocol/reference/Handler.java63
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/protocol/reference/ReferenceURLConnection.java109
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFile.java536
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileInputStream.java101
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileOutputStream.java141
-rw-r--r--bundles/org.eclipse.osgi/eclipseAdaptor/src/META-INF/ADAPTOR.MF3
-rw-r--r--bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/CachedManifest.java64
-rw-r--r--bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptor.java318
-rw-r--r--bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseBundleData.java353
-rw-r--r--bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseClassLoader.java76
-rw-r--r--bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseElementFactory.java20
-rw-r--r--bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseStarter.java535
-rw-r--r--bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EnvironmentInfo.java152
-rw-r--r--bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/Semaphore.java62
-rw-r--r--bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/framework/stats/BundleStats.java145
-rw-r--r--bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/framework/stats/ClassStats.java126
-rw-r--r--bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/framework/stats/ClassloaderStats.java224
-rw-r--r--bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/framework/stats/ResourceBundleStats.java123
-rw-r--r--bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/framework/stats/StatsManager.java108
-rw-r--r--bundles/org.eclipse.osgi/launch/.cvsignore4
-rw-r--r--bundles/org.eclipse.osgi/launch/.options11
-rw-r--r--bundles/org.eclipse.osgi/launch/DevFramework.launch16
-rw-r--r--bundles/org.eclipse.osgi/launch/EclipseFramework.launch16
-rw-r--r--bundles/org.eclipse.osgi/launch/osgi.properties116
-rw-r--r--bundles/org.eclipse.osgi/osgi/ee.foundation.jarbin0 -> 521334 bytes
-rw-r--r--bundles/org.eclipse.osgi/osgi/ee.minimum.jarbin0 -> 298251 bytes
-rw-r--r--bundles/org.eclipse.osgi/osgi/osgi-r3-jdk131-notsigned.jarbin0 -> 323815 bytes
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/copyright.txt64
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/environment/Constants.java122
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/environment/DebugOptions.java8
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/environment/EnvironmentInfo.java79
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/resolver/BundleDelta.java72
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/resolver/BundleDescription.java146
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/resolver/BundleSpecification.java14
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/resolver/HostSpecification.java11
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/resolver/PackageSpecification.java11
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/resolver/PlatformAdmin.java46
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/resolver/Resolver.java70
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/resolver/State.java265
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/resolver/StateChangeEvent.java19
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/resolver/StateChangeListener.java17
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/resolver/StateDelta.java28
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/resolver/StateObjectFactory.java28
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/resolver/Version.java520
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/eclipse/osgi/service/resolver/VersionConstraint.java31
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/AdminPermission.java213
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/Bundle.java693
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/BundleActivator.java92
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/BundleContext.java643
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/BundleEvent.java159
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/BundleException.java84
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/BundleListener.java57
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/BundlePermission.java596
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/Configurable.java61
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/Constants.java564
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/Filter.java109
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/FrameworkEvent.java181
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/FrameworkListener.java58
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/InvalidSyntaxException.java78
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/PackagePermission.java572
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/ServiceEvent.java139
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/ServiceFactory.java96
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/ServiceListener.java66
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/ServicePermission.java548
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/ServiceReference.java115
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/ServiceRegistration.java112
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/SynchronousBundleListener.java55
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/service/packageadmin/ExportedPackage.java101
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/service/packageadmin/PackageAdmin.java164
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/service/permissionadmin/PermissionAdmin.java133
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/service/permissionadmin/PermissionInfo.java453
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/service/startlevel/StartLevel.java237
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/service/url/AbstractURLStreamHandlerService.java163
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/service/url/URLConstants.java47
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/service/url/URLStreamHandlerService.java96
-rw-r--r--bundles/org.eclipse.osgi/osgi/src/org/osgi/service/url/URLStreamHandlerSetter.java65
-rw-r--r--bundles/org.eclipse.osgi/plugin.xml24
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/dependencies/IDependency.java25
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/dependencies/IDependencySystem.java55
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/dependencies/IElement.java25
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/dependencies/IElementChange.java35
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/dependencies/IElementSet.java60
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/dependencies/IMatchRule.java19
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/dependencies/IResolutionDelta.java23
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/dependencies/ISelectionPolicy.java31
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/internal/dependencies/Assert.java52
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/internal/dependencies/AssertionFailedException.java34
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/internal/dependencies/ComputeNodeOrder.java521
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/internal/dependencies/Dependency.java83
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/internal/dependencies/DependencySystem.java312
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/internal/dependencies/Element.java65
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/internal/dependencies/ElementChange.java64
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/internal/dependencies/ElementSet.java251
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/internal/dependencies/IElementSetVisitor.java24
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/internal/dependencies/ResolutionDelta.java77
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/internal/dependencies/ResolutionVisitor.java66
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/internal/dependencies/SatisfactionVisitor.java71
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/internal/dependencies/SelectionVisitor.java56
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/core/internal/dependencies/SimpleSelectionPolicy.java36
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BundleDeltaImpl.java58
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BundleDescriptionImpl.java202
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BundleSpecificationImpl.java30
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/Eclipse21SelectionPolicy.java107
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/Eclipse30SelectionPolicy.java130
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/HostSpecificationImpl.java28
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/PackageSpecificationImpl.java26
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ResolverHelper.java157
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ResolverImpl.java190
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateBuilder.java127
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateDeltaImpl.java89
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateImpl.java336
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateManager.java114
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateObjectFactoryImpl.java129
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateReader.java170
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateWriter.java164
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/VersionConstraintImpl.java84
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/debug/Debug.java166
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/eventmgr/EventListeners.java72
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/eventmgr/EventManager.java128
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/eventmgr/EventQueue.java115
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/eventmgr/EventSource.java44
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/eventmgr/EventThread.java190
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/eventmgr/ListenerList.java164
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/core/ExternalMessages.properties78
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/core/Msg.java41
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFile.java536
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileInputStream.java101
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileOutputStream.java141
263 files changed, 50604 insertions, 0 deletions
diff --git a/bundles/org.eclipse.osgi.services/.classpath b/bundles/org.eclipse.osgi.services/.classpath
new file mode 100644
index 000000000..6c5aa836e
--- /dev/null
+++ b/bundles/org.eclipse.osgi.services/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry exported="true" sourcepath="servicessrc.zip" kind="lib" path="services.jar"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.osgi.services/.cvsignore b/bundles/org.eclipse.osgi.services/.cvsignore
new file mode 100644
index 000000000..ba077a403
--- /dev/null
+++ b/bundles/org.eclipse.osgi.services/.cvsignore
@@ -0,0 +1 @@
+bin
diff --git a/bundles/org.eclipse.osgi.services/.project b/bundles/org.eclipse.osgi.services/.project
new file mode 100644
index 000000000..3c3b0970f
--- /dev/null
+++ b/bundles/org.eclipse.osgi.services/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.osgi.services</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.osgi.services/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi.services/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..36a3f4eeb
--- /dev/null
+++ b/bundles/org.eclipse.osgi.services/META-INF/MANIFEST.MF
@@ -0,0 +1,20 @@
+Manifest-Version: 1.0
+Bundle-Name: OSGi-Service-Interfaces
+Bundle-GlobalName: org.eclipse.osgi.services
+Bundle-Version: 3.0
+Bundle-Description: OSGi Service Platform Release 3 Service Interfaces
+ and Classes
+Bundle-Vendor: Eclipse
+Bundle-DocUrl: http://www.eclipse.org
+Bundle-ContactAddress: www.eclipse.org
+Bundle-Copyright: Copyright (c) The Open Services Gateway Initiative (
+ 2001, 2003). All Rights Reserved.
+Bundle-ClassPath: services.jar
+Export-Package: org.osgi.service.cm; specification-version=1.1,
+ org.osgi.service.device; specification-version=1.1,
+ org.osgi.service.log; specification-version=1.2,
+ org.osgi.service.metatype; specification-version=1.0,
+ org.osgi.service.prefs; specification-version=1.0,
+ org.osgi.service.useradmin; specification-version=1.0,
+ org.osgi.service.wireadmin; specification-version=1.0
+Import-Package: org.osgi.framework; specification-version=1.2
diff --git a/bundles/org.eclipse.osgi.services/about.html b/bundles/org.eclipse.osgi.services/about.html
new file mode 100644
index 000000000..9db411aab
--- /dev/null
+++ b/bundles/org.eclipse.osgi.services/about.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<html>
+<head>
+<title>About</title>
+<meta http-equiv=Content-Type content="text/html; charset=ISO-8859-1">
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>20th June, 2002</p>
+<h3>License</h3>
+<p>Eclipse.org makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the
+Common Public License Version 1.0 (&quot;CPL&quot;). A copy of the CPL is available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>.
+For purposes of the CPL, &quot;Program&quot; will mean the Content.</p>
+
+<h3>Contributions</h3>
+
+<p>If this Content is licensed to you under the terms and conditions of the CPL, any Contributions, as defined in the CPL, uploaded, submitted, or otherwise
+made available to Eclipse.org, members of Eclipse.org and/or the host of Eclipse.org web site, by you that relate to such
+Content are provided under the terms and conditions of the CPL and can be made available to others under the terms of the CPL.</p>
+
+<p>If this Content is licensed to you under license terms and conditions other than the CPL (&quot;Other License&quot;), any modifications, enhancements and/or
+other code and/or documentation (&quot;Modifications&quot;) uploaded, submitted, or otherwise made available to Eclipse.org, members of Eclipse.org and/or the
+host of Eclipse.org, by you that relate to such Content are provided under terms and conditions of the Other License and can be made available
+to others under the terms of the Other License. In addition, with regard to Modifications for which you are the copyright holder, you are also
+providing the Modifications under the terms and conditions of the CPL and such Modifications can be made available to others under the terms of
+the CPL.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/bundles/org.eclipse.osgi.services/build.properties b/bundles/org.eclipse.osgi.services/build.properties
new file mode 100644
index 000000000..72666c7d0
--- /dev/null
+++ b/bundles/org.eclipse.osgi.services/build.properties
@@ -0,0 +1,6 @@
+bin.includes = plugin.xml,\
+ services.jar,\
+ about.html,\
+ META-INF/
+src.includes = *.zip,\
+ about.html
diff --git a/bundles/org.eclipse.osgi.services/plugin.xml b/bundles/org.eclipse.osgi.services/plugin.xml
new file mode 100644
index 000000000..b0acc2a61
--- /dev/null
+++ b/bundles/org.eclipse.osgi.services/plugin.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin
+ id="org.eclipse.osgi.services"
+ name="org.eclipse.osgi.services"
+ version="1.0.0">
+
+ <runtime>
+ <library name="services.jar">
+ <export name="*"/>
+ </library>
+ </runtime>
+
+</plugin>
diff --git a/bundles/org.eclipse.osgi.services/services.jar b/bundles/org.eclipse.osgi.services/services.jar
new file mode 100644
index 000000000..fe22c9acb
--- /dev/null
+++ b/bundles/org.eclipse.osgi.services/services.jar
Binary files differ
diff --git a/bundles/org.eclipse.osgi.services/servicessrc.zip b/bundles/org.eclipse.osgi.services/servicessrc.zip
new file mode 100644
index 000000000..3474afde4
--- /dev/null
+++ b/bundles/org.eclipse.osgi.services/servicessrc.zip
Binary files differ
diff --git a/bundles/org.eclipse.osgi.util/.classpath b/bundles/org.eclipse.osgi.util/.classpath
new file mode 100644
index 000000000..e9a51753e
--- /dev/null
+++ b/bundles/org.eclipse.osgi.util/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry exported="true" sourcepath="utilsrc.zip" kind="lib" path="util.jar"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.osgi.util/.cvsignore b/bundles/org.eclipse.osgi.util/.cvsignore
new file mode 100644
index 000000000..ba077a403
--- /dev/null
+++ b/bundles/org.eclipse.osgi.util/.cvsignore
@@ -0,0 +1 @@
+bin
diff --git a/bundles/org.eclipse.osgi.util/.project b/bundles/org.eclipse.osgi.util/.project
new file mode 100644
index 000000000..2d0ce3af1
--- /dev/null
+++ b/bundles/org.eclipse.osgi.util/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.osgi.util</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.osgi.util/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi.util/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..3788b03f5
--- /dev/null
+++ b/bundles/org.eclipse.osgi.util/META-INF/MANIFEST.MF
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Bundle-Name: OSGi-Utility-Classes
+Bundle-GlobalName: org.eclipse.osgi.util
+Bundle-Version: 3.0
+Bundle-Description: OSGi Service Platform Release 3 Utility Classes
+Bundle-Vendor: Eclipse
+Bundle-DocUrl: http://www.eclipse.org
+Bundle-ContactAddress: www.eclipse.org
+Bundle-Copyright: Copyright (c) The Open Services Gateway Initiative (
+ 2001, 2003). All Rights Reserved.
+Bundle-ClassPath: util.jar
+Export-Package: org.osgi.util.tracker; specification-version=1.2,
+ org.osgi.util.measurement; specification-version=1.0,
+ org.osgi.util.position; specification-version=1.0,
+ org.osgi.util.xml; specification-version=1.0
+Import-Package: org.osgi.framework; specification-version=1.1
+Build-Information: ${build-information}
diff --git a/bundles/org.eclipse.osgi.util/about.html b/bundles/org.eclipse.osgi.util/about.html
new file mode 100644
index 000000000..9db411aab
--- /dev/null
+++ b/bundles/org.eclipse.osgi.util/about.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<html>
+<head>
+<title>About</title>
+<meta http-equiv=Content-Type content="text/html; charset=ISO-8859-1">
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>20th June, 2002</p>
+<h3>License</h3>
+<p>Eclipse.org makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the
+Common Public License Version 1.0 (&quot;CPL&quot;). A copy of the CPL is available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>.
+For purposes of the CPL, &quot;Program&quot; will mean the Content.</p>
+
+<h3>Contributions</h3>
+
+<p>If this Content is licensed to you under the terms and conditions of the CPL, any Contributions, as defined in the CPL, uploaded, submitted, or otherwise
+made available to Eclipse.org, members of Eclipse.org and/or the host of Eclipse.org web site, by you that relate to such
+Content are provided under the terms and conditions of the CPL and can be made available to others under the terms of the CPL.</p>
+
+<p>If this Content is licensed to you under license terms and conditions other than the CPL (&quot;Other License&quot;), any modifications, enhancements and/or
+other code and/or documentation (&quot;Modifications&quot;) uploaded, submitted, or otherwise made available to Eclipse.org, members of Eclipse.org and/or the
+host of Eclipse.org, by you that relate to such Content are provided under terms and conditions of the Other License and can be made available
+to others under the terms of the Other License. In addition, with regard to Modifications for which you are the copyright holder, you are also
+providing the Modifications under the terms and conditions of the CPL and such Modifications can be made available to others under the terms of
+the CPL.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/bundles/org.eclipse.osgi.util/build.properties b/bundles/org.eclipse.osgi.util/build.properties
new file mode 100644
index 000000000..f110ed9b2
--- /dev/null
+++ b/bundles/org.eclipse.osgi.util/build.properties
@@ -0,0 +1,6 @@
+bin.includes = plugin.xml,\
+ util.jar,\
+ about.html,\
+ META-INF/
+src.includes = *.zip,\
+ about.html
diff --git a/bundles/org.eclipse.osgi.util/plugin.xml b/bundles/org.eclipse.osgi.util/plugin.xml
new file mode 100644
index 000000000..1b9d43dfe
--- /dev/null
+++ b/bundles/org.eclipse.osgi.util/plugin.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin
+ id="org.eclipse.osgi.util"
+ name="org.eclipse.osgi.util"
+ version="1.0.0">
+
+ <runtime>
+ <library name="util.jar">
+ <export name="*"/>
+ </library>
+ </runtime>
+
+</plugin>
diff --git a/bundles/org.eclipse.osgi.util/util.jar b/bundles/org.eclipse.osgi.util/util.jar
new file mode 100644
index 000000000..3a80ae0aa
--- /dev/null
+++ b/bundles/org.eclipse.osgi.util/util.jar
Binary files differ
diff --git a/bundles/org.eclipse.osgi.util/utilsrc.zip b/bundles/org.eclipse.osgi.util/utilsrc.zip
new file mode 100644
index 000000000..afa095392
--- /dev/null
+++ b/bundles/org.eclipse.osgi.util/utilsrc.zip
Binary files differ
diff --git a/bundles/org.eclipse.osgi/.classpath b/bundles/org.eclipse.osgi/.classpath
new file mode 100644
index 000000000..d85b7fc4f
--- /dev/null
+++ b/bundles/org.eclipse.osgi/.classpath
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="console/src"/>
+ <classpathentry kind="src" path="core/adaptor"/>
+ <classpathentry kind="src" path="core/framework"/>
+ <classpathentry kind="src" path="defaultAdaptor/src"/>
+ <classpathentry kind="src" path="eclipseAdaptor/src"/>
+ <classpathentry kind="src" path="osgi/src"/>
+ <classpathentry kind="src" path="resolver/src"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="src" path="/org.eclipse.osgi.services"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.osgi/.cvsignore b/bundles/org.eclipse.osgi/.cvsignore
new file mode 100644
index 000000000..533dc387a
--- /dev/null
+++ b/bundles/org.eclipse.osgi/.cvsignore
@@ -0,0 +1,9 @@
+bin
+temp.folder
+build.xml
+console.jar
+core.jar
+defaultAdaptor.jar
+eclipseAdaptor.jar
+osgi.jar
+resolver.jar
diff --git a/bundles/org.eclipse.osgi/.project b/bundles/org.eclipse.osgi/.project
new file mode 100644
index 000000000..ffcb87342
--- /dev/null
+++ b/bundles/org.eclipse.osgi/.project
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.osgi</name>
+ <comment></comment>
+ <projects>
+ <project>org.eclipse.osgi.services</project>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.osgi/build.properties b/bundles/org.eclipse.osgi/build.properties
new file mode 100644
index 000000000..f10d04561
--- /dev/null
+++ b/bundles/org.eclipse.osgi/build.properties
@@ -0,0 +1,13 @@
+bin.includes = plugin.properties, plugin.xml, *.jar, about.html, META-INF/MANIFEST.MF
+
+jars.compile.order = osgi.jar, core.jar, resolver.jar, defaultAdaptor.jar, eclipseAdaptor.jar, console.jar
+
+source.osgi.jar = osgi/src
+source.core.jar = core/adaptor/, core/framework/
+source.defaultAdaptor.jar = defaultAdaptor/src/
+source.eclipseAdaptor.jar = eclipseAdaptor/src/
+source.console.jar = console/src/
+source.resolver.jar = resolver/src/
+
+extra.core.jar = ../org.eclipse.osgi.services/services.jar
+extra.console.jar = ../org.eclipse.osgi.services/services.jar
diff --git a/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/ConsoleMessages.properties b/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/ConsoleMessages.properties
new file mode 100644
index 000000000..0a554d848
--- /dev/null
+++ b/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/ConsoleMessages.properties
@@ -0,0 +1,148 @@
+###############################################################################
+# Copyright (c) 2003 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Common Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/cpl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+
+#External Messages for EN locale
+CONSOLE_PROMPT=osgi>
+CONSOLE_ID=id
+CONSOLE_TYPE=Type
+CONSOLE_LOCATION=location
+CONSOLE_STARTLEVEL=start level
+CONSOLE_MORE=-- More...Press Enter to Continue...
+CONSOLE_HELP_CONTROLLING_CONSOLE_HEADING=---Controlling the Console---
+CONSOLE_HELP_MORE=More prompt for console output
+CONSOLE_HELP_DISCONNECT=Disconnects from telnet session
+CONSOLE_CONFIRM_MORE=Use 'more' prompt?
+CONSOLE_MORE_ENTER_LINES=Enter maximum number of lines to scroll:
+CONSOLE_CONFIRM_DISCONNECT=Disconnect from console?
+CONSOLE_CONFIRM=Confirm
+CONSOLE_CONFIRM_VALUES=y/n; default=
+CONSOLE_Y=y
+CONSOLE_N=n
+CONSOLE_ERROR_READING_RESOURCE=Error reading {0}
+CONSOLE_RESOURCE_NOT_IN_BUNDLE={0} not found in {1}
+CONSOLE_NESTED_EXCEPTION=Nested Exception:
+CONSOLE_PROMPT_DEFAULT=default
+CONSOLE_INVALID_INPUT=Invalid input.
+CONSOLE_TOO_MUCH_INVALID_INPUT=Too much invalid input.
+CONSOLE_LINES_TO_SCROLL_NEGATIVE_ERROR=Lines to scroll is set to a negative number
+CONSOLE_HELP_VALID_COMMANDS_HEADER=Valid commands:
+CONSOLE_HELP_CONTROLLING_FRAMEWORK_HEADER=Controlling the OSGi framework
+CONSOLE_HELP_LAUNCH_COMMAND_DESCRIPTION=start the OSGi Framework
+CONSOLE_HELP_SHUTDOWN_COMMAND_DESCRIPTION=shutdown the OSGi Framework
+CONSOLE_HELP_CLOSE_COMMAND_DESCRIPTION=shutdown and exit
+CONSOLE_HELP_EXIT_COMMAND_DESCRIPTION=exit immediately (System.exit)
+CONSOLE_HELP_GC_COMMAND_DESCRIPTION=perform a garbage collection
+CONSOLE_HELP_INIT_COMMAND_DESCRIPTION=uninstall all bundles
+CONSOLE_HELP_SETPROP_COMMAND_DESCRIPTION=set the OSGi property
+CONSOLE_HELP_CONTROLLING_BUNDLES_HEADER=Controlling Bundles
+CONSOLE_HELP_INSTALL_COMMAND_DESCRIPTION=install and optionally start bundle from the given URL
+CONSOLE_HELP_UNINSTALL_COMMAND_DESCRIPTION=uninstall the specified bundle(s)
+CONSOLE_HELP_START_COMMAND_DESCRIPTION=start the specified bundle(s)
+CONSOLE_HELP_STOP_COMMAND_DESCRIPTION=stop the specified bundle(s)
+CONSOLE_HELP_REFRESH_COMMAND_DESCRIPTION=refresh the packages of the specified bundles
+CONSOLE_HELP_UPDATE_COMMAND_DESCRIPTION=update the specified bundle(s)
+CONSOLE_HELP_DISPLAYING_STATUS_HEADER=Displaying Status
+CONSOLE_HELP_STATUS_COMMAND_DESCRIPTION=display installed bundles and registered services
+CONSOLE_HELP_SS_COMMAND_DESCRIPTION=display installed bundles (short status)
+CONSOLE_HELP_SERVICES_COMMAND_DESCRIPTION=display registered service details
+CONSOLE_HELP_PACKAGES_COMMAND_DESCRIPTION=display imported/exported package details
+CONSOLE_HELP_BUNDLES_COMMAND_DESCRIPTION=display details for all installed bundles
+CONSOLE_HELP_BUNDLE_COMMAND_DESCRIPTION=display details for the specified bundle(s)
+CONSOLE_HELP_HEADERS_COMMAND_DESCRIPTION=print bundle headers
+CONSOLE_HELP_PROPS_COMMAND_DESCRIPTION=display System properties
+CONSOLE_HELP_THREADS_COMMAND_DESCRIPTION=display threads and thread groups
+CONSOLE_HELP_LOG_COMMAND_DESCRIPTION=display log entries
+CONSOLE_HELP_EXTRAS_HEADER=Extras
+CONSOLE_HELP_EXEC_COMMAND_DESCRIPTION=execute a command in a separate process and wait
+CONSOLE_HELP_FORK_COMMAND_DESCRIPTION=execute a command in a separate process
+CONSOLE_HELP_KEYVALUE_ARGUMENT_DESCRIPTION=<key>=<value>
+CONSOLE_HELP_FILTER_ARGUMENT_DESCRIPTION={filter}
+CONSOLE_HELP_PACKAGES_ARGUMENT_DESCRIPTION={<pkgname>|<id>|<location>}
+CONSOLE_HELP_IDLOCATION_ARGUMENT_DESCRIPTION=(<id>|<location>)
+CONSOLE_HELP_OPTIONAL_IDLOCATION_ARGUMENT_DESCRIPTION={(<id>|<location>)}
+CONSOLE_HELP_COMMAND_ARGUMENT_DESCRIPTION=<command>
+CONSOLE_NO_BUNDLE_SPECIFIED_ERROR=No bundle(s) specified!
+CONSOLE_NOTHING_TO_INSTALL_ERROR=Nothing to install!
+CONSOLE_NO_INSTALLED_BUNDLES_ERROR=No installed bundles.
+CONSOLE_BUNDLE_ID_MESSAGE=Bundle id is
+CONSOLE_FRAMEWORK_IS_LAUNCHED_MESSAGE=Framework is launched.
+CONSOLE_FRAMEWORK_IS_SHUTDOWN_MESSAGE=Framework is shutdown.
+CONSOLE_ID_MESSAGE=Id={0}
+CONSOLE_BUNDLE_LOCATION_MESSAGE=Bundle Location
+CONSOLE_STATE_BUNDLE_FILE_NAME_HEADER=State Bundle File Name
+CONSOLE_REGISTERED_SERVICES_MESSAGE=Registered Services
+CONSOLE_REGISTERED_BY_BUNDLE_MESSAGE=Registered by bundle:
+CONSOLE_BUNDLES_USING_SERVICE_MESSAGE=Bundles using service:
+CONSOLE_NO_BUNDLES_USING_SERVICE_MESSAGE=No bundles using service.
+CONSOLE_NO_REGISTERED_SERVICES_MESSAGE=No registered services.
+CONSOLE_NO_EXPORTED_PACKAGES_MESSAGE=No exported packages
+CONSOLE_NO_IMPORTED_PACKAGES_MESSAGE=No imported packages
+CONSOLE_REMOVAL_PENDING_MESSAGE=removal pending
+CONSOLE_IMPORTS_MESSAGE=imports
+CONSOLE_STALE_MESSAGE=stale
+CONSOLE_NO_EXPORTED_PACKAGES_NO_PACKAGE_ADMIN_MESSAGE=No exported packages [PackageAdmin service is not registered]
+CONSOLE_SERVICES_IN_USE_MESSAGE=Services in use:
+CONSOLE_NO_SERVICES_IN_USE_MESSAGE=No services in use.
+CONSOLE_STATUS_MESSAGE=Status={0}
+CONSOLE_DATA_ROOT_MESSAGE=Data Root={0}
+CONSOLE_EXPORTED_PACKAGES_MESSAGE=Exported packages
+CONSOLE_IMPORTED_PACKAGES_MESSAGE=Imported packages
+CONSOLE_EXPORTED_REMOVAL_PENDING_MESSAGE=[exported(removal pending)]
+CONSOLE_EXPORTED_MESSAGE=[exported]
+CONSOLE_STALE_MESSAGE=stale
+CONSOLE_DEBUG_MESSAGE=Debug
+CONSOLE_INFO_MESSAGE=Info
+CONSOLE_WARNING_MESSAGE=Warn
+CONSOLE_ERROR_MESSAGE=Error
+CONSOLE_LOGSERVICE_NOT_REGISTERED_MESSAGE=The LogReaderService is not registered.
+CONSOLE_FREE_MEMORY_BEFORE_GARBAGE_COLLECTION_MESSAGE=Free memory before GC:
+CONSOLE_FREE_MEMORY_AFTER_GARBAGE_COLLECTION_MESSAGE=Free memory after GC:
+CONSOLE_MEMORY_GAINED_WITH_GARBAGE_COLLECTION_MESSAGE=Memory gained with GC:
+CONSOLE_FRAMEWORK_LAUNCHED_PLEASE_SHUTDOWN_MESSAGE=Framework is launched. Please shutdown framework first.
+CONSOLE_INVALID_BUNDLE_SPECIFICATION_ERROR=Invalid bundle specification.
+CONSOLE_CAN_NOT_REFRESH_NO_PACKAGE_ADMIN_ERROR=Cannot refresh [PackageAdmin service is not registered]
+CONSOLE_CAN_NOT_USE_STARTLEVEL_NO_STARTLEVEL_SVC_ERROR=Cannot use Startlevel commands [Startlevel service is not registered]
+CONSOLE_NO_COMMAND_SPECIFIED_ERROR=No command specified
+CONSOLE_EXECUTED_RESULT_CODE_MESSAGE=Executed ({0}); result code = {1}
+CONSOLE_STARTED_IN_MESSAGE=Started({0}) in {1}
+CONSOLE_BUNDLE_HEADERS_TITLE=Bundle headers:
+CONSOLE_SYSTEM_PROPERTIES_TITLE=System properties:
+CONSOLE_NO_PARAMETERS_SPECIFIED_TITLE=No parameters specified:
+CONSOLE_SETTING_PROPERTIES_TITLE=Setting Properties:
+CONSOLE_STATE_BUNDLE_TITLE=State Bundle
+CONSOLE_THREADGROUP_TITLE=ThreadGroupType: Name: ParentGroup: MaxP: Threads:
+CONSOLE_THREADTYPE_TITLE=ThreadType: Name: ThreadGroup: Prio:
+CONSOLE_CANNOT_FIND_BUNDLE_ERROR=Cannot find bundle {0}
+CONSOLE_INSTALLED_MESSAGE=INSTALLED
+CONSOLE_UNINSTALLED_MESSAGE=UNINSTALLED
+CONSOLE_RESOLVED_MESSAGE=RESOLVED
+CONSOLE_STARTING_MESSAGE=STARTING
+CONSOLE_STOPPING_MESSAGE=STOPPING
+CONSOLE_ACTIVE_MESSAGE=ACTIVE
+CONSOLE_LISTENING_ON_PORT=Listening on port {0} ...
+CONSOLE_TELNET_CONNECTION_REFUSED=Connection refused.
+CONSOLE_TELNET_CURRENTLY_USED=Telnet is currently being used.
+CONSOLE_TELNET_ONE_CLIENT_ONLY=Only one client can access at a time.
+STARTLEVEL_HELP_HEADING=Controlling Start Level
+STARTLEVEL_HELP_SL=display the start level for the specified bundle, or for the framework if no bundle specified
+STARTLEVEL_HELP_SETFWSL=set the framework start level
+STARTLEVEL_HELP_SETBSL=set the start level for the bundle(s)
+STARTLEVEL_HELP_SETIBSL=set the initial bundle start level
+STARTLEVEL_CANT_CHANGE_SYSTEMBUNDLE_STARTLEVEL=The System Bundle's start level can not be modified.
+STARTLEVEL_FRAMEWORK_ACTIVE_STARTLEVEL=Framework Active Start Level = {0}
+STARTLEVEL_NO_STARTLEVEL_GIVEN=No Start Level given.
+STARTLEVEL_NO_STARTLEVEL_OR_BUNDLE_GIVEN=No Bundle or Start Level given.
+STARTLEVEL_INITIAL_BUNDLE_STARTLEVEL=Initial Bundle Start Level = {0}
+STARTLEVEL_BUNDLE_STARTLEVEL=Bundle {0} Start Level = {1}
+STARTLEVEL_ARGUMENT_DESCRIPTION = <start level>
+STARTLEVEL_IDLOCATION_ARGUMENT_DESCRIPTION = <start level> (<id>|<location>)
+BUNDLE_CANT_FIND_BUNDLE=Can not find bundle.
+STARTLEVEL_POSITIVE_INTEGER=Startlevel must be a positive integer. \ No newline at end of file
diff --git a/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/ConsoleMsg.java b/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/ConsoleMsg.java
new file mode 100644
index 000000000..f7d4f8a0e
--- /dev/null
+++ b/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/ConsoleMsg.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import org.eclipse.osgi.framework.msg.MessageFormat;
+
+/**
+ * This class retrieves strings from a resource bundle
+ * and returns them, formatting them with MessageFormat
+ * when required.
+ * <p>
+ * It is used by the system classes to provide national
+ * language support, by looking up messages in the
+ * <code>
+ * org.eclipse.osgi.framework.internal.core.ExternalMessages
+ * </code>
+ * resource bundle. Note that if this file is not available,
+ * or an invalid key is looked up, or resource bundle support
+ * is not available, the key itself will be returned as the
+ * associated message. This means that the <em>KEY</em> should
+ * a reasonable human-readable (english) string.
+ */
+
+public class ConsoleMsg
+{
+
+ static public MessageFormat formatter;
+
+ // Attempt to load the message bundle.
+ static
+ {
+ formatter = new MessageFormat("org.eclipse.osgi.framework.internal.core.ConsoleMessages");
+ }
+}
diff --git a/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkCommandInterpreter.java b/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkCommandInterpreter.java
new file mode 100644
index 000000000..16318fc54
--- /dev/null
+++ b/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkCommandInterpreter.java
@@ -0,0 +1,529 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+
+import org.eclipse.osgi.framework.console.CommandInterpreter;
+import org.eclipse.osgi.framework.console.CommandProvider;
+;
+
+/**
+ * This class knows how to parse and execute the command line arguments to the FrameworkConsole.
+ * It attempts to pass the command to each registered CommandProvider until it finds one
+ * that knows what to do with it.
+ *
+ * FrameworkCommandInterpreter provides support for the "More" command which allows the operator to configure
+ * the number of lines to display before being prompted to continue.
+ *
+ * FrameworkCommandInterpreter provides several print methods which handle the "More" command.
+ */
+public class FrameworkCommandInterpreter implements CommandInterpreter {
+
+ /** The command line in StringTokenizer form */
+ private StringTokenizer tok;
+ /** The active CommandProviders */
+ private Object[] commandProviders;
+ /** The FrameworkConsole */
+ private FrameworkConsole con;
+ /** The stream to send output to */
+ private PrintWriter out;
+
+ /** Strings used to format other strings */
+ private String tab = "\t";
+ private String newline = "\r\n";
+
+
+ /**
+ * The maximum number of lines to print without user prompt.
+ * 0 means no user prompt is required, the window is scrollable.
+ */
+ protected static int maxLineCount;
+
+ /** The number of lines printed without user prompt.*/
+ protected int currentLineCount;
+
+ /**
+ * The constructor. It turns the cmdline string into a StringTokenizer and remembers
+ * the input parms.
+ */
+ public FrameworkCommandInterpreter(String cmdline, Object[] commandProviders, FrameworkConsole con) {
+ tok = new StringTokenizer(cmdline);
+ this.commandProviders = commandProviders;
+ this.con = con;
+ this.out = con.getWriter();
+ }
+
+ /**
+ Get the next argument in the input.
+
+ E.g. if the commandline is hello world, the _hello method
+ will get "world" as the first argument.
+
+ @return A string containing the next argument on the command line
+ */
+ public String nextArgument() {
+ if (tok==null || !tok.hasMoreElements()) {
+ return null;
+ }
+ String token = tok.nextToken();
+ //check for quotes
+ int index = token.indexOf('"');
+ if (index != -1)
+ {
+ //if we only have one quote, find the second quote
+ if(index == token.lastIndexOf('"'))
+ {
+ token += tok.nextToken("\"");
+ }
+ StringBuffer buf = new StringBuffer(token);
+
+ //strip quotes
+ while(index != -1)
+ {
+ buf.deleteCharAt(index);
+ token = buf.toString();
+ index = token.indexOf('"');
+ }
+ return buf.toString();
+ }
+ return (token);
+ }
+
+ /**
+ Execute a command line as if it came from the end user.
+
+ Searches the list of command providers using introspection until
+ it finds one that contains a matching method. It searches for a method
+ with the name "_cmd" where cmd is the command to execute. For example,
+ for a command of "launch" execute searches for a method called "_launch".
+
+ @param The name of the command to execute.
+ @return The object returned by the method executed.
+ */
+ public Object execute(String cmd) {
+ resetLineCount();
+ Object retval=null;
+ // handle "more" command here
+ if (cmd.equalsIgnoreCase("more")) {
+ try {
+ _more();
+ } catch (Exception e) {
+ printStackTrace(e);
+ }
+ return retval;
+ }
+ // handle "disconnect" command here
+ if (cmd.equalsIgnoreCase("disconnect") && con.getUseSocketStream()){
+ try{
+ _disconnect();
+ } catch (Exception e){
+ printStackTrace(e);
+ }
+ return retval;
+ }
+ Class[] parameterTypes = new Class[] { CommandInterpreter.class };
+ Object[] parameters = new Object[] { this };
+ boolean executed = false;
+ int size = commandProviders.length;
+ for (int i = 0; !executed && (i < size); i++)
+ {
+ try {
+ Object target = commandProviders[i];
+ Method method = target.getClass().getMethod( "_" + cmd, parameterTypes );
+ retval = method.invoke( target, parameters );
+ executed = true; // stop after the command has been found
+ }
+ catch( NoSuchMethodException ite ) {
+ // keep going - maybe another command provider will be able to execute this command
+ }
+ catch (InvocationTargetException ite) {
+ executed = true; // don't want to keep trying - we found the method but got an error
+ printStackTrace(ite.getTargetException());
+ }
+ catch( Exception ee ) {
+ executed = true; // don't want to keep trying - we got an error we don't understand
+ printStackTrace(ee);
+ }
+ }
+ // if no command was found to execute, display help for all registered command providers
+ if (!executed) {
+ for (int i = 0; i < size; i++)
+ {
+ try {
+ CommandProvider commandProvider = (CommandProvider) commandProviders[i];
+ out.print(commandProvider.getHelp());
+ out.flush();
+ } catch (Exception ee) {
+ printStackTrace(ee);
+ }
+ }
+ // call help for the more command provided by this class
+ out.print(getHelp());
+ out.flush();
+ }
+ return retval;
+ }
+
+ /**
+ * Answers the number of lines output to the console
+ * window should scroll without user interaction.
+ *
+ * @return The number of lines to scroll.
+ */
+ private int getMaximumLinesToScroll() {
+ return maxLineCount;
+ }
+
+ /**
+ * Sets the number of lines output to the console
+ * window will scroll without user interaction.
+ * <p>
+ * Note that this number does not include the line
+ * for the 'more' prompt itself.
+ * <p>
+ * If the number of lines is 0 then no 'more' prompt
+ * is disabled.
+ *
+ * @param lines the number of lines to scroll
+ */
+ private void setMaximumLinesToScroll(int lines) {
+ if (lines < 0) {
+ throw new IllegalArgumentException(ConsoleMsg.formatter.getString("CONSOLE_LINES_TO_SCROLL_NEGATIVE_ERROR"));
+ }
+
+ maxLineCount = lines;
+ }
+
+ /**
+ * Resets the line counter for the 'more' prompt.
+ */
+ private void resetLineCount() {
+ currentLineCount = 0;
+ }
+
+ /**
+ * Prints a string to the output medium (appended with newline character).
+ * <p>
+ * This method does not increment the line counter for the 'more' prompt.
+ *
+ * @param string the string to be printed
+ */
+ private void printline(Object o) {
+ print(o + newline);
+ }
+
+ /**
+ * Prints an object to the outputstream
+ *
+ * @param o the object to be printed
+ */
+ public void print(Object o) {
+ synchronized(out) {
+ check4More();
+ out.print(o);
+ out.flush();
+ }
+ }
+
+ /**
+ * Prints a empty line to the outputstream
+ */
+ public void println() {
+ println("");
+ }
+
+ /**
+ * Print a stack trace including nested exceptions.
+ * @param The offending exception
+ */
+ public void printStackTrace(Throwable t)
+ {
+ t.printStackTrace(out);
+
+ Method[] methods = t.getClass().getMethods();
+
+ int size = methods.length;
+ Class throwable = Throwable.class;
+
+ for (int i = 0; i < size; i++)
+ {
+ Method method = methods[i];
+
+ if (Modifier.isPublic(method.getModifiers()) &&
+ method.getName().startsWith("get") &&
+ throwable.isAssignableFrom(method.getReturnType()) &&
+ (method.getParameterTypes().length == 0))
+ {
+ try
+ {
+ Throwable nested = (Throwable) method.invoke(t, null);
+
+ if ((nested != null) && (nested != t))
+ {
+ out.println(ConsoleMsg.formatter.getString("CONSOLE_NESTED_EXCEPTION"));
+ printStackTrace(nested);
+ }
+ }
+ catch (IllegalAccessException e)
+ {
+ }
+ catch (InvocationTargetException e)
+ {
+ }
+ }
+ }
+ }
+
+ /**
+ * Prints an object to the output medium (appended with newline character).
+ * <p>
+ * If running on the target environment, the user is prompted with '--more'
+ * if more than the configured number of lines have been printed without user prompt.
+ * This enables the user of the program to have control over scrolling.
+ * <p>
+ * For this to work properly you should not embed "\n" etc. into the string.
+ *
+ * @param o the object to be printed
+ */
+ public void println(Object o) {
+ if(o == null)
+ {
+ return;
+ }
+ synchronized (out) {
+ check4More();
+ printline(o);
+ currentLineCount++;
+ currentLineCount += o.toString().length() / 80;
+ }
+ }
+
+ /**
+ * Prints the given dictionary sorted by keys.
+ *
+ * @param dic the dictionary to print
+ * @param title the header to print above the key/value pairs
+ */
+ public void printDictionary(Dictionary dic, String title) {
+ if (dic == null)
+ return;
+
+ int count = dic.size();
+ String[] keys = new String[count];
+ Enumeration enum = dic.keys();
+ int i = 0;
+ while (enum.hasMoreElements()) {
+ keys[i++] = (String) enum.nextElement();
+ }
+ Util.sort(keys);
+
+ if (title != null) {
+ println(title);
+ }
+ for (i = 0; i < count; i++) {
+ println(" " + keys[i] + " = " + dic.get(keys[i]));
+ }
+ println();
+ }
+
+ /**
+ * Prints the given bundle resource if it exists
+ *
+ * @param bundle the bundle containing the resource
+ * @param resource the resource to print
+ */
+ public void printBundleResource(Bundle bundle, String resource) {
+ URL entry=null;
+ try {
+ entry = bundle.getEntry(resource);
+ } catch (IOException e1) {
+ }
+ if (entry != null) {
+ try {
+ println(resource);
+ InputStream in = entry.openStream();
+ byte[] buffer = new byte[1024];
+ int read = 0;
+ try {
+ while ((read = in.read(buffer)) != -1)
+ print(new String(buffer, 0, read));
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {}
+ }
+ }
+ } catch (Exception e) {
+ System.err.println(ConsoleMsg.formatter.getString("CONSOLE_ERROR_READING_RESOURCE", resource));
+ }
+ } else {
+ println(ConsoleMsg.formatter.getString("CONSOLE_RESOURCE_NOT_IN_BUNDLE", resource, bundle.toString()));
+ }
+ }
+
+ /**
+ * Displays the more... prompt if the max line count has been reached
+ * and waits for the operator to hit enter.
+ *
+ * @param The Object to be printed - used to determine how many lines the object takes
+ */
+ private void check4More() {
+ int max = getMaximumLinesToScroll();
+ if (max > 0) {
+ if (currentLineCount >= max) {
+ out.print(ConsoleMsg.formatter.getString("CONSOLE_MORE"));
+ out.flush();
+ con.getInput(); // wait for user entry
+ resetLineCount(); //Reset the line counter for the 'more' prompt
+ }
+ }
+ }
+
+ /**
+ Answer a string (may be as many lines as you like) with help
+ texts that explain the command.
+ */
+ public String getHelp() {
+ StringBuffer help = new StringBuffer(256);
+ help.append(newline);
+ help.append(ConsoleMsg.formatter.getString("CONSOLE_HELP_CONTROLLING_CONSOLE_HEADING"));
+ help.append(newline);
+ help.append(tab);
+ help.append("more - ");
+ help.append(ConsoleMsg.formatter.getString("CONSOLE_HELP_MORE"));
+ if( con.getUseSocketStream() ){
+ help.append(newline);
+ help.append(tab);
+ help.append("disconnect - ");
+ help.append(ConsoleMsg.formatter.getString("CONSOLE_HELP_DISCONNECT"));
+ }
+ return help.toString();
+ }
+
+ /**
+ * Toggles the use of the more prompt for displayed output.
+ *
+ */
+ public void _more() throws Exception {
+ if (confirm(ConsoleMsg.formatter.getString("CONSOLE_CONFIRM_MORE"), true)) {
+ int lines = prompt(newline + ConsoleMsg.formatter.getString("CONSOLE_MORE_ENTER_LINES"), 24);
+ setMaximumLinesToScroll(lines);
+ } else {
+ setMaximumLinesToScroll(0);
+ }
+ }
+
+ private void _disconnect() throws Exception {
+ if( confirm(ConsoleMsg.formatter.getString("CONSOLE_CONFIRM_DISCONNECT"), true)){
+ con.disconnect();
+ }
+ }
+
+ /**
+ * Prompts the user for confirmation.
+ *
+ * @param string the message to present to the user to confirm
+ * @param defaultAnswer the default result
+ *
+ * @return <code>true</code> if the user confirms; <code>false</code> otherwise.
+ */
+ protected boolean confirm(String string, boolean defaultAnswer) {
+ synchronized (out) {
+ if (string.length() > 0) {
+ print(string);
+ } else {
+ print(ConsoleMsg.formatter.getString("CONSOLE_CONFIRM"));
+ }
+ print(" ("+ConsoleMsg.formatter.getString("CONSOLE_CONFIRM_VALUES"));
+ if (defaultAnswer) {
+ print(ConsoleMsg.formatter.getString("CONSOLE_Y") + ") ");
+ } else {
+ print(ConsoleMsg.formatter.getString("CONSOLE_N") + ") ");
+ }
+ }
+ String input = con.getInput();
+ resetLineCount();
+ if (input.length() == 0) {
+ return defaultAnswer;
+ }
+ return input.toLowerCase().charAt(0) == ConsoleMsg.formatter.getString("CONSOLE_Y").charAt(0);
+ }
+
+ /**
+ * Prompts the user for input from the input medium providing a default value.
+ *
+ * @param string the message to present to the user
+ * @param defaultAnswer the string to use as a default return value
+ *
+ * @return The user provided string or the defaultAnswer,
+ * if user provided string was empty.
+ */
+ protected String prompt(String string, String defaultAnswer) {
+ if (string.length() > 0) {
+ if (defaultAnswer.length() > 0) {
+ StringBuffer buf = new StringBuffer(256);
+ buf.append(string);
+ buf.append(" ");
+ buf.append(ConsoleMsg.formatter.getString("CONSOLE_PROMPT_DEFAULT"));
+ buf.append("=");
+ buf.append(defaultAnswer);
+ buf.append(") ");
+ print(buf.toString());
+ } else {
+ print(string);
+ }
+ }
+ String input = con.getInput();
+ resetLineCount();
+ if (input.length() > 0) {
+ return input;
+ }
+ return defaultAnswer;
+ }
+
+ /**
+ * Prompts the user for input of a positive integer.
+ *
+ * @param string the message to present to the user
+ * @param defaultAnswer the integer to use as a default return value
+ *
+ * @return The user provided integer or the defaultAnswer,
+ * if user provided an empty input.
+ */
+ protected int prompt(String string, int defaultAnswer) {
+ Integer i = new Integer(defaultAnswer);
+ int answer;
+ for (int j = 0; j < 3; j++) {
+ String s = prompt(string, i.toString());
+ try {
+ answer = Integer.parseInt(s);
+ if (answer >= 0) {
+ return answer;
+ }
+ } catch (NumberFormatException e) {}
+ println(ConsoleMsg.formatter.getString("CONSOLE_INVALID_INPUT"));
+ }
+ println(ConsoleMsg.formatter.getString("CONSOLE_TOO_MUCH_INVALID_INPUT"));
+ return defaultAnswer;
+ }
+}
diff --git a/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkCommandProvider.java b/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkCommandProvider.java
new file mode 100644
index 000000000..3f4471aa1
--- /dev/null
+++ b/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkCommandProvider.java
@@ -0,0 +1,1636 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.security.ProtectionDomain;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.eclipse.osgi.framework.console.CommandInterpreter;
+import org.eclipse.osgi.framework.console.CommandProvider;
+import org.eclipse.osgi.framework.launcher.Launcher;
+import org.osgi.framework.BundleException;
+
+/**
+ * This class provides methods to execute commands from the command line. It registers
+ * itself as a CommandProvider so it can be invoked by a CommandInterpreter. The
+ * FrameworkCommandProvider registers itself with the highest ranking (Integer.MAXVALUE) so it will always be
+ * called first. Other CommandProviders should register with lower rankings.
+ *
+ * The commands provided by this class are:
+ ---Controlling the OSGi framework---
+ close - shutdown and exit
+ exit - exit immediately (System.exit)
+ gc - perform a garbage collection
+ init - uninstall all bundles
+ launch - start the Service Management Framework
+ setprop <key>=<value> - set the OSGI property
+ shutdown - shutdown the Service Management Framework
+ ---Controlliing Bundles---
+ install <url> {s[tart]} - install and optionally start bundle from the given URL
+ refresh (<id>|<location>) - refresh the packages of the specified bundles
+ start (<id>|<location>) - start the specified bundle(s)
+ stop (<id>|<location>) - stop the specified bundle(s)
+ uninstall (<id>|<location>) - uninstall the specified bundle(s)
+ update (<id>|<location>|<*>) - update the specified bundle(s)
+ ---Displaying Status---
+ bundle (<id>|<location>) - display details for the specified bundle(s)
+ bundles - display details for all installed bundles
+ headers (<id>|<location>) - print bundle headers
+ packages {<pkgname>|<id>|<location>} - display imported/exported package details
+ props - display System properties
+ services {filter} - display registered service details
+ ss - display installed bundles (short status)
+ status - display installed bundles and registered services
+ threads - display threads and thread groups
+ ---Log Commands---
+ log {(<id>|<location>)} - display log entries
+ ---Extras---
+ exec <command> - execute a command in a separate process and wait
+ fork <command> - execute a command in a separate process
+ ---Controlling StartLevel---
+ sl {(<id>|<location>)} - display the start level for the specified bundle, or for the framework if no bundle specified
+ setfwsl <start level> - set the framework start level
+ setbsl <start level> (<id>|<location>) - set the start level for the bundle(s)
+ setibsl <start level> - set the initial bundle start level
+
+ *
+ * There is a method for each command which is named '_'+method. The methods are
+ * invoked by a CommandInterpreter's execute method.
+ */
+public class FrameworkCommandProvider implements CommandProvider {
+
+ /** An instance of the OSGi framework */
+ private OSGi osgi;
+ /** The system bundle context */
+ private org.osgi.framework.BundleContext context;
+ /** The start level implementation */
+ private StartLevelImpl slImpl;
+
+ /** Strings used to format other strings */
+ private String tab = "\t";
+ private String newline = "\r\n";
+
+ /**
+ * Constructor.
+ *
+ * It registers itself as a CommandProvider with the highest ranking possible.
+ *
+ * @param osgi The current instance of OSGi
+ */
+ public FrameworkCommandProvider(OSGi osgi) {
+ this.osgi = osgi;
+ context = osgi.getBundleContext();
+ slImpl = osgi.framework.startLevelImpl;
+ Dictionary props = new Hashtable();
+ props.put(Constants.SERVICE_RANKING, new Integer(Integer.MAX_VALUE));
+ context.registerService( CommandProvider.class.getName(), this, props );
+ }
+
+
+ /**
+ Answer a string (may be as many lines as you like) with help
+ texts that explain the command. This getHelp() method uses the
+ ConsoleMsg class to obtain the correct NLS data to display to the user.
+
+ @return The help string
+ */
+ public String getHelp() {
+ StringBuffer help = new StringBuffer(1024);
+ help.append(newline);
+ help.append(ConsoleMsg.formatter.getString("CONSOLE_HELP_VALID_COMMANDS_HEADER"));
+ help.append(newline);
+ addHeader("CONSOLE_HELP_CONTROLLING_FRAMEWORK_HEADER",help);
+ addCommand("launch","CONSOLE_HELP_LAUNCH_COMMAND_DESCRIPTION",help);
+ addCommand("shutdown","CONSOLE_HELP_SHUTDOWN_COMMAND_DESCRIPTION",help);
+ addCommand("close","CONSOLE_HELP_CLOSE_COMMAND_DESCRIPTION",help);
+ addCommand("exit","CONSOLE_HELP_EXIT_COMMAND_DESCRIPTION",help);
+ addCommand("gc","CONSOLE_HELP_GC_COMMAND_DESCRIPTION",help);
+ addCommand("init","CONSOLE_HELP_INIT_COMMAND_DESCRIPTION",help);
+ addCommand("setprop","CONSOLE_HELP_KEYVALUE_ARGUMENT_DESCRIPTION","CONSOLE_HELP_SETPROP_COMMAND_DESCRIPTION",help);
+ addHeader("CONSOLE_HELP_CONTROLLING_BUNDLES_HEADER",help);
+ addCommand("install","CONSOLE_HELP_INSTALL_COMMAND_DESCRIPTION",help);
+ addCommand("uninstall","CONSOLE_HELP_UNINSTALL_COMMAND_DESCRIPTION",help);
+ addCommand("start","CONSOLE_HELP_START_COMMAND_DESCRIPTION",help);
+ addCommand("stop","CONSOLE_HELP_STOP_COMMAND_DESCRIPTION",help);
+ addCommand("refresh","CONSOLE_HELP_REFRESH_COMMAND_DESCRIPTION",help);
+ addCommand("update","CONSOLE_HELP_UPDATE_COMMAND_DESCRIPTION",help);
+ addHeader("CONSOLE_HELP_DISPLAYING_STATUS_HEADER",help);
+ addCommand("status","CONSOLE_HELP_STATUS_COMMAND_DESCRIPTION",help);
+ addCommand("ss","CONSOLE_HELP_SS_COMMAND_DESCRIPTION",help);
+ addCommand("services","CONSOLE_HELP_FILTER_ARGUMENT_DESCRIPTION","CONSOLE_HELP_SERVICES_COMMAND_DESCRIPTION",help);
+ addCommand("packages","CONSOLE_HELP_PACKAGES_ARGUMENT_DESCRIPTION","CONSOLE_HELP_PACKAGES_COMMAND_DESCRIPTION",help);
+ addCommand("bundles","CONSOLE_HELP_BUNDLES_COMMAND_DESCRIPTION",help);
+ addCommand("bundle","CONSOLE_HELP_IDLOCATION_ARGUMENT_DESCRIPTION","CONSOLE_HELP_BUNDLE_COMMAND_DESCRIPTION",help);
+ addCommand("headers","CONSOLE_HELP_IDLOCATION_ARGUMENT_DESCRIPTION","CONSOLE_HELP_HEADERS_COMMAND_DESCRIPTION",help);
+ addCommand("log","CONSOLE_HELP_IDLOCATION_ARGUMENT_DESCRIPTION","CONSOLE_HELP_LOG_COMMAND_DESCRIPTION",help);
+ addHeader("CONSOLE_HELP_EXTRAS_HEADER",help);
+ addCommand("exec","CONSOLE_HELP_COMMAND_ARGUMENT_DESCRIPTION","CONSOLE_HELP_EXEC_COMMAND_DESCRIPTION",help);
+ addCommand("fork","CONSOLE_HELP_COMMAND_ARGUMENT_DESCRIPTION","CONSOLE_HELP_FORK_COMMAND_DESCRIPTION",help);
+ addHeader("STARTLEVEL_HELP_HEADING", help);
+ addCommand("sl", "CONSOLE_HELP_OPTIONAL_IDLOCATION_ARGUMENT_DESCRIPTION","STARTLEVEL_HELP_SL", help);
+ addCommand("setfwsl", "STARTLEVEL_ARGUMENT_DESCRIPTION", "STARTLEVEL_HELP_SETFWSL", help);
+ addCommand("setbsl", "STARTLEVEL_IDLOCATION_ARGUMENT_DESCRIPTION","STARTLEVEL_HELP_SETBSL",help);
+ addCommand("setibsl", "STARTLEVEL_ARGUMENT_DESCRIPTION", "STARTLEVEL_HELP_SETIBSL",help);
+ return help.toString();
+ }
+
+
+ /** Private helper method for getHelp. Formats the help headers. */
+ private void addHeader(String header, StringBuffer help)
+ {
+ help.append("---");
+ help.append(ConsoleMsg.formatter.getString(header));
+ help.append("---");
+ help.append(newline);
+ }
+
+ /** Private helper method for getHelp. Formats the command descriptions. */
+ private void addCommand(String command,String description,StringBuffer help)
+ {
+ help.append(tab);
+ help.append(command);
+ help.append(" - ");
+ help.append(ConsoleMsg.formatter.getString(description));
+ help.append(newline);
+ }
+
+ /** Private helper method for getHelp. Formats the command descriptions with command arguements. */
+ private void addCommand(String command,String parameters, String description,StringBuffer help)
+ {
+ help.append(tab);
+ help.append(command);
+ help.append(" ");
+ help.append(ConsoleMsg.formatter.getString(parameters));
+ help.append(" - ");
+ help.append(ConsoleMsg.formatter.getString(description));
+ help.append(newline);
+ }
+
+ /**
+ * Handle the exit command. Exit immediately (System.exit)
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _exit(CommandInterpreter intp) throws Exception
+ {
+ intp.println();
+ System.exit(0);
+ }
+
+ /**
+ * Handle the launch command. Start the OSGi framework.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _launch(CommandInterpreter intp) throws Exception
+ {
+ osgi.launch();
+ }
+
+ /**
+ * Handle the shutdown command. Shutdown the OSGi framework.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _shutdown(CommandInterpreter intp) throws Exception
+ {
+ osgi.shutdown();
+ }
+
+ /**
+ * Handle the start command's abbreviation. Invoke _start()
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _sta(CommandInterpreter intp) throws Exception
+ {
+ _start(intp);
+ }
+
+ /**
+ * Handle the start command. Start the specified bundle(s).
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _start(CommandInterpreter intp) throws Exception
+ {
+ String nextArg = intp.nextArgument();
+ if (nextArg==null) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_BUNDLE_SPECIFIED_ERROR"));
+ }
+ while (nextArg!=null) {
+ Bundle bundle = getBundleFromToken(intp, nextArg, true);
+ if (bundle != null) {
+ bundle.start();
+ }
+ nextArg = intp.nextArgument();
+ }
+ }
+
+ /**
+ * Handle the stop command's abbreviation. Invoke _stop()
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _sto(CommandInterpreter intp) throws Exception
+ {
+ _stop(intp);
+ }
+
+ /**
+ * Handle the stop command. Stop the specified bundle(s).
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _stop(CommandInterpreter intp) throws Exception
+ {
+ String nextArg = intp.nextArgument();
+ if (nextArg==null) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_BUNDLE_SPECIFIED_ERROR"));
+ }
+ while (nextArg!=null) {
+ Bundle bundle = getBundleFromToken(intp, nextArg, true);
+ if (bundle != null) {
+ bundle.stop();
+ }
+ nextArg = intp.nextArgument();
+ }
+ }
+
+ /**
+ * Handle the install command's abbreviation. Invoke _install()
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _i(CommandInterpreter intp) throws Exception
+ {
+ _install(intp);
+ }
+
+ /**
+ * Handle the install command. Install and optionally start bundle from the given URL\r\n"
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _install(CommandInterpreter intp) throws Exception
+ {
+ String url = intp.nextArgument();
+ if (url==null) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NOTHING_TO_INSTALL_ERROR"));
+ } else {
+ Bundle bundle = (Bundle)context.installBundle(url);
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_BUNDLE_ID_MESSAGE"));
+ intp.println(new Long(bundle.getBundleId()));
+
+ String nextArg = intp.nextArgument();
+ if (nextArg != null) {
+ String start = nextArg.toLowerCase();
+
+ if (Launcher.matchCommand("start", start, 1)) {
+ bundle.start();
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Handle the update command's abbreviation. Invoke _update()
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _up(CommandInterpreter intp) throws Exception
+ {
+ _update(intp);
+ }
+
+ /**
+ * Handle the update command. Update the specified bundle(s).
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _update(CommandInterpreter intp) throws Exception
+ {
+ String token = intp.nextArgument();
+ if (token==null) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_BUNDLE_SPECIFIED_ERROR"));
+ }
+ while (token!=null) {
+
+ if ("*".equals(token)) {
+ Bundle[] bundles = (Bundle[])context.getBundles();
+
+ int size = bundles.length;
+
+ if (size > 0) {
+ for (int i = 0; i < size; i++) {
+ Bundle bundle = bundles[i];
+
+ if (bundle.getBundleId() != 0) {
+ try {
+ bundle.update();
+ } catch (BundleException e) {
+ intp.printStackTrace(e);
+ }
+ }
+ }
+ } else {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_INSTALLED_BUNDLES_ERROR"));
+ }
+ } else {
+ Bundle bundle = getBundleFromToken(intp, token, true);
+ if (bundle != null) {
+ String source = intp.nextArgument();
+ try {
+ if (source != null) {
+ bundle.update(new URL(source).openStream());
+ }
+ else{
+ bundle.update();
+ }
+ } catch (BundleException e) {
+ intp.printStackTrace(e);
+ }
+ }
+ }
+ token = intp.nextArgument();
+ }
+ }
+
+
+ /**
+ * Handle the uninstall command's abbreviation. Invoke _uninstall()
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _un(CommandInterpreter intp) throws Exception
+ {
+ _uninstall(intp);
+ }
+
+ /**
+ * Handle the uninstall command. Uninstall the specified bundle(s).
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _uninstall(CommandInterpreter intp) throws Exception
+ {
+ String nextArg = intp.nextArgument();
+ if (nextArg==null) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_BUNDLE_SPECIFIED_ERROR"));
+ }
+ while (nextArg!=null) {
+ Bundle bundle = getBundleFromToken(intp, nextArg, true);
+ if (bundle != null) {
+ bundle.uninstall();
+ }
+ nextArg = intp.nextArgument();
+ }
+ }
+
+
+ /**
+ * Handle the status command's abbreviation. Invoke _status()
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _s(CommandInterpreter intp) throws Exception
+ {
+ _status(intp);
+ }
+
+ /**
+ * Handle the status command. Display installed bundles and registered services.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _status(CommandInterpreter intp) throws Exception
+ {
+ if (osgi.isActive()) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_FRAMEWORK_IS_LAUNCHED_MESSAGE"));
+ } else {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_FRAMEWORK_IS_SHUTDOWN_MESSAGE"));
+ }
+ intp.println();
+
+ Bundle[] bundles = (Bundle[])context.getBundles();
+ int size = bundles.length;
+
+ if (size == 0) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_INSTALLED_BUNDLES_ERROR"));
+ return;
+ }
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_ID"));
+ intp.print(tab);
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_BUNDLE_LOCATION_MESSAGE"));
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_STATE_BUNDLE_FILE_NAME_HEADER"));
+ for (int i = 0; i < size; i++) {
+ Bundle bundle = bundles[i];
+ intp.print(new Long(bundle.getBundleId()));
+ intp.print(tab);
+ intp.println(bundle.getLocation());
+ intp.print(" ");
+ intp.print(getStateName(bundle.getState()));
+ intp.println(bundle.bundledata);
+ }
+
+ ServiceReference[] services = (ServiceReference[])context.getServiceReferences(null, null);
+ if (services != null) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_REGISTERED_SERVICES_MESSAGE"));
+ size = services.length;
+ for (int i = 0; i < size; i++) {
+ intp.println(services[i]);
+ }
+ }
+ }
+
+
+ /**
+ * Handle the services command's abbreviation. Invoke _services()
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _se(CommandInterpreter intp) throws Exception
+ {
+ _services(intp);
+ }
+
+ /**
+ * Handle the services command. Display registered service details.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _services(CommandInterpreter intp) throws Exception
+ {
+ String filter = null;
+
+ String nextArg = intp.nextArgument();
+ if (nextArg!=null) {
+ StringBuffer buf = new StringBuffer();
+ while (nextArg!=null) {
+ buf.append(' ');
+ buf.append(nextArg);
+ nextArg = intp.nextArgument();
+ }
+ filter = buf.toString();
+ }
+
+ ServiceReference[] services = (ServiceReference[])context.getServiceReferences(null, filter);
+ if (services != null) {
+ int size = services.length;
+ if (size > 0) {
+ for (int j = 0; j < size; j++) {
+ ServiceReference service = services[j];
+ intp.println(service);
+ intp.print(" ");
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_REGISTERED_BY_BUNDLE_MESSAGE")); intp.print(" ");
+ intp.println(service.getBundle());
+ Bundle[] users = (Bundle[])service.getUsingBundles();
+ if (users != null) {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_BUNDLES_USING_SERVICE_MESSAGE"));
+ for (int k = 0; k < users.length; k++) {
+ intp.print(" ");
+ intp.println(users[k]);
+ }
+ } else {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_BUNDLES_USING_SERVICE_MESSAGE"));
+ }
+ }
+ return;
+ }
+ }
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_REGISTERED_SERVICES_MESSAGE"));
+ }
+
+
+ /**
+ * Handle the packages command's abbreviation. Invoke _packages()
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _p(CommandInterpreter intp) throws Exception
+ {
+ _packages(intp);
+ }
+
+ /**
+ * Handle the packages command. Display imported/exported package details.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _packages(CommandInterpreter intp) throws Exception
+ {
+ org.osgi.framework.Bundle bundle = null;
+
+ String token = intp.nextArgument();
+ if (token!=null) {
+ bundle = getBundleFromToken(intp, token, false);
+ }
+
+ org.osgi.framework.ServiceReference packageAdminRef = context.getServiceReference("org.osgi.service.packageadmin.PackageAdmin");
+ if (packageAdminRef != null) {
+ org.osgi.service.packageadmin.PackageAdmin packageAdmin = (org.osgi.service.packageadmin.PackageAdmin)context.getService(packageAdminRef);
+ if (packageAdmin != null) {
+ try {
+ org.osgi.service.packageadmin.ExportedPackage[] packages = null;
+
+ if ((token != null) && (bundle == null)) {
+ org.osgi.service.packageadmin.ExportedPackage pkg = packageAdmin.getExportedPackage(token);
+
+ if (pkg != null) {
+ packages = new org.osgi.service.packageadmin.ExportedPackage[] {pkg};
+ }
+ } else {
+ packages = packageAdmin.getExportedPackages(bundle);
+ }
+
+ if (packages == null) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_EXPORTED_PACKAGES_MESSAGE"));
+ } else {
+ for (int i = 0; i < packages.length; i++) {
+ org.osgi.service.packageadmin.ExportedPackage pkg = packages[i];
+ intp.print(pkg);
+
+ boolean removalPending = pkg.isRemovalPending();
+ if (removalPending) {
+ intp.print("(");
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_REMOVAL_PENDING_MESSAGE"));
+ intp.println(")");
+ }
+
+ org.osgi.framework.Bundle exporter = pkg.getExportingBundle();
+ if (exporter != null) {
+ intp.print("<");
+ intp.print(exporter);
+ intp.println(">");
+
+ org.osgi.framework.Bundle[] importers = pkg.getImportingBundles();
+ for (int j = 0; j < importers.length; j++) {
+ intp.print(" ");
+ intp.print(importers[j]);
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_IMPORTS_MESSAGE"));
+ }
+ } else {
+ intp.print("<");
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_STALE_MESSAGE"));
+ intp.println(">");
+ }
+
+ }
+ }
+ } finally {
+ context.ungetService(packageAdminRef);
+ }
+ }
+ } else {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_EXPORTED_PACKAGES_NO_PACKAGE_ADMIN_MESSAGE"));
+ }
+ }
+
+ /**
+ * Handle the bundles command. Display details for all installed bundles.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _bundles(CommandInterpreter intp) throws Exception
+ {
+ Bundle[] bundles = (Bundle[])context.getBundles();
+ int size = bundles.length;
+
+ if (size == 0) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_INSTALLED_BUNDLES_ERROR"));
+ return;
+ }
+
+ for (int i = 0; i < size; i++) {
+ Bundle bundle = bundles[i];
+ long id = bundle.getBundleId();
+ intp.println(bundle);
+ intp.print(" ");
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_ID_MESSAGE",String.valueOf(id)));
+ intp.print(", ");
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_STATUS_MESSAGE",getStateName(bundle.getState())));
+ if (id != 0) {
+ File dataRoot = osgi.framework.getDataFile(bundle, "");
+
+ String root = (dataRoot == null) ? null : dataRoot.getAbsolutePath();
+
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_DATA_ROOT_MESSAGE",root));
+ } else {
+ intp.println();
+ }
+
+ ServiceReference[] services = (ServiceReference[])bundle.getRegisteredServices();
+ if (services != null) {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_REGISTERED_SERVICES_MESSAGE"));
+ for (int j = 0; j < services.length; j++) {
+ intp.print(" ");
+ intp.println(services[j]);
+ }
+ } else {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_REGISTERED_SERVICES_MESSAGE"));
+ }
+
+ services = (ServiceReference[])bundle.getServicesInUse();
+ if (services != null) {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_SERVICES_IN_USE_MESSAGE"));
+ for (int j = 0; j < services.length; j++) {
+ intp.print(" ");
+ intp.println(services[j]);
+ }
+ } else {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_SERVICES_IN_USE_MESSAGE"));
+ }
+ }
+ }
+
+
+ /**
+ * Handle the bundle command's abbreviation. Invoke _bundle()
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _b(CommandInterpreter intp) throws Exception
+ {
+ _bundle(intp);
+ }
+
+ /**
+ * Handle the bundle command. Display details for the specified bundle(s).
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _bundle(CommandInterpreter intp) throws Exception
+ {
+ String nextArg = intp.nextArgument();
+ if (nextArg==null) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_BUNDLE_SPECIFIED_ERROR"));
+ }
+ while (nextArg!=null) {
+ Bundle bundle = getBundleFromToken(intp, nextArg, true);
+ if (bundle != null) {
+ long id = bundle.getBundleId();
+ intp.println(bundle);
+ intp.print(" ");
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_ID_MESSAGE",String.valueOf(id)));
+ intp.print(", ");
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_STATUS_MESSAGE",getStateName(bundle.getState())));
+ if (id != 0) {
+ File dataRoot = osgi.framework.getDataFile(bundle, "");
+
+ String root = (dataRoot == null) ? null : dataRoot.getAbsolutePath();
+
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_DATA_ROOT_MESSAGE",root));
+ } else {
+ intp.println();
+ }
+
+ ServiceReference[] services = (ServiceReference[])bundle.getRegisteredServices();
+ if (services != null) {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_REGISTERED_SERVICES_MESSAGE"));
+ for (int j = 0; j < services.length; j++) {
+ intp.print(" ");
+ intp.println(services[j]);
+ }
+ } else {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_REGISTERED_SERVICES_MESSAGE"));
+ }
+
+ services = (ServiceReference[])bundle.getServicesInUse();
+ if (services != null) {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_SERVICES_IN_USE_MESSAGE"));
+ for (int j = 0; j < services.length; j++) {
+ intp.print(" ");
+ intp.println(services[j]);
+ }
+ } else {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_SERVICES_IN_USE_MESSAGE"));
+ }
+
+ org.osgi.framework.ServiceReference packageAdminRef = context.getServiceReference("org.osgi.service.packageadmin.PackageAdmin");
+ if (packageAdminRef != null) {
+ org.osgi.service.packageadmin.PackageAdmin packageAdmin = (org.osgi.service.packageadmin.PackageAdmin)context.getService(packageAdminRef);
+ if (packageAdmin != null) {
+ try {
+ org.osgi.service.packageadmin.ExportedPackage exportedpkgs[] = packageAdmin.getExportedPackages(null);
+
+ if (exportedpkgs == null) {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_EXPORTED_PACKAGES_MESSAGE"));
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_IMPORTED_PACKAGES_MESSAGE"));
+ } else {
+ boolean title = true;
+
+ for (int i = 0; i < exportedpkgs.length; i++) {
+ org.osgi.service.packageadmin.ExportedPackage exportedpkg = exportedpkgs[i];
+
+ if (exportedpkg.getExportingBundle() == bundle) {
+ if (title) {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_EXPORTED_PACKAGES_MESSAGE"));
+ title = false;
+ }
+ intp.print(" ");
+ intp.print(exportedpkg);
+ if (exportedpkg.isRemovalPending()) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_EXPORTED_REMOVAL_PENDING_MESSAGE"));
+ } else {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_EXPORTED_MESSAGE"));
+ }
+ }
+ }
+
+ if (title) {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_EXPORTED_PACKAGES_MESSAGE"));
+ }
+
+ title = true;
+
+ for (int i = 0; i < exportedpkgs.length; i++) {
+ org.osgi.service.packageadmin.ExportedPackage exportedpkg = exportedpkgs[i];
+
+ org.osgi.framework.Bundle[] importers = exportedpkg.getImportingBundles();
+ for (int j = 0; j < importers.length; j++) {
+ if (importers[j] == bundle) {
+ if (title) {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_IMPORTED_PACKAGES_MESSAGE"));
+ title = false;
+ }
+ intp.print(" ");
+ intp.print(exportedpkg);
+ org.osgi.framework.Bundle exporter = exportedpkg.getExportingBundle();
+ if (exporter != null) {
+ intp.print("<");
+ intp.print(exporter);
+ intp.println(">");
+ } else {
+ intp.print("<");
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_STALE_MESSAGE"));
+ intp.println(">");
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (title) {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_IMPORTED_PACKAGES_MESSAGE"));
+ }
+
+ }
+ } finally {
+ context.ungetService(packageAdminRef);
+ }
+ }
+ } else {
+ intp.print(" ");
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_EXPORTED_PACKAGES_NO_PACKAGE_ADMIN_MESSAGE"));
+ }
+
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ ProtectionDomain domain = bundle.getProtectionDomain();
+
+ intp.println(domain);
+ }
+ }
+ nextArg = intp.nextArgument();
+ }
+ }
+
+
+ /**
+ * Handle the log command's abbreviation. Invoke _log()
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _l(CommandInterpreter intp) throws Exception
+ {
+ _log(intp);
+ }
+
+ /**
+ * Handle the log command. Display log entries.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _log(CommandInterpreter intp) throws Exception
+ {
+ long logid = -1;
+ String token = intp.nextArgument();
+ if (token!=null) {
+ Bundle bundle = getBundleFromToken(intp, token, false);
+
+ if (bundle == null) {
+ try {
+ logid = Long.parseLong(token);
+ } catch (NumberFormatException e) {
+ return;
+ }
+ } else {
+ logid = bundle.getBundleId();
+ }
+ }
+
+ org.osgi.framework.ServiceReference logreaderRef = context.getServiceReference("org.osgi.service.log.LogReaderService");
+ if (logreaderRef != null) {
+ Object logreader = context.getService(logreaderRef);
+ if (logreader != null) {
+ try {
+ Enumeration logentries = (Enumeration) (logreader.getClass().getMethod("getLog", null).invoke(logreader, null));
+
+ if (logentries.hasMoreElements()) {
+ Object logentry = logentries.nextElement();
+ Class clazz = logentry.getClass();
+ Method getBundle = clazz.getMethod("getBundle", null);
+ Method getLevel = clazz.getMethod("getLevel", null);
+ Method getMessage = clazz.getMethod("getMessage", null);
+ Method getServiceReference = clazz.getMethod("getServiceReference", null);
+ Method getException = clazz.getMethod("getException", null);
+
+ while (true) {
+ Bundle bundle = (Bundle) getBundle.invoke(logentry, null);
+
+ if ((logid == -1) || ((bundle != null) && (logid == bundle.getBundleId()))) {
+ Integer level = (Integer) getLevel.invoke(logentry, null);
+ switch (level.intValue()) {
+ case org.osgi.service.log.LogService.LOG_DEBUG:
+ intp.print(">");
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_DEBUG_MESSAGE"));
+ intp.print(" ");
+ break;
+ case org.osgi.service.log.LogService.LOG_INFO:
+ intp.print(">");
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_INFO_MESSAGE")); intp.print(" ");
+ break;
+ case org.osgi.service.log.LogService.LOG_WARNING:
+ intp.print(">");
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_WARNING_MESSAGE"));
+ intp.print(" ");
+ break;
+ case org.osgi.service.log.LogService.LOG_ERROR:
+ intp.print(">");
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_ERROR_MESSAGE"));
+ intp.print(" ");
+ break;
+ default:
+ intp.print(">");
+ intp.print(level);
+ intp.print(" ");
+ break;
+ }
+
+ if (bundle != null) {
+ intp.print("[");
+ intp.print(new Long(bundle.getBundleId()));
+ intp.print("] ");
+ }
+
+ intp.print(getMessage.invoke(logentry, null));
+ intp.print(" ");
+
+ ServiceReference svcref = (ServiceReference) getServiceReference.invoke(logentry, null);
+ if (svcref != null) {
+ intp.print("{");
+ intp.print(Constants.SERVICE_ID);
+ intp.print("=");
+ intp.print(svcref.getProperty(Constants.SERVICE_ID).toString());
+ intp.println("}");
+ } else {
+ if (bundle != null) {
+ intp.println(bundle.getLocation());
+ } else {
+ intp.println();
+ }
+ }
+
+ Throwable t = (Throwable) getException.invoke(logentry, null);
+ if (t != null) {
+ intp.printStackTrace(t);
+ }
+ }
+
+
+ if (logentries.hasMoreElements()) {
+ logentry = logentries.nextElement();
+ } else {
+ break;
+ }
+ }
+ }
+ } finally {
+ context.ungetService(logreaderRef);
+ }
+ return;
+ }
+ }
+
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_LOGSERVICE_NOT_REGISTERED_MESSAGE"));
+ }
+
+ /**
+ * Handle the gc command. Perform a garbage collection.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _gc(CommandInterpreter intp) throws Exception
+ {
+ long before = Runtime.getRuntime().freeMemory();
+
+ /* Let the finilizer finish its work and remove objects from its queue */
+ System.gc(); /* asyncronous garbage collector might already run */
+ System.gc(); /* to make sure it does a full gc call it twice */
+ System.runFinalization();
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+
+ long after = Runtime.getRuntime().freeMemory();
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_FREE_MEMORY_BEFORE_GARBAGE_COLLECTION_MESSAGE"));
+ intp.println(String.valueOf(before));
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_FREE_MEMORY_AFTER_GARBAGE_COLLECTION_MESSAGE"));
+ intp.println(String.valueOf(after));
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_MEMORY_GAINED_WITH_GARBAGE_COLLECTION_MESSAGE"));
+ intp.println(String.valueOf(after - before));
+ }
+
+ /**
+ * Handle the init command. Uninstall all bundles.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _init(CommandInterpreter intp) throws Exception
+ {
+ if (osgi.isActive()) {
+ intp.print(newline);
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_FRAMEWORK_LAUNCHED_PLEASE_SHUTDOWN_MESSAGE"));
+ return;
+ }
+
+ Bundle[] bundles = (Bundle[])context.getBundles();
+
+ int size = bundles.length;
+
+ if (size > 0) {
+ for (int i = 0; i < size; i++) {
+ Bundle bundle = bundles[i];
+
+ if (bundle.getBundleId() != 0) {
+ try {
+ bundle.uninstall();
+ } catch (BundleException e) {
+ intp.printStackTrace(e);
+ }
+ }
+ }
+ } else {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_INSTALLED_BUNDLES_ERROR"));
+ }
+ }
+
+ /**
+ * Handle the close command. Shutdown and exit.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _close(CommandInterpreter intp) throws Exception
+ {
+ intp.println();
+ osgi.close();
+ System.exit(0);
+ }
+
+
+ /**
+ * Handle the refresh command's abbreviation. Invoke _refresh()
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _r(CommandInterpreter intp) throws Exception
+ {
+ _refresh(intp);
+ }
+
+ /**
+ * Handle the refresh command. Refresh the packages of the specified bundles.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _refresh(CommandInterpreter intp) throws Exception
+ {
+ org.osgi.framework.ServiceReference packageAdminRef = context.getServiceReference("org.osgi.service.packageadmin.PackageAdmin");
+ if (packageAdminRef != null) {
+ org.osgi.service.packageadmin.PackageAdmin packageAdmin = (org.osgi.service.packageadmin.PackageAdmin)context.getService(packageAdminRef);
+ if (packageAdmin != null) {
+ try {
+ Bundle[] refresh = null;
+
+ String token = intp.nextArgument();
+ if (token!=null) {
+ Vector bundles = new Vector();
+
+ while (token!=null) {
+ Bundle bundle = getBundleFromToken(intp, token, true);
+
+ if (bundle != null) {
+ bundles.addElement(bundle);
+ }
+ token = intp.nextArgument();
+ }
+
+ int size = bundles.size();
+
+ if (size == 0) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_INVALID_BUNDLE_SPECIFICATION_ERROR"));
+ return;
+ }
+
+ refresh = new Bundle[size];
+ bundles.copyInto(refresh);
+ }
+
+ packageAdmin.refreshPackages(refresh);
+ } finally {
+ context.ungetService(packageAdminRef);
+ }
+ }
+ } else {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_CAN_NOT_REFRESH_NO_PACKAGE_ADMIN_ERROR"));
+ }
+ }
+
+
+ /**
+ * Executes the given system command in a separate system process
+ * and waits for it to finish.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _exec(CommandInterpreter intp) throws Exception {
+ String command = intp.nextArgument();
+ if (command == null) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_COMMAND_SPECIFIED_ERROR"));
+ return;
+ }
+
+ Process p = Runtime.getRuntime().exec(command);
+
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_STARTED_IN_MESSAGE",command,String.valueOf(p)));
+ int result = p.waitFor();
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_EXECUTED_RESULT_CODE_MESSAGE",command,String.valueOf(result)));
+ }
+
+ /**
+ * Executes the given system command in a separate system process. It does
+ * not wait for a result.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _fork(CommandInterpreter intp) throws Exception {
+ String command = intp.nextArgument();
+ if (command == null) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_COMMAND_SPECIFIED_ERROR"));
+ return;
+ }
+
+ Process p = Runtime.getRuntime().exec(command);
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_STARTED_IN_MESSAGE",command,String.valueOf(p)));
+ }
+
+ /**
+ * Handle the headers command's abbreviation. Invoke _headers()
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _h(CommandInterpreter intp) throws Exception {
+ _headers(intp);
+ }
+
+ /**
+ * Handle the headers command. Display headers for the specified bundle(s).
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _headers(CommandInterpreter intp) throws Exception {
+
+ String nextArg = intp.nextArgument();
+ if (nextArg==null) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_BUNDLE_SPECIFIED_ERROR"));
+ }
+ while (nextArg!=null) {
+ Bundle bundle = getBundleFromToken(intp, nextArg, true);
+ if (bundle != null) {
+ intp.printDictionary(bundle.getHeaders(),ConsoleMsg.formatter.getString("CONSOLE_BUNDLE_HEADERS_TITLE"));
+ intp.printBundleResource(bundle, "META-INF/IVEATTRS.XML");
+ intp.printBundleResource(bundle, "META-INF/IVERES.XML");
+ }
+ nextArg = intp.nextArgument();
+ }
+ }
+
+ /**
+ * Prints the the meta data of bundles.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _meta(CommandInterpreter intp) throws Exception
+ {
+ String nextArg = intp.nextArgument();
+ if (nextArg == null) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_BUNDLE_SPECIFIED_ERROR"));
+ }
+
+ /* TODO figure out if we can remove the meta command.
+ while (nextArg != null) {
+ Bundle bundle = getBundleFromToken(intp, nextArg, true);
+ if (bundle != null) {
+ intp.printDictionary(bundle.getMetadata(), bundle.toString());
+ }
+ nextArg = intp.nextArgument();
+ }
+ */
+ }
+
+ /**
+ * Handles the props command's abbreviation. Invokes _props()
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _pr(CommandInterpreter intp) throws Exception {
+ _props(intp);
+ }
+
+ /**
+ * Handles the _props command. Prints the system properties sorted.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _props(CommandInterpreter intp) throws Exception {
+ intp.printDictionary(System.getProperties(), ConsoleMsg.formatter.getString("CONSOLE_SYSTEM_PROPERTIES_TITLE"));
+ }
+
+ /**
+ * Handles the setprop command's abbreviation. Invokes _setprop()
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _setp(CommandInterpreter intp) throws Exception {
+ _setprop(intp);
+ }
+
+ /**
+ * Handles the setprop command. Sets the CDS property in the given argument.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _setprop(CommandInterpreter intp) throws Exception {
+ String argument = intp.nextArgument();
+ if (argument == null) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_PARAMETERS_SPECIFIED_TITLE"));
+ _props(intp);
+ } else {
+ InputStream in = new ByteArrayInputStream(argument.getBytes());
+ try {
+ Properties sysprops = System.getProperties();
+ Properties newprops = new Properties();
+ newprops.load(in);
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_SETTING_PROPERTIES_TITLE"));
+ Enumeration keys = newprops.propertyNames();
+ while (keys.hasMoreElements()) {
+ String key = (String) keys.nextElement();
+ String value = (String) newprops.get(key);
+ sysprops.put(key, value);
+ intp.println(tab + key + " = " + value);
+ }
+ } catch (IOException e) {
+ } finally {
+ try {
+ in.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ /**
+ * Prints the short version of the status.
+ * For the long version use "status".
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _ss(CommandInterpreter intp) throws Exception {
+ if (osgi.isActive()) {
+ intp.println();
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_FRAMEWORK_IS_LAUNCHED_MESSAGE"));
+ } else {
+ intp.println();
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_FRAMEWORK_IS_SHUTDOWN_MESSAGE"));
+ }
+
+ Bundle[] bundles = (Bundle[]) context.getBundles();
+ if (bundles.length == 0) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_NO_INSTALLED_BUNDLES_ERROR"));
+ } else {
+ intp.print(newline);
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_ID")); intp.print(tab);
+ intp.print(ConsoleMsg.formatter.getString("CONSOLE_TYPE"));
+ intp.print(tab);
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_STATE_BUNDLE_TITLE"));
+ for (int i = 0; i < bundles.length; i++) {
+ Bundle b = (Bundle) bundles[i];
+ String type = " ";
+ // :TODO need to determine the type?
+ intp.println(b.getBundleId() + "\t" + type + " \t" + getStateName(b.getState()) + b);
+ if (b.isFragment()) {
+ Bundle master = (Bundle)b.getHost();
+ if (master!=null)
+ intp.println("\t\tMaster="+master.getBundleId());
+ } else {
+ Bundle fragment;
+ org.osgi.framework.Bundle fragments[] = b.getFragments();
+ if (fragments!=null) {
+ for (int f=0;f<fragments.length;f++) {
+ fragment = (Bundle)fragments[f];
+ intp.println("\t\tFragment="+fragment.getBundleId());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Handles the threads command abbreviation. Invokes _threads().
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _t(CommandInterpreter intp) throws Exception {
+ _threads(intp);
+ }
+
+ /**
+ * Prints the information about the currently running threads
+ * in the embedded system.
+ *
+ * @param intp A CommandInterpreter object containing the command
+ * and it's arguments.
+ */
+ public void _threads(CommandInterpreter intp) throws Exception
+ {
+
+ ThreadGroup[] threadGroups = getThreadGroups();
+ Util.sort(threadGroups);
+
+ ThreadGroup tg = getTopThreadGroup();
+ Thread[] threads = new Thread[tg.activeCount()];
+ int count = tg.enumerate(threads, true);
+ Util.sort(threads);
+
+ StringBuffer sb = new StringBuffer(120);
+ intp.println();
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_THREADGROUP_TITLE"));
+ for (int i = 0; i < threadGroups.length; i++) {
+ tg = threadGroups[i];
+ int all = tg.activeCount(); //tg.allThreadsCount();
+ int local = tg.enumerate(new Thread[all], false); //tg.threadsCount();
+ ThreadGroup p = tg.getParent();
+ String parent = (p == null) ? "-none-" : p.getName();
+ sb.setLength(0);
+ sb.append(Util.toString(simpleClassName(tg), 18))
+ .append(" ")
+ .append(Util.toString(tg.getName(), 21))
+ .append(" ")
+ .append(Util.toString(parent, 16))
+ .append(Util.toString(new Integer(tg.getMaxPriority()), 3))
+ .append(Util.toString(new Integer(local), 4))
+ .append("/")
+ .append(Util.toString(String.valueOf(all), 6));
+ intp.println(sb.toString());
+ }
+ intp.print(newline);
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_THREADTYPE_TITLE"));
+ for (int j = 0; j < count; j++) {
+ Thread t = threads[j];
+ if (t != null) {
+ sb.setLength(0);
+ sb.append(Util.toString(simpleClassName(t), 18))
+ .append(" ")
+ .append(Util.toString(t.getName(), 21))
+ .append(" ")
+ .append(Util.toString(t.getThreadGroup().getName(), 16))
+ .append(Util.toString(new Integer(t.getPriority()), 3));
+ intp.println(sb.toString());
+ }
+ }
+ }
+
+ /**
+ * Handles the sl (startlevel) command.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _sl(CommandInterpreter intp) throws Exception {
+ if (isStartLevelSvcPresent(intp)) {
+ org.osgi.framework.Bundle bundle = null;
+ String token = intp.nextArgument();
+ int value = 0;
+ if (token != null) {
+ bundle = getBundleFromToken(intp, token, true);
+ if (bundle == null) {
+ return;
+ }
+ }
+ if (bundle == null) { // must want framework startlevel
+ value = slImpl.getStartLevel();
+ intp.println(
+ ConsoleMsg.formatter.getString(
+ "STARTLEVEL_FRAMEWORK_ACTIVE_STARTLEVEL",
+ value));
+ } else { // must want bundle startlevel
+ value = slImpl.getBundleStartLevel(bundle);
+ intp.println(
+ ConsoleMsg.formatter.getString(
+ "STARTLEVEL_BUNDLE_STARTLEVEL",
+ new Long(bundle.getBundleId()),
+ new Integer(value)));
+ }
+ }
+ }
+
+ /**
+ * Handles the setfwsl (set framework startlevel) command.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _setfwsl(CommandInterpreter intp) throws Exception {
+ if (isStartLevelSvcPresent(intp)) {
+ int value=0;
+ String token = intp.nextArgument();
+ if (token==null) {
+ intp.println(ConsoleMsg.formatter.getString("STARTLEVEL_NO_STARTLEVEL_GIVEN"));
+ value = slImpl.getStartLevel();
+ intp.println(ConsoleMsg.formatter.getString("STARTLEVEL_FRAMEWORK_ACTIVE_STARTLEVEL", value));
+ } else {
+ value = this.getStartLevelFromToken(intp, token);
+ if (value>0) {
+ try {
+ slImpl.setStartLevel(value);
+ intp.println(ConsoleMsg.formatter.getString("STARTLEVEL_FRAMEWORK_ACTIVE_STARTLEVEL", value));
+ } catch (IllegalArgumentException e) {
+ intp.println(e.getMessage());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Handles the setbsl (set bundle startlevel) command.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _setbsl(CommandInterpreter intp) throws Exception {
+ if (isStartLevelSvcPresent(intp)) {
+ String token;
+ Bundle bundle = null;
+ token = intp.nextArgument();
+ if (token==null) {
+ intp.println(ConsoleMsg.formatter.getString("STARTLEVEL_NO_STARTLEVEL_OR_BUNDLE_GIVEN"));
+ return;
+ }
+
+ int newSL = this.getStartLevelFromToken(intp, token);
+
+ token = intp.nextArgument();
+ if (token==null) {
+ intp.println(ConsoleMsg.formatter.getString("STARTLEVEL_NO_STARTLEVEL_OR_BUNDLE_GIVEN"));
+ return;
+ }
+ while (token!=null) {
+ bundle = getBundleFromToken(intp, token, true);
+ if (bundle!=null) {
+ try {
+ slImpl.setBundleStartLevel(bundle, newSL);
+ intp.println(ConsoleMsg.formatter.getString("STARTLEVEL_BUNDLE_STARTLEVEL", new Long(bundle.getBundleId()), new Integer(newSL)));
+ } catch (IllegalArgumentException e) {
+ intp.println(e.getMessage());
+ }
+ }
+ token = intp.nextArgument();
+ }
+ }
+ }
+
+ /**
+ * Handles the setibsl (set initial bundle startlevel) command.
+ *
+ * @param intp A CommandInterpreter object containing the command and it's arguments.
+ */
+ public void _setibsl(CommandInterpreter intp) throws Exception {
+ if (isStartLevelSvcPresent(intp)) {
+ int value=0;
+ String token = intp.nextArgument();
+ if (token==null) {
+ intp.println(ConsoleMsg.formatter.getString("STARTLEVEL_NO_STARTLEVEL_GIVEN"));
+ value = slImpl.getInitialBundleStartLevel();
+ intp.println(ConsoleMsg.formatter.getString("STARTLEVEL_INITIAL_BUNDLE_STARTLEVEL", value));
+ } else {
+ value = this.getStartLevelFromToken(intp, token);
+ if (value>0) {
+ try {
+ slImpl.setInitialBundleStartLevel(value);
+ intp.println(ConsoleMsg.formatter.getString("STARTLEVEL_INITIAL_BUNDLE_STARTLEVEL", value));
+ } catch (IllegalArgumentException e) {
+ intp.println(e.getMessage());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks for the presence of the StartLevel Service. Outputs a message if it is not present.
+ * @param intp The CommandInterpreter object to be used to write to the console
+ * @return true or false if service is present or not
+ */
+ protected boolean isStartLevelSvcPresent (CommandInterpreter intp) {
+ boolean retval = false;
+ org.osgi.framework.ServiceReference slSvcRef = context.getServiceReference("org.osgi.service.startlevel.StartLevel");
+ if (slSvcRef != null) {
+ org.osgi.service.startlevel.StartLevel slSvc = (org.osgi.service.startlevel.StartLevel) context.getService(slSvcRef);
+ if (slSvc != null) {
+ retval = true;
+ }
+ } else {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_CAN_NOT_USE_STARTLEVEL_NO_STARTLEVEL_SVC_ERROR"));
+ }
+ return retval;
+ }
+
+
+ /**
+ * Given a number, retrieve the Bundle object with that id.
+ *
+ * @param A string containing a potential bundle it
+ * @param A boolean indicating whether or not to output a message
+ * @return The requested Bundle object
+ */
+ protected Bundle getBundleFromToken(CommandInterpreter intp, String token, boolean error)
+ {
+ Bundle bundle;
+ try {
+ long id = Long.parseLong(token);
+ bundle =(Bundle)context.getBundle(id);
+ } catch (NumberFormatException nfe) {
+ bundle = ((BundleContext)context).getBundleByLocation(token);
+ }
+
+ if ((bundle == null) && error) {
+ intp.println(ConsoleMsg.formatter.getString("CONSOLE_CANNOT_FIND_BUNDLE_ERROR",token));
+ }
+
+ return(bundle);
+ }
+
+ /**
+ * Given a string containing a startlevel value, validate it and convert it to an int
+ *
+ * @param A CommandInterpreter object used for printing out error messages
+ * @param A string containing a potential startlevel
+ * @return The start level or an int <0 if it was invalid
+ */
+ protected int getStartLevelFromToken(CommandInterpreter intp, String value) {
+ int retval=-1;
+ try {
+ retval = Integer.parseInt(value);
+ if (Integer.parseInt(value)<=0) {
+ intp.println(ConsoleMsg.formatter.getString("STARTLEVEL_POSITIVE_INTEGER"));
+ }
+ } catch (NumberFormatException nfe) {
+ intp.println(ConsoleMsg.formatter.getString("STARTLEVEL_POSITIVE_INTEGER"));
+ }
+ return retval;
+ }
+
+
+
+ /**
+ * Given a state value, return the string describing that state.
+ *
+ * @param An int containing a state value
+ * @return A String describing the state
+ */
+ protected String getStateName(int state)
+ {
+ switch (state) {
+ case Bundle.UNINSTALLED:
+ return(ConsoleMsg.formatter.getString("CONSOLE_UNINSTALLED_MESSAGE"));
+
+ case Bundle.INSTALLED:
+ return(ConsoleMsg.formatter.getString("CONSOLE_INSTALLED_MESSAGE"));
+
+ case Bundle.RESOLVED:
+ return(ConsoleMsg.formatter.getString("CONSOLE_RESOLVED_MESSAGE"));
+
+ case Bundle.STARTING:
+ return(ConsoleMsg.formatter.getString("CONSOLE_STARTING_MESSAGE"));
+
+ case Bundle.STOPPING:
+ return(ConsoleMsg.formatter.getString("CONSOLE_STOPPING_MESSAGE"));
+
+ case Bundle.ACTIVE:
+ return(ConsoleMsg.formatter.getString("CONSOLE_ACTIVE_MESSAGE"));
+
+ default:
+ return(Integer.toHexString(state));
+ }
+ }
+
+ /**
+ * Answers all thread groups in the system.
+ *
+ * @return An array of all thread groups.
+ */
+ protected ThreadGroup[] getThreadGroups() {
+ ThreadGroup tg = getTopThreadGroup();
+ ThreadGroup[] groups = new ThreadGroup[tg.activeGroupCount()];
+ int count = tg.enumerate(groups, true);
+ if (count == groups.length) {
+ return groups;
+ }
+ // get rid of null entries
+ ThreadGroup[] ngroups = new ThreadGroup[count];
+ System.arraycopy(groups, 0, ngroups, 0, count);
+ return ngroups;
+ }
+
+ /**
+ * Answers the top level group of the current thread.
+ * <p>
+ * It is the 'system' or 'main' thread group under
+ * which all 'user' thread groups are allocated.
+ *
+ * @return The parent of all user thread groups.
+ */
+ protected ThreadGroup getTopThreadGroup() {
+ ThreadGroup topGroup = Thread.currentThread().getThreadGroup();
+ if (topGroup != null) {
+ while (topGroup.getParent() != null) {
+ topGroup = topGroup.getParent();
+ }
+ }
+ return topGroup;
+ }
+
+ /**
+ * Returns the simple class name of an object.
+ *
+ * @param The object for which a class name is requested
+ * @return The simple class name.
+ */
+ public String simpleClassName(Object o) {
+ java.util.StringTokenizer t = new java.util.StringTokenizer(o.getClass().getName(), ".");
+ int ct = t.countTokens();
+ for (int i = 1; i < ct; i++) {
+ t.nextToken();
+ }
+ return t.nextToken();
+ }
+}
+
diff --git a/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkConsole.java b/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkConsole.java
new file mode 100644
index 000000000..add42e9bf
--- /dev/null
+++ b/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkConsole.java
@@ -0,0 +1,497 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import org.eclipse.osgi.framework.console.CommandInterpreter;
+import org.eclipse.osgi.framework.console.CommandProvider;
+import org.eclipse.osgi.framework.tracker.ServiceTracker;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * This class starts OSGi with a console for development use.
+ *
+ * FrameworkConsole provides a printStackTrace method to print Exceptions and their
+ * nested Exceptions.
+ */
+public class FrameworkConsole implements Runnable {
+ /** The stream to receive commands on */
+ protected Reader in;
+ /** The stream to write command results to */
+ protected PrintWriter out;
+ /** The current bundle context */
+ protected org.osgi.framework.BundleContext context;
+ /** The current osgi instance */
+ protected OSGi osgi;
+ /** The command line arguments passed at launch time*/
+ protected String[] args;
+ /** The OSGi Command Provider */
+ protected CommandProvider osgicp;
+ /** A tracker containing the service object of all registered command providers */
+ protected CommandProviderTracker cptracker;
+
+ /** Default code page which must be supported by all JVMs */
+ static String defaultEncoding = "iso8859-1";
+ /** The current setting for code page */
+ static String encoding =
+ System.getProperty("file.encoding", defaultEncoding);
+
+ /** set to true if accepting commands from port */
+ protected boolean useSocketStream = false;
+ protected boolean disconnect = false;
+ protected int port = 0;
+ protected ServerSocket ss = null;
+ protected ConsoleSocketGetter scsg = null;
+ protected Socket s;
+
+ /**
+ Constructor for FrameworkConsole.
+ It creates a service tracker to track CommandProvider registrations.
+ The console InputStream is set to System.in and the console PrintStream is set to System.out.
+ @param osgi - an instance of an osgi framework
+ @param args - any arguments passed on the command line when Launcher is started.
+ */
+ public FrameworkConsole(OSGi osgi, String[] args) {
+
+ getDefaultStreams();
+
+ this.args = args;
+ this.osgi = osgi;
+
+ initialize();
+
+ }
+
+ /**
+ Constructor for FrameworkConsole.
+ It creates a service tracker to track CommandProvider registrations.
+ The console InputStream is set to System.in and the console PrintStream is set to System.out.
+ @param osgi - an instance of an osgi framework
+ @param args - any arguments passed on the command line when Launcher is started.
+ */
+ public FrameworkConsole(OSGi osgi, int port, String[] args) {
+
+ getSocketStream(port);
+
+ this.useSocketStream = true;
+ this.port = port;
+ this.args = args;
+ this.osgi = osgi;
+
+ initialize();
+ }
+
+ /**
+ * Open streams for system.in and system.out
+ */
+ private void getDefaultStreams() {
+ in = createBufferedReader(System.in);
+ out = createPrintWriter(System.out);
+ }
+
+ /**
+ * Open a socket and create input and output streams
+ *
+ * @param port number to listen on
+ */
+ private void getSocketStream(int port) {
+ try {
+ System.out.println(
+ ConsoleMsg.formatter.getString(
+ "CONSOLE_LISTENING_ON_PORT",
+ port));
+ if (ss == null) {
+ ss = new ServerSocket(port);
+ scsg = new ConsoleSocketGetter(ss);
+ }
+ scsg.setAcceptConnections(true);
+ s = scsg.getSocket();
+
+ in = createBufferedReader(s.getInputStream());
+ out = createPrintWriter(s.getOutputStream());
+ } catch (UnknownHostException uhe) {
+ uhe.printStackTrace();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Return a BufferedReader from an InputStream. Handle encoding.
+ *
+ * @param An InputStream to wrap with a BufferedReader
+ * @return a BufferedReader
+ */
+ private BufferedReader createBufferedReader(InputStream _in) {
+ BufferedReader reader;
+ try {
+ reader = new BufferedReader(new InputStreamReader(_in, encoding));
+ } catch (UnsupportedEncodingException uee) {
+ // if the encoding is not supported by the jvm, punt and use whatever encodiing there is
+ reader = new BufferedReader(new InputStreamReader(_in));
+ }
+ return reader;
+ }
+
+ /**
+ * Return a PrintWriter from an OutputStream. Handle encoding.
+ *
+ * @param An OutputStream to wrap with a PrintWriter
+ * @return a PrintWriter
+ */
+ private PrintWriter createPrintWriter(OutputStream _out) {
+ PrintWriter writer;
+ try {
+ writer =
+ new PrintWriter(
+ new BufferedWriter(new OutputStreamWriter(_out, encoding)),
+ true);
+ } catch (UnsupportedEncodingException uee) {
+ // if the encoding is not supported by the jvm, punt and use whatever encodiing there is
+ writer =
+ new PrintWriter(
+ new BufferedWriter(new OutputStreamWriter(_out)),
+ true);
+ }
+ return writer;
+ }
+
+ /**
+ * Return the current output PrintWriter
+ * @return The currently active PrintWriter
+ */
+ public PrintWriter getWriter() {
+ return out;
+ }
+
+ /**
+ * Return the current input BufferedReader
+ * @return The currently active BufferedReader
+ */
+ public BufferedReader getReader() {
+ return (BufferedReader) in;
+ }
+
+ /**
+ * Return if the SocketSteam (telnet to the console) is being used
+ * @return Return if the SocketSteam is being used
+ */
+ public boolean getUseSocketStream() {
+ return useSocketStream;
+ }
+
+ /**
+ * Initialize common things:
+ * - system bundle context
+ * - ServiceTracker to track CommandProvider registrations
+ * - create OSGi CommandProvider object
+ */
+ private void initialize() {
+
+ context = osgi.getBundleContext();
+
+ // set up a service tracker to track CommandProvider registrations
+ cptracker =
+ new CommandProviderTracker(
+ context,
+ CommandProvider.class.getName(),
+ this);
+ cptracker.open();
+
+ // register the OSGi command provider
+ osgicp = new FrameworkCommandProvider(osgi);
+
+ }
+
+ /**
+ * Begin doing the active part of the class' code. Starts up the console.
+ */
+ public void run() {
+ console(args);
+ if (useSocketStream) {
+ while (true) {
+ getSocketStream(port);
+ console();
+ }
+ }
+ }
+
+ /**
+ * Command Line Interface for OSGi. The method processes the initial commands
+ * and then reads and processes commands from the console InputStream.
+ * Command output is written to the console PrintStream. The method will
+ * loop reading commands from the console InputStream until end-of-file
+ * is reached. This method will then return.
+ *
+ * @param args Initial set of commands to execute.
+ */
+ public void console(String args[]) {
+ // first handle any args passed in from launch
+ if (args != null) {
+ for (int i = 0; i < args.length; i++) {
+ docommand(args[i]);
+ }
+ }
+ console();
+ }
+
+ /**
+ * Command Line Interface for OSGi. The method processes the initial commands
+ * and then reads and processes commands from the console InputStream.
+ * Command output is written to the console PrintStream. The method will
+ * loop reading commands from the console InputStream until end-of-file
+ * is reached. This method will then return.
+ */
+ protected void console() {
+ Object lock = new Object();
+ disconnect = false;
+ // wait to receive commands from console and handle them
+ BufferedReader br = (BufferedReader) in;
+ //cache the console prompt String
+ String consolePrompt =
+ "\r\n" + ConsoleMsg.formatter.getString("CONSOLE_PROMPT");
+ while (!disconnect) {
+ out.print(consolePrompt);
+ out.flush();
+
+ // avoid waiting on input stream - apparently generates contention with other native calls
+
+ String cmdline = null;
+ try {
+ synchronized (lock) {
+ while (!br.ready()) {
+ lock.wait(300);
+ }
+ }
+ cmdline = br.readLine();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ continue;
+ }
+
+ if (cmdline == null) {
+ break;
+ }
+
+ docommand(cmdline);
+ }
+ }
+
+ /**
+ * Process the args on the command line.
+ * This method invokes a CommandInterpreter to do the actual work.
+ *
+ * @param a string containing the command line arguments
+ */
+ protected void docommand(String cmdline) {
+ if (cmdline != null && cmdline.length() > 0) {
+ CommandInterpreter intcp =
+ new FrameworkCommandInterpreter(
+ cmdline,
+ cptracker.getServices(),
+ this);
+ String command = intcp.nextArgument();
+ if (command != null) {
+ intcp.execute(command);
+ }
+ }
+ }
+
+ /**
+ * Disconnects from console if useSocketStream is set to true. This
+ * will cause the console to close from a telnet session.
+ */
+
+ void disconnect() throws IOException {
+ disconnect = true;
+ out.close();
+ in.close();
+ s.close();
+ }
+
+ /**
+ * Reads a string from standard input until user hits the Enter key.
+ *
+ * @return The string read from the standard input without the newline character.
+ */
+ public String getInput() {
+ String input;
+ try {
+ /** The buffered input reader on standard in. */
+ input = ((BufferedReader) in).readLine();
+ } catch (IOException e) {
+ input = "";
+ }
+ return input;
+ }
+
+ /**
+ * ConsoleSocketGetter - provides a Thread that listens on the port
+ * for FrameworkConsole. If acceptConnections is set to true then
+ * the thread will notify the getSocket method to return the socket.
+ * If acceptConnections is set to false then the client is notified
+ * that connections are not currently accepted and closes the socket.
+ */
+ class ConsoleSocketGetter implements Runnable {
+
+ /** The ServerSocket to accept connections from */
+ ServerSocket server;
+ /** The current socket to be returned by getSocket */
+ Socket socket;
+ /** if set to true then allow the socket to be returned by getSocket */
+ boolean acceptConnections = true;
+ /** Lock object to synchronize returning of the socket */
+ Object lock = new Object();
+
+ /**
+ * Constructor - sets the server and starts the thread to
+ * listen for connections.
+ *
+ * @param a ServerSocket to accept connections from
+ */
+ ConsoleSocketGetter(ServerSocket server) {
+ this.server = server;
+ Thread t = new Thread(this, "ConsoleSocketGetter");
+ t.start();
+ }
+
+ public void run() {
+ while (true) {
+
+ try {
+ socket = ss.accept();
+ if (!acceptConnections) {
+ PrintWriter o =
+ createPrintWriter(socket.getOutputStream());
+ o.println(
+ ConsoleMsg.formatter.getString(
+ "CONSOLE_TELNET_CONNECTION_REFUSED"));
+ o.println(
+ ConsoleMsg.formatter.getString(
+ "CONSOLE_TELNET_CURRENTLY_USED"));
+ o.println(
+ ConsoleMsg.formatter.getString(
+ "CONSOLE_TELNET_ONE_CLIENT_ONLY"));
+ o.close();
+ socket.close();
+ } else {
+ synchronized (lock) {
+ lock.notify();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+ }
+
+ /**
+ * Method to get a socket connection from a client.
+ *
+ * @return - Socket from a connected client
+ */
+ public Socket getSocket() throws InterruptedException {
+ // wait for a socket to get assigned from the accepter thread
+ synchronized (lock) {
+ lock.wait();
+ }
+ setAcceptConnections(false);
+ return socket;
+ }
+
+ /**
+ * Method to indicate if connections are accepted or not. If set
+ * to false then the clients will be notified that connections
+ * are not accepted.
+ */
+ public void setAcceptConnections(boolean acceptConnections) {
+ this.acceptConnections = acceptConnections;
+ }
+ }
+
+ class CommandProviderTracker extends ServiceTracker {
+
+ FrameworkConsole con;
+ CommandProviderTracker(
+ org.osgi.framework.BundleContext context,
+ String clazz,
+ FrameworkConsole con) {
+ super(context, clazz, null);
+ this.con = con;
+ }
+
+ /**
+ * Default implementation of the <tt>ServiceTrackerCustomizer.addingService</tt> method.
+ *
+ * <p>This method is only called when this <tt>ServiceTracker</tt> object
+ * has been constructed with a <tt>null</tt> <tt>ServiceTrackerCustomizer</tt> argument.
+ *
+ * The default implementation returns the result of
+ * calling <tt>getService</tt>, on the
+ * <tt>BundleContext</tt> object with which this <tt>ServiceTracker</tt> object was created,
+ * passing the specified <tt>ServiceReference</tt> object.
+ *
+ * <p>This method can be overridden to customize
+ * the service object to be tracked for the service
+ * being added.
+ *
+ * @param reference Reference to service being added to this
+ * <tt>ServiceTracker</tt> object.
+ * @return The service object to be tracked for the service
+ * added to this <tt>ServiceTracker</tt> object.
+ */
+ public Object addingService(ServiceReference reference) {
+ CommandProvider cp =
+ (CommandProvider) super.addingService(reference);
+ return cp;
+ }
+
+ /**
+ * Return an array of service objects for all services
+ * being tracked by this <tt>ServiceTracker</tt> object.
+ *
+ * The array is sorted primarily by descending Service Ranking and
+ * secondarily by ascending Service ID.
+ *
+ * @return Array of service objects or <tt>null</tt> if no service
+ * are being tracked.
+ */
+ public Object[] getServices() {
+ ServiceReference[] serviceRefs =
+ (ServiceReference[]) super.getServiceReferences();
+ Util.dsort(serviceRefs, 0, serviceRefs.length);
+
+ Object[] serviceObjects = new Object[serviceRefs.length];
+ for (int i = 0; i < serviceRefs.length; i++) {
+ serviceObjects[i] =
+ FrameworkConsole.this.context.getService(serviceRefs[i]);
+ }
+ return serviceObjects;
+ }
+
+ }
+
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleClassLoader.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleClassLoader.java
new file mode 100644
index 000000000..76c7ffa3f
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleClassLoader.java
@@ -0,0 +1,297 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.adaptor;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.ProtectionDomain;
+import java.util.Enumeration;
+import org.eclipse.osgi.framework.debug.Debug;
+
+/**
+ * The framework needs access to some protected methods in order to
+ * load local resources and classes. The BundleClassLoader simply exposes
+ * some new public methods that call protected methods for the framework.
+ */
+public abstract class BundleClassLoader extends ClassLoader {
+
+ /**
+ * The delegate used to get classes and resources from. The delegate
+ * must always be queried first before the local ClassLoader is searched for
+ * a class or resource.
+ */
+ protected ClassLoaderDelegate delegate;
+
+ /**
+ * The ProtectionDomain to use to define classes.
+ */
+ protected ProtectionDomain domain;
+
+ /**
+ * Indicates this class loader is closed.
+ */
+ protected boolean closed = false;
+
+ /**
+ * The default parent classloader to use when one is not specified.
+ * The behavior of the default parent classloader will be to load classes
+ * from the boot strap classloader.
+ */
+ protected static ParentClassLoader defaultParentClassLoader = new ParentClassLoader();
+
+ /**
+ * The BundleClassLoader parent.
+ */
+ protected ClassLoader parentClassLoader;
+
+ /**
+ * BundleClassLoader constructor.
+ * @param delegate The ClassLoaderDelegate for this bundle.
+ * @param domain The ProtectionDomain for this bundle.
+ */
+ public BundleClassLoader(ClassLoaderDelegate delegate, ProtectionDomain domain, String[] ignored)
+ {
+ this(delegate, domain, ignored, null);
+ }
+
+ /**
+ * BundleClassLoader constructor.
+ * @param delegate The ClassLoaderDelegate for this bundle.
+ * @param domain The ProtectionDomain for this bundle.
+ * @param parent The parent classloader to use.
+ */
+ public BundleClassLoader(ClassLoaderDelegate delegate, ProtectionDomain domain, String[] ignored, ClassLoader parent)
+ {
+ this.delegate = delegate;
+ this.domain = domain;
+ // use the defaultParentClassLoader if a parent is not specified.
+ if (parent == null)
+ parentClassLoader=defaultParentClassLoader;
+ else
+ parentClassLoader = parent;
+ }
+
+ /**
+ * Loads a class for the bundle. First delegate.findClass(name) is called.
+ * The delegate will query the system class loader, bundle imports, bundle
+ * local classes, bundle hosts and fragments. The delegate will call
+ * BundleClassLoader.findLocalClass(name) to find a class local to this
+ * bundle.
+ * @param name the name of the class to load.
+ * @param resolve indicates whether to resolve the loaded class or not.
+ * @return The Class object.
+ * @throws ClassNotFoundException if the class is not found.
+ */
+ public Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ if (closed)
+ throw new ClassNotFoundException(name);
+
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ Debug.println("BundleClassLoader[" + delegate + "].loadClass(" + name + ")");
+
+ try {
+ // First check the parent classloader for system classes.
+ try{
+ return parentClassLoader.loadClass(name);
+ } catch (ClassNotFoundException e){
+ // Do nothing. continue to delegate.
+ }
+
+ // Just ask the delegate. This could result in findLocalClass(name) being called.
+ Class clazz = delegate.findClass(name);
+ // resolve the class if asked to.
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ } catch (Error e) {
+ if (Debug.DEBUG && Debug.DEBUG_LOADER) {
+ Debug.println("BundleClassLoader[" + delegate + "].loadClass(" + name + ") failed.");
+ Debug.printStackTrace(e);
+ }
+ throw e;
+ } catch (ClassNotFoundException e) {
+ // If the class is not found do not try to look for it locally.
+ // The delegate would have already done that for us.
+ if (Debug.DEBUG && Debug.DEBUG_LOADER) {
+ Debug.println("BundleClassLoader[" + delegate + "].loadClass(" + name + ") failed.");
+ Debug.printStackTrace(e);
+ }
+ throw e;
+ }
+ }
+
+ /**
+ * Finds a class local to this bundle. The bundle class path is used
+ * to search for the class. The delegate must not be used. This method
+ * is abstract to force extending classes to implement this method instead
+ * of using the ClassLoader.findClass(String) method.
+ * @param name The classname of the class to find
+ * @return The Class object.
+ * @throws ClassNotFoundException if the class is not found.
+ */
+ abstract protected Class findClass(String name) throws ClassNotFoundException ;
+
+ /**
+ * Gets a resource for the bundle. First delegate.findResource(name) is
+ * called. The delegate will query the system class loader, bundle imports,
+ * bundle local resources, bundle hosts and fragments. The delegate will
+ * call BundleClassLoader.findLocalResource(name) to find a resource local
+ * to this bundle.
+ * @param name The resource path to get.
+ * @return The URL of the resource or null if it does not exist.
+ */
+ public URL getResource(String name) {
+ if (closed) {
+ return null;
+ }
+ if (Debug.DEBUG && Debug.DEBUG_LOADER) {
+ Debug.println("BundleClassLoader[" + delegate +"].getResource("+name+")");
+ }
+
+ try
+ {
+ // First check the parent classloader for system resources.
+ URL url = parentClassLoader.getResource(name);
+ if (url != null) {
+ return(url);
+ }
+ url = delegate.findResource(name);
+ if (url != null) {
+ return(url);
+ }
+ }
+ catch (ImportResourceNotFoundException e)
+ {
+ }
+
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ {
+ Debug.println("BundleClassLoader[" + delegate +"].getResource("+name+") failed.");
+ }
+
+ return(null);
+ }
+
+ /**
+ * Finds a resource local to this bundle. Simply calls
+ * findResourceImpl(name) to find the resource.
+ * @param name The resource path to find.
+ * @return The URL of the resource or null if it does not exist.
+ */
+ abstract protected URL findResource(String name);
+
+ /**
+ * Finds all resources with the specified name. This method must call
+ * delegate.findResources(name) to find all the resources.
+ * @param name The resource path to find.
+ * @return An Enumeration of all resources found or null if the resource.
+ */
+ protected Enumeration findResources(String name) throws IOException {
+ /* Note: this class cannot be constructed with super(parent).
+ * In order to properly search the imported packages,
+ * ClassLoader.getResources cannot call parent.findResources
+ * which will happen if this class is constructed with super(parent).
+ * This is necessary because ClassLoader.getResources is final. Otherwise
+ * we could override it to better implement the desired behavior.
+ * So instead, we do not have a parent and call delegate.findResources(name).
+ * The delegate may call findLocalResources(name) to find the resources
+ * locally if they are not found outside the bundle.
+ */
+ try {
+ return(delegate.findResources(name));
+ } catch (Exception e){
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ {
+ Debug.println("BundleClassLoader[" + delegate +"].findResources("+name+") failed.");
+ Debug.printStackTrace(e);
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Finds a library for this bundle. Simply calls
+ * delegate.findLibrary(libname) to find the library.
+ * @param libname The library to find.
+ * @return The URL of the resource or null if it does not exist.
+ */
+ protected String findLibrary(String libname){
+ return delegate.findLibrary(libname);
+ }
+
+ /**
+ * Finds a local resource in the BundleClassLoader without
+ * consulting the delegate.
+ * @param resource the resource path to find.
+ * @return a URL to the resource or null if the resource does not exist.
+ */
+ public URL findLocalResource(String resource){
+ return this.findResource(resource);
+ }
+
+ /**
+ * Finds all local resources in the BundleClassLoader with the specified
+ * path without consulting the delegate.
+ * @param classname
+ * @return An Enumeration of all resources found or null if the resource.
+ * does not exist.
+ */
+ abstract public Enumeration findLocalResources(String resource);
+
+ /**
+ * Finds a local class in the BundleClassLoader without
+ * consulting the delegate.
+ * @param classname the classname to find.
+ * @return The class object found.
+ * @throws ClassNotFoundException if the classname does not exist locally.
+ */
+ public Class findLocalClass(String classname) throws ClassNotFoundException{
+ return findClass(classname);
+ }
+
+ /**
+ * Closes this class loader. After this method is called
+ * loadClass will always throw ClassNotFoundException,
+ * getResource, getResourceAsStream, and getResources will
+ * return null.
+ *
+ */
+ public void close() {
+ closed = false;
+ }
+
+ /**
+ * Empty parent classloader. This is used by default as our parentClassLoader
+ * The BundleClassLoader constructor may assign a different parentClassLoader
+ * if desired.
+ */
+ protected static class ParentClassLoader extends ClassLoader {
+ protected ParentClassLoader(){
+ super(null);
+ }
+ }
+
+ /**
+ * Attaches the BundleData for a fragment to this BundleClassLoader.
+ * The Fragment BundleData resources must be appended to the end of
+ * this BundleClassLoader's classpath. Fragment BundleData resources
+ * must be searched ordered by Bundle ID's.
+ * @param bundledata The BundleData of the fragment.
+ * @param domain The ProtectionDomain of the resources of the fragment.
+ * Any classes loaded from the fragment's BundleData must belong to this
+ * ProtectionDomain.
+ * @param classpath An array of Bundle-ClassPath entries to
+ * use for loading classes and resources. This is specified by the
+ * Bundle-ClassPath manifest entry of the fragment.
+ */
+ abstract public void attachFragment(BundleData bundledata, ProtectionDomain domain, String[] classpath);
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleData.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleData.java
new file mode 100644
index 000000000..ef7a256a6
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleData.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.adaptor;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.security.ProtectionDomain;
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+
+/**
+ * The <code>BundleData</code> represents a single bundle that is persistently
+ * stored by a <code>FrameworkAdaptor</code>. A <code>BundleData</code> creates
+ * the ClassLoader for a bundle, finds native libraries installed in the
+ * FrameworkAdaptor for the bundle, creates data files for the bundle,
+ * used to access bundle entries, manifest information, and getting and saving
+ * metadata.
+ */
+public interface BundleData
+{
+ /**
+ * Creates the ClassLoader for the BundleData. The ClassLoader created
+ * must use the <code>ClassLoaderDelegate</code> to delegate class, resource
+ * and library loading. The delegate is responsible for finding any resource
+ * or classes imported by the bundle or provided by bundle fragments or
+ * bundle hosts. The <code>ProtectionDomain</code> domain must be used
+ * by the Classloader when defining a class.
+ * @param delegate The <code>ClassLoaderDelegate</code> to delegate to.
+ * @param domain The <code>ProtectionDomain</code> to use when defining a class.
+ * @param bundleclasspath An array of bundle classpaths to use to create this
+ * classloader. This is specified by the Bundle-ClassPath manifest entry.
+ * @return The new ClassLoader for the BundleData.
+ */
+ public BundleClassLoader createClassLoader(ClassLoaderDelegate delegate, ProtectionDomain domain, String[] bundleclasspath);
+
+ /**
+ * Gets a <code>URL</code> to the bundle entry specified by path.
+ * This method must not use the BundleClassLoader to find the
+ * bundle entry since the ClassLoader will delegate to find the resource.
+ * @param path The bundle entry path.
+ * @return A URL used to access the entry or null if the entry
+ * does not exist.
+ */
+ public URL getEntry(String path);
+
+ /**
+ * Gets all of the bundle entries that exist under the specified path.
+ * For example: <p>
+ * <code>getEntryPaths("/META-INF")</code> <p>
+ * This will return all entries from the /META-INF directory of the bundle.
+ * @param path The path to a directory in the bundle.
+ * @return An Enumeration of the entry paths or null if the specified path
+ * does not exist.
+ */
+ public Enumeration getEntryPaths(String path);
+
+ /**
+ * Returns the absolute path name of a native library. The BundleData
+ * ClassLoader invokes this method to locate the native libraries that
+ * belong to classes loaded from this BundleData. Returns
+ * null if the library does not exist in this BundleData.
+ * @param libname The name of the library to find the absolute path to.
+ * @return The absolute path name of the native library or null if
+ * the library does not exist.
+ */
+ public String findLibrary(String libname);
+
+ /**
+ * Installs the native code paths for this BundleData. Each
+ * element of nativepaths must be installed for lookup when findLibrary
+ * is called.
+ * @param nativepaths The array of native code paths to install for
+ * the bundle.
+ * @throws BundleException If any error occurs during install.
+ */
+ public void installNativeCode(String[] nativepaths) throws BundleException;
+
+ /**
+ * Return the bundle data directory.
+ * Attempt to create the directory if it does not exist.
+ *
+ * @return Bundle data directory.
+ */
+
+ public File getDataFile(String path);
+
+ /**
+ * Return the BundleManifest for the BundleData.
+ * @return Dictionary for containing the Manifest headers for the BundleData.
+ * @throws BundleException if an error occurred while reading the
+ * bundle manifest data.
+ */
+ public Dictionary getManifest() throws BundleException;
+
+ /**
+ * Get the BundleData bundle ID. This will be used as the bundle
+ * ID by the framework.
+ * @return The BundleData ID.
+ */
+ public long getBundleID();
+
+ /**
+ * Get the BundleData Location. This will be used as the bundle
+ * location by the framework.
+ * @return the BundleData location.
+ */
+ public String getLocation();
+
+ /**
+ * Return a Dictionary of all manifest headers.
+ * @return all manifest headers.
+ */
+ public Dictionary getHeaders();
+
+ /**
+ * Close all resources for this BundleData
+ * @throws IOException If an error occurs closing.
+ */
+ public void close() throws IOException;
+
+ /**
+ * Open the BundleData. This method will reopen the BundleData if it has been
+ * previously closed.
+ * @throws IOException If an error occurs opening.
+ */
+ public void open() throws IOException;
+
+ /**
+ * Sets the Bundle object for this BundleData.
+ * @param bundle The Bundle Object for this BundleData.
+ */
+ public void setBundle(Bundle bundle);
+
+ public int getStartLevel();
+ public int getStatus();
+ public void setStartLevel(int value);
+ public void setStatus(int value);
+ public void save() throws IOException;
+
+ public String getUniqueId();
+ public Version getVersion();
+ public boolean isFragment();
+ public String getClassPath();
+ public String getActivator();
+ public String getExecutionEnvironment();
+ public String getDynamicImports();
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleOperation.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleOperation.java
new file mode 100644
index 000000000..23a08550c
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleOperation.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.adaptor;
+
+import org.osgi.framework.*;
+
+/**
+ * Bundle Storage interface for managing a persistent storage life
+ * cycle operation upon a bundle.
+ *
+ * <p>This class is used to provide methods to manage a life cycle
+ * operation on a bundle in persistent storage. BundleOperation objects
+ * are returned by the FrameworkAdaptor object and are called by OSGi
+ * to complete the persistent storage life cycle operation.
+ *
+ * <p>For example
+ * <pre>
+ * Bundle bundle;
+ * BundleOperation storage = adaptor.installBundle(location, source);
+ * try {
+ * bundle = storage.begin();
+ *
+ * // Perform some implementation specific work
+ * // which may fail.
+ *
+ * storage.commit(false);
+ * // bundle has been successfully installed
+ * } catch (BundleException e) {
+ * storage.undo();
+ * throw e; // rethrow the error
+ * }
+ * return bundle;
+ * </pre>
+ *
+ */
+public abstract interface BundleOperation
+{
+
+ /**
+ * Begin the operation on the bundle (install, update, uninstall).
+ *
+ * @return BundleData object for the target bundle.
+ * @throws BundleException If a failure occured modifiying peristent storage.
+ */
+ public abstract BundleData begin() throws BundleException;
+
+ /**
+ * Commit the operation performed.
+ *
+ * @param postpone If true, the bundle's persistent
+ * storage cannot be immediately reclaimed. This may occur if the
+ * bundle is still exporting a package.
+ * @throws BundleException If a failure occured modifiying peristent storage.
+ */
+ public abstract void commit(boolean postpone) throws BundleException;
+
+ /**
+ * Undo the change to persistent storage.
+ * <p>This method can be called before calling commit or if commit
+ * throws an exception to undo any changes in progress.
+ *
+ * @throws BundleException If a failure occured modifiying peristent storage.
+ */
+ public abstract void undo() throws BundleException;
+
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ClassLoaderDelegate.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ClassLoaderDelegate.java
new file mode 100644
index 000000000..6e3cc61f4
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ClassLoaderDelegate.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.adaptor;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+
+/**
+ * A ClassLoaderDelegate is used by the BundleClassLoader in a similar
+ * fashion that a parent ClassLoader is used. A ClassLoaderDelegate must
+ * be queried for any resource or class before it is loaded by the
+ * BundleClassLoader.
+ */
+public interface ClassLoaderDelegate {
+ /**
+ * Finds a class for a bundle that may be outside of the actual bundle
+ * (i.e. an imported class or a fragment/host class). The following is a
+ * list of steps that a ClassLoaderDelegate must take when trying to load
+ * a class. <p>
+ * <ul>
+ * <li>Try to load the class using the System ClassLoader.
+ *
+ * <li>If the bundle is not a fragment then continue to the next step
+ * otherwise try to load the class from the host bundle, if the class
+ * is not found in the host then throw a ClassNotFoundException.
+ *
+ * <li>Try to load the class from an imported package. If the class is
+ * not found and it belongs to a package that has been imported then throw
+ * an <code>ImportClassNotFoundException</code>. If the class does not
+ * belong to an imported package then continue to the next step.
+ *
+ * <li>If the bundle is not a host to any fragments then continue to the
+ * next step. Try to load the class as an imported class from all of the
+ * fragment bundles for this host bundle. If the class is not found and
+ * it belongs to a package that has been imported by a fragment then throw
+ * an <code>ImportClassNotFoundException</code>.
+ *
+ * <li>Try to load the class from the actual bundle. This must be done
+ * by calling the findLocalClass(classname) method on the BundleClassLoader.
+ *
+ * <li>If the bundle is a host to any fragments then try to load the class
+ * from the fragment bundles. This must be done by calling the
+ * findLocalClass(classname) method on the fragement BundleClassLoader.
+ *
+ * </ul>
+ * If no class is found then a ClassNotFoundException is thrown.
+ * @param classname the class to find.
+ * @return the Class.
+ * @throws ImportClassNotFoundException if trying to import a class from an
+ * imported package and the class is not found.
+ * @throws ClassNotFoundException if the class is not found.
+ */
+ public Class findClass(String classname) throws ClassNotFoundException;
+
+ /**
+ * Finds a resource for a bundle that may be outside of the actual bundle
+ * (i.e. an imported resource or a fragment/host resource). The following
+ * is a list steps that a ClassLoaderDelegate must take when trying to find
+ * a resource. <p>
+ * <ul>
+ * <li>Try to load the resource using the System ClassLoader.
+ *
+ * <li>If the bundle is not a fragment then continue to the next step
+ * otherwise try to load the resource from the host bundle, if the resource
+ * is not found in the host null is returned.
+ *
+ * <li>Try to load the resource from an imported package. If the resource is
+ * not found and it belongs to a package that has been imported then throw
+ * an <code>ImportResourceNotFoundException</code>. If the resource does not
+ * belong to an imported package then continue to the next step.
+ *
+ * <li>If the bundle is not a host to any fragments then continue to the
+ * next step. Try to load the resource as an imported resource from all
+ * of the fragment bundles for this host bundle. If the resource is not found
+ * and it belongs to a package that has been imported by a fragment then
+ * throw an <code>ImportResourceNotFoundException</code>.
+ *
+ * <li>Try to load the resource from the actual bundle. This must be done
+ * by calling the findLocalResource(name) method on the BundleClassLoader.
+ *
+ * <li>If the bundle is a host to any fragments then try to load the resource
+ * from the fragment bundles. This must be done by calling the
+ * findLocalResource(name) method on the fragement BundleClassLoader.
+ *
+ * </ul>
+ * If no resource is found then return null.
+ * @param resource the resource to load.
+ * @return the resource or null if resource is not found.
+ * @throws ImportResourceNotFoundException if trying to import a resource from an
+ * imported package and the resource is not found.
+ */
+ public URL findResource(String resource) throws ImportResourceNotFoundException;
+
+ /**
+ * Finds a list of resources for a bundle that may be outside of the actual
+ * bundle (i.e. an imported resource or a fragment/host resource). The
+ * following is a list of steps that a ClassLoaderDelegate must take
+ * when trying to find a resource. <p>
+ * <ul>
+ * <li>Try to find the list of resources using the System ClassLoader.
+ *
+ * <li>If the bundle is not a fragment then continue to the next step
+ * otherwise try to find the list of resources from the host bundle, if the
+ * resource is not found in the host then return null.
+ *
+ * <li>Try to find the list of resources from an imported package. If the
+ * resource is not found and it belongs to a package that has been imported
+ * then throw an <code>ImportResourceNotFoundException</code>. If the
+ * resource does not belong to an imported package then continue to the
+ * next step.
+ *
+ * <li>If the bundle is not a host to any fragments then continue to the
+ * next step. Try to find the list of resources as an imported resource
+ * from all of the fragment bundles for this host bundle. If the resource
+ * is not found and it belongs to a package that has been imported by a
+ * fragment then throw an <code>ImportResourceNotFoundException</code>.
+ *
+ * <li>Try to find the list of resources from the actual bundle.
+ *
+ * <li>If the bundle is a host to any fragments then try to find the list of
+ * resources from the fragment bundles.
+ *
+ * </ul>
+ * If no resource is found then return null.
+ * @param resource the resource to find.
+ * @return the enumeration of resource paths found or null if the resource
+ * does not exist.
+ * @throws ImportResourceNotFoundException if trying to import a resource from an
+ * imported package and the resource is not found.
+ */
+ public Enumeration findResources(String resource) throws ImportResourceNotFoundException, IOException;
+
+ /**
+ * Returns the absolute path name of a native library. The following is
+ * a list of steps that a ClassLoaderDelegate must take when trying to
+ * find a library:
+ * <ul>
+ * <li>If the bundle is a fragment then try to find the library in the
+ * host bundle.
+ * <li>if the bundle is a host then try to find the library in the
+ * host bundle and then try to find the library in the fragment
+ * bundles.
+ * </ul>
+ * If no library is found return null.
+ * @param libraryname the library to find the path to.
+ * @return the path to the library or null if not found.
+ */
+ public String findLibrary(String libraryname);
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/EventPublisher.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/EventPublisher.java
new file mode 100644
index 000000000..dcb8f83fa
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/EventPublisher.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.adaptor;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * The EventPublisher is used by FrameworkAdaptors to publish events to the
+ * Framework.
+ */
+public interface EventPublisher
+{
+
+ /**
+ * Publish a FrameworkEvent.
+ *
+ * @param type FrameworkEvent type.
+ * @param bundle Bundle related to FrameworkEvent.
+ * @param throwable Related exception or <tt>null</tt>.
+ * @see org.osgi.framework.FrameworkEvent
+ */
+ public abstract void publishFrameworkEvent(int type, Bundle bundle, Throwable throwable);
+
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/FrameworkAdaptor.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/FrameworkAdaptor.java
new file mode 100644
index 000000000..cb0fbeae9
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/FrameworkAdaptor.java
@@ -0,0 +1,268 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.adaptor;
+
+import java.io.IOException;
+import java.net.URLConnection;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.eclipse.osgi.service.resolver.PlatformAdmin;
+import org.eclipse.osgi.service.resolver.State;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+
+/**
+ * FrameworkAdaptor interface to the osgi framework. This class is used to provide
+ * platform specific support for the osgi framework.
+ *
+ * <p>The OSGi framework will call this class to perform platform specific functions.
+ *
+ * Classes that implement FrameworkAdaptor MUST provide a constructor that takes as a
+ * parameter an array of Strings. This array will contain arguments to be
+ * handled by the FrameworkAdaptor. The FrameworkAdaptor implementation may define the format
+ * and content of its arguments.
+ *
+ * The constructor should parse the arguments passed to it and remember them.
+ * The initialize method should perform the actual processing of the adaptor
+ * arguments.
+ */
+
+public interface FrameworkAdaptor
+{
+
+ /**
+ * Initialize the FrameworkAdaptor object so that it is ready to be
+ * called by the framework. Handle the arguments that were
+ * passed to the constructor.
+ * This method must be called before any other FrameworkAdaptor methods.
+ * @param eventPublisher The EventPublisher used to publish any events to
+ * the framework.
+ */
+ public void initialize(EventPublisher eventPublisher);
+
+ /**
+ * Initialize the persistent storage for the adaptor.
+ *
+ * @throws IOException If the adaptor is unable to
+ * initialize the bundle storage.
+ */
+ public void initializeStorage() throws IOException;
+
+ /**
+ * Compact/cleanup the persistent storage for the adaptor.
+ * @throws ####
+ *
+ */
+ public void compactStorage() throws IOException;
+
+ /**
+ * Return the properties object for the adaptor.
+ * The properties in the returned object supplement
+ * the System properties.
+ * The framework may modify this object.
+ *
+ * @return The properties object for the adaptor.
+ */
+ public Properties getProperties();
+
+ /**
+ * Return a list of the installed bundles. Each element in the
+ * list must be of type <code>BundleData</code>. Each <code>BundleData</code>
+ * corrosponds to one bundle that is persitently stored.
+ * This method must construct <code>BundleData</code> objects for all
+ * installed bundles and return a Vector containing the objects.
+ * The returned Vector becomes the property of the framework.
+ *
+ * @return Vector of installed BundleData objects.
+ */
+ public Vector getInstalledBundles();
+
+ /**
+ * Map a location to a URLConnection.
+ *
+ * @param location of the bundle.
+ * @return URLConnection that represents the location.
+ * @throws BundleException if the mapping fails.
+ */
+ public URLConnection mapLocationToURLConnection(String location)
+ throws BundleException;
+
+ /**
+ * Prepare to install a bundle from a URLConnection.
+ * <p>To complete the install,
+ * begin and then commit
+ * must be called on the returned <code>BundleOperation</code> object.
+ * If either of these methods throw a BundleException
+ * or some other error occurs,
+ * then undo must be called on the <code>BundleOperation</code> object
+ * to undo the change to persistent storage.
+ *
+ * @param location Bundle location.
+ * @param source URLConnection from which the bundle may be read.
+ * Any InputStreams returned from the source
+ * (URLConnections.getInputStream) must be closed by the
+ * <code>BundleOperation</code> object.
+ * @return BundleOperation object to be used to complete the install.
+ * @throws BundleException if the install preparation fails.
+ */
+ public BundleOperation installBundle(String location, URLConnection source);
+
+ /**
+ * Prepare to update a bundle from a URLConnection.
+ * <p>To complete the update
+ * begin and then commit
+ * must be called on the returned <code>BundleOperation</code> object.
+ * If either of these methods throw a BundleException
+ * or some other error occurs,
+ * then undo must be called on the <code>BundleOperation</code> object
+ * to undo the change to persistent storage.
+ *
+ * @param bundledata BundleData to update.
+ * @param source URLConnection from which the updated bundle may be read.
+ * Any InputStreams returned from the source
+ * (URLConnections.getInputStream) must be closed by the
+ * <code>BundleOperation</code> object.
+ * @return BundleOperation object to be used to complete the update.
+ * @throws BundleException if the update preparation fails.
+ */
+ public BundleOperation updateBundle(BundleData bundledata, URLConnection source);
+
+ /**
+ * Prepare to uninstall a bundle.
+ * <p>To complete the uninstall,
+ * begin and then commit
+ * must be called on the returned <code>BundleOperation</code> object.
+ * If either of these methods throw a BundleException
+ * or some other error occurs,
+ * then undo must be called on the <code>BundleOperation</code> object
+ * to undo the change to persistent storage.
+ *
+ * @param bundledata BundleData to uninstall.
+ * @return BundleOperation object to be used to complete the uninstall.
+ */
+ public BundleOperation uninstallBundle(BundleData bundledata);
+
+ /**
+ * Returns the total amount of free space available for bundle storage on the device.
+ *
+ * @return Free space available in bytes or -1 if it does not apply to this adaptor
+ * @exception IOException if an I/O error occurs determining the available space
+ */
+ public long getTotalFreeSpace() throws IOException;
+
+ /**
+ * Returns the PermissionStorage object which will be used to
+ * to manage the permission data.
+ *
+ * @return The PermissionStorage object for the adaptor.
+ * @see "org.osgi.service.permissionadmin.PermissionAdmin"
+ */
+ public PermissionStorage getPermissionStorage() throws IOException;
+
+ /**
+ * Returns the <code>ServiceRegistry</code> object which will be used
+ * to manage ServiceReference bindings.
+ * @return The ServiceRegistry object for the adaptor.
+ */
+ public ServiceRegistry getServiceRegistry();
+
+ /**
+ * The framework uses this value when creating Vectors in data structures
+ * that have long lifespans. <p>
+ * This value specifies amount by which the capacity of a vector is
+ * automatically incremented when its size becomes greater than its
+ * capacity.
+ * @return The Vector capacity increment.
+ */
+ public int getVectorCapacityIncrement();
+
+ /**
+ * The framework uses this value when creating Vectors in data structures
+ * that have long lifespans. <p>
+ * This value specifies the initial capacity of a vector
+ * @return The Vector initial capacity.
+ */
+ public int getVectorInitialCapacity();
+
+ /**
+ * The framework uses this value when creating Hashtables in data structures
+ * that have long lifespans. <p>
+ * This value specifies the initial capacity of a Hashtable
+ * @return The Hashtable initial capacity.
+ */
+ public int getHashtableInitialCapacity();
+
+ /**
+ * The framework uses this value when creating Hashtables in data structures
+ * that have long lifespans. <p>
+ * This value specifies how full the hash table is allowed to get before
+ * its capacity is automatically increased.
+ * @return The Hashtable load factor.
+ */
+ public float getHashtableLoadFactor();
+
+ /**
+ * The framework will call the frameworkStart(BundleContext) method after the
+ * System BundleActivator.start(BundleContext) has been called. The context is
+ * the System Bundle's BundleContext. This method allows FrameworkAdaptors to
+ * have access to the OSGi framework to get services, register services and
+ * perform other OSGi operations.
+ * @param context The System Bundle's BundleContext.
+ * @exception BundleException on any error that may occur.
+ */
+ public void frameworkStart(BundleContext context) throws BundleException;
+
+ /**
+ * The framework will call the frameworkStop(BundleContext) method after the
+ * System BundleActivator.stop(BundleContext) has been called. The context is
+ * the System Bundle's BundleContext. This method allows FrameworkAdaptors to
+ * have access to the OSGi framework to get services, register services and
+ * perform other OSGi operations.
+ * @param context The System Bundle's BundleContext.
+ * @exception BundleException on any error that may occur.
+ */
+ public void frameworkStop(BundleContext context)throws BundleException;
+
+ /**
+ * Gets the value for Export-Package for packages that a FrameworkAdaptor is exporting
+ * to the framework. The String returned will be parsed by the framework
+ * and the packages specified will be exported by the System Bundle.
+ * @return The value for Export-Package that the System Bundle will export or
+ * null if none exist.
+ */
+ public String getExportPackages();
+
+ /**
+ * Gets any Service class names that a FrameworkAdaptor is exporting to the
+ * framework. The class names returned will be exported by the System Bundle.
+ * @return The value of Export-Service that the System Bundle will export or
+ * null if none exist
+ */
+ public String getExportServices();
+
+ /**
+ * Returns the initial bundle start level as maintained by this adaptor
+ * @return the initial bundle start level
+ */
+ public int getInitialBundleStartLevel();
+
+ /**
+ * Sets the initial bundle start level
+ * @param value the initial bundle start level
+ */
+ public void setInitialBundleStartLevel(int value);
+
+ public IBundleStats getBundleStats();
+ public PlatformAdmin getPlatformAdmin();
+ public State getState();
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/IBundleStats.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/IBundleStats.java
new file mode 100644
index 000000000..c7fdcc7be
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/IBundleStats.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osgi.framework.adaptor;
+
+/**
+ * Contains information about activated bundles and acts as the main
+ * entry point for logging plugin activity.
+ */
+
+public interface IBundleStats {
+ public void startActivation(String bundle);
+ public void endActivation(String bundle);
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ImportClassNotFoundException.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ImportClassNotFoundException.java
new file mode 100644
index 000000000..8b479765a
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ImportClassNotFoundException.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.adaptor;
+
+/**
+ * Exception class to denote that the class is in an imported package
+ * but the class was not found! This is thrown by ImportClassLoader
+ * and caught by BundleClassLoader in the loadClass method after
+ * calling parent.loadClass().
+ *
+ */
+public class ImportClassNotFoundException extends ClassNotFoundException
+{
+ /**
+ * Constructor with no detail message
+ */
+ public ImportClassNotFoundException()
+ {
+ super();
+ }
+
+ /**
+ * Constructor with detail message
+ *
+ * @param s the detail message.
+ */
+ public ImportClassNotFoundException(String s)
+ {
+ super(s);
+ }
+}
+
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ImportResourceNotFoundException.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ImportResourceNotFoundException.java
new file mode 100644
index 000000000..82f38ff11
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ImportResourceNotFoundException.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.adaptor;
+
+/**
+ * Exception class to denote that the resource is in an imported package
+ * but the resource was not found! This is thrown by ImportClassLoader
+ * and caught by BundleClassLoader in the getResource* methods after
+ * calling parent.getResource*().
+ *
+ */
+public class ImportResourceNotFoundException extends RuntimeException
+{
+ /**
+ * Constructor with no detail message
+ */
+ public ImportResourceNotFoundException()
+ {
+ super();
+ }
+
+ /**
+ * Constructor with detail message
+ *
+ * @param s the detail message.
+ */
+ public ImportResourceNotFoundException(String s)
+ {
+ super(s);
+ }
+}
+
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/PermissionStorage.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/PermissionStorage.java
new file mode 100644
index 000000000..fd6f5a23a
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/PermissionStorage.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.adaptor;
+
+import java.io.IOException;
+
+/**
+ * Permission Storage interface for managing a persistent storage of
+ * bundle permissions.
+ *
+ * <p>This class is used to provide methods to manage
+ * persistent storage of bundle permissions. The PermissionStorage object
+ * is returned by the FrameworkAdaptor object and is called
+ * to persistently store bundle permissions.
+ *
+ * <p>The permission data will typically take the form of encoded
+ * <tt>PermissionInfo</tt> Strings.
+ * See org.osgi.service.permissionadmin.PermissionInfo.
+ *
+ * <p>For example
+ * <pre>
+ * PermissionStorage storage = adaptor.getPermissionStorage();
+ * try {
+ * storage.setPermissionData(location, permissions);
+ * } catch (IOException e) {
+ * // Take some error action.
+ * }
+ * </pre>
+ *
+ */
+public interface PermissionStorage
+{
+ /**
+ * Returns the locations that have permission data assigned to them,
+ * that is, locations for which permission data
+ * exists in persistent storage.
+ *
+ * @return The locations that have permission data in
+ * persistent storage, or <tt>null</tt> if there is no permission data
+ * in persistent storage.
+ * @throws IOException If a failure occurs accessing peristent storage.
+ */
+ public abstract String[] getLocations() throws IOException;
+
+ /**
+ * Gets the permission data assigned to the specified
+ * location.
+ *
+ * @param location The location whose permission data is to
+ * be returned.
+ * The location can be <tt>null</tt> for the default permission data.
+ *
+ * @return The permission data assigned to the specified
+ * location, or <tt>null</tt> if that location has not been assigned any
+ * permission data.
+ * @throws IOException If a failure occurs accessing peristent storage.
+ */
+ public abstract String[] getPermissionData(String location) throws IOException;
+
+ /**
+ * Assigns the specified permission data to the specified
+ * location.
+ *
+ * @param location The location that will be assigned the
+ * permissions.
+ * The location can be <tt>null</tt> for the default permission data.
+ * @param data The permission data to be assigned, or <tt>null</tt>
+ * if the specified location is to be removed from persistent storaqe.
+ * @throws IOException If a failure occurs modifying peristent storage.
+ */
+ public abstract void setPermissionData(String location, String[] data) throws IOException;
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ServiceRegistry.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ServiceRegistry.java
new file mode 100644
index 000000000..c7b4a8fb2
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ServiceRegistry.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.adaptor;
+
+import java.util.Vector;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * The ServiceRegistry interface is used by the framework to store and
+ * lookup currently registered services.
+ */
+public interface ServiceRegistry {
+
+ /**
+ * Publishes a service to this ServiceRegistry.
+ * @param context the BundleContext that registered the service.
+ * @param serviceReg the ServiceRegistration to register.
+ */
+ public void publishService(BundleContext context, ServiceRegistration serviceReg);
+
+ /**
+ * Unpublishes a service from this ServiceRegistry
+ * @param context the BundleContext that registered the service.
+ * @param serviceReg the ServiceRegistration to unpublish.
+ */
+ public void unpublishService(BundleContext context, ServiceRegistration serviceReg);
+
+ /**
+ * Unpublishes all services from this ServiceRegistry that the
+ * specified BundleContext registered.
+ * @param context the BundleContext to unpublish all services for.
+ */
+ public void unpublishServices(BundleContext context);
+
+ /**
+ * Performs a lookup for ServiceReferences that are bound to this
+ * ServiceRegistry. If both clazz and filter are null then all bound
+ * ServiceReferences are returned.
+ * @param clazz A fully qualified class name. All ServiceReferences that
+ * reference an object that implement this class are returned. May be
+ * null.
+ * @param filter Used to match against published Services. All
+ * ServiceReferences that match the filter are returned. If a clazz is
+ * specified then all ServiceReferences that match the clazz and the
+ * filter parameter are returned. May be null.
+ * @return A Vector of all matching ServiceReferences or null
+ * if none exist.
+ */
+ public Vector lookupServiceReferences(String clazz, Filter filter);
+
+ /**
+ * Performs a lookup for ServiceReferences that are bound to this
+ * ServiceRegistry using the specified BundleContext.
+ * @param context The BundleContext to lookup the ServiceReferences on.
+ * @return A Vector of all matching ServiceReferences or null if none
+ * exist.
+ */
+ public Vector lookupServiceReferences(BundleContext context);
+
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/Version.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/Version.java
new file mode 100644
index 000000000..bd7e4a4f6
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/Version.java
@@ -0,0 +1,521 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osgi.framework.adaptor;
+
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+/**
+ * <p>
+ * Version identifier for a plug-in. In its string representation,
+ * it consists of up to 4 tokens separated by a decimal point.
+ * The first 3 tokens are positive integer numbers, the last token
+ * is an uninterpreted string (no whitespace characters allowed).
+ * For example, the following are valid version identifiers
+ * (as strings):
+ * <ul>
+ * <li><code>0.0.0</code></li>
+ * <li><code>1.0.127564</code></li>
+ * <li><code>3.7.2.build-127J</code></li>
+ * <li><code>1.9</code> (interpreted as <code>1.9.0</code>)</li>
+ * <li><code>3</code> (interpreted as <code>3.0.0</code>)</li>
+ * </ul>
+ * </p>
+ * <p>
+ * The version identifier can be decomposed into a major, minor,
+ * service level component and qualifier components. A difference
+ * in the major component is interpreted as an incompatible version
+ * change. A difference in the minor (and not the major) component
+ * is interpreted as a compatible version change. The service
+ * level component is interpreted as a cumulative and compatible
+ * service update of the minor version component. The qualifier is
+ * not interpreted, other than in version comparisons. The
+ * qualifiers are compared using lexicographical string comparison.
+ * </p>
+ * <p>
+ * Version identifiers can be matched as perfectly equal, equivalent,
+ * compatible or greaterOrEqual.
+ * </p>
+ * <p>
+ * Clients may instantiate; not intended to be subclassed by clients.
+ * </p>
+ * @see IPluginDescriptor#getVersionIdentifier
+ * @see java.lang.String#compareTo
+ */
+public final class Version implements Comparable {
+
+ private int major = 0;
+ private int minor = 0;
+ private int service = 0;
+ private String qualifier = ""; //$NON-NLS-1$
+
+ private static final String SEPARATOR = "."; //$NON-NLS-1$
+
+ public static Version emptyVersion = new Version(0, 0, 0);
+
+ /**
+ * Creates a plug-in version identifier from a given Version.
+ *
+ * @param version
+ */
+ public Version(Version version) {
+ this(version.major, version.minor, version.service, version.qualifier);
+ }
+
+ /**
+ * Creates a plug-in version identifier from its components.
+ *
+ * @param major major component of the version identifier
+ * @param minor minor component of the version identifier
+ * @param service service update component of the version identifier
+ */
+ public Version(int major, int minor, int service) {
+ this(major, minor, service, null);
+ }
+ /**
+ * Creates a plug-in version identifier from its components.
+ *
+ * @param major major component of the version identifier
+ * @param minor minor component of the version identifier
+ * @param service service update component of the version identifier
+ * @param qualifier qualifier component of the version identifier.
+ * Qualifier characters that are not a letter or a digit are replaced.
+ */
+ public Version(int major, int minor, int service, String qualifier)
+ throws IllegalArgumentException {
+
+ // Do the test outside of the assert so that they 'Policy.bind'
+ // will not be evaluated each time (including cases when we would
+ // have passed by the assert).
+
+ if (major < 0)
+ throw new IllegalArgumentException("Negative major");
+ if (minor < 0)
+ throw new IllegalArgumentException("Negative minor");
+ if (service < 0)
+ throw new IllegalArgumentException("Negative service");
+ if (qualifier == null)
+ qualifier = ""; //$NON-NLS-1$
+
+ this.major = major;
+ this.minor = minor;
+ this.service = service;
+ this.qualifier = verifyQualifier(qualifier);
+ }
+ /**
+ * Creates a plug-in version identifier from the given string.
+ * The string represenation consists of up to 4 tokens
+ * separated by decimal point.
+ * For example, the following are valid version identifiers
+ * (as strings):
+ * <ul>
+ * <li><code>0.0.0</code></li>
+ * <li><code>1.0.127564</code></li>
+ * <li><code>3.7.2.build-127J</code></li>
+ * <li><code>1.9</code> (interpreted as <code>1.9.0</code>)</li>
+ * <li><code>3</code> (interpreted as <code>3.0.0</code>)</li>
+ * </ul>
+ * </p>
+ *
+ * @param versionId string representation of the version identifier.
+ * Qualifier characters that are not a letter or a digit are replaced.
+ */
+ public Version(String versionId) {
+ if (versionId==null) versionId = "0.0.0";
+ Object[] parts = parseVersion(versionId);
+ this.major = ((Integer) parts[0]).intValue();
+ this.minor = ((Integer) parts[1]).intValue();
+ this.service = ((Integer) parts[2]).intValue();
+ this.qualifier = (String) parts[3];
+ }
+ /**
+ * Validates the given string as a plug-in version identifier.
+ *
+ * @param version the string to validate
+ * @return a status object with code <code>IStatus.OK</code> if
+ * the given string is valid as a plug-in version identifier, otherwise a status
+ * object indicating what is wrong with the string
+ * @since 2.0
+ */
+ public static RuntimeException validateVersion(String version) {
+ try {
+ parseVersion(version);
+ } catch (RuntimeException e) {
+ return e;
+ // OG...
+ // return new Status(IStatus.ERROR, Platform.PI_RUNTIME, IStatus.ERROR, e.getMessage(), e);
+ }
+ return null;
+ // OG...
+ // return new Status(IStatus.OK, Platform.PI_RUNTIME, IStatus.OK, Policy.bind("ok"), null); //$NON-NLS-1$
+ }
+ private static Object[] parseVersion(String versionId) {
+
+ // Do the test outside of the assert so that they 'Policy.bind'
+ // will not be evaluated each time (including cases when we would
+ // have passed by the assert).
+ if (versionId == null)
+ throw new IllegalArgumentException("Null version string");
+
+ String s = versionId.trim();
+ if (s.equals("")) //$NON-NLS-1$
+ throw new IllegalArgumentException("Empty version string");
+ if (s.startsWith(SEPARATOR))
+ throw new IllegalArgumentException("Invalid version format");
+ if (s.endsWith(SEPARATOR))
+ throw new IllegalArgumentException("Invalid version format");
+ if (s.indexOf(SEPARATOR + SEPARATOR) != -1)
+ throw new IllegalArgumentException("Invalid version format");
+
+ StringTokenizer st = new StringTokenizer(s, SEPARATOR);
+ Vector elements = new Vector(4);
+
+ while (st.hasMoreTokens())
+ elements.addElement(st.nextToken());
+
+ int elementSize = elements.size();
+
+ if (elementSize <= 0)
+ throw new IllegalArgumentException("Invalid version format (no token)");
+ if (elementSize > 4)
+ throw new IllegalArgumentException("Invalid version format (more than 4 tokens)");
+
+ int[] numbers = new int[3];
+ try {
+ numbers[0] = Integer.parseInt((String) elements.elementAt(0));
+ if (numbers[0] < 0)
+ throw new IllegalArgumentException("Negative major");
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException("Invalid major");
+ }
+
+ try {
+ if (elementSize >= 2) {
+ numbers[1] = Integer.parseInt((String) elements.elementAt(1));
+ if (numbers[1] < 0)
+ throw new IllegalArgumentException("Negative minor");
+ } else
+ numbers[1] = 0;
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException("Invalid minor");
+ }
+
+ try {
+ if (elementSize >= 3) {
+ numbers[2] = Integer.parseInt((String) elements.elementAt(2));
+ if (numbers[2] < 0)
+ throw new IllegalArgumentException("Invalid service");
+ } else
+ numbers[2] = 0;
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException("Invalid service");
+ }
+
+ // "result" is a 4-element array with the major, minor, service, and qualifier
+ Object[] result = new Object[4];
+ result[0] = new Integer(numbers[0]);
+ result[1] = new Integer(numbers[1]);
+ result[2] = new Integer(numbers[2]);
+ if (elementSize >= 4)
+ result[3] = verifyQualifier((String) elements.elementAt(3));
+ else
+ result[3] = ""; //$NON-NLS-1$
+ return result;
+ }
+ /**
+ * Compare version identifiers for equality. Identifiers are
+ * equal if all of their components are equal.
+ *
+ * @param object an object to compare
+ * @return whehter or not the two objects are equal
+ */
+ public boolean equals(Object object) {
+ if (!(object instanceof Version))
+ return false;
+ Version v = (Version) object;
+ return v.getMajorComponent() == major
+ && v.getMinorComponent() == minor
+ && v.getServiceComponent() == service
+ && v.getQualifierComponent().equals(qualifier);
+ }
+ /**
+ * Returns a hash code value for the object.
+ *
+ * @return an integer which is a hash code value for this object.
+ */
+ public int hashCode() {
+ int code = major + minor + service; // R1.0 result
+ if (qualifier.equals("")) //$NON-NLS-1$
+ return code;
+ else
+ return code + qualifier.hashCode();
+ }
+ /**
+ * Returns the major (incompatible) component of this
+ * version identifier.
+ *
+ * @return the major version
+ */
+ public int getMajorComponent() {
+ return major;
+ }
+ /**
+ * Returns the minor (compatible) component of this
+ * version identifier.
+ *
+ * @return the minor version
+ */
+ public int getMinorComponent() {
+ return minor;
+ }
+ /**
+ * Returns the service level component of this
+ * version identifier.
+ *
+ * @return the service level
+ */
+ public int getServiceComponent() {
+ return service;
+ }
+ /**
+ * Returns the qualifier component of this
+ * version identifier.
+ *
+ * @return the qualifier
+ */
+ public String getQualifierComponent() {
+ return qualifier;
+ }
+ /**
+ * Compares two version identifiers to see if this one is
+ * greater than or equal to the argument.
+ * <p>
+ * A version identifier is considered to be greater than or equal
+ * if its major component is greater than the argument major
+ * component, or the major components are equal and its minor component
+ * is greater than the argument minor component, or the
+ * major and minor components are equal and its service component is
+ * greater than the argument service component, or the major, minor and
+ * service components are equal and the qualifier component is
+ * greated than the argument qualifier component (using lexicographic
+ * string comparison), or all components are equal.
+ * </p>
+ *
+ * @param versionId the other version identifier
+ * @return <code>true</code> is this version identifier
+ * is compatible with the given version identifier, and
+ * <code>false</code> otherwise
+ * @since 2.0
+ */
+ public boolean isGreaterOrEqualTo(Version id) {
+ if (id == null)
+ return false;
+ if (major > id.getMajorComponent())
+ return true;
+ if ((major == id.getMajorComponent()) && (minor > id.getMinorComponent()))
+ return true;
+ if ((major == id.getMajorComponent())
+ && (minor == id.getMinorComponent())
+ && (service > id.getServiceComponent()))
+ return true;
+ if ((major == id.getMajorComponent())
+ && (minor == id.getMinorComponent())
+ && (service == id.getServiceComponent())
+ && (qualifier.compareTo(id.getQualifierComponent()) >= 0))
+ return true;
+ else
+ return false;
+ }
+ /**
+ * Compares two version identifiers for compatibility.
+ * <p>
+ * A version identifier is considered to be compatible if its major
+ * component equals to the argument major component, and its minor component
+ * is greater than or equal to the argument minor component.
+ * If the minor components are equal, than the service level of the
+ * version identifier must be greater than or equal to the service level
+ * of the argument identifier. If the service levels are equal, the two
+ * version identifiers are considered to be equivalent if this qualifier is
+ * greated or equal to the qualifier of the argument (using lexicographic
+ * string comparison).
+ * </p>
+ *
+ * @param versionId the other version identifier
+ * @return <code>true</code> is this version identifier
+ * is compatible with the given version identifier, and
+ * <code>false</code> otherwise
+ */
+ public boolean isCompatibleWith(Version id) {
+ if (id == null)
+ return false;
+ if (major != id.getMajorComponent())
+ return false;
+ if (minor > id.getMinorComponent())
+ return true;
+ if (minor < id.getMinorComponent())
+ return false;
+ if (service > id.getServiceComponent())
+ return true;
+ if (service < id.getServiceComponent())
+ return false;
+ if (qualifier.compareTo(id.getQualifierComponent()) >= 0)
+ return true;
+ else
+ return false;
+ }
+ /**
+ * Compares two version identifiers for equivalency.
+ * <p>
+ * Two version identifiers are considered to be equivalent if their major
+ * and minor component equal and are at least at the same service level
+ * as the argument. If the service levels are equal, the two version
+ * identifiers are considered to be equivalent if this qualifier is
+ * greated or equal to the qualifier of the argument (using lexicographic
+ * string comparison).
+ *
+ * </p>
+ *
+ * @param versionId the other version identifier
+ * @return <code>true</code> is this version identifier
+ * is equivalent to the given version identifier, and
+ * <code>false</code> otherwise
+ */
+ public boolean isEquivalentTo(Version id) {
+ if (id == null)
+ return false;
+ if (major != id.getMajorComponent())
+ return false;
+ if (minor != id.getMinorComponent())
+ return false;
+ if (service > id.getServiceComponent())
+ return true;
+ if (service < id.getServiceComponent())
+ return false;
+ if (qualifier.compareTo(id.getQualifierComponent()) >= 0)
+ return true;
+ else
+ return false;
+ }
+ /**
+ * Compares two version identifiers for perfect equality.
+ * <p>
+ * Two version identifiers are considered to be perfectly equal if their
+ * major, minor, service and qualifier components are equal
+ * </p>
+ *
+ * @param versionId the other version identifier
+ * @return <code>true</code> is this version identifier
+ * is perfectly equal to the given version identifier, and
+ * <code>false</code> otherwise
+ * @since 2.0
+ */
+ public boolean isPerfect(Version id) {
+ if (id == null)
+ return false;
+ if ((major != id.getMajorComponent())
+ || (minor != id.getMinorComponent())
+ || (service != id.getServiceComponent())
+ || (!qualifier.equals(id.getQualifierComponent())))
+ return false;
+ else
+ return true;
+ }
+ /**
+ * Compares two version identifiers for order using multi-decimal
+ * comparison.
+ *
+ * @param versionId the other version identifier
+ * @return <code>true</code> is this version identifier
+ * is greater than the given version identifier, and
+ * <code>false</code> otherwise
+ */
+ public boolean isGreaterThan(Version id) {
+
+ if (id == null) {
+ if (major == 0 && minor == 0 && service == 0 && qualifier.equals(""))
+ return false; //$NON-NLS-1$
+ else
+ return true;
+ }
+
+ if (major > id.getMajorComponent())
+ return true;
+ if (major < id.getMajorComponent())
+ return false;
+ if (minor > id.getMinorComponent())
+ return true;
+ if (minor < id.getMinorComponent())
+ return false;
+ if (service > id.getServiceComponent())
+ return true;
+ if (service < id.getServiceComponent())
+ return false;
+ if (qualifier.compareTo(id.getQualifierComponent()) > 0)
+ return true;
+ else
+ return false;
+
+ }
+ /**
+ * Returns the string representation of this version identifier.
+ * The result satisfies
+ * <code>vi.equals(new PluginVersionIdentifier(vi.toString()))</code>.
+ *
+ * @return the string representation of this plug-in version identifier
+ */
+ public String toString() {
+ String base = major + SEPARATOR + minor + SEPARATOR + service;
+ // R1.0 result
+ if (qualifier.equals("")) //$NON-NLS-1$
+ return base;
+ else
+ return base + SEPARATOR + qualifier;
+ }
+
+ private static String verifyQualifier(String s) {
+ char[] chars = s.trim().toCharArray();
+ boolean whitespace = false;
+ for (int i = 0; i < chars.length; i++) {
+ char c = chars[i];
+ if (!(Character.isLetter(c) || Character.isDigit(c))) {
+ chars[i] = '-';
+ whitespace = true;
+ }
+ }
+ return whitespace ? new String(chars) : s;
+ }
+
+ /**
+ * Compares this Version object with the specified Version object for order.
+ * Returns a negative integer, zero, or a positive integer as this object is less
+ * than, equal to, or greater than the specified object.<p>
+ *
+ * @param obj the Version object to be compared.
+ * @return a negative integer, zero, or a positive integer as this object
+ * is less than, equal to, or greater than the specified Version object.
+ *
+ * @throws ClassCastException if the specified object's type
+ * is not Version.
+ */
+ public int compareTo(Object o) {
+ if (!(o instanceof Version))
+ throw new ClassCastException();
+
+ Version version = (Version) o;
+ if (equals(o))
+ return 0;
+
+ if (isGreaterThan((Version) o))
+ return 1;
+
+ return -1;
+ }
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/core/AbstractBundleData.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/core/AbstractBundleData.java
new file mode 100644
index 000000000..0cc98ffab
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/core/AbstractBundleData.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.adaptor.core;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Dictionary;
+
+import org.eclipse.osgi.framework.adaptor.BundleData;
+import org.eclipse.osgi.framework.internal.core.Constants;
+import org.eclipse.osgi.framework.internal.core.Msg;
+import org.eclipse.osgi.framework.util.Headers;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+
+/**
+ * An abstract BundleData class that has default implementations that most
+ * BundleData implementations can use.
+ */
+public abstract class AbstractBundleData implements BundleData {
+
+ /**
+ * The BundleManfifest for this BundleData.
+ */
+ protected Dictionary manifest = null;
+
+ /**
+ * The Bundle object for this BundleData.
+ */
+ protected Bundle bundle;
+
+ /**
+ * Return the BundleManifest for the BundleData. If the manifest
+ * field is null this method will parse the bundle manifest file and
+ * construct a BundleManifest file to return. If the manifest field is
+ * not null then the manifest object is returned.
+ * @return BundleManifest for the BundleData.
+ * @throws BundleException if an error occurred while reading the
+ * bundle manifest data.
+ */
+ public Dictionary getManifest() throws BundleException {
+ if (manifest == null) {
+ synchronized (this) {
+ // make sure the manifest is still null after we have aquired the lock.
+ if (manifest == null) {
+ URL url = getEntry(Constants.OSGI_BUNDLE_MANIFEST);
+ if (url == null){
+ throw new BundleException(Msg.formatter.getString("MANIFEST_NOT_FOUND_EXCEPTION",Constants.OSGI_BUNDLE_MANIFEST,getLocation()));
+ }
+ try {
+ manifest = Headers.parseManifest(url.openStream());
+ } catch (IOException e) {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_NOT_FOUND_EXCEPTION",Constants.OSGI_BUNDLE_MANIFEST,getLocation()), e);
+ }
+ }
+ }
+ }
+ return manifest;
+ }
+
+ /**
+ * Returns a Dictionary of all manifest headers. Returns the
+ * BundleManifest object of this BundleData. Note that the core
+ * implementation of BundleManifest extends the Dictionary class.
+ * @return A Dictionary of all manifest headers.
+ */
+ public Dictionary getHeaders(){
+ try {
+ return getManifest();
+ } catch (BundleException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Sets the Bundle object for this BundleData.
+ * @param bundle The Bundle Object for this BundleData.
+ */
+ public void setBundle(Bundle bundle){
+ this.bundle = bundle;
+ }
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/core/AbstractFrameworkAdaptor.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/core/AbstractFrameworkAdaptor.java
new file mode 100644
index 000000000..90d7a1928
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/core/AbstractFrameworkAdaptor.java
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.adaptor.core;
+
+import java.io.*;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Properties;
+import org.eclipse.osgi.framework.adaptor.EventPublisher;
+import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor;
+import org.eclipse.osgi.framework.debug.Debug;
+import org.eclipse.osgi.framework.internal.core.Constants;
+import org.eclipse.osgi.framework.internal.core.Msg;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+
+/**
+ * An abstract FrameworkAdaptor class that has default implementations that most
+ * FrameworkAdaptor implementations can use.
+ */
+public abstract class AbstractFrameworkAdaptor implements FrameworkAdaptor {
+
+ protected EventPublisher eventPublisher;
+
+ /**
+ * The ServiceRegistry object for this FrameworkAdaptor.
+ */
+ protected ServiceRegistry serviceRegistry;
+
+ /**
+ * The Properties object for this FrameworkAdaptor
+ */
+ protected Properties properties;
+
+ /**
+ * The System Bundle's BundleContext.
+ */
+ protected BundleContext context;
+
+ /**
+ * The Vector Initial Capacity value.
+ */
+ protected int vic;
+
+ /**
+ * The Vector Capacity Increment value.
+ */
+ protected int vci;
+
+ /**
+ * The Hashtable Initial Capacity value.
+ */
+ protected int hic;
+
+ /**
+ * The Hashtable Load Factor value.
+ */
+ protected float hlf;
+
+ /**
+ * The initial bundle start level.
+ */
+ protected int initialBundleStartLevel = 1;
+ /**
+ * Initializes the ServiceRegistry, loads the properties for this
+ * FrameworkAdaptor and initializes all the Vector and Hashtable capacity,
+ * increment and factor values.
+ * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#initialize()
+ */
+ public void initialize(EventPublisher eventPublisher) {
+ this.eventPublisher = eventPublisher;
+ serviceRegistry = new ServiceRegistry();
+ serviceRegistry.initialize();
+ loadProperties();
+ vic = 10;
+ vci = 10;
+ hic = 10;
+ hlf = 0.75f;
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getProperties()
+ */
+ public Properties getProperties() {
+ return properties;
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#mapLocationToURLConnection(String)
+ */
+ public URLConnection mapLocationToURLConnection(String location) throws BundleException {
+ try {
+ return (new URL(location).openConnection());
+ } catch (IOException e) {
+ throw new BundleException(Msg.formatter.getString("ADAPTOR_URL_CREATE_EXCEPTION", location), e);
+ }
+ }
+
+ /**
+ * Always returns -1 to indicate that this operation is not supported by this
+ * FrameworkAdaptor. Extending classes should override this method if
+ * they support this operation.
+ * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getTotalFreeSpace()
+ */
+ public long getTotalFreeSpace() throws IOException {
+ return -1;
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getServiceRegistry()
+ */
+ public org.eclipse.osgi.framework.adaptor.ServiceRegistry getServiceRegistry() {
+ return serviceRegistry;
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getVectorInitialCapacity()
+ */
+ public int getVectorInitialCapacity() {
+ return vic;
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getVectorCapacityIncrement()
+ */
+ public int getVectorCapacityIncrement(){
+ return vci;
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getHashtableInitialCapacity()
+ */
+ public int getHashtableInitialCapacity() {
+ return hic;
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getHashtableLoadFactor()
+ */
+ public float getHashtableLoadFactor() {
+ return hlf;
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#frameworkStart(org.osgi.framework.BundleContext)
+ */
+ public void frameworkStart(BundleContext context) throws BundleException
+ {
+ this.context = context;
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#frameworkStop(org.osgi.framework.BundleContext)
+ */
+ public void frameworkStop(BundleContext context) throws BundleException
+ {
+ this.context = null;
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getExportPackages()
+ */
+ public String getExportPackages()
+ {
+ return null;
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getExportServices()
+ */
+ public String getExportServices()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the EventPublisher for this FrameworkAdaptor.
+ * @return The EventPublisher.
+ */
+ public EventPublisher getEventPublisher(){
+ return eventPublisher;
+ }
+
+ /**
+ * This method locates and reads the osgi.properties file.
+ * If the system property <i>org.eclipse.osgi.framework.internal.core.properties</i> is specifed, its value
+ * will be used as the name of the file instead of
+ * <tt>osgi.properties</tt>. There are 3 places to look for these properties. These
+ * 3 places are searched in the following order, stopping when the properties are found.
+ *
+ * <ol>
+ * <li>Look for a file in the file system
+ * <li>Look for a resource in the FrameworkAdaptor's package
+ * </ol>
+ */
+ protected void loadProperties() {
+ properties = new Properties();
+
+ String resource = System.getProperty(Constants.KEY_OSGI_PROPERTIES, Constants.DEFAULT_OSGI_PROPERTIES);
+
+ try
+ {
+ InputStream in = null;
+ File file = new File(resource);
+ if (file.exists())
+ {
+ in = new FileInputStream(file);
+ }
+
+ if (in == null)
+ {
+ in = getClass().getResourceAsStream(resource);
+ }
+
+
+ if (in != null)
+ {
+ try
+ {
+ properties.load(new BufferedInputStream(in));
+ }
+ finally
+ {
+ try
+ {
+ in.close();
+ }
+ catch (IOException ee)
+ {
+ }
+ }
+ }
+ else
+ {
+ Debug.println("Unable to find osgi.properties");
+ }
+ }
+ catch (IOException e)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println("Unable to load osgi.properties: " + e.getMessage());
+ }
+ }
+ }
+
+ public int getInitialBundleStartLevel() {
+ return initialBundleStartLevel;
+ }
+
+ public void setInitialBundleStartLevel(int value) {
+ initialBundleStartLevel = value;
+ }
+
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/core/ServiceRegistry.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/core/ServiceRegistry.java
new file mode 100644
index 000000000..ce3d79066
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/core/ServiceRegistry.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.adaptor.core;
+
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * A default implementation of the ServiceRegistry.
+ */
+public class ServiceRegistry implements org.eclipse.osgi.framework.adaptor.ServiceRegistry {
+
+ /** Published services by class name. Key is a String class name; Value is a Vector of ServiceRegistrations */
+ protected Hashtable publishedServicesByClass;
+ /** All published services. Value is ServiceRegistrations */
+ protected Vector allPublishedServices;
+ /** Published services by BundleContext. Key is a BundleContext; Value is a Vector of ServiceRegistrations*/
+ protected Hashtable publishedServicesByContext;
+
+ /**
+ * Initializes the internal data structures of this ServiceRegistry.
+ *
+ */
+ public void initialize(){
+ publishedServicesByClass = new Hashtable(53);
+ publishedServicesByContext = new Hashtable(53);
+ allPublishedServices = new Vector(50, 20);
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.ServiceRegistry#publishService(BundleContext, ServiceRegistration)
+ */
+ public void publishService(BundleContext context, ServiceRegistration serviceReg) {
+
+ // Add the ServiceRegistration to the list of Services published by BundleContext.
+ Vector contextServices = (Vector) publishedServicesByContext.get(context);
+ if (contextServices == null) {
+ contextServices = new Vector(10, 10);
+ publishedServicesByContext.put(context, contextServices);
+ }
+ contextServices.addElement(serviceReg);
+
+ // Add the ServiceRegistration to the list of Services published by Class Name.
+ String[] clazzes = (String[]) serviceReg.getReference().getProperty(Constants.OBJECTCLASS);
+ int size = clazzes.length;
+
+ for (int i = 0; i < size; i++) {
+ String clazz = clazzes[i];
+
+ Vector services = (Vector) publishedServicesByClass.get(clazz);
+
+ if (services == null) {
+ services = new Vector(10, 10);
+ publishedServicesByClass.put(clazz, services);
+ }
+
+ services.addElement(serviceReg);
+ }
+
+ // Add the ServiceRegistration to the list of all published Services.
+ allPublishedServices.addElement(serviceReg);
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.ServiceRegistry#unpublishService(BundleContext, ServiceRegistration)
+ */
+ public void unpublishService(BundleContext context, ServiceRegistration serviceReg) {
+
+ // Remove the ServiceRegistration from the list of Services published by BundleContext.
+ Vector contextServices = (Vector) publishedServicesByContext.get(context);
+ if (contextServices != null) {
+ contextServices.removeElement(serviceReg);
+ }
+
+ // Remove the ServiceRegistration from the list of Services published by Class Name.
+ String[] clazzes = (String[]) serviceReg.getReference().getProperty(Constants.OBJECTCLASS);
+ int size = clazzes.length;
+
+ for (int i = 0; i < size; i++) {
+ String clazz = clazzes[i];
+ Vector services = (Vector) publishedServicesByClass.get(clazz);
+ services.removeElement(serviceReg);
+ }
+
+ // Remove the ServiceRegistration from the list of all published Services.
+ allPublishedServices.removeElement(serviceReg);
+
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.ServiceRegistry#unpublishServices(BundleContext)
+ */
+ public void unpublishServices(BundleContext context) {
+ // Get all the Services published by the BundleContext.
+ Vector serviceRegs = (Vector) publishedServicesByContext.get(context);
+ if (serviceRegs != null) {
+ // Remove this list for the BundleContext
+ publishedServicesByContext.remove(context);
+ int size = serviceRegs.size();
+ for (int i = 0; i < size; i++) {
+ ServiceRegistration serviceReg = (ServiceRegistration) serviceRegs.elementAt(i);
+ // Remove each service from the list of all published Services
+ allPublishedServices.removeElement(serviceReg);
+
+ // Remove each service from the list of Services published by Class Name.
+ String[] clazzes = (String[]) serviceReg.getReference().getProperty(Constants.OBJECTCLASS);
+ int numclazzes = clazzes.length;
+
+ for (int j = 0; j < numclazzes; j++) {
+ String clazz = clazzes[j];
+ Vector services = (Vector) publishedServicesByClass.get(clazz);
+ services.removeElement(serviceReg);
+ }
+ }
+ }
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.ServiceRegistry#lookupServiceReferences(String, Filter)
+ */
+ public Vector lookupServiceReferences(String clazz, Filter filter) {
+ int size;
+ Vector references = new Vector();
+
+ if (clazz == null) /* all services */ {
+ Vector serviceRegs = allPublishedServices;
+
+ if (serviceRegs == null) {
+ return (null);
+ }
+
+ size = serviceRegs.size();
+
+ if (size == 0) {
+ return (null);
+ }
+
+ for (int i = 0; i < size; i++) {
+ ServiceRegistration registration = (ServiceRegistration) serviceRegs.elementAt(i);
+
+ ServiceReference reference = registration.getReference();
+ if ((filter == null) || filter.match(reference)) {
+ references.addElement(reference);
+ }
+ }
+ } else /* services registered under the class name */ {
+ Vector serviceRegs = (Vector) publishedServicesByClass.get(clazz);
+
+ if (serviceRegs == null) {
+ return (null);
+ }
+
+ size = serviceRegs.size();
+
+ if (size == 0) {
+ return (null);
+ }
+
+ for (int i = 0; i < size; i++) {
+ ServiceRegistration registration = (ServiceRegistration) serviceRegs.elementAt(i);
+
+ ServiceReference reference = registration.getReference();
+ if ((filter == null) || filter.match(reference)) {
+ references.addElement(reference);
+ }
+ }
+ }
+
+ if (references.size() == 0) {
+ return null;
+ }
+
+ return (references);
+
+ }
+
+ /**
+ * @see org.eclipse.osgi.framework.adaptor.ServiceRegistry#lookupServiceReferences(BundleContext)
+ */
+ public Vector lookupServiceReferences(BundleContext context){
+ int size;
+ Vector references = new Vector();
+ Vector serviceRegs = (Vector) publishedServicesByContext.get(context);
+
+ if (serviceRegs == null) {
+ return (null);
+ }
+
+ size = serviceRegs.size();
+
+ if (size == 0) {
+ return (null);
+ }
+
+ for (int i = 0; i < size; i++) {
+ ServiceRegistration registration = (ServiceRegistration) serviceRegs.elementAt(i);
+
+ ServiceReference reference = registration.getReference();
+ references.addElement(reference);
+ }
+
+ if (references.size() == 0) {
+ return null;
+ }
+
+ return (references);
+ }
+
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/Headers.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/Headers.java
new file mode 100644
index 000000000..1b57cb243
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/Headers.java
@@ -0,0 +1,312 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.eclipse.osgi.framework.internal.core.Msg;
+import org.osgi.framework.BundleException;
+
+/**
+ * Headers classes. This class implements a Dictionary that has
+ * the following behaviour:
+ * <ul>
+ * <li>put and remove clear throw UnsupportedOperationException.
+ * The Dictionary is thus read-only to others.
+ * <li>The String keys in the Dictionary are case-preserved,
+ * but the get operation is case-insensitive.
+ * </ul>
+ */
+public class Headers extends Dictionary
+{
+ /**
+ * Dictionary of keys: Lower case key => Case preserved key.
+ */
+ protected Dictionary headers;
+
+ /**
+ * Dictionary of values: Case preserved key => value.
+ */
+ protected Dictionary values;
+
+ /**
+ * Create an empty Headers dictionary.
+ *
+ * @param initialCapacity The initial capacity of this Headers object.
+ */
+ public Headers(int initialCapacity)
+ {
+ super();
+
+ headers = new Hashtable(initialCapacity);
+ values = new Hashtable(initialCapacity);
+ }
+
+ /**
+ * Create a Headers dictionary from a Dictionary.
+ *
+ * @param values The initial dictionary for this Headers object.
+ * @exception IllegalArgumentException If a case-variant of the key is
+ * in the dictionary parameter.
+ */
+ public Headers(Dictionary values)
+ {
+ super();
+
+ headers = new Hashtable(values.size());
+ this.values = values;
+
+ /* initialize headers dictionary */
+ Enumeration enum = values.keys();
+
+ while (enum.hasMoreElements())
+ {
+ Object key = enum.nextElement();
+
+ if (key instanceof String)
+ {
+ String header = ((String)key).toLowerCase();
+
+ if (headers.put(header, key) != null) /* if case-variant already present */
+ {
+ throw new IllegalArgumentException(Msg.formatter.getString("HEADER_DUPLICATE_KEY_EXCEPTION", header));
+ }
+ }
+ }
+ }
+
+ /**
+ * Case-preserved keys.
+ */
+ public synchronized Enumeration keys()
+ {
+ return(values.keys());
+ }
+
+ /**
+ * Values.
+ */
+ public synchronized Enumeration elements()
+ {
+ return(values.elements());
+ }
+
+ /**
+ * Support case-insensitivity for keys.
+ *
+ * @param key name.
+ */
+ public synchronized Object get(Object key)
+ {
+ Object value = values.get(key);
+
+ if ((value == null) && (key instanceof String))
+ {
+ key = headers.get(((String)key).toLowerCase());
+
+ if (key != null)
+ {
+ value = values.get(key);
+ }
+ }
+
+ return(value);
+ }
+
+ /**
+ * Set a header value.
+ *
+ * @param key Key name.
+ * @param value Value of the key or null to remove key.
+ * @return the previous value to which the key was mapped,
+ * or null if the key did not have a previous mapping.
+ *
+ * @exception IllegalArgumentException If a case-variant of the key is
+ * already present.
+ */
+ public synchronized Object set(Object key, Object value)
+ {
+ String header = (key instanceof String) ? ((String)key).toLowerCase() : null;
+
+ if (value == null) /* remove */
+ {
+ if (header != null) /* String key */
+ {
+ key = headers.remove(header);
+
+ if (key != null) /* is String key in hashtable? */
+ {
+ value = values.remove(key);
+ }
+ }
+ else /* non-String key */
+ {
+ value = values.remove(key);
+ }
+
+ return(value);
+ }
+ else /* put */
+ {
+ if (header != null) /* String key */
+ {
+ Object oldKey = headers.put(header, key);
+
+ if ((oldKey != null) && !header.equals(oldKey)) /* if case-variant already present */
+ {
+ headers.put(header, oldKey); /* put old case-variant back */
+
+ throw new IllegalArgumentException(Msg.formatter.getString("HEADER_DUPLICATE_KEY_EXCEPTION", header));
+ }
+
+ }
+
+ return(values.put(key, value));
+ }
+
+ }
+
+ /**
+ * Returns the number of entries (distinct keys) in this dictionary.
+ *
+ * @return the number of keys in this dictionary.
+ */
+ public synchronized int size()
+ {
+ return(values.size());
+ }
+
+ /**
+ * Tests if this dictionary maps no keys to value. The general contract
+ * for the <tt>isEmpty</tt> method is that the result is true if and only
+ * if this dictionary contains no entries.
+ *
+ * @return <code>true</code> if this dictionary maps no keys to values;
+ * <code>false</code> otherwise.
+ */
+ public synchronized boolean isEmpty()
+ {
+ return(values.isEmpty());
+ }
+
+ /**
+ * Always throws UnsupportedOperationException.
+ *
+ * @param key header name.
+ * @param value header value.
+ * @throws UnsupportedOperationException.
+ */
+ public Object put(Object key, Object value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Always throws UnsupportedOperationException.
+ *
+ * @param key header name.
+ * @throws UnsupportedOperationException.
+ */
+ public Object remove(Object key)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public String toString()
+ {
+ return(values.toString());
+ }
+
+ public static Headers parseManifest(InputStream in) throws BundleException {
+ try
+ {
+ Headers headers = new Headers(10);
+ BufferedReader br;
+ try
+ {
+ br = new BufferedReader(new InputStreamReader(in, "UTF8"));
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ br = new BufferedReader(new InputStreamReader(in));
+ }
+
+ String header = null;
+ StringBuffer value = new StringBuffer(256);
+ boolean firstLine = true;
+
+ while (true)
+ {
+ String line = br.readLine();
+ /* The java.util.jar classes in JDK 1.3 use the value of the last
+ * encountered manifest header. So we do the same to emulate
+ * this behavior. We no longer throw a BundleException
+ * for duplicate manifest headers.
+ */
+
+ if ((line == null) || (line.length() == 0)) /* EOF or empty line */
+ {
+ if (!firstLine) /* flush last line */
+ {
+ headers.set(header, null); /* remove old attribute,if present */
+ headers.set(header, value.toString().trim());
+ }
+ break; /* done processing main attributes */
+ }
+
+ if (line.charAt(0) == ' ') /* continuation */
+ {
+ if (firstLine) /* if no previous line */
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_LINE_EXCEPTION", line));
+ }
+ value.append(line.substring(1));
+ continue;
+ }
+
+ if (!firstLine)
+ {
+ headers.set(header, null); /* remove old attribute,if present */
+ headers.set(header, value.toString().trim());
+ value.setLength(0); /* clear StringBuffer */
+ }
+
+ int colon = line.indexOf(':');
+ if (colon == -1) /* no colon */
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_LINE_EXCEPTION", line));
+ }
+ header = line.substring(0, colon).trim();
+ value.append(line.substring(colon+1).trim());
+ firstLine = false;
+ }
+ return headers;
+ } catch (IOException e) {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_LINE_EXCEPTION", ""), e);
+ } finally {
+ try
+ {
+ in.close();
+ }
+ catch (IOException ee)
+ {
+ }
+ }
+ }
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/ManifestElement.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/ManifestElement.java
new file mode 100644
index 000000000..d10b38cdd
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/ManifestElement.java
@@ -0,0 +1,592 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.util;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.eclipse.osgi.framework.debug.Debug;
+import org.eclipse.osgi.framework.internal.core.Msg;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+
+
+
+/**
+ * This class represents a manifest element.
+ */
+public class ManifestElement
+{
+
+ protected String value;
+ protected Hashtable attributes;
+
+ public ManifestElement(){
+ this(null);
+ }
+
+ public ManifestElement(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public String getAttribute(String key) {
+ if (attributes == null) {
+ return null;
+ }
+ return (String) attributes.get(key);
+ }
+
+ public Enumeration getKeys(){
+ if (attributes == null) {
+ return null;
+ }
+ return attributes.keys();
+ }
+
+ protected void setValue(String value) {
+ this.value = value;
+ }
+
+ protected void addAttribute(String key, String value) {
+ if (attributes == null) {
+ attributes = new Hashtable(7);
+ }
+ String curValue = (String) attributes.get(key);
+ if (curValue != null) {
+ value = curValue + ";" + value;
+ }
+ attributes.put(key,value);
+ }
+
+
+ public static ManifestElement[] parseClassPath(String value) throws BundleException
+ {
+ if (value == null)
+ {
+ return (null);
+ }
+ Vector classpaths = new Vector(10);
+
+ Tokenizer tokenizer = new Tokenizer(value);
+
+ parseloop : while (true)
+ {
+ String path = tokenizer.getToken(",");
+ if (path == null)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_HEADER_EXCEPTION", Constants.BUNDLE_CLASSPATH, value));
+ }
+
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
+ {
+ Debug.println("Classpath entry: " + path);
+ }
+ ManifestElement classpath = new ManifestElement(path);
+
+ int index = path.indexOf(";");
+ if (index != -1)
+ {
+ if ((index + 1) >= path.length())
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_HEADER_EXCEPTION", Constants.BUNDLE_CLASSPATH, value));
+ }
+ String filterString = path.substring(index + 1);
+
+ if (!filterString.endsWith(")"))
+ {
+ // we have a space in the filter or an invalid Bundle-ClassPath header
+ StringBuffer buf = new StringBuffer(filterString);
+ buf.append(' ');
+ while (true)
+ {
+ char nextChar = tokenizer.getChar();
+ if (nextChar == -1)
+ {
+ throw new BundleException(
+ Msg.formatter.getString("MANIFEST_INVALID_HEADER_EXCEPTION", Constants.BUNDLE_CLASSPATH, value));
+ }
+ buf.append(nextChar);
+ if (nextChar == ')')
+ {
+ break;
+ }
+ }
+ filterString = buf.toString();
+ }
+ classpath.addAttribute("filter", filterString);
+ }
+ classpaths.addElement(classpath);
+
+ char c = tokenizer.getChar();
+
+ if (c == ',') /* another path */
+ {
+ continue parseloop;
+ }
+
+ if (c == '\0') /* end of value */
+ {
+ break parseloop;
+ }
+
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_HEADER_EXCEPTION", Constants.BUNDLE_CLASSPATH, value));
+ }
+
+ int size = classpaths.size();
+
+ if (size == 0)
+ {
+ return (null);
+ }
+
+ ManifestElement[] result = new ManifestElement[size];
+ classpaths.copyInto(result);
+
+ return (result);
+ }
+
+ /**
+ * @param value The key to query the manifest for exported packages
+ * @return The Array of all ManifestElements that describe import or export package statements.
+ * @throws BundleException
+ */
+ public static ManifestElement[] parsePackageDescription(String value)
+ throws BundleException
+ {
+ if (value == null)
+ {
+ return(null);
+ }
+
+ Vector pkgvec = new Vector(10, 10);
+
+ Tokenizer tokenizer = new Tokenizer(value);
+
+ parseloop:
+ while (true)
+ {
+ String pkgname = tokenizer.getToken(";,");
+ if (pkgname == null)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value));
+ }
+
+ ManifestElement pkgdes = new ManifestElement(pkgname);
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
+ {
+ Debug.print("PackageDescription: "+pkgname);
+ }
+
+ char c = tokenizer.getChar();
+
+ while (c == ';') /* attributes */
+ {
+ String key = tokenizer.getToken(";,=");
+ if (key == null)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value));
+ }
+
+ c = tokenizer.getChar();
+
+ if (c == '=') /* must be an attribute */
+ {
+ String val = tokenizer.getString(";,");
+ if (val == null)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value));
+ }
+
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
+ {
+ Debug.print(";"+key+"="+val);
+ }
+ try
+ {
+ pkgdes.addAttribute(key, val);
+ }
+ catch (Exception e)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value), e);
+ }
+
+ c = tokenizer.getChar();
+ }
+ else /* error */
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value));
+ }
+ }
+
+ pkgvec.addElement(pkgdes);
+
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
+ {
+ Debug.println("");
+ }
+
+ if (c == ',') /* another description */
+ {
+ continue parseloop;
+ }
+
+ if (c == '\0') /* end of value */
+ {
+ break parseloop;
+ }
+
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value));
+ }
+
+ int size = pkgvec.size();
+
+ if (size == 0)
+ {
+ return (null);
+ }
+
+ ManifestElement[] result = new ManifestElement[size];
+ pkgvec.copyInto(result);
+
+ return(result);
+ }
+
+ public static ManifestElement[] parseBundleDescriptions(String value) throws BundleException
+ {
+ if (value == null)
+ {
+ return(null);
+ }
+
+ Vector bundlevec = new Vector(10, 10);
+
+ Tokenizer tokenizer = new Tokenizer(value);
+
+ parseloop:
+ while (true)
+ {
+ String bundleUID = tokenizer.getToken(";,");
+ if (bundleUID == null)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value));
+ }
+
+ ManifestElement bundledes = new ManifestElement(bundleUID);
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
+ {
+ Debug.print("BundleDescription: "+bundleUID);
+ }
+
+ char c = tokenizer.getChar();
+
+ while (c == ';') /* attributes */
+ {
+ String key = tokenizer.getToken(";,=");
+ if (key == null)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value));
+ }
+
+ c = tokenizer.getChar();
+
+ if (c == '=') /* must be an attribute */
+ {
+ String val = tokenizer.getString(";,");
+ if (val == null)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value));
+ }
+
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
+ {
+ Debug.print(";"+key+"="+val);
+ }
+ try
+ {
+ bundledes.addAttribute(key, val);
+ }
+ catch (Exception e)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value), e);
+ }
+
+ c = tokenizer.getChar();
+ }
+ else /* error */
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value));
+ }
+ }
+
+ bundlevec.addElement(bundledes);
+
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
+ {
+ Debug.println("");
+ }
+
+ if (c == ',') /* another description */
+ {
+ continue parseloop;
+ }
+
+ if (c == '\0') /* end of value */
+ {
+ break parseloop;
+ }
+
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value));
+ }
+
+ int size = bundlevec.size();
+
+ if (size == 0)
+ {
+ return (null);
+ }
+
+ ManifestElement[] result = new ManifestElement[size];
+ bundlevec.copyInto(result);
+
+ return(result);
+ }
+
+ public static ManifestElement[] parseNativeCodeDescription(String value) throws BundleException
+ {
+ if (value == null)
+ {
+ return(null);
+ }
+
+ Vector nativevec = new Vector(10, 10);
+
+ Tokenizer tokenizer = new Tokenizer(value);
+
+ parseloop:
+ while (true)
+ {
+ String next = tokenizer.getToken(";,");
+ if (next == null)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_HEADER_EXCEPTION", Constants.BUNDLE_NATIVECODE, value));
+ }
+
+ StringBuffer codepaths = new StringBuffer(next);
+
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
+ {
+ Debug.print("NativeCodeDescription: "+next);
+ }
+
+ char c = tokenizer.getChar();
+
+ while (c == ';')
+ {
+ next = tokenizer.getToken(";,=");
+ if (next == null)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_HEADER_EXCEPTION", Constants.BUNDLE_NATIVECODE, value));
+ }
+
+ c = tokenizer.getChar();
+
+ if (c == ';') /* more */
+ {
+ codepaths.append(";").append(next);
+
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
+ {
+ Debug.print(";"+next);
+ }
+ }
+ }
+
+ ManifestElement nativedes = new ManifestElement(codepaths.toString());
+
+ while (c == '=')
+ {
+ String val = tokenizer.getString(";,");
+ if (val == null)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_HEADER_EXCEPTION", Constants.BUNDLE_NATIVECODE, value));
+ }
+
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
+ {
+ Debug.print(";"+next+"="+val);
+ }
+ try
+ {
+ nativedes.addAttribute(next, val);
+ }
+ catch (Exception e)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_HEADER_EXCEPTION", Constants.BUNDLE_NATIVECODE, value), e);
+ }
+
+ c = tokenizer.getChar();
+
+ if (c == ';') /* more */
+ {
+ next = tokenizer.getToken("=");
+
+ if (next == null)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_HEADER_EXCEPTION", Constants.BUNDLE_NATIVECODE, value));
+ }
+
+ c = tokenizer.getChar();
+ }
+ }
+
+ nativevec.addElement(nativedes);
+
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
+ {
+ Debug.println("");
+ }
+
+ if (c == ',') /* another description */
+ {
+ continue parseloop;
+ }
+
+ if (c == '\0') /* end of value */
+ {
+ break parseloop;
+ }
+
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_HEADER_EXCEPTION", Constants.BUNDLE_NATIVECODE, value));
+ }
+
+ int size = nativevec.size();
+
+ if (size == 0)
+ {
+ return (null);
+ }
+
+ ManifestElement[] result = new ManifestElement[size];
+ nativevec.copyInto(result);
+
+ return(result);
+ }
+
+
+ public static ManifestElement[] parseBasicCommaSeparation(String header, String value) throws BundleException
+ {
+ if (value == null)
+ {
+ return(null);
+ }
+
+ Vector bundlevec = new Vector(10, 10);
+
+ Tokenizer tokenizer = new Tokenizer(value);
+
+ parseloop:
+ while (true)
+ {
+ String elementname = tokenizer.getToken(";,");
+ if (elementname == null)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value));
+ }
+
+ ManifestElement element = new ManifestElement(elementname);
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
+ {
+ Debug.print("ManifestElement: "+elementname);
+ }
+
+ char c = tokenizer.getChar();
+
+ while (c == ';') /* attributes */
+ {
+ String key = tokenizer.getToken(";,=");
+ if (key == null)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value));
+ }
+
+ c = tokenizer.getChar();
+
+ if (c == '=') /* must be an attribute */
+ {
+ String val = tokenizer.getString(";,");
+ if (val == null)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value));
+ }
+
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
+ {
+ Debug.print(";"+key+"="+val);
+ }
+ try
+ {
+ element.addAttribute(key, val);
+ }
+ catch (Exception e)
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_PACKAGE_EXCEPTION", value), e);
+ }
+
+ c = tokenizer.getChar();
+ }
+ else /* error */
+ {
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_HEADER_EXCEPTION", value));
+ }
+ }
+
+ bundlevec.addElement(element);
+
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
+ {
+ Debug.println("");
+ }
+
+ if (c == ',') /* another description */
+ {
+ continue parseloop;
+ }
+
+ if (c == '\0') /* end of value */
+ {
+ break parseloop;
+ }
+
+ throw new BundleException(Msg.formatter.getString("MANIFEST_INVALID_HEADER_EXCEPTION", value));
+ }
+
+ int size = bundlevec.size();
+
+ if (size == 0)
+ {
+ return (null);
+ }
+
+ ManifestElement[] result = new ManifestElement[size];
+ bundlevec.copyInto(result);
+
+ return(result);
+
+ }
+
+}
+
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/Tokenizer.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/Tokenizer.java
new file mode 100644
index 000000000..b8cad4fef
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/Tokenizer.java
@@ -0,0 +1,172 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.util;
+
+/**
+ * Simple tokenizer class. Used to parse data.
+ */
+public class Tokenizer
+{
+ protected char value[];
+ protected int max;
+ protected int cursor;
+
+ public Tokenizer(String value)
+ {
+ this.value = value.toCharArray();
+ max = this.value.length;
+ cursor = 0;
+ }
+
+ private void skipWhiteSpace()
+ {
+ char[] val = value;
+ int cur = cursor;
+
+ for ( ;cur < max; cur++)
+ {
+ char c = val[cur];
+ if ((c == ' ') || (c == '\t'))
+ {
+ continue;
+ }
+ break;
+ }
+ cursor = cur;
+ }
+
+ public String getToken(String terminals)
+ {
+ skipWhiteSpace();
+ char[] val = value;
+ int cur = cursor;
+
+ int begin = cur;
+ for ( ;cur < max; cur++)
+ {
+ char c = val[cur];
+ if ((c == ' ') || (c == '\t') || (terminals.indexOf(c) != -1))
+ {
+ break;
+ }
+ }
+ cursor = cur;
+ int count = cur-begin;
+ if (count > 0)
+ {
+ skipWhiteSpace();
+ return(new String(val, begin, count));
+ }
+ return(null);
+ }
+
+ public String getString(String terminals)
+ {
+ skipWhiteSpace();
+ char[] val = value;
+ int cur = cursor;
+
+ if (cur < max)
+ {
+ if (val[cur] == '\"') /* if a quoted string */
+ {
+ cur++; /* skip quote */
+ char c = '\0';
+ int begin = cur;
+ for ( ;cur < max; cur++)
+ {
+ c = val[cur];
+ if (c == '\"')
+ {
+ break;
+ }
+ }
+ int count = cur-begin;
+ if (c == '\"')
+ {
+ cur++;
+ }
+ cursor = cur;
+ if (count > 0)
+ {
+ skipWhiteSpace();
+ return(new String(val, begin, count));
+ }
+ }
+ else /* not a quoted string; same as token */
+ {
+ int begin = cur;
+ for ( ;cur < max; cur++)
+ {
+ char c = val[cur];
+ if (c=='\"') {
+ // but there could be a quoted string in the middle of the string
+ cur = cur+skipQuotedString(val,cur);
+ } else if ((c == ' ') || (c == '\t') || (terminals.indexOf(c) != -1)) {
+ break;
+ }
+ }
+ cursor = cur;
+ int count = cur-begin;
+ if (count > 0)
+ {
+ skipWhiteSpace();
+ return(new String(val, begin, count));
+ }
+ }
+ }
+ return(null);
+ }
+
+ private int skipQuotedString(char[] val, int cur) {
+ cur++; /* skip quote */
+ char c = '\0';
+ int begin = cur;
+ for ( ;cur < max; cur++)
+ {
+ c = val[cur];
+ if (c == '\"')
+ {
+ break;
+ }
+ }
+ int count = cur-begin;
+ if (c == '\"')
+ {
+ cur++;
+ }
+ cursor = cur;
+ if (count > 0)
+ {
+ skipWhiteSpace();
+ }
+ return count;
+ }
+
+ public char getChar()
+ {
+ int cur = cursor;
+ if (cur < max)
+ {
+ cursor = cur+1;
+ return(value[cur]);
+ }
+ return('\0'); /* end of value */
+ }
+
+ public boolean hasMoreTokens() {
+ if (cursor<max) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/META-INF/SYSTEMBUNDLE.MF b/bundles/org.eclipse.osgi/core/framework/META-INF/SYSTEMBUNDLE.MF
new file mode 100644
index 000000000..cf8585285
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/META-INF/SYSTEMBUNDLE.MF
@@ -0,0 +1,30 @@
+Export-Package: org.osgi.framework; specification-version=1.2,
+ org.osgi.service.packageadmin; specification-version=1.1,
+ org.osgi.service.permissionadmin; specification-version=1.1,
+ org.osgi.service.url; specification-version=1.0,
+ org.osgi.service.startlevel; specification-version=1.0,
+ org.eclipse.osgi.framework.eventmgr,
+ org.eclipse.osgi.framework.msg; specification-version=1.0,
+ org.eclipse.osgi.service.environment
+Import-Package: org.osgi.framework; specification-version=1.2,
+ org.osgi.service.packageadmin; specification-version=1.1,
+ org.osgi.service.permissionadmin; specification-version=1.1,
+ org.osgi.service.url; specification-version=1.0,
+ org.osgi.service.startlevel; specification-version=1.0,
+ org.eclipse.osgi.framework.eventmgr,
+ org.eclipse.osgi.framework.msg; specification-version=1.0,
+ org.eclipse.osgi.service.environment
+Export-Service: org.osgi.service.packageadmin.PackageAdmin,
+ org.osgi.service.permissionadmin.PermissionAdmin,
+ org.osgi.service.startlevel.StartLevel,
+ org.eclipse.osgi.service.environment.DebugOptions
+Bundle-Name: OSGi System Bundle
+Bundle-GlobalName: org.osgi.framework
+Bundle-Activator: org.eclipse.osgi.framework.internal.core.SystemBundleActivator
+Bundle-Description: OSGi System Bundle
+Bundle-Copyright: Copyright (c) 2003 IBM Corporation and others. All rights reserved. This program and the accompanying materials are made available under the terms of the Common Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/cpl-v10.html
+Bundle-Vendor: Eclipse
+Bundle-Version: 3.6.0
+Bundle-DocUrl: http://www.eclipse.org
+Bundle-ContactAddress: pervasive@us.ibm.com
+
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/console/CommandInterpreter.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/console/CommandInterpreter.java
new file mode 100644
index 000000000..485e4b58f
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/console/CommandInterpreter.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.console;
+
+import java.util.Dictionary;
+
+import org.eclipse.osgi.framework.internal.core.Bundle;
+
+/** A command interpreter is a shell that can interpret command
+ * lines. This object is passed as parameter when a CommandProvider
+ * is invoked.
+*/
+public interface CommandInterpreter {
+ public final static String NAME = "org.eclipse.osgi.framework.internal.core.command.CommandInterpreter";
+
+ /**
+ * Get the next argument in the input.
+ *
+ * E.g. if the commandline is hello world, the _hello method
+ * will get "world" as the first argument.
+ */
+ public String nextArgument();
+
+ /**
+ * Execute a command line as if it came from the end user
+ * and return the result.
+ *
+ * Throws any exceptions generated by the command that executed.
+ */
+ public Object execute( String cmd );
+
+ /**
+ * Prints an object to the outputstream
+ *
+ * @param o the object to be printed
+ */
+ public void print(Object o);
+
+ /**
+ * Prints an empty line to the outputstream
+ */
+ public void println();
+
+ /**
+ * Prints an object to the output medium (appended with newline character).
+ * <p>
+ * If running on the target environment the user is prompted with '--more'
+ * if more than the configured number of lines have been printed without user prompt.
+ * That way the user of the program has control over the scrolling.
+ * <p>
+ * For this to work properly you should not embedded "\n" etc. into the string.
+ *
+ * @param o the object to be printed
+ */
+ public void println(Object o);
+
+ /**
+ * Print a stack trace including nested exceptions.
+ * @param The offending exception
+ */
+ public void printStackTrace(Throwable t);
+
+
+ /**
+ * Prints the given dictionary sorted by keys.
+ *
+ * @param dic the dictionary to print
+ * @param title the header to print above the key/value pairs
+ */
+ public void printDictionary(Dictionary dic, String title);
+
+ /**
+ * Prints the given bundle resource if it exists
+ *
+ * @param bundle the bundle containing the resource
+ * @param resource the resource to print
+ */
+ public void printBundleResource(Bundle bundle, String resource);
+}
+
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/console/CommandProvider.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/console/CommandProvider.java
new file mode 100644
index 000000000..faeda3677
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/console/CommandProvider.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.console;
+
+/**
+ When an object wants to provide a number of commands
+ to the console, it should register an object with this
+ interface. Some console can then pick this up and execute
+ command lines.
+ The SERVICE_RANKING registration property can be used to influence the
+ order that a CommandProvider gets called. Specify a value less than
+ Integer.MAXVALUE, where higher is more significant. The default value
+ if SERVICE_RANKING is not set is 0.
+ <p>
+ The interface contains only methods for the help.
+ The console should use inspection
+ to find the commands. All public commands, starting with
+ a '_' and taking a CommandInterpreter as parameter
+ will be found. E.g.
+ <pre>
+ public Object _hello( CommandInterpreter intp ) {
+ return "hello " + intp.nextArgument();
+ }
+ </pre>
+*/
+public interface CommandProvider {
+ public final static String NAME = "org.eclipse.osgi.framework.internal.core.command.CommandProvider";
+
+ /**
+ Answer a string (may be as many lines as you like) with help
+ texts that explain the command.
+ */
+ public String getHelp();
+
+}
+
+
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/debug/Debug.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/debug/Debug.java
new file mode 100644
index 000000000..ece10fbc0
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/debug/Debug.java
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.debug;
+
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+public class Debug
+{
+ public static final boolean DEBUG = true;
+ public static boolean DEBUG_GENERAL = false; // "debug"
+ public static boolean DEBUG_BUNDLE_TIME = false; //"debug.bundleTime"
+ public static boolean DEBUG_LOADER = false; // "debug.loader"
+ public static boolean DEBUG_EVENTS = false; // "debug.events"
+ public static boolean DEBUG_SERVICES = false; // "debug.services"
+ public static boolean DEBUG_PACKAGES = false; // "debug.packages"
+ public static boolean DEBUG_MANIFEST = false; // "debug.manifest"
+ public static boolean DEBUG_FILTER = false; // "debug.filter"
+ public static boolean DEBUG_SECURITY = false; // "debug.security"
+ public static boolean DEBUG_STARTLEVEL = false; // "debug.startlevel"
+ public static boolean DEBUG_PACKAGEADMIN = false; // "debug.packageadmin"
+ public static boolean DEBUG_PACKAGEADMIN_TIMING = false; //"debug.packageadmin/timing"
+ static {
+ DebugOptions dbgOptions = DebugOptions.getDefault();
+ if (dbgOptions != null) {
+ DEBUG_GENERAL = dbgOptions.getBooleanOption("debug", false);
+ DEBUG_BUNDLE_TIME = dbgOptions.getBooleanOption("debug.bundleTime", false) || dbgOptions.getBooleanOption("org.eclipse.core.runtime/timing/startup", false);
+ DEBUG_LOADER = dbgOptions.getBooleanOption("debug.loader",false);
+ DEBUG_EVENTS = dbgOptions.getBooleanOption("debug.events",false);
+ DEBUG_SERVICES = dbgOptions.getBooleanOption("debug.services",false);
+ DEBUG_PACKAGES = dbgOptions.getBooleanOption("debug.packages",false);
+ DEBUG_MANIFEST = dbgOptions.getBooleanOption("debug.manifest",false);
+ DEBUG_FILTER = dbgOptions.getBooleanOption("debug.filter",false);
+ DEBUG_SECURITY = dbgOptions.getBooleanOption("debug.security",false);
+ DEBUG_STARTLEVEL = dbgOptions.getBooleanOption("debug.startlevel",false);
+ DEBUG_PACKAGEADMIN = dbgOptions.getBooleanOption("debug.packageadmin",false) ;
+ DEBUG_PACKAGEADMIN_TIMING = dbgOptions.getBooleanOption("debug.packageadmin/timing", false) || dbgOptions.getBooleanOption("org.eclipse.core.runtime/debug", false);
+ }
+ }
+ public static PrintStream out = System.out;
+
+ public static void print(boolean x)
+ {
+ out.print(x);
+ }
+ public static void print(char x)
+ {
+ out.print(x);
+ }
+ public static void print(int x)
+ {
+ out.print(x);
+ }
+ public static void print(long x)
+ {
+ out.print(x);
+ }
+ public static void print(float x)
+ {
+ out.print(x);
+ }
+ public static void print(double x)
+ {
+ out.print(x);
+ }
+ public static void print(char x[])
+ {
+ out.print(x);
+ }
+ public static void print(String x)
+ {
+ out.print(x);
+ }
+ public static void print(Object x)
+ {
+ out.print(x);
+ }
+ public static void println(boolean x)
+ {
+ out.println(x);
+ }
+ public static void println(char x)
+ {
+ out.println(x);
+ }
+ public static void println(int x)
+ {
+ out.println(x);
+ }
+ public static void println(long x)
+ {
+ out.println(x);
+ }
+ public static void println(float x)
+ {
+ out.println(x);
+ }
+ public static void println(double x)
+ {
+ out.println(x);
+ }
+ public static void println(char x[])
+ {
+ out.println(x);
+ }
+ public static void println(String x)
+ {
+ out.println(x);
+ }
+ public static void println(Object x)
+ {
+ out.println(x);
+ }
+ public static void printStackTrace(Throwable x)
+ {
+ printStackTrace(x,out);
+ }
+ private static void printStackTrace(Throwable t, PrintStream out)
+ {
+ t.printStackTrace(out);
+
+ Method[] methods = t.getClass().getMethods();
+
+ int size = methods.length;
+ Class throwable = Throwable.class;
+
+ for (int i = 0; i < size; i++)
+ {
+ Method method = methods[i];
+
+ if (Modifier.isPublic(method.getModifiers()) &&
+ method.getName().startsWith("get") &&
+ throwable.isAssignableFrom(method.getReturnType()) &&
+ (method.getParameterTypes().length == 0))
+ {
+ try
+ {
+ Throwable nested = (Throwable) method.invoke(t, null);
+
+ if ((nested != null) && (nested != t))
+ {
+ out.println("Nested Exception:");
+ printStackTrace(nested, out);
+ }
+ }
+ catch (IllegalAccessException e)
+ {
+ }
+ catch (InvocationTargetException e)
+ {
+ }
+ }
+ }
+ }
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/debug/DebugOptions.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/debug/DebugOptions.java
new file mode 100644
index 000000000..2e6f7e736
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/debug/DebugOptions.java
@@ -0,0 +1,123 @@
+package org.eclipse.osgi.framework.debug;
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.Properties;
+
+public class DebugOptions implements org.eclipse.osgi.service.environment.DebugOptions {
+ Properties options = null;
+
+ private static DebugOptions singleton = null;
+ private static boolean debugEnabled = true;
+ private static final String OPTIONS = ".options"; //$NON-NLS-1$
+
+ public static DebugOptions getDefault() {
+ if (singleton == null && debugEnabled) {
+ DebugOptions result = new DebugOptions();
+ debugEnabled = result.isDebugEnabled();
+ if (debugEnabled)
+ singleton = result;
+ }
+ return singleton;
+ }
+
+ private DebugOptions() {
+ super();
+ loadOptions();
+ }
+
+ public boolean getBooleanOption(String option, boolean defaultValue) {
+ String optionValue = getOption(option);
+ return (optionValue != null && optionValue.equalsIgnoreCase("true")) || defaultValue; //$NON-NLS-1$
+ }
+
+ public String getOption(String option) {
+ return options != null ? options.getProperty(option) : null;
+ }
+
+ public int getIntegerOption(String option, int defaultValue) {
+ String value = getOption(option);
+ try {
+ return value == null ? defaultValue : Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ public void setOption(String option, String value) {
+ if (options != null)
+ options.put(option, value.trim());
+ }
+
+ public boolean isDebugEnabled() {
+ return options != null;
+ }
+
+ private void loadOptions() {
+ // if no debug option was specified, don't even bother to try.
+ // Must ensure that the options slot is null as this is the signal to the
+ // platform that debugging is not enabled.
+ String debugOptionsFilename = System.getProperty("osgi.debug");
+ if (debugOptionsFilename == null)
+ return;
+ options = new Properties();
+ URL optionsFile;
+ if (debugOptionsFilename.length() == 0) {
+ // default options location is user.dir (install location may be r/o so
+ // is not a good candidate for a trace options that need to be updatable by
+ // by the user)
+ String userDir = System.getProperty("user.dir").replace(File.separatorChar,'/'); //$NON-NLS-1$
+ if (!userDir.endsWith("/")) //$NON-NLS-1$
+ userDir += "/"; //$NON-NLS-1$
+ debugOptionsFilename = "file:" + userDir + OPTIONS; //$NON-NLS-1$
+ }
+ try {
+ optionsFile = getURL(debugOptionsFilename);
+ } catch (MalformedURLException e) {
+ System.out.println("Unable to construct URL for options file: " + debugOptionsFilename); //$NON-NLS-1$
+ e.printStackTrace(System.out);
+ return;
+ }
+ System.out.println("Debug-Options:\n " + debugOptionsFilename); //$NON-NLS-1$
+ try {
+ InputStream input = optionsFile.openStream();
+ try {
+ options.load(input);
+ } finally {
+ input.close();
+ }
+ } catch (FileNotFoundException e) {
+ // Its not an error to not find the options file
+ } catch (IOException e) {
+ System.out.println("Could not parse the options file: " + optionsFile); //$NON-NLS-1$
+ e.printStackTrace(System.out);
+ }
+ // trim off all the blanks since properties files don't do that.
+ for (Iterator i = options.keySet().iterator(); i.hasNext();) {
+ Object key = i.next();
+ options.put(key, ((String) options.get(key)).trim());
+ }
+ if (options.size() == 0)
+ options = null;
+ }
+ /**
+ * Helper method that creates an URL object from the given string
+ * representation. The string must correspond to a valid URL or file system
+ * path.
+ */
+ private URL getURL(String urlString) throws MalformedURLException {
+ try {
+ return new URL(urlString);
+ } catch (MalformedURLException e) {
+ // if it is not a well formed URL, tries to create a "file:" URL
+ try {
+ return new File(urlString).toURL();
+ } catch (MalformedURLException ex) {
+ // re-throw the original exception if nothing works
+ throw e;
+ }
+ }
+ }
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventListeners.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventListeners.java
new file mode 100644
index 000000000..2dc9c5a58
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventListeners.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.eventmgr;
+
+/**
+ * This class manages the list of listeners.
+ * Listeners may be added or removed as necessary.
+ */
+
+public class EventListeners
+{
+ /**
+ * This field contains the listener list.
+ */
+ ListenerList list;
+
+ /**
+ * Constructor for EventListeners. An empty list of listeners is created.
+ *
+ */
+ public EventListeners()
+ {
+ list = null;
+ }
+
+ /**
+ * This method is called to add a listener to the list.
+ *
+ * @param listener This is the listener object to be added to the list.
+ * @param listenerObject This is an optional listener-specific object.
+ * This object will be passed to the EventSource along with the listener
+ * when the listener is to be called.
+ */
+ public synchronized void addListener(Object listener, Object listenerObject)
+ {
+ if (listener != null)
+ {
+ list = ListenerList.addListener(list, listener, listenerObject);
+ }
+ }
+
+ /**
+ * This method is called to remove a listener from the list.
+ *
+ * @param listener This is the listener object to be removed from the list.
+ */
+ public synchronized void removeListener(Object listener)
+ {
+ if (listener != null)
+ {
+ list = ListenerList.removeListener(list, listener);
+ }
+ }
+
+ /**
+ * This method is called to remove all listeners from the list.
+ */
+ public synchronized void removeAllListeners()
+ {
+ list = null;
+ }
+}
+
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventManager.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventManager.java
new file mode 100644
index 000000000..b1b85f6ea
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventManager.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.eventmgr;
+
+
+
+/**
+ * This class is the central class for the event manager. Each
+ * program that wishes to use the event manager should construct
+ * an EventManager object and use that object to construct
+ * EventQueue for dispatching events.
+ */
+
+public class EventManager
+{
+ /**
+ * EventThread for asynchronous dispatch of events.
+ */
+ protected EventThread thread;
+
+ /**
+ * EventThread Name
+ */
+ protected String threadName;
+
+ /**
+ * EventManager constructor. An EventManager object is responsible for
+ * the delivery of events to listeners via an EventSource.
+ *
+ */
+ public EventManager()
+ {
+ thread = null;
+ }
+
+ public EventManager(String threadName){
+ this();
+ this.threadName = threadName;
+ }
+
+ /**
+ * This method can be called to release any resources associated with this
+ * EventManager.
+ *
+ */
+ public synchronized void close()
+ {
+ if (thread != null)
+ {
+ thread.close();
+ thread = null;
+ }
+ }
+
+ /**
+ * Asynchronously dispatch an event to the set of listeners. An event dispatch thread
+ * maintained by the associated EventManager is used to deliver the events.
+ * This method may return immediately to the caller.
+ *
+ * @param ll The set of listeners to which the event will be dispatched.
+ * @param eventAction This value is passed back to the event source when the call back
+ * is made to the EventSource object along with each listener.
+ * @param eventObject This object is passed back to the event source when the call back
+ * is made to the EventSource object along with each listener.
+ */
+ void dispatchEventAsynchronous(ListenerList ll, int eventAction, Object eventObject)
+ {
+ EventThread thread = getEventThread();
+
+ for (; ll != null; ll = ll.list)
+ {
+ thread.postEvent((ListenerList) ll.listener, (EventSource) ll.object, eventAction, eventObject);
+ }
+ }
+
+ /**
+ * Synchronously dispatch an event to the set of listeners. The event may
+ * be dispatch on the current thread or an event dispatch thread
+ * maintained by the associated EventManager.
+ * This method will not return to the caller until an EventSource
+ * has been called (and returned) for each listener.
+ *
+ * @param ll The set of listeners to which the event will be dispatched.
+ * @param eventAction This value is passed back to the event source when the call back
+ * is made to the EventSource object along with each listener.
+ * @param eventObject This object is passed back to the event source when the call back
+ * is made to the EventSource object along with each listener.
+ */
+ void dispatchEventSynchronous(ListenerList ll, int eventAction, Object eventObject)
+ {
+ for (; ll != null; ll = ll.list)
+ {
+ ((ListenerList) ll.listener).dispatchEvent((EventSource) ll.object, eventAction, eventObject);
+ }
+ }
+
+ /**
+ * Returns an EventThread to use for dispatching events asynchronously.
+ *
+ * @return EventThread.
+ */
+ private synchronized EventThread getEventThread()
+ {
+ if (thread == null)
+ {
+ if (threadName == null)
+ {
+ thread = new EventThread();
+ }
+ else
+ {
+ thread = new EventThread(threadName);
+ }
+ }
+
+ return(thread);
+ }
+}
+
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventQueue.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventQueue.java
new file mode 100644
index 000000000..e3f767348
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventQueue.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.eventmgr;
+
+
+
+/**
+ * The EventQueue is used to build the set of listeners and then dispatch
+ * events to those listeners. An EventQueue object is associated with a
+ * specific EventManager object.
+ *
+ * <p>EventQueue objects are created on demand to build a set of listeners
+ * that should receive a specific event. Once the set is created, the event
+ * can then be synchronously or asynchronously delivered to the set of
+ * listeners. After the event has been dispatched for delivery, the
+ * EventQueue object should be discarded. A new EventQueue object should be
+ * created for the delivery of another specific event.
+ */
+
+public class EventQueue
+{
+ /**
+ * EventManager with which this queue is associated.
+ */
+ protected EventManager manager;
+ /**
+ * Set of listeners (list of listener lists).
+ */
+ protected ListenerList queue;
+
+ /**
+ * EventQueue constructor. This method creates an empty event queue.
+ *
+ * @param manager The EventManager this queue is associated with.
+ * @exception java.lang.NullPointerException if manager is null.
+ */
+ public EventQueue(EventManager manager)
+ {
+ this.manager = manager;
+ if (manager == null)
+ {
+ throw new NullPointerException();
+ }
+
+ queue = null;
+ }
+
+ /**
+ * Build the set of listeners. This method can be called multiple times, prior to
+ * calling one of the dispatchEvent methods, to build the set of listeners for the
+ * delivery of a specific event. The current list of listeners in the given ListenerList,
+ * at the time this method is called, is added to the set.
+ *
+ * @param listeners An EventListeners object to add to the queue. All listeners
+ * previously added to
+ * the EventListeners object will be called when an event is dispatched.
+ * @param source An EventSource object to use when dispatching an event
+ * to the listeners on this ListenerList.
+ */
+ public synchronized void queueListeners(EventListeners listeners, EventSource source)
+ {
+ if (listeners != null)
+ {
+ ListenerList list = listeners.list;
+
+ if (list != null)
+ {
+ queue = ListenerList.addListener(queue, list, source);
+ }
+ }
+ }
+
+ /**
+ * Asynchronously dispatch an event to the set of listeners. An event dispatch thread
+ * maintained by the associated EventManager is used to deliver the events.
+ * This method may return immediately to the caller.
+ *
+ * @param eventAction This value is passed back to the event source when the call back
+ * is made to the EventSource object along with each listener.
+ * @param eventObject This object is passed back to the event source when the call back
+ * is made to the EventSource object along with each listener.
+ */
+ public void dispatchEventAsynchronous(int eventAction, Object eventObject)
+ {
+ manager.dispatchEventAsynchronous(queue, eventAction, eventObject);
+ }
+
+ /**
+ * Synchronously dispatch an event to the set of listeners. The event may
+ * be dispatched on the current thread or an event dispatch thread
+ * maintained by the associated EventManager.
+ * This method will not return to the caller until an EventSource
+ * has been called (and returned) for each listener.
+ *
+ * @param eventAction This value is passed back to the event source when the call back
+ * is made to the EventSource object along with each listener.
+ * @param eventObject This object is passed back to the event source when the call back
+ * is made to the EventSource object along with each listener.
+ */
+ public void dispatchEventSynchronous(int eventAction, Object eventObject)
+ {
+ manager.dispatchEventSynchronous(queue, eventAction, eventObject);
+ }
+
+}
+
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventSource.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventSource.java
new file mode 100644
index 000000000..fc4e51d8b
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventSource.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.eventmgr;
+
+
+
+/**
+ * The EventSource interface contains the method that is called by the
+ * Event Manager to complete the event delivery to the event listener.
+ */
+
+public abstract interface EventSource
+{
+ /**
+ * This method is the call back that is called once for each listener.
+ * This method must cast the EventListener object to the appropriate listener
+ * class for the event type and call the appropriate listener method.
+ *
+ * @param listener This listener must be cast to the appropriate listener
+ * class for the events created by this source and the appropriate listener method
+ * must then be called.
+ * @param listenerObject This is the optional object that was passed to
+ * ListenerList.addListener when the listener was added to the ListenerList.
+ * @param eventAction This value was passed to the EventQueue object via one of its
+ * dispatchEvent* method calls. It can provide information (such
+ * as which listener method to call) so that this method
+ * can complete the delivery of the event to the listener.
+ * @param eventObject This object was passed to the EventQueue object via one of its
+ * dispatchEvent* method calls. This object was created by the event source and
+ * is passed to this method. It should contain all the necessary information (such
+ * as what event object to pass) so that this method
+ * can complete the delivery of the event to the listener.
+ */
+ public abstract void dispatchEvent(Object listener, Object listenerObject, int eventAction, Object eventObject);
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventThread.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventThread.java
new file mode 100644
index 000000000..1eb7e31da
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/EventThread.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.eventmgr;
+
+
+
+/**
+ * This class is used for asynchronously dispatching events.
+ */
+
+class EventThread extends Thread
+{
+ /**
+ * EventThreadItem is a nested top-level (non-member) class. This class
+ * represents the items which are placed on the queue.
+ */
+ static class EventThreadItem
+ {
+ /** listener list for this event */
+ private final ListenerList listeners;
+ /** source of this event */
+ private final EventSource source;
+ /** action for this event */
+ private final int action;
+ /** object for this event */
+ private final Object object;
+ /** next item in event queue */
+ EventThreadItem next;
+
+ /**
+ * Constructor for event queue item
+ *
+ * @param l Listener list for this event
+ * @param s Source for this event
+ * @param a Action for this event
+ * @param o Object for this event
+ */
+ EventThreadItem(ListenerList l, EventSource s, int a, Object o)
+ {
+ listeners = l;
+ source = s;
+ action = a;
+ object = o;
+ next = null;
+ }
+
+ /**
+ * This method will dispatch this event queue item to its listeners
+ */
+ void dispatchEvent()
+ {
+ listeners.dispatchEvent(source, action, object);
+ }
+ }
+
+ /** item at the head of the event queue */
+ private EventThreadItem head;
+ /** item at the tail of the event queue */
+ private EventThreadItem tail;
+ /** if false the thread must terminate */
+ private volatile boolean running;
+
+ /**
+ * Constructor for the event queue. The queue is created empty and the
+ * queue dispatcher thread is started.
+ */
+ EventThread(String threadName)
+ {
+ super(threadName);
+ init();
+ }
+
+ /**
+ * Constructor for the event queue. The queue is created empty and the
+ * queue dispatcher thread is started.
+ */
+ EventThread()
+ {
+ super();
+ init();
+ }
+
+ void init(){
+ running = true;
+ head = null;
+ tail = null;
+
+ setDaemon(true); /* Mark thread as daemon thread */
+ start(); /* Start thread */
+ }
+
+ /**
+ * Stop thread.
+ */
+ void close()
+ {
+ running = false;
+ interrupt();
+ }
+
+ /**
+ * This method is the event queue dispatcher thread. It pulls events from
+ * the queue and dispatches them.
+ */
+ public void run()
+ {
+ while (running)
+ {
+ try
+ {
+ getNextEvent().dispatchEvent();
+ }
+ catch (Throwable t)
+ {
+ }
+ }
+ }
+
+ /**
+ * This methods takes the input parameters and creates an EventThreadItem
+ * and queues it.
+ * The thread is notified.
+ *
+ * @param l Listener list for this event
+ * @param s Source for this event
+ * @param a Action for this event
+ * @param o Object for this event
+ */
+ synchronized void postEvent(ListenerList l, EventSource s, int a, Object o)
+ {
+ EventThreadItem item = new EventThreadItem(l, s, a, o);
+
+ if (head == null) /* if the queue was empty */
+ {
+ head = item;
+ tail = item;
+ }
+ else /* else add to end of queue */
+ {
+ tail.next = item;
+ tail = item;
+ }
+
+ notify();
+ }
+
+ /**
+ * This method is called by the thread to remove
+ * items from the queue so that they can be dispatched to their listeners.
+ * If the queue is empty, the thread waits.
+ *
+ * @return The EventThreadItem removed from the top of the queue.
+ */
+ private synchronized EventThreadItem getNextEvent() throws InterruptedException
+ {
+ while (running && (head == null))
+ {
+ try
+ {
+ wait();
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+
+ if (!running) /* if we are stopping */
+ {
+ throw new InterruptedException(); /* throw an exception */
+ }
+
+ EventThreadItem item = head;
+ head = item.next;
+ if (head == null)
+ {
+ tail = null;
+ }
+
+ return(item);
+ }
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/ListenerList.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/ListenerList.java
new file mode 100644
index 000000000..cdaa49347
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/eventmgr/ListenerList.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.eventmgr;
+
+/**
+ * This internal class manages the list of listeners. Each object is
+ * immutable, once created it cannot be modified. The most expensive
+ * operation on the list is removeListener. This operation must descend
+ * the list until the listener is found, then as it returns up the call
+ * chain, new ListenerList objects are created and returned to rebuild the list.
+ */
+
+class ListenerList
+{
+ /**
+ * Next item in list.
+ */
+ final ListenerList list;
+
+ /**
+ * Listener referenced by this item.
+ */
+ final Object listener;
+
+ /**
+ * Listener object referenced by this item.
+ */
+ final Object object;
+
+ static final boolean DEBUG = true;
+
+ /**
+ * Private constructor used by addListener and removeListener.
+ *
+ * @param oldlist Existing list or null if no list.
+ * @param l Listener to be added to list.
+ * @return List object.
+ */
+ private ListenerList(ListenerList oldlist, Object l, Object o)
+ {
+ list = oldlist;
+ listener = l;
+ object = o;
+ }
+
+ /**
+ * Static method to add a listener to a list.
+ *
+ * @param oldlist Existing list to which the listener is to be added.
+ * @param l Listener to be added to list.
+ * @param o Listener specific object to be added to list.
+ * @return New list with listener added.
+ */
+ static ListenerList addListener(ListenerList oldlist, Object l, Object o)
+ {
+ /* Create the linked list element in the listener's memory space */
+ // resman begin
+ return (new ListenerList(oldlist, l, o));
+ // resman end
+ }
+
+ /**
+ * Static method to remove a listener from the list.
+ *
+ * @param oldlist Existing list from which the listener is to be removed
+ * @param l Listener to be removed from list
+ * @return New list with listener removed.
+ */
+ static ListenerList removeListener(ListenerList oldlist, Object l)
+ {
+ if (oldlist != null) /* list is not empty */
+ {
+ try
+ {
+ return (oldlist.removeListener(l));
+ }
+ catch (IllegalArgumentException e)
+ {
+ /* Listener to be removed was not found */
+ }
+ }
+ return (oldlist);
+ }
+
+ /**
+ * Private method to recurse down the list looking for the listener to remove.
+ * When the listener is found, the call chain returns creating new List
+ * objects rebuilding the list.
+ *
+ * @param l Listener to be removed from list
+ * @return New sublist with listener removed.
+ * @exception java.lang.IllegalArgumentException If listener to be removed
+ * is not found
+ */
+ private ListenerList removeListener(Object l)
+ throws IllegalArgumentException
+ {
+ if (listener == l) /* Check if this the guy to remove */
+ {
+ return (list); /* return the next on the list */
+ }
+
+ if (list != null) /* we've not reached the end of the list */
+ {
+ ListenerList ll = list.removeListener(l);
+
+ /* Create the linked list element in the listener's memory space */
+ // resman begin
+ return (new ListenerList(ll, listener, object));
+ // resman end
+ }
+
+ /* We have reached the end of the list and have not found the listener */
+ throw new IllegalArgumentException();
+ }
+
+ /**
+ * This method calls the EventSource object to complete the dispatch of
+ * the event. If there are more listeners in the list, call dispatchEvent
+ * on the next item on the list.
+ *
+ * @param source Call back object which is called to complete the delivery of
+ * the event.
+ * @param action This value was passed by the event source and
+ * is passed to this method. This is passed on to the call back object.
+ * @param object This object was created by the event source and
+ * is passed to this method. This is passed on to the call back object.
+ */
+ void dispatchEvent(EventSource source, int action, Object object)
+ {
+ /* Remember the current thread's active memory space */
+ // resman begin
+ for (ListenerList ll = this; ll != null; ll = ll.list)
+ {
+ /* Dispatch the event in the listener's memory space */
+ // resman select memoryspace
+
+ try
+ {
+ /* Call the call back method with the listener */
+ source.dispatchEvent(ll.listener, ll.object, action, object);
+ }
+ catch (Throwable t)
+ {
+ /* Consume and ignore any exceptions thrown by the listener */
+
+ if (DEBUG) {
+ System.out.println("Exception in " + ll.listener);
+ t.printStackTrace();
+ }
+ }
+ }
+ // resman end
+ }
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/AliasMapper.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/AliasMapper.java
new file mode 100644
index 000000000..0b603570f
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/AliasMapper.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.Hashtable;
+
+import org.eclipse.osgi.framework.debug.Debug;
+import org.eclipse.osgi.framework.util.*;
+
+/**
+ * This class maps aliases.
+ */
+public class AliasMapper
+{
+ private static Hashtable processorAliasTable;
+ private static Hashtable osnameAliasTable;
+
+ /**
+ * Constructor.
+ *
+ */
+ public AliasMapper()
+ {
+ }
+
+ /**
+ * Return the master alias for the processor.
+ *
+ * @param processor Input name
+ * @return aliased name (if any)
+ */
+ public String aliasProcessor(String processor)
+ {
+ processor = processor.toLowerCase();
+
+ if (processorAliasTable == null)
+ {
+ InputStream in = getClass().getResourceAsStream(Constants.OSGI_PROCESSOR_ALIASES);
+ if (in != null)
+ {
+ try
+ {
+ processorAliasTable = initAliases(in);
+ }
+ finally
+ {
+ try
+ {
+ in.close();
+ }
+ catch (IOException ee)
+ {
+ }
+ }
+ }
+
+ }
+
+ if (processorAliasTable != null)
+ {
+ String alias = (String)processorAliasTable.get(processor);
+
+ if (alias != null)
+ {
+ processor = alias;
+ }
+ }
+
+ return(processor);
+ }
+
+ /**
+ * Return the master alias for the osname.
+ *
+ * @param osname Input name
+ * @return aliased name (if any)
+ */
+ public String aliasOSName(String osname)
+ {
+ osname = osname.toLowerCase();
+
+ if (osnameAliasTable == null)
+ {
+ InputStream in = getClass().getResourceAsStream(Constants.OSGI_OSNAME_ALIASES);
+ if (in != null)
+ {
+ try
+ {
+ osnameAliasTable = initAliases(in);
+ }
+ finally
+ {
+ try
+ {
+ in.close();
+ }
+ catch (IOException ee)
+ {
+ }
+ }
+ }
+ }
+
+ if (osnameAliasTable != null)
+ {
+ String alias = (String)osnameAliasTable.get(osname);
+
+ if (alias != null)
+ {
+ osname = alias;
+ }
+ }
+
+ return(osname);
+ }
+
+ /**
+ * Read alias data and populate a Hashtable.
+ *
+ * @param in InputStream from which to read alias data.
+ * @return Hashtable of aliases.
+ */
+ protected static Hashtable initAliases(InputStream in)
+ {
+ Hashtable aliases = new Hashtable(37);
+
+ try
+ {
+ BufferedReader br;
+ try
+ {
+ br = new BufferedReader(new InputStreamReader(in, "UTF8"));
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ br = new BufferedReader(new InputStreamReader(in));
+ }
+
+ while (true)
+ {
+ String line = br.readLine();
+
+ if (line == null) /* EOF */
+ {
+ break; /* done */
+ }
+
+ Tokenizer tokenizer = new Tokenizer(line);
+
+ String master = tokenizer.getString("#");
+
+ if (master != null)
+ {
+ aliases.put(master.toLowerCase(), master);
+
+ parseloop:
+ while (true)
+ {
+ String alias = tokenizer.getString("#");
+
+ if (alias == null)
+ {
+ break parseloop;
+ }
+
+ aliases.put(alias.toLowerCase(), master);
+ }
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.printStackTrace(e);
+ }
+ }
+
+ return(aliases);
+ }
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Bundle.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Bundle.java
new file mode 100644
index 000000000..e17acbcf4
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Bundle.java
@@ -0,0 +1,1591 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.*;
+import java.util.*;
+import org.eclipse.osgi.framework.adaptor.*;
+import org.eclipse.osgi.framework.adaptor.Version;
+import org.eclipse.osgi.framework.debug.Debug;
+import org.eclipse.osgi.service.resolver.*;
+import org.osgi.framework.*;
+
+/**
+ * This object is given out to bundles and wraps the internal
+ * Bundle object. It is destroyed when a bundle is uninstalled
+ * and reused if a bundle is updated. This class is abstract and
+ * is extended by BundleHost and BundleFragment.
+ */
+
+public abstract class Bundle implements org.osgi.framework.Bundle, Comparable, KeyedElement {
+
+ /** The Framework this bundle is part of */
+ protected Framework framework;
+
+ /** The state of the bundle. */
+ protected volatile int state;
+
+ /** A flag to denote whether a bundle state change is in progress */
+ protected volatile Thread stateChanging;
+
+ /** Bundle's BundleData object */
+ protected BundleData bundledata;
+
+ /** The unique identifier */
+ protected long id;
+
+ /** The identity string for the bundle */
+ protected String location;
+
+ /** Internal object used for state change synchronization */
+ protected Object statechangeLock = new Object();
+
+ /** ProtectionDomain for the bundle */
+ protected ProtectionDomain domain;
+
+ /** Bundle assigned startlevel */
+ protected int startLevel;
+
+ /**
+ * This exception captures the package names that could not be resolved.
+ * This information is collected by importPackages, but the
+ * exception cannot be thrown during the resolve phase. It is saved
+ * here to be thrown later (by Bundle.start for example).
+ */
+ protected BundleException resolveException;
+
+ public static boolean MONITOR_BUNDLES = false;
+
+ /**
+ * Bundle object constructor.
+ * This constructor should not perform any real work.
+ *
+ * @param id Unique context id assigned to bundle
+ * @param bundleFile the bundle's file
+ * @param localStore adaptor specific object for the bundle's local storage
+ * @param manifest Bundle's manifest
+ * @param location identity string for the bundle
+ * @param framework Framework this bundle is running in
+ */
+ protected static Bundle createBundle(BundleData bundledata, String location, Framework framework, int startLevel) throws BundleException
+ {
+ if (bundledata.isFragment())
+ return new BundleFragment(bundledata,location,framework,startLevel);
+ else
+ return new BundleHost(bundledata,location,framework,startLevel);
+ }
+ /**
+ * Bundle object constructor.
+ * This constructor should not perform any real work.
+ *
+ * @param id Unique context id assigned to bundle
+ * @param bundleFile the bundle's file
+ * @param localStore adaptor specific object for the bundle's local storage
+ * @param manifest Bundle's manifest
+ * @param location identity string for the bundle
+ * @param framework Framework this bundle is running in
+ */
+ protected Bundle(BundleData bundledata, String location, Framework framework, int startLevel) throws BundleException
+ {
+ state = INSTALLED;
+ stateChanging = null;
+
+ this.id = bundledata.getBundleID();
+ this.bundledata = bundledata;
+ this.location = location;
+ this.framework = framework;
+ this.startLevel = startLevel;
+ bundledata.setBundle(this);
+ }
+
+ /**
+ * Load the bundle.
+ * @exception org.osgi.framework.BundleException
+ */
+ protected abstract void load() throws BundleException;
+
+ /**
+ * Reload from a new bundle.
+ * This method must be called while holding the bundles lock.
+ *
+ * @param newBundle Dummy Bundle which contains new data.
+ * @return true if an exported package is "in use". i.e. it has been imported by a bundle
+ * @exception org.osgi.framework.BundleException
+ */
+ protected abstract boolean reload(Bundle newBundle) throws BundleException;
+
+ /**
+ * Refresh the bundle. This is called by Framework.refreshPackages.
+ * This method must be called while holding the bundles lock.
+ * this.loader.unimportPackages must have already been called before calling
+ * this method!
+ *
+ * @exception org.osgi.framework.BundleException if an exported package is "in use". i.e. it has been imported by a bundle
+ */
+ protected abstract void refresh() throws BundleException;
+
+ /**
+ * Unload the bundle.
+ * This method must be called while holding the bundles lock.
+ *
+ * @return true if an exported package is "in use". i.e. it has been imported by a bundle
+ */
+ protected abstract boolean unload();
+
+ /**
+ * Close the the Bundle's file.
+ *
+ */
+ protected void close()
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ if ((state & (INSTALLED)) == 0)
+ {
+ Debug.println("Bundle.close called when state != INSTALLED: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ }
+
+ state = UNINSTALLED;
+ }
+
+ /**
+ * Load and instantiate bundle's BundleActivator class
+ */
+ protected BundleActivator loadBundleActivator() throws BundleException
+ {
+ /* load Bundle's BundleActivator if it has one */
+ String activatorClassName = (String)bundledata.getActivator();
+ if (activatorClassName != null)
+ {
+ try
+ {
+ Class activatorClass = loadClass(activatorClassName,false);
+
+ /* Create the activator for the bundle*/
+ return (BundleActivator)(activatorClass.newInstance());
+
+ }
+ catch (Throwable t)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.printStackTrace(t);
+ }
+ throw new BundleException(Msg.formatter.getString("BUNDLE_INVALID_ACTIVATOR_EXCEPTION", activatorClassName), t);
+ }
+ }
+
+ return(null);
+ }
+
+ /**
+ * This method loads a class from the bundle.
+ *
+ * @param name the name of the desired Class.
+ * @param checkPermission indicates whether a permission check should be done.
+ * @return the resulting Class
+ * @exception java.lang.ClassNotFoundException if the class definition was not found.
+ */
+ protected abstract Class loadClass(String name, boolean checkPermission) throws ClassNotFoundException;
+
+ /**
+ * Find the specified resource in this bundle.
+ *
+ * This bundle's class loader is called to search for the named resource.
+ * If this bundle's state is <tt>INSTALLED</tt>, then only this bundle will
+ * be searched for the specified resource. Imported packages cannot be searched
+ * when a bundle has not been resolved.
+ *
+ * @param name The name of the resource.
+ * See <tt>java.lang.ClassLoader.getResource</tt> for a description of
+ * the format of a resource name.
+ * @return a URL to the named resource, or <tt>null</tt> if the resource could
+ * not be found or if the caller does not have
+ * the <tt>AdminPermission</tt>, and the Java Runtime Environment supports permissions.
+ *
+ * @exception java.lang.IllegalStateException If this bundle has been uninstalled.
+ */
+ public abstract URL getResource(String name);
+
+ /**
+ * Returns the current state of the bundle.
+ *
+ * A bundle can only be in one state at any time.
+ *
+ * @return bundle's state.
+ */
+ public int getState()
+ {
+ return(state);
+ }
+
+ /**
+ * Return true if the bundle is starting or active.
+ *
+ */
+ protected boolean isActive()
+ {
+ return((state & (ACTIVE | STARTING)) != 0);
+ }
+
+ /**
+ * Return true if the bundle is resolved.
+ *
+ */
+ protected boolean isResolved()
+ {
+ return (state & (INSTALLED | UNINSTALLED)) == 0;
+ }
+
+ /**
+ * Start this bundle.
+ *
+ * If the current start level is less than this bundle's start level, then the
+ * Framework must persistently mark this bundle as started and delay the
+ * starting of this bundle until the Framework's current start level becomes
+ * equal or more than the bundle's start level.
+ * <p>Otherwise, the following steps are required to start a bundle:
+ * <ol>
+ * <li>If the bundle is {@link #UNINSTALLED} then
+ * an <code>IllegalStateException</code> is thrown.
+ * <li>If the bundle is {@link #ACTIVE} or {@link #STARTING}
+ * then this method returns immediately.
+ * <li>If the bundle is {@link #STOPPING}
+ * then this method may wait for the bundle to return
+ * to the {@link #RESOLVED} state before continuing. If this does not occur
+ * in a reasonable time, a {@link BundleException} is thrown to indicate
+ * the bundle was unable to be started.
+ * <li>If the bundle is not {@link #RESOLVED},
+ * an attempt is made to resolve the bundle. If the bundle cannot be
+ * resolved, a {@link BundleException} is thrown.
+ * <li>The state of the bundle is set to {@link #STARTING}.
+ * <li>The {@link BundleActivator#start start} method of the bundle's
+ * {@link BundleActivator}, if one is specified, is called.
+ * If the {@link BundleActivator}
+ * is invalid or throws an exception, the state of the bundle
+ * is set back to {@link #RESOLVED},
+ * the bundle's listeners, if any, are removed,
+ * service's registered by the bundle, if any, are unregistered,
+ * and service's used by the bundle, if any, are released.
+ * A {@link BundleException} is then thrown.
+ * <li>It is recorded that this bundle has been started, so that when
+ * the framework is restarted, this bundle will be automatically started.
+ * <li>The state of the bundle is set to {@link #ACTIVE}.
+ * <li>A {@link BundleEvent} of type {@link BundleEvent#STARTED} is broadcast.
+ * </ol>
+ *
+ * <h5>Preconditons</h5>
+ * <ul>
+ * <li>getState() in {{@link #INSTALLED},{@link #RESOLVED}}.
+ * </ul>
+ * <h5>Postconditons, no exceptions thrown</h5>
+ * <ul>
+ * <li>getState() in {{@link #ACTIVE}}.
+ * <li>{@link BundleActivator#start BundleActivator.start} has been called and did not
+ * throw an exception.
+ * </ul>
+ * <h5>Postconditions, when an exception is thrown</h5>
+ * <ul>
+ * <li>getState() not in {{@link #STARTING}, {@link #ACTIVE}}.
+ * </ul>
+ *
+ * @exception BundleException If the bundle couldn't be started.
+ * This could be because a code dependency could not be resolved or
+ * the specified BundleActivator could not be loaded or threw an exception.
+ * @exception java.lang.IllegalStateException If the
+ * bundle has been uninstalled or the
+ * bundle tries to change its own state.
+ * @exception java.lang.SecurityException If the caller does not have
+ * {@link AdminPermission} permission and the Java runtime environment
+ * supports permissions.
+ */
+
+ public void start() throws BundleException
+ {
+ long start = 0;
+ if (Debug.DEBUG && Debug.DEBUG_BUNDLE_TIME) {
+ start = System.currentTimeMillis();
+ System.out.println("Starting " + getGlobalName());
+ }
+ framework.checkAdminPermission();
+ checkValid();
+ beginStateChange();
+ try
+ {
+ startWorker(true);
+ }
+ finally
+ {
+ completeStateChange();
+ }
+ if (Debug.DEBUG && Debug.DEBUG_BUNDLE_TIME)
+ System.out.println("End starting " + getGlobalName() + " " + (System.currentTimeMillis() - start));
+ }
+
+ /**
+ * Internal worker to start a bundle.
+ *
+ * @param persistent if true persistently record the bundle was started.
+ */
+ protected abstract void startWorker(boolean persistent) throws BundleException;
+
+ /**
+ * Start this bundle w/o marking is persistently started.
+ *
+ * <p>The following steps are followed to start a bundle:
+ * <ol>
+ * <li>If the bundle is {@link #UNINSTALLED} then
+ * an <code>IllegalStateException</code> is thrown.
+ * <li>If the bundle is {@link #ACTIVE} or {@link #STARTING}
+ * then this method returns immediately.
+ * <li>If the bundle is {@link #STOPPING}
+ * then this method may wait for the bundle to return
+ * to the {@link #RESOLVED} state before continuing. If this does not occur
+ * in a reasonable time, a {@link BundleException} is thrown to indicate
+ * the bundle was unable to be started.
+ * <li>If the bundle is not {@link #RESOLVED},
+ * an attempt is made to resolve the bundle. If the bundle cannot be
+ * resolved, a {@link BundleException} is thrown.
+ * <li>The state of the bundle is set to {@link #STARTING}.
+ * <li>The {@link BundleActivator#start start} method of the bundle's
+ * {@link BundleActivator}, if one is specified, is called.
+ * If the {@link BundleActivator}
+ * is invalid or throws an exception, the state of the bundle
+ * is set back to {@link #RESOLVED},
+ * the bundle's listeners, if any, are removed,
+ * service's registered by the bundle, if any, are unregistered,
+ * and service's used by the bundle, if any, are released.
+ * A {@link BundleException} is then thrown.
+ * <li>The state of the bundle is set to {@link #ACTIVE}.
+ * <li>A {@link BundleEvent} of type {@link BundleEvent#STARTED} is broadcast.
+ * </ol>
+ *
+ * <h5>Preconditons</h5>
+ * <ul>
+ * <li>getState() in {{@link #INSTALLED},{@link #RESOLVED}}.
+ * </ul>
+ * <h5>Postconditons, no exceptions thrown</h5>
+ * <ul>
+ * <li>getState() in {{@link #ACTIVE}}.
+ * <li>{@link BundleActivator#start BundleActivator.start} has been called and did not
+ * throw an exception.
+ * </ul>
+ * <h5>Postconditions, when an exception is thrown</h5>
+ * <ul>
+ * <li>getState() not in {{@link #STARTING}, {@link #ACTIVE}}.
+ * </ul>
+ *
+ * @exception BundleException If the bundle couldn't be started.
+ * This could be because a code dependency could not be resolved or
+ * the specified BundleActivator could not be loaded or threw an exception.
+ * @exception java.lang.IllegalStateException If the
+ * bundle tries to change its own state.
+ */
+ protected void resume() throws BundleException
+ {
+ if (state == UNINSTALLED)
+ {
+ return;
+ }
+
+ beginStateChange();
+ try
+ {
+ startWorker(false);
+ }
+ finally
+ {
+ completeStateChange();
+ }
+ }
+
+ /**
+ * Stop this bundle.
+ *
+ * Any services registered by this bundle will be unregistered.
+ * Any services used by this bundle will be released.
+ * Any listeners registered by this bundle will be removed.
+ *
+ * <p>The following steps are followed to stop a bundle:
+ * <ol>
+ * <li>If the bundle is {@link #UNINSTALLED} then
+ * an <code>IllegalStateException</code> is thrown.
+ * <li>If the bundle is {@link #STOPPING}, {@link #RESOLVED},
+ * or {@link #INSTALLED}
+ * then this method returns immediately.
+ * <li>If the bundle is {@link #STARTING}
+ * then this method may wait for the bundle to reach
+ * the {@link #ACTIVE} state before continuing. If this does not occur
+ * in a reasonable time, a {@link BundleException} is thrown to indicate
+ * the bundle was unable to be stopped.
+ * <li>The state of the bundle is set to {@link #STOPPING}.
+ * <li>It is recorded that this bundle has been stopped, so that when
+ * the framework is restarted, this bundle will not be automatically started.
+ * <li>The {@link BundleActivator#stop stop} method of the bundle's
+ * {@link BundleActivator}, if one is specified, is called.
+ * If the {@link BundleActivator}
+ * throws an exception, this method will continue to stop the bundle.
+ * A {@link BundleException} will be thrown after completion of the remaining steps.
+ * <li>The bundle's listeners, if any, are removed,
+ * service's registered by the bundle, if any, are unregistered, and
+ * service's used by the bundle, if any, are released.
+ * <li>The state of the bundle is set to {@link #RESOLVED}.
+ * <li>A {@link BundleEvent} of type {@link BundleEvent#STOPPED} is broadcast.
+ * </ol>
+ *
+ * <h5>Preconditons</h5>
+ * <ul>
+ * <li>getState() in {{@link #ACTIVE}}.
+ * </ul>
+ * <h5>Postconditons, no exceptions thrown</h5>
+ * <ul>
+ * <li>getState() not in {{@link #ACTIVE}, {@link #STOPPING}}.
+ * <li>{@link BundleActivator#stop BundleActivator.stop} has been called and did not
+ * throw an exception.
+ * </ul>
+ * <h5>Postconditions, when an exception is thrown</h5>
+ * <ul>
+ * <li>None.
+ * </ul>
+ *
+ * @exception BundleException If the bundle's
+ * BundleActivator could not be loaded or threw an exception.
+ * @exception java.lang.IllegalStateException If the
+ * bundle has been uninstalled or the
+ * bundle tries to change its own state.
+ * @exception java.lang.SecurityException If the caller does not have
+ * {@link AdminPermission} permission and the Java runtime environment
+ * supports permissions.
+ */
+ public void stop() throws BundleException
+ {
+ framework.checkAdminPermission();
+
+ checkValid();
+
+ beginStateChange();
+ try
+ {
+ stopWorker(true);
+ }
+ finally
+ {
+ completeStateChange();
+ }
+ }
+
+ /**
+ * Internal worker to stop a bundle.
+ *
+ * @param persistent if true persistently record the bundle was stopped.
+ */
+ protected abstract void stopWorker(boolean persistent) throws BundleException;
+
+ /**
+ * Set the persistent status bit for the bundle.
+ *
+ * @param mask Mask for bit to set/clear
+ * @param state true to set bit, false to clear bit
+ */
+ protected void setStatus(final int mask, final boolean state)
+
+ {
+ try
+ {
+ AccessController.doPrivileged(new PrivilegedExceptionAction()
+ {
+ public Object run() throws BundleException, IOException
+ {
+ int status = bundledata.getStatus();
+ boolean test = ((status & mask) != 0);
+ if (test != state)
+ {
+ bundledata.setStatus(state ? (status | mask) : (status & ~mask));
+ bundledata.save();
+ }
+
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException pae)
+ {
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, pae.getException());
+ }
+ }
+
+ /**
+ * Stop this bundle w/o marking is persistently stopped.
+ *
+ * Any services registered by this bundle will be unregistered.
+ * Any services used by this bundle will be released.
+ * Any listeners registered by this bundle will be removed.
+ *
+ * <p>The following steps are followed to stop a bundle:
+ * <ol>
+ * <li>If the bundle is {@link #UNINSTALLED} then
+ * an <code>IllegalStateException</code> is thrown.
+ * <li>If the bundle is {@link #STOPPING}, {@link #RESOLVED},
+ * or {@link #INSTALLED}
+ * then this method returns immediately.
+ * <li>If the bundle is {@link #STARTING}
+ * then this method may wait for the bundle to reach
+ * the {@link #ACTIVE} state before continuing. If this does not occur
+ * in a reasonable time, a {@link BundleException} is thrown to indicate
+ * the bundle was unable to be stopped.
+ * <li>The state of the bundle is set to {@link #STOPPING}.
+ * <li>The {@link BundleActivator#stop stop} method of the bundle's
+ * {@link BundleActivator}, if one is specified, is called.
+ * If the {@link BundleActivator}
+ * throws an exception, this method will continue to stop the bundle.
+ * A {@link BundleException} will be thrown after completion of the remaining steps.
+ * <li>The bundle's listeners, if any, are removed,
+ * service's registered by the bundle, if any, are unregistered, and
+ * service's used by the bundle, if any, are released.
+ * <li>The state of the bundle is set to {@link #RESOLVED}.
+ * <li>A {@link BundleEvent} of type {@link BundleEvent#STOPPED} is broadcast.
+ * </ol>
+ *
+ * <h5>Preconditons</h5>
+ * <ul>
+ * <li>getState() in {{@link #ACTIVE}}.
+ * </ul>
+ * <h5>Postconditons, no exceptions thrown</h5>
+ * <ul>
+ * <li>getState() not in {{@link #ACTIVE}, {@link #STOPPING}}.
+ * <li>{@link BundleActivator#stop BundleActivator.stop} has been called and did not
+ * throw an exception.
+ * </ul>
+ * <h5>Postconditions, when an exception is thrown</h5>
+ * <ul>
+ * <li>None.
+ * </ul>
+ *
+ * @param lock true if state change lock should be held
+ * when returning from this method.
+ * @exception BundleException If the bundle's
+ * BundleActivator could not be loaded or threw an exception.
+ * @exception java.lang.IllegalStateException If the
+ * bundle tries to change its own state.
+ */
+ protected void suspend(boolean lock) throws BundleException
+ {
+ if (state == UNINSTALLED)
+ {
+ return;
+ }
+
+ beginStateChange();
+ try
+ {
+ stopWorker(false);
+ }
+ finally
+ {
+ if (!lock)
+ {
+ completeStateChange();
+ }
+ }
+ }
+
+ /**
+ * Update this bundle. If the bundle is {@link #ACTIVE}, the bundle will be stopped
+ * before the update and started after the update successfully completes.
+ *
+ * <p>The following steps are followed to update a bundle:
+ * <ol>
+ * <li>If the bundle is {@link #UNINSTALLED} then
+ * an <code>IllegalStateException</code> is thrown.
+ * <li>If the bundle is {@link #ACTIVE} or {@link #STARTING},
+ * the bundle is stopped as described in the {@link #stop} method.
+ * If {@link #stop} throws an exception, the exception is rethrown
+ * terminating the update.
+ * <li>The location for the new version of the bundle is determined from either the
+ * manifest header <code>Bundle-UpdateLocation</code> if available or the original
+ * location.
+ * <li>The location is interpreted in an implementation dependent way
+ * (typically as a URL) and the new version of the bundle is obtained from the location.
+ * <li>The new version of the bundle is installed. If the framework is unable
+ * to install the new version of the bundle, the original version of the bundle will
+ * be restored and a {@link BundleException} will be thrown
+ * after completion of the remaining steps.
+ * <li>The state of the bundle is set to {@link #INSTALLED}.
+ * <li>If the new version of the bundle was successfully installed,
+ * a {@link BundleEvent} of type {@link BundleEvent#UPDATED} is broadcast.
+ * <li>If the bundle was originally {@link #ACTIVE},
+ * the updated bundle is started as described in the {@link #start} method.
+ * If {@link #start} throws an exception,
+ * a {@link FrameworkEvent} of type {@link FrameworkEvent#ERROR} is broadcast
+ * containing the exception.
+ * </ol>
+ *
+ * <h5>Preconditions</h5>
+ * <ul>
+ * <li>getState() not in {{@link #UNINSTALLED}}.
+ * </ul>
+ * <h5>Postconditons, no exceptions thrown</h5>
+ * <ul>
+ * <li>getState() in {{@link #INSTALLED},{@link #RESOLVED},{@link #ACTIVE}}.
+ * <li>The bundle has been updated.
+ * </ul>
+ * <h5>Postconditions, when an exception is thrown</h5>
+ * <ul>
+ * <li>getState() in {{@link #INSTALLED},{@link #RESOLVED},{@link #ACTIVE}}.
+ * <li>Original bundle is still used, no update took place.
+ * </ul>
+ *
+ * @exception BundleException If the update fails.
+ * @exception java.lang.IllegalStateException If the
+ * bundle has been uninstalled or the
+ * bundle tries to change its own state.
+ * @exception java.lang.SecurityException If the caller does not have
+ * {@link AdminPermission} permission and the Java runtime environment
+ * supports permissions.
+ * @see #stop()
+ * @see #start()
+ */
+ public void update() throws BundleException
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println("update location "+location);
+ }
+
+ framework.checkAdminPermission();
+
+ checkValid();
+
+ beginStateChange();
+ try
+ {
+ updateWorker(new PrivilegedExceptionAction()
+ {
+ public Object run() throws BundleException
+ {
+ /* compute the update location */
+ String updateLocation = location;
+ if (bundledata.getManifest().get(Constants.BUNDLE_UPDATELOCATION) != null)
+ {
+ updateLocation = (String)bundledata.getManifest().get(Constants.BUNDLE_UPDATELOCATION);
+
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println(" from location: " + updateLocation);
+ }
+ }
+
+ /* Map the identity to a URLConnection */
+ URLConnection source = framework.adaptor.mapLocationToURLConnection(updateLocation);
+
+ /* call the worker */
+ updateWorkerPrivileged(source);
+
+ return null;
+ }
+ });
+ }
+ catch (BundleException e)
+ {
+ if (!(e.getNestedException() instanceof NothingToUpdateException))
+ {
+ throw e;
+ }
+
+ //There is no work to be done with this update.
+ //Quietly return with no error.
+ }
+ finally
+ {
+ completeStateChange();
+ }
+ }
+
+ /**
+ * Update this bundle from an InputStream.
+ *
+ * <p>This method performs all the steps listed in
+ * {@link #update}, except the bundle
+ * will be read in through the supplied <code>InputStream</code>, rather
+ * than a <code>URL</code>.
+ *
+ * @param in The InputStream from which to read the new bundle.
+ * @see #update()
+ */
+ public void update(final InputStream in) throws BundleException
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println("update location "+location);
+ Debug.println(" from: "+in);
+ }
+
+ framework.checkAdminPermission();
+
+ checkValid();
+
+ beginStateChange();
+ try
+ {
+ updateWorker(new PrivilegedExceptionAction()
+ {
+ public Object run() throws BundleException
+ {
+ /* Map the InputStream to a URLConnection */
+ URLConnection source = new BundleSource(in);
+
+ /* call the worker */
+ updateWorkerPrivileged(source);
+
+ return null;
+ }
+ });
+ }
+ finally
+ {
+ completeStateChange();
+ }
+ }
+
+ /**
+ * Update worker. Assumes the caller has the state change lock.
+ */
+ protected void updateWorker(PrivilegedExceptionAction action) throws BundleException
+ {
+ boolean bundleActive = false;
+ Bundle host=null;
+ if (isFragment()) {
+ host = (Bundle) getHost();
+ bundleActive = (host == null ? false : (host.state == ACTIVE));
+ }
+ else {
+ bundleActive = (state == ACTIVE);
+ }
+
+ if (bundleActive)
+ {
+ try
+ {
+ if (isFragment()){
+ host.stopWorker(false);
+ }
+ else {
+ stopWorker(false);
+ }
+ }
+ catch (BundleException e)
+ {
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, e);
+
+ if (state == ACTIVE) /* if the bundle is still active */
+ {
+ throw e;
+ }
+ }
+ }
+
+ try
+ {
+ AccessController.doPrivileged(action);
+
+ framework.publishBundleEvent(BundleEvent.UPDATED, this);
+ }
+ catch (PrivilegedActionException pae)
+ {
+ throw (BundleException)pae.getException();
+ }
+ finally
+ {
+ if (bundleActive)
+ {
+ try
+ {
+ if (isFragment()){
+ host.startWorker(false);
+ }
+ else {
+ startWorker(false);
+ }
+ }
+ catch (BundleException e)
+ {
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Update worker. Assumes the caller has the state change lock.
+ */
+ protected void updateWorkerPrivileged(URLConnection source) throws BundleException
+ {
+ Bundle oldBundle = Bundle.createBundle(this.bundledata, this.location, framework, this.startLevel);
+ boolean reloaded = false;
+
+ BundleOperation storage = framework.adaptor.updateBundle(this.bundledata, source);
+ BundleRepository bundles = framework.getBundles();
+
+ try
+ {
+ BundleData newBundleData = storage.begin();
+ // Must call framework createBundle to check execution environment.
+ Bundle newBundle = framework.createBundle(newBundleData,this.location,this.startLevel);
+
+ // Check for a bundle already installed with the same UniqueId
+ // and version.
+ Bundle installedBundle =
+ framework.getBundleByUniqueId(newBundle.getGlobalName(), newBundle.getVersion().toString());
+ if (installedBundle != null && installedBundle != this) {
+ throw new BundleException(
+ Msg.formatter.getString(
+ "BUNDLE_INSTALL_SAME_UNIQUEID",
+ newBundle.getGlobalName(), newBundle.getVersion().toString()));
+ }
+
+ String[] nativepaths = framework.selectNativeCode(newBundle);
+ if (nativepaths != null) {
+ bundledata.installNativeCode(nativepaths);
+ }
+
+ boolean exporting;
+
+ synchronized (bundles)
+ {
+ bundles.markDependancies();
+ exporting = reload(newBundle);
+ }
+ reloaded = true; /* indicate we have loaded from the new version of the bundle */
+
+ storage.commit(exporting);
+ }
+ catch (BundleException e)
+ {
+ try
+ {
+ storage.undo();
+
+ if (reloaded) /* if we loaded from the new version of the bundle */
+ {
+ synchronized (bundles)
+ {
+ reload(oldBundle); /* revert to old version */
+ }
+ }
+ }
+ catch (BundleException ee)
+ {
+ /* if we fail to revert then we are in big trouble */
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, ee);
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Uninstall this bundle.
+ * <p>This method removes all traces of the bundle, including any data in the
+ * persistent storage area provided for the bundle by the framework.
+ *
+ * <p>The following steps are followed to uninstall a bundle:
+ * <ol>
+ * <li>If the bundle is {@link #UNINSTALLED} then
+ * an <code>IllegalStateException</code> is thrown.
+ * <li>If the bundle is {@link #ACTIVE} or {@link #STARTING},
+ * the bundle is stopped as described in the {@link #stop} method.
+ * If {@link #stop} throws an exception,
+ * a {@link FrameworkEvent} of type {@link FrameworkEvent#ERROR} is broadcast
+ * containing the exception.
+ * <li>A {@link BundleEvent} of type {@link BundleEvent#UNINSTALLED} is broadcast.
+ * <li>The state of the bundle is set to {@link #UNINSTALLED}.
+ * <li>The bundle and the
+ * persistent storage area provided for the bundle by the framework,
+ * if any, is removed.
+ * </ol>
+ *
+ * <h5>Preconditions</h5>
+ * <ul>
+ * <li>getState() not in {{@link #UNINSTALLED}}.
+ * </ul>
+ * <h5>Postconditons, no exceptions thrown</h5>
+ * <ul>
+ * <li>getState() in {{@link #UNINSTALLED}}.
+ * <li>The bundle has been uninstalled.
+ * </ul>
+ * <h5>Postconditions, when an exception is thrown</h5>
+ * <ul>
+ * <li>getState() not in {{@link #UNINSTALLED}}.
+ * <li>The Bundle has not been uninstalled.
+ * </ul>
+ *
+ * @exception BundleException If the uninstall failed.
+ * @exception java.lang.IllegalStateException If the
+ * bundle has been uninstalled or the
+ * bundle tries to change its own state.
+ * @exception java.lang.SecurityException If the caller does not have
+ * {@link AdminPermission} permission and the Java runtime environment
+ * supports permissions.
+ * @see #stop()
+ */
+ public void uninstall() throws BundleException
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println("uninstall location: " + location);
+ }
+
+ framework.checkAdminPermission();
+
+ checkValid();
+
+ beginStateChange();
+ try
+ {
+ uninstallWorker(new PrivilegedExceptionAction()
+ {
+ public Object run() throws BundleException
+ {
+ uninstallWorkerPrivileged();
+
+ return null;
+ }
+ });
+ } finally
+ {
+ completeStateChange();
+ }
+ }
+
+ /**
+ * Uninstall worker. Assumes the caller has the state change lock.
+ */
+ protected void uninstallWorker(PrivilegedExceptionAction action) throws BundleException
+ {
+ boolean bundleActive = false;
+ Bundle host=null;
+ if (isFragment()) {
+ host = (Bundle) getHost();
+ bundleActive = (host == null ? false : (host.state == ACTIVE));
+ }
+ else {
+ bundleActive = (state == ACTIVE);
+ }
+
+ if (bundleActive)
+ {
+ try
+ {
+ if (isFragment()){
+ host.stopWorker(true);
+ }
+ else {
+ stopWorker(true);
+ }
+ }
+ catch (BundleException e)
+ {
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, e);
+ }
+ }
+
+ try
+ {
+ AccessController.doPrivileged(action);
+ }
+ catch (PrivilegedActionException pae)
+ {
+ if (bundleActive) /* if we stopped the bundle */
+ {
+ try
+ {
+ if (isFragment()){
+ host.startWorker(false);
+ }
+ else {
+ startWorker(false);
+ }
+ }
+ catch (BundleException e)
+ {
+ /* if we fail to start the original bundle then we are in big trouble */
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, e);
+ }
+ // set the bundleActive to false so that the finally will not try
+ // to start the bundle again.
+ bundleActive = false;
+ }
+
+ throw (BundleException)pae.getException();
+ }
+ finally {
+ if (isFragment() && bundleActive) {
+ try {
+ host.startWorker(false);
+ }
+ catch (BundleException e)
+ {
+ /* if we fail to start the original host bundle then we are in big trouble */
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, e);
+ }
+ }
+ }
+
+ framework.publishBundleEvent(BundleEvent.UNINSTALLED, this);
+ }
+
+ /**
+ * Uninstall worker. Assumes the caller has the state change lock.
+ */
+ protected void uninstallWorkerPrivileged() throws BundleException
+ {
+ boolean unloaded = false;
+
+ BundleOperation storage = framework.adaptor.uninstallBundle(this.bundledata);
+
+ BundleRepository bundles = framework.getBundles();
+
+ try
+ {
+ storage.begin();
+
+ boolean exporting;
+
+ synchronized (bundles)
+ {
+ bundles.markDependancies();
+ bundles.remove(this); /* remove before calling unload */
+ exporting = unload();
+ }
+ unloaded = true;
+
+ storage.commit(exporting);
+
+ close();
+ }
+ catch (BundleException e)
+ {
+ try
+ {
+ storage.undo();
+
+ if (unloaded) /* if we unloaded the bundle */
+ {
+ synchronized (bundles) {
+ load(); /* reload the bundle */
+
+ bundles.add(this);
+ }
+ }
+ }
+ catch (BundleException ee)
+ {
+ /* if we fail to load the original bundle then we are in big trouble */
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, ee);
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Return the bundle's manifest headers and values from the manifest's
+ * preliminary section. That is all the manifest's headers and values
+ * prior to the first blank line.
+ *
+ * <p>Manifest header names are case-insensitive. The methods of the
+ * returned <code>Dictionary</code> object will operate on header names
+ * in a case-insensitive manner.
+ *
+ * <p>For example, the following manifest headers and values are included
+ * if they are present in the manifest:
+ * <pre>
+ * Bundle-Name
+ * Bundle-Vendor
+ * Bundle-Version
+ * Bundle-Description
+ * Bundle-DocURL
+ * Bundle-ContactAddress
+ * </pre>
+ *
+ * <p>This method will continue to return this information
+ * when the bundle is in the {@link #UNINSTALLED} state.
+ *
+ * @return A <code>Dictionary</code> object containing
+ * the bundle's manifest headers and values.
+ * @exception java.lang.SecurityException If the caller does not have
+ * {@link AdminPermission} permission and the Java runtime environment
+ * supports permissions.
+ */
+ public Dictionary getHeaders()
+ {
+ framework.checkAdminPermission();
+ return bundledata.getHeaders();
+ }
+
+ /**
+ * Retrieve the bundle's unique identifier, which the framework
+ * assigned to this bundle when it was installed.
+ *
+ * <p>The unique identifier has the following attributes:
+ * <ul>
+ * <li>It is unique and persistent.
+ * <li>The identifier is a long.
+ * <li>Once its value is assigned to a bundle, that value is
+ * not reused for another bundle, even after the bundle
+ * is uninstalled.
+ * <li>Its value does not change as long as the bundle remains installed.
+ * <li>Its value does not change when the bundle is updated
+ * </ul>
+ *
+ * <p>This method will continue to return the bundle's unique identifier
+ * when the bundle is in the {@link #UNINSTALLED} state.
+ *
+ * @return This bundle's unique identifier.
+ */
+ public long getBundleId()
+ {
+ return(id);
+ }
+
+
+ /**
+ * Retrieve the location identifier of the bundle.
+ * This is typically the location passed to
+ * {@link BundleContext#installBundle BundleContext.installBundle}
+ * when the bundle was installed. The location identifier of the
+ * bundle may change during bundle update.
+ * Calling this method while framework is updating
+ * the bundle results in undefined behavior.
+ *
+ * <p>This method will continue to return the bundle's location
+ * identifier when the bundle is in the {@link #UNINSTALLED} state.
+ *
+ * @return A string that is the location identifier of the bundle.
+ * @exception java.lang.SecurityException If the caller does not have
+ * {@link AdminPermission} permission and the Java runtime environment
+ * supports permissions.
+ */
+ public String getLocation()
+ {
+ framework.checkAdminPermission();
+
+ return(location);
+ }
+
+ /**
+ * Provides a list of {@link ServiceReference}s for the services
+ * registered by this bundle
+ * or <code>null</code> if the bundle has no registered
+ * services.
+ *
+ * <p>The list is valid at the time
+ * of the call to this method, but the framework is a very dynamic
+ * environment and services can be modified or unregistered at anytime.
+ *
+ * @return An array of {@link ServiceReference} or <code>null</code>.
+ * @exception java.lang.IllegalStateException If the
+ * bundle has been uninstalled.
+ * @see ServiceRegistration
+ * @see ServiceReference
+ */
+ public abstract org.osgi.framework.ServiceReference[] getRegisteredServices();
+
+ /**
+ * Provides a list of {@link ServiceReference}s for the
+ * services this bundle is using,
+ * or <code>null</code> if the bundle is not using any services.
+ * A bundle is considered to be using a service if the bundle's
+ * use count for the service is greater than zero.
+ *
+ * <p>The list is valid at the time
+ * of the call to this method, but the framework is a very dynamic
+ * environment and services can be modified or unregistered at anytime.
+ *
+ * @return An array of {@link ServiceReference} or <code>null</code>.
+ * @exception java.lang.IllegalStateException If the
+ * bundle has been uninstalled.
+ * @see ServiceReference
+ */
+ public abstract org.osgi.framework.ServiceReference[] getServicesInUse();
+
+ /**
+ * Determine whether the bundle has the requested
+ * permission.
+ *
+ * <p>If the Java runtime environment does not supports permissions
+ * this method always returns <code>true</code>.
+ * The permission parameter is of type <code>Object</code> to
+ * avoid referencing the <code>java.security.Permission</code> class
+ * directly. This is to allow the framework to be implemented in Java
+ * environments which do not support permissions.
+ *
+ * @param permission The requested permission.
+ * @return <code>true</code> if the bundle has the requested permission or
+ * <code>false</code> if the bundle does not have the permission
+ * or the permission parameter is not an
+ * <code>instanceof java.security.Permission</code>.
+ * @exception java.lang.IllegalStateException If the
+ * bundle has been uninstalled.
+ */
+ public boolean hasPermission(Object permission)
+ {
+ checkValid();
+
+ if (domain != null)
+ {
+ if (permission instanceof Permission)
+ {
+ return domain.implies((Permission)permission);
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * This method marks the bundle's state as changing so that other calls to
+ * start/stop/suspend/update/uninstall can wait until the state change is complete.
+ * If stateChanging is non-null when this method is called, we will wait for the
+ * state change to complete. If the timeout expires without changing state (this may
+ * happen if the state change is back up our call stack), a BundleException is thrown
+ * so that we don't wait forever.
+ *
+ * A call to this method should be immediately followed by a try block whose
+ * finally block calls completeStateChange().
+ *
+ * beginStateChange();
+ * try
+ * {
+ * // change the bundle's state here...
+ * }
+ * finally
+ * {
+ * completeStateChange();
+ * }
+ *
+ * @exception org.osgi.framework.BundleException if the bundles state
+ * is still changing after waiting for the timeout.
+ */
+ protected void beginStateChange() throws BundleException
+ {
+ synchronized (statechangeLock)
+ {
+ boolean doubleFault = false;
+ while (true)
+ {
+ if (stateChanging == null)
+ {
+ stateChanging = Thread.currentThread();
+ return;
+ }
+
+ if (doubleFault || (stateChanging == Thread.currentThread()))
+ {
+ throw new BundleException(Msg.formatter.getString("BUNDLE_STATE_CHANGE_EXCEPTION"));
+ }
+
+ try
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println(" Waiting for state to change in bundle "+this);
+ }
+ long start = 0;
+ if (Debug.DEBUG)
+ start = System.currentTimeMillis();
+ statechangeLock.wait(5000); /* wait for other thread to finish changing state */
+ if (Debug.DEBUG) {
+ long end = System.currentTimeMillis();
+ if (end - start > 0) {
+ System.out.println("Waiting... : " + getGlobalName() + " " + (end -start) );
+ }
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+
+ doubleFault = true;
+ }
+ }
+ }
+
+ /**
+ * This method completes the bundle state change by setting stateChanging
+ * to null and notifying one waiter that the state change has completed.
+ */
+ protected void completeStateChange()
+ {
+ synchronized (statechangeLock)
+ {
+ if (stateChanging != null)
+ {
+ stateChanging = null;
+ statechangeLock.notify(); /* notify one waiting thread that the state change is complete */
+ }
+ }
+ }
+
+ /**
+ * Return a string representation of this bundle.
+ *
+ * @return String
+ */
+ public String toString()
+ {
+ return(location+" ["+id+"]");
+ }
+
+ /**
+ * Answers an integer indicating the relative positions
+ * of the receiver and the argument in the natural order
+ * of elements of the receiver's class.
+ *
+ * @return int
+ * which should be <0 if the receiver
+ * should sort before the argument, 0
+ * if the receiver should sort in the
+ * same position as the argument, and
+ * >0 if the receiver should sort after
+ * the argument.
+ * @param obj another Bundle
+ * an object to compare the receiver to
+ * @exception ClassCastException
+ * if the argument can not be converted
+ * into something comparable with the
+ * receiver.
+ */
+ public int compareTo(Object obj)
+ {
+ int slcomp = startLevel - ((Bundle)obj).startLevel;
+ if (slcomp != 0)
+ {
+ return slcomp;
+ }
+
+ long idcomp = id - ((Bundle)obj).id;
+ return (idcomp < 0L) ? -1 : ((idcomp > 0L) ? 1 : 0);
+ }
+
+ /**
+ * This method checks that the bundle is not uninstalled. If the bundle is
+ * uninstalled, an IllegalStateException is thrown.
+ *
+ * @exception java.lang.IllegalStateException
+ * If the bundle is uninstalled.
+ */
+ protected void checkValid()
+ {
+ if (state == UNINSTALLED)
+ {
+ throw new IllegalStateException(Msg.formatter.getString("BUNDLE_UNINSTALLED_EXCEPTION"));
+ }
+ }
+
+ /**
+ * Get the bundle's ProtectionDomain.
+ *
+ * @return bundle's ProtectionDomain.
+ */
+ protected ProtectionDomain getProtectionDomain()
+ {
+ return domain;
+ }
+
+ /**
+ * The bundle must unresolve the permissions in these packages.
+ *
+ * @param unresolvedPackages A list of the package which have been unresolved
+ * as a result of a packageRefresh
+ */
+ protected void unresolvePermissions(Hashtable unresolvedPackages)
+ {
+ if (domain != null)
+ {
+ BundlePermissionCollection collection = (BundlePermissionCollection) domain.getPermissions();
+
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println("Unresolving permissions in bundle "+this);
+ }
+
+ collection.unresolvePermissions(unresolvedPackages);
+ }
+ }
+
+
+
+ public org.osgi.framework.Bundle[] getFragments() {
+ checkValid();
+ return null;
+ }
+
+ public boolean isFragment() {
+ return false;
+ }
+
+ public org.osgi.framework.Bundle getHost() {
+ checkValid();
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.osgi.framework.Bundle#findClass(java.lang.String)
+ */
+ public Class loadClass(String classname) throws ClassNotFoundException {
+ return loadClass(classname, true);
+ }
+
+ /* (non-Javadoc)
+ * @see org.osgi.framework.Bundle#getResourcePaths(java.lang.String)
+ */
+ public Enumeration getEntryPaths(final String path) {
+ try {
+ framework.checkAdminPermission();
+ }
+ catch (SecurityException e) {
+ return null;
+ }
+ checkValid();
+
+ if (bundledata == null) {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println("Bundle.getResourcePaths("+path+") called when bundledata == null: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+
+ return(null);
+ }
+ return (Enumeration) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return bundledata.getEntryPaths(path);
+ }
+ });
+ }
+
+ /* (non-Javadoc)
+ * @see org.osgi.framework.Bundle#getFile(java.lang.String)
+ */
+ public URL getEntry(String fileName) throws IOException {
+ try {
+ framework.checkAdminPermission();
+ }
+ catch (SecurityException e) {
+ return null;
+ }
+ checkValid();
+ if (bundledata == null) {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println("Bundle.getFile("+fileName+") called when bundledata == null: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+
+ return(null);
+ }
+
+ if (System.getSecurityManager() == null)
+ return bundledata.getEntry(fileName);
+
+ final String ffileName = fileName;
+ return (URL) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return bundledata.getEntry(ffileName);
+ }
+ });
+
+ }
+
+ public String getGlobalName() {
+ return bundledata.getUniqueId();
+ }
+
+ public BundleData getBundleData() {
+ return bundledata;
+ }
+
+ public Version getVersion() {
+ return bundledata.getVersion();
+ }
+ protected BundleDescription getBundleDescription() {
+ return framework.adaptor.getState().getBundle(getBundleId());
+ }
+
+ public abstract BundleLoader getBundleLoader();
+
+ protected abstract void resolve();
+ protected abstract boolean unresolve() throws BundleException;
+
+ /**
+ * Return the current context for this bundle.
+ *
+ * @return BundleContext for this bundle.
+ */
+ abstract protected BundleContext getContext();
+
+ protected String getResolutionFailureMessage() {
+ String defaultMessage = Msg.formatter.getString("BUNDLE_UNRESOLVED_EXCEPTION");
+ // don't spend time if debug info is not needed
+ if (!Debug.DEBUG) {
+ return defaultMessage;
+ }
+ BundleDescription bundleDescription = getBundleDescription();
+ if (bundleDescription == null) {
+ return defaultMessage;
+ }
+ // just a sanity check - this would be an inconsistency between the framework and the state
+ if (bundleDescription.isResolved()) {
+ throw new IllegalStateException("bundle *is* resolved");
+ }
+ VersionConstraint[] unsatisfied = bundleDescription.getUnsatisfiedConstraints();
+ if (unsatisfied.length == 0) {
+ return Msg.formatter.getString("BUNDLE_UNRESOLVED_NOT_CHOSEN_EXCEPTION");
+ }
+ StringBuffer missing = new StringBuffer();
+ for (int i = 0; i < unsatisfied.length; i++) {
+ if (unsatisfied[i] instanceof PackageSpecification) {
+ missing.append(Msg.formatter.getString("BUNDLE_UNRESOLVED_PACKAGE", toString(unsatisfied[i])));
+ } else if (unsatisfied[i] instanceof BundleSpecification) {
+ missing.append(Msg.formatter.getString("BUNDLE_UNRESOLVED_BUNDLE", toString(unsatisfied[i])));
+ } else {
+ missing.append(Msg.formatter.getString("BUNDLE_UNRESOLVED_HOST", toString(unsatisfied[i])));
+ }
+ missing.append(',');
+ }
+ missing.deleteCharAt(missing.length()-1);
+ return Msg.formatter.getString("BUNDLE_UNRESOLVED_UNSATISFIED_CONSTRAINT_EXCEPTION", missing.toString());
+ }
+ private String toString(VersionConstraint constraint) {
+ org.eclipse.osgi.service.resolver.Version versionSpec = constraint.getVersionSpecification();
+ if (versionSpec == null)
+ return constraint.getName();
+ return constraint.getName() + '_' + versionSpec;
+ }
+ public int getKeyHashCode() {
+ return (int)id;
+ }
+ public boolean compare(KeyedElement other) {
+ return id == ((Bundle)other).getBundleId();
+ }
+ public Object getKey() {
+ return new Long(id);
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleCombinedPermissions.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleCombinedPermissions.java
new file mode 100644
index 000000000..08eb14403
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleCombinedPermissions.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.security.Permission;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.NoSuchElementException;
+
+/**
+ * A combination of two BundlePermissionCollection classes.
+ *
+ */
+final class BundleCombinedPermissions extends BundlePermissionCollection
+{
+ private BundlePermissionCollection assigned;
+ private BundlePermissionCollection implied;
+
+ /**
+ * Create a permission combiner class.
+ *
+ * @param implied The permissions a bundle always has.
+ */
+ BundleCombinedPermissions(BundlePermissionCollection implied)
+ {
+ this.implied = implied;
+
+ setReadOnly(); /* this doesn't really mean anything */
+ }
+
+ /**
+ * Assign the administrator defined permissions.
+ *
+ * @param assigned The permissions assigned by the administrator.
+ */
+ void setAssignedPermissions(BundlePermissionCollection assigned)
+ {
+ this.assigned = assigned;
+ }
+
+ /**
+ * The Permission collection will unresolve the permissions in these packages.
+ *
+ * @param unresolvedPackages A list of the package which have been unresolved
+ * as a result of a packageRefresh
+ */
+ void unresolvePermissions(Hashtable unresolvedPackages)
+ {
+ if (assigned != null)
+ {
+ assigned.unresolvePermissions(unresolvedPackages);
+ }
+
+ if (implied != null)
+ {
+ implied.unresolvePermissions(unresolvedPackages);
+ }
+ }
+
+ /**
+ * Adds the argument to the collection.
+ *
+ * @param permission java.security.Permission
+ * the permission to add to the collection.
+ * @exception SecurtityException
+ * if the collection is read only.
+ */
+ public void add(Permission permission)
+ {
+ throw new SecurityException();
+ }
+ /**
+ * Answers an enumeration of the permissions
+ * in the receiver.
+ *
+ * @return Enumeration
+ * the permissions in the receiver.
+ */
+ public Enumeration elements()
+ {
+ return new Enumeration() {
+ private int i = 0;
+ private Enumeration[] enums;
+
+ {
+ enums = new Enumeration[]
+ {
+ (assigned == null) ? null : assigned.elements(),
+ (implied == null) ? null : implied.elements()
+ };
+ }
+
+ /**
+ * Answers if this Enumeration has more elements.
+ *
+ * @return true if there are more elements, false otherwise
+ *
+ * @see #nextElement
+ */
+ public boolean hasMoreElements()
+ {
+ while (i < enums.length)
+ {
+ Enumeration enum = enums[i];
+ if ((enum != null) && enum.hasMoreElements())
+ {
+ return true;
+ }
+
+ i++;
+ }
+
+ return false;
+ }
+ /**
+ * Answers the next element in this Enumeration.
+ *
+ * @return the next element in this Enumeration
+ *
+ * @exception NoSuchElementException when there are no more elements
+ *
+ * @see #hasMoreElements
+ */
+ public Object nextElement()
+ {
+ while (i < enums.length)
+ {
+ try
+ {
+ Enumeration enum = enums[i];
+ if (enum != null)
+ {
+ return enum.nextElement();
+ }
+ }
+ catch (NoSuchElementException e)
+ {
+ }
+ i++;
+ }
+
+ throw new NoSuchElementException();
+ }
+ };
+ }
+
+ /**
+ * Indicates whether the argument permission is implied
+ * by the permissions contained in the receiver.
+ *
+ * @return boolean
+ * <code>true</code> if the argument permission
+ * is implied by the permissions in the receiver,
+ * and <code>false</code> if it is not.
+ * @param permission java.security.Permission
+ * the permission to check
+ */
+ public boolean implies(Permission permission)
+ {
+ return ((assigned != null) && assigned.implies(permission)) ||
+ ((implied != null) && implied.implies(permission));
+ }
+}
+
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleContext.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleContext.java
new file mode 100644
index 000000000..78cedd6f4
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleContext.java
@@ -0,0 +1,1629 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.io.File;
+import java.io.InputStream;
+import java.security.*;
+import java.util.*;
+import org.eclipse.osgi.framework.adaptor.BundleClassLoader;
+import org.eclipse.osgi.framework.debug.Debug;
+import org.eclipse.osgi.framework.eventmgr.EventListeners;
+import org.eclipse.osgi.framework.eventmgr.EventSource;
+import org.osgi.framework.*;
+
+/**
+ * Bundle's execution context.
+ *
+ * This object is given out to bundles and wraps the internal
+ * BundleContext object. It is destroyed when a bundle is stopped.
+ */
+
+public class BundleContext implements org.osgi.framework.BundleContext, EventSource {
+ /** Bundle object this context is associated with. */
+ protected BundleHost bundle;
+
+ /** Internal framework object. */
+ protected Framework framework;
+
+ /** Services that bundle has used. Key is ServiceReference,
+ Value is ServiceUse */
+ protected Hashtable servicesInUse;
+
+ /** Listener list for bundle's BundleListeners */
+ protected EventListeners bundleEvent;
+
+ /** Listener list for bundle's SynchronousBundleListeners */
+ protected EventListeners bundleEventSync;
+
+ /** Listener list for bundle's ServiceListeners */
+ protected EventListeners serviceEvent;
+
+ /** Listener list for bundle's FrameworkListeners */
+ protected EventListeners frameworkEvent;
+
+ /** The current instantiation of the activator. */
+ protected BundleActivator activator;
+
+ /** The current instantiation of fragment activators */
+ protected BundleActivator[] fragmentActivators;
+
+ /** private object for locking */
+ protected Object contextLock = new Object();
+
+ /**
+ * Construct a BundleContext which wrappers the framework for a
+ * bundle
+ *
+ * @param bundle The bundle we are wrapping.
+ */
+ protected BundleContext(BundleHost bundle)
+ {
+ this.bundle = bundle;
+ framework = bundle.framework;
+ bundleEvent = null;
+ bundleEventSync = null;
+ serviceEvent = null;
+ frameworkEvent = null;
+ servicesInUse = null;
+ activator = null;
+ fragmentActivators = null;
+ }
+
+ /**
+ * Destroy the wrapper. This is called when the bundle is stopped.
+ *
+ */
+ protected void close()
+ {
+ bundle = null; /* invalidate context */
+
+ if (serviceEvent != null)
+ {
+ framework.serviceEvent.removeListener(this);
+ serviceEvent = null;
+ }
+ if (frameworkEvent != null)
+ {
+ framework.frameworkEvent.removeListener(this);
+ frameworkEvent = null;
+ }
+ if (bundleEvent != null)
+ {
+ framework.bundleEvent.removeListener(this);
+ bundleEvent = null;
+ }
+ if (bundleEventSync != null) {
+ framework.bundleEventSync.removeListener(this);
+ bundleEventSync = null;
+ }
+
+ /* service's registered by the bundle, if any, are unregistered. */
+
+ Vector registeredServices = null;
+ ServiceReference[] publishedReferences = null;
+ int regSize=0;
+ synchronized (framework.serviceRegistry) {
+ registeredServices = framework.serviceRegistry.lookupServiceReferences(this);
+ if (registeredServices != null){
+ regSize = registeredServices.size();
+ }
+
+ if (regSize > 0) {
+ if (Debug.DEBUG && Debug.DEBUG_SERVICES) {
+ Debug.println("Unregistering services");
+ }
+
+ publishedReferences = new ServiceReference[regSize];
+ registeredServices.copyInto(publishedReferences);
+ }
+ }
+
+ for (int i = 0; i < regSize; i++) {
+ try {
+ publishedReferences[i].registration.unregister();
+ } catch (IllegalStateException e) {
+ /* already unregistered */
+ }
+ }
+
+ registeredServices = null;
+
+ /* service's used by the bundle, if any, are released. */
+ if (servicesInUse != null)
+ {
+ int usedSize;
+ ServiceReference[] usedRefs = null;
+
+ synchronized (servicesInUse)
+ {
+ usedSize = servicesInUse.size();
+
+ if (usedSize > 0)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_SERVICES)
+ {
+ Debug.println("Releasing services");
+ }
+
+ usedRefs = new ServiceReference[usedSize];
+
+ Enumeration enum = servicesInUse.keys();
+ for (int i = 0; i < usedSize; i++)
+ {
+ usedRefs[i] = (ServiceReference)enum.nextElement();
+ }
+ }
+ }
+
+ for (int i = 0; i < usedSize; i++)
+ {
+ usedRefs[i].registration.releaseService(this);
+ }
+
+ servicesInUse = null;
+ }
+ }
+
+ /**
+ * Retrieve the value of the named environment property.
+ *
+ * @param key The name of the requested property.
+ * @return The value of the requested property, or <code>null</code> if
+ * the property is undefined.
+ */
+ public String getProperty(String key)
+ {
+ SecurityManager sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ sm.checkPropertyAccess(key);
+ }
+
+ return(framework.getProperty(key));
+ }
+
+ /**
+ * Retrieve the Bundle object for the context bundle.
+ *
+ * @return The context bundle's Bundle object.
+ */
+ public org.osgi.framework.Bundle getBundle()
+ {
+ checkValid();
+
+ return(bundle);
+ }
+
+ /**
+ * Install a bundle from a location.
+ *
+ * The bundle is obtained from the location
+ * parameter as interpreted by the framework
+ * in an implementation dependent way. Typically, location
+ * will most likely be a URL.
+ *
+ * @param location The location identifier of the bundle to install.
+ * @return The Bundle object of the installed bundle.
+ */
+ public org.osgi.framework.Bundle installBundle(String location) throws BundleException
+ {
+
+ framework.checkAdminPermission();
+
+ checkValid();
+ // TODO: check if we only want to use only one type of protocal to install. Maybe inquire the FrameworkAdaptor?
+
+ return framework.installBundle(location);
+
+ }
+
+ /**
+ * Install a bundle from an InputStream.
+ *
+ * <p>This method performs all the steps listed in
+ * {@link #installBundle(java.lang.String)}, except the
+ * bundle's content will be read from the InputStream.
+ * The location identifier specified will be used
+ * as the identity of the bundle.
+ *
+ * @param location The location identifier of the bundle to install.
+ * @param in The InputStream from which the bundle will be read.
+ * @return The Bundle of the installed bundle.
+ */
+ public org.osgi.framework.Bundle installBundle(String location, InputStream in) throws BundleException
+ {
+ framework.checkAdminPermission();
+
+ checkValid();
+
+ return framework.installBundle(location, in);
+ }
+
+ /**
+ * Retrieve the bundle that has the given unique identifier.
+ *
+ * @param id The identifier of the bundle to retrieve.
+ * @return A Bundle object, or <code>null</code>
+ * if the identifier doesn't match any installed bundle.
+ */
+ public org.osgi.framework.Bundle getBundle(long id)
+ {
+ return(framework.getBundle(id));
+ }
+
+ /**
+ * Retrieve the bundle that has the given location.
+ *
+ * @param location The location string of the bundle to retrieve.
+ * @return A Bundle object, or <code>null</code>
+ * if the location doesn't match any installed bundle.
+ */
+ public Bundle getBundleByLocation(String location)
+ {
+ return(framework.getBundleByLocation(location));
+ }
+
+ /**
+ * Retrieve a list of all installed bundles.
+ * The list is valid at the time
+ * of the call to getBundles, but the framework is a very dynamic
+ * environment and bundles can be installed or uninstalled at anytime.
+ *
+ * @return An array of {@link Bundle} objects, one
+ * object per installed bundle.
+ */
+ public org.osgi.framework.Bundle[] getBundles()
+ {
+ BundleRepository bundles = framework.getBundles();
+
+ synchronized (bundles)
+ {
+ List allBundles = bundles.getBundles();
+ int size = allBundles.size();
+
+ if (size == 0)
+ {
+ return(null);
+ }
+
+ Bundle[] bundlelist = new Bundle[size];
+
+ allBundles.toArray(bundlelist);
+
+ return(bundlelist);
+ }
+ }
+
+ /**
+ * Add a service listener with a filter.
+ * {@link ServiceListener}s are notified when a service has a lifecycle
+ * state change.
+ * See {@link #getServiceReferences getServiceReferences}
+ * for a description of the filter syntax.
+ * The listener is added to the context bundle's list of listeners.
+ * See {@link #getBundle() getBundle()}
+ * for a definition of context bundle.
+ *
+ * <p>The listener is called if the filter criteria is met.
+ * To filter based upon the class of the service, the filter
+ * should reference the "objectClass" property.
+ * If the filter paramater is <code>null</code>, all services
+ * are considered to match the filter.
+ * <p>If the Java runtime environment supports permissions, then additional
+ * filtering is done.
+ * {@link Bundle#hasPermission Bundle.hasPermission} is called for the
+ * bundle which defines the listener to validate that the listener has the
+ * {@link ServicePermission} permission to <code>"get"</code> the service
+ * using at least one of the named classes the service was registered under.
+ *
+ * @param listener The service listener to add.
+ * @param filter The filter criteria.
+ * @exception InvalidSyntaxException If the filter parameter contains
+ * an invalid filter string which cannot be parsed.
+ * @see ServiceEvent
+ * @see ServiceListener
+ * @exception java.lang.IllegalStateException
+ * If the context bundle {@link <a href="#context_valid">has stopped</a>}.
+ */
+ public void addServiceListener(ServiceListener listener, String filter)
+ throws InvalidSyntaxException
+ {
+ checkValid();
+
+ if (Debug.DEBUG && Debug.DEBUG_EVENTS)
+ {
+ String listenerName = listener.getClass().getName() + "@" + Integer.toHexString(listener.hashCode());
+ Debug.println("addServiceListener["+bundle+"]("+listenerName+", \""+filter+"\")");
+ }
+
+ ServiceListener filteredListener = (filter == null) ? listener :
+ new FilteredServiceListener(filter, listener);
+
+ synchronized (framework.serviceEvent)
+ {
+ if (serviceEvent == null)
+ {
+ serviceEvent = new EventListeners();
+ framework.serviceEvent.addListener(this, this);
+ }
+ else
+ {
+ serviceEvent.removeListener(listener);
+ }
+
+ serviceEvent.addListener(listener, filteredListener);
+ }
+ }
+
+ /**
+ * Add a service listener.
+ *
+ * <p>This method is the same as calling
+ * {@link #addServiceListener(ServiceListener, String)}
+ * with filter set to <code>null</code>.
+ *
+ * @see #addServiceListener(ServiceListener, String)
+ */
+ public void addServiceListener(ServiceListener listener)
+ {
+ try
+ {
+ addServiceListener(listener, null);
+ }
+ catch (InvalidSyntaxException e)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println("InvalidSyntaxException w/ null filter" + e.getMessage());
+ Debug.printStackTrace(e);
+ }
+ }
+ }
+
+ /**
+ * Remove a service listener.
+ * The listener is removed from the context bundle's list of listeners.
+ * See {@link #getBundle() getBundle()}
+ * for a definition of context bundle.
+ *
+ * <p>If this method is called with a listener which is not registered,
+ * then this method does nothing.
+ *
+ * @param listener The service listener to remove.
+ * @exception java.lang.IllegalStateException
+ * If the context bundle {@link <a href="#context_valid">has stopped</a>}.
+ */
+ public void removeServiceListener(ServiceListener listener)
+ {
+ checkValid();
+
+ if (Debug.DEBUG && Debug.DEBUG_SERVICES)
+ {
+ String listenerName = listener.getClass().getName() + "@" + Integer.toHexString(listener.hashCode());
+ Debug.println("removeServiceListener["+bundle+"]("+listenerName+")");
+ }
+
+ if (serviceEvent != null)
+ {
+ synchronized (framework.serviceEvent)
+ {
+ serviceEvent.removeListener(listener);
+ }
+ }
+ }
+
+ /**
+ * Add a bundle listener.
+ * {@link BundleListener}s are notified when a bundle has a lifecycle
+ * state change.
+ * The listener is added to the context bundle's list of listeners.
+ * See {@link #getBundle() getBundle()}
+ * for a definition of context bundle.
+ *
+ * @param listener The bundle listener to add.
+ * @exception java.lang.IllegalStateException
+ * If the context bundle {@link <a href="#context_valid">has stopped</a>}.
+ * @see BundleEvent
+ * @see BundleListener
+ */
+ public void addBundleListener(BundleListener listener)
+ {
+ checkValid();
+
+ if (Debug.DEBUG && Debug.DEBUG_EVENTS)
+ {
+ String listenerName = listener.getClass().getName() + "@" + Integer.toHexString(listener.hashCode());
+ Debug.println("addBundleListener["+bundle+"]("+listenerName+")");
+ }
+
+ if (listener instanceof SynchronousBundleListener)
+ {
+ framework.checkAdminPermission();
+
+ synchronized (framework.bundleEventSync)
+ {
+ if (bundleEventSync == null)
+ {
+ bundleEventSync = new EventListeners();
+ framework.bundleEventSync.addListener(this, this);
+ }
+ else
+ {
+ bundleEventSync.removeListener(listener);
+ }
+
+ bundleEventSync.addListener(listener, listener);
+ }
+ }
+ else
+ {
+ synchronized (framework.bundleEvent)
+ {
+ if (bundleEvent == null)
+ {
+ bundleEvent = new EventListeners();
+ framework.bundleEvent.addListener(this, this);
+ }
+ else
+ {
+ bundleEvent.removeListener(listener);
+ }
+
+ bundleEvent.addListener(listener, listener);
+ }
+ }
+ }
+
+ /**
+ * Remove a bundle listener.
+ * The listener is removed from the context bundle's list of listeners.
+ * See {@link #getBundle() getBundle()}
+ * for a definition of context bundle.
+ *
+ * <p>If this method is called with a listener which is not registered,
+ * then this method does nothing.
+ *
+ * @param listener The bundle listener to remove.
+ * @exception java.lang.IllegalStateException
+ * If the context bundle {@link <a href="#context_valid">has stopped</a>}.
+ */
+ public void removeBundleListener(BundleListener listener)
+ {
+ checkValid();
+
+ if (Debug.DEBUG && Debug.DEBUG_EVENTS)
+ {
+ String listenerName = listener.getClass().getName() + "@" + Integer.toHexString(listener.hashCode());
+ Debug.println("removeBundleListener["+bundle+"]("+listenerName+")");
+ }
+
+ if (listener instanceof SynchronousBundleListener)
+ {
+ framework.checkAdminPermission();
+
+ if (bundleEventSync != null)
+ {
+ synchronized (framework.bundleEventSync)
+ {
+ bundleEventSync.removeListener(listener);
+ }
+ }
+ }
+ else
+ {
+ if (bundleEvent != null)
+ {
+ synchronized (framework.bundleEvent)
+ {
+ bundleEvent.removeListener(listener);
+ }
+ }
+ }
+ }
+
+ /**
+ * Add a general framework listener.
+ * {@link FrameworkListener}s are notified of general framework events.
+ * The listener is added to the context bundle's list of listeners.
+ * See {@link #getBundle() getBundle()}
+ * for a definition of context bundle.
+ *
+ * @param listener The framework listener to add.
+ * @exception java.lang.IllegalStateException
+ * If the context bundle {@link <a href="#context_valid">has stopped</a>}.
+ * @see FrameworkEvent
+ * @see FrameworkListener
+ */
+ public void addFrameworkListener(FrameworkListener listener)
+ {
+ checkValid();
+
+ if (Debug.DEBUG && Debug.DEBUG_EVENTS)
+ {
+ String listenerName = listener.getClass().getName() + "@" + Integer.toHexString(listener.hashCode());
+ Debug.println("addFrameworkListener["+bundle+"]("+listenerName+")");
+ }
+
+ synchronized (framework.frameworkEvent)
+ {
+ if (frameworkEvent == null)
+ {
+ frameworkEvent = new EventListeners();
+ framework.frameworkEvent.addListener(this, this);
+ }
+ else
+ {
+ frameworkEvent.removeListener(listener);
+ }
+
+ frameworkEvent.addListener(listener, listener);
+ }
+ }
+
+ /**
+ * Remove a framework listener.
+ * The listener is removed from the context bundle's list of listeners.
+ * See {@link #getBundle() getBundle()}
+ * for a definition of context bundle.
+ *
+ * <p>If this method is called with a listener which is not registered,
+ * then this method does nothing.
+ *
+ * @param listener The framework listener to remove.
+ * @exception java.lang.IllegalStateException
+ * If the context bundle {@link <a href="#context_valid">has stopped</a>}.
+ */
+ public void removeFrameworkListener(FrameworkListener listener)
+ {
+ checkValid();
+
+ if (Debug.DEBUG && Debug.DEBUG_EVENTS)
+ {
+ String listenerName = listener.getClass().getName() + "@" + Integer.toHexString(listener.hashCode());
+ Debug.println("removeFrameworkListener["+bundle+"]("+listenerName+")");
+ }
+
+ if (frameworkEvent != null)
+ {
+ synchronized (framework.frameworkEvent)
+ {
+ frameworkEvent.removeListener(listener);
+ }
+ }
+ }
+
+ /**
+ * Register a service with multiple names.
+ * This method registers the given service object with the given properties
+ * under the given class names.
+ * A {@link ServiceRegistration} object is returned.
+ * The {@link ServiceRegistration} object is for the private use of the bundle
+ * registering the service and should not be shared with other bundles.
+ * The registering bundle is defined to be the context bundle.
+ * See {@link #getBundle()} for a definition of context bundle.
+ * Other bundles can locate the service by using either the
+ * {@link #getServiceReferences getServiceReferences} or
+ * {@link #getServiceReference getServiceReference} method.
+ *
+ * <p>A bundle can register a service object that implements the
+ * {@link ServiceFactory} interface to
+ * have more flexiblity in providing service objects to different
+ * bundles.
+ *
+ * <p>The following steps are followed to register a service:
+ * <ol>
+ * <li>If the service parameter is not a {@link ServiceFactory},
+ * an <code>IllegalArgumentException</code> is thrown if the
+ * service parameter is not an <code>instanceof</code>
+ * all the classes named.
+ * <li>The service is added to the framework's service registry
+ * and may now be used by other bundles.
+ * <li>A {@link ServiceEvent} of type {@link ServiceEvent#REGISTERED}
+ * is synchronously sent.
+ * <li>A {@link ServiceRegistration} object for this registration
+ * is returned.
+ * </ol>
+ *
+ * @param clazzes The class names under which the service can be located.
+ * The class names in this array will be stored in the service's
+ * properties under the key "objectClass".
+ * @param service The service object or a {@link ServiceFactory} object.
+ * @param properties The properties for this service.
+ * The keys in the properties object must all be Strings.
+ * Changes should not be made to this object after calling this method.
+ * To update the service's properties call the
+ * {@link ServiceRegistration#setProperties ServiceRegistration.setProperties}
+ * method.
+ * This parameter may be <code>null</code> if the service has no properties.
+ * @return A {@link ServiceRegistration} object for use by the bundle
+ * registering the service to update the
+ * service's properties or to unregister the service.
+ * @exception java.lang.IllegalArgumentException If one of the following is true:
+ * <ul>
+ * <li>The service parameter is null.
+ * <li>The service parameter is not a {@link ServiceFactory} and is not an
+ * <code>instanceof</code> all the named classes in the clazzes parameter.
+ * </ul>
+ * @exception java.lang.SecurityException If the caller does not have
+ * {@link ServicePermission} permission to "register" the service for
+ * all the named classes
+ * and the Java runtime environment supports permissions.
+ * @exception java.lang.IllegalStateException
+ * If the context bundle {@link <a href="#context_valid">has stopped</a>}.
+ * @see ServiceRegistration
+ * @see ServiceFactory
+ */
+ public org.osgi.framework.ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties)
+ {
+ checkValid();
+
+ if (service == null)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_SERVICES)
+ {
+ Debug.println("Service object is null");
+ }
+
+ throw new NullPointerException(Msg.formatter.getString("SERVICE_ARGUMENT_NULL_EXCEPTION"));
+ }
+
+ int size = clazzes.length;
+
+ if (size == 0)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_SERVICES)
+ {
+ Debug.println("Classes array is empty");
+ }
+
+ throw new IllegalArgumentException(Msg.formatter.getString("SERVICE_EMPTY_CLASS_LIST_EXCEPTION"));
+ }
+
+ /* copy the array so that changes to the original will not affect us. */
+ String[] copy = new String[clazzes.length];
+ for (int i = 0; i < clazzes.length; i++)
+ {
+ copy[i] = new String(clazzes[i].getBytes());
+ }
+ clazzes = copy;
+
+
+ /* check for ServicePermissions. */
+ framework.checkRegisterServicePermission(clazzes);
+
+ if (!(service instanceof ServiceFactory))
+ {
+ PackageAdmin packageAdmin = framework.packageAdmin;
+
+ for (int i = 0; i < size; i++)
+ {
+ Class clazz;
+
+ try
+ {
+ clazz = bundle.loadClass(clazzes[i],false);
+ }
+ catch (ClassNotFoundException e)
+ {
+ try
+ {
+ // TODO this code really never should be run. If the factory's classloader cannot
+ // see the required class (above) then it is not available. Looking in a global list of
+ // package exporters etc is not a good plan in the face of modules and multiple
+ // versions. Actually, it is unclear that we need to verify the pedigree of the service object
+ // at registration time.
+ // For now just put in a dummy classload call to reduce code impact.
+ clazz = Class.forName(clazzes[i]);
+// clazz = packageAdmin.loadClass(clazzes[i]);
+ }
+ catch (ClassNotFoundException ee)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_SERVICES)
+ {
+ Debug.println(clazzes[i] + " class not found");
+ }
+
+ throw new IllegalArgumentException(Msg.formatter.getString("SERVICE_CLASS_NOT_FOUND_EXCEPTION", clazzes[i]));
+ }
+ }
+
+ if (!clazz.isInstance(service))
+ {
+ if (Debug.DEBUG && Debug.DEBUG_SERVICES)
+ {
+ Debug.println("Service object is not an instanceof "+clazzes[i]);
+ }
+
+ throw new IllegalArgumentException(Msg.formatter.getString("SERVICE_NOT_INSTANCEOF_CLASS_EXCEPTION", clazzes[i]));
+ }
+ }
+ }
+
+ return(createServiceRegistration(clazzes, service, properties));
+ }
+
+ /**
+ * Create a new ServiceRegistration object. This method is used so that it may be overridden
+ * by a secure implementation.
+ *
+ * @param clazzes The class names under which the service can be located.
+ * @param service The service object or a {@link ServiceFactory} object.
+ * @param properties The properties for this service.
+ * @return A {@link ServiceRegistration} object for use by the bundle.
+ */
+ protected ServiceRegistration createServiceRegistration(String[] clazzes, Object service, Dictionary properties)
+ {
+ return(new ServiceRegistration(this, clazzes, service, properties));
+ }
+
+ /**
+ * Register a service with a single name.
+ * This method registers the given service object with the given properties
+ * under the given class name.
+ *
+ * <p>This method is otherwise identical to
+ * {@link #registerService(java.lang.String[], java.lang.Object, java.util.Dictionary)}
+ * and is provided as a convenience when the service parameter will only be registered
+ * under a single class name.
+ *
+ * @see #registerService(java.lang.String[], java.lang.Object, java.util.Dictionary)
+ */
+ public org.osgi.framework.ServiceRegistration registerService(String clazz, Object service, Dictionary properties)
+ {
+ String[] clazzes = new String[] { clazz };
+
+ return(registerService(clazzes, service, properties));
+ }
+
+ /**
+ * Returns a list of <tt>ServiceReference</tt> objects. This method returns a list of
+ * <tt>ServiceReference</tt> objects for services which implement and were registered under
+ * the specified class and match the specified filter criteria.
+ *
+ * <p>The list is valid at the time of the call to this method, however as the Framework is
+ * a very dynamic environment, services can be modified or unregistered at anytime.
+ *
+ * <p><tt>filter</tt> is used to select the registered service whose
+ * properties objects contain keys and values which satisfy the filter.
+ * See {@link Filter}for a description of the filter string syntax.
+ *
+ * <p>If <tt>filter</tt> is <tt>null</tt>, all registered services
+ * are considered to match the filter.
+ * <p>If <tt>filter</tt> cannot be parsed, an {@link InvalidSyntaxException}will
+ * be thrown with a human readable message where the filter became unparsable.
+ *
+ * <p>The following steps are required to select a service:
+ * <ol>
+ * <li>If the Java Runtime Environment supports permissions, the caller is checked for the
+ * <tt>ServicePermission</tt> to get the service with the specified class.
+ * If the caller does not have the correct permission, <tt>null</tt> is returned.
+ * <li>If the filter string is not <tt>null</tt>, the filter string is
+ * parsed and the set of registered services which satisfy the filter is
+ * produced.
+ * If the filter string is <tt>null</tt>, then all registered services
+ * are considered to satisfy the filter.
+ * <li>If <code>clazz</code> is not <tt>null</tt>, the set is further reduced to
+ * those services which are an <tt>instanceof</tt> and were registered under the specified class.
+ * The complete list of classes of which a service is an instance and which
+ * were specified when the service was registered is available from the
+ * service's {@link Constants#OBJECTCLASS}property.
+ * <li>An array of <tt>ServiceReference</tt> to the selected services is returned.
+ * </ol>
+ *
+ * @param clazz The class name with which the service was registered, or
+ * <tt>null</tt> for all services.
+ * @param filter The filter criteria.
+ * @return An array of <tt>ServiceReference</tt> objects, or
+ * <tt>null</tt> if no services are registered which satisfy the search.
+ * @exception InvalidSyntaxException If <tt>filter</tt> contains
+ * an invalid filter string which cannot be parsed.
+ */
+ public org.osgi.framework.ServiceReference[] getServiceReferences(String clazz, String filter)
+ throws InvalidSyntaxException
+ {
+ checkValid();
+
+ if (Debug.DEBUG && Debug.DEBUG_SERVICES)
+ {
+ Debug.println("getServiceReferences("+clazz+", \""+filter+"\")");
+ }
+
+ return(framework.getServiceReferences(clazz, filter));
+ }
+
+ /**
+ * Get a service reference.
+ * Retrieves a {@link ServiceReference} for a service
+ * which implements the named class.
+ *
+ * <p>This reference is valid at the time
+ * of the call to this method, but since the framework is a very dynamic
+ * environment, services can be modified or unregistered at anytime.
+ *
+ * <p>This method is provided as a convenience for when the caller is
+ * interested in any service which implements a named class. This method is
+ * the same as calling {@link #getServiceReferences getServiceReferences}
+ * with a <code>null</code> filter string but only a single {@link ServiceReference}
+ * is returned.
+ *
+ * @param clazz The class name which the service must implement.
+ * @return A {@link ServiceReference} object, or <code>null</code>
+ * if no services are registered which implement the named class.
+ * @see #getServiceReferences
+ */
+ public org.osgi.framework.ServiceReference getServiceReference(String clazz)
+ {
+ checkValid();
+
+ if (Debug.DEBUG && Debug.DEBUG_SERVICES)
+ {
+ Debug.println("getServiceReference("+clazz+")");
+ }
+
+ try
+ {
+ ServiceReference[] references = framework.getServiceReferences(clazz, null);
+
+ if (references != null)
+ {
+ int index = 0;
+
+ int length = references.length;
+
+ if (length > 1) /* if more than one service, select highest ranking */
+ {
+ int rankings[] = new int[length];
+ int count = 0;
+ int maxRanking = Integer.MIN_VALUE;
+
+ for (int i = 0 ; i < length; i++)
+ {
+ int ranking = references[i].getRanking();
+
+ rankings[i] = ranking;
+
+ if (ranking > maxRanking)
+ {
+ index = i;
+ maxRanking = ranking;
+ count = 1;
+ }
+ else
+ {
+ if (ranking == maxRanking)
+ {
+ count++;
+ }
+ }
+ }
+
+ if (count > 1) /* if still more than one service, select lowest id */
+ {
+ long minId = Long.MAX_VALUE;
+
+ for (int i = 0 ; i < length; i++)
+ {
+ if (rankings[i] == maxRanking)
+ {
+ long id = references[i].getId();
+
+ if (id < minId)
+ {
+ index = i;
+ minId = id;
+ }
+ }
+ }
+ }
+ }
+
+ return(references[index]);
+ }
+ }
+ catch (InvalidSyntaxException e)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println("InvalidSyntaxException w/ null filter" + e.getMessage());
+ Debug.printStackTrace(e);
+ }
+ }
+
+ return(null);
+ }
+
+ /**
+ * Get a service's service object.
+ * Retrieves the service object for a service.
+ * A bundle's use of a service is tracked by a
+ * use count. Each time a service's service object is returned by
+ * {@link #getService}, the context bundle's use count for the service
+ * is incremented by one. Each time the service is release by
+ * {@link #ungetService}, the context bundle's use count
+ * for the service is decremented by one.
+ * When a bundle's use count for a service
+ * drops to zero, the bundle should no longer use the service.
+ * See {@link #getBundle()} for a definition of context bundle.
+ *
+ * <p>This method will always return <code>null</code> when the
+ * service associated with this reference has been unregistered.
+ *
+ * <p>The following steps are followed to get the service object:
+ * <ol>
+ * <li>If the service has been unregistered,
+ * <code>null</code> is returned.
+ * <li>The context bundle's use count for this service is incremented by one.
+ * <li>If the context bundle's use count for the service is now one and
+ * the service was registered with a {@link ServiceFactory},
+ * the {@link ServiceFactory#getService ServiceFactory.getService} method
+ * is called to create a service object for the context bundle.
+ * This service object is cached by the framework.
+ * While the context bundle's use count for the service is greater than zero,
+ * subsequent calls to get the services's service object for the context bundle
+ * will return the cached service object.
+ * <br>If the service object returned by the {@link ServiceFactory}
+ * is not an <code>instanceof</code>
+ * all the classes named when the service was registered or
+ * the {@link ServiceFactory} throws an exception,
+ * <code>null</code> is returned and a
+ * {@link FrameworkEvent} of type {@link FrameworkEvent#ERROR} is broadcast.
+ * <li>The service object for the service is returned.
+ * </ol>
+ *
+ * @param reference A reference to the service whose service object is desired.
+ * @return A service object for the service associated with this
+ * reference, or <code>null</code> if the service is not registered.
+ * @exception java.lang.SecurityException If the caller does not have
+ * {@link ServicePermission} permission to "get" the service
+ * using at least one of the named classes the service was registered under
+ * and the Java runtime environment supports permissions.
+ * @exception java.lang.IllegalStateException
+ * If the context bundle {@link <a href="#context_valid">has stopped</a>}.
+ * @see #ungetService
+ * @see ServiceFactory
+ */
+ public Object getService(org.osgi.framework.ServiceReference reference)
+ {
+ checkValid();
+
+ if (servicesInUse == null)
+ {
+ synchronized (contextLock)
+ {
+ if (servicesInUse == null)
+ {
+ servicesInUse = new Hashtable(17);
+ }
+ }
+ }
+
+ ServiceRegistration registration = ((ServiceReference)reference).registration;
+
+ framework.checkGetServicePermission(registration.clazzes);
+
+ return registration.getService(BundleContext.this);
+ }
+
+ /**
+ * Unget a service's service object.
+ * Releases the service object for a service.
+ * If the context bundle's use count for the service is zero, this method
+ * returns <code>false</code>. Otherwise, the context bundle's use count for the
+ * service is decremented by one.
+ * See {@link #getBundle()} for a definition of context bundle.
+ *
+ * <p>The service's service object
+ * should no longer be used and all references to it should be destroyed
+ * when a bundle's use count for the service
+ * drops to zero.
+ *
+ * <p>The following steps are followed to unget the service object:
+ * <ol>
+ * <li>If the context bundle's use count for the service is zero or
+ * the service has been unregistered,
+ * <code>false</code> is returned.
+ * <li>The context bundle's use count for this service is decremented by one.
+ * <li>If the context bundle's use count for the service is now zero and
+ * the service was registered with a {@link ServiceFactory},
+ * the {@link ServiceFactory#ungetService ServiceFactory.ungetService} method
+ * is called to release the service object for the context bundle.
+ * <li><code>true</code> is returned.
+ * </ol>
+ *
+ * @param reference A reference to the service to be released.
+ * @return <code>false</code> if the context bundle's use count for the service
+ * is zero or if the service has been unregistered,
+ * otherwise <code>true</code>.
+ * @exception java.lang.IllegalStateException
+ * If the context bundle {@link <a href="#context_valid">has stopped</a>}.
+ * @see #getService
+ * @see ServiceFactory
+ */
+ public boolean ungetService(org.osgi.framework.ServiceReference reference)
+ {
+ checkValid();
+
+ ServiceRegistration registration = ((ServiceReference)reference).registration;
+
+ return registration.ungetService(BundleContext.this);
+ }
+
+ /**
+ * Creates a <code>File</code> object for a file in the
+ * persistent storage area provided for the bundle by the framework.
+ * If the adaptor does not have file system support, this method will
+ * return <code>null</code>.
+ *
+ * <p>A <code>File</code> object for the base directory of the
+ * persistent storage area provided for the context bundle by the framework
+ * can be obtained by calling this method with the empty string ("")
+ * as the parameter.
+ * See {@link #getBundle()} for a definition of context bundle.
+ *
+ * <p>If the Java runtime environment supports permissions,
+ * the framework the will ensure that the bundle has
+ * <code>java.io.FilePermission</code> with actions
+ * "read","write","execute","delete" for all files (recursively) in the
+ * persistent storage area provided for the context bundle by the framework.
+ *
+ * @param filename A relative name to the file to be accessed.
+ * @return A <code>File</code> object that represents the requested file or
+ * <code>null</code> if the adaptor does not have file system support.
+ * @exception java.lang.IllegalStateException
+ * If the context bundle {@link <a href="#context_valid">has stopped</a>}.
+ */
+ public File getDataFile(String filename)
+ {
+ checkValid();
+
+ return(framework.getDataFile(bundle, filename));
+ }
+
+
+ /**
+ * Call bundle's BundleActivator.start()
+ * This method is called by Bundle.startWorker to start the bundle.
+ *
+ * @exception org.osgi.framework.BundleException if
+ * the bundle has a class that implements the BundleActivator interface,
+ * but Framework couldn't instantiate it, or the BundleActivator.start()
+ * method failed
+ */
+ protected void start() throws BundleException
+ {
+ activator = bundle.loadBundleActivator();
+
+ if (activator != null)
+ {
+ try {
+ startActivator(activator);
+ }
+ catch (BundleException be) {
+ activator = null;
+ throw be;
+ }
+ }
+
+ // now start all attached fragments.
+ if (bundle.fragments != null) {
+ synchronized (bundle.fragments)
+ {
+ fragmentActivators = new BundleActivator[bundle.fragments.size()];
+ for (int i = 0; i < fragmentActivators.length; i++)
+ {
+ BundleFragment fragment = (BundleFragment) bundle.fragments.elementAt(i);
+ try {
+ fragmentActivators[i] = fragment.loadBundleActivator();
+ }
+ catch (Throwable t) {
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR,fragment,t);
+ }
+ }
+ for (int i = 0; i < fragmentActivators.length; i++)
+ {
+ Bundle fragment = (Bundle) bundle.fragments.elementAt(i);
+ if (fragmentActivators[i] != null)
+ {
+ try {
+ // set the fragment state to STARTING
+ fragment.state = Bundle.STARTING;
+
+ // call the start() method on the fragment activator
+ startActivator(fragmentActivators[i]);
+
+ // set the fragment state to ACTIVE
+ fragment.state = Bundle.ACTIVE;
+ framework.publishBundleEvent(BundleEvent.STARTED, fragment);
+ }
+ catch (Throwable t) {
+ // set the fragment activator to null so that it will not get called during
+ // host stop.
+ fragmentActivators[i] = null;
+
+ // set the fragment state to resolved.
+ fragment.state = Bundle.RESOLVED;
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR,fragment,t);
+ }
+ }
+ else {
+ fragment.state = Bundle.ACTIVE;
+ framework.publishBundleEvent(BundleEvent.STARTED, fragment);
+ }
+ }
+ }
+ }
+
+ /* activator completed successfully. We must use this
+ same activator object when we stop this bundle. */
+ }
+
+ /**
+ * Calls the start method of a BundleActivator.
+ * @param bundleActivator that activator to start
+ */
+ protected void startActivator(final BundleActivator bundleActivator) throws BundleException {
+ try
+ {
+ AccessController.doPrivileged(new PrivilegedExceptionAction()
+ {
+ public Object run() throws Exception
+ {
+ if (bundleActivator != null)
+ {
+ /* Start the bundle synchronously */
+ bundleActivator.start(BundleContext.this);
+ }
+ return null;
+ }
+ });
+ }
+ catch (Throwable t)
+ {
+ if (t instanceof PrivilegedActionException)
+ {
+ t = ((PrivilegedActionException)t).getException();
+ }
+
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.printStackTrace(t);
+ }
+
+ String clazz = null;
+ clazz = bundleActivator.getClass().getName();
+
+ throw new BundleException(Msg.formatter.getString("BUNDLE_ACTIVATOR_EXCEPTION", clazz, "start"), t);
+ }
+
+ }
+
+ /**
+ * This method is called when a fragment attaches to an already active
+ * host.
+ * @param fragment The fragment bundle to start.
+ */
+ protected void startFragment(BundleFragment fragment) {
+ BundleActivator fragmentActivator=null;
+
+ try {
+ fragmentActivator = fragment.loadBundleActivator();
+ }
+ catch (Throwable t) {
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR,fragment,t);
+ }
+
+ if (fragmentActivator != null) {
+ try
+ {
+ // set the fragment state to STARTING
+ fragment.state = Bundle.STARTING;
+ startActivator(fragmentActivator);
+
+ if (fragmentActivators != null)
+ {
+ BundleActivator[] newFragmentActivators = new BundleActivator[fragmentActivators.length + 1];
+ System.arraycopy(fragmentActivators, 0, newFragmentActivators, 0, fragmentActivators.length);
+ newFragmentActivators[newFragmentActivators.length - 1] = fragmentActivator;
+ fragmentActivators = newFragmentActivators;
+ }
+ else
+ {
+ fragmentActivators = new BundleActivator[] { fragmentActivator };
+ }
+
+ // set the fragment state to ACTIVE
+ fragment.state = Bundle.ACTIVE;
+ framework.publishBundleEvent(BundleEvent.STARTED, fragment);
+ } catch (Throwable t)
+ {
+ // set the fragment state to resolved.
+ fragment.state = Bundle.RESOLVED;
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR, fragment, t);
+ }
+ }
+ else{
+ fragment.state = Bundle.ACTIVE;
+ framework.publishBundleEvent(BundleEvent.STARTED, fragment);
+ }
+ }
+
+ /**
+ * Call bundle's BundleActivator.stop()
+ * This method is called by Bundle.stopWorker to stop the bundle.
+ *
+ * @exception org.osgi.framework.BundleException if
+ * the bundle has a class that implements the BundleActivator interface,
+ * and the BundleActivator.stop() method failed
+ */
+ protected void stop() throws BundleException
+ {
+ try
+ {
+ AccessController.doPrivileged(new PrivilegedExceptionAction()
+ {
+ public Object run() throws Exception
+ {
+ // first suspend all attached fragments;
+ if (fragmentActivators != null) {
+ for (int i=fragmentActivators.length-1; i>=0; i--) {
+ if (fragmentActivators[i] != null) {
+ Bundle fragment = (Bundle) bundle.fragments.elementAt(i);
+
+ fragment.state = Bundle.STOPPING;
+
+ try {
+ fragmentActivators[i].stop(BundleContext.this);
+ }
+ catch (Throwable t) {
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR,fragment,t);
+ }
+ finally {
+ fragment.state = Bundle.RESOLVED;
+ framework.publishBundleEvent(BundleEvent.STOPPED, fragment);
+ }
+
+ }
+ }
+ }
+ if (activator != null)
+ {
+ /* Stop the bundle synchronously */
+ activator.stop(BundleContext.this);
+ }
+ return null;
+ }
+ });
+ }
+ catch (Throwable t)
+ {
+ if (t instanceof PrivilegedActionException)
+ {
+ t = ((PrivilegedActionException)t).getException();
+ }
+
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.printStackTrace(t);
+ }
+
+ String clazz = (activator == null) ? "" : activator.getClass().getName();
+
+ throw new BundleException(Msg.formatter.getString("BUNDLE_ACTIVATOR_EXCEPTION", clazz, "stop"), t);
+ }
+ finally
+ {
+ activator = null;
+ fragmentActivators = null;
+ }
+ }
+
+ /**
+ * Provides a list of {@link ServiceReference}s for the services
+ * registered by this bundle
+ * or <code>null</code> if the bundle has no registered
+ * services.
+ *
+ * <p>The list is valid at the time
+ * of the call to this method, but the framework is a very dynamic
+ * environment and services can be modified or unregistered at anytime.
+ *
+ * @return An array of {@link ServiceReference} or <code>null</code>.
+ * @exception java.lang.IllegalStateException If the
+ * bundle has been uninstalled.
+ * @see ServiceRegistration
+ * @see ServiceReference
+ */
+ protected ServiceReference[] getRegisteredServices() {
+ ServiceReference[] references = null;
+
+ synchronized (framework.serviceRegistry) {
+ Vector services = framework.serviceRegistry.lookupServiceReferences(this);
+ if (services == null) {
+ return null;
+ }
+
+ for (int i = services.size()-1; i >= 0; i--) {
+ ServiceReference ref = (ServiceReference) services.elementAt(i);
+ String[] classes = ref.getClasses();
+ try { /* test for permission to the classes */
+ framework.checkGetServicePermission(classes);
+ } catch (SecurityException se) {
+ services.removeElementAt(i);
+ }
+ }
+
+ if (services.size() > 0) {
+ references = new ServiceReference[services.size()];
+ services.toArray(references);
+ }
+ }
+ return (references);
+
+ }
+
+ /**
+ * Provides a list of {@link ServiceReference}s for the
+ * services this bundle is using,
+ * or <code>null</code> if the bundle is not using any services.
+ * A bundle is considered to be using a service if the bundle's
+ * use count for the service is greater than zero.
+ *
+ * <p>The list is valid at the time
+ * of the call to this method, but the framework is a very dynamic
+ * environment and services can be modified or unregistered at anytime.
+ *
+ * @return An array of {@link ServiceReference} or <code>null</code>.
+ * @exception java.lang.IllegalStateException If the
+ * bundle has been uninstalled.
+ * @see ServiceReference
+ */
+ protected ServiceReference[] getServicesInUse()
+ {
+ if (servicesInUse == null)
+ {
+ return(null);
+ }
+
+ synchronized (servicesInUse)
+ {
+ int size = servicesInUse.size();
+
+ if (size == 0)
+ {
+ return(null);
+ }
+
+ ServiceReference[] references = new ServiceReference[size];
+ int refcount = 0;
+
+ Enumeration enum = servicesInUse.keys();
+
+ for (int i = 0; i < size; i++)
+ {
+ ServiceReference reference = (ServiceReference)enum.nextElement();
+
+ try
+ {
+ framework.checkGetServicePermission(reference.registration.clazzes);
+ }
+ catch (SecurityException se)
+ {
+ continue;
+ }
+
+ references[refcount] = reference;
+ refcount++;
+ }
+
+ if (refcount < size)
+ {
+ if (refcount == 0)
+ {
+ return(null);
+ }
+
+ ServiceReference[] refs = references;
+ references = new ServiceReference[refcount];
+
+ System.arraycopy(refs, 0, references, 0, refcount);
+ }
+
+ return(references);
+ }
+ }
+
+ /**
+ * Bottom level event dispatcher for the BundleContext.
+ *
+ * @param originalListener listener object registered under.
+ * @param l listener to call (may be filtered).
+ * @param action Event class type
+ * @param object Event object
+ */
+ public void dispatchEvent(Object originalListener, Object l, int action, Object object)
+ {
+ // save the bundle ref to a local variable
+ // to avoid interference from another thread closing this context
+ Bundle tmpBundle = bundle;
+ try
+ {
+ if (tmpBundle != null) /* if context still valid */
+ {
+ switch (action)
+ {
+ case Framework.BUNDLEEVENT:
+ case Framework.BUNDLEEVENTSYNC:
+ {
+ BundleListener listener = (BundleListener) l;
+
+ if (Debug.DEBUG && Debug.DEBUG_EVENTS)
+ {
+ String listenerName = listener.getClass().getName() + "@" + Integer.toHexString(listener.hashCode());
+ Debug.println("dispatchBundleEvent["+tmpBundle+"]("+listenerName+")");
+ }
+
+ listener.bundleChanged((BundleEvent)object);
+ break;
+ }
+
+ case Framework.SERVICEEVENT:
+ {
+ ServiceEvent event = (ServiceEvent) object;
+
+ if (hasListenServicePermission(event))
+ {
+ ServiceListener listener = (ServiceListener) l;
+
+ if (Debug.DEBUG && Debug.DEBUG_EVENTS)
+ {
+ String listenerName = listener.getClass().getName() + "@" + Integer.toHexString(listener.hashCode());
+ Debug.println("dispatchServiceEvent["+tmpBundle+"]("+listenerName+")");
+ }
+
+ listener.serviceChanged(event);
+ }
+
+ break;
+ }
+
+ case Framework.FRAMEWORKEVENT:
+ {
+ FrameworkListener listener = (FrameworkListener) l;
+
+ if (Debug.DEBUG && Debug.DEBUG_EVENTS)
+ {
+ String listenerName = listener.getClass().getName() + "@" + Integer.toHexString(listener.hashCode());
+ Debug.println("dispatchFrameworkEvent["+tmpBundle+"]("+listenerName+")");
+ }
+
+ listener.frameworkEvent((FrameworkEvent)object);
+ break;
+ }
+ }
+ }
+ }
+ catch (Throwable t)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println("Exception in bottom level event dispatcher: " + t.getMessage());
+ Debug.printStackTrace(t);
+ }
+
+ publisherror:
+ {
+ if (action == Framework.FRAMEWORKEVENT)
+ {
+ FrameworkEvent event = (FrameworkEvent)object;
+ if (event.getType() == FrameworkEvent.ERROR)
+ {
+ break publisherror; // avoid infinite loop
+ }
+ }
+
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR, tmpBundle, t);
+ }
+ }
+ }
+
+ /**
+ * Check for permission to listen to a service.
+ */
+ protected boolean hasListenServicePermission(ServiceEvent event)
+ {
+ ProtectionDomain domain = bundle.getProtectionDomain();
+
+ if (domain != null)
+ {
+ ServiceReference reference = (ServiceReference)event.getServiceReference();
+
+ String[] names = reference.registration.clazzes;
+
+ int len = names.length;
+
+ for (int i = 0; i < len; i++)
+ {
+ if (domain.implies(new ServicePermission(names[i], ServicePermission.GET)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return(true);
+ }
+
+ /**
+ * Construct a Filter object. This filter object may be used
+ * to match a ServiceReference or a Dictionary.
+ * See Filter
+ * for a description of the filter string syntax.
+ *
+ * @param filter The filter string.
+ * @return A Filter object encapsulating the filter string.
+ * @exception InvalidSyntaxException If the filter parameter contains
+ * an invalid filter string which cannot be parsed.
+ */
+ public org.osgi.framework.Filter createFilter(String filter) throws InvalidSyntaxException
+ {
+ checkValid();
+
+ return(new Filter(filter));
+ }
+
+ /**
+ * This method checks that the context is still valid. If the context is
+ * no longer valid, an IllegalStateException is thrown.
+ *
+ * @exception java.lang.IllegalStateException
+ * If the context bundle has stopped.
+ */
+ protected void checkValid()
+ {
+ if (bundle == null)
+ {
+ throw new IllegalStateException(Msg.formatter.getString("BUNDLE_CONTEXT_INVALID_EXCEPTION"));
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.osgi.framework.BundleContext#getBundle(java.lang.String)
+ */
+ public org.osgi.framework.Bundle[] getBundles(String uniqueId) {
+ return framework.getBundleByUniqueId(uniqueId);
+ }
+
+ public org.osgi.framework.Bundle getBundle(String uniqueId) {
+ org.osgi.framework.Bundle[] bundles = getBundles(uniqueId);
+ return bundles == null ? null : bundles[0];
+ }
+
+ /* (non-Javadoc)
+ * @see org.osgi.framework.BundleContext#getBundleFor(java.lang.Object)
+ */
+ public org.osgi.framework.Bundle getBundleFor(Object object) {
+ ClassLoader cl = object.getClass().getClassLoader();
+ if (cl == null) {
+ return null;
+ }
+
+ if (cl instanceof BundleClassLoader) {
+ return framework.getBundleByClassLoader((BundleClassLoader) cl);
+ }
+ return null;
+ }
+
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleFragment.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleFragment.java
new file mode 100644
index 000000000..7ba5b88d3
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleFragment.java
@@ -0,0 +1,474 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.*;
+import org.eclipse.osgi.framework.adaptor.BundleData;
+import org.eclipse.osgi.framework.debug.Debug;
+import org.eclipse.osgi.service.resolver.BundleDescription;
+import org.osgi.framework.*;
+import org.osgi.framework.ServiceReference;
+
+public class BundleFragment extends Bundle
+{
+
+ /** The resolved host that this fragment is attached to */
+ protected BundleHost host;
+ /** The current instantiation of the activator. */
+ protected BundleActivator activator;
+
+ /**
+ * @param bundledata
+ * @param location
+ * @param framework
+ * @param startLevel
+ * @throws BundleException
+ */
+ public BundleFragment(BundleData bundledata, String location, Framework framework, int startLevel) throws BundleException
+ {
+ super(bundledata, location, framework, startLevel);
+ host = null;
+ }
+
+
+ /**
+ * Load the bundle.
+ * @exception org.osgi.framework.BundleException
+ */
+ protected void load() throws BundleException
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ if ((state & (INSTALLED)) == 0)
+ {
+ Debug.println("Bundle.load called when state != INSTALLED: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ }
+
+ if (framework.isActive())
+ {
+ SecurityManager sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ PermissionCollection collection = framework.permissionAdmin.createPermissionCollection(this);
+
+ domain = new ProtectionDomain(null, collection);
+ }
+
+ try
+ {
+ bundledata.open(); /* make sure the BundleData is open */
+ } catch (IOException e)
+ {
+ throw new BundleException(Msg.formatter.getString("BUNDLE_READ_EXCEPTION"), e);
+ }
+ }
+ }
+
+ /**
+ * Changes the state from ACTIVE | RESOVED to INSTALLED. This is called when a
+ * host gets reloaded or unloaded.
+ * This method must be called while holding the bundles lock.
+ *
+ * @return true if an exported package is "in use". i.e. it has been imported by a bundle
+ * @exception org.osgi.framework.BundleException
+ */
+ protected boolean unresolve()
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ if ((state & (INSTALLED | RESOLVED)) == 0)
+ {
+ Debug.println("Bundle.reload called when state != INSTALLED | RESOLVED: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ }
+
+ if (framework.isActive())
+ {
+ if (host != null)
+ {
+ if (state == RESOLVED)
+ {
+ state = INSTALLED;
+ host = null;
+ }
+ }
+ }
+ else
+ {
+ /* close the outgoing jarfile */
+ try
+ {
+ this.bundledata.close();
+ }
+ catch (IOException e)
+ {
+ // Do Nothing
+ }
+ }
+
+ return(false);
+ }
+
+
+ /**
+ * Reload from a new bundle.
+ * This method must be called while holding the bundles lock.
+ *
+ * @param newBundle Dummy Bundle which contains new data.
+ * @return true if an exported package is "in use". i.e. it has been imported by a bundle
+ * @exception org.osgi.framework.BundleException
+ */
+ protected boolean reload(Bundle newBundle) throws BundleException
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ if ((state & (INSTALLED | RESOLVED)) == 0)
+ {
+ Debug.println("Bundle.reload called when state != INSTALLED | RESOLVED: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ }
+
+ boolean exporting = false;
+
+ if (framework.isActive())
+ {
+ if (host != null)
+ {
+ if (state == RESOLVED)
+ {
+ // Unresolving the host will cause the fragment to unresolve
+ exporting = host.unresolve();
+ }
+ }
+
+ }
+
+ if (!exporting)
+ {
+ /* close the outgoing jarfile */
+ try
+ {
+ this.bundledata.close();
+ }
+ catch (IOException e)
+ {
+ // Do Nothing
+ }
+ }
+
+ this.bundledata = newBundle.bundledata;
+ this.bundledata.setBundle(this);
+ return(exporting);
+ }
+
+
+ /**
+ * Refresh the bundle. This is called by Framework.refreshPackages.
+ * This method must be called while holding the bundles lock.
+ * this.loader.unimportPackages must have already been called before calling
+ * this method!
+ *
+ * @exception org.osgi.framework.BundleException if an exported package is "in use". i.e. it has been imported by a bundle
+ */
+ protected void refresh() throws BundleException
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ if ((state & (UNINSTALLED | INSTALLED | RESOLVED)) == 0)
+ {
+ Debug.println("Bundle.refresh called when state != UNINSTALLED | INSTALLED | RESOLVED: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ }
+
+ if (state == RESOLVED) {
+ host=null;
+ state = INSTALLED;
+ }
+ }
+
+ /**
+ * Unload the bundle.
+ * This method must be called while holding the bundles lock.
+ *
+ * @return true if an exported package is "in use". i.e. it has been imported by a bundle
+ */
+ protected boolean unload()
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ if ((state & (UNINSTALLED | INSTALLED | RESOLVED)) == 0)
+ {
+ Debug.println("Bundle.unload called when state != UNINSTALLED | INSTALLED | RESOLVED: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ }
+
+ boolean exporting = false;
+
+ if (framework.isActive())
+ {
+ if (host != null)
+ {
+ BundleHost resumeHost = host;
+ if (state == RESOLVED)
+ {
+ // Unresolving the host will cause the fragment to unresolve
+ try {
+ exporting = host.unresolve();
+ }
+ catch (BundleException be) {
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR,this,be);
+ }
+ }
+ if (!exporting) {
+ domain = null;
+ try
+ {
+ this.bundledata.close();
+ }
+ catch (IOException e)
+ { // Do Nothing.
+ }
+ }
+ // We must resume the host now that we are unloaded.
+ framework.resumeBundle(resumeHost);
+ }
+ }
+ else
+ {
+ try
+ {
+ this.bundledata.close();
+ }
+ catch (IOException e)
+ { // Do Nothing.
+ }
+ }
+
+ return(exporting);
+ }
+
+ /**
+ * This method loads a class from the bundle.
+ *
+ * @param name the name of the desired Class.
+ * @param checkPermission indicates whether a permission check should be done.
+ * @return the resulting Class
+ * @exception java.lang.ClassNotFoundException if the class definition was not found.
+ */
+ protected Class loadClass(String name, boolean checkPermission) throws ClassNotFoundException
+ {
+ if (checkPermission) {
+ framework.checkAdminPermission();
+ checkValid();
+ }
+ if (host == null)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println("Bundle.loadClass("+name+") called when host == null: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+
+ throw new ClassNotFoundException(name);
+ }
+
+ return(host.loadClass(name,checkPermission));
+ }
+
+ /**
+ * Find the specified resource in this bundle.
+ *
+ * This bundle's class loader is called to search for the named resource.
+ * If this bundle's state is <tt>INSTALLED</tt>, then only this bundle will
+ * be searched for the specified resource. Imported packages cannot be searched
+ * when a bundle has not been resolved.
+ *
+ * @param name The name of the resource.
+ * See <tt>java.lang.ClassLoader.getResource</tt> for a description of
+ * the format of a resource name.
+ * @return a URL to the named resource, or <tt>null</tt> if the resource could
+ * not be found or if the caller does not have
+ * the <tt>AdminPermission</tt>, and the Java Runtime Environment supports permissions.
+ *
+ * @exception java.lang.IllegalStateException If this bundle has been uninstalled.
+ */
+ public URL getResource(String name)
+ {
+ checkValid();
+
+ if (host == null)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println("Bundle.getResource("+name+") called when host == null: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+
+ return(null);
+ }
+
+ return(host.getResource(name));
+ }
+
+ /**
+ * Internal worker to start a bundle.
+ *
+ * @param persistent if true persistently record the bundle was started.
+ */
+ protected void startWorker(boolean persistent) throws BundleException
+ {
+ throw new BundleException(Msg.formatter.getString("FRAGMENT_CANNOT_START"));
+ }
+
+ /**
+ * Internal worker to stop a bundle.
+ *
+ * @param persistent if true persistently record the bundle was stopped.
+ */
+ protected void stopWorker(boolean persistent) throws BundleException
+ {
+ throw new BundleException(Msg.formatter.getString("FRAGMENT_CANNOT_STOP"));
+ }
+
+ /**
+ * Provides a list of {@link ServiceReference}s for the services
+ * registered by this bundle
+ * or <code>null</code> if the bundle has no registered
+ * services.
+ *
+ * <p>The list is valid at the time
+ * of the call to this method, but the framework is a very dynamic
+ * environment and services can be modified or unregistered at anytime.
+ *
+ * @return An array of {@link ServiceReference} or <code>null</code>.
+ * @exception java.lang.IllegalStateException If the
+ * bundle has been uninstalled.
+ * @see ServiceRegistration
+ * @see ServiceReference
+ */
+ public ServiceReference[] getRegisteredServices()
+ {
+ checkValid();
+ if (host == null) {
+ return null;
+ }
+ return host.getRegisteredServices();
+ }
+
+ /**
+ * Provides a list of {@link ServiceReference}s for the
+ * services this bundle is using,
+ * or <code>null</code> if the bundle is not using any services.
+ * A bundle is considered to be using a service if the bundle's
+ * use count for the service is greater than zero.
+ *
+ * <p>The list is valid at the time
+ * of the call to this method, but the framework is a very dynamic
+ * environment and services can be modified or unregistered at anytime.
+ *
+ * @return An array of {@link ServiceReference} or <code>null</code>.
+ * @exception java.lang.IllegalStateException If the
+ * bundle has been uninstalled.
+ * @see ServiceReference
+ */
+ public ServiceReference[] getServicesInUse()
+ {
+ checkValid();
+ if (host == null) {
+ return null;
+ }
+ return host.getServicesInUse();
+ }
+
+ public org.osgi.framework.Bundle getHost() {
+ return host;
+ }
+
+ public boolean isFragment() {
+ return true;
+ }
+
+ /**
+ * Sets the host for this fragment from the list of available
+ * BundleExporters. If a matching host cannot be found then a
+ * resolve Exception is logged.
+ * @param exporters The available BundleExporters to resolve the host from.
+ */
+ protected boolean setHost(BundleHost value) {
+ host = value;
+ if (host != null){
+ try {
+ host.attachFragment(this);
+ }
+ catch (BundleException be) {
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR,host,be);
+ return false;
+ }
+ }
+ return true;
+ // TODO detach the fragment if the host is null???
+ }
+
+ /**
+ * Check for BundlePermission to Host.
+ *
+ * @return true if bundle has the require permission.
+ */
+ protected boolean hasHostBundlePermission(String uniqueId)
+ {
+ if (domain != null)
+ {
+ return domain.implies(new BundlePermission(uniqueId, BundlePermission.HOST));
+ }
+
+ return true;
+ }
+
+ public BundleLoader getBundleLoader() {
+ return host == null ? null : host.getBundleLoader();
+ }
+
+ /**
+ * Mark this bundle as resolved
+ */
+ protected void resolve() {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
+ if ((state & (INSTALLED)) == 0) {
+ Debug.println("Bundle.resolve called when state != INSTALLED: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ if (host == null) {
+ Debug.println("Bundle.resolve called when host == null: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ }
+ state = RESOLVED;
+ }
+
+ /**
+ * Return the current context for this bundle.
+ *
+ * @return BundleContext for this bundle.
+ */
+ protected BundleContext getContext() {
+ return host == null ? null : host.getContext();
+ }
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleHost.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleHost.java
new file mode 100644
index 000000000..fc2775f82
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleHost.java
@@ -0,0 +1,728 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.PermissionCollection;
+import java.security.ProtectionDomain;
+import java.util.Vector;
+import org.eclipse.osgi.framework.adaptor.BundleData;
+import org.eclipse.osgi.framework.debug.Debug;
+import org.eclipse.osgi.service.resolver.BundleDescription;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+
+public class BundleHost extends Bundle {
+
+ /** Loaded state object. */
+ protected BundleLoader loader;
+
+ private BundleLoaderProxy proxy;
+
+ /** The BundleContext that represents this Bundle and all of its fragments */
+ protected BundleContext context;
+
+ /** The List of BundleFragments */
+ protected Vector fragments;
+
+ public BundleHost(BundleData bundledata, String location, Framework framework, int startLevel) throws BundleException {
+ super(bundledata, location, framework, startLevel);
+ context = null;
+ loader = null;
+ fragments = null;
+ }
+
+ protected BundleLoader basicGetBundleLoader() {
+ return loader;
+ }
+
+ /**
+ * Load the bundle.
+ * @exception org.osgi.framework.BundleException
+ */
+ protected void load() throws BundleException
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ if ((state & (INSTALLED)) == 0)
+ {
+ Debug.println("Bundle.load called when state != INSTALLED: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ if (loader != null)
+ {
+ Debug.println("Bundle.load called when loader != null: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ }
+
+ if (framework.isActive())
+ {
+ SecurityManager sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ PermissionCollection collection = framework.permissionAdmin.createPermissionCollection(this);
+
+ domain = new ProtectionDomain(null, collection);
+ }
+
+ }
+ loader = null;
+
+ }
+
+ /**
+ * Changes the state from ACTIVE | RESOVED to INSTALLED. This is called when a
+ * fragment gets reloaded or unloaded.
+ * This method must be called while holding the bundles lock.
+ *
+ * @return true if an exported package is "in use". i.e. it has been imported by a bundle
+ * @exception org.osgi.framework.BundleException
+ */
+ protected boolean unresolve() throws BundleException
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ if ((state & (INSTALLED | RESOLVED)) == 0)
+ {
+ Debug.println("Bundle.reload called when state != INSTALLED | RESOLVED: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ }
+
+ boolean exporting = false;
+
+ if (framework.isActive())
+ {
+
+ if (state == RESOLVED)
+ {
+ // suspend and acquire the state change lock
+ if (isActive()) {
+ boolean suspended = framework.suspendBundle(this,true);
+ if (!suspended) {
+ throw new BundleException(Msg.formatter.getString("BUNDLE_STATE_CHANGE_EXCEPTION"));
+ }
+ }
+ else {
+ beginStateChange();
+ }
+
+ BundleLoaderProxy curProxy = getLoaderProxy();
+ exporting = curProxy.inUse();
+ if (exporting){
+ // make sure the BundleLoader is created so it can
+ // be added to the removalPending list.
+ curProxy.getBundleLoader();
+ framework.packageAdmin.addRemovalPending(curProxy);
+ }
+ else {
+ framework.packageAdmin.unexportResources(curProxy);
+ if (loader != null) {
+ loader.clear();
+ loader.close();
+ }
+ framework.bundles.unMarkDependancies(curProxy);
+ }
+
+ unresolveFragments();
+ loader = null;
+ fragments = null;
+ proxy = null;
+ state = INSTALLED;
+ completeStateChange();
+ }
+ }
+ else
+ {
+ /* close the outgoing jarfile */
+ try
+ {
+ this.bundledata.close();
+ }
+ catch (IOException e)
+ {
+ // Do Nothing
+ }
+ }
+
+ return(exporting);
+ }
+
+ /**
+ * Reload from a new bundle.
+ * This method must be called while holding the bundles lock.
+ *
+ * @param newBundle Dummy Bundle which contains new data.
+ * @return true if an exported package is "in use". i.e. it has been imported by a bundle
+ * @exception org.osgi.framework.BundleException
+ */
+ protected boolean reload(Bundle newBundle) throws BundleException
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ if ((state & (INSTALLED | RESOLVED)) == 0)
+ {
+ Debug.println("Bundle.reload called when state != INSTALLED | RESOLVED: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ }
+
+ boolean exporting = false;
+
+ if (framework.isActive())
+ {
+ if (state == RESOLVED)
+ {
+ BundleLoaderProxy curProxy = getLoaderProxy();
+ exporting = curProxy.inUse();
+ if (exporting) {
+ // make sure the BundleLoader is created so it can
+ // be added to the removalPending list.
+ curProxy.getBundleLoader();
+ framework.packageAdmin.addRemovalPending(curProxy);
+ }
+ else {
+ framework.packageAdmin.unexportResources(curProxy);
+ if (loader != null)
+ {
+ loader.clear();
+ loader.close();
+ }
+ framework.bundles.unMarkDependancies(curProxy);
+ }
+ state = INSTALLED;
+ loader = null;
+ proxy = null;
+ unresolveFragments();
+ fragments = null;
+ }
+
+
+ }
+ else
+ {
+ /* close the outgoing jarfile */
+ try
+ {
+ this.bundledata.close();
+ }
+ catch (IOException e)
+ {
+ // Do Nothing
+ }
+ }
+ this.bundledata = newBundle.bundledata;
+ this.bundledata.setBundle(this);
+ return(exporting);
+ }
+
+ /**
+ * Unresolves all attached fragments. This is called any time the host
+ * bundle is reloaded, unloaded or is unresovled.
+ *
+ */
+ protected void unresolveFragments() {
+ if (fragments != null) {
+// TODO is this sync really needed? unresolve should only ever be done in with the state change lock aquired no?
+ synchronized (fragments) {
+ int size = fragments.size();
+ for (int i=0; i<size; i++) {
+ BundleFragment fragment = (BundleFragment) fragments.elementAt(i);
+ fragment.unresolve();
+ }
+ }
+ }
+ }
+
+ /**
+ * Refresh the bundle. This is called by Framework.refreshPackages.
+ * This method must be called while holding the bundles lock.
+ *
+ * @exception org.osgi.framework.BundleException if an exported package is "in use". i.e. it has been imported by a bundle
+ */
+ protected void refresh() throws BundleException
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ if ((state & (UNINSTALLED | INSTALLED | RESOLVED)) == 0)
+ {
+ Debug.println("Bundle.reload called when state != UNINSTALLED | INSTALLED | RESOLVED: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ }
+ if (state == RESOLVED) {
+ BundleLoaderProxy curProxy = getLoaderProxy();
+ framework.packageAdmin.unexportResources(curProxy);
+ if (loader != null) {
+ loader.clear();
+ loader.close();
+ }
+ framework.bundles.unMarkDependancies(curProxy);
+ loader = null;
+ proxy = null;
+ fragments = null;
+ state = INSTALLED;
+ }
+
+ }
+
+ /**
+ * Unload the bundle.
+ * This method must be called while holding the bundles lock.
+ *
+ * @return true if an exported package is "in use". i.e. it has been imported by a bundle
+ */
+ protected boolean unload()
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ if ((state & (UNINSTALLED | INSTALLED | RESOLVED)) == 0)
+ {
+ Debug.println("Bundle.unload called when state != UNINSTALLED | INSTALLED | RESOLVED: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ }
+
+ boolean exporting = false;
+
+ if (framework.isActive())
+ {
+ if (state == RESOLVED)
+ {
+ BundleLoaderProxy curProxy = getLoaderProxy();
+ exporting = curProxy.inUse();
+ if (exporting) {
+ // make sure the BundleLoader is created so it can
+ // be added to the removalPending list.
+ curProxy.getBundleLoader();
+ framework.packageAdmin.addRemovalPending(curProxy);
+ }
+ else {
+ framework.packageAdmin.unexportResources(curProxy);
+ if (loader != null)
+ {
+ loader.clear();
+ loader.close();
+ }
+ framework.bundles.unMarkDependancies(curProxy);
+ }
+
+ state = INSTALLED;
+ loader = null;
+ proxy = null;
+ unresolveFragments();
+ fragments = null;
+ domain = null;
+ }
+
+ //TODO Do we need to fix something here?
+ //BUGBUG ? search for any detached loaders for this bundle and
+ // close them if they are not exporting.
+ }
+ else
+ {
+ try
+ {
+ this.bundledata.close();
+ }
+ catch (IOException e)
+ { // Do Nothing.
+ }
+ }
+
+ return(exporting);
+ }
+
+ /**
+ * This method loads a class from the bundle.
+ *
+ * @param name the name of the desired Class.
+ * @param checkPermission indicates whether a permission check should be done.
+ * @return the resulting Class
+ * @exception java.lang.ClassNotFoundException if the class definition was not found.
+ */
+ protected Class loadClass(String name, boolean checkPermission) throws ClassNotFoundException
+ {
+ if (checkPermission) {
+ framework.checkAdminPermission();
+ checkValid();
+ }
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ if ((state & (STARTING|ACTIVE|STOPPING)) == 0)
+ {
+ Debug.println("Bundle.loadClass("+name+") called when state != STARTING | ACTIVE | STOPPING: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ }
+
+ getBundleLoader();
+ if (loader == null)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println("Bundle.loadClass("+name+") called when loader == null: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ throw new ClassNotFoundException(name);
+ }
+
+ return(loader.loadClass(name));
+ }
+
+ /**
+ * Find the specified resource in this bundle.
+ *
+ * This bundle's class loader is called to search for the named resource.
+ * If this bundle's state is <tt>INSTALLED</tt>, then only this bundle will
+ * be searched for the specified resource. Imported packages cannot be searched
+ * when a bundle has not been resolved.
+ *
+ * @param name The name of the resource.
+ * See <tt>java.lang.ClassLoader.getResource</tt> for a description of
+ * the format of a resource name.
+ * @return a URL to the named resource, or <tt>null</tt> if the resource could
+ * not be found or if the caller does not have
+ * the <tt>AdminPermission</tt>, and the Java Runtime Environment supports permissions.
+ *
+ * @exception java.lang.IllegalStateException If this bundle has been uninstalled.
+ */
+ public URL getResource(String name)
+ {
+ checkValid();
+
+ getBundleLoader();
+ if (loader == null)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println("Bundle.getResource("+name+") called when loader == null: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+
+ return(null);
+ }
+
+ return(loader.findResource(name));
+ }
+
+ /**
+ * Internal worker to start a bundle.
+ *
+ * @param persistent if true persistently record the bundle was started.
+ */
+ protected void startWorker(boolean persistent) throws BundleException
+ {
+ if (framework.active) {
+ if ((state & (STARTING | ACTIVE)) != 0) {
+ return;
+ }
+
+ //STARTUP TIMING Start here
+ if (Debug.DEBUG && MONITOR_BUNDLES)
+ framework.adaptor.getBundleStats().startActivation(getGlobalName());
+
+ try {
+ if (state == INSTALLED) {
+ framework.packageAdmin.resolveBundles();
+
+ if (state != RESOLVED) {
+ throw new BundleException(getResolutionFailureMessage());
+ }
+ }
+
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
+ Debug.println("Bundle: Active sl = " + framework.startLevelImpl.getStartLevel() + "; Bundle " + id + " sl = " + this.startLevel);
+ }
+
+ if (this.startLevel <= framework.startLevelImpl.getStartLevel()) {
+ state = STARTING;
+
+ context = createContext();
+ try {
+ context.start();
+
+ if (framework.active) {
+ state = ACTIVE;
+
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
+ Debug.println("->started " + this);
+ }
+
+ framework.publishBundleEvent(BundleEvent.STARTED, this);
+ }
+
+ } catch (BundleException e) {
+ context.close();
+ context = null;
+
+ state = RESOLVED;
+
+ throw e;
+ }
+
+ if (state == UNINSTALLED) {
+ context.close();
+ context = null;
+
+ throw new BundleException(Msg.formatter.getString("BUNDLE_UNINSTALLED_EXCEPTION"));
+ }
+ }
+ } finally {
+ if (Debug.DEBUG && MONITOR_BUNDLES)
+ framework.adaptor.getBundleStats().endActivation(getGlobalName());
+ }
+ }
+
+ if (persistent)
+ {
+ setStatus(Constants.BUNDLE_STARTED, true);
+ }
+ }
+
+ /**
+ * Create a BundleContext for this bundle.
+ *
+ * @return BundleContext for this bundle.
+ */
+ protected BundleContext createContext()
+ {
+ return(new BundleContext(this));
+ }
+
+ /**
+ * Return the current context for this bundle.
+ *
+ * @return BundleContext for this bundle.
+ */
+ protected BundleContext getContext()
+ {
+ return(context);
+ }
+
+ /**
+ * Internal worker to stop a bundle.
+ *
+ * @param persistent if true persistently record the bundle was stopped.
+ */
+ protected void stopWorker(boolean persistent) throws BundleException
+ {
+ if (persistent)
+ {
+ setStatus(Constants.BUNDLE_STARTED, false);
+ }
+
+ if (framework.active)
+ {
+ if ((state & (STOPPING | RESOLVED | INSTALLED)) != 0)
+ {
+ return;
+ }
+
+ state = STOPPING;
+
+ try
+ {
+ context.stop();
+ }
+ finally
+ {
+ context.close();
+ context = null;
+
+ checkValid();
+
+ state = RESOLVED;
+
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL)
+ {
+ Debug.println("->stopped "+ this);
+ }
+
+ framework.publishBundleEvent(BundleEvent.STOPPED, this);
+ }
+ }
+ }
+
+ /**
+ * Provides a list of {@link ServiceReference}s for the services
+ * registered by this bundle
+ * or <code>null</code> if the bundle has no registered
+ * services.
+ *
+ * <p>The list is valid at the time
+ * of the call to this method, but the framework is a very dynamic
+ * environment and services can be modified or unregistered at anytime.
+ *
+ * @return An array of {@link ServiceReference} or <code>null</code>.
+ * @exception java.lang.IllegalStateException If the
+ * bundle has been uninstalled.
+ * @see ServiceRegistration
+ * @see ServiceReference
+ */
+ public org.osgi.framework.ServiceReference[] getRegisteredServices()
+ {
+ checkValid();
+
+ if (context == null)
+ {
+ return(null);
+ }
+
+ return(context.getRegisteredServices());
+ }
+
+ /**
+ * Provides a list of {@link ServiceReference}s for the
+ * services this bundle is using,
+ * or <code>null</code> if the bundle is not using any services.
+ * A bundle is considered to be using a service if the bundle's
+ * use count for the service is greater than zero.
+ *
+ * <p>The list is valid at the time
+ * of the call to this method, but the framework is a very dynamic
+ * environment and services can be modified or unregistered at anytime.
+ *
+ * @return An array of {@link ServiceReference} or <code>null</code>.
+ * @exception java.lang.IllegalStateException If the
+ * bundle has been uninstalled.
+ * @see ServiceReference
+ */
+ public org.osgi.framework.ServiceReference[] getServicesInUse()
+ {
+ checkValid();
+
+ if (context == null)
+ {
+ return(null);
+ }
+
+ return(context.getServicesInUse());
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.osgi.framework.Bundle#getFragments()
+ */
+ public org.osgi.framework.Bundle[] getFragments() {
+
+ synchronized (this) {
+ if (fragments == null)
+ return null;
+ org.osgi.framework.Bundle[] result = new org.osgi.framework.Bundle[fragments.size()];
+ fragments.toArray(result);
+ return result;
+ }
+ }
+
+ /**
+ * Attaches a fragment to this BundleHost. Fragments must be attached to
+ * the host by ID order. If the ClassLoader of the host is already created
+ * then the fragment must be attached to the host ClassLoader
+ * @param fragment The fragment bundle to attach
+ * return true if the fragment successfully attached; false if the fragment
+ * could not be logically inserted at the end of the fragment chain.
+ */
+ public void attachFragment(BundleFragment fragment) throws BundleException
+ {
+ if (fragments == null)
+ {
+ synchronized (this)
+ {
+ if (fragments == null)
+ {
+ fragments = new Vector(10);
+ fragments.addElement(fragment);
+ }
+ }
+ }
+ else {
+ synchronized (fragments) {
+ int size = fragments.size();
+ boolean inserted = false;
+ // We must keep our fragments ordered by bundle ID; or
+ // install order.
+ for (int i = 0; i < size; i++) {
+ BundleFragment frag = (BundleFragment) fragments.elementAt(i);
+ if (fragment.id < frag.id) {
+ // if the loader has already been created
+ // then we cannot attach a fragment into the middle
+ // of the fragment chain.
+ if (loader != null) {
+ throw new BundleException(Msg.formatter.getString("FRAGMENT_ATTACHMENT ERROR"));
+ }
+ fragments.insertElementAt(fragment, i);
+ inserted = true;
+ }
+ }
+ if (!inserted) {
+ fragments.addElement(fragment);
+ }
+ }
+ }
+
+ // If the Host ClassLoader has exists then we must attach
+ // the fragment to the ClassLoader.
+ if (loader != null) {
+ loader.attachFragment(fragment,System.getProperties());
+ }
+
+ if (state == ACTIVE && context != null) {
+ context.startFragment(fragment);
+ }
+ }
+
+ public BundleLoader getBundleLoader() {
+ if (loader == null) {
+ synchronized(this) {
+ if (loader == null)
+ try {
+ loader = new BundleLoader(this, getBundleDescription());
+ getLoaderProxy().setBundleLoader(loader);
+ } catch (BundleException e) {
+ // TODO log something here
+ e.printStackTrace();
+ return null;
+ }
+ }
+ }
+ return loader;
+ }
+
+ /**
+ * Mark this bundle as resolved.
+ */
+ protected void resolve() {
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
+ if ((state & (INSTALLED)) == 0) {
+ Debug.println("Bundle.resolve called when state != INSTALLED: "+this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ }
+ state = RESOLVED;
+ }
+
+ protected BundleLoaderProxy getLoaderProxy() {
+ if (proxy == null){
+ synchronized(this){
+ if (proxy == null){
+ proxy = new BundleLoaderProxy(this);
+ }
+ }
+ }
+ return proxy;
+ }
+
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoader.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoader.java
new file mode 100644
index 000000000..0bdb053a6
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoader.java
@@ -0,0 +1,1045 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.*;
+import java.util.*;
+import org.eclipse.osgi.framework.adaptor.*;
+import org.eclipse.osgi.framework.debug.Debug;
+import org.eclipse.osgi.framework.util.ManifestElement;
+import org.eclipse.osgi.service.resolver.*;
+import org.osgi.framework.*;
+
+/**
+ * This object is created when the bundle
+ * loaded at framework launch or bundle install or update.
+ *
+ * It represents the loaded state of the bundle.
+ *
+ */
+public class BundleLoader implements ClassLoaderDelegate
+{
+ /** Bundle object */
+ protected BundleHost bundle;
+
+ /** The is the BundleClassLoader for the bundle */
+ protected BundleClassLoader classloader;
+
+ /** Single object for permission checks */
+ protected BundleResourcePermission resourcePermission;
+
+ /**
+ * Hashtable of imported packages. Key is packagename, Value is BundleLoader
+ */
+ protected KeyedHashSet importedPackages;
+
+ protected boolean hasImportedPackages = false;
+
+ protected boolean hasDynamicImports = false;
+ /**
+ * If true, import all packages dynamically.
+ */
+ protected boolean dynamicImportPackageAll;
+ /**
+ * If not null, list of package stems to import dynamically.
+ */
+ protected String[] dynamicImportPackageStems;
+ /**
+ * If not null, list of package names to import dynamically.
+ */
+ protected String[] dynamicImportPackages;
+
+ protected KeyedHashSet providedPackages;
+ protected KeyedHashSet requiredPackagesCache;
+ protected BundleLoaderProxy[] requiredBundles;
+ protected int[] reexportTable;
+
+ /**
+ * Returns the package name from the specified class name.
+ * The returned package is dot seperated.
+ *
+ * @param name Name of a class.
+ * @return Dot separated package name or null if the class
+ * has no package name.
+ */
+ protected static String getPackageName(String name) {
+ if (name != null) {
+ int index = name.lastIndexOf('.'); /* find last period in class name */
+ if (index > 0)
+ return name.substring(0, index);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the package name from the specified resource name.
+ * The returned package is dot seperated.
+ *
+ * @param name Name of a resource.
+ * @return Dot separated package name or null if the resource
+ * has no package name.
+ */
+ protected static String getResourcePackageName(String name) {
+ if (name != null) {
+ /* check for leading slash*/
+ int begin = ((name.length() > 1) && (name.charAt(0) == '/')) ? 1 : 0;
+ int end = name.lastIndexOf('/'); /* index of last slash */
+ if (end > begin)
+ return name.substring(begin, end).replace('/', '.');
+ }
+ return null;
+ }
+
+ /**
+ * Bundle runtime constructor. This object is created when the bundle is
+ * loaded at framework launch or bundle install or update.
+ *
+ * @param bundle Bundle object for this loader.
+ * @param file BundleFile for this object
+ * @param manifest Bundle's manifest
+ * @exception org.osgi.framework.BundleException
+ */
+ protected BundleLoader(BundleHost bundle, org.eclipse.osgi.service.resolver.BundleDescription description) throws BundleException {
+ this.bundle = bundle;
+ try {
+ bundle.getBundleData().open(); /* make sure the BundleData is open */
+ } catch (IOException e) {
+ throw new BundleException(Msg.formatter.getString("BUNDLE_READ_EXCEPTION"), e);
+ }
+ initialize(description);
+ }
+
+ protected void initialize(BundleDescription description) {
+ hasImportedPackages = hasDynamicImports = SystemBundleLoader.getSystemPackages() != null;
+
+ //This is the fastest way to access to the description for fragments since the hostdescription.getFragments() is slow
+ org.osgi.framework.Bundle[] fragmentObjects = bundle.getFragments();
+ BundleDescription[] fragments = new BundleDescription[fragmentObjects==null ? 0 : fragmentObjects.length];
+ for (int i = 0; i < fragments.length; i++) {
+ fragments[i] = ((Bundle) fragmentObjects[i]).getBundleDescription();
+ }
+
+ // init the imported packages list taking the bundle...
+ addImportedPackages(description.getPackages());
+ // ...and its fragments
+ for (int i = 0; i < fragments.length; i++)
+ if (fragments[i].isResolved())
+ addImportedPackages(fragments[i].getPackages());
+
+ // init the require bundles list. Need to account for optional bundles so bundles with
+ // no supplier should be skipped.
+ BundleSpecification[] required = description.getRequiredBundles();
+ ArrayList bundles = new ArrayList(Arrays.asList(required == null ? new BundleSpecification[0] : required));
+ for (int i = 0; i < fragments.length; i++)
+ if (fragments[i].isResolved()) {
+ BundleSpecification[] fragmentRequires = fragments[i].getRequiredBundles();
+ if (fragmentRequires != null)
+ bundles.addAll(Arrays.asList(fragmentRequires));
+ }
+ if (bundles.size() > 0) {
+ ArrayList bound = new ArrayList(bundles.size());
+ int[] reexported = new int[bundles.size()];
+ int reexportIndex = 0;
+ for (int i = 0; i < bundles.size(); i++) {
+ BundleSpecification spec = (BundleSpecification)bundles.get(i);
+ if (spec.isResolved()) {
+ String bundleKey = new StringBuffer(spec.getName()).append("_").append(spec.getActualVersion().toString()).toString();
+
+ BundleLoaderProxy loaderProxy =
+ (BundleLoaderProxy) bundle.framework.packageAdmin.exportedBundles.getByKey(bundleKey);
+ if (loaderProxy != null) {
+ bound.add(loaderProxy);
+ if (spec.isExported())
+ reexported[reexportIndex++] = i;
+ }
+ else {
+ // TODO log error
+ System.out.println("Could not find loaderProxy: " + bundleKey);
+ }
+ }
+ }
+ requiredBundles = (BundleLoaderProxy[])bound.toArray(new BundleLoaderProxy[bound.size()]);
+ if (reexportIndex > 0) {
+ reexportTable = new int[reexportIndex];
+ System.arraycopy(reexported, 0, reexportTable, 0, reexportIndex);
+ }
+ }
+
+ // init the provided packages
+ String[] provides = description.getProvidedPackages();
+ ArrayList packages = new ArrayList(Arrays.asList(required == null ? new String[0] : provides));
+ for (int i = 0; i < fragments.length; i++)
+ if (fragments[i].isResolved()) {
+ String[] fragmentProvides = fragments[i].getProvidedPackages();
+ if (fragmentProvides != null)
+ packages.addAll(Arrays.asList(fragmentProvides));
+ }
+ if (packages.size() > 0) {
+ providedPackages = new KeyedHashSet(packages.size());
+ for (int i = 0; i < packages.size(); i++)
+ providedPackages.add(new SingleSourcePackage((String)packages.get(i), bundle.getLoaderProxy()));
+ }
+
+ // init the dynamic imports tables
+ try {
+ String spec = bundle.getBundleData().getDynamicImports();
+ ManifestElement[] imports = ManifestElement.parsePackageDescription(spec);
+ initDynamicImportPackage(imports);
+ } catch (BundleException e) {
+ // TODO log an error
+ }
+ }
+
+ private void addImportedPackages(PackageSpecification[] packages) {
+ if (packages != null && packages.length > 0) {
+ if (!hasImportedPackages || importedPackages == null) {
+ hasImportedPackages = true;
+ importedPackages = new KeyedHashSet();
+ }
+ for (int i = 0; i < packages.length; i++) {
+ SingleSourcePackage packagesource =
+ (SingleSourcePackage) bundle.framework.packageAdmin.exportedPackages.getByKey(packages[i].getName());
+ if (packagesource != null) {
+ importedPackages.add(packagesource);
+ }
+ }
+ }
+ }
+
+ protected BundleHost getSupplier(VersionConstraint spec) {
+ BundleDescription supplier = spec.getSupplier();
+ if (supplier == null)
+ return null;
+ return (BundleHost)bundle.framework.getBundle(supplier.getBundleId());
+ }
+
+ /**
+ * Close the the Bundle's file.
+ *
+ */
+ protected void close() {
+ if (bundle == null)
+ return;
+ BundleData bundleData = bundle.getBundleData();
+ importedPackages = null;
+ if (bundleData != null) {
+ if (classloader != null)
+ classloader.close();
+ classloader = null;
+ /* close the jar file */
+ try {
+ bundleData.close();
+ } catch (IOException e) {
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ Debug.println("IOException on close :" + e.getMessage());
+ }
+ bundle = null; /* This indicates the BundleLoader is destroyed */
+ }
+ }
+
+ /**
+ * This method loads a class from the bundle. The class is searched for in the
+ * same manner as it would if it was being loaded from a bundle (i.e. all
+ * hosts, fragments, import, required bundles and local resources are searched.
+ *
+ * @param name the name of the desired Class.
+ * @return the resulting Class
+ * @exception java.lang.ClassNotFoundException if the class definition was not found.
+ */
+ protected Class loadClass(String name) throws ClassNotFoundException {
+ return createClassLoader().loadClass(name, false);
+ }
+
+ /**
+ * Gets a ResourceBundle using the bundle's classloader.
+ * @param name The name of the ResourceBundle to get.
+ * @param locale The locale to use to get the ResourceBundle.
+ * @return The ResourceBundle.
+ * @throws java.util.MissingResourceException if the resource is not found.
+ */
+ protected ResourceBundle getResourceBundle(String name, Locale locale){
+ return ResourceBundle.getBundle(name, locale, createClassLoader());
+ }
+
+ /**
+ * Imports a class from this Bundle Loader. The local
+ * classloader is searched then the fragments.
+ * @param name The name of the class to import.
+ * @return The loaded Class or null if the class is not found.
+ */
+ protected Class importClass(String name) {
+ Class result = findLocalClass(name);
+ return result;
+ }
+
+ protected BundleClassLoader createClassLoader() {
+ if (classloader != null)
+ return classloader;
+ synchronized(this) {
+ if (classloader != null)
+ return classloader;
+
+ try {
+ String[] classpath = getClassPath(bundle, System.getProperties());
+ if (classpath != null){
+ classloader = createBCLPrevileged(bundle.getProtectionDomain(), classpath);
+ org.osgi.framework.Bundle[] fragments = bundle.getFragments();
+ if (fragments != null)
+ for (int i = 0; i < fragments.length; i++) {
+ Bundle fragment = (Bundle)fragments[i];
+ classloader.attachFragment(fragment.getBundleData(), fragment.domain, getClassPath(fragment, System.getProperties()));
+ }
+ }
+ else {
+ bundle.framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle, new BundleException(Msg.formatter.getString("BUNDLE_NO_CLASSPATH_MATCH")));
+ }
+ } catch (BundleException e) {
+ bundle.framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle,e);
+ }
+
+ }
+ return classloader;
+ }
+
+ /**
+ * Finds a class local to this bundle. Only the classloader for this bundle is searched.
+ * @param name The name of the class to find.
+ * @return The loaded Class or null if the class is not found.
+ */
+ protected Class findLocalClass(String name) {
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ Debug.println("BundleLoader["+this+"].findLocalClass("+name+")");
+ try {
+ Class clazz = createClassLoader().findLocalClass(name);
+ if (Debug.DEBUG && Debug.DEBUG_LOADER && clazz != null)
+ Debug.println("BundleLoader[" + this + "] found local class " + name);
+ return clazz;
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Finds the class for a bundle. This method is used for delegation by the bundle's classloader.
+ */
+ public Class findClass(String name) throws ClassNotFoundException {
+ if (isClosed())
+ throw new ClassNotFoundException(name);
+
+ if (Debug.DEBUG && Debug.DEBUG_LOADER) {
+ Debug.println("BundleLoader["+this+"].loadBundleClass("+name+")");
+ }
+
+ String packageName = getPackageName(name);
+
+ Class result = null;
+ if (packageName != null) {
+ result = findImportedClass(name, packageName);
+ if (result == null) {
+ result = findRequiredClass(name, packageName);
+ }
+ }
+
+ if (result==null) {
+ result = findLocalClass(name);
+ if (result==null) {
+ throw new ClassNotFoundException(name);
+ }
+ }
+
+ return result;
+ }
+
+ boolean isClosed() {
+ return bundle == null;
+ }
+ /**
+ * Finds the resource for a bundle. This method is used for delegation by the bundle's classloader.
+ */
+ public URL findResource(String name) {
+ if (isClosed())
+ return null;
+ if ((name.length() > 1) && (name.charAt(0) == '/')) /* if name has a leading slash */
+ name = name.substring(1); /* remove leading slash before search */
+
+ try {
+ checkResourcePermission();
+ } catch (SecurityException e) {
+ try {
+ bundle.framework.checkAdminPermission();
+ } catch (SecurityException ee) {
+ return null;
+ }
+ }
+ String packageName = getResourcePackageName(name);
+
+ URL resource = null;
+ if (packageName != null) {
+ resource = findImportedResource(name, packageName);
+ if (resource == null) {
+ resource = findRequiredResource(name, packageName);
+ }
+ }
+
+ if (resource == null) {
+ resource = findLocalResource(name);
+ }
+
+ return resource;
+ }
+
+ /**
+ * Finds the resources for a bundle. This method is used for delegation by the bundle's classloader.
+ */
+ public Enumeration findResources(String name) throws IOException {
+ if (isClosed())
+ return null;
+ if ((name.length() > 1) && (name.charAt(0) == '/')) /* if name has a leading slash */
+ name = name.substring(1); /* remove leading slash before search */
+
+ try {
+ checkResourcePermission();
+ } catch (SecurityException e) {
+ try {
+ bundle.framework.checkAdminPermission();
+ } catch (SecurityException ee) {
+ return null;
+ }
+ }
+ String packageName = getResourcePackageName(name);
+
+ Enumeration result = null;
+ if (packageName != null) {
+ result = findImportedResources(name, packageName);
+ if (result == null) {
+ result = findRequiredResources(name, packageName);
+ }
+ }
+
+ if (result == null) {
+ result = findLocalResources(name);
+ }
+
+ return result;
+ }
+
+ /**
+ * Imports a resource from this Bundle Loader. The local
+ * classloader is searched then the fragments.
+ * @param name The name of the resource to import.
+ * @return The URL to the resource or null if the resource is not found.
+ */
+ protected URL importResource(String name) {
+ URL result = findLocalResource(name);
+ return result;
+ }
+
+ /**
+ * Finds a resource local to this bundle. Only the classloader for this bundle is searched.
+ * @param name The name of the resource to find.
+ * @return The URL to the resource or null if the resource is not found.
+ */
+ protected URL findLocalResource(final String name) {
+ if (System.getSecurityManager() == null)
+ return createClassLoader().findLocalResource(name);
+ return (URL) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return createClassLoader().findLocalResource(name);
+ }
+ });
+ }
+
+ /**
+ * Imports the resources from this Bundle Loader. The local
+ * classloader is searched then the fragments.
+ * @param name The name of the resource to import.
+ * @return an Enumeration of URLs for the resources or null if the resource is not found.
+ */
+ protected Enumeration importResources(String name) {
+ Enumeration result = findLocalResources(name);
+ return result;
+ }
+
+ /**
+ * Returns an Enumeration of URLs representing all the resources with
+ * the given name. Only the classloader for this bundle is searched.
+ *
+ * @param name the resource name
+ * @return an Enumeration of URLs for the resources
+ * @throws IOException if I/O errors occur
+ */
+ protected Enumeration findLocalResources(String name) {
+ if ((name.length() > 1) && (name.charAt(0) == '/')) /* if name has a leading slash */
+ name = name.substring(1);
+ try {
+ checkResourcePermission();
+ } catch (SecurityException e) {
+ return null;
+ }
+ return createClassLoader().findLocalResources(name);
+ }
+
+ /**
+ * Returns the absolute path name of a native library.
+ *
+ * @param name the library name
+ * @return the absolute path of the native library or null if not found
+ */
+ public String findLibrary(final String name) {
+ if (isClosed())
+ return null;
+ if (System.getSecurityManager() == null)
+ return findLocalLibrary(name);
+ return (String) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return findLocalLibrary(name);
+ }
+ });
+ }
+
+ protected String findLocalLibrary(final String name) {
+ String result = bundle.getBundleData().findLibrary(name);
+ if (result != null)
+ return result;
+
+ org.osgi.framework.Bundle[] fragments = bundle.getFragments();
+ if (fragments == null || fragments.length == 0)
+ return null;
+
+ // look in fragments imports ...
+ for (int i=0; i<fragments.length; i++) {
+ result = ((Bundle)fragments[i]).getBundleData().findLibrary(name);
+ if (result !=null)
+ return result;
+ }
+ return result;
+ }
+
+ /**
+ * Return the bundle we are associated with.
+ *
+ */
+ protected Bundle getBundle() {
+ return bundle;
+ }
+
+ private BundleClassLoader createBCLPrevileged(final ProtectionDomain pd, final String[] cp){
+ if (System.getSecurityManager() == null)
+ return bundle.getBundleData().createClassLoader(BundleLoader.this,pd,cp);
+ return (BundleClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return bundle.getBundleData().createClassLoader(BundleLoader.this,pd,cp);
+ }
+ });
+ }
+
+ /**
+ * Check for PackagePermission to Export.
+ *
+ * @return true if bundle has the package permission.
+ */
+ protected boolean hasExportPackagePermission(String name) {
+ ProtectionDomain domain = bundle.getProtectionDomain();
+ if (domain != null)
+ return domain.implies(new PackagePermission(name, PackagePermission.EXPORT));
+ return true;
+ }
+
+ /**
+ * Check for BundlePermission to Provide.
+ *
+ * @return true if bundle has the permission to export the bundle.
+ */
+ protected boolean hasProvideBundlePermission(String uniqueId) {
+ ProtectionDomain domain = bundle.getProtectionDomain();
+ if (domain != null)
+ return domain.implies(new BundlePermission(uniqueId, BundlePermission.PROVIDE));
+ return true;
+ }
+
+ /**
+ * Check for PackagePermission to Import.
+ *
+ * @return true if bundle has the package permission.
+ */
+ protected boolean hasImportPackagePermission(String name) {
+ ProtectionDomain domain = bundle.getProtectionDomain();
+ if (domain != null)
+ return domain.implies(new PackagePermission(name, PackagePermission.IMPORT));
+ return true;
+ }
+
+ /**
+ * Check for BundlePermission to Require.
+ *
+ * @return true if bundle has the require permission.
+ */
+ protected boolean hasRequireBundlePermission(String uniqueId) {
+ ProtectionDomain domain = bundle.getProtectionDomain();
+ if (domain != null)
+ return domain.implies(new BundlePermission(uniqueId, BundlePermission.REQUIRE));
+ return true;
+ }
+
+ /**
+ * Check for BundlePermission to Host.
+ *
+ * @return true if bundle has the require permission.
+ */
+ protected boolean hasHostBundlePermission(String uniqueId) {
+ ProtectionDomain domain = bundle.getProtectionDomain();
+ if (domain != null)
+ return domain.implies(new BundlePermission(uniqueId, BundlePermission.HOST));
+ return true;
+ }
+
+ /**
+ * Return a string representation of this loader.
+ *
+ * @return String
+ */
+ public String toString() {
+ BundleData result = bundle.getBundleData();
+ return result == null ? "BundleLoader.bundledata == null!" : result.toString();
+ }
+
+ protected void checkResourcePermission() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ if (resourcePermission == null)
+ resourcePermission = new BundleResourcePermission(bundle.getBundleId());
+ sm.checkPermission(resourcePermission);
+ }
+ }
+
+ /**
+ * Get the BundleLoader for the package if it is imported.
+ *
+ * @param pkgname The name of the package to import.
+ * @return BundleLoader to load from or null if the package is not imported.
+ */
+ protected BundleLoader getPackageExporter(String pkgname) {
+ if (importedPackages != null) {
+ PackageSource exporter = (PackageSource)importedPackages.getByKey(pkgname);
+ if (exporter != null)
+ return exporter.getSupplier().getBundleLoader();
+ }
+
+ if (isDynamicallyImported(pkgname)) {
+ PackageSource exporter =
+ (PackageSource) bundle.framework.packageAdmin.exportedPackages.getByKey(pkgname);
+ if (exporter != null) {
+ exporter.getSupplier().markUsed(bundle.getLoaderProxy());
+ importedPackages.add(exporter);
+ return exporter.getSupplier().getBundleLoader();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return true if the target package name matches
+ * a name in the DynamicImport-Package manifest header.
+ *
+ * @param pkgname The name of the requested class' package.
+ * @return true if the package should be imported.
+ */
+ protected boolean isDynamicallyImported(String pkgname)
+ {
+ /* quick shortcut check */
+ if (!hasDynamicImports) {
+ return false;
+ }
+
+ /* "*" shortcut */
+ if (dynamicImportPackageAll)
+ return true;
+
+ /*
+ * If including the system bundle packages by default, dynamically import them.
+ * Most OSGi framework implementations assume the system bundle packages
+ * are on the VM classpath. As a result some bundles neglect to import
+ * framework packages (e.g. org.osgi.framework).
+ */
+ String[] systemPackages = SystemBundleLoader.getSystemPackages();
+ if (systemPackages != null) {
+ for (int i = 0; i < systemPackages.length; i++)
+ if (pkgname.equals(systemPackages[i]))
+ return true;
+ }
+
+ /* match against specific names */
+ if (dynamicImportPackages != null)
+ for (int i = 0; i < dynamicImportPackages.length; i++)
+ if (pkgname.equals(dynamicImportPackages[i]))
+ return true;
+
+ /* match against names with trailing wildcards */
+ if (dynamicImportPackageStems != null)
+ for (int i = 0; i < dynamicImportPackageStems.length; i++)
+ if (pkgname.startsWith(dynamicImportPackageStems[i]))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Find a class using the imported packages for this bundle. Only the
+ * ImportClassLoader is used for the search.
+ * @param name The name of the class to find.
+ * @return The loaded class or null if the class does not belong to a package
+ * that is imported by the bundle.
+ * @throws ImportClassNotFoundException If the class does belong to a package
+ * that is imported by the bundle but the class is not found.
+ */
+ protected Class findImportedClass(String name, String packageName) throws ImportClassNotFoundException {
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ Debug.println("ImportClassLoader["+this+"].findImportedClass("+name+")");
+ if (!hasImportedPackages)
+ return null;
+ Class result = null;
+
+ try {
+ BundleLoader exporter = getPackageExporter(packageName);
+ if (exporter != null) {
+ result = exporter.importClass(name);
+ if (result == null)
+ throw new ImportClassNotFoundException(name);
+ }
+ } finally {
+ if (result == null) {
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ Debug.println("ImportClassLoader[" + this + "] class "+name+" not found in imported package " + packageName);
+ } else {
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ Debug.println("BundleLoader["+this+"] found imported class "+name);
+ }
+ }
+ return result;
+ }
+
+ protected void addExportedProvidersFor(String packageName, ArrayList result, KeyedHashSet visited) {
+ // TODO is it ok to use bundle as the visit token or should it be the loader?
+ if (!visited.add(bundle))
+ return;
+ PackageSource local = getProvidedPackage(packageName);
+ if (local != null)
+ result.add(local.getSupplier());
+ if (requiredBundles == null)
+ return;
+ int size = reexportTable == null ? 0 : reexportTable.length;
+ int reexportIndex = 0;
+ for (int i = 0; i < requiredBundles.length; i++) {
+ if (reexportIndex < size && reexportTable[reexportIndex] == i) {
+ reexportIndex++;
+ requiredBundles[i].getBundleLoader().addExportedProvidersFor(packageName, result, visited);
+ }
+ }
+ }
+
+ /**
+ * Find a class using the required bundles for this bundle. Only the
+ * required bundles are used to search for the class.
+ * @param name The name of the class to find.
+ * @return The loaded class or null if the class is not found.
+ */
+ protected PackageSource getProvidersFor(String packageName) {
+ // first look in the required packages cache
+ if (requiredPackagesCache != null) {
+ PackageSource result = (PackageSource)requiredPackagesCache.getByKey(packageName);
+
+ if (result != null){
+ if (result.isNullSource()) {
+ return null;
+ }
+ else {
+ return result;
+ }
+ }
+ }
+
+ // didn't find it in the cache search the actual required bundles
+ if (requiredBundles == null)
+ return null;
+ KeyedHashSet visited = new KeyedHashSet(false);
+ ArrayList result = new ArrayList(3);
+ for (int i = 0; i < requiredBundles.length; i++) {
+ BundleLoader requiredLoader = requiredBundles[i].getBundleLoader();
+ requiredLoader.addExportedProvidersFor(packageName, result, visited);
+ }
+
+ // found some so cache the result for next time and return
+ if (requiredPackagesCache == null)
+ requiredPackagesCache = new KeyedHashSet();
+ if (result.size() == 0){
+ // did not find it in our required bundles lets record the failure
+ // so we do not have to do the search again for this package.
+ requiredPackagesCache.add(new NullPackageSource(packageName));
+ return null;
+ }
+ else if (result.size() == 1) {
+ // if there is just one source, remember just the single source
+ BundleLoaderProxy bundle = (BundleLoaderProxy)result.get(0);
+ PackageSource source = new SingleSourcePackage(packageName, bundle);
+ requiredPackagesCache.add(source);
+ return source;
+ } else {
+ // if there was more than one source, build a multisource and cache that.
+ BundleLoaderProxy[] bundles = (BundleLoaderProxy[])result.toArray(new BundleLoaderProxy[result.size()]);
+ MultiSourcePackage source = new MultiSourcePackage(packageName, bundles);
+ requiredPackagesCache.add(source);
+ return source;
+ }
+ }
+
+
+ /**
+ * Find a class using the required bundles for this bundle. Only the
+ * required bundles are used to search for the class.
+ * @param name The name of the class to find.
+ * @return The loaded class or null if the class is not found.
+ */
+ protected Class findRequiredClass(String name, String packageName) {
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ Debug.println("ImportClassLoader["+this+"].findRequiredClass("+name+")");
+ PackageSource source = getProvidersFor(packageName);
+ if (source == null)
+ return null;
+ if (source.isMultivalued()) {
+ BundleLoaderProxy[] bundles = source.getSuppliers();
+ for (int i = 0; i < bundles.length; i++) {
+ Class result = bundles[i].getBundleLoader().importClass(name);
+ if (result != null)
+ return result;
+ }
+ } else
+ return source.getSupplier().getBundleLoader().importClass(name);
+ return null;
+ }
+
+ protected PackageSource getProvidedPackage(String name) {
+ return providedPackages == null ? null : (PackageSource)providedPackages.getByKey(name);
+ }
+
+ /**
+ * Find a resource using the imported packages for this bundle. Only the
+ * ImportClassLoader is used for the search.
+ * @param name The name of the resource to find.
+ * @return The URL of the resource or null if the resource does not belong to a package
+ * that is imported by the bundle.
+ * @throws ImportResourceNotFoundException If the resource does belong to a package
+ * that is imported by the bundle but the resource is not found.
+ */
+ protected URL findImportedResource(String name, String packageName) {
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ Debug.println("ImportClassLoader["+this+"].findImportedResource("+name+")");
+ if (!hasImportedPackages)
+ return null;
+
+ BundleLoader exporter = getPackageExporter(packageName);
+ if (exporter != null) {
+ URL url = exporter.importResource(name);
+ if (url != null)
+ return url;
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ Debug.println("ImportClassLoader["+this+"] resource "+name+" not found in imported package "+ packageName);
+ throw new ImportResourceNotFoundException(name);
+ }
+ return null;
+ }
+
+ /**
+ * Find a resource using the required bundles for this bundle. Only the
+ * required bundles are used to search.
+ * @param name The name of the resource to find.
+ * @return The URL for the resource or null if the resource is not found.
+ */
+ protected URL findRequiredResource(String name, String packageName) {
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ Debug.println("ImportClassLoader["+ this +"].findRequiredResource("+name+")");
+ PackageSource source = getProvidersFor(packageName);
+ if (source == null)
+ return null;
+ if (source.isMultivalued()) {
+ BundleLoaderProxy[] bundles = source.getSuppliers();
+ for (int i = 0; i < bundles.length; i++) {
+ URL result = bundles[i].getBundleLoader().importResource(name);
+ if (result != null)
+ return result;
+ }
+ } else
+ return source.getSupplier().getBundleLoader().importResource(name);
+ return null;
+ }
+
+ /**
+ * Returns an Enumeration of URLs representing all the resources with
+ * the given name.
+ *
+ * If the resource is in a package that is imported, call the exporting
+ * bundle. Otherwise return null.
+ *
+ * @param name the resource name
+ * @return an Enumeration of URLs for the resources if the package is
+ * imported, null otherwise.
+ * @throws IOException if I/O errors occur
+ */
+ protected Enumeration findImportedResources(String name, String packageName) {
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ Debug.println("ImportClassLoader["+this+"].findImportedResources("+name+")");
+ if (!hasImportedPackages)
+ return null;
+ BundleLoader exporter = getPackageExporter(packageName);
+ if (exporter != null)
+ return exporter.importResources(name);
+ return null;
+ }
+
+ /**
+ * Returns an Enumeration of URLs representing all the resources with
+ * the given name.
+ * Find the resources using the required bundles for this bundle. Only the
+ * required bundles are used to search.
+ *
+ * If the resource is in a package that is imported, call the exporting
+ * bundle. Otherwise return null.
+ *
+ * @param name the resource name
+ * @return an Enumeration of URLs for the resources if the package is
+ * imported, null otherwise.
+ * @throws IOException if I/O errors occur
+ */
+ protected Enumeration findRequiredResources(String name, String packageName) {
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ Debug.println("ImportClassLoader["+this+"].findRequiredResources("+name+")");
+ PackageSource source = getProvidersFor(packageName);
+ if (source == null)
+ return null;
+ if (source.isMultivalued()) {
+ BundleLoaderProxy[] bundles = source.getSuppliers();
+ for (int i = 0; i < bundles.length; i++) {
+ Enumeration result = bundles[i].getBundleLoader().importResources(name);
+ if (result != null)
+ return result;
+ }
+ } else
+ return source.getSupplier().getBundleLoader().importResources(name);
+ return null;
+ }
+
+ protected void initDynamicImportPackage(ManifestElement[] packages) {
+ if (packages == null && SystemBundleLoader.getSystemPackages() == null)
+ return;
+
+ hasDynamicImports = hasImportedPackages = true;
+ // make sure importedPackages is not null;
+ if (importedPackages == null) {
+ importedPackages = new KeyedHashSet();
+ }
+
+ if (packages == null)
+ return;
+
+ int size = packages.length;
+ ArrayList stems = new ArrayList(size);
+ ArrayList names = new ArrayList(size);
+ for (int i = 0; i < size; i++) {
+ String name = packages[i].getValue();
+ if (name.equals("*")) { /* shortcut */
+ dynamicImportPackageAll = true;
+ return;
+ }
+
+ if (name.endsWith(".*"))
+ stems.add(name.substring(1, name.length()-1));
+ else
+ names.add(name);
+ }
+
+ size = stems.size();
+ if (size > 0)
+ dynamicImportPackageStems = (String[]) stems.toArray(new String[size]);
+
+ size = names.size();
+ if (size > 0)
+ dynamicImportPackages = (String[]) names.toArray(new String[size]);
+ }
+
+ protected void clear() {
+ providedPackages = null;
+ requiredBundles = null;
+ importedPackages = null;
+ dynamicImportPackages = null;
+ dynamicImportPackageStems = null;
+ }
+
+ protected ClassLoader getClassLoader() {
+ return classloader;
+ }
+
+ protected void attachFragment(BundleFragment fragment, Properties props){
+ initialize(bundle.getBundleDescription());
+ if (classloader == null)
+ return;
+
+ try {
+ String[] classpath = getClassPath(fragment, props);
+ if (classpath != null)
+ classloader.attachFragment(fragment.getBundleData(), fragment.domain, classpath);
+ else
+ bundle.framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle, new BundleException(Msg.formatter.getString("BUNDLE_NO_CLASSPATH_MATCH")));
+ } catch (BundleException e) {
+ bundle.framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle,e);
+ }
+
+ }
+
+ protected String[] getClassPath(Bundle bundle, Properties props) throws BundleException {
+ String spec = bundle.getBundleData().getClassPath();
+ ManifestElement[] classpathElements = ManifestElement.parseClassPath(spec);
+ return matchClassPath(classpathElements, props);
+ }
+
+ protected String[] matchClassPath(ManifestElement[] classpath, Properties props) {
+ if (classpath == null) {
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ Debug.println(" no classpath");
+ /* create default BundleClassPath */
+ return new String[] { "." };
+ }
+
+ ArrayList result = new ArrayList(10);
+ for (int i = 0; i < classpath.length; i++) {
+ Filter filter = createFilter(classpath[i].getAttribute("filter"));
+ if (filter == null || filter.match(props)) {
+ if (Debug.DEBUG && Debug.DEBUG_LOADER)
+ Debug.println(" found match for classpath entry " + classpath[i].getValue());
+ result.add(classpath[i].getValue());
+ }
+ }
+ return (String[]) result.toArray(new String[result.size()]);
+ }
+
+ protected Filter createFilter(String filter) {
+ if (filter == null)
+ return null;
+ try {
+ return new Filter(filter);
+ } catch (InvalidSyntaxException e) {
+ bundle.framework.publishFrameworkEvent(FrameworkEvent.ERROR,bundle,e);
+ return null;
+ }
+ }
+
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoaderProxy.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoaderProxy.java
new file mode 100644
index 000000000..ead61a922
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoaderProxy.java
@@ -0,0 +1,155 @@
+package org.eclipse.osgi.framework.internal.core;
+
+import org.eclipse.osgi.framework.debug.Debug;
+import org.eclipse.osgi.service.resolver.BundleDescription;
+import org.eclipse.osgi.service.resolver.BundleSpecification;
+import org.eclipse.osgi.service.resolver.PackageSpecification;
+
+public class BundleLoaderProxy implements KeyedElement {
+ private BundleLoader loader;
+ private BundleHost bundle;
+ private String uniqueId;
+ private String key;
+ private boolean stale = false;
+ private KeyedHashSet users;
+ protected boolean markedUsedDependencies = false;
+
+ public BundleLoaderProxy(BundleHost bundle) {
+ this.bundle = bundle;
+ this.uniqueId = bundle.getGlobalName();
+ if (this.uniqueId == null) {
+ this.uniqueId = new StringBuffer().append(bundle.id).append("NOUNIQUEID").toString();
+ }
+ this.key = new StringBuffer(uniqueId).append("_").append(bundle.getVersion().toString()).toString();
+ this.users = new KeyedHashSet(false);
+ }
+ public BundleLoader getBundleLoader() {
+ if (loader == null)
+ loader = bundle.getBundleLoader();
+ return loader;
+ }
+ public Bundle getBundle() {
+ return bundle;
+ }
+
+ public void setBundleLoader(BundleLoader value) {
+ loader = value;
+ }
+
+ public void markUsed(BundleLoaderProxy user){
+ // only mark as used if the user is not our own bundle.
+ if (user.getBundle() != bundle) {
+ users.add(user);
+ }
+ }
+
+ public void unMarkUsed(BundleLoaderProxy user){
+ users.removeByKey(user.getKey());
+ }
+
+ public int getKeyHashCode() {
+ return key.hashCode();
+ }
+
+ public boolean compare(KeyedElement other) {
+ if (!(other instanceof BundleLoaderProxy))
+ return false;
+ BundleLoaderProxy otherLoaderProxy = (BundleLoaderProxy) other;
+ return (uniqueId.equals(otherLoaderProxy.uniqueId) &&
+ bundle.getVersion().isPerfect(otherLoaderProxy.bundle.getVersion()));
+ }
+
+ public Object getKey() {
+ return key;
+ }
+
+ public void setStale() {
+ stale = true;
+ }
+ public boolean isStale() {
+ return stale;
+ }
+
+ public boolean inUse(){
+ return (users.size() > 0);
+ }
+
+ public Bundle[] getDependentBundles() {
+ KeyedElement[] proxyLoaders = users.elements();
+ KeyedHashSet bundles = new KeyedHashSet(proxyLoaders.length,false);
+ for (int i=0; i<proxyLoaders.length; i++) {
+ BundleLoaderProxy loaderProxy = (BundleLoaderProxy) proxyLoaders[i];
+ bundles.add(loaderProxy.getBundle());
+ }
+
+ KeyedElement[] elements = bundles.elements();
+ Bundle[] result = new Bundle[elements.length];
+ System.arraycopy(elements,0,result,0,elements.length);
+
+ return result;
+ }
+
+ public String toString() {
+ return bundle.getLocation();
+ }
+
+ protected void markDependencies(){
+ if (markedUsedDependencies || !bundle.isResolved()) {
+ return;
+ }
+ markedUsedDependencies = true;
+
+ BundleDescription bundleDes = bundle.getBundleDescription();
+ if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
+ if (bundleDes == null) {
+ Debug.println("Bundle.resolved called and getBundleDescription returned null: " + this);
+ Debug.printStackTrace(new Exception("Stack trace"));
+ }
+ }
+
+ PackageSpecification[] packages = bundleDes.getPackages();
+ BundleSpecification[] requiredBundles = bundleDes.getRequiredBundles();
+ BundleDescription[] fragDescriptions = bundleDes.getFragments();
+
+ markUsedPackages(packages);
+ markUsedBundles(requiredBundles);
+
+ for (int i=0; i<fragDescriptions.length; i++) {
+ if (fragDescriptions[i].isResolved()) {
+ markUsedPackages(fragDescriptions[i].getPackages());
+ markUsedBundles(fragDescriptions[i].getRequiredBundles());
+ }
+ }
+
+ // besure to create the BundleLoader;
+ getBundleLoader();
+ }
+
+ private void markUsedPackages(PackageSpecification[] packages) {
+ if (packages!=null) {
+ for (int i=0; i<packages.length; i++) {
+ SingleSourcePackage packagesource =
+ (SingleSourcePackage) bundle.framework.packageAdmin.exportedPackages.getByKey(packages[i].getName());
+ if (packagesource != null) {
+ packagesource.getSupplier().markUsed(this);
+ }
+ }
+ }
+ }
+
+ private void markUsedBundles(BundleSpecification[] requiredBundles) {
+ if (requiredBundles != null) {
+ for (int i=0; i<requiredBundles.length; i++) {
+ if (requiredBundles[i].isResolved()) {
+ String bundleKey = new StringBuffer(requiredBundles[i].getName()).append("_").append(requiredBundles[i].getActualVersion().toString()).toString();
+
+ BundleLoaderProxy loaderProxy =
+ (BundleLoaderProxy) bundle.framework.packageAdmin.exportedBundles.getByKey(bundleKey);
+ if (loaderProxy != null) {
+ loaderProxy.markUsed(this);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleNativeCode.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleNativeCode.java
new file mode 100644
index 000000000..6f3cbdb80
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleNativeCode.java
@@ -0,0 +1,530 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.eclipse.osgi.framework.adaptor.Version;
+import org.eclipse.osgi.framework.util.ManifestElement;
+import org.osgi.framework.Constants;
+
+/**
+ * This class represents a description of native code.
+ *
+ * Native Code dependencies
+ *
+ * The Bundle-NativeCode header allows a bundle to carry the native code it
+ * needs, and make use of it when it is installed. The bundle must have
+ * RuntimePermission in order to run native code in the Framework. The value
+ * of the header must conform to the following syntax:
+ *
+ *
+ * Bundle-NativeCode: nativecode-clause ( , nativecode-clause)*
+ * nativecode-clause: nativepaths ( ; env-parameter )*
+ * nativepaths: nativepath ( ; nativepath )*
+ * env-parameter: ( processordef | osnamedef | osversiondef | languagedef )
+ * processordef: <I>processor=</I>token
+ * osnamedef: <I>osname=</I>token
+ * osversiondef: <I>osversion=</I>token
+ * languagedef: <I>language=</I>token
+ *
+ * For example:
+ *
+ * Bundle-NativeCode: http.dll ; osname=Win95; processor=x86; language=en,
+ * libhttp.so; osname=Solaris; processor=sparc
+ *
+ * The Bundle-NativeCode header allows a bundle programmer to specify an
+ * environment, and to declare what native code libraries it carries for that
+ * specific environment. The environment is characterized by the following
+ * properties:
+ *
+ * <UL>
+ * <LI><CODE>processor</CODE> The processor on which the hosting the Framework is running.
+ * It is compared against <CODE>org.osgi.framework.processor</CODE>.
+ * <LI><CODE>osname</CODE> The operating system name.
+ * It is compared against <CODE>org.osgi.framework.os.name</CODE>.
+ * <LI><CODE>osversion</CODE> The version of the operating system.
+ * It is compared against <CODE>org.osgi.framework.os.version</CODE>.
+ * <LI><CODE>language</CODE> The language.
+ * It is compared against <CODE>org.osgi.framework.language</CODE>.
+ * </UL>
+ *
+ * These properties should follow the conventions and values defined in the
+ * "Open Software Description" specification.
+ *
+ * The Framework uses the following algorithm to find the "best" matching
+ * native code clause:
+ *
+ * <ol>
+ * <li>
+ * Pick the clauses with a matching processor and operating system with the
+ * one the Framework runs on. If
+ * no clause matches both the required processor and operating system, the
+ * bundle installation/activation fails. If only one clause matches, it can
+ * be used, otherwise, remaining steps are executed.
+ * </li>
+ * <li>
+ * Pick the clauses that best match the operating system version.
+ * If they match each
+ * other exactly, that clause is considered the best match. If there is only
+ * one clause with an exact match, it can be used. If there are more than
+ * one clause that matches the property, these clauses will be picked to
+ * perform the next step. Operating system versions are taken to be backward
+ * compatible. If there is no exact match in the clauses, clauses with
+ * operating system versions lower than the value specified in
+ * org.osgi.framework.osversion will be picked. If there is only one
+ * clause which has a compatible operating system version, it can be used.
+ * Otherwise, all clauses with compatible operating system versions will go
+ * through the next step. If no clause has a matching or compatible
+ * operating system version, pick the clause that does not have operating
+ * system version specified. If that is not possible, the bundle
+ * installation fails.
+ * </li>
+ * <li>
+ * Pick the clause that best matches the language. If
+ * more than one clause remains at that point, then the Framework is free to
+ * pick amongst them randomly. If no clauses have the exact match with the
+ * value of the property, pick the clause that does not have language
+ * specified. If that is not possible, the bundle installation fails.
+ * </li>
+ * </ol>
+ *
+ */
+public class BundleNativeCode
+{
+ /**
+ * The Native Code paths for the Native Code entry
+ */
+ private Attribute nativepaths;
+
+ /**
+ * The processor attribute for this Native Code entry
+ */
+ private Attribute processor;
+
+ /**
+ * The osname attribute for this Native Code entry
+ */
+ private Attribute osname;
+
+ /**
+ * The language attribute for this Native Code entry
+ */
+ private Attribute language;
+
+ /**
+ * The osversion attribute for this Native Code entry
+ */
+ private Attribute osversion;
+
+ /**
+ * The windowingsystem attribute for this Native Code entry
+ */
+ private Attribute windowingsystem;
+
+ /**
+ * The AliasMapper used to alias OS Names.
+ */
+ private static AliasMapper aliasMapper = new AliasMapper();
+
+ /**
+ * Constructor.
+ *
+ */
+ protected BundleNativeCode(ManifestElement element)
+ {
+ StringTokenizer st = new StringTokenizer(element.getValue(),";");
+ while (st.hasMoreTokens()) {
+ addPath(st.nextToken());
+ }
+
+ String attrValue = element.getAttribute(Constants.BUNDLE_NATIVECODE_OSNAME);
+ if (attrValue!=null){
+ StringTokenizer attrSt = new StringTokenizer(attrValue,",");
+ while(attrSt.hasMoreTokens()) {
+ addAttribute(Constants.BUNDLE_NATIVECODE_OSNAME,attrSt.nextToken());
+ }
+ }
+
+ attrValue = element.getAttribute(Constants.BUNDLE_NATIVECODE_PROCESSOR);
+ if (attrValue!=null){
+ StringTokenizer attrSt = new StringTokenizer(attrValue,",");
+ while(attrSt.hasMoreTokens()) {
+ addAttribute(Constants.BUNDLE_NATIVECODE_PROCESSOR,attrSt.nextToken());
+ }
+ }
+
+ attrValue = element.getAttribute(Constants.BUNDLE_NATIVECODE_OSVERSION);
+ if (attrValue!=null){
+ StringTokenizer attrSt = new StringTokenizer(attrValue,",");
+ while(attrSt.hasMoreTokens()) {
+ addAttribute(Constants.BUNDLE_NATIVECODE_OSVERSION,attrSt.nextToken());
+ }
+ }
+
+ attrValue = element.getAttribute(Constants.BUNDLE_NATIVECODE_LANGUAGE);
+ if (attrValue!=null){
+ StringTokenizer attrSt = new StringTokenizer(attrValue,",");
+ while(attrSt.hasMoreTokens()) {
+ addAttribute(Constants.BUNDLE_NATIVECODE_LANGUAGE,attrSt.nextToken());
+ }
+ }
+
+ attrValue = element.getAttribute(Constants.BUNDLE_NATIVECODE_WINDOWING_SYSTEM);
+ if (attrValue!=null){
+ StringTokenizer attrSt = new StringTokenizer(attrValue,",");
+ while(attrSt.hasMoreTokens()) {
+ addAttribute(Constants.BUNDLE_NATIVECODE_WINDOWING_SYSTEM,attrSt.nextToken());
+ }
+ }
+ }
+
+ /**
+ * Returns the native code paths.
+ *
+ * @return Vector of String code paths.
+ */
+ public String[] getPaths()
+ {
+ if(nativepaths == null){
+ return null;
+ }
+ String[] paths = new String[nativepaths.size()];
+ nativepaths.toArray(paths);
+
+ return(paths);
+ }
+
+ /**
+ * addPath is used to add a new element to the list of native
+ * files.
+ *
+ * @param nativepath new native file
+ */
+ protected void addPath(String nativepath)
+ {
+ if (nativepaths == null)
+ {
+ nativepaths = new Attribute();
+ }
+
+ nativepaths.addElement(nativepath);
+ }
+
+ /**
+ * addAttribute is used to add the specification-version string to the package
+ * description. It is the only key supported at this time.
+ *
+ * @param key attribute key name
+ * @param value attribute value name
+ */
+ protected synchronized void addAttribute(String key, String value)
+ {
+ if (key.equals(Constants.BUNDLE_NATIVECODE_PROCESSOR))
+ {
+ if (processor == null)
+ {
+ processor = new Attribute();
+ }
+
+ processor.addElement(aliasMapper.aliasProcessor(value));
+ return;
+ }
+ if (key.equals(Constants.BUNDLE_NATIVECODE_OSNAME))
+ {
+ if (osname == null)
+ {
+ osname = new Attribute();
+ }
+
+ osname.addElement(aliasMapper.aliasOSName(value));
+ return;
+ }
+ if (key.equals(Constants.BUNDLE_NATIVECODE_OSVERSION))
+ {
+ if (osversion == null)
+ {
+ osversion = new Attribute();
+ }
+
+ osversion.addElement(new Version(value));
+ return;
+ }
+ if (key.equals(Constants.BUNDLE_NATIVECODE_LANGUAGE))
+ {
+ if (language == null)
+ {
+ language = new Attribute();
+ }
+
+ language.addElement(value.toLowerCase());
+ return;
+ }
+ if (key.equals(Constants.BUNDLE_NATIVECODE_WINDOWING_SYSTEM))
+ {
+ if (windowingsystem == null)
+ {
+ windowingsystem = new Attribute();
+ }
+
+ windowingsystem.addElement(value.toLowerCase());
+ return;
+ }
+ }
+
+ /**
+ * Override toString. Return a String representation of this object
+ *
+ * @return String representation of the object
+ */
+ public String toString()
+ {
+ Vector nativepaths = this.nativepaths;
+ int size = nativepaths.size();
+ StringBuffer sb = new StringBuffer(50 * size);
+
+ for (int i = 0; i < size; i++)
+ {
+ if (i > 0)
+ {
+ sb.append(';');
+ }
+ sb.append(nativepaths.elementAt(i).toString());
+ }
+
+ if (processor != null)
+ {
+ size = processor.size();
+ for (int i = 0; i < size; i++)
+ {
+ sb.append(';');
+ sb.append(Constants.BUNDLE_NATIVECODE_PROCESSOR);
+ sb.append('=');
+ sb.append(processor.elementAt(i).toString());
+ }
+ }
+
+ if (osname != null)
+ {
+ size = osname.size();
+ for (int i = 0; i < size; i++)
+ {
+ sb.append(';');
+ sb.append(Constants.BUNDLE_NATIVECODE_OSNAME);
+ sb.append('=');
+ sb.append(osname.elementAt(i).toString());
+ }
+ }
+
+ if (osversion != null)
+ {
+ size = osversion.size();
+ for (int i = 0; i < size; i++)
+ {
+ sb.append(';');
+ sb.append(Constants.BUNDLE_NATIVECODE_OSVERSION);
+ sb.append('=');
+ sb.append(osversion.elementAt(i).toString());
+ }
+ }
+
+ if (language != null)
+ {
+ size = language.size();
+ for (int i = 0; i < size; i++)
+ {
+ sb.append(';');
+ sb.append(Constants.BUNDLE_NATIVECODE_LANGUAGE);
+ sb.append('=');
+ sb.append(language.elementAt(i).toString());
+ }
+ }
+
+ if (windowingsystem != null)
+ {
+ size = windowingsystem.size();
+ for (int i = 0; i < size; i++)
+ {
+ sb.append(';');
+ sb.append(Constants.BUNDLE_NATIVECODE_WINDOWING_SYSTEM);
+ sb.append('=');
+ sb.append(windowingsystem.elementAt(i).toString());
+ }
+ }
+
+ return(sb.toString());
+ }
+
+ /**
+ * Return the match value for the given processor and os name.
+ * A higher value indicates a better match.
+ *
+ * @param processor processor name to match against.
+ * @param osname os name to match against.
+ * @return match value
+ */
+ public int matchProcessorOSName(String processor, String osname)
+ {
+ if ((this.processor == null) || (this.osname == null))
+ {
+ return(0);
+ }
+
+ String otherProcessor = aliasMapper.aliasProcessor(processor);
+ String otherOSName = aliasMapper.aliasOSName(osname);
+
+ if (this.processor.equals(otherProcessor) &&
+ this.osname.equals(otherOSName))
+ {
+ return(1);
+ }
+
+ return(0);
+ }
+
+
+ /**
+ * Return the higest matching value for the given os version
+ * that is less than or equal to the given os version.
+ *
+ * @param version os version to match against.
+ * @return version or null if no match.
+ */
+ public org.eclipse.osgi.framework.adaptor.Version matchOSVersion(org.eclipse.osgi.framework.adaptor.Version version)
+ {
+ if (this.osversion == null)
+ {
+ return Version.emptyVersion;
+ }
+
+ Version result = null;
+ int size = this.osversion.size();
+
+ for (int i = 0; i < size; i++)
+ {
+ Version ver = (Version)this.osversion.elementAt(i);
+ int compare = ver.compareTo(version);
+
+ if (compare == 0) /* versions are equal; best possible match */
+ {
+ return ver;
+ }
+
+ if (compare < 0) /* requested version < current OS version */
+ {
+ if ((result == null) || (ver.compareTo(result) > 0))
+ {
+ result = ver; /* remember the highest version less than osversion */
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Return the match value for the given language.
+ * A higher value indicates a better match.
+ *
+ * @param language language name to match against.
+ * @return match value
+ */
+ public int matchLanguage(String language)
+ {
+ if (this.language == null)
+ {
+ return(1);
+ }
+
+ if (this.language.equals(language.toLowerCase()))
+ {
+ return(2);
+ }
+
+ return(0);
+ }
+
+ /**
+ * Return the match value for the given windowing system.
+ * A higher value indicates a better match.
+ *
+ * @param ws windowing system to match against.
+ * @return match value
+ */
+ public int matchWindowingSystem(String runtimeWS)
+ {
+ if(runtimeWS == null)
+ {
+ if(this.windowingsystem == null)
+ {
+ return(1);
+ }
+ return (0);
+ }
+ else
+ {
+ if (this.windowingsystem.equals(runtimeWS.toLowerCase()))
+ {
+ return(2);
+ }
+ return(0);
+ }
+ }
+
+ /**
+ * Extension of Vector for attributes.
+ */
+ static class Attribute extends Vector
+ {
+ /**
+ * Attribute constructor.
+ *
+ */
+ Attribute()
+ {
+ super(10, 10);
+ }
+
+ /**
+ * Perform an "OR" operation on equals.
+ *
+ * @param obj Object to test against.
+ * @return true if at least one attribute is equal; false otherwise.
+ */
+ public synchronized boolean equals(Object obj)
+ {
+ for (int i = 0; i < elementCount; i++)
+ {
+ if (elementData[i].equals(obj))
+ {
+ return(true);
+ }
+ }
+
+ return(false);
+ }
+
+ /**
+ * Add the object if it is not already in the vector.
+ *
+ * @param obj Object to add to the vector.
+ */
+ public synchronized void addElement(Object obj)
+ {
+ if (!contains(obj))
+ {
+ super.addElement(obj);
+ }
+ }
+ }
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundlePermissionCollection.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundlePermissionCollection.java
new file mode 100644
index 000000000..1c386d335
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundlePermissionCollection.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.security.PermissionCollection;
+import java.util.Hashtable;
+
+/**
+ * An abstract subclass of PermissionCollection.
+ *
+ */
+abstract class BundlePermissionCollection extends PermissionCollection
+{
+ /**
+ * The Permission collection will unresolve the permissions in these packages.
+ *
+ * @param unresolvedPackages A list of the package which have been unresolved
+ * as a result of a packageRefresh
+ */
+ abstract void unresolvePermissions(Hashtable unresolvedPackages);
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundlePermissions.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundlePermissions.java
new file mode 100644
index 000000000..74f149e4f
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundlePermissions.java
@@ -0,0 +1,344 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.security.AllPermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.NoSuchElementException;
+import java.util.Vector;
+
+import org.eclipse.osgi.framework.debug.Debug;
+
+/**
+ * A heterogeneous collection of permissions for a bundle.
+ *
+ */
+final class BundlePermissions extends BundlePermissionCollection
+{
+ /**
+ * Maps a Permission's class to an appropriate PermissionCollection.
+ * Class => PermissionCollection
+ */
+ private Hashtable collections = new Hashtable(8);
+
+ /**
+ * Set to an AllPermissionCollection if this Permissions contains AllPermission.
+ */
+ private PermissionCollection allPermission;
+
+ /** Used to load classes for unresolved permissions */
+ private PackageAdmin packageAdmin;
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ */
+ BundlePermissions(PackageAdmin packageAdmin)
+ {
+ super();
+
+ this.packageAdmin = packageAdmin;
+ }
+
+
+ /**
+ * Adds the argument to the collection.
+ *
+ * @param permission java.security.Permission
+ * the permission to add to the collection
+ */
+ public void add(Permission permission)
+ {
+ if (isReadOnly())
+ {
+ throw new SecurityException();
+ }
+
+ PermissionCollection collection;
+
+ synchronized (collections)
+ {
+ collection = findCollection(permission);
+
+ if (collection == null)
+ {
+ collection = newPermissionCollection(permission);
+ }
+ }
+
+ if (permission instanceof AllPermission)
+ {
+ allPermission = collection;
+ }
+
+ collection.add(permission);
+ }
+
+ /**
+ * Answers an enumeration of the permissions
+ * in the receiver.
+ *
+ * @return Enumeration
+ * the permissions in the receiver.
+ */
+ public Enumeration elements()
+ {
+ return new Enumeration() {
+ Enumeration enumMap = collections.elements();
+ PermissionCollection c;
+ Enumeration enumC;
+ Permission next = findNextPermission();
+
+ public boolean hasMoreElements()
+ {
+ return(next != null);
+ }
+
+ public Object nextElement()
+ {
+ if (next == null)
+ {
+ throw new NoSuchElementException();
+ }
+ else
+ {
+ Object answer = next;
+ next = findNextPermission();
+ return(answer);
+ }
+ }
+
+ // This method is the important one. It looks for and
+ // answers the next available permission. If there are
+ // no permissions left to return, it answers null.
+ private Permission findNextPermission()
+ {
+ // Loop until we get a collection with at least one element.
+ while (c == null && enumMap.hasMoreElements())
+ {
+ c = (PermissionCollection) enumMap.nextElement();
+ enumC = c.elements();
+ if (!enumC.hasMoreElements())
+ c = null;
+ }
+ // At this point, c == null if there are no more elements,
+ // and otherwise is the first collection with a free element
+ // (with enumC set up to return that element).
+ if (c == null)
+ {
+ // no more elements, so return null;
+ return(null);
+ }
+ else
+ {
+ Permission answer = (Permission) enumC.nextElement();
+ if (!enumC.hasMoreElements())
+ c = null;
+ return(answer);
+ }
+ }
+ };
+ }
+
+ /**
+ * Find the appropriate permission collection to use for
+ * the given permission.
+ *
+ * @param permission Permission
+ * the permission to find a collection for
+ * @return PermissionCollection
+ * the collection to use with the permission.
+ */
+ private PermissionCollection findCollection(Permission permission)
+ {
+ Class clazz = permission.getClass();
+
+ PermissionCollection collection = (PermissionCollection) collections.get(clazz);
+
+ if (collection == null)
+ {
+ synchronized (collections)
+ {
+ collection = (PermissionCollection) collections.get(clazz);
+
+ if (collection == null)
+ {
+ collection = resolvePermissions(permission);
+ }
+ }
+ }
+
+ return collection;
+ }
+
+ /**
+ * This method will attempt to resolve unresolved permissions of the
+ * type of the specified permission.
+ *
+ * This method should only be called while holding the collections lock.
+ *
+ * @param permission Permission whose type we shall attempt to resolve.
+ * @return A PermissionCollection for the resolved permissions or
+ * <tt>null</tt> if the permissions cannot currently be resolved.
+ */
+ private PermissionCollection resolvePermissions(Permission permission)
+ {
+ UnresolvedPermissionCollection unresolvedCollection = (UnresolvedPermissionCollection)collections.get(UnresolvedPermission.class);
+
+ if (unresolvedCollection != null)
+ {
+ String name = permission.getClass().getName();
+
+ Vector permissions = unresolvedCollection.getPermissions(name);
+
+ if (permissions != null)
+ {
+ PermissionCollection collection = null;
+ Class clazz;
+
+ try
+ {
+ // We really need to resolve the permission
+ // by loading it only from the proper classloader,
+ // i.e. the system classloader or and exporting bundle's
+ // classloader. Otherwise there is a security hole.
+
+ // TODO It is unclear how this works in the world of modules and multiple
+ // versions. Just loading up any old class with the right name does not seem
+ // appropriate. For now just put in a dummy classload call to reduce code impact.
+ clazz = Class.forName(name);
+// clazz = packageAdmin.loadClass(name);
+ }
+ catch (ClassNotFoundException e)
+ {
+ return null;
+ }
+
+ Enumeration enum = permissions.elements();
+
+ while (enum.hasMoreElements())
+ {
+ Permission resolved = ((UnresolvedPermission)enum.nextElement()).resolve(clazz);
+
+ if (resolved != null)
+ {
+ if (collection == null)
+ {
+ collection = newPermissionCollection(resolved);
+ }
+
+ collection.add(resolved);
+ }
+ }
+
+ return collection;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Creates a PermissionCollection suitable to hold the specified permission.
+ * The created collection is added to the collections Hashtable.
+ *
+ * This method should only be called while holding the collections lock.
+ */
+ private PermissionCollection newPermissionCollection(Permission permission)
+ {
+ PermissionCollection collection = permission.newPermissionCollection();
+
+ if (collection == null)
+ {
+ collection = new PermissionsHash();
+ }
+
+ collections.put(permission.getClass(), collection);
+
+ return collection;
+ }
+
+ /**
+ * Indicates whether the argument permission is implied
+ * by the permissions contained in the receiver.
+ *
+ * @return boolean
+ * <code>true</code> if the argument permission
+ * is implied by the permissions in the receiver,
+ * and <code>false</code> if it is not.
+ * @param perm java.security.Permission
+ * the permission to check
+ */
+ public boolean implies(Permission perm)
+ {
+ if ((allPermission != null) && allPermission.implies(perm))
+ {
+ return true;
+ }
+
+ PermissionCollection collection = findCollection(perm);
+
+ if (collection == null)
+ {
+ return false;
+ }
+
+ return collection.implies(perm);
+ }
+
+ /**
+ * The Permission collection will unresolve the permissions in these packages.
+ *
+ * @param unresolvedPackages A list of the package which have been unresolved
+ * as a result of a packageRefresh
+ */
+ void unresolvePermissions(Hashtable unresolvedPackages)
+ {
+ synchronized (collections)
+ {
+ int size = collections.size();
+
+ Class[] clazzes = new Class[size];
+ Enumeration enum = collections.keys();
+
+ for (int i = 0; i < size; i++)
+ {
+ clazzes[i] = (Class)enum.nextElement();
+ }
+
+ for (int i = 0; i < size; i++)
+ {
+ Class clazz = clazzes[i];
+
+ String name = clazz.getName();
+
+ int index = name.lastIndexOf('.'); /* find last period in class name */
+
+ if (index > 0)
+ {
+ if (unresolvedPackages.get(name.substring(0, index)) != null)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_SECURITY)
+ {
+ Debug.println(" Unresolving permission class "+name);
+ }
+
+ collections.remove(clazz);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleRepository.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleRepository.java
new file mode 100644
index 000000000..6fb69fe6d
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleRepository.java
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.eclipse.osgi.framework.adaptor.Version;
+
+public class BundleRepository {
+ /** bundles by install order */
+ private ArrayList bundlesByInstallOrder;
+
+ /** bundles keyed by bundle Id */
+ private KeyedHashSet bundlesById;
+
+ /** bundles keyed by GlobalName */
+ private Hashtable bundlesByGlobalName;
+
+ /** PackageAdmin */
+ private PackageAdmin packageAdmin;
+
+ public BundleRepository(int initialCapacity, PackageAdmin packageAdmin) {
+ bundlesByInstallOrder = new ArrayList(initialCapacity);
+ bundlesById = new KeyedHashSet(initialCapacity,true);
+ bundlesByGlobalName = new Hashtable(initialCapacity);
+ this.packageAdmin = packageAdmin;
+ }
+
+ /**
+ * Gets a list of bundles ordered by install order.
+ * @return List of bundles by install order.
+ */
+ public List getBundles() {
+ return bundlesByInstallOrder;
+ }
+
+ /**
+ * Gets a bundle by its bundle Id.
+ * @param bundleId
+ * @return
+ */
+ public Bundle getBundle(long bundleId) {
+ Long key = new Long(bundleId);
+ return (Bundle)bundlesById.getByKey(key);
+ }
+
+ public Bundle[] getBundles(String globalName) {
+ return (Bundle[]) bundlesByGlobalName.get(globalName);
+ }
+
+ public Bundle getBundle(String globalName, String version){
+ ArrayList list = (ArrayList) bundlesByGlobalName.get(globalName);
+ if (list != null) {
+ Version ver = new Version(version);
+ int size = list.size();
+ if (size>0) {
+ for(int i=0; i<size; i++) {
+ Bundle bundle = (Bundle) list.get(i);
+ if (bundle.getVersion().isPerfect(ver)) {
+ return bundle;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public void add(Bundle bundle) {
+ bundlesByInstallOrder.add(bundle);
+ bundlesById.add(bundle);
+ String globalName = bundle.getGlobalName();
+ if (globalName != null) {
+ Bundle[] bundles = (Bundle[]) bundlesByGlobalName.get(globalName);
+ if (bundles == null) {
+ // making the initial capacity on this 1 since it
+ // should be rare that multiple version exist
+ bundles = new Bundle[1];
+ bundles[0] = bundle;
+ bundlesByGlobalName.put(globalName,bundles);
+ return;
+ }
+ ArrayList list = new ArrayList(bundles.length+1);
+ // find place to insert the bundle
+ Version newVersion = bundle.getVersion();
+ boolean added = false;
+ for (int i=0; i<bundles.length; i++) {
+ Bundle oldBundle = bundles[i];
+ Version oldVersion = oldBundle.getVersion();
+ if (!added && newVersion.isGreaterOrEqualTo(oldVersion)){
+ added = true;
+ list.add(bundle);
+ }
+ list.add(oldBundle);
+ }
+ if (!added) {
+ list.add(bundle);
+ }
+
+ list.toArray(bundles);
+ bundlesByGlobalName.put(globalName,bundles);
+ }
+ }
+
+ public boolean remove(Bundle bundle) {
+ boolean removed = bundlesById.remove(bundle);
+ if (removed) {
+ bundlesByInstallOrder.remove(bundle);
+ String globalName = bundle.getGlobalName();
+ if (globalName != null) {
+ ArrayList list = (ArrayList) bundlesByGlobalName.get(globalName);
+ if (list != null) {
+ list.remove(bundle);
+ }
+ }
+ }
+ return removed;
+ }
+
+ public void removeAllBundles() {
+ bundlesByInstallOrder.clear();
+ bundlesById = new KeyedHashSet();
+ bundlesByGlobalName.clear();
+ }
+
+ public synchronized void markDependancies() {
+ KeyedElement[] elements = bundlesById.elements();
+ for(int i=0; i<elements.length; i++) {
+ if (elements[i] instanceof BundleHost) {
+ ((BundleHost)elements[i]).getLoaderProxy().markDependencies();
+ }
+ }
+ }
+
+ public synchronized void unMarkDependancies(BundleLoaderProxy user) {
+ KeyedElement[] elements = bundlesById.elements();
+ for(int i=0; i<elements.length; i++) {
+ if (elements[i] instanceof BundleHost) {
+ BundleLoaderProxy loaderProxy = ((BundleHost)elements[i]).getLoaderProxy();
+ loaderProxy.unMarkUsed(user);
+ }
+ }
+
+ // look in removal pending
+ int size = packageAdmin.removalPending.size();
+ for (int i=0; i<size; i++) {
+ BundleLoaderProxy loaderProxy = (BundleLoaderProxy) packageAdmin.removalPending.elementAt(i);
+ loaderProxy.unMarkUsed(user);
+ }
+ user.markedUsedDependencies = false;
+ }
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleResourcePermission.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleResourcePermission.java
new file mode 100644
index 000000000..6875a17b4
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleResourcePermission.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.security.Permission;
+
+/**
+ * Implementation specific permission to read a bundle's resources.
+ *
+ */
+
+final class BundleResourcePermission extends Permission
+{
+ private long id;
+
+ BundleResourcePermission(long id)
+ {
+ super(String.valueOf(id));
+
+ this.id = id;
+ }
+
+ BundleResourcePermission(String id)
+ {
+ super(id);
+
+ this.id = Long.parseLong(id);
+ }
+
+ /**
+ * Determines if the specified permission is implied by this object.
+ *
+ * @param p The target permission to interrogate.
+ * @return <tt>true</tt> if the specified permission is implied by
+ * this object; <tt>false</tt> otherwise.
+ */
+
+ public boolean implies(Permission p)
+ {
+ if (p instanceof BundleResourcePermission)
+ {
+ BundleResourcePermission target = (BundleResourcePermission) p;
+
+ return this.id == target.id;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the empty String.
+ */
+
+ public String getActions()
+ {
+ return "";
+ }
+
+ /**
+ * Determines the equality of two <tt>BundleResourcePermission</tt> objects.
+ *
+ * @param obj The object to test for equality with this object.
+ * @return <tt>true</tt> if <tt><i>obj</i></tt> is a <tt>BundleResourcePermission</tt>, and has the
+ * same bundle id this object; <tt>false</tt> otherwise.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return(true);
+ }
+
+ if (!(obj instanceof BundleResourcePermission))
+ {
+ return(false);
+ }
+
+ BundleResourcePermission target = (BundleResourcePermission) obj;
+
+ return this.id == target.id;
+ }
+
+ /**
+ * Returns the hash code value for this object.
+ *
+ * @return A hash code value for this object.
+ */
+
+ public int hashCode()
+ {
+ return getName().hashCode();
+ }
+}
+
+
+
+
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleSource.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleSource.java
new file mode 100644
index 000000000..436f09f04
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleSource.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLConnection;
+
+/**
+ * BundleSource class to wrap in InputStream.
+ *
+ * <p>This class implements a URLConnection which
+ * wraps an InputStream.
+ */
+public class BundleSource extends URLConnection
+{
+ private InputStream in;
+
+ protected BundleSource(InputStream in)
+ {
+ super(null);
+ this.in = in;
+ }
+
+ public void connect() throws IOException
+ {
+ connected = true;
+ }
+
+ public InputStream getInputStream() throws IOException
+ {
+ return(in);
+ }
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Constants.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Constants.java
new file mode 100644
index 000000000..129918fe8
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Constants.java
@@ -0,