diff options
author | Thomas Watson | 2013-06-21 17:22:50 +0000 |
---|---|---|
committer | Thomas Watson | 2013-07-18 20:21:26 +0000 |
commit | 2d9f0da79b5fda166e19b0d4af79f638da3ff332 (patch) | |
tree | 76edc46ba56364d5344212caa016e1e6f1c2678d /bundles | |
parent | 74dbf9088435ef5cfed74f1265f7509f7472c5cd (diff) | |
download | rt.equinox.framework-2d9f0da79b5fda166e19b0d4af79f638da3ff332.tar.gz rt.equinox.framework-2d9f0da79b5fda166e19b0d4af79f638da3ff332.tar.xz rt.equinox.framework-2d9f0da79b5fda166e19b0d4af79f638da3ff332.zip |
Bug 411404 - Build from source for osgi.services and osgi.util bundles
Diffstat (limited to 'bundles')
211 files changed, 13823 insertions, 402 deletions
diff --git a/bundles/org.eclipse.osgi.services/.classpath b/bundles/org.eclipse.osgi.services/.classpath index 6b1debc73..64c5e31b7 100644 --- a/bundles/org.eclipse.osgi.services/.classpath +++ b/bundles/org.eclipse.osgi.services/.classpath @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> - <classpathentry path="" kind="lib" exported="true" sourcepath="src.zip"/> - <classpathentry path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/OSGi%Minimum-1.2" kind="con"/> - <classpathentry path="org.eclipse.pde.core.requiredPlugins" kind="con"/> - <classpathentry path="bin" kind="output"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="output" path="bin"/> </classpath> diff --git a/bundles/org.eclipse.osgi.services/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.osgi.services/.settings/org.eclipse.jdt.core.prefs index 8e730b080..db619c076 100644 --- a/bundles/org.eclipse.osgi.services/.settings/org.eclipse.jdt.core.prefs +++ b/bundles/org.eclipse.osgi.services/.settings/org.eclipse.jdt.core.prefs @@ -1,4 +1,3 @@ -#Tue Dec 02 09:03:08 CST 2008 eclipse.preferences.version=1 org.eclipse.jdt.core.builder.cleanOutputFolder=clean org.eclipse.jdt.core.builder.duplicateResourceTask=warning @@ -7,24 +6,24 @@ org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch org.eclipse.jdt.core.circularClasspath=error org.eclipse.jdt.core.classpath.exclusionPatterns=enabled org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=disabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.4 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.doc.comment.support=enabled org.eclipse.jdt.core.compiler.maxProblemPerUnit=1000 org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning -org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.autoboxing=ignore org.eclipse.jdt.core.compiler.problem.deprecation=warning org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled org.eclipse.jdt.core.compiler.problem.discouragedReference=error org.eclipse.jdt.core.compiler.problem.emptyStatement=warning -org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.fieldHiding=warning org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning @@ -71,6 +70,6 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=en org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning -org.eclipse.jdt.core.compiler.source=1.3 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.incompatibleJDKLevel=ignore org.eclipse.jdt.core.incompleteClasspath=error diff --git a/bundles/org.eclipse.osgi.services/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi.services/META-INF/MANIFEST.MF index 747dae5f4..fcd6ae66f 100644 --- a/bundles/org.eclipse.osgi.services/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.osgi.services/META-INF/MANIFEST.MF @@ -2,19 +2,18 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %osgiServices Bundle-SymbolicName: org.eclipse.osgi.services -Bundle-Version: 3.3.100.qualifier +Bundle-Version: 3.4.0.qualifier Bundle-Description: %osgiServicesDes Bundle-Localization: plugin Bundle-Vendor: %eclipse.org Bundle-DocUrl: http://www.eclipse.org Bundle-ContactAddress: www.eclipse.org -Export-Package: org.osgi.service.cm; version="1.4", - org.osgi.service.component; version="1.2", +Export-Package: org.osgi.service.cm; version="1.5", + org.osgi.service.component; version="1.2.2", org.osgi.service.component.annotations; version="1.2", org.osgi.service.device; version="1.1", org.osgi.service.event; version="1.3", org.osgi.service.http; version="1.2.1", - org.osgi.service.io; version="1.0", org.osgi.service.log; version="1.3", org.osgi.service.metatype; version="1.2", org.osgi.service.provisioning; version="1.2", @@ -22,12 +21,12 @@ Export-Package: org.osgi.service.cm; version="1.4", org.osgi.service.useradmin; version="1.1", org.osgi.service.wireadmin; version="1.0.1" Import-Package: org.osgi.framework; version=1.6, - org.osgi.service.cm; version="[1.4, 1.5)", - org.osgi.service.component; version="[1.2, 1.3)", + org.osgi.service.cm; version="[1.5, 1.6)", + org.osgi.service.component; version="[1.2.2, 1.3)", + org.osgi.service.component.annotations; version="[1.2, 1.3)", org.osgi.service.device; version="[1.1, 1.2)", org.osgi.service.event; version="[1.3, 1.4)", org.osgi.service.http; version="[1.2.1, 1.3)", - org.osgi.service.io; version="[1.0, 1.1)", org.osgi.service.log; version="[1.3, 1.4)", org.osgi.service.metatype; version="[1.2, 1.3)", org.osgi.service.provisioning; version="[1.2, 1.3)", @@ -37,8 +36,5 @@ Import-Package: org.osgi.framework; version=1.6, javax.servlet; resolution:="optional", javax.servlet.http; resolution:="optional" DynamicImport-Package: javax.servlet, - javax.servlet.http, - javax.microedition.io -Bundle-RequiredExecutionEnvironment: OSGi/Minimum-1.2, - CDC-1.1/Foundation-1.1, - J2SE-1.4 + javax.servlet.http +Bundle-RequiredExecutionEnvironment: J2SE-1.5 diff --git a/bundles/org.eclipse.osgi.services/build.properties b/bundles/org.eclipse.osgi.services/build.properties index cf8b197e9..88dcd9445 100644 --- a/bundles/org.eclipse.osgi.services/build.properties +++ b/bundles/org.eclipse.osgi.services/build.properties @@ -11,13 +11,10 @@ bin.includes = plugin.properties,\ about.html,\ META-INF/,\ - org/,\ about_files/ -src.includes = src.zip,\ - about.html,\ +src.includes = about.html,\ about_files/ -source.. = . -output.. = . -customBuildCallbacks=customBuildCallbacks.xml -javacSource = 1.5 -javacTarget = 1.5 + +source.. = src/ +output.. = bin/ +jars.extra.classpath = lib/osgi.annotation.jar
\ No newline at end of file diff --git a/bundles/org.eclipse.osgi.services/customBuildCallbacks.xml b/bundles/org.eclipse.osgi.services/customBuildCallbacks.xml deleted file mode 100644 index 91871121b..000000000 --- a/bundles/org.eclipse.osgi.services/customBuildCallbacks.xml +++ /dev/null @@ -1,162 +0,0 @@ -<!-- ===================================================================== --> -<!-- Custom targets called from a project's generated build.xml --> -<!-- Set customBuildCallbacks=<path/to/this/file> in your build.properties.--> -<!-- ===================================================================== --> -<project name="Build specific targets and properties" default="noDefault"> - - <!-- ===================================================================== --> - <!-- Default target --> - <!-- ===================================================================== --> - <target name="noDefault"> - <echo message="This file must be called with explicit targets" /> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do before the target build.jars --> - <!-- Available parameters : --> - <!-- build.result.folder - folder to contain the build results --> - <!-- ===================================================================== --> - <target name="pre.build.jars"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do after the target build.jars --> - <!-- Available parameters : --> - <!-- build.result.folder - folder to contain the build results --> - <!-- ===================================================================== --> - <target name="post.build.jars"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do before the target build.sources --> - <!-- Available parameters : --> - <!-- build.result.folder - folder to contain the build results --> - <!-- ===================================================================== --> - <target name="pre.build.sources"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do after the target build.sources --> - <!-- Available parameters : --> - <!-- build.result.folder - folder to contain the build results --> - <!-- ===================================================================== --> - <target name="post.build.sources"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do before the compilation target <name> --> - <!-- Substitute "name" with the name of the compilation target, eg @dot --> - <!-- Available parameters : --> - <!-- source.foldern : n = 1 ... N, the source folders --> - <!-- target.folder : where the results of the compilation go --> - <!-- <name>.classpath : name = name of the compilation target. A --> - <!-- reference to the classpath structure. --> - <!-- ===================================================================== --> - <target name="pre.name"> - </target> - - <target name="pre.@dot"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do during the compilation target <name>, after the compile --> - <!-- but before jaring. Substitute "name" with the name of the compilation--> - <!-- target, eg @dot --> - <!-- Available parameters : --> - <!-- source.foldern : n = 1 ... N, the source folders --> - <!-- target.folder : where the results of the compilation go --> - <!-- <name>.classpath : name = name of the compilation target. A --> - <!-- reference to the classpath structure. --> - <!-- ===================================================================== --> - <target name="post.compile.name"> - </target> - - <target name="post.compile.@dot"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do after the compilation target <name> --> - <!-- Substitute "name" with the name of the compilation target, eg @dot --> - <!-- Available parameters : --> - <!-- jar.location - the location of the compilation results --> - <!-- <name>.classpath : name = name of the compilation target. A --> - <!-- reference to the classpath structure. --> - <!-- ===================================================================== --> - <target name="post.name"> - </target> - - <target name="post.@dot"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do before the target gather.bin.parts --> - <!-- Available parameters : --> - <!-- build.result.folder - folder containing the build results --> - <!-- target.folder - destination folder --> - <!-- ===================================================================== --> - <target name="pre.gather.bin.parts"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do after the target gather.bin.parts --> - <!-- Available parameters : --> - <!-- build.result.folder - folder containing the build results --> - <!-- target.folder - destination folder --> - <!-- ===================================================================== --> - <target name="post.gather.bin.parts"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do before the target gather.sources --> - <!-- Available parameters : --> - <!-- destination.temp.folder - destination folder --> - <!-- ===================================================================== --> - <target name="pre.gather.sources"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do after the target gather.sources --> - <!-- Available parameters : --> - <!-- destination.temp.folder - destination folder --> - <!-- ===================================================================== --> - <target name="post.gather.sources"> - <unzip src="${target.folder}/src.zip" dest="${target.folder}" overwrite="false"/> - <delete file="${destination.temp.folder}/src.zip" /> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do before the target gather.logs --> - <!-- Available parameters : --> - <!-- destination.temp.folder - destination folder --> - <!-- ===================================================================== --> - <target name="pre.gather.logs"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do after the target gather.logs --> - <!-- Available parameters : --> - <!-- destination.temp.folder - destination folder --> - <!-- ===================================================================== --> - <target name="post.gather.logs"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do before the target clean --> - <!-- Available parameters : --> - <!-- destination.temp.folder - destination folder --> - <!-- ===================================================================== --> - <target name="pre.clean"> - <move file="src.zip" tofile="services_src.zip"/> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do after the target clean --> - <!-- Available parameters : --> - <!-- plugin.destination - final destination of the build --> - <!-- build.result.folder - results of the compilation --> - <!-- temp.folder - temporary folder --> - <!-- ===================================================================== --> - <target name="post.clean"> - <move file="services_src.zip" tofile="src.zip"/> - </target> -</project> diff --git a/bundles/org.eclipse.osgi.services/lib/osgi.annotation.jar b/bundles/org.eclipse.osgi.services/lib/osgi.annotation.jar Binary files differnew file mode 100644 index 000000000..947f158fb --- /dev/null +++ b/bundles/org.eclipse.osgi.services/lib/osgi.annotation.jar diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/Configuration.class b/bundles/org.eclipse.osgi.services/org/osgi/service/cm/Configuration.class Binary files differdeleted file mode 100644 index ceeb65785..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/Configuration.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationAdmin.class b/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationAdmin.class Binary files differdeleted file mode 100644 index 9fabc2f49..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationAdmin.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationEvent.class b/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationEvent.class Binary files differdeleted file mode 100644 index e25f669a2..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationEvent.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationException.class b/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationException.class Binary files differdeleted file mode 100644 index 1d92348c9..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationException.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationListener.class b/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationListener.class Binary files differdeleted file mode 100644 index 656435048..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationListener.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationPermission.class b/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationPermission.class Binary files differdeleted file mode 100644 index bd359a4d8..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationPermission.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationPermissionCollection.class b/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationPermissionCollection.class Binary files differdeleted file mode 100644 index 25058cab5..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationPermissionCollection.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationPlugin.class b/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationPlugin.class Binary files differdeleted file mode 100644 index db03a9a07..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ConfigurationPlugin.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ManagedService.class b/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ManagedService.class Binary files differdeleted file mode 100644 index 1265e1e73..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ManagedService.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ManagedServiceFactory.class b/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ManagedServiceFactory.class Binary files differdeleted file mode 100644 index eccb28301..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/cm/ManagedServiceFactory.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/component/ComponentConstants.class b/bundles/org.eclipse.osgi.services/org/osgi/service/component/ComponentConstants.class Binary files differdeleted file mode 100644 index 4a05902dd..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/component/ComponentConstants.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/component/ComponentContext.class b/bundles/org.eclipse.osgi.services/org/osgi/service/component/ComponentContext.class Binary files differdeleted file mode 100644 index ae69ba583..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/component/ComponentContext.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/component/ComponentException.class b/bundles/org.eclipse.osgi.services/org/osgi/service/component/ComponentException.class Binary files differdeleted file mode 100644 index 5d3cd8557..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/component/ComponentException.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/component/ComponentFactory.class b/bundles/org.eclipse.osgi.services/org/osgi/service/component/ComponentFactory.class Binary files differdeleted file mode 100644 index 3b00ffad4..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/component/ComponentFactory.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/component/ComponentInstance.class b/bundles/org.eclipse.osgi.services/org/osgi/service/component/ComponentInstance.class Binary files differdeleted file mode 100644 index f7ec3659f..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/component/ComponentInstance.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/Activate.class b/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/Activate.class Binary files differdeleted file mode 100644 index 5791c6b75..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/Activate.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/Component.class b/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/Component.class Binary files differdeleted file mode 100644 index 04ad0654c..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/Component.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/ConfigurationPolicy.class b/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/ConfigurationPolicy.class Binary files differdeleted file mode 100644 index 43e7f5b0f..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/ConfigurationPolicy.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/Deactivate.class b/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/Deactivate.class Binary files differdeleted file mode 100644 index 5b11dd292..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/Deactivate.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/Modified.class b/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/Modified.class Binary files differdeleted file mode 100644 index f5fc7fb81..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/Modified.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/Reference.class b/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/Reference.class Binary files differdeleted file mode 100644 index 8cc770674..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/Reference.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/ReferenceCardinality.class b/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/ReferenceCardinality.class Binary files differdeleted file mode 100644 index 64c12e561..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/ReferenceCardinality.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/ReferencePolicy.class b/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/ReferencePolicy.class Binary files differdeleted file mode 100644 index 4c63e7d69..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/ReferencePolicy.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/ReferencePolicyOption.class b/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/ReferencePolicyOption.class Binary files differdeleted file mode 100644 index 71061d218..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/component/annotations/ReferencePolicyOption.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/device/Constants.class b/bundles/org.eclipse.osgi.services/org/osgi/service/device/Constants.class Binary files differdeleted file mode 100644 index f782f7945..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/device/Constants.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/device/Device.class b/bundles/org.eclipse.osgi.services/org/osgi/service/device/Device.class Binary files differdeleted file mode 100644 index 237f58196..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/device/Device.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/device/Driver.class b/bundles/org.eclipse.osgi.services/org/osgi/service/device/Driver.class Binary files differdeleted file mode 100644 index 7fec66046..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/device/Driver.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/device/DriverLocator.class b/bundles/org.eclipse.osgi.services/org/osgi/service/device/DriverLocator.class Binary files differdeleted file mode 100644 index cae1e557f..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/device/DriverLocator.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/device/DriverSelector.class b/bundles/org.eclipse.osgi.services/org/osgi/service/device/DriverSelector.class Binary files differdeleted file mode 100644 index 9e5d67d4c..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/device/DriverSelector.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/device/Match.class b/bundles/org.eclipse.osgi.services/org/osgi/service/device/Match.class Binary files differdeleted file mode 100644 index a28afde31..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/device/Match.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/event/Event$FilterProperties.class b/bundles/org.eclipse.osgi.services/org/osgi/service/event/Event$FilterProperties.class Binary files differdeleted file mode 100644 index de3131d47..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/event/Event$FilterProperties.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/event/Event.class b/bundles/org.eclipse.osgi.services/org/osgi/service/event/Event.class Binary files differdeleted file mode 100644 index 99374d710..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/event/Event.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/event/EventAdmin.class b/bundles/org.eclipse.osgi.services/org/osgi/service/event/EventAdmin.class Binary files differdeleted file mode 100644 index bb2044fc0..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/event/EventAdmin.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/event/EventConstants.class b/bundles/org.eclipse.osgi.services/org/osgi/service/event/EventConstants.class Binary files differdeleted file mode 100644 index 824facdef..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/event/EventConstants.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/event/EventHandler.class b/bundles/org.eclipse.osgi.services/org/osgi/service/event/EventHandler.class Binary files differdeleted file mode 100644 index 2bf6d1e24..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/event/EventHandler.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/event/EventProperties.class b/bundles/org.eclipse.osgi.services/org/osgi/service/event/EventProperties.class Binary files differdeleted file mode 100644 index 9f89ef509..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/event/EventProperties.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/event/TopicPermission.class b/bundles/org.eclipse.osgi.services/org/osgi/service/event/TopicPermission.class Binary files differdeleted file mode 100644 index 1165dde99..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/event/TopicPermission.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/event/TopicPermissionCollection.class b/bundles/org.eclipse.osgi.services/org/osgi/service/event/TopicPermissionCollection.class Binary files differdeleted file mode 100644 index cd19b3325..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/event/TopicPermissionCollection.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/http/HttpContext.class b/bundles/org.eclipse.osgi.services/org/osgi/service/http/HttpContext.class Binary files differdeleted file mode 100644 index b7208d697..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/http/HttpContext.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/http/HttpService.class b/bundles/org.eclipse.osgi.services/org/osgi/service/http/HttpService.class Binary files differdeleted file mode 100644 index f77415f4a..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/http/HttpService.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/http/NamespaceException.class b/bundles/org.eclipse.osgi.services/org/osgi/service/http/NamespaceException.class Binary files differdeleted file mode 100644 index 01aff3c87..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/http/NamespaceException.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/io/ConnectionFactory.class b/bundles/org.eclipse.osgi.services/org/osgi/service/io/ConnectionFactory.class Binary files differdeleted file mode 100644 index ac4f846ab..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/io/ConnectionFactory.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/io/ConnectorService.class b/bundles/org.eclipse.osgi.services/org/osgi/service/io/ConnectorService.class Binary files differdeleted file mode 100644 index 22a782b0b..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/io/ConnectorService.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/log/LogEntry.class b/bundles/org.eclipse.osgi.services/org/osgi/service/log/LogEntry.class Binary files differdeleted file mode 100644 index 0fcaca353..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/log/LogEntry.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/log/LogListener.class b/bundles/org.eclipse.osgi.services/org/osgi/service/log/LogListener.class Binary files differdeleted file mode 100644 index 0a6017705..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/log/LogListener.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/log/LogReaderService.class b/bundles/org.eclipse.osgi.services/org/osgi/service/log/LogReaderService.class Binary files differdeleted file mode 100644 index 9cdf6c839..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/log/LogReaderService.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/log/LogService.class b/bundles/org.eclipse.osgi.services/org/osgi/service/log/LogService.class Binary files differdeleted file mode 100644 index 0f1ed6b85..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/log/LogService.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/metatype/AttributeDefinition.class b/bundles/org.eclipse.osgi.services/org/osgi/service/metatype/AttributeDefinition.class Binary files differdeleted file mode 100644 index 199e92065..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/metatype/AttributeDefinition.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/metatype/MetaTypeInformation.class b/bundles/org.eclipse.osgi.services/org/osgi/service/metatype/MetaTypeInformation.class Binary files differdeleted file mode 100644 index a3821db48..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/metatype/MetaTypeInformation.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/metatype/MetaTypeProvider.class b/bundles/org.eclipse.osgi.services/org/osgi/service/metatype/MetaTypeProvider.class Binary files differdeleted file mode 100644 index d20da8931..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/metatype/MetaTypeProvider.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/metatype/MetaTypeService.class b/bundles/org.eclipse.osgi.services/org/osgi/service/metatype/MetaTypeService.class Binary files differdeleted file mode 100644 index f92f16556..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/metatype/MetaTypeService.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/metatype/ObjectClassDefinition.class b/bundles/org.eclipse.osgi.services/org/osgi/service/metatype/ObjectClassDefinition.class Binary files differdeleted file mode 100644 index 5621a0ac8..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/metatype/ObjectClassDefinition.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/provisioning/ProvisioningService.class b/bundles/org.eclipse.osgi.services/org/osgi/service/provisioning/ProvisioningService.class Binary files differdeleted file mode 100644 index a132ad929..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/provisioning/ProvisioningService.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPAction.class b/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPAction.class Binary files differdeleted file mode 100644 index b7279940d..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPAction.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPDevice.class b/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPDevice.class Binary files differdeleted file mode 100644 index 8ecffa2d8..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPDevice.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPEventListener.class b/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPEventListener.class Binary files differdeleted file mode 100644 index c13a53898..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPEventListener.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPException.class b/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPException.class Binary files differdeleted file mode 100644 index 42e5976a8..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPException.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPIcon.class b/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPIcon.class Binary files differdeleted file mode 100644 index b45f77320..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPIcon.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPLocalStateVariable.class b/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPLocalStateVariable.class Binary files differdeleted file mode 100644 index 57c2e5e61..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPLocalStateVariable.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPService.class b/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPService.class Binary files differdeleted file mode 100644 index d76ec452d..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPService.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPStateVariable.class b/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPStateVariable.class Binary files differdeleted file mode 100644 index bc6e34a99..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/upnp/UPnPStateVariable.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/Authorization.class b/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/Authorization.class Binary files differdeleted file mode 100644 index 7e6df682d..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/Authorization.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/Group.class b/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/Group.class Binary files differdeleted file mode 100644 index 17964f8c3..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/Group.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/Role.class b/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/Role.class Binary files differdeleted file mode 100644 index e632ee16e..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/Role.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/User.class b/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/User.class Binary files differdeleted file mode 100644 index 775838b69..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/User.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/UserAdmin.class b/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/UserAdmin.class Binary files differdeleted file mode 100644 index a2398ea96..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/UserAdmin.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/UserAdminEvent.class b/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/UserAdminEvent.class Binary files differdeleted file mode 100644 index 5c38bc47b..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/UserAdminEvent.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/UserAdminListener.class b/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/UserAdminListener.class Binary files differdeleted file mode 100644 index b7204c96e..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/UserAdminListener.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/UserAdminPermission.class b/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/UserAdminPermission.class Binary files differdeleted file mode 100644 index d7a09edda..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/UserAdminPermission.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/UserAdminPermissionCollection.class b/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/UserAdminPermissionCollection.class Binary files differdeleted file mode 100644 index e9ecf3515..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/useradmin/UserAdminPermissionCollection.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/BasicEnvelope.class b/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/BasicEnvelope.class Binary files differdeleted file mode 100644 index 508637d6d..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/BasicEnvelope.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/Consumer.class b/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/Consumer.class Binary files differdeleted file mode 100644 index 421afec68..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/Consumer.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/Envelope.class b/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/Envelope.class Binary files differdeleted file mode 100644 index 82c60f556..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/Envelope.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/Producer.class b/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/Producer.class Binary files differdeleted file mode 100644 index 5f1eeebff..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/Producer.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/Wire.class b/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/Wire.class Binary files differdeleted file mode 100644 index c09aaad64..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/Wire.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WireAdmin.class b/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WireAdmin.class Binary files differdeleted file mode 100644 index 802f62676..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WireAdmin.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WireAdminEvent.class b/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WireAdminEvent.class Binary files differdeleted file mode 100644 index 57749c724..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WireAdminEvent.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WireAdminListener.class b/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WireAdminListener.class Binary files differdeleted file mode 100644 index bed095153..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WireAdminListener.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WireConstants.class b/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WireConstants.class Binary files differdeleted file mode 100644 index 9564c6433..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WireConstants.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WirePermission.class b/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WirePermission.class Binary files differdeleted file mode 100644 index f39b8c8a8..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WirePermission.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WirePermissionCollection.class b/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WirePermissionCollection.class Binary files differdeleted file mode 100644 index 16571c3f1..000000000 --- a/bundles/org.eclipse.osgi.services/org/osgi/service/wireadmin/WirePermissionCollection.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/pom.xml b/bundles/org.eclipse.osgi.services/pom.xml index 6686d5e04..8be589aeb 100644 --- a/bundles/org.eclipse.osgi.services/pom.xml +++ b/bundles/org.eclipse.osgi.services/pom.xml @@ -19,27 +19,6 @@ </parent> <groupId>org.eclipse.osgi</groupId> <artifactId>org.eclipse.osgi.services</artifactId> - <version>3.3.100-SNAPSHOT</version> + <version>3.4.0-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> - - <build> - <plugins> - <plugin> - <groupId>org.eclipse.tycho</groupId> - <artifactId>target-platform-configuration</artifactId> - <!-- - When building monolith, optional import-package javax.microedition.io causes circular dependency - between this org.eclipse.osgi.services bundle and org.eclipse.equinox.io. - Since this bundle does not need to compile anything, we just disable optional dependencies during - the build. - --> - <configuration> - <dependency-resolution> - <optionalDependencies>ignore</optionalDependencies> - </dependency-resolution> - </configuration> - </plugin> - </plugins> - </build> - </project> diff --git a/bundles/org.eclipse.osgi.services/src.zip b/bundles/org.eclipse.osgi.services/src.zip Binary files differdeleted file mode 100644 index 9117081e6..000000000 --- a/bundles/org.eclipse.osgi.services/src.zip +++ /dev/null diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/Configuration.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/Configuration.java new file mode 100644 index 000000000..1bfb10729 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/Configuration.java @@ -0,0 +1,275 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.cm; + +import java.io.IOException; +import java.util.Dictionary; +import org.osgi.annotation.versioning.ProviderType; +import org.osgi.framework.Filter; + +/** + * The configuration information for a {@code ManagedService} or + * {@code ManagedServiceFactory} object. + * + * The Configuration Admin service uses this interface to represent the + * configuration information for a {@code ManagedService} or for a service + * instance of a {@code ManagedServiceFactory}. + * + * <p> + * A {@code Configuration} object contains a configuration dictionary and allows + * the properties to be updated via this object. Bundles wishing to receive + * configuration dictionaries do not need to use this class - they register a + * {@code ManagedService} or {@code ManagedServiceFactory}. Only administrative + * bundles, and bundles wishing to update their own configurations need to use + * this class. + * + * <p> + * The properties handled in this configuration have case insensitive + * {@code String} objects as keys. However, case must be preserved from the last + * set key/value. + * <p> + * A configuration can be <i>bound</i> to a specific bundle or to a region of + * bundles using the <em>location</em>. In its simplest form the location is the + * location of the target bundle that registered a Managed Service or a Managed + * Service Factory. However, if the location starts with {@code ?} then the + * location indicates multiple delivery. In such a case the configuration must + * be delivered to all targets. + * + * If security is on, the Configuration Permission can be used to restrict the + * targets that receive updates. The Configuration Admin must only update a + * target when the configuration location matches the location of the target's + * bundle or the target bundle has a Configuration Permission with the action + * {@link ConfigurationPermission#TARGET} and a name that matches the + * configuration location. The name in the permission may contain wildcards ( + * {@code '*'}) to match the location using the same substring matching rules as + * {@link Filter}. + * + * Bundles can always create, manipulate, and be updated from configurations + * that have a location that matches their bundle location. + * + * <p> + * If a configuration's location is {@code null}, it is not yet bound to a + * location. It will become bound to the location of the first bundle that + * registers a {@code ManagedService} or {@code ManagedServiceFactory} object + * with the corresponding PID. + * <p> + * The same {@code Configuration} object is used for configuring both a Managed + * Service Factory and a Managed Service. When it is important to differentiate + * between these two the term "factory configuration" is used. + * + * @author $Id$ + */ +@ProviderType +public interface Configuration { + /** + * Get the PID for this {@code Configuration} object. + * + * @return the PID for this {@code Configuration} object. + * @throws IllegalStateException if this configuration has been deleted + */ + public String getPid(); + + /** + * Return the properties of this {@code Configuration} object. + * + * The {@code Dictionary} object returned is a private copy for the caller + * and may be changed without influencing the stored configuration. The keys + * in the returned dictionary are case insensitive and are always of type + * {@code String}. + * + * <p> + * If called just after the configuration is created and before update has + * been called, this method returns {@code null}. + * + * @return A private copy of the properties for the caller or {@code null}. + * These properties must not contain the "service.bundleLocation" + * property. The value of this property may be obtained from the + * {@link #getBundleLocation()} method. + * @throws IllegalStateException If this configuration has been deleted. + */ + public Dictionary<String, Object> getProperties(); + + /** + * Update the properties of this {@code Configuration} object. + * + * Stores the properties in persistent storage after adding or overwriting + * the following properties: + * <ul> + * <li>"service.pid" : is set to be the PID of this configuration.</li> + * <li>"service.factoryPid" : if this is a factory configuration it is set + * to the factory PID else it is not set.</li> + * </ul> + * These system properties are all of type {@code String}. + * + * <p> + * If the corresponding Managed Service/Managed Service Factory is + * registered, its updated method must be called asynchronously. Else, this + * callback is delayed until aforementioned registration occurs. + * + * <p> + * Also initiates an asynchronous call to all {@link ConfigurationListener}s + * with a {@link ConfigurationEvent#CM_UPDATED} event. + * + * @param properties the new set of properties for this configuration + * @throws IOException if update cannot be made persistent + * @throws IllegalArgumentException if the {@code Dictionary} object + * contains invalid configuration types or contains case variants of + * the same key name. + * @throws IllegalStateException If this configuration has been deleted. + */ + public void update(Dictionary<String, ?> properties) throws IOException; + + /** + * Delete this {@code Configuration} object. + * + * Removes this configuration object from the persistent store. Notify + * asynchronously the corresponding Managed Service or Managed Service + * Factory. A {@link ManagedService} object is notified by a call to its + * {@code updated} method with a {@code null} properties argument. A + * {@link ManagedServiceFactory} object is notified by a call to its + * {@code deleted} method. + * + * <p> + * Also initiates an asynchronous call to all {@link ConfigurationListener}s + * with a {@link ConfigurationEvent#CM_DELETED} event. + * + * @throws IOException If delete fails. + * @throws IllegalStateException If this configuration has been deleted. + */ + public void delete() throws IOException; + + /** + * For a factory configuration return the PID of the corresponding Managed + * Service Factory, else return {@code null}. + * + * @return factory PID or {@code null} + * @throws IllegalStateException If this configuration has been deleted. + */ + public String getFactoryPid(); + + /** + * Update the {@code Configuration} object with the current properties. + * + * Initiate the {@code updated} callback to the Managed Service or Managed + * Service Factory with the current properties asynchronously. + * + * <p> + * This is the only way for a bundle that uses a Configuration Plugin + * service to initiate a callback. For example, when that bundle detects a + * change that requires an update of the Managed Service or Managed Service + * Factory via its {@code ConfigurationPlugin} object. + * + * @see ConfigurationPlugin + * @throws IOException if update cannot access the properties in persistent + * storage + * @throws IllegalStateException If this configuration has been deleted. + */ + public void update() throws IOException; + + /** + * Bind this {@code Configuration} object to the specified location. + * + * If the location parameter is {@code null} then the {@code Configuration} + * object will not be bound to a location/region. It will be set to the + * bundle's location before the first time a Managed Service/Managed Service + * Factory receives this {@code Configuration} object via the updated method + * and before any plugins are called. The bundle location or region will be + * set persistently. + * + * <p> + * If the location starts with {@code ?} then all targets registered with + * the given PID must be updated. + * + * <p> + * If the location is changed then existing targets must be informed. If + * they can no longer see this configuration, the configuration must be + * deleted or updated with {@code null}. If this configuration becomes + * visible then they must be updated with this configuration. + * + * <p> + * Also initiates an asynchronous call to all {@link ConfigurationListener}s + * with a {@link ConfigurationEvent#CM_LOCATION_CHANGED} event. + * + * @param location a location, region, or {@code null} + * @throws IllegalStateException If this configuration has been deleted. + * @throws SecurityException when the required permissions are not available + * @throws SecurityException when the required permissions are not available + * @security ConfigurationPermission[this.location,CONFIGURE] if + * this.location is not {@code null} + * @security ConfigurationPermission[location,CONFIGURE] if location is not + * {@code null} + * @security ConfigurationPermission["*",CONFIGURE] if this.location is + * {@code null} or if location is {@code null} + */ + public void setBundleLocation(String location); + + /** + * Get the bundle location. + * + * Returns the bundle location or region to which this configuration is + * bound, or {@code null} if it is not yet bound to a bundle location or + * region. If the location starts with {@code ?} then the configuration is + * delivered to all targets and not restricted to a single bundle. + * + * @return location to which this configuration is bound, or {@code null}. + * @throws IllegalStateException If this configuration has been deleted. + * @throws SecurityException when the required permissions are not available + * @security ConfigurationPermission[this.location,CONFIGURE] if + * this.location is not {@code null} + * @security ConfigurationPermission["*",CONFIGURE] if this.location is + * {@code null} + * + */ + public String getBundleLocation(); + + /** + * Get the change count. + * + * The Configuration must maintain a change counter that every time when + * this configuration is updated and its properties are stored is + * incremented with a positive value. The counter must be changed after the + * properties are persisted but before the targets are updated and events + * are sent out. + * + * @return A monotonously increasing value reflecting changes in this + * Configuration + * + * @since 1.5 + */ + public long getChangeCount(); + + /** + * Equality is defined to have equal PIDs + * + * Two Configuration objects are equal when their PIDs are equal. + * + * @param other {@code Configuration} object to compare against + * @return {@code true} if equal, {@code false} if not a + * {@code Configuration} object or one with a different PID. + */ + public boolean equals(Object other); + + /** + * Hash code is based on PID. + * + * The hash code for two Configuration objects must be the same when the + * Configuration PID's are the same. + * + * @return hash code for this Configuration object + */ + public int hashCode(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationAdmin.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationAdmin.java new file mode 100644 index 000000000..3c2d838a0 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationAdmin.java @@ -0,0 +1,290 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.cm; + +import java.io.IOException; +import java.util.Dictionary; +import org.osgi.annotation.versioning.ProviderType; +import org.osgi.framework.Filter; +import org.osgi.framework.InvalidSyntaxException; + +/** + * Service for administering configuration data. + * + * <p> + * The main purpose of this interface is to store bundle configuration data + * persistently. This information is represented in {@code Configuration} + * objects. The actual configuration data is a {@code Dictionary} of properties + * inside a {@code Configuration} object. + * + * <p> + * There are two principally different ways to manage configurations. First + * there is the concept of a Managed Service, where configuration data is + * uniquely associated with an object registered with the service registry. + * + * <p> + * Next, there is the concept of a factory where the Configuration Admin service + * will maintain 0 or more {@code Configuration} objects for a Managed Service + * Factory that is registered with the Framework. + * + * <p> + * The first concept is intended for configuration data about "things/services" + * whose existence is defined externally, e.g. a specific printer. Factories are + * intended for "things/services" that can be created any number of times, e.g. + * a configuration for a DHCP server for different networks. + * + * <p> + * Bundles that require configuration should register a Managed Service or a + * Managed Service Factory in the service registry. A registration property + * named {@code service.pid} (persistent identifier or PID) must be used to + * identify this Managed Service or Managed Service Factory to the Configuration + * Admin service. + * + * <p> + * When the ConfigurationAdmin detects the registration of a Managed Service, it + * checks its persistent storage for a configuration object whose + * {@code service.pid} property matches the PID service property ( + * {@code service.pid}) of the Managed Service. If found, it calls + * {@link ManagedService#updated(Dictionary)} method with the new properties. + * The implementation of a Configuration Admin service must run these call-backs + * asynchronously to allow proper synchronization. + * + * <p> + * When the Configuration Admin service detects a Managed Service Factory + * registration, it checks its storage for configuration objects whose + * {@code service.factoryPid} property matches the PID service property of the + * Managed Service Factory. For each such {@code Configuration} objects, it + * calls the {@code ManagedServiceFactory.updated} method asynchronously with + * the new properties. The calls to the {@code updated} method of a + * {@code ManagedServiceFactory} must be executed sequentially and not overlap + * in time. + * + * <p> + * In general, bundles having permission to use the Configuration Admin service + * can only access and modify their own configuration information. Accessing or + * modifying the configuration of other bundles requires + * {@code ConfigurationPermission[location,CONFIGURE]}, where location is the + * configuration location. + * + * <p> + * {@code Configuration} objects can be <i>bound</i> to a specified bundle + * location or to a region (configuration location starts with {@code ?}). If a + * location is not set, it will be learned the first time a target is + * registered. If the location is learned this way, the Configuration Admin + * service must detect if the bundle corresponding to the location is + * uninstalled. If this occurs, the {@code Configuration} object must be + * unbound, that is its location field is set back to {@code null}. + * + * <p> + * If target's bundle location matches the configuration location it is always + * updated. + * + * <p> + * If the configuration location starts with {@code ?}, that is, the location is + * a region, then the configuration must be delivered to all targets registered + * with the given PID. If security is on, the target bundle must have + * Configuration Permission[location,TARGET], where location matches given the + * configuration location with wildcards as in the Filter substring match. The + * security must be verified using the + * {@link org.osgi.framework.Bundle#hasPermission(Object)} method on the target + * bundle. + * + * <p> + * If a target cannot be updated because the location does not match or it has + * no permission and security is active then the Configuration Admin service + * must not do the normal callback. + * + * <p> + * The method descriptions of this class refer to a concept of "the calling + * bundle". This is a loose way of referring to the bundle which obtained the + * Configuration Admin service from the service registry. Implementations of + * {@code ConfigurationAdmin} must use a + * {@link org.osgi.framework.ServiceFactory} to support this concept. + * + * @author $Id$ + */ +@ProviderType +public interface ConfigurationAdmin { + /** + * Configuration property naming the Factory PID in the configuration + * dictionary. The property's value is of type {@code String}. + * + * @since 1.1 + */ + public final static String SERVICE_FACTORYPID = "service.factoryPid"; + /** + * Configuration property naming the location of the bundle that is + * associated with a a {@code Configuration} object. This property can be + * searched for but must not appear in the configuration dictionary for + * security reason. The property's value is of type {@code String}. + * + * @since 1.1 + */ + public final static String SERVICE_BUNDLELOCATION = "service.bundleLocation"; + + /** + * Create a new factory {@code Configuration} object with a new PID. + * + * The properties of the new {@code Configuration} object are {@code null} + * until the first time that its {@link Configuration#update(Dictionary)} + * method is called. + * + * <p> + * It is not required that the {@code factoryPid} maps to a registered + * Managed Service Factory. + * + * <p> + * The {@code Configuration} object is bound to the location of the calling + * bundle. It is possible that the same factoryPid has associated + * configurations that are bound to different bundles. Bundles should only + * see the factory configurations that they are bound to or have the proper + * permission. + * + * @param factoryPid PID of factory (not {@code null}). + * @return A new {@code Configuration} object. + * @throws IOException if access to persistent storage fails. + */ + public Configuration createFactoryConfiguration(String factoryPid) throws IOException; + + /** + * Create a new factory {@code Configuration} object with a new PID. + * + * The properties of the new {@code Configuration} object are {@code null} + * until the first time that its {@link Configuration#update(Dictionary)} + * method is called. + * + * <p> + * It is not required that the {@code factoryPid} maps to a registered + * Managed Service Factory. + * + * <p> + * The {@code Configuration} is bound to the location specified. If this + * location is {@code null} it will be bound to the location of the first + * bundle that registers a Managed Service Factory with a corresponding PID. + * It is possible that the same factoryPid has associated configurations + * that are bound to different bundles. Bundles should only see the factory + * configurations that they are bound to or have the proper permission. + * + * <p> + * If the location starts with {@code ?} then the configuration must be + * delivered to all targets with the corresponding PID. + * + * @param factoryPid PID of factory (not {@code null}). + * @param location A bundle location string, or {@code null}. + * @return a new {@code Configuration} object. + * @throws IOException if access to persistent storage fails. + * @throws SecurityException when the require permissions are not available + * @security ConfigurationPermission[location,CONFIGURE] if location is not + * {@code null} + * @security ConfigurationPermission["*",CONFIGURE] if location is + * {@code null} + */ + public Configuration createFactoryConfiguration(String factoryPid, String location) throws IOException; + + /** + * Get an existing {@code Configuration} object from the persistent store, + * or create a new {@code Configuration} object. + * + * <p> + * If a {@code Configuration} with this PID already exists in Configuration + * Admin service return it. The location parameter is ignored in this case + * though it is still used for a security check. + * + * <p> + * Else, return a new {@code Configuration} object. This new object is bound + * to the location and the properties are set to {@code null}. If the + * location parameter is {@code null}, it will be set when a Managed Service + * with the corresponding PID is registered for the first time. If the + * location starts with {@code ?} then the configuration is bound to all + * targets that are registered with the corresponding PID. + * + * @param pid Persistent identifier. + * @param location The bundle location string, or {@code null}. + * @return An existing or new {@code Configuration} object. + * @throws IOException if access to persistent storage fails. + * @throws SecurityException when the require permissions are not available + * @security ConfigurationPermission[*,CONFIGURE] if location is + * {@code null} or if the returned configuration {@code c} already + * exists and c.location is {@code null} + * @security ConfigurationPermission[location,CONFIGURE] if location is not + * {@code null} + * @security ConfigurationPermission[c.location,CONFIGURE] if the returned + * configuration {@code c} already exists and c.location is not + * {@code null} + */ + public Configuration getConfiguration(String pid, String location) throws IOException; + + /** + * Get an existing or new {@code Configuration} object from the persistent + * store. + * + * If the {@code Configuration} object for this PID does not exist, create a + * new {@code Configuration} object for that PID, where properties are + * {@code null}. Bind its location to the calling bundle's location. + * + * <p> + * Otherwise, if the location of the existing {@code Configuration} object + * is {@code null}, set it to the calling bundle's location. + * + * @param pid persistent identifier. + * @return an existing or new {@code Configuration} matching the PID. + * @throws IOException if access to persistent storage fails. + * @throws SecurityException when the required permission is not available + * @security ConfigurationPermission[c.location,CONFIGURE] If the + * configuration {@code c} already exists and c.location is not + * {@code null} + */ + public Configuration getConfiguration(String pid) throws IOException; + + /** + * List the current {@code Configuration} objects which match the filter. + * + * <p> + * Only {@code Configuration} objects with non- {@code null} properties are + * considered current. That is, {@code Configuration.getProperties()} is + * guaranteed not to return {@code null} for each of the returned + * {@code Configuration} objects. + * + * <p> + * When there is no security on then all configurations can be returned. If + * security is on, the caller must have + * ConfigurationPermission[location,CONFIGURE]. + * + * <p> + * The syntax of the filter string is as defined in the {@link Filter} + * class. The filter can test any configuration properties including the + * following: + * <ul> + * <li>{@code service.pid} - the persistent identity</li> + * <li>{@code service.factoryPid} - the factory PID, if applicable</li> + * <li>{@code service.bundleLocation} - the bundle location</li> + * </ul> + * The filter can also be {@code null}, meaning that all + * {@code Configuration} objects should be returned. + * + * @param filter A filter string, or {@code null} to retrieve all + * {@code Configuration} objects. + * @return All matching {@code Configuration} objects, or {@code null} if + * there aren't any. + * @throws IOException if access to persistent storage fails + * @throws InvalidSyntaxException if the filter string is invalid + * @security ConfigurationPermission[c.location,CONFIGURE] Only + * configurations {@code c} are returned for which the caller has + * this permission + */ + public Configuration[] listConfigurations(String filter) throws IOException, InvalidSyntaxException; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationEvent.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationEvent.java new file mode 100644 index 000000000..b6e83bbc5 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationEvent.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) OSGi Alliance (2004, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.cm; + +import java.util.Dictionary; +import org.osgi.framework.ServiceReference; + +/** + * A Configuration Event. + * + * <p> + * {@code ConfigurationEvent} objects are delivered to all registered + * {@code ConfigurationListener} service objects. ConfigurationEvents must be + * asynchronously delivered in chronological order with respect to each + * listener. + * + * <p> + * A type code is used to identify the type of event. The following event types + * are defined: + * <ul> + * <li>{@link #CM_UPDATED}</li> + * <li>{@link #CM_DELETED}</li> + * <li>{@link #CM_LOCATION_CHANGED}</li> + * </ul> + * Additional event types may be defined in the future. + * + * <p> + * Security Considerations. {@code ConfigurationEvent} objects do not provide + * {@code Configuration} objects, so no sensitive configuration information is + * available from the event. If the listener wants to locate the + * {@code Configuration} object for the specified pid, it must use + * {@code ConfigurationAdmin}. + * + * @see ConfigurationListener + * @Immutable + * @author $Id$ + * @since 1.2 + */ +public class ConfigurationEvent { + /** + * A {@code Configuration} has been updated. + * + * <p> + * This {@code ConfigurationEvent} type that indicates that a + * {@code Configuration} object has been updated with new properties. + * + * An event is fired when a call to {@link Configuration#update(Dictionary)} + * successfully changes a configuration. + */ + public static final int CM_UPDATED = 1; + /** + * A {@code Configuration} has been deleted. + * + * <p> + * This {@code ConfigurationEvent} type that indicates that a + * {@code Configuration} object has been deleted. + * + * An event is fired when a call to {@link Configuration#delete()} + * successfully deletes a configuration. + */ + public static final int CM_DELETED = 2; + + /** + * The location of a {@code Configuration} has been changed. + * + * <p> + * This {@code ConfigurationEvent} type that indicates that the location of + * a {@code Configuration} object has been changed. + * + * An event is fired when a call to + * {@link Configuration#setBundleLocation(String)} successfully changes the + * location. + * + * @since 1.4 + */ + public static final int CM_LOCATION_CHANGED = 3; + /** + * Type of this event. + * + * @see #getType() + */ + private final int type; + /** + * The factory pid associated with this event. + */ + private final String factoryPid; + /** + * The pid associated with this event. + */ + private final String pid; + /** + * The ConfigurationAdmin service which created this event. + */ + private final ServiceReference<ConfigurationAdmin> reference; + + /** + * Constructs a {@code ConfigurationEvent} object from the given + * {@code ServiceReference} object, event type, and pids. + * + * @param reference The {@code ServiceReference} object of the Configuration + * Admin service that created this event. + * @param type The event type. See {@link #getType()}. + * @param factoryPid The factory pid of the associated configuration if the + * target of the configuration is a ManagedServiceFactory. Otherwise + * {@code null} if the target of the configuration is a + * ManagedService. + * @param pid The pid of the associated configuration. + */ + public ConfigurationEvent(ServiceReference<ConfigurationAdmin> reference, int type, String factoryPid, String pid) { + this.reference = reference; + this.type = type; + this.factoryPid = factoryPid; + this.pid = pid; + if ((reference == null) || (pid == null)) { + throw new NullPointerException("reference and pid must not be null"); + } + } + + /** + * Returns the factory pid of the associated configuration. + * + * @return Returns the factory pid of the associated configuration if the + * target of the configuration is a ManagedServiceFactory. Otherwise + * {@code null} if the target of the configuration is a + * ManagedService. + */ + public String getFactoryPid() { + return factoryPid; + } + + /** + * Returns the pid of the associated configuration. + * + * @return Returns the pid of the associated configuration. + */ + public String getPid() { + return pid; + } + + /** + * Return the type of this event. + * <p> + * The type values are: + * <ul> + * <li>{@link #CM_UPDATED}</li> + * <li>{@link #CM_DELETED}</li> + * <li>{@link #CM_LOCATION_CHANGED}</li> + * </ul> + * + * @return The type of this event. + */ + public int getType() { + return type; + } + + /** + * Return the {@code ServiceReference} object of the Configuration Admin + * service that created this event. + * + * @return The {@code ServiceReference} object for the Configuration Admin + * service that created this event. + */ + public ServiceReference<ConfigurationAdmin> getReference() { + return reference; + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationException.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationException.java new file mode 100644 index 000000000..373726d33 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationException.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.cm; + +/** + * An {@code Exception} class to inform the Configuration Admin service of + * problems with configuration data. + * + * @author $Id$ + */ +public class ConfigurationException extends Exception { + static final long serialVersionUID = -1690090413441769377L; + + private final String property; + private final String reason; + + /** + * Create a {@code ConfigurationException} object. + * + * @param property name of the property that caused the problem, + * {@code null} if no specific property was the cause + * @param reason reason for failure + */ + public ConfigurationException(String property, String reason) { + super(property + " : " + reason); + this.property = property; + this.reason = reason; + } + + /** + * Create a {@code ConfigurationException} object. + * + * @param property name of the property that caused the problem, + * {@code null} if no specific property was the cause + * @param reason reason for failure + * @param cause The cause of this exception. + * @since 1.2 + */ + public ConfigurationException(String property, String reason, Throwable cause) { + super(property + " : " + reason, cause); + this.property = property; + this.reason = reason; + } + + /** + * Return the property name that caused the failure or null. + * + * @return name of property or null if no specific property caused the + * problem + */ + public String getProperty() { + return property; + } + + /** + * Return the reason for this exception. + * + * @return reason of the failure + */ + public String getReason() { + return reason; + } + + /** + * Returns the cause of this exception or {@code null} if no cause was set. + * + * @return The cause of this exception or {@code null} if no cause was set. + * @since 1.2 + */ + public Throwable getCause() { + return super.getCause(); + } + + /** + * Initializes the cause of this exception to the specified value. + * + * @param cause The cause of this exception. + * @return This exception. + * @throws IllegalArgumentException If the specified cause is this + * exception. + * @throws IllegalStateException If the cause of this exception has already + * been set. + * @since 1.2 + */ + public Throwable initCause(Throwable cause) { + return super.initCause(cause); + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationListener.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationListener.java new file mode 100644 index 000000000..7b228e523 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationListener.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) OSGi Alliance (2004, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.cm; + +import org.osgi.annotation.versioning.ConsumerType; + +/** + * Listener for Configuration Events. When a {@code ConfigurationEvent} is + * fired, it is asynchronously delivered to a {@code ConfigurationListener}. + * + * <p> + * {@code ConfigurationListener} objects are registered with the Framework + * service registry and are notified with a {@code ConfigurationEvent} object + * when an event is fired. + * <p> + * {@code ConfigurationListener} objects can inspect the received + * {@code ConfigurationEvent} object to determine its type, the pid of the + * {@code Configuration} object with which it is associated, and the + * Configuration Admin service that fired the event. + * + * <p> + * Security Considerations. Bundles wishing to monitor configuration events will + * require {@code ServicePermission[ConfigurationListener,REGISTER]} to register + * a {@code ConfigurationListener} service. + * + * @author $Id$ + * @since 1.2 + */ +@ConsumerType +public interface ConfigurationListener { + /** + * Receives notification of a Configuration that has changed. + * + * @param event The {@code ConfigurationEvent}. + */ + public void configurationEvent(ConfigurationEvent event); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationPermission.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationPermission.java new file mode 100644 index 000000000..ea3f7764e --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationPermission.java @@ -0,0 +1,622 @@ +/* + * Copyright (c) OSGi Alliance (2004, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.cm; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; +import java.security.BasicPermission; +import java.security.Permission; +import java.security.PermissionCollection; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.osgi.framework.Filter; + +/** + * Indicates a bundle's authority to configure bundles or be updated by + * Configuration Admin. + * + * @ThreadSafe + * @author $Id$ + * @since 1.2 + */ + +public final class ConfigurationPermission extends BasicPermission { + static final long serialVersionUID = 5716868734811965383L; + /** + * Provides permission to create new configurations for other bundles as + * well as manipulate them. The action string {@value #CONFIGURE}. + */ + public final static String CONFIGURE = "configure"; + + /** + * The permission to be updated, that is, act as a Managed Service or + * Managed Service Factory. The action string {@value #TARGET}. + * + * @since 1.4 + */ + public final static String TARGET = "target"; + + private final static int ACTION_CONFIGURE = 0x00000001; + private final static int ACTION_TARGET = 0x00000002; + private final static int ACTION_ALL = ACTION_CONFIGURE | ACTION_TARGET; + final static int ACTION_NONE = 0; + + /** + * The actions mask. + */ + transient int action_mask; + + /** + * The actions in canonical form. + * + * @serial + */ + private volatile String actions = null; + + /** + * Parsed name if it includes wildcards: "*" + */ + private transient List<String> substrings; + + /** + * Create a new ConfigurationPermission. + * + * @param name Name of the permission. Wildcards ({@code '*'}) are allowed + * in the name. During {@link #implies(Permission)}, the name is + * matched to the requested permission using the substring matching + * rules used by {@link Filter}s. + * @param actions Comma separated list of {@link #CONFIGURE}, + * {@link #TARGET} (case insensitive). + */ + + public ConfigurationPermission(String name, String actions) { + this(name, parseActions(actions)); + } + + /** + * Package private constructor used by ConfigurationPermissionCollection. + * + * @param name location string + * @param mask action mask + */ + ConfigurationPermission(String name, int mask) { + super(name); + setTransients(mask); + } + + /** + * Called by constructors and when deserialized. + * + * @param mask action mask + */ + private void setTransients(int mask) { + if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) { + throw new IllegalArgumentException("invalid action string"); + } + action_mask = mask; + substrings = parseSubstring(getName()); + } + + /** + * Parse action string into action mask. + * + * @param actions Action string. + * @return action mask. + */ + private static int parseActions(String actions) { + boolean seencomma = false; + + int mask = ACTION_NONE; + + if (actions == null) { + return mask; + } + + char[] a = actions.toCharArray(); + + int i = a.length - 1; + if (i < 0) + return mask; + + while (i != -1) { + char c; + + // skip whitespace + while ((i != -1) && ((c = a[i]) == ' ' || c == '\r' || c == '\n' || c == '\f' || c == '\t')) + i--; + + // check for the known strings + int matchlen; + + if (i >= 5 && (a[i - 5] == 't' || a[i - 5] == 'T') + && (a[i - 4] == 'a' || a[i - 4] == 'A') + && (a[i - 3] == 'r' || a[i - 3] == 'R') + && (a[i - 2] == 'g' || a[i - 2] == 'G') + && (a[i - 1] == 'e' || a[i - 1] == 'E') + && (a[i] == 't' || a[i] == 'T')) { + matchlen = 6; + mask |= ACTION_TARGET; + + } else + if (i >= 8 && (a[i - 8] == 'c' || a[i - 8] == 'C') + && (a[i - 7] == 'o' || a[i - 7] == 'O') + && (a[i - 6] == 'n' || a[i - 6] == 'N') + && (a[i - 5] == 'f' || a[i - 5] == 'F') + && (a[i - 4] == 'i' || a[i - 4] == 'I') + && (a[i - 3] == 'g' || a[i - 3] == 'G') + && (a[i - 2] == 'u' || a[i - 2] == 'U') + && (a[i - 1] == 'r' || a[i - 1] == 'R') + && (a[i] == 'e' || a[i] == 'E')) { + matchlen = 9; + mask |= ACTION_CONFIGURE; + + } else { + // parse error + throw new IllegalArgumentException("invalid actions: " + actions); + } + + // make sure we didn't just match the tail of a word + // like "ackbarftarget". Also, skip to the comma. + seencomma = false; + while (i >= matchlen && !seencomma) { + switch (a[i - matchlen]) { + case ',' : + seencomma = true; + /* FALLTHROUGH */ + case ' ' : + case '\r' : + case '\n' : + case '\f' : + case '\t' : + break; + default : + throw new IllegalArgumentException("invalid permission: " + actions); + } + i--; + } + + // point i at the location of the comma minus one (or -1). + i -= matchlen; + } + + if (seencomma) { + throw new IllegalArgumentException("invalid actions: " + actions); + } + + return mask; + } + + /** + * Parse the name for wildcard processing. + * + * @param name The name of the permission. + * @return {@code null} is the name has no wildcards or a + * {@code List<String>} where element is a substring to match or + * null for {@code '*'}. + */ + private static List<String> parseSubstring(String name) { + if (name.indexOf('*') < 0) { + return null; + } + char[] chars = name.toCharArray(); + StringBuffer sb = new StringBuffer(chars.length); + + List<String> sub = new ArrayList<String>(10); + + for (int pos = 0; pos < chars.length; pos++) { + char c = chars[pos]; + + switch (c) { + case '*' : { + if (sb.length() > 0) { + sub.add(sb.toString()); + } + sb.setLength(0); + sub.add(null); + break; + } + + case '\\' : { + pos++; + if (pos < chars.length) { + c = chars[pos]; + } + /* fall through into default */ + } + + default : { + sb.append(c); + break; + } + } + } + if (sb.length() > 0) { + sub.add(sb.toString()); + } + + int size = sub.size(); + + if (size == 0) { + return null; + } + + if (size == 1) { + if (sub.get(0) != null) { + return null; + } + } + return sub; + } + + /** + * Determines if a {@code ConfigurationPermission} object "implies" the + * specified permission. + * + * @param p The target permission to check. + * @return {@code true} if the specified permission is implied by this + * object; {@code false} otherwise. + */ + + @Override + public boolean implies(Permission p) { + if (!(p instanceof ConfigurationPermission)) { + return false; + } + ConfigurationPermission requested = (ConfigurationPermission) p; + return implies0(requested, ACTION_NONE); + } + + /** + * Internal implies method. Used by the implies and the permission + * collection implies methods. + * + * @param requested The requested ConfigurationPermission which has already + * be validated as a proper argument. + * @param effective The effective actions with which to start. + * @return {@code true} if the specified permission is implied by this + * object; {@code false} otherwise. + */ + boolean implies0(ConfigurationPermission requested, int effective) { + /* check actions first - much faster */ + effective |= action_mask; + final int desired = requested.action_mask; + if ((effective & desired) != desired) { + return false; + } + String requestedName = requested.getName(); + if (substrings == null) { + return getName().equals(requestedName); + } + for (int i = 0, pos = 0, size = substrings.size(); i < size; i++) { + String substr = substrings.get(i); + + if (i + 1 < size) /* if this is not that last substr */{ + if (substr == null) /* * */{ + String substr2 = substrings.get(i + 1); + + if (substr2 == null) /* ** */ + continue; /* ignore first star */ + /* xxx */ + int index = requestedName.indexOf(substr2, pos); + if (index == -1) { + return false; + } + + pos = index + substr2.length(); + if (i + 2 < size) // if there are more + // substrings, increment + // over the string we just + // matched; otherwise need + // to do the last substr + // check + i++; + } else /* xxx */{ + int len = substr.length(); + if (requestedName.regionMatches(pos, substr, 0, len)) { + pos += len; + } else { + return false; + } + } + } else /* last substr */{ + if (substr == null) /* * */{ + return true; + } + /* xxx */ + return requestedName.endsWith(substr); + } + } + + return false; + } + + /** + * Determines the equality of two {@code ConfigurationPermission} objects. + * <p> + * Two {@code ConfigurationPermission} objects are equal. + * + * @param obj The object being compared for equality with this object. + * @return {@code true} if {@code obj} is equivalent to this + * {@code ConfigurationPermission}; {@code false} otherwise. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (!(obj instanceof ConfigurationPermission)) { + return false; + } + + ConfigurationPermission cp = (ConfigurationPermission) obj; + + return (action_mask == cp.action_mask) && getName().equals(cp.getName()); + } + + /** + * Returns the hash code value for this object. + * + * @return Hash code value for this object. + */ + + @Override + public int hashCode() { + int h = 31 * 17 + getName().hashCode(); + h = 31 * h + getActions().hashCode(); + return h; + } + + /** + * Returns the canonical string representation of the + * {@code ConfigurationPermission} actions. + * + * <p> + * Always returns present {@code ConfigurationPermission} actions in the + * following order: {@value #CONFIGURE}, {@value #TARGET} + * + * @return Canonical string representation of the + * {@code ConfigurationPermission} actions. + */ + @Override + public String getActions() { + String result = actions; + if (result == null) { + StringBuffer sb = new StringBuffer(); + boolean comma = false; + + int mask = action_mask; + if ((mask & ACTION_CONFIGURE) == ACTION_CONFIGURE) { + sb.append(CONFIGURE); + comma = true; + } + + if ((mask & ACTION_TARGET) == ACTION_TARGET) { + if (comma) + sb.append(','); + sb.append(TARGET); + } + + actions = result = sb.toString(); + } + + return result; + } + + /** + * Returns a new {@code PermissionCollection} object suitable for storing + * {@code ConfigurationPermission}s. + * + * @return A new {@code PermissionCollection} object. + */ + @Override + public PermissionCollection newPermissionCollection() { + return new ConfigurationPermissionCollection(); + } + + /** + * WriteObject is called to save the state of this permission object to a + * stream. The actions are serialized, and the superclass takes care of the + * name. + */ + private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { + // Write out the actions. The superclass takes care of the name + // call getActions to make sure actions field is initialized + if (actions == null) + getActions(); + s.defaultWriteObject(); + } + + /** + * readObject is called to restore the state of this permission from a + * stream. + */ + private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { + // Read in the data, then initialize the transients + s.defaultReadObject(); + setTransients(parseActions(actions)); + } +} + +/** + * Stores a set of {@code ConfigurationPermission} permissions. + * + * @see java.security.Permission + * @see java.security.Permissions + * @see java.security.PermissionCollection + */ +final class ConfigurationPermissionCollection extends PermissionCollection { + static final long serialVersionUID = -6917638867081695839L; + /** + * Collection of permissions. + * + * @serial + * @GuardedBy this + */ + private Map<String, ConfigurationPermission> permissions; + + /** + * Boolean saying if "*" is in the collection. + * + * @serial + * @GuardedBy this + */ + private boolean all_allowed; + + /** + * Creates an empty {@code ConfigurationPermissionCollection} object. + * + */ + public ConfigurationPermissionCollection() { + permissions = new HashMap<String, ConfigurationPermission>(); + all_allowed = false; + } + + /** + * Adds the specified permission to the + * {@code ConfigurationPermissionCollection}. The key for the hash is the + * interface name of the service. + * + * @param permission The {@code Permission} object to add. + * + * @exception IllegalArgumentException If the permission is not an + * {@code ConfigurationPermission}. + * + * @exception SecurityException If this ConfigurationPermissionCollection + * object has been marked read-only. + */ + + @Override + public void add(Permission permission) { + if (!(permission instanceof ConfigurationPermission)) { + throw new IllegalArgumentException("invalid permission: " + permission); + } + + if (isReadOnly()) + throw new SecurityException("attempt to add a Permission to a " + "readonly PermissionCollection"); + + final ConfigurationPermission cp = (ConfigurationPermission) permission; + final String name = cp.getName(); + synchronized (this) { + Map<String, ConfigurationPermission> pc = permissions; + final ConfigurationPermission existing = pc.get(name); + if (existing != null) { + final int oldMask = existing.action_mask; + final int newMask = cp.action_mask; + if (oldMask != newMask) { + pc.put(name, new ConfigurationPermission(name, oldMask | newMask)); + } + } else { + pc.put(name, cp); + } + + if (!all_allowed) { + if (name.equals("*")) { + all_allowed = true; + } + } + } + } + + /** + * Determines if the specified permissions implies the permissions expressed + * in {@code permission}. + * + * @param permission The Permission object to compare with this + * {@code ConfigurationPermission} object. + * @return {@code true} if {@code permission} is a proper subset of a + * permission in the set; {@code false} otherwise. + */ + @Override + public boolean implies(Permission permission) { + if (!(permission instanceof ConfigurationPermission)) { + return false; + } + final ConfigurationPermission requested = (ConfigurationPermission) permission; + int effective = ConfigurationPermission.ACTION_NONE; + + Collection<ConfigurationPermission> perms; + synchronized (this) { + Map<String, ConfigurationPermission> pc = permissions; + /* short circuit if the "*" Permission was added */ + if (all_allowed) { + ConfigurationPermission cp = pc.get("*"); + if (cp != null) { + effective |= cp.action_mask; + final int desired = requested.action_mask; + if ((effective & desired) == desired) { + return true; + } + } + } + perms = pc.values(); + } + /* iterate one by one over permissions */ + for (ConfigurationPermission perm : perms) { + if (perm.implies0(requested, effective)) { + return true; + } + } + return false; + } + + /** + * Returns an enumeration of all {@code ConfigurationPermission} objects in + * the container. + * + * @return Enumeration of all {@code ConfigurationPermission} objects. + */ + @Override + public synchronized Enumeration<Permission> elements() { + List<Permission> all = new ArrayList<Permission>(permissions.values()); + return Collections.enumeration(all); + } + + /* serialization logic */ + private static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("hasElement", Boolean.TYPE), new ObjectStreamField("permissions", HashMap.class), + new ObjectStreamField("all_allowed", Boolean.TYPE) }; + + private synchronized void writeObject(ObjectOutputStream out) throws IOException { + ObjectOutputStream.PutField pfields = out.putFields(); + pfields.put("hasElement", false); + pfields.put("permissions", permissions); + pfields.put("all_allowed", all_allowed); + out.writeFields(); + } + + private synchronized void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + ObjectInputStream.GetField gfields = in.readFields(); + boolean hasElement = gfields.get("hasElement", false); + if (hasElement) { // old format + permissions = new HashMap<String, ConfigurationPermission>(); + permissions.put("*", new ConfigurationPermission("*", ConfigurationPermission.CONFIGURE)); + all_allowed = true; + } else { + @SuppressWarnings("unchecked") + HashMap<String, ConfigurationPermission> p = (HashMap<String, ConfigurationPermission>) gfields.get("permissions", new HashMap<String, ConfigurationPermission>()); + permissions = p; + all_allowed = gfields.get("all_allowed", false); + } + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationPlugin.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationPlugin.java new file mode 100644 index 000000000..97d5ee807 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ConfigurationPlugin.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.cm; + +import java.util.Dictionary; +import org.osgi.annotation.versioning.ConsumerType; +import org.osgi.framework.ServiceReference; + +/** + * A service interface for processing configuration dictionary before the + * update. + * + * <p> + * A bundle registers a {@code ConfigurationPlugin} object in order to process + * configuration updates before they reach the Managed Service or Managed + * Service Factory. The Configuration Admin service will detect registrations of + * Configuration Plugin services and must call these services every time before + * it calls the {@code ManagedService} or {@code ManagedServiceFactory} + * {@code updated} method. The Configuration Plugin service thus has the + * opportunity to view and modify the properties before they are passed to the + * Managed Service or Managed Service Factory. + * + * <p> + * Configuration Plugin (plugin) services have full read/write access to all + * configuration information that passes through them. + * + * <p> + * The {@code Integer} {@code service.cmRanking} registration property may be + * specified. Not specifying this registration property, or setting it to + * something other than an {@code Integer}, is the same as setting it to the + * {@code Integer} zero. The {@code service.cmRanking} property determines the + * order in which plugins are invoked. Lower ranked plugins are called before + * higher ranked ones. In the event of more than one plugin having the same + * value of {@code service.cmRanking}, then the Configuration Admin service + * arbitrarily chooses the order in which they are called. + * + * <p> + * By convention, plugins with {@code service.cmRanking < 0} or + * {@code service.cmRanking > 1000} should not make modifications to the + * properties. + * + * <p> + * The Configuration Admin service has the right to hide properties from + * plugins, or to ignore some or all the changes that they make. This might be + * done for security reasons. Any such behavior is entirely implementation + * defined. + * + * <p> + * A plugin may optionally specify a {@code cm.target} registration property + * whose value is the PID of the Managed Service or Managed Service Factory + * whose configuration updates the plugin is intended to intercept. The plugin + * will then only be called with configuration updates that are targeted at the + * Managed Service or Managed Service Factory with the specified PID. Omitting + * the {@code cm.target} registration property means that the plugin is called + * for all configuration updates. + * + * @author $Id$ + */ +@ConsumerType +public interface ConfigurationPlugin { + /** + * A service property to limit the Managed Service or Managed Service + * Factory configuration dictionaries a Configuration Plugin service + * receives. + * + * This property contains a {@code String[]} of PIDs. A Configuration Admin + * service must call a Configuration Plugin service only when this property + * is not set, or the target service's PID is listed in this property. + */ + public static final String CM_TARGET = "cm.target"; + /** + * A service property to specify the order in which plugins are invoked. + * + * This property contains an {@code Integer} ranking of the plugin. Not + * specifying this registration property, or setting it to something other + * than an {@code Integer}, is the same as setting it to the {@code Integer} + * zero. This property determines the order in which plugins are invoked. + * Lower ranked plugins are called before higher ranked ones. + * + * @since 1.2 + */ + public static final String CM_RANKING = "service.cmRanking"; + + /** + * View and possibly modify the a set of configuration properties before + * they are sent to the Managed Service or the Managed Service Factory. The + * Configuration Plugin services are called in increasing order of their + * {@code service.cmRanking} property. If this property is undefined or is a + * non- {@code Integer} type, 0 is used. + * + * <p> + * This method should not modify the properties unless the + * {@code service.cmRanking} of this plugin is in the range + * {@code 0 <= service.cmRanking <= 1000}. + * <p> + * If this method throws any {@code Exception}, the Configuration Admin + * service must catch it and should log it. + * + * <p> + * A Configuration Plugin will only be called for properties from + * configurations that have a location for which the Configuration Plugin + * has permission when security is active. When security is not active, no + * filtering is done. + * + * @param reference reference to the Managed Service or Managed Service + * Factory + * @param properties The configuration properties. This argument must not + * contain the "service.bundleLocation" property. The value of this + * property may be obtained from the + * {@code Configuration.getBundleLocation} method. + */ + public void modifyConfiguration(ServiceReference<?> reference, Dictionary<String, Object> properties); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ManagedService.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ManagedService.java new file mode 100644 index 000000000..a4905c472 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ManagedService.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.cm; + +import java.util.Dictionary; +import org.osgi.annotation.versioning.ConsumerType; + +/** + * A service that can receive configuration data from a Configuration Admin + * service. + * + * <p> + * A Managed Service is a service that needs configuration data. Such an object + * should be registered with the Framework registry with the {@code service.pid} + * property set to some unique identifier called a PID. + * + * <p> + * If the Configuration Admin service has a {@code Configuration} object + * corresponding to this PID, it will callback the {@code updated()} method of + * the {@code ManagedService} object, passing the properties of that + * {@code Configuration} object. + * + * <p> + * If it has no such {@code Configuration} object, then it calls back with a + * {@code null} properties argument. Registering a Managed Service will always + * result in a callback to the {@code updated()} method provided the + * Configuration Admin service is, or becomes active. This callback must always + * be done asynchronously. + * + * <p> + * Else, every time that either of the {@code updated()} methods is called on + * that {@code Configuration} object, the {@code ManagedService.updated()} + * method with the new properties is called. If the {@code delete()} method is + * called on that {@code Configuration} object, {@code ManagedService.updated()} + * is called with a {@code null} for the properties parameter. All these + * callbacks must be done asynchronously. + * + * <p> + * The following example shows the code of a serial port that will create a port + * depending on configuration information. + * + * <pre> + * + * class SerialPort implements ManagedService { + * + * ServiceRegistration registration; + * Hashtable configuration; + * CommPortIdentifier id; + * + * synchronized void open(CommPortIdentifier id, + * BundleContext context) { + * this.id = id; + * registration = context.registerService( + * ManagedService.class.getName(), + * this, + * getDefaults() + * ); + * } + * + * Hashtable getDefaults() { + * Hashtable defaults = new Hashtable(); + * defaults.put( "port", id.getName() ); + * defaults.put( "product", "unknown" ); + * defaults.put( "baud", "9600" ); + * defaults.put( Constants.SERVICE_PID, + * "com.acme.serialport." + id.getName() ); + * return defaults; + * } + * + * public synchronized void updated( + * Dictionary configuration ) { + * if ( configuration == null ) + * registration.setProperties( getDefaults() ); + * else { + * setSpeed( configuration.get("baud") ); + * registration.setProperties( configuration ); + * } + * } + * ... + * } + * + * </pre> + * + * <p> + * As a convention, it is recommended that when a Managed Service is updated, it + * should copy all the properties it does not recognize into the service + * registration properties. This will allow the Configuration Admin service to + * set properties on services which can then be used by other applications. + * + * <p> + * Normally, a single Managed Service for a given PID is given the configuration + * dictionary, this is the configuration that is bound to the location of the + * registering bundle. However, when security is on, a Managed Service can have + * Configuration Permission to also be updated for other locations. + * + * @author $Id$ + */ +@ConsumerType +public interface ManagedService { + /** + * Update the configuration for a Managed Service. + * + * <p> + * When the implementation of {@code updated(Dictionary)} detects any kind + * of error in the configuration properties, it should create a new + * {@code ConfigurationException} which describes the problem. This can + * allow a management system to provide useful information to a human + * administrator. + * + * <p> + * If this method throws any other {@code Exception}, the Configuration + * Admin service must catch it and should log it. + * <p> + * The Configuration Admin service must call this method asynchronously with + * the method that initiated the callback. This implies that implementors of + * Managed Service can be assured that the callback will not take place + * during registration when they execute the registration in a synchronized + * method. + * + * <p> + * If the the location allows multiple managed services to be called back + * for a single configuration then the callbacks must occur in service + * ranking order. Changes in the location must be reflected by deleting the + * configuration if the configuration is no longer visible and updating when + * it becomes visible. + * + * <p> + * If no configuration exists for the corresponding PID, or the bundle has + * no access to the configuration, then the bundle must be called back with + * a {@code null} to signal that CM is active but there is no data. + * + * @param properties A copy of the Configuration properties, or {@code null} + * . This argument must not contain the "service.bundleLocation" + * property. The value of this property may be obtained from the + * {@code Configuration.getBundleLocation} method. + * @throws ConfigurationException when the update fails + * @security ConfigurationPermission[c.location,TARGET] Required by the + * bundle that registered this service + */ + public void updated(Dictionary<String, ?> properties) throws ConfigurationException; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ManagedServiceFactory.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ManagedServiceFactory.java new file mode 100644 index 000000000..e1d53892f --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/ManagedServiceFactory.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.cm; + +import java.util.Dictionary; +import org.osgi.annotation.versioning.ConsumerType; + +/** + * Manage multiple service instances. + * + * Bundles registering this interface are giving the Configuration Admin service + * the ability to create and configure a number of instances of a service that + * the implementing bundle can provide. For example, a bundle implementing a + * DHCP server could be instantiated multiple times for different interfaces + * using a factory. + * + * <p> + * Each of these <i>service instances </i> is represented, in the persistent + * storage of the Configuration Admin service, by a factory + * {@code Configuration} object that has a PID. When such a + * {@code Configuration} is updated, the Configuration Admin service calls the + * {@code ManagedServiceFactory} updated method with the new properties. When + * {@code updated} is called with a new PID, the Managed Service Factory should + * create a new factory instance based on these configuration properties. When + * called with a PID that it has seen before, it should update that existing + * service instance with the new configuration information. + * + * <p> + * In general it is expected that the implementation of this interface will + * maintain a data structure that maps PIDs to the factory instances that it has + * created. The semantics of a factory instance are defined by the Managed + * Service Factory. However, if the factory instance is registered as a service + * object with the service registry, its PID should match the PID of the + * corresponding {@code Configuration} object (but it should <b>not </b> be + * registered as a Managed Service!). + * + * <p> + * An example that demonstrates the use of a factory. It will create serial + * ports under command of the Configuration Admin service. + * + * <pre> + * + * class SerialPortFactory + * implements ManagedServiceFactory { + * ServiceRegistration registration; + * Hashtable ports; + * void start(BundleContext context) { + * Hashtable properties = new Hashtable(); + * properties.put( Constants.SERVICE_PID, + * "com.acme.serialportfactory" ); + * registration = context.registerService( + * ManagedServiceFactory.class.getName(), + * this, + * properties + * ); + * } + * public void updated( String pid, + * Dictionary properties ) { + * String portName = (String) properties.get("port"); + * SerialPortService port = + * (SerialPort) ports.get( pid ); + * if ( port == null ) { + * port = new SerialPortService(); + * ports.put( pid, port ); + * port.open(); + * } + * if ( port.getPortName().equals(portName) ) + * return; + * port.setPortName( portName ); + * } + * public void deleted( String pid ) { + * SerialPortService port = + * (SerialPort) ports.get( pid ); + * port.close(); + * ports.remove( pid ); + * } + * ... + * } + * + * </pre> + * + * @author $Id$ + */ +@ConsumerType +public interface ManagedServiceFactory { + /** + * Return a descriptive name of this factory. + * + * @return the name for the factory, which might be localized + */ + public String getName(); + + /** + * Create a new instance, or update the configuration of an existing + * instance. + * + * If the PID of the {@code Configuration} object is new for the Managed + * Service Factory, then create a new factory instance, using the + * configuration {@code properties} provided. Else, update the service + * instance with the provided {@code properties}. + * + * <p> + * If the factory instance is registered with the Framework, then the + * configuration {@code properties} should be copied to its registry + * properties. This is not mandatory and security sensitive properties + * should obviously not be copied. + * + * <p> + * If this method throws any {@code Exception}, the Configuration Admin + * service must catch it and should log it. + * + * <p> + * When the implementation of updated detects any kind of error in the + * configuration properties, it should create a new + * {@link ConfigurationException} which describes the problem. + * + * <p> + * The Configuration Admin service must call this method asynchronously. + * This implies that implementors of the {@code ManagedServiceFactory} class + * can be assured that the callback will not take place during registration + * when they execute the registration in a synchronized method. + * + * <p> + * If the security allows multiple managed service factories to be called + * back for a single configuration then the callbacks must occur in service + * ranking order. + * + * <p> + * It is valid to create multiple factory instances that are bound to + * different locations. Managed Service Factory services must only be + * updated with configurations that are bound to their location or that + * start with the {@code ?} prefix and for which they have permission. + * Changes in the location must be reflected by deleting the corresponding + * configuration if the configuration is no longer visible or updating when + * it becomes visible. + * + * @param pid The PID for this configuration. + * @param properties A copy of the configuration properties. This argument + * must not contain the service.bundleLocation" property. The value + * of this property may be obtained from the + * {@code Configuration.getBundleLocation} method. + * @throws ConfigurationException when the configuration properties are + * invalid. + * @security ConfigurationPermission[c.location,TARGET] Required by the + * bundle that registered this service + */ + public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException; + + /** + * Remove a factory instance. + * + * Remove the factory instance associated with the PID. If the instance was + * registered with the service registry, it should be unregistered. The + * Configuration Admin must call deleted for each instance it received in + * {@link #updated(String, Dictionary)}. + * + * <p> + * If this method throws any {@code Exception}, the Configuration Admin + * service must catch it and should log it. + * <p> + * The Configuration Admin service must call this method asynchronously. + * + * @param pid the PID of the service to be removed + */ + public void deleted(String pid); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/SynchronousConfigurationListener.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/SynchronousConfigurationListener.java new file mode 100644 index 000000000..bcd2b68aa --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/SynchronousConfigurationListener.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) OSGi Alliance (2012, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.cm; + +import org.osgi.annotation.versioning.ConsumerType; + +/** + * Synchronous Listener for Configuration Events. When a + * {@code ConfigurationEvent} is fired, it is synchronously delivered to a + * {@code SynchronousConfigurationListener}. + * + * <p> + * {@code SynchronousConfigurationListener} objects are registered with the + * Framework service registry and are synchronously notified with a + * {@code ConfigurationEvent} object when an event is fired. + * <p> + * {@code SynchronousConfigurationListener} objects can inspect the received + * {@code ConfigurationEvent} object to determine its type, the PID of the + * {@code Configuration} object with which it is associated, and the + * Configuration Admin service that fired the event. + * + * <p> + * Security Considerations. Bundles wishing to synchronously monitor + * configuration events will require + * {@code ServicePermission[SynchronousConfigurationListener,REGISTER]} to + * register a {@code SynchronousConfigurationListener} service. + * + * @author $Id$ + * @since 1.5 + */ +@ConsumerType +public interface SynchronousConfigurationListener extends ConfigurationListener { + // Marker interface +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/package-info.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/package-info.java new file mode 100644 index 000000000..f83587772 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/package-info.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) OSGi Alliance (2010, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Configuration Admin Package Version 1.5. + * + * <p> + * Bundles wishing to use this package must list the package in the + * Import-Package header of the bundle's manifest. This package has two types of + * users: the consumers that use the API in this package and the providers that + * implement the API in this package. + * + * <p> + * Example import for consumers using the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.cm; version="[1.5,2.0)"} + * <p> + * Example import for providers implementing the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.cm; version="[1.5,1.6)"} + * + * @author $Id$ + */ + +@Version("1.5") +package org.osgi.service.cm; + +import org.osgi.annotation.versioning.Version; + diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/packageinfo b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/packageinfo new file mode 100644 index 000000000..ccee95e92 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/cm/packageinfo @@ -0,0 +1 @@ +version 1.5 diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/ComponentConstants.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/ComponentConstants.java new file mode 100644 index 000000000..ac753054f --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/ComponentConstants.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) OSGi Alliance (2004, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.component; + +import org.osgi.annotation.versioning.ProviderType; + +/** + * Defines standard names for Service Component constants. + * + * @author $Id$ + */ +@ProviderType +public interface ComponentConstants { + /** + * Manifest header specifying the XML documents within a bundle that contain + * the bundle's Service Component descriptions. + * <p> + * The attribute value may be retrieved from the {@code Dictionary} object + * returned by the {@code Bundle.getHeaders} method. + */ + public static final String SERVICE_COMPONENT = "Service-Component"; + + /** + * A component property for a component configuration that contains the name + * of the component as specified in the {@code name} attribute of the + * {@code component} element. The value of this property must be of type + * {@code String}. + */ + public final static String COMPONENT_NAME = "component.name"; + + /** + * A component property that contains the generated id for a component + * configuration. The value of this property must be of type {@code Long}. + * + * <p> + * The value of this property is assigned by the Service Component Runtime + * when a component configuration is created. The Service Component Runtime + * assigns a unique value that is larger than all previously assigned values + * since the Service Component Runtime was started. These values are NOT + * persistent across restarts of the Service Component Runtime. + */ + public final static String COMPONENT_ID = "component.id"; + + /** + * A service registration property for a Component Factory that contains the + * value of the {@code factory} attribute. The value of this property must + * be of type {@code String}. + */ + public final static String COMPONENT_FACTORY = "component.factory"; + + /** + * The suffix for reference target properties. These properties contain the + * filter to select the target services for a reference. The value of this + * property must be of type {@code String}. + */ + public final static String REFERENCE_TARGET_SUFFIX = ".target"; + + /** + * The reason the component configuration was deactivated is unspecified. + * + * @since 1.1 + */ + public static final int DEACTIVATION_REASON_UNSPECIFIED = 0; + + /** + * The component configuration was deactivated because the component was + * disabled. + * + * @since 1.1 + */ + public static final int DEACTIVATION_REASON_DISABLED = 1; + + /** + * The component configuration was deactivated because a reference became + * unsatisfied. + * + * @since 1.1 + */ + public static final int DEACTIVATION_REASON_REFERENCE = 2; + + /** + * The component configuration was deactivated because its configuration was + * changed. + * + * @since 1.1 + */ + public static final int DEACTIVATION_REASON_CONFIGURATION_MODIFIED = 3; + + /** + * The component configuration was deactivated because its configuration was + * deleted. + * + * @since 1.1 + */ + public static final int DEACTIVATION_REASON_CONFIGURATION_DELETED = 4; + + /** + * The component configuration was deactivated because the component was + * disposed. + * + * @since 1.1 + */ + public static final int DEACTIVATION_REASON_DISPOSED = 5; + + /** + * The component configuration was deactivated because the bundle was + * stopped. + * + * @since 1.1 + */ + public static final int DEACTIVATION_REASON_BUNDLE_STOPPED = 6; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/ComponentContext.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/ComponentContext.java new file mode 100644 index 000000000..9855c2af8 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/ComponentContext.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) OSGi Alliance (2004, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.component; + +import java.util.Dictionary; +import org.osgi.annotation.versioning.ProviderType; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +/** + * A Component Context object is used by a component instance to interact with + * its execution context including locating services by reference name. Each + * component instance has a unique Component Context. + * + * <p> + * A component instance may have an activate method. If a component instance has + * a suitable and accessible activate method, this method will be called when a + * component configuration is activated. If the activate method takes a + * {@code ComponentContext} argument, it will be passed the component instance's + * Component Context object. If the activate method takes a + * {@code BundleContext} argument, it will be passed the component instance's + * Bundle Context object. If the activate method takes a {@code Map} argument, + * it will be passed an unmodifiable Map containing the component properties. + * + * <p> + * A component instance may have a deactivate method. If a component instance + * has a suitable and accessible deactivate method, this method will be called + * when the component configuration is deactivated. If the deactivate method + * takes a {@code ComponentContext} argument, it will be passed the component + * instance's Component Context object. If the deactivate method takes a + * {@code BundleContext} argument, it will be passed the component instance's + * Bundle Context object. If the deactivate method takes a {@code Map} argument, + * it will be passed an unmodifiable Map containing the component properties. If + * the deactivate method takes an {@code int} or {@code Integer} argument, it + * will be passed the reason code for the component instance's deactivation. + * + * @ThreadSafe + * @author $Id$ + */ +@ProviderType +public interface ComponentContext { + /** + * Returns the component properties for this Component Context. + * + * @return The properties for this Component Context. The Dictionary is read + * only and cannot be modified. + */ + public Dictionary<String, Object> getProperties(); + + /** + * Returns the service object for the specified reference name. + * + * <p> + * If the cardinality of the reference is {@code 0..n} or {@code 1..n} and + * multiple services are bound to the reference, the service with the + * highest ranking (as specified in its {@code Constants.SERVICE_RANKING} + * property) is returned. If there is a tie in ranking, the service with the + * lowest service ID (as specified in its {@code Constants.SERVICE_ID} + * property); that is, the service that was registered first is returned. + * + * @param name The name of a reference as specified in a {@code reference} + * element in this component's description. + * @return A service object for the referenced service or {@code null} if + * the reference cardinality is {@code 0..1} or {@code 0..n} and no + * bound service is available. + * @throws ComponentException If the Service Component Runtime catches an + * exception while activating the bound service. + */ + public Object locateService(String name); + + /** + * Returns the service object for the specified reference name and + * {@code ServiceReference}. + * + * @param name The name of a reference as specified in a {@code reference} + * element in this component's description. + * @param reference The {@code ServiceReference} to a bound service. This + * must be a {@code ServiceReference} provided to the component via + * the bind or unbind method for the specified reference name. + * @return A service object for the referenced service or {@code null} if + * the specified {@code ServiceReference} is not a bound service for + * the specified reference name. + * @throws ComponentException If the Service Component Runtime catches an + * exception while activating the bound service. + */ + public Object locateService(String name, ServiceReference<?> reference); + + /** + * Returns the service objects for the specified reference name. + * + * @param name The name of a reference as specified in a {@code reference} + * element in this component's description. + * @return An array of service objects for the referenced service or + * {@code null} if the reference cardinality is {@code 0..1} or + * {@code 0..n} and no bound service is available. If the reference + * cardinality is {@code 0..1} or {@code 1..1} and a bound service + * is available, the array will have exactly one element. + * @throws ComponentException If the Service Component Runtime catches an + * exception while activating a bound service. + */ + public Object[] locateServices(String name); + + /** + * Returns the {@code BundleContext} of the bundle which contains this + * component. + * + * @return The {@code BundleContext} of the bundle containing this + * component. + */ + public BundleContext getBundleContext(); + + /** + * If the component instance is registered as a service using the + * {@code servicefactory="true"} attribute, then this method returns the + * bundle using the service provided by the component instance. + * <p> + * This method will return {@code null} if: + * <ul> + * <li>The component instance is not a service, then no bundle can be using + * it as a service.</li> + * <li>The component instance is a service but did not specify the + * {@code servicefactory="true"} attribute, then all bundles using the + * service provided by the component instance will share the same component + * instance.</li> + * <li>The service provided by the component instance is not currently being + * used by any bundle.</li> + * </ul> + * + * @return The bundle using the component instance as a service or + * {@code null}. + */ + public Bundle getUsingBundle(); + + /** + * Returns the Component Instance object for the component instance + * associated with this Component Context. + * + * @return The Component Instance object for the component instance. + */ + public ComponentInstance getComponentInstance(); + + /** + * Enables the specified component name. The specified component name must + * be in the same bundle as this component. + * + * @param name The name of a component or {@code null} to indicate all + * components in the bundle. + */ + public void enableComponent(String name); + + /** + * Disables the specified component name. The specified component name must + * be in the same bundle as this component. + * + * @param name The name of a component. + */ + public void disableComponent(String name); + + /** + * If the component instance is registered as a service using the + * {@code service} element, then this method returns the service reference + * of the service provided by this component instance. + * <p> + * This method will return {@code null} if the component instance is not + * registered as a service. + * + * @return The {@code ServiceReference} object for the component instance or + * {@code null} if the component instance is not registered as a + * service. + */ + public ServiceReference<?> getServiceReference(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/ComponentException.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/ComponentException.java new file mode 100644 index 000000000..9ec6a42f2 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/ComponentException.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) OSGi Alliance (2004, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.component; + +/** + * Unchecked exception which may be thrown by the Service Component Runtime. + * + * @author $Id$ + */ +public class ComponentException extends RuntimeException { + static final long serialVersionUID = -7438212656298726924L; + + /** + * Construct a new ComponentException with the specified message and cause. + * + * @param message The message for the exception. + * @param cause The cause of the exception. May be {@code null}. + */ + public ComponentException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Construct a new ComponentException with the specified message. + * + * @param message The message for the exception. + */ + public ComponentException(String message) { + super(message); + } + + /** + * Construct a new ComponentException with the specified cause. + * + * @param cause The cause of the exception. May be {@code null}. + */ + public ComponentException(Throwable cause) { + super(cause); + } + + /** + * Returns the cause of this exception or {@code null} if no cause was set. + * + * @return The cause of this exception or {@code null} if no cause was set. + */ + @Override + public Throwable getCause() { + return super.getCause(); + } + + /** + * Initializes the cause of this exception to the specified value. + * + * @param cause The cause of this exception. + * @return This exception. + * @throws IllegalArgumentException If the specified cause is this + * exception. + * @throws IllegalStateException If the cause of this exception has already + * been set. + */ + @Override + public Throwable initCause(Throwable cause) { + return super.initCause(cause); + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/ComponentFactory.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/ComponentFactory.java new file mode 100644 index 000000000..efb1e1695 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/ComponentFactory.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) OSGi Alliance (2004, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.component; + +import java.util.Dictionary; +import org.osgi.annotation.versioning.ProviderType; + +/** + * When a component is declared with the {@code factory} attribute on its + * {@code component} element, the Service Component Runtime will register a + * Component Factory service to allow new component configurations to be created + * and activated rather than automatically creating and activating component + * configuration as necessary. + * + * @ThreadSafe + * @author $Id$ + */ +@ProviderType +public interface ComponentFactory { + /** + * Create and activate a new component configuration. Additional properties + * may be provided for the component configuration. + * + * @param properties Additional properties for the component configuration + * or {@code null} if there are no additional properties. + * @return A {@code ComponentInstance} object encapsulating the component + * instance of the component configuration. The component + * configuration has been activated and, if the component specifies + * a {@code service} element, the component instance has been + * registered as a service. + * @throws ComponentException If the Service Component Runtime is unable to + * activate the component configuration. + */ + public ComponentInstance newInstance(Dictionary<String, ?> properties); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/ComponentInstance.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/ComponentInstance.java new file mode 100644 index 000000000..8078babdd --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/ComponentInstance.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) OSGi Alliance (2004, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.component; + +import org.osgi.annotation.versioning.ProviderType; + +/** + * A ComponentInstance encapsulates a component instance of an activated + * component configuration. ComponentInstances are created whenever a component + * configuration is activated. + * + * <p> + * ComponentInstances are never reused. A new ComponentInstance object will be + * created when the component configuration is activated again. + * + * @ThreadSafe + * @author $Id$ + */ +@ProviderType +public interface ComponentInstance { + /** + * Dispose of the component configuration for this component instance. The + * component configuration will be deactivated. If the component + * configuration has already been deactivated, this method does nothing. + */ + public void dispose(); + + /** + * Returns the component instance of the activated component configuration. + * + * @return The component instance or {@code null} if the component + * configuration has been deactivated. + */ + public Object getInstance(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/Activate.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/Activate.java new file mode 100644 index 000000000..e24a899f7 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/Activate.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) OSGi Alliance (2011, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.component.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Identify the annotated method as the {@code activate} method of a Service + * Component. + * + * <p> + * The annotated method is the activate method of the Component. + * + * <p> + * This annotation is not processed at runtime by a Service Component Runtime + * implementation. It must be processed by tools and used to add a Component + * Description to the bundle. + * + * @see "The activate attribute of the component element of a Component Description." + * @author $Id$ + * @since 1.1 + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.METHOD) +public @interface Activate { + // marker annotation +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/Component.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/Component.java new file mode 100644 index 000000000..e7f072364 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/Component.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) OSGi Alliance (2011, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.component.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Identify the annotated class as a Service Component. + * + * <p> + * The annotated class is the implementation class of the Component. + * + * <p> + * This annotation is not processed at runtime by a Service Component Runtime + * implementation. It must be processed by tools and used to add a Component + * Description to the bundle. + * + * @see "The component element of a Component Description." + * @author $Id$ + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.TYPE) +public @interface Component { + /** + * The name of this Component. + * + * <p> + * If not specified, the name of this Component is the fully qualified type + * name of the class being annotated. + * + * @see "The name attribute of the component element of a Component Description." + */ + String name() default ""; + + /** + * The types under which to register this Component as a service. + * + * <p> + * If no service should be registered, the empty value + * <code>{}</code> must be specified. + * + * <p> + * If not specified, the service types for this Component are all the + * <i>directly</i> implemented interfaces of the class being annotated. + * + * @see "The service element of a Component Description." + */ + Class<?>[] service() default {}; + + /** + * The factory identifier of this Component. Specifying a factory identifier + * makes this Component a Factory Component. + * + * <p> + * If not specified, the default is that this Component is not a Factory + * Component. + * + * @see "The factory attribute of the component element of a Component Description." + */ + String factory() default ""; + + /** + * Declares whether this Component uses the OSGi ServiceFactory concept and + * each bundle using this Component's service will receive a different + * component instance. + * + * <p> + * If {@code true}, this Component uses the OSGi ServiceFactory concept. If + * {@code false} or not specified, this Component does not use the OSGi + * ServiceFactory concept. + * + * @see "The servicefactory attribute of the service element of a Component Description." + */ + boolean servicefactory() default false; + + /** + * Declares whether this Component is enabled when the bundle containing it + * is started. + * + * <p> + * If {@code true}, this Component is enabled. If {@code false} or not + * specified, this Component is disabled. + * + * @see "The enabled attribute of the component element of a Component Description." + */ + boolean enabled() default true; + + /** + * Declares whether this Component must be immediately activated upon + * becoming satisfied or whether activation should be delayed. + * + * <p> + * If {@code true}, this Component must be immediately activated upon + * becoming satisfied. If {@code false}, activation of this Component is + * delayed. If this property is specified, its value must be {@code false} + * if the {@link #factory} property is also specified or must be + * {@code true} if the {@link #service} property is specified with an empty + * value. + * + * <p> + * If not specified, the default is {@code false} if the {@link #factory} + * property is specified or the {@link #service} property is not specified + * or specified with a non-empty value and {@code true} otherwise. + * + * @see "The immediate attribute of the component element of a Component Description." + */ + boolean immediate() default false; + + /** + * Properties for this Component. + * + * <p> + * Each property string is specified as {@code "key=value"}. The type of the + * property value can be specified in the key as {@code key:type=value}. The + * type must be one of the property types supported by the type attribute of + * the property element of a Component Description. + * + * <p> + * To specify a property with multiple values, use multiple key, value + * pairs. For example, {@code "foo=bar", "foo=baz"}. + * + * @see "The property element of a Component Description." + */ + String[] property() default {}; + + /** + * Property entries for this Component. + * + * <p> + * Specifies the name of an entry in the bundle whose contents conform to a + * standard Java Properties File. The entry is read and processed to obtain + * the properties and their values. + * + * @see "The properties element of a Component Description." + */ + String[] properties() default {}; + + /** + * The XML name space of the Component Description for this Component. + * + * <p> + * If not specified, the XML name space of the Component Description for + * this Component should be the lowest Declarative Services XML name space + * which supports all the specification features used by this Component. + * + * @see "The XML name space specified for a Component Description." + */ + String xmlns() default ""; + + /** + * The configuration policy of this Component. + * + * <p> + * Controls whether component configurations must be satisfied depending on + * the presence of a corresponding Configuration object in the OSGi + * Configuration Admin service. A corresponding configuration is a + * Configuration object where the PID equals the name of the component. + * + * <p> + * If not specified, the {@link ConfigurationPolicy#OPTIONAL OPTIONAL} + * configuration policy is used. + * + * @see "The configuration-policy attribute of the component element of a Component Description." + * @since 1.1 + */ + ConfigurationPolicy configurationPolicy() default ConfigurationPolicy.OPTIONAL; + + /** + * The configuration PID for the configuration of this Component. + * + * <p> + * Allows the configuration PID for this Component to be different than the + * name of this Component. + * + * <p> + * If not specified, the name of this Component is used as the configuration + * PID of this Component. + * + * @see "The configuration-pid attribute of the component element of a Component Description." + * @since 1.2 + */ + String configurationPid() default ""; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/ConfigurationPolicy.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/ConfigurationPolicy.java new file mode 100644 index 000000000..2bb2640ae --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/ConfigurationPolicy.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) OSGi Alliance (2011, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.component.annotations; + +/** + * Configuration Policy for the {@link Component} annotation. + * + * <p> + * Controls whether component configurations must be satisfied depending on the + * presence of a corresponding Configuration object in the OSGi Configuration + * Admin service. A corresponding configuration is a Configuration object where + * the PID is the name of the component. + * + * @author $Id$ + * @since 1.1 + */ +public enum ConfigurationPolicy { + /** + * Use the corresponding Configuration object if present but allow the + * component to be satisfied even if the corresponding Configuration object + * is not present. + */ + OPTIONAL("optional"), + + /** + * There must be a corresponding Configuration object for the component + * configuration to become satisfied. + */ + REQUIRE("require"), + + /** + * Always allow the component configuration to be satisfied and do not use + * the corresponding Configuration object even if it is present. + */ + IGNORE("ignore"); + + private final String value; + + ConfigurationPolicy(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/Deactivate.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/Deactivate.java new file mode 100644 index 000000000..1809c70eb --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/Deactivate.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) OSGi Alliance (2011, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.component.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Identify the annotated method as the {@code deactivate} method of a Service + * Component. + * + * <p> + * The annotated method is the deactivate method of the Component. + * + * <p> + * This annotation is not processed at runtime by a Service Component Runtime + * implementation. It must be processed by tools and used to add a Component + * Description to the bundle. + * + * @see "The deactivate attribute of the component element of a Component Description." + * @author $Id$ + * @since 1.1 + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.METHOD) +public @interface Deactivate { + // marker annotation +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/Modified.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/Modified.java new file mode 100644 index 000000000..fd9f97d2f --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/Modified.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) OSGi Alliance (2011, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.component.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Identify the annotated method as the {@code modified} method of a Service + * Component. + * + * <p> + * The annotated method is the modified method of the Component. + * + * <p> + * This annotation is not processed at runtime by a Service Component Runtime + * implementation. It must be processed by tools and used to add a Component + * Description to the bundle. + * + * @see "The modified attribute of the component element of a Component Description." + * @author $Id$ + * @since 1.1 + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.METHOD) +public @interface Modified { + // marker annotation +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/Reference.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/Reference.java new file mode 100644 index 000000000..9887c51c7 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/Reference.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) OSGi Alliance (2011, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.component.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Identify the annotated method as a {@code bind} method of a Service + * Component. + * + * <p> + * The annotated method is a bind method of the Component. + * + * <p> + * This annotation is not processed at runtime by a Service Component Runtime + * implementation. It must be processed by tools and used to add a Component + * Description to the bundle. + * + * <p> + * In the generated Component Description for a component, the references must + * be ordered in ascending lexicographical order (using {@code String.compareTo} + * ) of the reference {@link #name() name}s. + * + * @see "The reference element of a Component Description." + * @author $Id$ + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.METHOD) +public @interface Reference { + /** + * The name of this reference. + * + * <p> + * If not specified, the name of this reference is based upon the name of + * the method being annotated. If the method name begins with {@code bind}, + * {@code set} or {@code add}, that is removed. + * + * @see "The name attribute of the reference element of a Component Description." + */ + String name() default ""; + + /** + * The type of the service to bind to this reference. + * + * <p> + * If not specified, the type of the service to bind is based upon the type + * of the first argument of the method being annotated. + * + * @see "The interface attribute of the reference element of a Component Description." + */ + Class<?> service() default Object.class; + + /** + * The cardinality of the reference. + * + * <p> + * If not specified, the reference has a + * {@link ReferenceCardinality#MANDATORY 1..1} cardinality. + * + * @see "The cardinality attribute of the reference element of a Component Description." + */ + ReferenceCardinality cardinality() default ReferenceCardinality.MANDATORY; + + /** + * The policy for the reference. + * + * <p> + * If not specified, the {@link ReferencePolicy#STATIC STATIC} reference + * policy is used. + * + * @see "The policy attribute of the reference element of a Component Description." + */ + ReferencePolicy policy() default ReferencePolicy.STATIC; + + /** + * The target filter for the reference. + * + * @see "The target attribute of the reference element of a Component Description." + */ + String target() default ""; + + /** + * The name of the unbind method which is associated with the annotated bind + * method. + * + * <p> + * To declare no unbind method, the value {@code "-"} must be used. + * + * <p> + * If not specified, the name of the unbind method is derived from the name + * of the annotated bind method. If the annotated method name begins with + * {@code bind}, {@code set} or {@code add}, that is replaced with + * {@code unbind}, {@code unset} or {@code remove}, respectively, to derive + * the unbind method name. Otherwise, {@code un} is prefixed to the + * annotated method name to derive the unbind method name. The unbind method + * is only set if the component type contains a method with the derived + * name. + * + * @see "The unbind attribute of the reference element of a Component Description." + */ + String unbind() default ""; + + /** + * The policy option for the reference. + * + * <p> + * If not specified, the {@link ReferencePolicyOption#RELUCTANT RELUCTANT} + * reference policy option is used. + * + * @see "The policy-option attribute of the reference element of a Component Description." + * @since 1.2 + */ + ReferencePolicyOption policyOption() default ReferencePolicyOption.RELUCTANT; + + /** + * The name of the updated method which is associated with the annotated + * bind method. + * + * <p> + * To declare no updated method, the value {@code "-"} must be used. + * + * <p> + * If not specified, the name of the updated method is derived from the name + * of the annotated bind method. If the annotated method name begins with + * {@code bind}, {@code set} or {@code add}, that is replaced with + * {@code updated} to derive the updated method name. Otherwise, + * {@code updated} is prefixed to the annotated method name to derive the + * updated method name. The updated method is only set if the component type + * contains a method with the derived name. + * + * @see "The updated attribute of the reference element of a Component Description." + * @since 1.2 + */ + String updated() default ""; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/ReferenceCardinality.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/ReferenceCardinality.java new file mode 100644 index 000000000..f01a55c3e --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/ReferenceCardinality.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) OSGi Alliance (2011, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.component.annotations; + +/** + * Cardinality for the {@link Reference} annotation. + * + * <p> + * Specifies if the reference is optional and if the component implementation + * support a single bound service or multiple bound services. + * + * @author $Id$ + */ +public enum ReferenceCardinality { + /** + * The reference is optional and unary. That is, the reference has a + * cardinality of {@code 0..1}. + */ + OPTIONAL("0..1"), + + /** + * The reference is mandatory and unary. That is, the reference has a + * cardinality of {@code 1..1}. + */ + MANDATORY("1..1"), + + /** + * The reference is optional and multiple. That is, the reference has a + * cardinality of {@code 0..n}. + */ + MULTIPLE("0..n"), + + /** + * The reference is mandatory and multiple. That is, the reference has a + * cardinality of {@code 1..n}. + */ + AT_LEAST_ONE("1..n"); + + private final String value; + + ReferenceCardinality(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/ReferencePolicy.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/ReferencePolicy.java new file mode 100644 index 000000000..835125670 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/ReferencePolicy.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) OSGi Alliance (2011, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.component.annotations; + +/** + * Policy for the {@link Reference} annotation. + * + * @author $Id$ + */ +public enum ReferencePolicy { + /** + * The static policy is the most simple policy and is the default policy. A + * component instance never sees any of the dynamics. Component + * configurations are deactivated before any bound service for a reference + * having a static policy becomes unavailable. If a target service is + * available to replace the bound service which became unavailable, the + * component configuration must be reactivated and bound to the replacement + * service. + */ + STATIC("static"), + + /** + * The dynamic policy is slightly more complex since the component + * implementation must properly handle changes in the set of bound services. + * With the dynamic policy, SCR can change the set of bound services without + * deactivating a component configuration. If the component uses the event + * strategy to access services, then the component instance will be notified + * of changes in the set of bound services by calls to the bind and unbind + * methods. + */ + DYNAMIC("dynamic"); + + private final String value; + + ReferencePolicy(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/ReferencePolicyOption.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/ReferencePolicyOption.java new file mode 100644 index 000000000..1023cb41a --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/ReferencePolicyOption.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) OSGi Alliance (2011, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.component.annotations; + +/** + * Policy option for the {@link Reference} annotation. + * + * @author $Id$ + * @since 1.2 + */ +public enum ReferencePolicyOption { + /** + * The reluctant policy option is the default policy option for both + * {@link ReferencePolicy#STATIC static} and {@link ReferencePolicy#DYNAMIC + * dynamic} reference policies. When a new target service for a reference + * becomes available, references having the reluctant policy option for the + * static policy or the dynamic policy with a unary cardinality will ignore + * the new target service. References having the dynamic policy with a + * multiple cardinality will bind the new target service. + */ + RELUCTANT("reluctant"), + + /** + * The greedy policy option is a valid policy option for both + * {@link ReferencePolicy#STATIC static} and {@link ReferencePolicy#DYNAMIC + * dynamic} reference policies. When a new target service for a reference + * becomes available, references having the greedy policy option will bind + * the new target service. + */ + GREEDY("greedy"); + + private final String value; + + ReferencePolicyOption(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/package-info.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/package-info.java new file mode 100644 index 000000000..dbfa48a1b --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/package-info.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) OSGi Alliance (2011, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Service Component Annotations Package Version 1.2. + * + * <p> + * This package is not used at runtime. Annotated classes are processed by + * tools to generate Component Descriptions which are used at runtime. + * + * @author $Id$ + */ + +@Version("1.2") +package org.osgi.service.component.annotations; + +import org.osgi.annotation.versioning.Version; + diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/packageinfo b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/packageinfo new file mode 100644 index 000000000..ef7df68cb --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/annotations/packageinfo @@ -0,0 +1 @@ +version 1.2 diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/package-info.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/package-info.java new file mode 100644 index 000000000..4b472f45b --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/package-info.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) OSGi Alliance (2010, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Service Component Package Version 1.2. + * + * <p> + * Bundles wishing to use this package must list the package in the + * Import-Package header of the bundle's manifest. This package has two types of + * users: the consumers that use the API in this package and the providers that + * implement the API in this package. + * + * <p> + * Example import for consumers using the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.component; version="[1.2,2.0)"} + * <p> + * Example import for providers implementing the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.component; version="[1.2,1.3)"} + * + * @author $Id$ + */ + +@Version("1.2.2") +package org.osgi.service.component; + +import org.osgi.annotation.versioning.Version; + diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/packageinfo b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/packageinfo new file mode 100644 index 000000000..19727573b --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/component/packageinfo @@ -0,0 +1 @@ +version 1.2.2 diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/Constants.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/Constants.java new file mode 100644 index 000000000..967b949d6 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/Constants.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) OSGi Alliance (2000, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.device; + +/** + * This interface defines standard names for property keys associated with + * {@link Device} and {@link Driver} services. + * + * <p> + * The values associated with these keys are of type {@code java.lang.String}, + * unless otherwise stated. + * + * @noimplement + * @author $Id$ + * @since 1.1 + * @see Device + * @see Driver + */ +public interface Constants { + /** + * Property (named "DRIVER_ID") identifying a driver. + * + * <p> + * A {@code DRIVER_ID} should start with the reversed domain name of the + * company that implemented the driver (e.g., {@code com.acme}), and must + * meet the following requirements: + * + * <ul> + * <li>It must be independent of the location from where it is obtained.</li> + * <li>It must be independent of the {@link DriverLocator} service that + * downloaded it.</li> + * <li>It must be unique.</li> + * <li>It must be different for different revisions of the same driver.</li> + * </ul> + * + * <p> + * This property is mandatory, i.e., every {@code Driver} service must be + * registered with it. + */ + public static final String DRIVER_ID = "DRIVER_ID"; + /** + * Property (named "DEVICE_CATEGORY") containing a human readable + * description of the device categories implemented by a device. This + * property is of type {@code String[]} + * + * <p> + * Services registered with this property will be treated as devices and + * discovered by the device manager + */ + public static final String DEVICE_CATEGORY = "DEVICE_CATEGORY"; + /** + * Property (named "DEVICE_SERIAL") specifying a device's serial + * number. + */ + public static final String DEVICE_SERIAL = "DEVICE_SERIAL"; + /** + * Property (named "DEVICE_DESCRIPTION") containing a human + * readable string describing the actual hardware device. + */ + public static final String DEVICE_DESCRIPTION = "DEVICE_DESCRIPTION"; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/Device.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/Device.java new file mode 100644 index 000000000..a3f26e7ec --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/Device.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) OSGi Alliance (2000, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.device; + +import org.osgi.framework.ServiceReference; + +/** + * <p> + * Interface for identifying device services. + * + * <p> + * A service must implement this interface or use the + * {@link Constants#DEVICE_CATEGORY} registration property to indicate that it + * is a device. Any services implementing this interface or registered with the + * {@code DEVICE_CATEGORY} property will be discovered by the device manager. + * + * <p> + * Device services implementing this interface give the device manager the + * opportunity to indicate to the device that no drivers were found that could + * (further) refine it. In this case, the device manager calls the + * {@link #noDriverFound()} method on the {@code Device} object. + * + * <p> + * Specialized device implementations will extend this interface by adding + * methods appropriate to their device category to it. + * + * @author $Id$ + * @see Driver + * @ThreadSafe + */ +public interface Device { + /** + * Return value from {@link Driver#match(ServiceReference)} indicating that + * the driver cannot refine the device presented to it by the device + * manager. + * + * The value is zero. + */ + public static final int MATCH_NONE = 0; + + /** + * Indicates to this {@code Device} object that the device manager has + * failed to attach any drivers to it. + * + * <p> + * If this {@code Device} object can be configured differently, the driver + * that registered this {@code Device} object may unregister it and register + * a different Device service instead. + */ + public void noDriverFound(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/Driver.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/Driver.java new file mode 100644 index 000000000..db46dfadf --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/Driver.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) OSGi Alliance (2000, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.device; + +import org.osgi.framework.ServiceReference; + +/** + * A {@code Driver} service object must be registered by each Driver bundle + * wishing to attach to Device services provided by other drivers. For each + * newly discovered {@link Device} object, the device manager enters a bidding + * phase. The {@code Driver} object whose {@link #match(ServiceReference)} + * method bids the highest for a particular {@code Device} object will be + * instructed by the device manager to attach to the {@code Device} object. + * + * @author $Id$ + * @see Device + * @see DriverLocator + * @ThreadSafe + */ +public interface Driver { + /** + * Checks whether this Driver service can be attached to the Device service. + * + * The Device service is represented by the given {@link ServiceReference} + * and returns a value indicating how well this driver can support the given + * Device service, or {@link Device#MATCH_NONE} if it cannot support the + * given Device service at all. + * + * <p> + * The return value must be one of the possible match values defined in the + * device category definition for the given Device service, or + * {@code Device.MATCH_NONE} if the category of the Device service is not + * recognized. + * + * <p> + * In order to make its decision, this Driver service may examine the + * properties associated with the given Device service, or may get the + * referenced service object (representing the actual physical device) to + * talk to it, as long as it ungets the service and returns the physical + * device to a normal state before this method returns. + * + * <p> + * A Driver service must always return the same match code whenever it is + * presented with the same Device service. + * + * <p> + * The match function is called by the device manager during the matching + * process. + * + * @param reference the {@code ServiceReference} object of the device to + * match + * + * @return value indicating how well this driver can support the given + * Device service, or {@code Device.MATCH_NONE} if it cannot support + * the Device service at all + * + * @throws java.lang.Exception if this Driver service cannot examine the + * Device service + */ + public int match(ServiceReference reference) throws Exception; + + /** + * Attaches this Driver service to the Device service represented by the + * given {@code ServiceReference} object. + * + * <p> + * A return value of {@code null} indicates that this Driver service has + * successfully attached to the given Device service. If this Driver service + * is unable to attach to the given Device service, but knows of a more + * suitable Driver service, it must return the {@code DRIVER_ID} of that + * Driver service. This allows for the implementation of referring drivers + * whose only purpose is to refer to other drivers capable of handling a + * given Device service. + * + * <p> + * After having attached to the Device service, this driver may register the + * underlying device as a new service exposing driver-specific + * functionality. + * + * <p> + * This method is called by the device manager. + * + * @param reference the {@code ServiceReference} object of the device to + * attach to + * + * @return {@code null} if this Driver service has successfully attached to + * the given Device service, or the {@code DRIVER_ID} of a more + * suitable driver + * + * @throws java.lang.Exception if the driver cannot attach to the given + * device and does not know of a more suitable driver + */ + public String attach(ServiceReference reference) throws Exception; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/DriverLocator.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/DriverLocator.java new file mode 100644 index 000000000..fdbe1a5d8 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/DriverLocator.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) OSGi Alliance (2000, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.device; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Dictionary; + +/** + * A Driver Locator service can find and load device driver bundles given a + * property set. Each driver is represented by a unique {@code DRIVER_ID}. + * <p> + * Driver Locator services provide the mechanism for dynamically downloading new + * device driver bundles into an OSGi environment. They are supplied by + * providers and encapsulate all provider-specific details related to the + * location and acquisition of driver bundles. + * + * @author $Id$ + * @see Driver + * @ThreadSafe + */ +public interface DriverLocator { + /** + * Returns an array of {@code DRIVER_ID} strings of drivers capable of + * attaching to a device with the given properties. + * + * <p> + * The property keys in the specified {@code Dictionary} objects are + * case-insensitive. + * + * @param props the properties of the device for which a driver is sought + * @return array of driver {@code DRIVER_ID} strings of drivers capable of + * attaching to a Device service with the given properties, or + * {@code null} if this Driver Locator service does not know of any + * such drivers + */ + public String[] findDrivers(Dictionary props); + + /** + * Get an {@code InputStream} from which the driver bundle providing a + * driver with the giving {@code DRIVER_ID} can be installed. + * + * @param id the {@code DRIVER_ID} of the driver that needs to be installed. + * @return An {@code InputStream} object from which the driver bundle can be + * installed or {@code null} if the driver with the given ID cannot + * be located + * @throws java.io.IOException the input stream for the bundle cannot be + * created + */ + public InputStream loadDriver(String id) throws IOException; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/DriverSelector.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/DriverSelector.java new file mode 100644 index 000000000..179ecc7fc --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/DriverSelector.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.device; + +import org.osgi.framework.ServiceReference; + +/** + * When the device manager detects a new Device service, it calls all registered + * Driver services to determine if anyone matches the Device service. If at + * least one Driver service matches, the device manager must choose one. If + * there is a Driver Selector service registered with the Framework, the device + * manager will ask it to make the selection. If there is no Driver Selector + * service, or if it returns an invalid result, or throws an {@code Exception}, + * the device manager uses the default selection strategy. + * + * @author $Id$ + * @since 1.1 + * @ThreadSafe + */ +public interface DriverSelector { + /** + * Return value from {@code DriverSelector.select}, if no Driver service + * should be attached to the Device service. The value is -1. + */ + public static final int SELECT_NONE = -1; + + /** + * Select one of the matching Driver services. The device manager calls this + * method if there is at least one driver bidding for a device. Only Driver + * services that have responded with nonzero (not {@link Device#MATCH_NONE}) + * {@code } match values will be included in the list. + * + * @param reference the {@code ServiceReference} object of the Device + * service. + * @param matches the array of all non-zero matches. + * @return index into the array of {@code Match} objects, or + * {@code SELECT_NONE} if no Driver service should be attached + */ + public int select(ServiceReference reference, Match[] matches); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/Match.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/Match.java new file mode 100644 index 000000000..d16251848 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/Match.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.device; + +import org.osgi.framework.ServiceReference; + +/** + * Instances of {@code Match} are used in the + * {@link DriverSelector#select(ServiceReference, Match[])} method to identify + * Driver services matching a Device service. + * + * @ThreadSafe + * @noimplement + * @author $Id$ + * @since 1.1 + * @see DriverSelector + */ +public interface Match { + /** + * Return the reference to a Driver service. + * + * @return {@code ServiceReference} object to a Driver service. + */ + public ServiceReference getDriver(); + + /** + * Return the match value of this object. + * + * @return the match value returned by this Driver service. + */ + public int getMatchValue(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/package-info.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/package-info.java new file mode 100644 index 000000000..92de050fb --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/package-info.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Device Access Package Version 1.1. + * + * <p> + * Bundles wishing to use this package must list the package in the + * Import-Package header of the bundle's manifest. This package has two types of + * users: the consumers that use the API in this package and the providers that + * implement the API in this package. + * + * <p> + * Example import for consumers using the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.device; version="[1.1,2.0)"} + * <p> + * Example import for providers implementing the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.device; version="[1.1,1.2)"} + * + * @version 1.1 + * @author $Id$ + */ + +package org.osgi.service.device; + diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/packageinfo b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/packageinfo new file mode 100644 index 000000000..3987f9c4e --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/device/packageinfo @@ -0,0 +1 @@ +version 1.1 diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/Event.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/Event.java new file mode 100644 index 000000000..6fc64b4e9 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/Event.java @@ -0,0 +1,294 @@ +/* + * Copyright (c) OSGi Alliance (2005, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.event; + +import static org.osgi.service.event.EventConstants.EVENT_TOPIC; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import org.osgi.framework.Filter; + +/** + * An event. + * + * {@code Event} objects are delivered to {@code EventHandler} services which + * subscribe to the topic of the event. + * + * @Immutable + * @author $Id$ + */ +public class Event { + /** + * The topic of this event. + */ + private final String topic; + /** + * The properties carried by this event. Keys are strings and values are + * objects + */ + private final EventProperties properties; + + /** + * Constructs an event. + * + * @param topic The topic of the event. + * @param properties The event's properties (may be {@code null}). A + * property whose key is not of type {@code String} will be ignored. + * @throws IllegalArgumentException If topic is not a valid topic name. + * @since 1.2 + */ + public Event(String topic, Map<String, ?> properties) { + validateTopicName(topic); + this.topic = topic; + // safely publish the event properties + this.properties = (properties instanceof EventProperties) ? (EventProperties) properties : new EventProperties(properties); + } + + /** + * Constructs an event. + * + * @param topic The topic of the event. + * @param properties The event's properties (may be {@code null}). A + * property whose key is not of type {@code String} will be ignored. + * @throws IllegalArgumentException If topic is not a valid topic name. + */ + public Event(String topic, Dictionary<String, ?> properties) { + validateTopicName(topic); + this.topic = topic; + // safely publish the event properties + this.properties = new EventProperties(properties); + } + + /** + * Retrieve the value of an event property. The event topic may be retrieved + * with the property name "event.topics". + * + * @param name The name of the property to retrieve. + * @return The value of the property, or {@code null} if not found. + */ + public final Object getProperty(String name) { + if (EVENT_TOPIC.equals(name)) { + return topic; + } + return properties.get(name); + } + + /** + * Indicate the presence of an event property. The event topic is present + * using the property name "event.topics". + * + * @param name The name of the property. + * @return {@code true} if a property with the specified name is in the + * event. This property may have a {@code null} value. {@code false} + * otherwise. + * @since 1.3 + */ + public final boolean containsProperty(String name) { + if (EVENT_TOPIC.equals(name)) { + return true; + } + return properties.containsKey(name); + } + + /** + * Returns a list of this event's property names. The list will include the + * event topic property name "event.topics". + * + * @return A non-empty array with one element per property. + */ + public final String[] getPropertyNames() { + int size = properties.size(); + String[] result = new String[size + 1]; + properties.keySet().toArray(result); + result[size] = EVENT_TOPIC; + return result; + } + + /** + * Returns the topic of this event. + * + * @return The topic of this event. + */ + public final String getTopic() { + return topic; + } + + /** + * Tests this event's properties against the given filter using a case + * sensitive match. + * + * @param filter The filter to test. + * @return true If this event's properties match the filter, false + * otherwise. + */ + public final boolean matches(Filter filter) { + return filter.matchCase(new FilterProperties(topic, properties)); + } + + /** + * Compares this {@code Event} object to another object. + * + * <p> + * An event is considered to be <b>equal to</b> another event if the topic + * is equal and the properties are equal. The properties are compared using + * the {@code java.util.Map.equals()} rules which includes identity + * comparison for array values. + * + * @param object The {@code Event} object to be compared. + * @return {@code true} if {@code object} is a {@code Event} and is equal to + * this object; {@code false} otherwise. + */ + @Override + public boolean equals(Object object) { + if (object == this) { // quick test + return true; + } + + if (!(object instanceof Event)) { + return false; + } + + Event event = (Event) object; + return topic.equals(event.topic) && properties.equals(event.properties); + } + + /** + * Returns a hash code value for this object. + * + * @return An integer which is a hash code value for this object. + */ + @Override + public int hashCode() { + int h = 31 * 17 + topic.hashCode(); + h = 31 * h + properties.hashCode(); + return h; + } + + /** + * Returns the string representation of this event. + * + * @return The string representation of this event. + */ + @Override + public String toString() { + return getClass().getName() + " [topic=" + topic + "]"; + } + + /** + * Called by the constructor to validate the topic name. + * + * @param topic The topic name to validate. + * @throws IllegalArgumentException If the topic name is invalid. + */ + private static void validateTopicName(String topic) { + char[] chars = topic.toCharArray(); + int length = chars.length; + if (length == 0) { + throw new IllegalArgumentException("empty topic"); + } + for (int i = 0; i < length; i++) { + char ch = chars[i]; + if (ch == '/') { + // Can't start or end with a '/' but anywhere else is okay + if (i == 0 || (i == length - 1)) { + throw new IllegalArgumentException("invalid topic: " + topic); + } + // Can't have "//" as that implies empty token + if (chars[i - 1] == '/') { + throw new IllegalArgumentException("invalid topic: " + topic); + } + continue; + } + if (('A' <= ch) && (ch <= 'Z')) { + continue; + } + if (('a' <= ch) && (ch <= 'z')) { + continue; + } + if (('0' <= ch) && (ch <= '9')) { + continue; + } + if ((ch == '_') || (ch == '-')) { + continue; + } + throw new IllegalArgumentException("invalid topic: " + topic); + } + } + + /** + * Dictionary to use for Filter matching. + */ + static private final class FilterProperties extends Dictionary<String, Object> { + private final String topic; + private final EventProperties properties; + + FilterProperties(String topic, EventProperties properties) { + this.topic = topic; + this.properties = properties; + } + + @Override + public Enumeration<Object> elements() { + Collection<Object> values = properties.values(); + List<Object> result = new ArrayList<Object>(values.size() + 1); + result.add(topic); + result.addAll(values); + return Collections.enumeration(result); + } + + @Override + public Object get(Object key) { + if (EVENT_TOPIC.equals(key)) { + return topic; + } + return properties.get(key); + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public Enumeration<String> keys() { + Collection<String> keys = properties.keySet(); + List<String> result = new ArrayList<String>(keys.size() + 1); + result.add(EVENT_TOPIC); + result.addAll(keys); + return Collections.enumeration(result); + } + + @Override + public Object put(String key, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public Object remove(Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public int size() { + return properties.size() + 1; + } + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/EventAdmin.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/EventAdmin.java new file mode 100644 index 000000000..529f0431b --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/EventAdmin.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) OSGi Alliance (2005, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.event; + +import org.osgi.annotation.versioning.ProviderType; + +/** + * The Event Admin service. Bundles wishing to publish events must obtain the + * Event Admin service and call one of the event delivery methods. + * + * @ThreadSafe + * @author $Id$ + */ +@ProviderType +public interface EventAdmin { + /** + * Initiate asynchronous, ordered delivery of an event. This method returns + * to the caller before delivery of the event is completed. Events are + * delivered in the order that they are received by this method. + * + * @param event The event to send to all listeners which subscribe to the + * topic of the event. + * + * @throws SecurityException If the caller does not have + * {@code TopicPermission[topic,PUBLISH]} for the topic specified in + * the event. + */ + void postEvent(Event event); + + /** + * Initiate synchronous delivery of an event. This method does not return to + * the caller until delivery of the event is completed. + * + * @param event The event to send to all listeners which subscribe to the + * topic of the event. + * + * @throws SecurityException If the caller does not have + * {@code TopicPermission[topic,PUBLISH]} for the topic specified in + * the event. + */ + void sendEvent(Event event); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/EventConstants.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/EventConstants.java new file mode 100644 index 000000000..d002775d3 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/EventConstants.java @@ -0,0 +1,243 @@ +/* + * Copyright (c) OSGi Alliance (2005, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.event; + +import org.osgi.annotation.versioning.ProviderType; +import org.osgi.framework.Bundle; +import org.osgi.framework.Constants; +import org.osgi.framework.Filter; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.Version; + +/** + * Defines standard names for {@code EventHandler} properties. + * + * @author $Id$ + */ +@ProviderType +public interface EventConstants { + + /** + * Service registration property specifying the {@code Event} topics of + * interest to an Event Handler service. + * <p> + * Event handlers SHOULD be registered with this property. Each value of + * this property is a string that describe the topics in which the handler + * is interested. An asterisk ('*') may be used as a trailing wildcard. + * Event Handlers which do not have a value for this property must not + * receive events. More precisely, the value of each string must conform to + * the following grammar: + * + * <pre> + * topic-description := '*' | topic ( '/*' )? + * topic := token ( '/' token )* + * </pre> + * + * <p> + * The value of this property must be of type {@code String}, + * {@code String[]}, or {@code Collection<String>}. + * + * @see Event + */ + public static final String EVENT_TOPIC = "event.topics"; + + /** + * Service Registration property specifying a filter to further select + * {@code Event} s of interest to an Event Handler service. + * <p> + * Event handlers MAY be registered with this property. The value of this + * property is a string containing an LDAP-style filter specification. Any + * of the event's properties may be used in the filter expression. Each + * event handler is notified for any event which belongs to the topics in + * which the handler has expressed an interest. If the event handler is also + * registered with this service property, then the properties of the event + * must also match the filter for the event to be delivered to the event + * handler. + * <p> + * If the filter syntax is invalid, then the Event Handler must be ignored + * and a warning should be logged. + * + * <p> + * The value of this property must be of type {@code String}. + * + * @see Event + * @see Filter + */ + public static final String EVENT_FILTER = "event.filter"; + + /** + * Service Registration property specifying the delivery qualities requested + * by an Event Handler service. + * <p> + * Event handlers MAY be registered with this property. Each value of this + * property is a string specifying a delivery quality for the Event handler. + * + * <p> + * The value of this property must be of type {@code String}, + * {@code String[]}, or {@code Collection<String>}. + * + * @see #DELIVERY_ASYNC_ORDERED + * @see #DELIVERY_ASYNC_UNORDERED + * @since 1.3 + */ + public static final String EVENT_DELIVERY = "event.delivery"; + + /** + * Event Handler delivery quality value specifying the Event Handler + * requires asynchronously delivered events be delivered in order. Ordered + * delivery is the default for asynchronously delivered events. + * + * <p> + * This delivery quality value is mutually exclusive with + * {@link #DELIVERY_ASYNC_UNORDERED}. However, if both this value and + * {@link #DELIVERY_ASYNC_UNORDERED} are specified for an event handler, + * this value takes precedence. + * + * @see #EVENT_DELIVERY + * @since 1.3 + */ + public static final String DELIVERY_ASYNC_ORDERED = "async.ordered"; + + /** + * Event Handler delivery quality value specifying the Event Handler does + * not require asynchronously delivered events be delivered in order. This + * may allow an Event Admin implementation to optimize asynchronous event + * delivery by relaxing ordering requirements. + * + * <p> + * This delivery quality value is mutually exclusive with + * {@link #DELIVERY_ASYNC_ORDERED}. However, if both this value and + * {@link #DELIVERY_ASYNC_ORDERED} are specified for an event handler, + * {@link #DELIVERY_ASYNC_ORDERED} takes precedence. + * + * @see #EVENT_DELIVERY + * @since 1.3 + */ + public static final String DELIVERY_ASYNC_UNORDERED = "async.unordered"; + + /** + * The Distinguished Names of the signers of the bundle relevant to the + * event. The type of the value for this event property is {@code String} or + * {@code Collection} of {@code String}. + */ + public static final String BUNDLE_SIGNER = "bundle.signer"; + + /** + * The Bundle Symbolic Name of the bundle relevant to the event. The type of + * the value for this event property is {@code String}. + */ + public static final String BUNDLE_SYMBOLICNAME = "bundle.symbolicName"; + + /** + * The Bundle id of the bundle relevant to the event. The type of the value + * for this event property is {@code Long}. + * + * @since 1.1 + */ + public static final String BUNDLE_ID = "bundle.id"; + + /** + * The Bundle object of the bundle relevant to the event. The type of the + * value for this event property is {@link Bundle}. + * + * @since 1.1 + */ + public static final String BUNDLE = "bundle"; + + /** + * The version of the bundle relevant to the event. The type of the value + * for this event property is {@link Version}. + * + * @since 1.2 + */ + public static final String BUNDLE_VERSION = "bundle.version"; + + /** + * The forwarded event object. Used when rebroadcasting an event that was + * sent via some other event mechanism. The type of the value for this event + * property is {@code Object}. + */ + public static final String EVENT = "event"; + + /** + * An exception or error. The type of the value for this event property is + * {@code Throwable}. + */ + public static final String EXCEPTION = "exception"; + + /** + * The name of the exception type. Must be equal to the name of the class of + * the exception in the event property {@link #EXCEPTION}. The type of the + * value for this event property is {@code String}. + * + * @since 1.1 + */ + public static final String EXCEPTION_CLASS = "exception.class"; + + /** + * The exception message. Must be equal to the result of calling + * {@code getMessage()} on the exception in the event property + * {@link #EXCEPTION}. The type of the value for this event property is + * {@code String}. + */ + public static final String EXCEPTION_MESSAGE = "exception.message"; + + /** + * A human-readable message that is usually not localized. The type of the + * value for this event property is {@code String}. + */ + public static final String MESSAGE = "message"; + + /** + * A service reference. The type of the value for this event property is + * {@link ServiceReference}. + */ + public static final String SERVICE = "service"; + + /** + * A service's id. The type of the value for this event property is + * {@code Long}. + */ + public static final String SERVICE_ID = Constants.SERVICE_ID; + + /** + * A service's objectClass. The type of the value for this event property is + * {@code String[]}. + */ + public static final String SERVICE_OBJECTCLASS = "service.objectClass"; + + /** + * A service's persistent identity. The type of the value for this event + * property is {@code String} or {@code Collection} of {@code String}. + */ + public static final String SERVICE_PID = Constants.SERVICE_PID; + + /** + * The time when the event occurred, as reported by + * {@code System.currentTimeMillis()}. The type of the value for this event + * property is {@code Long}. + */ + public static final String TIMESTAMP = "timestamp"; + + /** + * This constant was released with an incorrectly spelled name. It has been + * replaced by {@link #EXCEPTION_CLASS} + * + * @deprecated As of 1.1, replaced by EXCEPTION_CLASS + */ + public static final String EXECPTION_CLASS = "exception.class"; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/EventHandler.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/EventHandler.java new file mode 100644 index 000000000..996c63cec --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/EventHandler.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) OSGi Alliance (2005, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.event; + +import org.osgi.annotation.versioning.ConsumerType; + +/** + * Listener for Events. + * + * <p> + * {@code EventHandler} objects are registered with the Framework service + * registry and are notified with an {@code Event} object when an event is sent + * or posted. + * <p> + * {@code EventHandler} objects can inspect the received {@code Event} object to + * determine its topic and properties. + * + * <p> + * {@code EventHandler} objects must be registered with a service property + * {@link EventConstants#EVENT_TOPIC} whose value is the list of topics in which + * the event handler is interested. + * <p> + * For example: + * + * <pre> + * String[] topics = new String[] {"com/isv/*"}; + * Hashtable ht = new Hashtable(); + * ht.put(EventConstants.EVENT_TOPIC, topics); + * context.registerService(EventHandler.class.getName(), this, ht); + * </pre> + * + * Event Handler services can also be registered with an + * {@link EventConstants#EVENT_FILTER} service property to further filter the + * events. If the syntax of this filter is invalid, then the Event Handler must + * be ignored by the Event Admin service. The Event Admin service should log a + * warning. + * <p> + * Security Considerations. Bundles wishing to monitor {@code Event} objects + * will require {@code ServicePermission[EventHandler,REGISTER]} to register an + * {@code EventHandler} service. The bundle must also have + * {@code TopicPermission[topic,SUBSCRIBE]} for the topic specified in the event + * in order to receive the event. + * + * @see Event + * + * @ThreadSafe + * @author $Id$ + */ +@ConsumerType +public interface EventHandler { + /** + * Called by the {@link EventAdmin} service to notify the listener of an + * event. + * + * @param event The event that occurred. + */ + void handleEvent(Event event); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/EventProperties.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/EventProperties.java new file mode 100644 index 000000000..548895a00 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/EventProperties.java @@ -0,0 +1,261 @@ +/* + * Copyright (c) OSGi Alliance (2010, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.event; + +import static org.osgi.service.event.EventConstants.EVENT_TOPIC; +import java.util.Collection; +import java.util.Collections; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * The properties for an {@link Event}. An event source can create an + * EventProperties object if it needs to reuse the same event properties for + * multiple events. + * + * <p> + * The keys are all of type {@code String}. The values are of type + * {@code Object}. The key "event.topics" is ignored as event topics + * can only be set when an {@link Event} is constructed. + * + * <p> + * Once constructed, an EventProperties object is unmodifiable. However, the + * values of the map used to construct an EventProperties object are still + * subject to modification as they are not deeply copied. + * + * @Immutable + * @since 1.3 + * @author $Id$ + */ +public class EventProperties implements Map<String, Object> { + /** + * The properties for an event. Keys are strings and values are objects. The + * object is unmodifiable. + */ + private final Map<String, Object> properties; + + /** + * Create an EventProperties from the specified properties. + * + * <p> + * The specified properties will be copied into this EventProperties. + * Properties whose key is not of type {@code String} will be ignored. A + * property with the key "event.topics" will be ignored. + * + * @param properties The properties to use for this EventProperties object + * (may be {@code null}). + */ + public EventProperties(Map<String, ?> properties) { + int size = (properties == null) ? 0 : properties.size(); + Map<String, Object> p = new HashMap<String, Object>(size); + if (size > 0) { + for (Object key : (Set<?>) properties.keySet()) { + if ((key instanceof String) && !EVENT_TOPIC.equals(key)) { + Object value = properties.get(key); + p.put((String) key, value); + } + } + } + // safely publish the map + this.properties = Collections.unmodifiableMap(p); + } + + /** + * Create an EventProperties from the specified dictionary. + * + * <p> + * The specified properties will be copied into this EventProperties. + * Properties whose key is not of type {@code String} will be ignored. A + * property with the key "event.topics" will be ignored. + * + * @param properties The properties to use for this EventProperties object + * (may be {@code null}). + */ + EventProperties(Dictionary<String, ?> properties) { + int size = (properties == null) ? 0 : properties.size(); + Map<String, Object> p = new HashMap<String, Object>(size); + if (size > 0) { + for (Enumeration<?> e = properties.keys(); e.hasMoreElements();) { + Object key = e.nextElement(); + if ((key instanceof String) && !EVENT_TOPIC.equals(key)) { + Object value = properties.get(key); + p.put((String) key, value); + } + } + } + // safely publish the map + this.properties = Collections.unmodifiableMap(p); + } + + /** + * This method throws {@link UnsupportedOperationException}. + * + * @throws UnsupportedOperationException if called. + */ + public void clear() { + properties.clear(); + } + + /** + * Indicates if the specified property is present. + * + * @param name The property name. + * @return {@code true} If the property is present, {@code false} otherwise. + */ + public boolean containsKey(Object name) { + return properties.containsKey(name); + } + + /** + * Indicates if the specified value is present. + * + * @param value The property value. + * @return {@code true} If the value is present, {@code false} otherwise. + */ + public boolean containsValue(Object value) { + return properties.containsValue(value); + } + + /** + * Return the property entries. + * + * @return A set containing the property name/value pairs. + */ + public Set<java.util.Map.Entry<String, Object>> entrySet() { + return properties.entrySet(); + } + + /** + * Return the value of the specified property. + * + * @param name The name of the specified property. + * @return The value of the specified property. + */ + public Object get(Object name) { + return properties.get(name); + } + + /** + * Indicate if this properties is empty. + * + * @return {@code true} If this properties is empty, {@code false} + * otherwise. + */ + public boolean isEmpty() { + return properties.isEmpty(); + } + + /** + * Return the names of the properties. + * + * @return The names of the properties. + */ + public Set<String> keySet() { + return properties.keySet(); + } + + /** + * This method throws {@link UnsupportedOperationException}. + * + * @throws UnsupportedOperationException if called. + */ + public Object put(String key, Object value) { + return properties.put(key, value); + } + + /** + * This method throws {@link UnsupportedOperationException}. + * + * @throws UnsupportedOperationException if called. + */ + public void putAll(Map<? extends String, ? extends Object> map) { + properties.putAll(map); + } + + /** + * This method throws {@link UnsupportedOperationException}. + * + * @throws UnsupportedOperationException if called. + */ + public Object remove(Object key) { + return properties.remove(key); + } + + /** + * Return the number of properties. + * + * @return The number of properties. + */ + public int size() { + return properties.size(); + } + + /** + * Return the properties values. + * + * @return The values of the properties. + */ + public Collection<Object> values() { + return properties.values(); + } + + /** + * Compares this {@code EventProperties} object to another object. + * + * <p> + * The properties are compared using the {@code java.util.Map.equals()} + * rules which includes identity comparison for array values. + * + * @param object The {@code EventProperties} object to be compared. + * @return {@code true} if {@code object} is a {@code EventProperties} and + * is equal to this object; {@code false} otherwise. + */ + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (!(object instanceof EventProperties)) { + return false; + } + EventProperties other = (EventProperties) object; + return properties.equals(other.properties); + } + + /** + * Returns a hash code value for this object. + * + * @return An integer which is a hash code value for this object. + */ + @Override + public int hashCode() { + return properties.hashCode(); + } + + /** + * Returns the string representation of this object. + * + * @return The string representation of this object. + */ + @Override + public String toString() { + return properties.toString(); + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/TopicPermission.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/TopicPermission.java new file mode 100644 index 000000000..ad379bde2 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/TopicPermission.java @@ -0,0 +1,548 @@ +/* + * Copyright (c) OSGi Alliance (2005, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.event; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; +import java.security.Permission; +import java.security.PermissionCollection; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; + +/** + * A bundle's authority to publish or subscribe to event on a topic. + * + * <p> + * A topic is a slash-separated string that defines a topic. + * <p> + * For example: + * + * <pre> + * org/osgi/service/foo/FooEvent/ACTION + * </pre> + * + * <p> + * {@code TopicPermission} has two actions: {@code publish} and + * {@code subscribe}. + * + * @ThreadSafe + * @author $Id$ + */ +public final class TopicPermission extends Permission { + static final long serialVersionUID = -5855563886961618300L; + /** + * The action string {@code publish}. + */ + public final static String PUBLISH = "publish"; + /** + * The action string {@code subscribe}. + */ + public final static String SUBSCRIBE = "subscribe"; + private final static int ACTION_PUBLISH = 0x00000001; + private final static int ACTION_SUBSCRIBE = 0x00000002; + private final static int ACTION_ALL = ACTION_PUBLISH | ACTION_SUBSCRIBE; + private final static int ACTION_NONE = 0; + /** + * The actions mask. + */ + private transient int action_mask; + + /** + * prefix if the name is wildcarded. + */ + private transient volatile String prefix; + + /** + * The actions in canonical form. + * + * @serial + */ + private volatile String actions = null; + + /** + * Defines the authority to publich and/or subscribe to a topic within the + * EventAdmin service. + * <p> + * The name is specified as a slash-separated string. Wildcards may be used. + * For example: + * + * <pre> + * org/osgi/service/fooFooEvent/ACTION + * com/isv/* + * * + * </pre> + * + * <p> + * A bundle that needs to publish events on a topic must have the + * appropriate {@code TopicPermission} for that topic; similarly, a bundle + * that needs to subscribe to events on a topic must have the appropriate + * {@code TopicPermssion} for that topic. + * <p> + * + * @param name Topic name. + * @param actions {@code publish},{@code subscribe} (canonical order). + */ + public TopicPermission(String name, String actions) { + this(name, parseActions(actions)); + } + + /** + * Package private constructor used by TopicPermissionCollection. + * + * @param name class name + * @param mask action mask + */ + TopicPermission(String name, int mask) { + super(name); + setTransients(mask); + } + + /** + * Called by constructors and when deserialized. + * + * @param name topic name + * @param mask action mask + */ + private synchronized void setTransients(final int mask) { + final String name = getName(); + if ((name == null) || name.length() == 0) { + throw new IllegalArgumentException("invalid name"); + } + + if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) { + throw new IllegalArgumentException("invalid action string"); + } + action_mask = mask; + + if (name.equals("*")) { + prefix = ""; + } else { + if (name.endsWith("/*")) { + prefix = name.substring(0, name.length() - 1); + } else { + prefix = null; + } + } + } + + /** + * Returns the current action mask. + * <p> + * Used by the TopicPermissionCollection class. + * + * @return Current action mask. + */ + synchronized int getActionsMask() { + return action_mask; + } + + /** + * Parse action string into action mask. + * + * @param actions Action string. + * @return action mask. + */ + private static int parseActions(final String actions) { + boolean seencomma = false; + int mask = ACTION_NONE; + if (actions == null) { + return mask; + } + char[] a = actions.toCharArray(); + int i = a.length - 1; + if (i < 0) + return mask; + while (i != -1) { + char c; + // skip whitespace + while ((i != -1) && ((c = a[i]) == ' ' || c == '\r' || c == '\n' || c == '\f' || c == '\t')) + i--; + // check for the known strings + int matchlen; + if (i >= 8 && (a[i - 8] == 's' || a[i - 8] == 'S') + && (a[i - 7] == 'u' || a[i - 7] == 'U') + && (a[i - 6] == 'b' || a[i - 6] == 'B') + && (a[i - 5] == 's' || a[i - 5] == 'S') + && (a[i - 4] == 'c' || a[i - 4] == 'C') + && (a[i - 3] == 'r' || a[i - 3] == 'R') + && (a[i - 2] == 'i' || a[i - 2] == 'I') + && (a[i - 1] == 'b' || a[i - 1] == 'B') + && (a[i] == 'e' || a[i] == 'E')) { + matchlen = 9; + mask |= ACTION_SUBSCRIBE; + } + else + if (i >= 6 && (a[i - 6] == 'p' || a[i - 6] == 'P') + && (a[i - 5] == 'u' || a[i - 5] == 'U') + && (a[i - 4] == 'b' || a[i - 4] == 'B') + && (a[i - 3] == 'l' || a[i - 3] == 'L') + && (a[i - 2] == 'i' || a[i - 2] == 'I') + && (a[i - 1] == 's' || a[i - 1] == 'S') + && (a[i] == 'h' || a[i] == 'H')) { + matchlen = 7; + mask |= ACTION_PUBLISH; + } + else { + // parse error + throw new IllegalArgumentException("invalid permission: " + + actions); + } + // make sure we didn't just match the tail of a word + // like "ackbarfpublish". Also, skip to the comma. + seencomma = false; + while (i >= matchlen && !seencomma) { + switch (a[i - matchlen]) { + case ',' : + seencomma = true; + /* FALLTHROUGH */ + case ' ' : + case '\r' : + case '\n' : + case '\f' : + case '\t' : + break; + default : + throw new IllegalArgumentException("invalid permission: " + actions); + } + i--; + } + // point i at the location of the comma minus one (or -1). + i -= matchlen; + } + if (seencomma) { + throw new IllegalArgumentException("invalid permission: " + actions); + } + return mask; + } + + /** + * Determines if the specified permission is implied by this object. + * + * <p> + * This method checks that the topic name of the target is implied by the + * topic name of this object. The list of {@code TopicPermission} actions + * must either match or allow for the list of the target object to imply the + * target {@code TopicPermission} action. + * + * <pre> + * x/y/*,"publish" -> x/y/z,"publish" is true + * *,"subscribe" -> x/y,"subscribe" is true + * *,"publish" -> x/y,"subscribe" is false + * x/y,"publish" -> x/y/z,"publish" is false + * </pre> + * + * @param p The target permission to interrogate. + * @return {@code true} if the specified {@code TopicPermission} action is + * implied by this object; {@code false} otherwise. + */ + @Override + public boolean implies(Permission p) { + if (p instanceof TopicPermission) { + TopicPermission requested = (TopicPermission) p; + int requestedMask = requested.getActionsMask(); + if ((getActionsMask() & requestedMask) == requestedMask) { + String requestedName = requested.getName(); + String pre = prefix; + if (pre != null) { + return requestedName.startsWith(pre); + } + + return requestedName.equals(getName()); + } + } + return false; + } + + /** + * Returns the canonical string representation of the + * {@code TopicPermission} actions. + * + * <p> + * Always returns present {@code TopicPermission} actions in the following + * order: {@code publish},{@code subscribe}. + * + * @return Canonical string representation of the {@code TopicPermission} + * actions. + */ + @Override + public String getActions() { + String result = actions; + if (result == null) { + StringBuffer sb = new StringBuffer(); + boolean comma = false; + int mask = getActionsMask(); + if ((mask & ACTION_PUBLISH) == ACTION_PUBLISH) { + sb.append(PUBLISH); + comma = true; + } + if ((mask & ACTION_SUBSCRIBE) == ACTION_SUBSCRIBE) { + if (comma) + sb.append(','); + sb.append(SUBSCRIBE); + } + actions = result = sb.toString(); + } + return result; + } + + /** + * Returns a new {@code PermissionCollection} object suitable for storing + * {@code TopicPermission} objects. + * + * @return A new {@code PermissionCollection} object. + */ + @Override + public PermissionCollection newPermissionCollection() { + return new TopicPermissionCollection(); + } + + /** + * Determines the equality of two {@code TopicPermission} objects. + * + * This method checks that specified {@code TopicPermission} has the same + * topic name and actions as this {@code TopicPermission} object. + * + * @param obj The object to test for equality with this + * {@code TopicPermission} object. + * @return {@code true} if {@code obj} is a {@code TopicPermission}, and has + * the same topic name and actions as this {@code TopicPermission} + * object; {@code false} otherwise. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof TopicPermission)) { + return false; + } + TopicPermission tp = (TopicPermission) obj; + return (getActionsMask() == tp.getActionsMask()) && getName().equals(tp.getName()); + } + + /** + * Returns the hash code value for this object. + * + * @return A hash code value for this object. + */ + @Override + public int hashCode() { + int h = 31 * 17 + getName().hashCode(); + h = 31 * h + getActions().hashCode(); + return h; + } + + /** + * WriteObject is called to save the state of this permission object to a + * stream. The actions are serialized, and the superclass takes care of the + * name. + */ + private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { + // Write out the actions. The superclass takes care of the name + // call getActions to make sure actions field is initialized + if (actions == null) + getActions(); + s.defaultWriteObject(); + } + + /** + * readObject is called to restore the state of this permission from a + * stream. + */ + private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { + // Read in the action, then initialize the rest + s.defaultReadObject(); + setTransients(parseActions(actions)); + } +} + +/** + * Stores a set of {@code TopicPermission} permissions. + * + * @see java.security.Permission + * @see java.security.Permissions + * @see java.security.PermissionCollection + */ +final class TopicPermissionCollection extends PermissionCollection { + static final long serialVersionUID = -614647783533924048L; + /** + * Table of permissions. + * + * @GuardedBy this + */ + private transient Map<String, TopicPermission> permissions; + /** + * Boolean saying if "*" is in the collection. + * + * @serial + * @GuardedBy this + */ + private boolean all_allowed; + + /** + * Create an empty TopicPermissions object. + * + */ + public TopicPermissionCollection() { + permissions = new HashMap<String, TopicPermission>(); + all_allowed = false; + } + + /** + * Adds a permission to the {@code TopicPermission} objects. The key for the + * hash is the name. + * + * @param permission The {@code TopicPermission} object to add. + * + * @throws IllegalArgumentException If the permission is not a + * {@code TopicPermission} instance. + * + * @throws SecurityException If this {@code TopicPermissionCollection} + * object has been marked read-only. + */ + @Override + public void add(final Permission permission) { + if (!(permission instanceof TopicPermission)) { + throw new IllegalArgumentException("invalid permission: " + permission); + } + if (isReadOnly()) { + throw new SecurityException("attempt to add a Permission to a " + "readonly PermissionCollection"); + } + final TopicPermission tp = (TopicPermission) permission; + final String name = tp.getName(); + final int newMask = tp.getActionsMask(); + + synchronized (this) { + final TopicPermission existing = permissions.get(name); + if (existing != null) { + final int oldMask = existing.getActionsMask(); + if (oldMask != newMask) { + permissions.put(name, new TopicPermission(name, oldMask | newMask)); + } + } else { + permissions.put(name, tp); + } + if (!all_allowed) { + if (name.equals("*")) + all_allowed = true; + } + } + } + + /** + * Determines if the specified permissions implies the permissions expressed + * in {@code permission}. + * + * @param permission The Permission object to compare with this + * {@code TopicPermission} object. + * + * @return {@code true} if {@code permission} is a proper subset of a + * permission in the set; {@code false} otherwise. + */ + @Override + public boolean implies(final Permission permission) { + if (!(permission instanceof TopicPermission)) { + return false; + } + final TopicPermission requested = (TopicPermission) permission; + String name = requested.getName(); + final int desired = requested.getActionsMask(); + int effective = 0; + + TopicPermission x; + // short circuit if the "*" Permission was added + synchronized (this) { + if (all_allowed) { + x = permissions.get("*"); + if (x != null) { + effective |= x.getActionsMask(); + if ((effective & desired) == desired) { + return true; + } + } + } + x = permissions.get(name); + } + // strategy: + // Check for full match first. Then work our way up the + // name looking for matches on a/b/* + if (x != null) { + // we have a direct hit! + effective |= x.getActionsMask(); + if ((effective & desired) == desired) { + return true; + } + } + // work our way up the tree... + int last; + int offset = name.length() - 1; + while ((last = name.lastIndexOf("/", offset)) != -1) { + name = name.substring(0, last + 1) + "*"; + synchronized (this) { + x = permissions.get(name); + } + if (x != null) { + effective |= x.getActionsMask(); + if ((effective & desired) == desired) { + return true; + } + } + offset = last - 1; + } + // we don't have to check for "*" as it was already checked + // at the top (all_allowed), so we just return false + return false; + } + + /** + * Returns an enumeration of all {@code TopicPermission} objects in the + * container. + * + * @return Enumeration of all {@code TopicPermission} objects. + */ + @Override + public synchronized Enumeration<Permission> elements() { + List<Permission> all = new ArrayList<Permission>(permissions.values()); + return Collections.enumeration(all); + } + + /* serialization logic */ + private static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("permissions", Hashtable.class), new ObjectStreamField("all_allowed", Boolean.TYPE)}; + + private synchronized void writeObject(ObjectOutputStream out) throws IOException { + Hashtable<String, TopicPermission> hashtable = new Hashtable<String, TopicPermission>(permissions); + ObjectOutputStream.PutField pfields = out.putFields(); + pfields.put("permissions", hashtable); + pfields.put("all_allowed", all_allowed); + out.writeFields(); + } + + private synchronized void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + ObjectInputStream.GetField gfields = in.readFields(); + @SuppressWarnings("unchecked") + Hashtable<String, TopicPermission> hashtable = (Hashtable<String, TopicPermission>) gfields.get("permissions", null); + permissions = new HashMap<String, TopicPermission>(hashtable); + all_allowed = gfields.get("all_allowed", false); + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/package-info.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/package-info.java new file mode 100644 index 000000000..7fe07b461 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/package-info.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) OSGi Alliance (2010, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Event Admin Package Version 1.3. + * + * <p> + * Bundles wishing to use this package must list the package in the + * Import-Package header of the bundle's manifest. This package has two types of + * users: the consumers that use the API in this package and the providers that + * implement the API in this package. + * + * <p> + * Example import for consumers using the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.event; version="[1.3,2.0)"} + * <p> + * Example import for providers implementing the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.event; version="[1.3,1.4)"} + * + * @author $Id$ + */ + +@Version("1.3") +package org.osgi.service.event; + +import org.osgi.annotation.versioning.Version; + diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/packageinfo b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/packageinfo new file mode 100644 index 000000000..0117a56c1 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/event/packageinfo @@ -0,0 +1 @@ +version 1.3 diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/http/HttpContext.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/http/HttpContext.java new file mode 100644 index 000000000..d8c0c4b76 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/http/HttpContext.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) OSGi Alliance (2000, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.http; + +import java.io.IOException; +import java.net.URL; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * This interface defines methods that the Http Service may call to get + * information about a registration. + * + * <p> + * Servlets and resources may be registered with an {@code HttpContext} object; + * if no {@code HttpContext} object is specified, a default {@code HttpContext} + * object is used. Servlets that are registered using the same + * {@code HttpContext} object will share the same {@code ServletContext} object. + * + * <p> + * This interface is implemented by users of the {@code HttpService}. + * + * @author $Id$ + */ +public interface HttpContext { + /** + * {@code HttpServletRequest} attribute specifying the name of the + * authenticated user. The value of the attribute can be retrieved by + * {@code HttpServletRequest.getRemoteUser}. This attribute name is + * {@code org.osgi.service.http.authentication.remote.user}. + * + * @since 1.1 + */ + public static final String REMOTE_USER = "org.osgi.service.http.authentication.remote.user"; + /** + * {@code HttpServletRequest} attribute specifying the scheme used in + * authentication. The value of the attribute can be retrieved by + * {@code HttpServletRequest.getAuthType}. This attribute name is + * {@code org.osgi.service.http.authentication.type}. + * + * @since 1.1 + */ + public static final String AUTHENTICATION_TYPE = "org.osgi.service.http.authentication.type"; + /** + * {@code HttpServletRequest} attribute specifying the {@code Authorization} + * object obtained from the {@code org.osgi.service.useradmin.UserAdmin} + * service. The value of the attribute can be retrieved by + * {@code HttpServletRequest.getAttribute(HttpContext.AUTHORIZATION)}. This + * attribute name is {@code org.osgi.service.useradmin.authorization}. + * + * @since 1.1 + */ + public static final String AUTHORIZATION = "org.osgi.service.useradmin.authorization"; + + /** + * Handles security for the specified request. + * + * <p> + * The Http Service calls this method prior to servicing the specified + * request. This method controls whether the request is processed in the + * normal manner or an error is returned. + * + * <p> + * If the request requires authentication and the Authorization header in + * the request is missing or not acceptable, then this method should set the + * WWW-Authenticate header in the response object, set the status in the + * response object to Unauthorized(401) and return {@code false}. See also + * RFC 2617: <i>HTTP Authentication: Basic and Digest Access Authentication + * </i> (available at http://www.ietf.org/rfc/rfc2617.txt). + * + * <p> + * If the request requires a secure connection and the {@code getScheme} + * method in the request does not return 'https' or some other acceptable + * secure protocol, then this method should set the status in the response + * object to Forbidden(403) and return {@code false}. + * + * <p> + * When this method returns {@code false}, the Http Service will send the + * response back to the client, thereby completing the request. When this + * method returns {@code true}, the Http Service will proceed with servicing + * the request. + * + * <p> + * If the specified request has been authenticated, this method must set the + * {@link #AUTHENTICATION_TYPE} request attribute to the type of + * authentication used, and the {@link #REMOTE_USER} request attribute to + * the remote user (request attributes are set using the + * {@code setAttribute} method on the request). If this method does not + * perform any authentication, it must not set these attributes. + * + * <p> + * If the authenticated user is also authorized to access certain resources, + * this method must set the {@link #AUTHORIZATION} request attribute to the + * {@code Authorization} object obtained from the + * {@code org.osgi.service.useradmin.UserAdmin} service. + * + * <p> + * The servlet responsible for servicing the specified request determines + * the authentication type and remote user by calling the + * {@code getAuthType} and {@code getRemoteUser} methods, respectively, on + * the request. + * + * @param request the HTTP request + * @param response the HTTP response + * @return {@code true} if the request should be serviced, {@code false} if + * the request should not be serviced and Http Service will send the + * response back to the client. + * @throws java.io.IOException may be thrown by this method. If this occurs, + * the Http Service will terminate the request and close the socket. + */ + public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException; + + /** + * Maps a resource name to a URL. + * + * <p> + * Called by the Http Service to map a resource name to a URL. For servlet + * registrations, Http Service will call this method to support the + * {@code ServletContext} methods {@code getResource} and + * {@code getResourceAsStream}. For resource registrations, Http Service + * will call this method to locate the named resource. The context can + * control from where resources come. For example, the resource can be + * mapped to a file in the bundle's persistent storage area via + * {@code bundleContext.getDataFile(name).toURL()} or to a resource in the + * context's bundle via {@code getClass().getResource(name)} + * + * @param name the name of the requested resource + * @return URL that Http Service can use to read the resource or + * {@code null} if the resource does not exist. + */ + public URL getResource(String name); + + /** + * Maps a name to a MIME type. + * + * Called by the Http Service to determine the MIME type for the name. For + * servlet registrations, the Http Service will call this method to support + * the {@code ServletContext} method {@code getMimeType}. For resource + * registrations, the Http Service will call this method to determine the + * MIME type for the Content-Type header in the response. + * + * @param name determine the MIME type for this name. + * @return MIME type (e.g. text/html) of the name or {@code null} to + * indicate that the Http Service should determine the MIME type + * itself. + */ + public String getMimeType(String name); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/http/HttpService.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/http/HttpService.java new file mode 100644 index 000000000..c7dcd5824 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/http/HttpService.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) OSGi Alliance (2000, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.http; + +import java.util.Dictionary; +import javax.servlet.Servlet; +import javax.servlet.ServletException; + +/** + * The Http Service allows other bundles in the OSGi environment to dynamically + * register resources and servlets into the URI namespace of Http Service. A + * bundle may later unregister its resources or servlets. + * + * @noimplement + * @author $Id$ + * @see HttpContext + */ +public interface HttpService { + /** + * Registers a servlet into the URI namespace. + * + * <p> + * The alias is the name in the URI namespace of the Http Service at which + * the registration will be mapped. + * + * <p> + * An alias must begin with slash ('/') and must not end with slash ('/'), + * with the exception that an alias of the form "/" is used to + * denote the root alias. See the specification text for details on how HTTP + * requests are mapped to servlet and resource registrations. + * + * <p> + * The Http Service will call the servlet's {@code init} method before + * returning. + * + * <pre> + * httpService.registerServlet("/myservlet", servlet, initparams, context); + * </pre> + * + * <p> + * Servlets registered with the same {@code HttpContext} object will share + * the same {@code ServletContext}. The Http Service will call the + * {@code context} argument to support the {@code ServletContext} methods + * {@code getResource},{@code getResourceAsStream} and {@code getMimeType}, + * and to handle security for requests. If the {@code context} argument is + * {@code null}, a default {@code HttpContext} object is used (see + * {@link #createDefaultHttpContext()}). + * + * @param alias name in the URI namespace at which the servlet is registered + * @param servlet the servlet object to register + * @param initparams initialization arguments for the servlet or + * {@code null} if there are none. This argument is used by the + * servlet's {@code ServletConfig} object. + * @param context the {@code HttpContext} object for the registered servlet, + * or {@code null} if a default {@code HttpContext} is to be created + * and used. + * @throws NamespaceException if the registration fails because the alias is + * already in use. + * @throws javax.servlet.ServletException if the servlet's {@code init} + * method throws an exception, or the given servlet object has + * already been registered at a different alias. + * @throws java.lang.IllegalArgumentException if any of the arguments are + * invalid + */ + public void registerServlet(String alias, Servlet servlet, Dictionary initparams, HttpContext context) throws ServletException, NamespaceException; + + /** + * Registers resources into the URI namespace. + * + * <p> + * The alias is the name in the URI namespace of the Http Service at which + * the registration will be mapped. An alias must begin with slash ('/') and + * must not end with slash ('/'), with the exception that an alias of the + * form "/" is used to denote the root alias. The name parameter + * must also not end with slash ('/') with the exception that a name of the + * form "/" is used to denote the root of the bundle. See the + * specification text for details on how HTTP requests are mapped to servlet + * and resource registrations. + * <p> + * For example, suppose the resource name /tmp is registered to the alias + * /files. A request for /files/foo.txt will map to the resource name + * /tmp/foo.txt. + * + * <pre> + * httpservice.registerResources("/files", "/tmp", context); + * </pre> + * + * The Http Service will call the {@code HttpContext} argument to map + * resource names to URLs and MIME types and to handle security for + * requests. If the {@code HttpContext} argument is {@code null}, a default + * {@code HttpContext} is used (see {@link #createDefaultHttpContext()}). + * + * @param alias name in the URI namespace at which the resources are + * registered + * @param name the base name of the resources that will be registered + * @param context the {@code HttpContext} object for the registered + * resources, or {@code null} if a default {@code HttpContext} is to + * be created and used. + * @throws NamespaceException if the registration fails because the alias is + * already in use. + * @throws java.lang.IllegalArgumentException if any of the parameters are + * invalid + */ + public void registerResources(String alias, String name, HttpContext context) throws NamespaceException; + + /** + * Unregisters a previous registration done by {@code registerServlet} or + * {@code registerResources} methods. + * + * <p> + * After this call, the registered alias in the URI name-space will no + * longer be available. If the registration was for a servlet, the Http + * Service must call the {@code destroy} method of the servlet before + * returning. + * <p> + * If the bundle which performed the registration is stopped or otherwise + * "unget"s the Http Service without calling {@link #unregister(String)} + * then Http Service must automatically unregister the registration. + * However, if the registration was for a servlet, the {@code destroy} + * method of the servlet will not be called in this case since the bundle + * may be stopped. {@link #unregister(String)} must be explicitly called to + * cause the {@code destroy} method of the servlet to be called. This can be + * done in the {@code BundleActivator.stop} method of the bundle registering + * the servlet. + * + * @param alias name in the URI name-space of the registration to unregister + * @throws java.lang.IllegalArgumentException if there is no registration + * for the alias or the calling bundle was not the bundle which + * registered the alias. + */ + public void unregister(String alias); + + /** + * Creates a default {@code HttpContext} for registering servlets or + * resources with the HttpService, a new {@code HttpContext} object is + * created each time this method is called. + * + * <p> + * The behavior of the methods on the default {@code HttpContext} is defined + * as follows: + * <ul> + * <li>{@code getMimeType} - Does not define any customized MIME types for + * the Content-Type header in the response, and always returns {@code null}. + * </li> + * <li>{@code handleSecurity} - Performs implementation-defined + * authentication on the request.</li> + * <li>{@code getResource} - Assumes the named resource is in the context + * bundle; this method calls the context bundle's {@code Bundle.getResource} + * method, and returns the appropriate URL to access the resource. On a Java + * runtime environment that supports permissions, the Http Service needs to + * be granted {@code org.osgi.framework.AdminPermission[*,RESOURCE]}.</li> + * </ul> + * + * @return a default {@code HttpContext} object. + * @since 1.1 + */ + public HttpContext createDefaultHttpContext(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/http/NamespaceException.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/http/NamespaceException.java new file mode 100644 index 000000000..6e4d8f6f5 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/http/NamespaceException.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) OSGi Alliance (2000, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.http; + +/** + * A NamespaceException is thrown to indicate an error with the caller's request + * to register a servlet or resources into the URI namespace of the Http + * Service. This exception indicates that the requested alias already is in use. + * + * @author $Id$ + */ +public class NamespaceException extends Exception { + static final long serialVersionUID = 7235606031147877747L; + + /** + * Construct a {@code NamespaceException} object with a detail message. + * + * @param message the detail message + */ + public NamespaceException(String message) { + super(message); + } + + /** + * Construct a {@code NamespaceException} object with a detail message and a + * nested exception. + * + * @param message The detail message. + * @param cause The nested exception. + */ + public NamespaceException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Returns the nested exception. + * + * <p> + * This method predates the general purpose exception chaining mechanism. + * The {@code getCause()} method is now the preferred means of obtaining + * this information. + * + * @return The result of calling {@code getCause()}. + */ + public Throwable getException() { + return getCause(); + } + + /** + * Returns the cause of this exception or {@code null} if no cause was set. + * + * @return The cause of this exception or {@code null} if no cause was set. + * @since 1.2 + */ + public Throwable getCause() { + return super.getCause(); + } + + /** + * Initializes the cause of this exception to the specified value. + * + * @param cause The cause of this exception. + * @return This exception. + * @throws IllegalArgumentException If the specified cause is this + * exception. + * @throws IllegalStateException If the cause of this exception has already + * been set. + * @since 1.2 + */ + public Throwable initCause(Throwable cause) { + return super.initCause(cause); + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/http/package-info.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/http/package-info.java new file mode 100644 index 000000000..349de707c --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/http/package-info.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) OSGi Alliance (2010, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Http Service Package Version 1.2. + * + * <p> + * Bundles wishing to use this package must list the package in the + * Import-Package header of the bundle's manifest. This package has two types of + * users: the consumers that use the API in this package and the providers that + * implement the API in this package. + * + * <p> + * Example import for consumers using the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.http; version="[1.2,2.0)"} + * <p> + * Example import for providers implementing the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.http; version="[1.2,1.3)"} + * + * @version 1.2.1 + * @author $Id$ + */ + +package org.osgi.service.http; + diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/http/packageinfo b/bundles/org.eclipse.osgi.services/src/org/osgi/service/http/packageinfo new file mode 100644 index 000000000..6ebb891f1 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/http/packageinfo @@ -0,0 +1 @@ +version 1.2.1 diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/LogEntry.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/LogEntry.java new file mode 100644 index 000000000..1a6c322e6 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/LogEntry.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) OSGi Alliance (2000, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.log; + +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceReference; + +/** + * Provides methods to access the information contained in an individual Log + * Service log entry. + * + * <p> + * A {@code LogEntry} object may be acquired from the + * {@code LogReaderService.getLog} method or by registering a + * {@code LogListener} object. + * + * @ThreadSafe + * @noimplement + * @author $Id$ + * @see LogReaderService#getLog + * @see LogListener + */ +public interface LogEntry { + /** + * Returns the bundle that created this {@code LogEntry} object. + * + * @return The bundle that created this {@code LogEntry} object; + * {@code null} if no bundle is associated with this + * {@code LogEntry} object. + */ + public Bundle getBundle(); + + /** + * Returns the {@code ServiceReference} object for the service associated + * with this {@code LogEntry} object. + * + * @return {@code ServiceReference} object for the service associated with + * this {@code LogEntry} object; {@code null} if no + * {@code ServiceReference} object was provided. + */ + public ServiceReference getServiceReference(); + + /** + * Returns the severity level of this {@code LogEntry} object. + * + * <p> + * This is one of the severity levels defined by the {@code LogService} + * interface. + * + * @return Severity level of this {@code LogEntry} object. + * + * @see LogService#LOG_ERROR + * @see LogService#LOG_WARNING + * @see LogService#LOG_INFO + * @see LogService#LOG_DEBUG + */ + public int getLevel(); + + /** + * Returns the human readable message associated with this {@code LogEntry} + * object. + * + * @return {@code String} containing the message associated with this + * {@code LogEntry} object. + */ + public String getMessage(); + + /** + * Returns the exception object associated with this {@code LogEntry} + * object. + * + * <p> + * In some implementations, the returned exception may not be the original + * exception. To avoid references to a bundle defined exception class, thus + * preventing an uninstalled bundle from being garbage collected, the Log + * Service may return an exception object of an implementation defined + * Throwable subclass. The returned object will attempt to provide as much + * information as possible from the original exception object such as the + * message and stack trace. + * + * @return {@code Throwable} object of the exception associated with this + * {@code LogEntry};{@code null} if no exception is associated with + * this {@code LogEntry} object. + */ + public Throwable getException(); + + /** + * Returns the value of {@code currentTimeMillis()} at the time this + * {@code LogEntry} object was created. + * + * @return The system time in milliseconds when this {@code LogEntry} object + * was created. + * @see "System.currentTimeMillis()" + */ + public long getTime(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/LogListener.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/LogListener.java new file mode 100644 index 000000000..4e27a9415 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/LogListener.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) OSGi Alliance (2000, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.log; + +import java.util.EventListener; + +/** + * Subscribes to {@code LogEntry} objects from the {@code LogReaderService}. + * + * <p> + * A {@code LogListener} object may be registered with the Log Reader Service + * using the {@code LogReaderService.addLogListener} method. After the listener + * is registered, the {@code logged} method will be called for each + * {@code LogEntry} object created. The {@code LogListener} object may be + * unregistered by calling the {@code LogReaderService.removeLogListener} + * method. + * + * @ThreadSafe + * @author $Id$ + * @see LogReaderService + * @see LogEntry + * @see LogReaderService#addLogListener(LogListener) + * @see LogReaderService#removeLogListener(LogListener) + */ +public interface LogListener extends EventListener { + /** + * Listener method called for each LogEntry object created. + * + * <p> + * As with all event listeners, this method should return to its caller as + * soon as possible. + * + * @param entry A {@code LogEntry} object containing log information. + * @see LogEntry + */ + public void logged(LogEntry entry); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/LogReaderService.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/LogReaderService.java new file mode 100644 index 000000000..ecc3958bd --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/LogReaderService.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) OSGi Alliance (2000, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.log; + +import java.util.Enumeration; + +/** + * Provides methods to retrieve {@code LogEntry} objects from the log. + * <p> + * There are two ways to retrieve {@code LogEntry} objects: + * <ul> + * <li>The primary way to retrieve {@code LogEntry} objects is to register a + * {@code LogListener} object whose {@code LogListener.logged} method will be + * called for each entry added to the log.</li> + * <li>To retrieve past {@code LogEntry} objects, the {@code getLog} method can + * be called which will return an {@code Enumeration} of all {@code LogEntry} + * objects in the log.</li> + * </ul> + * + * @ThreadSafe + * @author $Id$ + * @see LogEntry + * @see LogListener + * @see LogListener#logged(LogEntry) + */ +public interface LogReaderService { + /** + * Subscribes to {@code LogEntry} objects. + * + * <p> + * This method registers a {@code LogListener} object with the Log Reader + * Service. The {@code LogListener.logged(LogEntry)} method will be called + * for each {@code LogEntry} object placed into the log. + * + * <p> + * When a bundle which registers a {@code LogListener} object is stopped or + * otherwise releases the Log Reader Service, the Log Reader Service must + * remove all of the bundle's listeners. + * + * <p> + * If this Log Reader Service's list of listeners already contains a + * listener {@code l} such that {@code (l==listener)}, this method does + * nothing. + * + * @param listener A {@code LogListener} object to register; the + * {@code LogListener} object is used to receive {@code LogEntry} + * objects. + * @see LogListener + * @see LogEntry + * @see LogListener#logged(LogEntry) + */ + public void addLogListener(LogListener listener); + + /** + * Unsubscribes to {@code LogEntry} objects. + * + * <p> + * This method unregisters a {@code LogListener} object from the Log Reader + * Service. + * + * <p> + * If {@code listener} is not contained in this Log Reader Service's list of + * listeners, this method does nothing. + * + * @param listener A {@code LogListener} object to unregister. + * @see LogListener + */ + public void removeLogListener(LogListener listener); + + /** + * Returns an {@code Enumeration} of all {@code LogEntry} objects in the + * log. + * + * <p> + * Each element of the enumeration is a {@code LogEntry} object, ordered + * with the most recent entry first. Whether the enumeration is of all + * {@code LogEntry} objects since the Log Service was started or some recent + * past is implementation-specific. Also implementation-specific is whether + * informational and debug {@code LogEntry} objects are included in the + * enumeration. + * + * @return An {@code Enumeration} of all {@code LogEntry} objects in the + * log. + */ + public Enumeration getLog(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/LogService.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/LogService.java new file mode 100644 index 000000000..dc7a9f634 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/LogService.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) OSGi Alliance (2000, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.log; + +import org.osgi.framework.ServiceReference; + +/** + * Provides methods for bundles to write messages to the log. + * + * <p> + * {@code LogService} methods are provided to log messages; optionally with a + * {@code ServiceReference} object or an exception. + * + * <p> + * Bundles must log messages in the OSGi environment with a severity level + * according to the following hierarchy: + * <ol> + * <li>{@link #LOG_ERROR}</li> + * <li>{@link #LOG_WARNING}</li> + * <li>{@link #LOG_INFO}</li> + * <li>{@link #LOG_DEBUG}</li> + * </ol> + * + * @ThreadSafe + * @noimplement + * @author $Id$ + */ +public interface LogService { + /** + * An error message (Value 1). + * + * <p> + * This log entry indicates the bundle or service may not be functional. + */ + public static final int LOG_ERROR = 1; + /** + * A warning message (Value 2). + * + * <p> + * This log entry indicates a bundle or service is still functioning but may + * experience problems in the future because of the warning condition. + */ + public static final int LOG_WARNING = 2; + /** + * An informational message (Value 3). + * + * <p> + * This log entry may be the result of any change in the bundle or service + * and does not indicate a problem. + */ + public static final int LOG_INFO = 3; + /** + * A debugging message (Value 4). + * + * <p> + * This log entry is used for problem determination and may be irrelevant to + * anyone but the bundle developer. + */ + public static final int LOG_DEBUG = 4; + + /** + * Logs a message. + * + * <p> + * The {@code ServiceReference} field and the {@code Throwable} field of the + * {@code LogEntry} object will be set to {@code null}. + * + * @param level The severity of the message. This should be one of the + * defined log levels but may be any integer that is interpreted in a + * user defined way. + * @param message Human readable string describing the condition or + * {@code null}. + * @see #LOG_ERROR + * @see #LOG_WARNING + * @see #LOG_INFO + * @see #LOG_DEBUG + */ + public void log(int level, String message); + + /** + * Logs a message with an exception. + * + * <p> + * The {@code ServiceReference} field of the {@code LogEntry} object will be + * set to {@code null}. + * + * @param level The severity of the message. This should be one of the + * defined log levels but may be any integer that is interpreted in a + * user defined way. + * @param message The human readable string describing the condition or + * {@code null}. + * @param exception The exception that reflects the condition or + * {@code null}. + * @see #LOG_ERROR + * @see #LOG_WARNING + * @see #LOG_INFO + * @see #LOG_DEBUG + */ + public void log(int level, String message, Throwable exception); + + /** + * Logs a message associated with a specific {@code ServiceReference} + * object. + * + * <p> + * The {@code Throwable} field of the {@code LogEntry} will be set to + * {@code null}. + * + * @param sr The {@code ServiceReference} object of the service that this + * message is associated with or {@code null}. + * @param level The severity of the message. This should be one of the + * defined log levels but may be any integer that is interpreted in a + * user defined way. + * @param message Human readable string describing the condition or + * {@code null}. + * @see #LOG_ERROR + * @see #LOG_WARNING + * @see #LOG_INFO + * @see #LOG_DEBUG + */ + public void log(ServiceReference sr, int level, String message); + + /** + * Logs a message with an exception associated and a + * {@code ServiceReference} object. + * + * @param sr The {@code ServiceReference} object of the service that this + * message is associated with. + * @param level The severity of the message. This should be one of the + * defined log levels but may be any integer that is interpreted in a + * user defined way. + * @param message Human readable string describing the condition or + * {@code null}. + * @param exception The exception that reflects the condition or + * {@code null}. + * @see #LOG_ERROR + * @see #LOG_WARNING + * @see #LOG_INFO + * @see #LOG_DEBUG + */ + public void log(ServiceReference sr, int level, String message, Throwable exception); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/package-info.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/package-info.java new file mode 100644 index 000000000..928099019 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/package-info.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Log Service Package Version 1.3. + * + * <p> + * Bundles wishing to use this package must list the package in the + * Import-Package header of the bundle's manifest. This package has two types of + * users: the consumers that use the API in this package and the providers that + * implement the API in this package. + * + * <p> + * Example import for consumers using the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.log; version="[1.3,2.0)"} + * <p> + * Example import for providers implementing the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.log; version="[1.3,1.4)"} + * + * @version 1.3 + * @author $Id$ + */ + +package org.osgi.service.log; + diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/packageinfo b/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/packageinfo new file mode 100644 index 000000000..0117a56c1 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/log/packageinfo @@ -0,0 +1 @@ +version 1.3 diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/AttributeDefinition.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/AttributeDefinition.java new file mode 100644 index 000000000..f2aa9ead0 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/AttributeDefinition.java @@ -0,0 +1,304 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.metatype; + +/** + * An interface to describe an attribute. + * + * <p> + * An {@code AttributeDefinition} object defines a description of the data type + * of a property/attribute. + * + * @ThreadSafe + * @author $Id$ + */ +public interface AttributeDefinition { + /** + * The {@code STRING} (1) type. + * + * <p> + * Attributes of this type should be stored as {@code String}, + * {@code Vector} with {@code String} or {@code String[]} objects, depending + * on the {@code getCardinality()} value. + */ + int STRING = 1; + /** + * The {@code LONG} (2) type. + * + * Attributes of this type should be stored as {@code Long}, {@code Vector} + * with {@code Long} or {@code long[]} objects, depending on the + * {@code getCardinality()} value. + */ + int LONG = 2; + /** + * The {@code INTEGER} (3) type. + * + * Attributes of this type should be stored as {@code Integer}, + * {@code Vector} with {@code Integer} or {@code int[]} objects, depending + * on the {@code getCardinality()} value. + */ + int INTEGER = 3; + /** + * The {@code SHORT} (4) type. + * + * Attributes of this type should be stored as {@code Short}, {@code Vector} + * with {@code Short} or {@code short[]} objects, depending on the + * {@code getCardinality()} value. + */ + int SHORT = 4; + /** + * The {@code CHARACTER} (5) type. + * + * Attributes of this type should be stored as {@code Character}, + * {@code Vector} with {@code Character} or {@code char[]} objects, + * depending on the {@code getCardinality()} value. + */ + int CHARACTER = 5; + /** + * The {@code BYTE} (6) type. + * + * Attributes of this type should be stored as {@code Byte}, {@code Vector} + * with {@code Byte} or {@code byte[]} objects, depending on the + * {@code getCardinality()} value. + */ + int BYTE = 6; + /** + * The {@code DOUBLE} (7) type. + * + * Attributes of this type should be stored as {@code Double}, + * {@code Vector} with {@code Double} or {@code double[]} objects, depending + * on the {@code getCardinality()} value. + */ + int DOUBLE = 7; + /** + * The {@code FLOAT} (8) type. + * + * Attributes of this type should be stored as {@code Float}, {@code Vector} + * with {@code Float} or {@code float[]} objects, depending on the + * {@code getCardinality()} value. + */ + int FLOAT = 8; + /** + * The {@code BIGINTEGER} (9) type. + * + * Attributes of this type should be stored as {@code BigInteger}, + * {@code Vector} with {@code BigInteger} or {@code BigInteger[]} objects, + * depending on the {@code getCardinality()} value. + * + * @deprecated As of 1.1. + */ + int BIGINTEGER = 9; + /** + * The {@code BIGDECIMAL} (10) type. + * + * Attributes of this type should be stored as {@code BigDecimal}, + * {@code Vector} with {@code BigDecimal} or {@code BigDecimal[]} objects + * depending on {@code getCardinality()}. + * + * @deprecated As of 1.1. + */ + int BIGDECIMAL = 10; + /** + * The {@code BOOLEAN} (11) type. + * + * Attributes of this type should be stored as {@code Boolean}, + * {@code Vector} with {@code Boolean} or {@code boolean[]} objects + * depending on {@code getCardinality()}. + */ + int BOOLEAN = 11; + + /** + * The {@code PASSWORD} (12) type. + * + * Attributes of this type must be stored as {@code String}, {@code Vector} + * with {@code String} or {@code String[]} objects depending on {link + * getCardinality()}. A {@code PASSWORD} must be treated as a string but the + * type can be used to disguise the information when displayed to a user to + * prevent others from seeing it. + * + * @since 1.2 + */ + int PASSWORD = 12; + + /** + * Get the name of the attribute. This name may be localized. + * + * @return The localized name of the definition. + */ + String getName(); + + /** + * Unique identity for this attribute. + * + * Attributes share a global namespace in the registry. E.g. an attribute + * {@code cn} or {@code commonName} must always be a {@code String} and the + * semantics are always a name of some object. They share this aspect with + * LDAP/X.500 attributes. In these standards the OSI Object Identifier (OID) + * is used to uniquely identify an attribute. If such an OID exists, (which + * can be requested at several standard organisations and many companies + * already have a node in the tree) it can be returned here. Otherwise, a + * unique id should be returned which can be a Java class name (reverse + * domain name) or generated with a GUID algorithm. Note that all LDAP + * defined attributes already have an OID. It is strongly advised to define + * the attributes from existing LDAP schemes which will give the OID. Many + * such schemes exist ranging from postal addresses to DHCP parameters. + * + * @return The id or oid + */ + String getID(); + + /** + * Return a description of this attribute. + * + * The description may be localized and must describe the semantics of this + * type and any constraints. + * + * @return The localized description of the definition. + */ + String getDescription(); + + /** + * Return the cardinality of this attribute. + * + * The OSGi environment handles multi valued attributes in arrays ([]) or in + * {@code Vector} objects. The return value is defined as follows: + * + * <pre> + * + * x = Integer.MIN_VALUE no limit, but use Vector + * x < 0 -x = max occurrences, store in Vector + * x > 0 x = max occurrences, store in array [] + * x = Integer.MAX_VALUE no limit, but use array [] + * x = 0 1 occurrence required + * + * </pre> + * + * @return The cardinality of this attribute. + */ + int getCardinality(); + + /** + * Return the type for this attribute. + * + * <p> + * Defined in the following constants which map to the appropriate Java + * type. {@code STRING},{@code LONG},{@code INTEGER}, {@code CHAR}, + * {@code BYTE},{@code DOUBLE},{@code FLOAT}, {@code BOOLEAN}. + * + * @return The type for this attribute. + */ + int getType(); + + /** + * Return a list of option values that this attribute can take. + * + * <p> + * If the function returns {@code null}, there are no option values + * available. + * + * <p> + * Each value must be acceptable to validate() (return "") and must be a + * {@code String} object that can be converted to the data type defined by + * getType() for this attribute. + * + * <p> + * This list must be in the same sequence as {@code getOptionLabels()}. I.e. + * for each index i in {@code getOptionValues}, i in + * {@code getOptionLabels()} should be the label. + * + * <p> + * For example, if an attribute can have the value male, female, unknown, + * this list can return + * <code>new String[] { "male", "female", "unknown" }</code>. + * + * @return A list values + */ + String[] getOptionValues(); + + /** + * Return a list of labels of option values. + * + * <p> + * The purpose of this method is to allow menus with localized labels. It is + * associated with {@code getOptionValues}. The labels returned here are + * ordered in the same way as the values in that method. + * + * <p> + * If the function returns {@code null}, there are no option labels + * available. + * <p> + * This list must be in the same sequence as the {@code getOptionValues()} + * method. I.e. for each index i in {@code getOptionLabels}, i in + * {@code getOptionValues()} should be the associated value. + * + * <p> + * For example, if an attribute can have the value male, female, unknown, + * this list can return (for dutch) + * <code>new String[] { "Man", "Vrouw", "Onbekend" }</code>. + * + * @return A list values + */ + String[] getOptionLabels(); + + /** + * Validate an attribute in {@code String} form. + * + * An attribute might be further constrained in value. This method will + * attempt to validate the attribute according to these constraints. It can + * return three different values: + * + * <pre> + * null No validation present + * "" No problems detected + * "..." A localized description of why the value is wrong + * </pre> + * + * If the cardinality of this attribute is multi-valued then this string + * must be interpreted as a comma delimited string. The complete value must + * be trimmed from white space as well as spaces around commas. Commas ( + * {@code ','} \u002C) and spaces ({@code ' '} \u0020) and + * backslashes ({@code '\'} \u005C) can be escaped with another + * backslash. Escaped spaces must not be trimmed. For example: + * + * <pre> + * value=" a\,b,b\,c,\ c\\,d " => [ "a,b", "b,c", " c\", "d" ] + * </pre> + * + * @param value The value before turning it into the basic data type. If the + * cardinality indicates a multi-valued attribute then the given + * string must be escaped. + * @return {@code null}, "", or another string + */ + String validate(String value); + + /** + * Return a default for this attribute. + * + * The object must be of the appropriate type as defined by the cardinality + * and {@code getType()}. The return type is a list of {@code String} + * objects that can be converted to the appropriate type. The cardinality of + * the return array must follow the absolute cardinality of this type. E.g. + * if the cardinality = 0, the array must contain 1 element. If the + * cardinality is 1, it must contain 0 or 1 elements. If it is -5, it must + * contain from 0 to max 5 elements. Note that the special case of a 0 + * cardinality, meaning a single value, does not allow arrays or vectors of + * 0 elements. + * + * @return Return a default value or {@code null} if no default exists. + */ + String[] getDefaultValue(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/MetaTypeInformation.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/MetaTypeInformation.java new file mode 100644 index 000000000..5d7956910 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/MetaTypeInformation.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) OSGi Alliance (2005, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.metatype; + +import org.osgi.framework.Bundle; + +/** + * A MetaType Information object is created by the MetaTypeService to return + * meta type information for a specific bundle. + * + * @ThreadSafe + * @noimplement + * @author $Id$ + * @since 1.1 + */ +public interface MetaTypeInformation extends MetaTypeProvider { + /** + * Return the PIDs (for ManagedServices) for which ObjectClassDefinition + * information is available. + * + * @return Array of PIDs. + */ + public String[] getPids(); + + /** + * Return the Factory PIDs (for ManagedServiceFactories) for which + * ObjectClassDefinition information is available. + * + * @return Array of Factory PIDs. + */ + public String[] getFactoryPids(); + + /** + * Return the bundle for which this object provides meta type information. + * + * @return Bundle for which this object provides meta type information. + */ + public Bundle getBundle(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/MetaTypeProvider.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/MetaTypeProvider.java new file mode 100644 index 000000000..44778640e --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/MetaTypeProvider.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.metatype; + +/** + * Provides access to metatypes. This interface can be implemented on a Managed + * Service or Managed Service Factory as well as registered as a service. When + * registered as a service, it must be registered with a + * {@link #METATYPE_FACTORY_PID} or {@link #METATYPE_PID} service property (or + * both). Any PID mentioned in either of these factories must be a valid + * argument to the {@link #getObjectClassDefinition(String, String)} method. + * + * @ThreadSafe + * @author $Id$ + */ +public interface MetaTypeProvider { + + /** + * Service property to signal that this service has + * {@link ObjectClassDefinition} objects for the given PIDs. The type of + * this service property is {@code String+}. + * + * @since 1.2 + */ + String METATYPE_PID = "metatype.pid"; + + /** + * Service property to signal that this service has + * {@link ObjectClassDefinition} objects for the given factory PIDs. The + * type of this service property is {@code String+}. + * + * @since 1.2 + */ + String METATYPE_FACTORY_PID = "metatype.factory.pid"; + + /** + * Returns an object class definition for the specified id localized to the + * specified locale. + * + * <p> + * The locale parameter must be a name that consists of {@code language}[ + * "_" {@code country}[ "_" {@code variation}] ] as is customary in the + * {@code Locale} class. This {@code Locale} class is not used because + * certain profiles do not contain it. + * + * @param id The ID of the requested object class. This can be a pid or + * factory pid returned by getPids or getFactoryPids. + * @param locale The locale of the definition or {@code null} for default + * locale. + * @return A {@code ObjectClassDefinition} object. + * @throws IllegalArgumentException If the id or locale arguments are not + * valid + */ + public ObjectClassDefinition getObjectClassDefinition(String id, String locale); + + /** + * Return a list of available locales. + * + * The results must be names that consists of language [ _ country [ _ + * variation ]] as is customary in the {@code Locale} class. + * + * @return An array of locale strings or {@code null} if there is no locale + * specific localization can be found. + * + */ + public String[] getLocales(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/MetaTypeService.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/MetaTypeService.java new file mode 100644 index 000000000..e4733d8f8 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/MetaTypeService.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) OSGi Alliance (2005, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.metatype; + +import org.osgi.framework.Bundle; + +/** + * The MetaType Service can be used to obtain meta type information for a + * bundle. The MetaType Service will examine the specified bundle for meta type + * documents to create the returned {@code MetaTypeInformation} object. + * + * <p> + * If the specified bundle does not contain any meta type documents, then a + * {@code MetaTypeInformation} object will be returned that wrappers any + * {@code ManagedService} or {@code ManagedServiceFactory} services registered + * by the specified bundle that implement {@code MetaTypeProvider}. Thus the + * MetaType Service can be used to retrieve meta type information for bundles + * which contain a meta type documents or which provide their own + * {@code MetaTypeProvider} objects. + * + * @ThreadSafe + * @noimplement + * @author $Id$ + * @since 1.1 + */ +public interface MetaTypeService { + /** + * Return the MetaType information for the specified bundle. + * + * @param bundle The bundle for which meta type information is requested. + * @return A MetaTypeInformation object for the specified bundle. + */ + public MetaTypeInformation getMetaTypeInformation(Bundle bundle); + + /** + * Location of meta type documents. The MetaType Service will process each + * entry in the meta type documents directory. + */ + public final static String METATYPE_DOCUMENTS_LOCATION = "OSGI-INF/metatype"; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/ObjectClassDefinition.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/ObjectClassDefinition.java new file mode 100644 index 000000000..f65f64dbc --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/ObjectClassDefinition.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.metatype; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Description for the data type information of an objectclass. + * + * @ThreadSafe + * @author $Id$ + */ +public interface ObjectClassDefinition { + /** + * Argument for {@code getAttributeDefinitions(int)}. + * <p> + * {@code REQUIRED} indicates that only the required definitions are + * returned. The value is 1. + */ + public static final int REQUIRED = 1; + /** + * Argument for {@code getAttributeDefinitions(int)}. + * <p> + * {@code OPTIONAL} indicates that only the optional definitions are + * returned. The value is 2. + */ + public static final int OPTIONAL = 2; + /** + * Argument for {@code getAttributeDefinitions(int)}. + * <p> + * {@code ALL} indicates that all the definitions are returned. The value is + * -1. + */ + public static final int ALL = 0xFFFFFFFF; + + /** + * Return the name of this object class. + * + * The name may be localized. + * + * @return The name of this object class. + */ + public String getName(); + + /** + * Return the id of this object class. + * + * <p> + * {@code ObjectDefintion} objects share a global namespace in the registry. + * They share this aspect with LDAP/X.500 attributes. In these standards the + * OSI Object Identifier (OID) is used to uniquely identify object classes. + * If such an OID exists, (which can be requested at several standard + * organisations and many companies already have a node in the tree) it can + * be returned here. Otherwise, a unique id should be returned which can be + * a java class name (reverse domain name) or generated with a GUID + * algorithm. Note that all LDAP defined object classes already have an OID + * associated. It is strongly advised to define the object classes from + * existing LDAP schemes which will give the OID for free. Many such schemes + * exist ranging from postal addresses to DHCP parameters. + * + * @return The id of this object class. + */ + public String getID(); + + /** + * Return a description of this object class. + * + * The description may be localized. + * + * @return The description of this object class. + */ + public String getDescription(); + + /** + * Return the attribute definitions for this object class. + * + * <p> + * Return a set of attributes. The filter parameter can distinguish between + * {@code ALL},{@code REQUIRED} or the {@code OPTIONAL} attributes. + * + * @param filter {@code ALL},{@code REQUIRED},{@code OPTIONAL} + * @return An array of attribute definitions or {@code null} if no + * attributes are selected + */ + public AttributeDefinition[] getAttributeDefinitions(int filter); + + /** + * Return an {@code InputStream} object that can be used to create an icon + * from. + * + * <p> + * Indicate the size and return an {@code InputStream} object containing an + * icon. The returned icon maybe larger or smaller than the indicated size. + * + * <p> + * The icon may depend on the localization. + * + * @param size Requested size of an icon, e.g. a 16x16 pixels icon then size + * = 16 + * @return An InputStream representing an icon or {@code null} + * @throws IOException If the {@code InputStream} cannot be returned. + */ + public InputStream getIcon(int size) throws IOException; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/package-info.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/package-info.java new file mode 100644 index 000000000..3be55f7d3 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/package-info.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Metatype Package Version 1.2. + * + * <p> + * Bundles wishing to use this package must list the package in the + * Import-Package header of the bundle's manifest. This package has two types of + * users: the consumers that use the API in this package and the providers that + * implement the API in this package. + * + * <p> + * Example import for consumers using the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.metatype; version="[1.2,2.0)"} + * <p> + * Example import for providers implementing the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.metatype; version="[1.2,1.3)"} + * + * @version 1.2 + * @author $Id$ + */ + +package org.osgi.service.metatype; + diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/packageinfo b/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/packageinfo new file mode 100644 index 000000000..ef7df68cb --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/metatype/packageinfo @@ -0,0 +1 @@ +version 1.2 diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/provisioning/ProvisioningService.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/provisioning/ProvisioningService.java new file mode 100644 index 000000000..50e49f069 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/provisioning/ProvisioningService.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.provisioning; + +import java.io.IOException; +import java.util.Dictionary; +import java.util.zip.ZipInputStream; + +/** + * Service for managing the initial provisioning information. + * <p> + * Initial provisioning of an OSGi device is a multi step process that + * culminates with the installation and execution of the initial management + * agent. At each step of the process, information is collected for the next + * step. Multiple bundles may be involved and this service provides a means for + * these bundles to exchange information. It also provides a means for the + * initial Management Bundle to get its initial configuration information. + * <p> + * The provisioning information is collected in a {@code Dictionary} object, + * called the Provisioning Dictionary. Any bundle that can access the service + * can get a reference to this object and read and update provisioning + * information. The key of the dictionary is a {@code String} object and the + * value is a {@code String} or {@code byte[]} object. The single exception is + * the PROVISIONING_UPDATE_COUNT value which is an Integer. The + * {@code provisioning} prefix is reserved for keys defined by OSGi, other key + * names may be used for implementation dependent provisioning systems. + * <p> + * Any changes to the provisioning information will be reflected immediately in + * all the dictionary objects obtained from the Provisioning Service. + * <p> + * Because of the specific application of the Provisioning Service, there should + * be only one Provisioning Service registered. This restriction will not be + * enforced by the Framework. Gateway operators or manufactures should ensure + * that a Provisioning Service bundle is not installed on a device that already + * has a bundle providing the Provisioning Service. + * <p> + * The provisioning information has the potential to contain sensitive + * information. Also, the ability to modify provisioning information can have + * drastic consequences. Thus, only trusted bundles should be allowed to + * register and get the Provisioning Service. The {@code ServicePermission} is + * used to limit the bundles that can gain access to the Provisioning Service. + * There is no check of {@code Permission} objects to read or modify the + * provisioning information, so care must be taken not to leak the Provisioning + * Dictionary received from {@code getInformation} method. + * + * @noimplement + * @author $Id$ + */ +public interface ProvisioningService { + /** + * The key to the provisioning information that uniquely identifies the + * Service Platform. The value must be of type {@code String}. + */ + public final static String PROVISIONING_SPID = "provisioning.spid"; + + /** + * The key to the provisioning information that contains the location of the + * provision data provider. The value must be of type {@code String}. + */ + public final static String PROVISIONING_REFERENCE = "provisioning.reference"; + + /** + * The key to the provisioning information that contains the initial + * configuration information of the initial Management Agent. The value will + * be of type {@code byte[]}. + */ + public final static String PROVISIONING_AGENT_CONFIG = "provisioning.agent.config"; + + /** + * The key to the provisioning information that contains the update count of + * the info data. Each set of changes to the provisioning information must + * end with this value being incremented. The value must be of type + * {@code Integer}. This key/value pair is also reflected in the properties + * of the ProvisioningService in the service registry. + */ + public final static String PROVISIONING_UPDATE_COUNT = "provisioning.update.count"; + + /** + * The key to the provisioning information that contains the location of the + * bundle to start with {@code AllPermission}. The bundle must have be + * previously installed for this entry to have any effect. + */ + public final static String PROVISIONING_START_BUNDLE = "provisioning.start.bundle"; + + /** + * The key to the provisioning information that contains the root X509 + * certificate used to establish trust with operator when using HTTPS. + */ + public final static String PROVISIONING_ROOTX509 = "provisioning.rootx509"; + + /** + * The key to the provisioning information that contains the shared secret + * used in conjunction with the RSH protocol. + */ + public final static String PROVISIONING_RSH_SECRET = "provisioning.rsh.secret"; + + /** + * MIME type to be stored in the extra field of a {@code ZipEntry} object + * for String data. + */ + public final static String MIME_STRING = "text/plain;charset=utf-8"; + + /** + * MIME type to be stored stored in the extra field of a {@code ZipEntry} + * object for {@code byte[]} data. + */ + public final static String MIME_BYTE_ARRAY = "application/octet-stream"; + + /** + * MIME type to be stored in the extra field of a {@code ZipEntry} object + * for an installable bundle file. Zip entries of this type will be + * installed in the framework, but not started. The entry will also not be + * put into the information dictionary. + */ + public final static String MIME_BUNDLE = "application/vnd.osgi.bundle"; + + /** + * Alternative MIME type to be stored in the extra field of a + * {@code ZipEntry} object for an installable bundle file. Zip entries of + * this type will be installed in the framework, but not started. The entry + * will also not be put into the information dictionary. This alternative + * entry is only for backward compatibility, new applications are + * recommended to use {@code MIME_BUNDLE}, which is an official IANA MIME + * type. + * + * @since 1.2 + */ + public final static String MIME_BUNDLE_ALT = "application/x-osgi-bundle"; + + /** + * MIME type to be stored in the extra field of a ZipEntry for a String that + * represents a URL for a bundle. Zip entries of this type will be used to + * install (but not start) a bundle from the URL. The entry will not be put + * into the information dictionary. + */ + public final static String MIME_BUNDLE_URL = "text/x-osgi-bundle-url"; + + /** + * Name of the header that specifies the type information for the ZIP file + * entries. + * + * @since 1.2 + */ + public final static String INITIALPROVISIONING_ENTRIES = "InitialProvisioning-Entries"; + + /** + * Returns a reference to the Provisioning Dictionary. Any change operations + * (put and remove) to the dictionary will cause an + * {@code UnsupportedOperationException} to be thrown. Changes must be done + * using the {@code setInformation} and {@code addInformation} methods of + * this service. + * + * @return A reference to the Provisioning Dictionary. + */ + public Dictionary getInformation(); + + /** + * Replaces the Provisioning Information dictionary with the key/value pairs + * contained in {@code info}. Any key/value pairs not in {@code info} will + * be removed from the Provisioning Information dictionary. This method + * causes the {@code PROVISIONING_UPDATE_COUNT} to be incremented. + * + * @param info the new set of Provisioning Information key/value pairs. Any + * keys are values that are of an invalid type will be silently + * ignored. + */ + public void setInformation(Dictionary info); + + /** + * Adds the key/value pairs contained in {@code info} to the Provisioning + * Information dictionary. This method causes the + * {@code PROVISIONING_UPDATE_COUNT} to be incremented. + * + * @param info the set of Provisioning Information key/value pairs to add to + * the Provisioning Information dictionary. Any keys are values that + * are of an invalid type will be silently ignored. + */ + public void addInformation(Dictionary info); + + /** + * Processes the {@code ZipInputStream} and extracts information to add to + * the Provisioning Information dictionary, as well as, install/update and + * start bundles. This method causes the {@code PROVISIONING_UPDATE_COUNT} + * to be incremented. + * + * @param zis the {@code ZipInputStream} that will be used to add key/value + * pairs to the Provisioning Information dictionary and install and + * start bundles. If a {@code ZipEntry} does not have an + * {@code Extra} field that corresponds to one of the four defined + * MIME types ({@code MIME_STRING}, {@code MIME_BYTE_ARRAY}, + * {@code MIME_BUNDLE}, and {@code MIME_BUNDLE_URL}) in will be + * silently ignored. + * @throws IOException if an error occurs while processing the + * ZipInputStream. No additions will be made to the Provisioning + * Information dictionary and no bundles must be started or + * installed. + */ + public void addInformation(ZipInputStream zis) throws IOException; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/provisioning/package-info.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/provisioning/package-info.java new file mode 100644 index 000000000..d47e07a89 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/provisioning/package-info.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Provisioning Package Version 1.2. + * + * <p> + * Bundles wishing to use this package must list the package in the + * Import-Package header of the bundle's manifest. This package has two types of + * users: the consumers that use the API in this package and the providers that + * implement the API in this package. + * + * <p> + * Example import for consumers using the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.provisioning; version="[1.2,2.0)"} + * <p> + * Example import for providers implementing the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.provisioning; version="[1.2,1.3)"} + * + * @version 1.2 + * @author $Id$ + */ + +package org.osgi.service.provisioning; + diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/provisioning/packageinfo b/bundles/org.eclipse.osgi.services/src/org/osgi/service/provisioning/packageinfo new file mode 100644 index 000000000..ef7df68cb --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/provisioning/packageinfo @@ -0,0 +1 @@ +version 1.2 diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPAction.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPAction.java new file mode 100644 index 000000000..f1ba100ae --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPAction.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.upnp; + +import java.util.Dictionary; + +/** + * A UPnP action. + * + * Each UPnP service contains zero or more actions. Each action may have zero or + * more UPnP state variables as arguments. + * + * @author $Id$ + */ +public interface UPnPAction { + /** + * Returns the action name. + * + * The action name corresponds to the {@code name} field in the + * {@code actionList} of the service description. + * <ul> + * <li>For standard actions defined by a UPnP Forum working committee, + * action names must not begin with {@code X_ } nor {@code A_}.</li> + * <li>For non-standard actions specified by a UPnP vendor and added to a + * standard service, action names must begin with {@code X_}.</li> + * </ul> + * + * <p> + * This method must continue to return the action name after the UPnP action + * has been removed from the network. + * + * @return Name of action, must not contain a hyphen character or a hash + * character + */ + String getName(); + + /** + * Returns the name of the designated return argument. + * <p> + * One of the output arguments can be flagged as a designated return + * argument. + * + * <p> + * This method must continue to return the action return argument name after + * the UPnP action has been removed from the network. + * + * @return The name of the designated return argument or {@code null} if + * none is marked. + */ + String getReturnArgumentName(); + + /** + * Lists all input arguments for this action. + * <p> + * Each action may have zero or more input arguments. + * + * <p> + * This method must continue to return the action input argument names after + * the UPnP action has been removed from the network. + * + * @return Array of input argument names or {@code null} if no input + * arguments. + * + * @see UPnPStateVariable + */ + String[] getInputArgumentNames(); + + /** + * List all output arguments for this action. + * + * <p> + * This method must continue to return the action output argument names + * after the UPnP action has been removed from the network. + * + * @return Array of output argument names or {@code null} if there are no + * output arguments. + * + * @see UPnPStateVariable + */ + String[] getOutputArgumentNames(); + + /** + * Finds the state variable associated with an argument name. + * + * Helps to resolve the association of state variables with argument names + * in UPnP actions. + * + * @param argumentName The name of the UPnP action argument. + * @return State variable associated with the named argument or {@code null} + * if there is no such argument. + * + * @throws IllegalStateException if the UPnP action has been removed from + * the network. + * + * @see UPnPStateVariable + */ + UPnPStateVariable getStateVariable(String argumentName); + + /** + * Invokes the action. + * + * The input and output arguments are both passed as {@code Dictionary} + * objects. Each entry in the {@code Dictionary} object has a {@code String} + * object as key representing the argument name and the value is the + * argument itself. The class of an argument value must be assignable from + * the class of the associated UPnP state variable. + * + * The input argument {@code Dictionary} object must contain exactly those + * arguments listed by {@code getInputArguments} method. The output argument + * {@code Dictionary} object will contain exactly those arguments listed by + * {@code getOutputArguments} method. + * + * @param args A {@code Dictionary} of arguments. Must contain the correct + * set and type of arguments for this action. May be {@code null} if + * no input arguments exist. + * + * @return A {@code Dictionary} with the output arguments. {@code null} if + * the action has no output arguments. + * + * @throws UPnPException A UPnP error has occurred. + * @throws IllegalStateException if the UPnP action has been removed from + * the network. + * @throws Exception The execution fails for some reason. + * + * @see UPnPStateVariable + */ + Dictionary invoke(Dictionary args) throws Exception; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPDevice.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPDevice.java new file mode 100644 index 000000000..a09c1c2f3 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPDevice.java @@ -0,0 +1,291 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.upnp; + +import java.util.Dictionary; + +/** + * Represents a UPnP device. + * + * For each UPnP root and embedded device, an object is registered with the + * framework under the {@code UPnPDevice} interface. + * <p> + * The relationship between a root device and its embedded devices can be + * deduced using the {@code UPnPDevice.CHILDREN_UDN} and + * {@code UPnPDevice.PARENT_UDN} service registration properties. + * <p> + * The values of the UPnP property names are defined by the UPnP Forum. + * <p> + * All values of the UPnP properties are obtained from the device using the + * device's default locale. + * <p> + * If an application wants to query for a set of localized property values, it + * has to use the method {@code UPnPDevice.getDescriptions(String locale)}. + * + * @author $Id$ + */ +public interface UPnPDevice { + /* + * Constants for the UPnP device match scale. + */ + /** + * Constant for the UPnP device match scale, indicating a generic match for + * the device. Value is 1. + */ + int MATCH_GENERIC = 1; + /** + * Constant for the UPnP device match scale, indicating a match with the + * device type. Value is 3. + */ + int MATCH_TYPE = 3; + /** + * Constant for the UPnP device match scale, indicating a match with the + * device model. Value is 7. + */ + int MATCH_MANUFACTURER_MODEL = 7; + /** + * Constant for the UPnP device match scale, indicating a match with the + * device revision. Value is 15. + */ + int MATCH_MANUFACTURER_MODEL_REVISION = 15; + /** + * Constant for the UPnP device match scale, indicating a match with the + * device revision and the serial number. Value is 31. + */ + int MATCH_MANUFACTURER_MODEL_REVISION_SERIAL = 31; + /** + * Constant for the value of the service property {@code DEVICE_CATEGORY} + * used for all UPnP devices. Value is "UPnP". + * + * @see "org.osgi.service.device.Constants.DEVICE_CATEGORY" + */ + String DEVICE_CATEGORY = "UPnP"; + /** + * The {@code UPnP.export} service property is a hint that marks a device to + * be picked up and exported by the UPnP Service. Imported devices do not + * have this property set. The registered property requires no value. + * <p> + * The UPNP_EXPORT string is "UPnP.export". + */ + String UPNP_EXPORT = "UPnP.export"; + /** + * Property key for the Unique Device Name (UDN) property. It is the unique + * identifier of an instance of a {@code UPnPDevice}. The value of the + * property is a {@code String} object of the Device UDN. Value of the key + * is "UPnP.device.UDN". This property must be set. + */ + String UDN = "UPnP.device.UDN"; + /** + * Property key for the Unique Device ID property. This property is an alias + * to {@code UPnPDevice.UDN}. It is merely provided for reasons of symmetry + * with the {@code UPnPService.ID} property. The value of the property is a + * {@code String} object of the Device UDN. The value of the key is + * "UPnP.device.UDN". + */ + String ID = UDN; + /** + * Property key for the UPnP Device Type property. Some standard property + * values are defined by the Universal Plug and Play Forum. The type string + * also includes a version number as defined in the UPnP specification. This + * property must be set. + * <p> + * For standard devices defined by a UPnP Forum working committee, this must + * consist of the following components in the given order separated by + * colons: + * <ul> + * <li>{@code urn}</li> + * <li>schemas-upnp-org</li> + * <li>{@code device}</li> + * <li>a device type suffix</li> + * <li>an integer device version</li> + * </ul> + * For non-standard devices specified by UPnP vendors following components + * must be specified in the given order separated by colons: + * <ul> + * <li>{@code urn}</li> + * <li>an ICANN domain name owned by the vendor</li> + * <li>{@code device}</li> + * <li>a device type suffix</li> + * <li>an integer device version</li> + * </ul> + * <p> + * To allow for backward compatibility the UPnP driver must automatically + * generate additional Device Type property entries for smaller versions + * than the current one. If for example a device announces its type as + * version 3, then properties for versions 2 and 1 must be automatically + * generated. + * <p> + * In the case of exporting a UPnPDevice, the highest available version must + * be announced on the network. + * <p> + * Syntax Example: {@code urn:schemas-upnp-org:device:deviceType:v} + * <p> + * The value is "UPnP.device.type". + */ + String TYPE = "UPnP.device.type"; + /** + * Mandatory property key for the device manufacturer's property. The + * property value holds a String representation of the device manufacturer's + * name. Value is "UPnP.device.manufacturer". + */ + String MANUFACTURER = "UPnP.device.manufacturer"; + /** + * Mandatory property key for the device model name. The property value + * holds a {@code String} object giving more information about the device + * model. Value is "UPnP.device.modelName". + */ + String MODEL_NAME = "UPnP.device.modelName"; + /** + * Mandatory property key for a short user friendly version of the device + * name. The property value holds a {@code String} object with the user + * friendly name of the device. Value is "UPnP.device.friendlyName". + */ + String FRIENDLY_NAME = "UPnP.device.friendlyName"; + /** + * Optional property key for a URL to the device manufacturers Web site. The + * value of the property is a {@code String} object representing the URL. + * Value is "UPnP.device.manufacturerURL". + */ + String MANUFACTURER_URL = "UPnP.device.manufacturerURL"; + /** + * Optional (but recommended) property key for a {@code String} object with + * a long description of the device for the end user. The value is + * "UPnP.device.modelDescription". + */ + String MODEL_DESCRIPTION = "UPnP.device.modelDescription"; + /** + * Optional (but recommended) property key for a {@code String} class typed + * property holding the model number of the device. Value is + * "UPnP.device.modelNumber". + */ + String MODEL_NUMBER = "UPnP.device.modelNumber"; + /** + * Optional property key for a {@code String} typed property holding a + * string representing the URL to the Web site for this model. Value is + * "UPnP.device.modelURL". + */ + String MODEL_URL = "UPnP.device.modelURL"; + /** + * Optional (but recommended) property key for a {@code String} typed + * property holding the serial number of the device. Value is + * "UPnP.device.serialNumber". + */ + String SERIAL_NUMBER = "UPnP.device.serialNumber"; + /** + * Optional property key for a {@code String} typed property holding the + * Universal Product Code (UPC) of the device. Value is "UPnP.device.UPC". + */ + String UPC = "UPnP.device.UPC"; + /** + * Optional (but recommended) property key for a {@code String} typed + * property holding a string representing the URL to a device representation + * Web page. Value is "UPnP.presentationURL". + */ + String PRESENTATION_URL = "UPnP.presentationURL"; + /** + * The property key that must be set for all embedded devices. It contains + * the UDN of the parent device. The property is not set for root devices. + * The value is "UPnP.device.parentUDN". + */ + String PARENT_UDN = "UPnP.device.parentUDN"; + /** + * The property key that must be set for all devices containing other + * embedded devices. + * <p> + * The value is an array of UDNs for each of the device's children ( + * {@code String[]}). The array contains UDNs for the immediate descendants + * only. + * </p> + * <p> + * If an embedded device in turn contains embedded devices, the latter are + * not included in the array. + * </p> + * The UPnP Specification does not encourage more than two levels of + * nesting. + * <p> + * The property is not set if the device does not contain embedded devices. + * <p> + * The property is of type {@code String[]}. Value is + * "UPnP.device.childrenUDN" + */ + String CHILDREN_UDN = "UPnP.device.childrenUDN"; + + /** + * Locates a specific service by its service id. + * + * @param serviceId The service id + * @return The requested service or null if not found. + * + * @throws IllegalStateException if the UPnP device has been removed from + * the network. + */ + UPnPService getService(String serviceId); + + /** + * Lists all services provided by this device. + * + * @return Array of services or {@code null} if no services are available. + * + * @throws IllegalStateException if the UPnP device has been removed from + * the network. + */ + UPnPService[] getServices(); + + /** + * Lists all icons for this device in a given locale. + * + * The UPnP specification allows a device to present different icons based + * on the client's locale. + * + * @param locale A language tag as defined by RFC 1766 and maintained by ISO + * 639. Examples include "{@code de}", "{@code en}" or " + * {@code en-US}". The default locale of the device is specified by + * passing a {@code null} argument. + * + * @return Array of icons or null if no icons are available. + * + * @throws IllegalStateException if the UPnP device has been removed from + * the network. + */ + UPnPIcon[] getIcons(String locale); + + /** + * Get a set of localized UPnP properties. + * + * The UPnP specification allows a device to present different device + * properties based on the client's locale. The properties used to register + * the UPnPDevice service in the OSGi registry are based on the device's + * default locale. To obtain a localized set of the properties, an + * application can use this method. + * <p> + * Not all properties might be available in all locales. This method does + * <b>not </b> substitute missing properties with their default locale + * versions. + * <p> + * This method must continue to return the properties after the UPnP device + * has been removed from the network. + * + * @param locale A language tag as defined by RFC 1766 and maintained by ISO + * 639. Examples include "{@code de}", "{@code en}" or " + * {@code en-US}". The default locale of the device is specified by + * passing a {@code null} argument. + * @return Dictionary mapping property name Strings to property value + * Strings + * + */ + Dictionary getDescriptions(String locale); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPEventListener.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPEventListener.java new file mode 100644 index 000000000..0daf43c61 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPEventListener.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.upnp; + +import java.util.Dictionary; + +/** + * UPnP Events are mapped and delivered to applications according to the OSGi + * whiteboard model. An application that wishes to be notified of events + * generated by a particular UPnP Device registers a service extending this + * interface. + * <p> + * The notification call from the UPnP Service to any {@code UPnPEventListener} + * object must be done asynchronous with respect to the originator (in a + * separate thread). + * <p> + * Upon registration of the UPnP Event Listener service with the Framework, the + * service is notified for each variable which it listens for with an initial + * event containing the current value of the variable. Subsequent notifications + * only happen on changes of the value of the variable. + * <p> + * A UPnP Event Listener service filter the events it receives. This event set + * is limited using a standard framework filter expression which is specified + * when the listener service is registered. + * <p> + * The filter is specified in a property named "upnp.filter" and has as a value + * an object of type {@code org.osgi.framework.Filter}. + * <p> + * When the Filter is evaluated, the folowing keywords are recognized as defined + * as literal constants in the {@code UPnPDevice} class. + * <p> + * The valid subset of properties for the registration of UPnP Event Listener + * services are: + * <ul> + * <li>{@code UPnPDevice.TYPE}-- Which type of device to listen for events.</li> + * <li>{@code UPnPDevice.ID}-- The ID of a specific device to listen for events. + * </li> + * <li>{@code UPnPService.TYPE}-- The type of a specific service to listen for + * events.</li> + * <li>{@code UPnPService.ID}-- The ID of a specific service to listen for + * events.</li> + * </ul> + * + * @author $Id$ + */ +public interface UPnPEventListener { + /** + * Key for a service property having a value that is an object of type + * {@code org.osgi.framework.Filter} and that is used to limit received + * events. + */ + static final String UPNP_FILTER = "upnp.filter"; + + /** + * Callback method that is invoked for received events. + * + * The events are collected in a {@code Dictionary} object. Each entry has a + * {@code String} key representing the event name (= state variable name) + * and the new value of the state variable. The class of the value object + * must match the class specified by the UPnP State Variable associated with + * the event. This method must be called asynchronously + * + * @param deviceId ID of the device sending the events + * @param serviceId ID of the service sending the events + * @param events {@code Dictionary} object containing the new values for the + * state variables that have changed. + * + * + */ + void notifyUPnPEvent(String deviceId, String serviceId, Dictionary events); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPException.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPException.java new file mode 100644 index 000000000..ffd3b84b0 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPException.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) OSGi Alliance (2005, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.upnp; + +/** + * There are several defined error situations describing UPnP problems while a + * control point invokes actions to UPnPDevices. + * + * @since 1.1 + * @author $Id$ + */ +public class UPnPException extends Exception { + + static final long serialVersionUID = -262013318122195146L; + + /** + * No Action found by that name at this service. + */ + public final static int INVALID_ACTION = 401; + + /** + * Not enough arguments, too many arguments with a specific name, or one of + * more of the arguments are of the wrong type. + */ + public final static int INVALID_ARGS = 402; + + /** + * The different end-points are no longer in synchronization. + */ + public final static int INVALID_SEQUENCE_NUMBER = 403; + + /** + * Refers to a non existing variable. + */ + public final static int INVALID_VARIABLE = 404; + + /** + * The invoked action failed during execution. + */ + public final static int DEVICE_INTERNAL_ERROR = 501; + + /** + * Key for an error information that is an int type variable and that is + * used to identify occurred errors. + */ + private final int errorCode; + + /** + * This constructor creates a {@code UPnPException} on the specified error + * code and error description. + * + * @param errorCode error code which defined by UPnP Device Architecture + * V1.0. + * @param errorDescription error description which explain the type of + * problem. + */ + public UPnPException(int errorCode, String errorDescription) { + super(errorDescription); + this.errorCode = errorCode; + } + + /** + * This constructor creates a {@code UPnPException} on the specified error + * code, error description and error cause. + * + * @param errorCode error code which defined by UPnP Device Architecture + * V1.0. + * @param errorDescription error description which explain the type of the + * problem. + * @param errorCause cause of that {@code UPnPException}. + * + * @since 1.2 + */ + public UPnPException(int errorCode, String errorDescription, Throwable errorCause) { + super(errorDescription, errorCause); + this.errorCode = errorCode; + } + + /** + * Returns the UPnP Error Code occurred by UPnPDevices during invocation. + * + * @return The UPnPErrorCode defined by a UPnP Forum working committee or + * specified by a UPnP vendor. + * + * @since 1.2 + */ + public int getUPnPErrorCode() { + return errorCode; + } + + /** + * Returns the UPnPError Code occurred by UPnPDevices during invocation. + * + * @return The UPnPErrorCode defined by a UPnP Forum working committee or + * specified by a UPnP vendor. + * @deprecated As of version 1.2, replaced by {@link #getUPnPErrorCode()} + */ + public int getUPnPError_Code() { + return getUPnPErrorCode(); + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPIcon.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPIcon.java new file mode 100644 index 000000000..dd5af435f --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPIcon.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.upnp; + +import java.io.IOException; +import java.io.InputStream; + +/** + * A UPnP icon representation. + * + * Each UPnP device can contain zero or more icons. + * + * @author $Id$ + */ +public interface UPnPIcon { + /** + * Returns the MIME type of the icon. + * + * This method returns the format in which the icon graphics, read from the + * {@code InputStream} object obtained by the {@code getInputStream()} + * method, is encoded. + * <p> + * The format of the returned string is in accordance to RFC2046. A list of + * valid MIME types is maintained by the <a + * href="http://www.iana.org/assignments/media-types/">IANA</a>. + * <p> + * Typical values returned include: "image/jpeg" or "image/gif" + * + * <p> + * This method must continue to return the icon MIME type after the UPnP + * device has been removed from the network. + * + * @return The MIME type of the encoded icon. + */ + String getMimeType(); + + /** + * Returns the width of the icon in pixels. + * + * If the actual width of the icon is unknown, -1 is returned. + * + * <p> + * This method must continue to return the icon width after the UPnP device + * has been removed from the network. + * + * @return The width in pixels, or -1 if unknown. + */ + int getWidth(); + + /** + * Returns the height of the icon in pixels. + * + * If the actual height of the icon is unknown, -1 is returned. + * + * <p> + * This method must continue to return the icon height after the UPnP device + * has been removed from the network. + * + * @return The height in pixels, or -1 if unknown. + */ + int getHeight(); + + /** + * Returns the size of the icon in bytes. + * + * This method returns the number of bytes of the icon available to read + * from the {@code InputStream} object obtained by the + * {@code getInputStream()} method. If the actual size can not be + * determined, -1 is returned. + * + * @return The icon size in bytes, or -1 if the size is unknown. + * + * @throws IllegalStateException if the UPnP device has been removed from + * the network. + */ + int getSize(); + + /** + * Returns the color depth of the icon in bits. + * + * <p> + * This method must continue to return the icon depth after the UPnP device + * has been removed from the network. + * + * @return The color depth in bits. If the actual color depth of the icon is + * unknown, -1 is returned. + */ + int getDepth(); + + /** + * Returns an {@code InputStream} object for the icon data. + * + * The {@code InputStream} object provides a way for a client to read the + * actual icon graphics data. The number of bytes available from this + * {@code InputStream} object can be determined via the {@code getSize()} + * method. The format of the data encoded can be determined by the MIME type + * available via the {@code getMimeType()} method. + * + * @return An InputStream to read the icon graphics data from. + * + * @throws IOException If the {@code InputStream} cannot be returned. + * @throws IllegalStateException if the UPnP device has been removed from + * the network. + * + * @see UPnPIcon#getMimeType() + */ + InputStream getInputStream() throws IOException; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPLocalStateVariable.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPLocalStateVariable.java new file mode 100644 index 000000000..351a0315b --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPLocalStateVariable.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) OSGi Alliance (2005, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * To keep the current values getting from subscribed UPnPDevices. + * + * The actual values of the UPnPStateVaraible are passed as Java object type. + * + * @since 1.1 + **/ + +package org.osgi.service.upnp; + +/** + * A local UPnP state variable which allows the value of the state variable to + * be queried. + * + * @since 1.1 + * + * @author $Id$ + */ +public interface UPnPLocalStateVariable extends UPnPStateVariable { + /** + * This method will keep the current values of UPnPStateVariables of a + * UPnPDevice whenever UPnPStateVariable's value is changed , this method + * must be called. + * + * @return {@code Object} current value of UPnPStateVariable. if the current + * value is initialized with the default value defined UPnP service + * description. + * + * @throws IllegalStateException if the UPnP state variable has been + * removed. + */ + public Object getCurrentValue(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPService.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPService.java new file mode 100644 index 000000000..08eea1f04 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPService.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.upnp; + +/** + * A representation of a UPnP Service. + * + * Each UPnP device contains zero or more services. The UPnP description for a + * service defines actions, their arguments, and event characteristics. + * + * @author $Id$ + */ +public interface UPnPService { + /** + * Property key for the optional service type uri. + * + * The service type property is used when registering UPnP Device services + * and UPnP Event Listener services. The property contains a {@code String} + * array ({@code String[]}) of service types. A UPnP Device service can thus + * announce what types of services it contains. A UPnP Event Listener + * service can announce for what type of UPnP services it wants + * notifications. The service version is encoded in the type string as + * specified in the UPnP specification. A {@code null} value is a wildcard, + * matching <b>all </b> service types. Value is "UPnP.service.type". + * + * @see UPnPService#getType() + */ + String TYPE = "UPnP.service.type"; + /** + * Property key for the optional service id. + * + * The service id property is used when registering UPnP Device services or + * UPnP Event Listener services. The value of the property contains a + * {@code String} array ({@code String[]}) of service ids. A UPnP Device + * service can thus announce what service ids it contains. A UPnP Event + * Listener service can announce for what UPnP service ids it wants + * notifications. A service id does <b>not </b> have to be universally + * unique. It must be unique only within a device. A {@code null} value is a + * wildcard, matching <b>all </b> services. The value is "UPnP.service.id". + */ + String ID = "UPnP.service.id"; + + /** + * Returns the {@code serviceId} field in the UPnP service description. + * + * + * <p> + * For standard services defined by a UPnP Forum working committee, the + * serviceId must contain the following components in the indicated order: + * <ul> + * <li>{@code urn:upnp-org:serviceId:}</li> + * <li>service ID suffix</li> + * </ul> + * Example: {@code urn:upnp-org:serviceId:serviceID}. + * + * <p> + * Note that {@code upnp-org} is used instead of {@code schemas-upnp-org} in + * this example because an XML schema is not defined for each serviceId. + * </p> + * + * <p> + * For non-standard services specified by UPnP vendors, the serviceId must + * contain the following components in the indicated order: + * <ul> + * <li>{@code urn:}</li> + * <li>ICANN domain name owned by the vendor</li> + * <li>{@code :serviceId:}</li> + * <li>service ID suffix</li> + * </ul> + * Example: {@code urn:domain-name:serviceId:serviceID}. + * + * <p> + * This method must continue to return the service id after the UPnP service + * has been removed from the network. + * + * @return The service ID suffix defined by a UPnP Forum working committee + * or specified by a UPnP vendor. Must be <= 64 characters. + * Single URI. + */ + String getId(); + + /** + * Returns the {@code serviceType} field in the UPnP service description. + * + * <p> + * For standard services defined by a UPnP Forum working committee, the + * serviceType must contain the following components in the indicated order: + * <ul> + * <li>{@code urn:schemas-upnp-org:service:}</li> + * <li>service type suffix:</li> + * <li>integer service version</li> + * </ul> + * Example: {@code urn:schemas-upnp-org:service:serviceType:v}. + * + * <p> + * For non-standard services specified by UPnP vendors, the + * {@code serviceType} must contain the following components in the + * indicated order: + * <ul> + * <li>{@code urn:}</li> + * <li>ICANN domain name owned by the vendor</li> + * <li>{@code :service:}</li> + * <li>service type suffix:</li> + * <li>integer service version</li> + * </ul> + * Example: {@code urn:domain-name:service:serviceType:v}. + * + * <p> + * This method must continue to return the service type after the UPnP + * service has been removed from the network. + * + * @return The service type suffix defined by a UPnP Forum working committee + * or specified by a UPnP vendor. Must be <= 64 characters, not + * including the version suffix and separating colon. Single URI. + */ + String getType(); + + /** + * Returns the version suffix encoded in the {@code serviceType} field in + * the UPnP service description. + * + * <p> + * This method must continue to return the service version after the UPnP + * service has been removed from the network. + * + * @return The integer service version defined by a UPnP Forum working + * committee or specified by a UPnP vendor. + */ + String getVersion(); + + /** + * Locates a specific action by name. + * + * Looks up an action by its name. + * + * @param name Name of action. Must not contain hyphen or hash characters. + * Should be < 32 characters. + * + * @return The requested action or {@code null} if no action is found. + * + * @throws IllegalStateException if the UPnP service has been removed from + * the network. + */ + UPnPAction getAction(String name); + + /** + * Lists all actions provided by this service. + * + * @return Array of actions ({@code UPnPAction[]} )or {@code null} if no + * actions are defined for this service. + * + * @throws IllegalStateException if the UPnP service has been removed from + * the network. + */ + UPnPAction[] getActions(); + + /** + * Lists all {@code UPnPStateVariable} objects provided by this service. + * + * @return Array of state variables or {@code null} if none are defined for + * this service. + * + * @throws IllegalStateException if the UPnP service has been removed from + * the network. + */ + UPnPStateVariable[] getStateVariables(); + + /** + * Gets a {@code UPnPStateVariable} objects provided by this service by name + * + * @param name Name of the State Variable + * + * @return State variable or {@code null} if no such state variable exists + * for this service. + * + * @throws IllegalStateException if the UPnP service has been removed from + * the network. + */ + UPnPStateVariable getStateVariable(String name); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPStateVariable.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPStateVariable.java new file mode 100644 index 000000000..1ebafb56d --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/UPnPStateVariable.java @@ -0,0 +1,378 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.upnp; + +/** + * The meta-information of a UPnP state variable as declared in the device's + * service state table (SST). + * <p> + * Method calls to interact with a device (e.g. {@code UPnPAction.invoke(...);}) + * use this class to encapsulate meta information about the input and output + * arguments. + * <p> + * The actual values of the arguments are passed as Java objects. The mapping of + * types from UPnP data types to Java data types is described with the field + * definitions. + * + * @author $Id$ + */ +public interface UPnPStateVariable { + /** + * Unsigned 1 {@code Byte} int. + * <p> + * Mapped to an {@code Integer} object. + */ + static final String TYPE_UI1 = "ui1"; + /** + * Unsigned 2 Byte int. + * <p> + * Mapped to {@code Integer} object. + */ + static final String TYPE_UI2 = "ui2"; + /** + * Unsigned 4 Byte int. + * <p> + * Mapped to {@code Long} object. + */ + static final String TYPE_UI4 = "ui4"; + /** + * 1 Byte int. + * <p> + * Mapped to {@code Integer} object. + */ + static final String TYPE_I1 = "i1"; + /** + * 2 Byte int. + * <p> + * Mapped to {@code Integer} object. + */ + static final String TYPE_I2 = "i2"; + /** + * 4 Byte int. + * <p> + * Must be between -2147483648 and 2147483647 + * <p> + * Mapped to {@code Integer} object. + */ + static final String TYPE_I4 = "i4"; + /** + * Integer number. + * <p> + * Mapped to {@code Integer} object. + */ + static final String TYPE_INT = "int"; + /** + * 4 Byte float. + * <p> + * Same format as float. Must be between 3.40282347E+38 to 1.17549435E-38. + * <p> + * Mapped to {@code Float} object. + */ + static final String TYPE_R4 = "r4"; + /** + * 8 Byte float. + * <p> + * Same format as float. Must be between -1.79769313486232E308 and + * -4.94065645841247E-324 for negative values, and between + * 4.94065645841247E-324 and 1.79769313486232E308 for positive values, i.e., + * IEEE 64-bit (8-Byte) double. + * <p> + * Mapped to {@code Double} object. + */ + static final String TYPE_R8 = "r8"; + /** + * Same as r8. + * <p> + * Mapped to {@code Double} object. + */ + static final String TYPE_NUMBER = "number"; + /** + * Same as r8 but no more than 14 digits to the left of the decimal point + * and no more than 4 to the right. + * <p> + * Mapped to {@code Double} object. + */ + static final String TYPE_FIXED_14_4 = "fixed.14.4"; + /** + * Floating-point number. + * <p> + * Mantissa (left of the decimal) and/or exponent may have a leading sign. + * Mantissa and/or exponent may have leading zeros. Decimal character in + * mantissa is a period, i.e., whole digits in mantissa separated from + * fractional digits by period. Mantissa separated from exponent by E. (No + * currency symbol.) (No grouping of digits in the mantissa, e.g., no + * commas.) + * <p> + * Mapped to {@code Float} object. + */ + static final String TYPE_FLOAT = "float"; + /** + * Unicode string. + * <p> + * One character long. + * <p> + * Mapped to {@code Character} object. + */ + static final String TYPE_CHAR = "char"; + /** + * Unicode string. + * <p> + * No limit on length. + * <p> + * Mapped to {@code String} object. + */ + static final String TYPE_STRING = "string"; + /** + * A calendar date. + * <p> + * Date in a subset of ISO 8601 format without time data. + * <p> + * See <a + * href="http://www.w3.org/TR/xmlschema-2/#date">http://www.w3.org/TR/ + * xmlschema-2/#date </a>. + * <p> + * Mapped to {@code java.util.Date} object. Always 00:00 hours. + */ + static final String TYPE_DATE = "date"; + /** + * A specific instant of time. + * <p> + * Date in ISO 8601 format with optional time but no time zone. + * <p> + * See <a + * href="http://www.w3.org/TR/xmlschema-2/#dateTime">http://www.w3.org + * /TR/xmlschema-2/#dateTime </a>. + * <p> + * Mapped to {@code java.util.Date} object using default time zone. + */ + static final String TYPE_DATETIME = "dateTime"; + /** + * A specific instant of time. + * <p> + * Date in ISO 8601 format with optional time and optional time zone. + * <p> + * See <a + * href="http://www.w3.org/TR/xmlschema-2/#dateTime">http://www.w3.org + * /TR/xmlschema-2/#dateTime </a>. + * <p> + * Mapped to {@code java.util.Date} object adjusted to default time zone. + */ + static final String TYPE_DATETIME_TZ = "dateTime.tz"; + /** + * An instant of time that recurs every day. + * <p> + * Time in a subset of ISO 8601 format with no date and no time zone. + * <p> + * See <a + * href="http://www.w3.org/TR/xmlschema-2/#dateTime">http://www.w3.org + * /TR/xmlschema-2/#time </a>. + * <p> + * Mapped to {@code Long}. Converted to milliseconds since midnight. + */ + static final String TYPE_TIME = "time"; + /** + * An instant of time that recurs every day. + * <p> + * Time in a subset of ISO 8601 format with optional time zone but no date. + * <p> + * See <a + * href="http://www.w3.org/TR/xmlschema-2/#dateTime">http://www.w3.org + * /TR/xmlschema-2/#time </a>. + * <p> + * Mapped to {@code Long} object. Converted to milliseconds since midnight + * and adjusted to default time zone, wrapping at 0 and 24*60*60*1000. + */ + static final String TYPE_TIME_TZ = "time.tz"; + /** + * True or false. + * <p> + * Mapped to {@code Boolean} object. + */ + static final String TYPE_BOOLEAN = "boolean"; + /** + * MIME-style Base64 encoded binary BLOB. + * <p> + * Takes 3 Bytes, splits them into 4 parts, and maps each 6 bit piece to an + * octet. (3 octets are encoded as 4.) No limit on size. + * <p> + * Mapped to {@code byte[]} object. The Java byte array will hold the + * decoded content of the BLOB. + */ + static final String TYPE_BIN_BASE64 = "bin.base64"; + /** + * Hexadecimal digits representing octets. + * <p> + * Treats each nibble as a hex digit and encodes as a separate Byte. (1 + * octet is encoded as 2.) No limit on size. + * <p> + * Mapped to {@code byte[]} object. The Java byte array will hold the + * decoded content of the BLOB. + */ + static final String TYPE_BIN_HEX = "bin.hex"; + /** + * Universal Resource Identifier. + * <p> + * Mapped to {@code String} object. + */ + static final String TYPE_URI = "uri"; + /** + * Universally Unique ID. + * <p> + * Hexadecimal digits representing octets. Optional embedded hyphens are + * ignored. + * <p> + * Mapped to {@code String} object. + */ + static final String TYPE_UUID = "uuid"; + + /** + * Returns the variable name. + * + * <ul> + * <li>All standard variables defined by a UPnP Forum working committee must + * not begin with {@code X_} nor {@code A_}.</li> + * <li>All non-standard variables specified by a UPnP vendor and added to a + * standard service must begin with {@code X_}.</li> + * </ul> + * + * <p> + * This method must continue to return the state variable name after the + * UPnP state variable has been removed from the network. + * + * @return Name of state variable. Must not contain a hyphen character nor a + * hash character. Should be < 32 characters. + */ + String getName(); + + /** + * Returns the Java class associated with the UPnP data type of this state + * variable. + * <P> + * Mapping between the UPnP data types and Java classes is performed + * according to the schema mentioned above. + * + * <pre> + * + * Integer ui1, ui2, i1, i2, i4, int + * Long ui4, time, time.tz + * Float r4, float + * Double r8, number, fixed.14.4 + * Character char + * String string, uri, uuid + * Date date, dateTime, dateTime.tz + * Boolean boolean + * byte[] bin.base64, bin.hex + * + * </pre> + * + * <p> + * This method must continue to return the state variable java type after + * the UPnP state variable has been removed from the network. + * + * @return A class object corresponding to the Java type of this argument. + */ + Class getJavaDataType(); + + /** + * Returns the UPnP type of this state variable. Valid types are defined as + * constants. + * + * <p> + * This method must continue to return the state variable UPnP data type + * after the UPnP state variable has been removed from the network. + * + * @return The UPnP data type of this state variable, as defined in above + * constants. + */ + String getUPnPDataType(); + + /** + * Returns the default value, if defined. + * + * <p> + * This method must continue to return the state variable default value + * after the UPnP state variable has been removed from the network. + * + * @return The default value or {@code null} if not defined. The type of the + * returned object can be determined by {@code getJavaDataType}. + */ + Object getDefaultValue(); + + /** + * Returns the allowed values, if defined. Allowed values can be defined + * only for String types. + * + * <p> + * This method must continue to return the state variable allowed values + * after the UPnP state variable has been removed from the network. + * + * @return The allowed values or {@code null} if not defined. Should be less + * than 32 characters. + */ + String[] getAllowedValues(); + + /** + * Returns the minimum value, if defined. Minimum values can only be defined + * for numeric types. + * + * <p> + * This method must continue to return the state variable minimum value + * after the UPnP state variable has been removed from the network. + * + * @return The minimum value or {@code null} if not defined. + */ + Number getMinimum(); + + /** + * Returns the maximum value, if defined. Maximum values can only be defined + * for numeric types. + * + * <p> + * This method must continue to return the state variable maximum value + * after the UPnP state variable has been removed from the network. + * + * @return The maximum value or {@code null} if not defined. + */ + Number getMaximum(); + + /** + * Returns the size of an increment operation, if defined. Step sizes can be + * defined only for numeric types. + * + * <p> + * This method must continue to return the step size after the UPnP state + * variable has been removed from the network. + * + * @return The increment size or null if not defined. + */ + Number getStep(); + + /** + * Tells if this StateVariable can be used as an event source. + * + * If the StateVariable is eventable, an event listener service can be + * registered to be notified when changes to the variable appear. + * + * <p> + * This method must continue to return the correct value after the UPnP + * state variable has been removed from the network. + * + * @return {@code true} if the {@code StateVariable} generates events, + * {@code false} otherwise. + */ + boolean sendsEvents(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/package-info.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/package-info.java new file mode 100644 index 000000000..141651627 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/package-info.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * UPnP Package Version 1.2. + * + * <p> + * Bundles wishing to use this package must list the package in the + * Import-Package header of the bundle's manifest. This package has two types of + * users: the consumers that use the API in this package and the providers that + * implement the API in this package. + * + * <p> + * Example import for consumers using the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.upnp; version="[1.2,2.0)"} + * <p> + * Example import for providers implementing the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.upnp; version="[1.2,1.3)"} + * + * @version 1.2 + * @author $Id$ + */ + +package org.osgi.service.upnp; + diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/packageinfo b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/packageinfo new file mode 100644 index 000000000..ef7df68cb --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/upnp/packageinfo @@ -0,0 +1 @@ +version 1.2 diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/Authorization.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/Authorization.java new file mode 100644 index 000000000..4786641d1 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/Authorization.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.useradmin; + +/** + * The {@code Authorization} interface encapsulates an authorization context on + * which bundles can base authorization decisions, where appropriate. + * <p> + * Bundles associate the privilege to access restricted resources or operations + * with roles. Before granting access to a restricted resource or operation, a + * bundle will check if the {@code Authorization} object passed to it possess + * the required role, by calling its {@code hasRole} method. + * <p> + * Authorization contexts are instantiated by calling the + * {@link UserAdmin#getAuthorization(User)} method. + * + * <p> + * <i>Trusting Authorization objects </i> + * <p> + * There are no restrictions regarding the creation of {@code Authorization} + * objects. Hence, a service must only accept {@code Authorization} objects from + * bundles that has been authorized to use the service using code based (or Java + * 2) permissions. + * + * <p> + * In some cases it is useful to use {@code ServicePermission} to do the code + * based access control. A service basing user access control on + * {@code Authorization} objects passed to it, will then require that a calling + * bundle has the {@code ServicePermission} to get the service in question. This + * is the most convenient way. The OSGi environment will do the code based + * permission check when the calling bundle attempts to get the service from the + * service registry. + * <p> + * Example: A servlet using a service on a user's behalf. The bundle with the + * servlet must be given the {@code ServicePermission} to get the Http Service. + * <p> + * However, in some cases the code based permission checks need to be more + * fine-grained. A service might allow all bundles to get it, but require + * certain code based permissions for some of its methods. + * <p> + * Example: A servlet using a service on a user's behalf, where some service + * functionality is open to anyone, and some is restricted by code based + * permissions. When a restricted method is called (e.g., one handing over an + * {@code Authorization} object), the service explicitly checks that the calling + * bundle has permission to make the call. + * + * @noimplement + * @author $Id$ + */ +public interface Authorization { + /** + * Gets the name of the {@link User} that this {@code Authorization} context + * was created for. + * + * @return The name of the {@link User} object that this + * {@code Authorization} context was created for, or {@code null} if + * no user was specified when this {@code Authorization} context was + * created. + */ + public String getName(); + + /** + * Checks if the role with the specified name is implied by this + * {@code Authorization} context. + * <p> + * + * Bundles must define globally unique role names that are associated with + * the privilege of accessing restricted resources or operations. Operators + * will grant users access to these resources, by creating a {@link Group} + * object for each role and adding {@link User} objects to it. + * + * @param name The name of the role to check for. + * + * @return {@code true} if this {@code Authorization} context implies the + * specified role, otherwise {@code false}. + */ + public boolean hasRole(String name); + + /** + * Gets the names of all roles implied by this {@code Authorization} + * context. + * + * @return The names of all roles implied by this {@code Authorization} + * context, or {@code null} if no roles are in the context. The + * predefined role {@code user.anyone} will not be included in this + * list. + */ + public String[] getRoles(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/Group.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/Group.java new file mode 100644 index 000000000..0ffc7e843 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/Group.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.useradmin; + +/** + * A named grouping of roles ({@code Role} objects). + * <p> + * Whether or not a given {@code Authorization} context implies a {@code Group} + * object depends on the members of that {@code Group} object. + * <p> + * A {@code Group} object can have two kinds of members: <i>basic </i> and + * <i>required </i>. A {@code Group} object is implied by an + * {@code Authorization} context if all of its required members are implied and + * at least one of its basic members is implied. + * <p> + * A {@code Group} object must contain at least one basic member in order to be + * implied. In other words, a {@code Group} object without any basic member + * roles is never implied by any {@code Authorization} context. + * <p> + * A {@code User} object always implies itself. + * <p> + * No loop detection is performed when adding members to {@code Group} objects, + * which means that it is possible to create circular implications. Loop + * detection is instead done when roles are checked. The semantics is that if a + * role depends on itself (i.e., there is an implication loop), the role is not + * implied. + * <p> + * The rule that a {@code Group} object must have at least one basic member to + * be implied is motivated by the following example: + * + * <pre> + * + * group foo + * required members: marketing + * basic members: alice, bob + * + * </pre> + * + * Privileged operations that require membership in "foo" can be performed only + * by "alice" and "bob", who are in marketing. + * <p> + * If "alice" and "bob" ever transfer to a different department, anybody in + * marketing will be able to assume the "foo" role, which certainly must be + * prevented. Requiring that "foo" (or any {@code Group} object for that matter) + * must have at least one basic member accomplishes that. + * <p> + * However, this would make it impossible for a {@code Group} object to be + * implied by just its required members. An example where this implication might + * be useful is the following declaration: "Any citizen who is an adult is + * allowed to vote." An intuitive configuration of "voter" would be: + * + * <pre> + * + * group voter + * required members: citizen, adult + * basic members: + * + * </pre> + * + * However, according to the above rule, the "voter" role could never be assumed + * by anybody, since it lacks any basic members. In order to address this issue + * a predefined role named "user.anyone" can be specified, which is always + * implied. The desired implication of the "voter" group can then be achieved by + * specifying "user.anyone" as its basic member, as follows: + * + * <pre> + * + * group voter + * required members: citizen, adult + * basic members: user.anyone + * + * </pre> + * + * @noimplement + * @author $Id$ + */ +public interface Group extends User { + /** + * Adds the specified {@code Role} object as a basic member to this + * {@code Group} object. + * + * @param role The role to add as a basic member. + * + * @return {@code true} if the given role could be added as a basic member, + * and {@code false} if this {@code Group} object already contains a + * {@code Role} object whose name matches that of the specified + * role. + * + * @throws SecurityException If a security manager exists and the caller + * does not have the {@code UserAdminPermission} with name + * {@code admin}. + */ + public boolean addMember(Role role); + + /** + * Adds the specified {@code Role} object as a required member to this + * {@code Group} object. + * + * @param role The {@code Role} object to add as a required member. + * + * @return {@code true} if the given {@code Role} object could be added as a + * required member, and {@code false} if this {@code Group} object + * already contains a {@code Role} object whose name matches that of + * the specified role. + * + * @throws SecurityException If a security manager exists and the caller + * does not have the {@code UserAdminPermission} with name + * {@code admin}. + */ + public boolean addRequiredMember(Role role); + + /** + * Removes the specified {@code Role} object from this {@code Group} object. + * + * @param role The {@code Role} object to remove from this {@code Group} + * object. + * + * @return {@code true} if the {@code Role} object could be removed, + * otherwise {@code false}. + * + * @throws SecurityException If a security manager exists and the caller + * does not have the {@code UserAdminPermission} with name + * {@code admin}. + */ + public boolean removeMember(Role role); + + /** + * Gets the basic members of this {@code Group} object. + * + * @return The basic members of this {@code Group} object, or {@code null} + * if this {@code Group} object does not contain any basic members. + */ + public Role[] getMembers(); + + /** + * Gets the required members of this {@code Group} object. + * + * @return The required members of this {@code Group} object, or + * {@code null} if this {@code Group} object does not contain any + * required members. + */ + public Role[] getRequiredMembers(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/Role.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/Role.java new file mode 100644 index 000000000..c366d5a63 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/Role.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.useradmin; + +import java.util.Dictionary; + +/** + * The base interface for {@code Role} objects managed by the User Admin + * service. + * + * <p> + * This interface exposes the characteristics shared by all {@code Role} + * classes: a name, a type, and a set of properties. + * <p> + * Properties represent public information about the {@code Role} object that + * can be read by anyone. Specific {@link UserAdminPermission} objects are + * required to change a {@code Role} object's properties. + * <p> + * {@code Role} object properties are {@code Dictionary} objects. Changes to + * these objects are propagated to the User Admin service and made persistent. + * <p> + * Every User Admin service contains a set of predefined {@code Role} objects + * that are always present and cannot be removed. All predefined {@code Role} + * objects are of type {@code ROLE}. This version of the + * {@code org.osgi.service.useradmin} package defines a single predefined role + * named "user.anyone", which is inherited by any other role. Other + * predefined roles may be added in the future. Since "user.anyone" is + * a {@code Role} object that has properties associated with it that can be read + * and modified. Access to these properties and their use is application + * specific and is controlled using {@code UserAdminPermission} in the same way + * that properties for other {@code Role} objects are. + * + * @noimplement + * @author $Id$ + */ +public interface Role { + /** + * The name of the predefined role, user.anyone, that all users and groups + * belong to. + * + * @since 1.1 + */ + public static final String USER_ANYONE = "user.anyone"; + /** + * The type of a predefined role. + * + * <p> + * The value of {@code ROLE} is 0. + */ + public static final int ROLE = 0; + /** + * The type of a {@link User} role. + * + * <p> + * The value of {@code USER} is 1. + */ + public static final int USER = 1; + /** + * The type of a {@link Group} role. + * + * <p> + * The value of {@code GROUP} is 2. + */ + public static final int GROUP = 2; + + /** + * Returns the name of this role. + * + * @return The role's name. + */ + public String getName(); + + /** + * Returns the type of this role. + * + * @return The role's type. + */ + public int getType(); + + /** + * Returns a {@code Dictionary} of the (public) properties of this + * {@code Role} object. Any changes to the returned {@code Dictionary} will + * change the properties of this {@code Role} object. This will cause a + * {@code UserAdminEvent} object of type {@link UserAdminEvent#ROLE_CHANGED} + * to be broadcast to any {@code UserAdminListener} objects. + * + * <p> + * Only objects of type {@code String} may be used as property keys, and + * only objects of type {@code String} or {@code byte[]} may be used as + * property values. Any other types will cause an exception of type + * {@code IllegalArgumentException} to be raised. + * + * <p> + * In order to add, change, or remove a property in the returned + * {@code Dictionary}, a {@link UserAdminPermission} named after the + * property name (or a prefix of it) with action {@code changeProperty} is + * required. + * + * @return {@code Dictionary} containing the properties of this {@code Role} + * object. + */ + public Dictionary getProperties(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/User.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/User.java new file mode 100644 index 000000000..0520ec2dd --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/User.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.useradmin; + +import java.util.Dictionary; + +/** + * A {@code User} role managed by a User Admin service. + * + * <p> + * In this context, the term "user" is not limited to just human + * beings. Instead, it refers to any entity that may have any number of + * credentials associated with it that it may use to authenticate itself. + * <p> + * In general, {@code User} objects are associated with a specific User Admin + * service (namely the one that created them), and cannot be used with other + * User Admin services. + * <p> + * A {@code User} object may have credentials (and properties, inherited from + * the {@link Role} class) associated with it. Specific + * {@link UserAdminPermission} objects are required to read or change a + * {@code User} object's credentials. + * <p> + * Credentials are {@code Dictionary} objects and have semantics that are + * similar to the properties in the {@code Role} class. + * + * @noimplement + * @author $Id$ + */ +public interface User extends Role { + /** + * Returns a {@code Dictionary} of the credentials of this {@code User} + * object. Any changes to the returned {@code Dictionary} object will change + * the credentials of this {@code User} object. This will cause a + * {@code UserAdminEvent} object of type {@link UserAdminEvent#ROLE_CHANGED} + * to be broadcast to any {@code UserAdminListeners} objects. + * + * <p> + * Only objects of type {@code String} may be used as credential keys, and + * only objects of type {@code String} or of type {@code byte[]} may be used + * as credential values. Any other types will cause an exception of type + * {@code IllegalArgumentException} to be raised. + * + * <p> + * In order to retrieve a credential from the returned {@code Dictionary} + * object, a {@link UserAdminPermission} named after the credential name (or + * a prefix of it) with action {@code getCredential} is required. + * <p> + * In order to add or remove a credential from the returned + * {@code Dictionary} object, a {@link UserAdminPermission} named after the + * credential name (or a prefix of it) with action {@code changeCredential} + * is required. + * + * @return {@code Dictionary} object containing the credentials of this + * {@code User} object. + */ + public Dictionary getCredentials(); + + /** + * Checks to see if this {@code User} object has a credential with the + * specified {@code key} set to the specified {@code value}. + * + * <p> + * If the specified credential {@code value} is not of type {@code String} + * or {@code byte[]}, it is ignored, that is, {@code false} is returned (as + * opposed to an {@code IllegalArgumentException} being raised). + * + * @param key The credential {@code key}. + * @param value The credential {@code value}. + * + * @return {@code true} if this user has the specified credential; + * {@code false} otherwise. + * + * @throws SecurityException If a security manager exists and the caller + * does not have the {@code UserAdminPermission} named after the + * credential key (or a prefix of it) with action + * {@code getCredential}. + */ + public boolean hasCredential(String key, Object value); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/UserAdmin.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/UserAdmin.java new file mode 100644 index 000000000..60b8b60bc --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/UserAdmin.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.useradmin; + +import org.osgi.framework.InvalidSyntaxException; + +/** + * This interface is used to manage a database of named {@code Role} objects, + * which can be used for authentication and authorization purposes. + * + * <p> + * This version of the User Admin service defines two types of {@code Role} + * objects: "User" and "Group". Each type of role is represented by an + * {@code int} constant and an interface. The range of positive integers is + * reserved for new types of roles that may be added in the future. When + * defining proprietary role types, negative constant values must be used. + * + * <p> + * Every role has a name and a type. + * + * <p> + * A {@link User} object can be configured with credentials (e.g., a password) + * and properties (e.g., a street address, phone number, etc.). + * <p> + * A {@link Group} object represents an aggregation of {@link User} and + * {@link Group} objects. In other words, the members of a {@code Group} object + * are roles themselves. + * <p> + * Every User Admin service manages and maintains its own namespace of + * {@code Role} objects, in which each {@code Role} object has a unique name. + * + * @noimplement + * @author $Id$ + */ +public interface UserAdmin { + /** + * Creates a {@code Role} object with the given name and of the given type. + * + * <p> + * If a {@code Role} object was created, a {@code UserAdminEvent} object of + * type {@link UserAdminEvent#ROLE_CREATED} is broadcast to any + * {@code UserAdminListener} object. + * + * @param name The {@code name} of the {@code Role} object to create. + * @param type The type of the {@code Role} object to create. Must be either + * a {@link Role#USER} type or {@link Role#GROUP} type. + * + * @return The newly created {@code Role} object, or {@code null} if a role + * with the given name already exists. + * + * @throws IllegalArgumentException if {@code type} is invalid. + * + * @throws SecurityException If a security manager exists and the caller + * does not have the {@code UserAdminPermission} with name + * {@code admin}. + */ + public Role createRole(String name, int type); + + /** + * Removes the {@code Role} object with the given name from this User Admin + * service and all groups it is a member of. + * + * <p> + * If the {@code Role} object was removed, a {@code UserAdminEvent} object + * of type {@link UserAdminEvent#ROLE_REMOVED} is broadcast to any + * {@code UserAdminListener} object. + * + * @param name The name of the {@code Role} object to remove. + * + * @return {@code true} If a {@code Role} object with the given name is + * present in this User Admin service and could be removed, + * otherwise {@code false}. + * + * @throws SecurityException If a security manager exists and the caller + * does not have the {@code UserAdminPermission} with name + * {@code admin}. + */ + public boolean removeRole(String name); + + /** + * Gets the {@code Role} object with the given {@code name} from this User + * Admin service. + * + * @param name The name of the {@code Role} object to get. + * + * @return The requested {@code Role} object, or {@code null} if this User + * Admin service does not have a {@code Role} object with the given + * {@code name}. + */ + public Role getRole(String name); + + /** + * Gets the {@code Role} objects managed by this User Admin service that + * have properties matching the specified LDAP filter criteria. See + * {@code org.osgi.framework.Filter} for a description of the filter syntax. + * If a {@code null} filter is specified, all Role objects managed by this + * User Admin service are returned. + * + * @param filter The filter criteria to match. + * + * @return The {@code Role} objects managed by this User Admin service whose + * properties match the specified filter criteria, or all + * {@code Role} objects if a {@code null} filter is specified. If no + * roles match the filter, {@code null} will be returned. + * @throws InvalidSyntaxException If the filter is not well formed. + * + */ + public Role[] getRoles(String filter) throws InvalidSyntaxException; + + /** + * Gets the user with the given property {@code key}-{@code value} pair from + * the User Admin service database. This is a convenience method for + * retrieving a {@code User} object based on a property for which every + * {@code User} object is supposed to have a unique value (within the scope + * of this User Admin service), such as for example a X.500 distinguished + * name. + * + * @param key The property key to look for. + * @param value The property value to compare with. + * + * @return A matching user, if <em>exactly</em> one is found. If zero or + * more than one matching users are found, {@code null} is returned. + */ + public User getUser(String key, String value); + + /** + * Creates an {@code Authorization} object that encapsulates the specified + * {@code User} object and the {@code Role} objects it possesses. The + * {@code null} user is interpreted as the anonymous user. The anonymous + * user represents a user that has not been authenticated. An + * {@code Authorization} object for an anonymous user will be unnamed, and + * will only imply groups that user.anyone implies. + * + * @param user The {@code User} object to create an {@code Authorization} + * object for, or {@code null} for the anonymous user. + * + * @return the {@code Authorization} object for the specified {@code User} + * object. + */ + public Authorization getAuthorization(User user); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/UserAdminEvent.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/UserAdminEvent.java new file mode 100644 index 000000000..606618cc7 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/UserAdminEvent.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.useradmin; + +import org.osgi.framework.ServiceReference; + +/** + * {@code Role} change event. + * <p> + * {@code UserAdminEvent} objects are delivered asynchronously to any + * {@code UserAdminListener} objects when a change occurs in any of the + * {@code Role} objects managed by a User Admin service. + * + * <p> + * A type code is used to identify the event. The following event types are + * defined: {@link #ROLE_CREATED} type, {@link #ROLE_CHANGED} type, and + * {@link #ROLE_REMOVED} type. Additional event types may be defined in the + * future. + * + * @see UserAdmin + * @see UserAdminListener + * + * @author $Id$ + */ +public class UserAdminEvent { + private ServiceReference ref; + private int type; + private Role role; + /** + * A {@code Role} object has been created. + * + * <p> + * The value of {@code ROLE_CREATED} is 0x00000001. + */ + public static final int ROLE_CREATED = 0x00000001; + /** + * A {@code Role} object has been modified. + * + * <p> + * The value of {@code ROLE_CHANGED} is 0x00000002. + */ + public static final int ROLE_CHANGED = 0x00000002; + /** + * A {@code Role} object has been removed. + * + * <p> + * The value of {@code ROLE_REMOVED} is 0x00000004. + */ + public static final int ROLE_REMOVED = 0x00000004; + + /** + * Constructs a {@code UserAdminEvent} object from the given + * {@code ServiceReference} object, event type, and {@code Role} object. + * + * @param ref The {@code ServiceReference} object of the User Admin service + * that generated this event. + * @param type The event type. + * @param role The {@code Role} object on which this event occurred. + */ + public UserAdminEvent(ServiceReference ref, int type, Role role) { + this.ref = ref; + this.type = type; + this.role = role; + } + + /** + * Gets the {@code ServiceReference} object of the User Admin service that + * generated this event. + * + * @return The User Admin service's {@code ServiceReference} object. + */ + public ServiceReference getServiceReference() { + return ref; + } + + /** + * Returns the type of this event. + * + * <p> + * The type values are {@link #ROLE_CREATED} type, {@link #ROLE_CHANGED} + * type, and {@link #ROLE_REMOVED} type. + * + * @return The event type. + */ + public int getType() { + return type; + } + + /** + * Gets the {@code Role} object this event was generated for. + * + * @return The {@code Role} object this event was generated for. + */ + public Role getRole() { + return role; + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/UserAdminListener.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/UserAdminListener.java new file mode 100644 index 000000000..3d45a44b2 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/UserAdminListener.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.useradmin; + +/** + * Listener for UserAdminEvents. + * + * <p> + * {@code UserAdminListener} objects are registered with the Framework service + * registry and notified with a {@code UserAdminEvent} object when a + * {@code Role} object has been created, removed, or modified. + * <p> + * {@code UserAdminListener} objects can further inspect the received + * {@code UserAdminEvent} object to determine its type, the {@code Role} object + * it occurred on, and the User Admin service that generated it. + * + * @see UserAdmin + * @see UserAdminEvent + * + * @author $Id$ + */ +public interface UserAdminListener { + /** + * Receives notification that a {@code Role} object has been created, + * removed, or modified. + * + * @param event The {@code UserAdminEvent} object. + */ + public void roleChanged(UserAdminEvent event); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/UserAdminPermission.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/UserAdminPermission.java new file mode 100644 index 000000000..536a2ac22 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/UserAdminPermission.java @@ -0,0 +1,606 @@ +/* + * Copyright (c) OSGi Alliance (2001, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.useradmin; + +import java.io.IOException; +import java.security.BasicPermission; +import java.security.Permission; +import java.security.PermissionCollection; +import java.util.Enumeration; +import java.util.Hashtable; + +/** + * Permission to configure and access the {@link Role} objects managed by a User + * Admin service. + * + * <p> + * This class represents access to the {@code Role} objects managed by a User + * Admin service and their properties and credentials (in the case of + * {@link User} objects). + * <p> + * The permission name is the name (or name prefix) of a property or credential. + * The naming convention follows the hierarchical property naming convention. + * Also, an asterisk may appear at the end of the name, following a + * ".", or by itself, to signify a wildcard match. For example: + * "org.osgi.security.protocol.*" or "*" is valid, but + * "*protocol" or "a*b" are not valid. + * + * <p> + * The {@code UserAdminPermission} with the reserved name "admin" + * represents the permission required for creating and removing {@code Role} + * objects in the User Admin service, as well as adding and removing members in + * a {@code Group} object. This {@code UserAdminPermission} does not have any + * actions associated with it. + * + * <p> + * The actions to be granted are passed to the constructor in a string + * containing a list of one or more comma-separated keywords. The possible + * keywords are: {@code changeProperty},{@code changeCredential}, and + * {@code getCredential}. Their meaning is defined as follows: + * + * <pre> + * + * action + * changeProperty Permission to change (i.e., add and remove) + * Role object properties whose names start with + * the name argument specified in the constructor. + * changeCredential Permission to change (i.e., add and remove) + * User object credentials whose names start + * with the name argument specified in the constructor. + * getCredential Permission to retrieve and check for the + * existence of User object credentials whose names + * start with the name argument specified in the + * constructor. + * + * </pre> + * + * The action string is converted to lowercase before processing. + * + * <p> + * Following is a PermissionInfo style policy entry which grants a user + * administration bundle a number of {@code UserAdminPermission} object: + * + * <pre> + * + * (org.osgi.service.useradmin.UserAdminPermission "admin") + * (org.osgi.service.useradmin.UserAdminPermission "com.foo.*" + * "changeProperty,getCredential,changeCredential") + * (org.osgi.service.useradmin.UserAdminPermission "user.*" + * "changeProperty,changeCredential") + * + * </pre> + * + * The first permission statement grants the bundle the permission to perform + * any User Admin service operations of type "admin", that is, create and remove + * roles and configure {@code Group} objects. + * + * <p> + * The second permission statement grants the bundle the permission to change + * any properties as well as get and change any credentials whose names start + * with {@code com.foo.}. + * + * <p> + * The third permission statement grants the bundle the permission to change any + * properties and credentials whose names start with {@code user.}. This means + * that the bundle is allowed to change, but not retrieve any credentials with + * the given prefix. + * + * <p> + * The following policy entry empowers the Http Service bundle to perform user + * authentication: + * + * <pre> + * + * grant codeBase "${jars}http.jar" { + * permission org.osgi.service.useradmin.UserAdminPermission + * "user.password", "getCredential"; + * }; + * + * </pre> + * + * <p> + * The permission statement grants the Http Service bundle the permission to + * validate any password credentials (for authentication purposes), but the + * bundle is not allowed to change any properties or credentials. + * + * @ThreadSafe + * @author $Id$ + */ +public final class UserAdminPermission extends BasicPermission { + static final long serialVersionUID = -1179971692401603789L; + /** + * The permission name "admin". + */ + public static final String ADMIN = "admin"; + /** + * The action string "changeProperty". + */ + public static final String CHANGE_PROPERTY = "changeProperty"; + private static final int ACTION_CHANGE_PROPERTY = 0x1; + /** + * The action string "changeCredential". + */ + public static final String CHANGE_CREDENTIAL = "changeCredential"; + private static final int ACTION_CHANGE_CREDENTIAL = 0x2; + /** + * The action string "getCredential". + */ + public static final String GET_CREDENTIAL = "getCredential"; + private static final int ACTION_GET_CREDENTIAL = 0x4; + /** + * All actions + */ + private static final int ACTION_ALL = ACTION_CHANGE_PROPERTY | ACTION_CHANGE_CREDENTIAL | ACTION_GET_CREDENTIAL; + /** + * No actions. + */ + static final int ACTION_NONE = 0; + /** + * The actions in canonical form. + * + * @serial + */ + private volatile String actions = null; + /** + * The actions mask. + */ + private transient int action_mask; + + /** + * Creates a new {@code UserAdminPermission} with the specified name and + * actions. {@code name} is either the reserved string "admin" or + * the name of a credential or property, and {@code actions} contains a + * comma-separated list of the actions granted on the specified name. Valid + * actions are {@code changeProperty},{@code changeCredential}, and + * getCredential. + * + * @param name the name of this {@code UserAdminPermission} + * @param actions the action string. + * + * @throws IllegalArgumentException If {@code name} equals "admin" + * and {@code actions} are specified. + */ + public UserAdminPermission(String name, String actions) { + this(name, parseActions(actions)); + } + + /** + * Package private constructor used by {@code UserAdminPermissionCollection} + * . + * + * @param name class name + * @param mask action mask + */ + UserAdminPermission(String name, int mask) { + super(name); + setTransients(mask); + } + + /** + * Called by constructors and when deserialized. + * + * @param mask action mask + */ + private synchronized void setTransients(int mask) { + if (getName().equals(ADMIN)) { + if (mask != ACTION_NONE) { + throw new IllegalArgumentException("Actions specified for " + "no-action " + "UserAdminPermission"); + } + } else { + if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) { + throw new IllegalArgumentException("Invalid action string"); + } + } + action_mask = mask; + } + + /** + * Returns the current action mask. + * <p> + * Used by the UserAdminPermissionCollection class. + * + * @return Current action mask. + */ + synchronized int getActionsMask() { + return action_mask; + } + + /** + * Parse action string into action mask. + * + * @param actions Action string. + * @return action mask. + */ + private static int parseActions(String actions) { + boolean seencomma = false; + int mask = ACTION_NONE; + if (actions == null) { + return mask; + } + char[] a = actions.toCharArray(); + int i = a.length - 1; + if (i < 0) + return mask; + while (i != -1) { + char c; + // skip whitespace + while ((i != -1) && ((c = a[i]) == ' ' || c == '\r' || c == '\n' || c == '\f' || c == '\t')) + i--; + // check for the known strings + int matchlen; + if (i >= 12 && match_get(a, i - 10) && match_credential(a, i)) { + matchlen = 13; + mask |= ACTION_GET_CREDENTIAL; + } else + if (i >= 13 && match_change(a, i - 8) && match_property(a, i)) { + matchlen = 14; + mask |= ACTION_CHANGE_PROPERTY; + } else + if (i >= 15 && match_change(a, i - 10) && match_credential(a, i)) { + matchlen = 16; + mask |= ACTION_CHANGE_CREDENTIAL; + } else { + // parse error + throw new IllegalArgumentException("invalid permission: " + actions); + } + // make sure we didn't just match the tail of a word + // like "ackbarfimport". Also, skip to the comma. + seencomma = false; + while (i >= matchlen && !seencomma) { + switch (a[i - matchlen]) { + case ',' : + seencomma = true; + /* FALLTHROUGH */ + case ' ' : + case '\r' : + case '\n' : + case '\f' : + case '\t' : + break; + default : + throw new IllegalArgumentException("invalid permission: " + actions); + } + i--; + } + // point i at the location of the comma minus one (or -1). + i -= matchlen; + } + if (seencomma) { + throw new IllegalArgumentException("invalid permission: " + actions); + } + return mask; + } + + private static boolean match_change(char[] a, int i) { + return ((a[i - 5] == 'c' || a[i - 5] == 'C') && (a[i - 4] == 'h' || a[i - 4] == 'H') && (a[i - 3] == 'a' || a[i - 3] == 'A') && (a[i - 2] == 'n' || a[i - 2] == 'N') + && (a[i - 1] == 'g' || a[i - 1] == 'G') && (a[i - 0] == 'e' || a[i - 0] == 'E')); + } + + private static boolean match_get(char[] a, int i) { + return ((a[i - 2] == 'g' || a[i - 2] == 'G') && (a[i - 1] == 'e' || a[i - 1] == 'E') && (a[i - 0] == 't' || a[i - 0] == 'T')); + } + + private static boolean match_property(char[] a, int i) { + return ((a[i - 7] == 'p' || a[i - 7] == 'P') && (a[i - 6] == 'r' || a[i - 6] == 'R') && (a[i - 5] == 'o' || a[i - 5] == 'O') && (a[i - 4] == 'p' || a[i - 4] == 'P') + && (a[i - 3] == 'e' || a[i - 3] == 'E') && (a[i - 2] == 'r' || a[i - 2] == 'R') && (a[i - 1] == 't' || a[i - 1] == 'T') && (a[i - 0] == 'y' || a[i - 0] == 'Y')); + } + + private static boolean match_credential(char[] a, int i) { + return ((a[i - 9] == 'c' || a[i - 9] == 'C') && (a[i - 8] == 'r' || a[i - 8] == 'R') && (a[i - 7] == 'e' || a[i - 7] == 'E') && (a[i - 6] == 'd' || a[i - 6] == 'D') + && (a[i - 5] == 'e' || a[i - 5] == 'E') && (a[i - 4] == 'n' || a[i - 4] == 'N') && (a[i - 3] == 't' || a[i - 3] == 'T') && (a[i - 2] == 'i' || a[i - 2] == 'I') + && (a[i - 1] == 'a' || a[i - 1] == 'A') && (a[i - 0] == 'l' || a[i - 0] == 'L')); + } + + /** + * Checks if this {@code UserAdminPermission} object "implies" the + * specified permission. + * <P> + * More specifically, this method returns {@code true} if: + * <p> + * <ul> + * <li><i>p</i> is an instanceof {@code UserAdminPermission},</li> + * <li><i>p</i>'s actions are a proper subset of this object's actions, and</li> + * <li><i>p</i>'s name is implied by this object's name. For example, + * "java.*" implies "java.home".</li> + * </ul> + * + * @param p the permission to check against. + * + * @return {@code true} if the specified permission is implied by this + * object; {@code false} otherwise. + */ + public boolean implies(Permission p) { + if (p instanceof UserAdminPermission) { + UserAdminPermission requested = (UserAdminPermission) p; + int mask = getActionsMask(); + int targetMask = requested.getActionsMask(); + return // Check that the we have the requested action + ((targetMask & mask) == targetMask) && + // If the target action mask is ACTION_NONE, it must be an + // admin permission, and then we must be that too + (targetMask != ACTION_NONE || mask == ACTION_NONE) && + // Check that name name matches + super.implies(p); + } + return false; + } + + /** + * Returns the canonical string representation of the actions, separated by + * comma. + * + * @return the canonical string representation of the actions. + */ + public String getActions() { + String result = actions; + if (result == null) { + StringBuffer sb = new StringBuffer(); + boolean comma = false; + int mask = getActionsMask(); + if ((mask & ACTION_CHANGE_CREDENTIAL) == ACTION_CHANGE_CREDENTIAL) { + sb.append(CHANGE_CREDENTIAL); + comma = true; + } + if ((mask & ACTION_CHANGE_PROPERTY) == ACTION_CHANGE_PROPERTY) { + if (comma) + sb.append(','); + sb.append(CHANGE_PROPERTY); + comma = true; + } + if ((mask & ACTION_GET_CREDENTIAL) == ACTION_GET_CREDENTIAL) { + if (comma) + sb.append(','); + sb.append(GET_CREDENTIAL); + } + actions = result = sb.toString(); + } + return result; + } + + /** + * Returns a new {@code PermissionCollection} object for storing + * {@code UserAdminPermission} objects. + * + * @return a new {@code PermissionCollection} object suitable for storing + * {@code UserAdminPermission} objects. + */ + public PermissionCollection newPermissionCollection() { + return new UserAdminPermissionCollection(); + } + + /** + * Checks two {@code UserAdminPermission} objects for equality. Checks that + * {@code obj} is a {@code UserAdminPermission}, and has the same name and + * actions as this object. + * + * @param obj the object to be compared for equality with this object. + * + * @return {@code true} if {@code obj} is a {@code UserAdminPermission} + * object, and has the same name and actions as this + * {@code UserAdminPermission} object. + */ + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof UserAdminPermission)) { + return false; + } + + UserAdminPermission uap = (UserAdminPermission) obj; + + return (getActionsMask() == uap.getActionsMask()) && getName().equals(uap.getName()); + } + + /** + * Returns the hash code value for this object. + * + * @return A hash code value for this object. + */ + public int hashCode() { + int h = 31 * 17 + getName().hashCode(); + h = 31 * h + getActions().hashCode(); + return h; + } + + /** + * writeObject is called to save the state of this object to a stream. The + * actions are serialized, and the superclass takes care of the name. + */ + private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { + // Write out the actions. The superclass takes care of the name + // call getActions to make sure actions field is initialized + if (actions == null) + getActions(); + s.defaultWriteObject(); + } + + /* + * Restores this object from a stream (i.e., deserializes it). + */ + private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { + // Read in the action, then initialize the rest + s.defaultReadObject(); + setTransients(parseActions(actions)); + } + + /** + * Returns a string describing this {@code UserAdminPermission} object. This + * string must be in {@code PermissionInfo} encoded format. + * + * @return The {@code PermissionInfo} encoded string for this + * {@code UserAdminPermission} object. + * @see "org.osgi.service.permissionadmin.PermissionInfo.getEncoded()" + */ + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append('('); + sb.append(getClass().getName()); + sb.append(" \""); + sb.append(getName()); + String a = getActions(); + if (a.length() > 0) { + sb.append("\" \""); + sb.append(a); + } + sb.append("\")"); + return sb.toString(); + } +} + +/** + * A {@code UserAdminPermissionCollection} stores a set of + * {@code UserAdminPermission} permissions. + */ + +final class UserAdminPermissionCollection extends PermissionCollection { + static final long serialVersionUID = -7222111885230120581L; + /** + * Table of permissions. + * + * @serial + * @GuardedBy this + */ + private final Hashtable permissions; + /** + * Boolean saying if "*" is in the collection. + * + * @serial + * @GuardedBy this + */ + private boolean all_allowed; + + /** + * Creates an empty {@code UserAdminPermissionCollection} object. + */ + public UserAdminPermissionCollection() { + permissions = new Hashtable(); + all_allowed = false; + } + + /** + * Adds the given permission to this {@code UserAdminPermissionCollection}. + * The key for the hash is the name. + * + * @param permission the {@code Permission} object to add. + * + * @throws IllegalArgumentException If the given permission is not a + * {@code UserAdminPermission} + * @throws SecurityException If this {@code UserAdminPermissionCollection} + * object has been marked readonly + */ + public void add(Permission permission) { + if (!(permission instanceof UserAdminPermission)) + throw new IllegalArgumentException("Invalid permission: " + permission); + if (isReadOnly()) { + throw new SecurityException("Attempt to add a Permission to a " + "readonly PermissionCollection"); + } + final UserAdminPermission uap = (UserAdminPermission) permission; + final String name = uap.getName(); + synchronized (this) { + final UserAdminPermission existing = (UserAdminPermission) permissions.get(name); + if (existing != null) { + int oldMask = existing.getActionsMask(); + int newMask = uap.getActionsMask(); + if (oldMask != newMask) { + permissions.put(name, new UserAdminPermission(name, oldMask | newMask)); + } + } else { + permissions.put(name, uap); + } + if (!all_allowed) { + if (name.equals("*")) { + all_allowed = true; + } + } + } + } + + /** + * Checks to see if this {@code PermissionCollection} implies the given + * permission. + * + * @param permission the {@code Permission} object to check against + * + * @return true if the given permission is implied by this + * {@code PermissionCollection}, false otherwise. + */ + public boolean implies(Permission permission) { + if (!(permission instanceof UserAdminPermission)) { + return false; + } + final UserAdminPermission requested = (UserAdminPermission) permission; + String name = requested.getName(); + final int desired = requested.getActionsMask(); + UserAdminPermission x; + int effective = 0; + synchronized (this) { + // Short circuit if the "*" Permission was added. + // desired can only be ACTION_NONE when name is "admin". + if (all_allowed && (desired != UserAdminPermission.ACTION_NONE)) { + x = (UserAdminPermission) permissions.get("*"); + if (x != null) { + effective |= x.getActionsMask(); + if ((effective & desired) == desired) { + return true; + } + } + } + // strategy: + // Check for full match first. Then work our way up the + // name looking for matches on a.b.* + + x = (UserAdminPermission) permissions.get(name); + } + if (x != null) { + // we have a direct hit! + effective |= x.getActionsMask(); + if ((effective & desired) == desired) { + return true; + } + } + // work our way up the tree... + int last; + int offset = name.length() - 1; + while ((last = name.lastIndexOf(".", offset)) != -1) { + name = name.substring(0, last + 1) + "*"; + synchronized (this) { + x = (UserAdminPermission) permissions.get(name); + } + if (x != null) { + effective |= x.getActionsMask(); + if ((effective & desired) == desired) { + return true; + } + } + offset = last - 1; + } + // we don't have to check for "*" as it was already checked + // at the top (all_allowed), so we just return false + return false; + } + + /** + * Returns an enumeration of all the {@code UserAdminPermission} objects in + * the container. + * + * @return an enumeration of all the {@code UserAdminPermission} objects. + */ + public Enumeration elements() { + return permissions.elements(); + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/package-info.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/package-info.java new file mode 100644 index 000000000..b79edb198 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/package-info.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * User Admin Package Version 1.1. + * + * <p> + * Bundles wishing to use this package must list the package in the + * Import-Package header of the bundle's manifest. This package has two types of + * users: the consumers that use the API in this package and the providers that + * implement the API in this package. + * + * <p> + * Example import for consumers using the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.useradmin; version="[1.1,2.0)"} + * <p> + * Example import for providers implementing the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.useradmin; version="[1.1,1.2)"} + * + * @version 1.1 + * @author $Id$ + */ + +package org.osgi.service.useradmin; + diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/packageinfo b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/packageinfo new file mode 100644 index 000000000..3987f9c4e --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/useradmin/packageinfo @@ -0,0 +1 @@ +version 1.1 diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/BasicEnvelope.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/BasicEnvelope.java new file mode 100644 index 000000000..e7f7111ce --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/BasicEnvelope.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.wireadmin; + +/** + * {@code BasicEnvelope} is an implementation of the {@link Envelope} interface + * + * @Immutable + * @author $Id$ + */ +public class BasicEnvelope implements Envelope { + private final Object value; + private final Object identification; + private final String scope; + + /** + * Constructor. + * + * @param value Content of this envelope, may be {@code null}. + * @param identification Identifying object for this {@code Envelope} + * object, must not be {@code null} + * @param scope Scope name for this object, must not be {@code null} + * @see Envelope + */ + public BasicEnvelope(Object value, Object identification, String scope) { + this.value = value; + this.identification = identification; + this.scope = scope; + } + + /** + * @see org.osgi.service.wireadmin.Envelope#getValue() + */ + public Object getValue() { + return value; + } + + /** + * @see org.osgi.service.wireadmin.Envelope#getIdentification() + */ + public Object getIdentification() { + return identification; + } + + /** + * @see org.osgi.service.wireadmin.Envelope#getScope() + */ + public String getScope() { + return scope; + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/Consumer.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/Consumer.java new file mode 100644 index 000000000..3363ead47 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/Consumer.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.wireadmin; + +/** + * Data Consumer, a service that can receive udpated values from + * {@link Producer} services. + * + * <p> + * Service objects registered under the {@code Consumer} interface are expected + * to consume values from a Producer service via a {@code Wire} object. A + * Consumer service may poll the Producer service by calling the + * {@link Wire#poll()} method. The Consumer service will also receive an updated + * value when called at it's {@link #updated(Wire, Object)} method. The Producer + * service should have coerced the value to be an instance of one of the types + * specified by the {@link Wire#getFlavors()} method, or one of their + * subclasses. + * + * <p> + * Consumer service objects must register with a {@code service.pid} and a + * {@link WireConstants#WIREADMIN_CONSUMER_FLAVORS} property. It is recommended + * that Consumer service objects also register with a + * {@code service.description} property. + * + * <p> + * If an {@code Exception} is thrown by any of the {@code Consumer} methods, a + * {@code WireAdminEvent} of type {@link WireAdminEvent#CONSUMER_EXCEPTION} is + * broadcast by the Wire Admin service. + * + * <p> + * Security Considerations - Data consuming bundles will require + * {@code ServicePermission[Consumer,REGISTER]}. In general, only the Wire Admin + * service bundle should have this permission. Thus only the Wire Admin service + * may directly call a Consumer service. Care must be taken in the sharing of + * {@code Wire} objects with other bundles. + * <p> + * Consumer services must be registered with their scope when they can receive + * different types of objects from the Producer service. The Consumer service + * should have {@code WirePermission} for each of these scope names. + * + * @author $Id$ + */ +public interface Consumer { + /** + * Update the value. This Consumer service is called by the {@code Wire} + * object with an updated value from the Producer service. + * + * <p> + * Note: This method may be called by a {@code Wire} object prior to this + * object being notified that it is connected to that {@code Wire} object + * (via the {@link #producersConnected(Wire[])} method). + * <p> + * When the Consumer service can receive {@code Envelope} objects, it must + * have registered all scope names together with the service object, and + * each of those names must be permitted by the bundle's + * {@code WirePermission}. If an {@code Envelope} object is delivered with + * the {@code updated} method, then the Consumer service should assume that + * the security check has been performed. + * + * @param wire The {@code Wire} object which is delivering the updated + * value. + * @param value The updated value. The value should be an instance of one of + * the types specified by the {@link Wire#getFlavors()} method. + */ + public void updated(Wire wire, Object value); + + /** + * Update the list of {@code Wire} objects to which this Consumer service is + * connected. + * + * <p> + * This method is called when the Consumer service is first registered and + * subsequently whenever a {@code Wire} associated with this Consumer + * service becomes connected, is modified or becomes disconnected. + * + * <p> + * The Wire Admin service must call this method asynchronously. This implies + * that implementors of Consumer can be assured that the callback will not + * take place during registration when they execute the registration in a + * synchronized method. + * + * @param wires An array of the current and complete list of {@code Wire} + * objects to which this Consumer service is connected. May be + * {@code null} if the Consumer service is not currently connected to + * any {@code Wire} objects. + */ + public void producersConnected(Wire[] wires); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/Envelope.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/Envelope.java new file mode 100644 index 000000000..f00816c73 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/Envelope.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.wireadmin; + +/** + * Identifies a contained value. + * + * An {@code Envelope} object combines a status value, an identification object + * and a scope name. The {@code Envelope} object allows the use of standard Java + * types when a Producer service can produce more than one kind of object. The + * {@code Envelope} object allows the Consumer service to recognize the kind of + * object that is received. For example, a door lock could be represented by a + * {@code Boolean} object. If the {@code Producer} service would send such a + * {@code Boolean} object, then the Consumer service would not know what door + * the {@code Boolean} object represented. The {@code Envelope} object contains + * an identification object so the Consumer service can discriminate between + * different kinds of values. The identification object may be a simple + * {@code String} object, but it can also be a domain specific object that is + * mutually agreed by the Producer and the Consumer service. This object can + * then contain relevant information that makes the identification easier. + * <p> + * The scope name of the envelope is used for security. The Wire object must + * verify that any {@code Envelope} object send through the {@code update} + * method or coming from the {@code poll} method has a scope name that matches + * the permissions of both the Producer service and the Consumer service + * involved. The wireadmin package also contains a class {@code BasicEnvelope} + * that implements the methods of this interface. + * + * @see WirePermission + * @see BasicEnvelope + * + * @author $Id$ + */ +public interface Envelope { + /** + * Return the value associated with this {@code Envelope} object. + * + * @return the value of the status item, or {@code null} when no item is + * associated with this object. + */ + public Object getValue(); + + /** + * Return the identification of this {@code Envelope} object. + * + * An identification may be of any Java type. The type must be mutually + * agreed between the Consumer and Producer services. + * + * @return an object which identifies the status item in the address space + * of the composite producer, must not be null. + */ + public Object getIdentification(); + + /** + * Return the scope name of this {@code Envelope} object. + * + * Scope names are used to restrict the communication between the Producer + * and Consumer services. Only {@code Envelopes} objects with a scope name + * that is permitted for the Producer and the Consumer services must be + * passed through a {@code Wire} object. + * + * @return the security scope for the status item, must not be null. + */ + public String getScope(); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/Producer.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/Producer.java new file mode 100644 index 000000000..a65183e1e --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/Producer.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.wireadmin; + +/** + * Data Producer, a service that can generate values to be used by + * {@link Consumer} services. + * + * <p> + * Service objects registered under the Producer interface are expected to + * produce values (internally generated or from external sensors). The value can + * be of different types. When delivering a value to a {@code Wire} object, the + * Producer service should coerce the value to be an instance of one of the + * types specified by {@link Wire#getFlavors()}. The classes are specified in + * order of preference. + * + * <p> + * When the data represented by the Producer object changes, this object should + * send the updated value by calling the {@code update} method on each of + * {@code Wire} objects passed in the most recent call to this object's + * {@link #consumersConnected(Wire[])} method. These {@code Wire} objects will + * pass the value on to the associated {@code Consumer} service object. + * + * <p> + * The Producer service may use the information in the {@code Wire} object's + * properties to schedule the delivery of values to the {@code Wire} object. + * + * <p> + * Producer service objects must register with a {@code service.pid} and a + * {@link WireConstants#WIREADMIN_PRODUCER_FLAVORS} property. It is recommended + * that a Producer service object also registers with a + * {@code service.description} property. Producer service objects must register + * with a {@link WireConstants#WIREADMIN_PRODUCER_FILTERS} property if the + * Producer service will be performing filtering instead of the {@code Wire} + * object. + * + * <p> + * If an exception is thrown by a Producer object method, a + * {@code WireAdminEvent} of type {@link WireAdminEvent#PRODUCER_EXCEPTION} is + * broadcast by the Wire Admin service. + * + * <p> + * Security Considerations. Data producing bundles will require + * {@code ServicePermission[Producer,REGISTER]} to register a Producer service. + * In general, only the Wire Admin service should have + * {@code ServicePermission[Producer,GET]}. Thus only the Wire Admin service may + * directly call a Producer service. Care must be taken in the sharing of + * {@code Wire} objects with other bundles. + * <p> + * Producer services must be registered with scope names when they can send + * different types of objects (composite) to the Consumer service. The Producer + * service should have {@code WirePermission} for each of these scope names. + * + * @author $Id$ + */ +public interface Producer { + /** + * Return the current value of this {@code Producer} object. + * + * <p> + * This method is called by a {@code Wire} object in response to the + * Consumer service calling the {@code Wire} object's {@code poll} method. + * The Producer should coerce the value to be an instance of one of the + * types specified by {@link Wire#getFlavors()}. The types are specified in + * order of of preference. The returned value should be as new or newer than + * the last value furnished by this object. + * + * <p> + * Note: This method may be called by a {@code Wire} object prior to this + * object being notified that it is connected to that {@code Wire} object + * (via the {@link #consumersConnected(Wire[])} method). + * <p> + * If the Producer service returns an {@code Envelope} object that has an + * unpermitted scope name, then the Wire object must ignore (or remove) the + * transfer. + * <p> + * If the {@code Wire} object has a scope set, the return value must be an + * array of {@code Envelope} objects ({@code Envelope[]}). The {@code Wire} + * object must have removed any {@code Envelope} objects that have a scope + * name that is not in the Wire object's scope. + * + * @param wire The {@code Wire} object which is polling this service. + * @return The current value of the Producer service or {@code null} if the + * value cannot be coerced into a compatible type. Or an array of + * {@code Envelope} objects. + */ + public Object polled(Wire wire); + + /** + * Update the list of {@code Wire} objects to which this {@code Producer} + * object is connected. + * + * <p> + * This method is called when the Producer service is first registered and + * subsequently whenever a {@code Wire} associated with this Producer + * becomes connected, is modified or becomes disconnected. + * + * <p> + * The Wire Admin service must call this method asynchronously. This implies + * that implementors of a Producer service can be assured that the callback + * will not take place during registration when they execute the + * registration in a synchronized method. + * + * @param wires An array of the current and complete list of {@code Wire} + * objects to which this Producer service is connected. May be + * {@code null} if the Producer is not currently connected to any + * {@code Wire} objects. + */ + public void consumersConnected(Wire[] wires); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/Wire.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/Wire.java new file mode 100644 index 000000000..de75c27d5 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/Wire.java @@ -0,0 +1,271 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.wireadmin; + +import java.util.Dictionary; + +/** + * A connection between a Producer service and a Consumer service. + * + * <p> + * A {@code Wire} object connects a Producer service to a Consumer service. Both + * the Producer and Consumer services are identified by their unique + * {@code service.pid} values. The Producer and Consumer services may + * communicate with each other via {@code Wire} objects that connect them. The + * Producer service may send updated values to the Consumer service by calling + * the {@link #update(Object)} method. The Consumer service may request an + * updated value from the Producer service by calling the {@link #poll()} + * method. + * + * <p> + * A Producer service and a Consumer service may be connected through multiple + * {@code Wire} objects. + * + * <p> + * Security Considerations. {@code Wire} objects are available to Producer and + * Consumer services connected to a given {@code Wire} object and to bundles + * which can access the {@code WireAdmin} service. A bundle must have + * {@code ServicePermission[WireAdmin,GET]} to get the {@code WireAdmin} service + * to access all {@code Wire} objects. A bundle registering a Producer service + * or a Consumer service must have the appropriate + * {@code ServicePermission[Consumer|Producer,REGISTER]} to register the service + * and will be passed {@code Wire} objects when the service object's + * {@code consumersConnected} or {@code producersConnected} method is called. + * + * <p> + * Scope. Each Wire object can have a scope set with the {@code setScope} + * method. This method should be called by a Consumer service when it assumes a + * Producer service that is composite (supports multiple information items). The + * names in the scope must be verified by the {@code Wire} object before it is + * used in communication. The semantics of the names depend on the Producer + * service and must not be interpreted by the Wire Admin service. + * + * @noimplement + * @author $Id$ + */ +public interface Wire { + /** + * Return the state of this {@code Wire} object. + * + * <p> + * A connected {@code Wire} must always be disconnected before becoming + * invalid. + * + * @return {@code false} if this {@code Wire} object is invalid because it + * has been deleted via {@link WireAdmin#deleteWire(Wire)}; + * {@code true} otherwise. + */ + public boolean isValid(); + + /** + * Return the connection state of this {@code Wire} object. + * + * <p> + * A {@code Wire} is connected after the Wire Admin service receives + * notification that the Producer service and the Consumer service for this + * {@code Wire} object are both registered. This method will return + * {@code true} prior to notifying the Producer and Consumer services via + * calls to their respective {@code consumersConnected} and + * {@code producersConnected} methods. + * <p> + * A {@code WireAdminEvent} of type {@link WireAdminEvent#WIRE_CONNECTED} + * must be broadcast by the Wire Admin service when the {@code Wire} becomes + * connected. + * + * <p> + * A {@code Wire} object is disconnected when either the Consumer or + * Producer service is unregistered or the {@code Wire} object is deleted. + * <p> + * A {@code WireAdminEvent} of type {@link WireAdminEvent#WIRE_DISCONNECTED} + * must be broadcast by the Wire Admin service when the {@code Wire} becomes + * disconnected. + * + * @return {@code true} if both the Producer and Consumer for this + * {@code Wire} object are connected to the {@code Wire} object; + * {@code false} otherwise. + */ + public boolean isConnected(); + + /** + * Return the list of data types understood by the Consumer service + * connected to this {@code Wire} object. Note that subclasses of the + * classes in this list are acceptable data types as well. + * + * <p> + * The list is the value of the + * {@link WireConstants#WIREADMIN_CONSUMER_FLAVORS} service property of the + * Consumer service object connected to this object. If no such property was + * registered or the type of the property value is not {@code Class[]}, this + * method must return {@code null}. + * + * @return An array containing the list of classes understood by the + * Consumer service or {@code null} if the {@code Wire} is not + * connected, or the consumer did not register a + * {@link WireConstants#WIREADMIN_CONSUMER_FLAVORS} property or the + * value of the property is not of type {@code Class[]}. + */ + public Class[] getFlavors(); + + /** + * Update the value. + * + * <p> + * This methods is called by the Producer service to notify the Consumer + * service connected to this {@code Wire} object of an updated value. + * <p> + * If the properties of this {@code Wire} object contain a + * {@link WireConstants#WIREADMIN_FILTER} property, then filtering is + * performed. If the Producer service connected to this {@code Wire} object + * was registered with the service property + * {@link WireConstants#WIREADMIN_PRODUCER_FILTERS}, the Producer service + * will perform the filtering according to the rules specified for the + * filter. Otherwise, this {@code Wire} object will perform the filtering of + * the value. + * <p> + * If no filtering is done, or the filter indicates the updated value should + * be delivered to the Consumer service, then this {@code Wire} object must + * call the {@link Consumer#updated(Wire, Object)} method with the updated + * value. If this {@code Wire} object is not connected, then the Consumer + * service must not be called and the value is ignored. + * <p> + * If the value is an {@code Envelope} object, and the scope name is not + * permitted, then the {@code Wire} object must ignore this call and not + * transfer the object to the Consumer service. + * + * <p> + * A {@code WireAdminEvent} of type {@link WireAdminEvent#WIRE_TRACE} must + * be broadcast by the Wire Admin service after the Consumer service has + * been successfully called. + * + * @param value The updated value. The value should be an instance of one of + * the types returned by {@link #getFlavors()}. + * @see WireConstants#WIREADMIN_FILTER + */ + public void update(Object value); + + /** + * Poll for an updated value. + * + * <p> + * This methods is normally called by the Consumer service to request an + * updated value from the Producer service connected to this {@code Wire} + * object. This {@code Wire} object will call the + * {@link Producer#polled(Wire)} method to obtain an updated value. If this + * {@code Wire} object is not connected, then the Producer service must not + * be called. + * <p> + * + * If this {@code Wire} object has a scope, then this method must return an + * array of {@code Envelope} objects. The objects returned must match the + * scope of this object. The {@code Wire} object must remove all + * {@code Envelope} objects with a scope name that is not in the + * {@code Wire} object's scope. Thus, the list of objects returned must only + * contain {@code Envelope} objects with a permitted scope name. If the + * array becomes empty, {@code null} must be returned. + * + * <p> + * A {@code WireAdminEvent} of type {@link WireAdminEvent#WIRE_TRACE} must + * be broadcast by the Wire Admin service after the Producer service has + * been successfully called. + * + * @return A value whose type should be one of the types returned by + * {@link #getFlavors()},{@code Envelope[]}, or {@code null} if the + * {@code Wire} object is not connected, the Producer service threw + * an exception, or the Producer service returned a value which is + * not an instance of one of the types returned by + * {@link #getFlavors()}. + */ + public Object poll(); + + /** + * Return the last value sent through this {@code Wire} object. + * + * <p> + * The returned value is the most recent, valid value passed to the + * {@link #update(Object)} method or returned by the {@link #poll()} method + * of this object. If filtering is performed by this {@code Wire} object, + * this methods returns the last value provided by the Producer service. + * This value may be an {@code Envelope[]} when the Producer service uses + * scoping. If the return value is an Envelope object (or array), it must be + * verified that the Consumer service has the proper WirePermission to see + * it. + * + * @return The last value passed though this {@code Wire} object or + * {@code null} if no valid values have been passed or the Consumer + * service has no permission. + */ + public Object getLastValue(); + + /** + * Return the wire properties for this {@code Wire} object. + * + * @return The properties for this {@code Wire} object. The returned + * {@code Dictionary} must be read only. + */ + public Dictionary getProperties(); + + /** + * Return the calculated scope of this {@code Wire} object. + * + * The purpose of the {@code Wire} object's scope is to allow a Producer + * and/or Consumer service to produce/consume different types over a single + * {@code Wire} object (this was deemed necessary for efficiency reasons). + * Both the Consumer service and the Producer service must set an array of + * scope names (their scope) with the service registration property + * {@code WIREADMIN_PRODUCER_SCOPE}, or {@code WIREADMIN_CONSUMER_SCOPE} + * when they can produce multiple types. If a Producer service can produce + * different types, it should set this property to the array of scope names + * it can produce, the Consumer service must set the array of scope names it + * can consume. The scope of a {@code Wire} object is defined as the + * intersection of permitted scope names of the Producer service and + * Consumer service. + * <p> + * If neither the Consumer, or the Producer service registers scope names + * with its service registration, then the {@code Wire} object's scope must + * be {@code null}. + * <p> + * The {@code Wire} object's scope must not change when a Producer or + * Consumer services modifies its scope. + * <p> + * A scope name is permitted for a Producer service when the registering + * bundle has {@code WirePermission[name,PRODUCE]}, and for a Consumer + * service when the registering bundle has + * {@code WirePermission[name,CONSUME]}. + * <p> + * If either Consumer service or Producer service has not set a + * {@code WIREADMIN_*_SCOPE} property, then the returned value must be + * {@code null}. + * <p> + * If the scope is set, the {@code Wire} object must enforce the scope names + * when {@code Envelope} objects are used as a parameter to update or + * returned from the {@code poll} method. The {@code Wire} object must then + * remove all {@code Envelope} objects with a scope name that is not + * permitted. + * + * @return A list of permitted scope names or null if the Produce or + * Consumer service has set no scope names. + */ + public String[] getScope(); + + /** + * Return true if the given name is in this {@code Wire} object's scope. + * + * @param name The scope name + * @return true if the name is listed in the permitted scope names + */ + public boolean hasScope(String name); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/WireAdmin.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/WireAdmin.java new file mode 100644 index 000000000..783de096c --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/WireAdmin.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.wireadmin; + +import java.util.Dictionary; +import org.osgi.framework.InvalidSyntaxException; + +/** + * Wire Administration service. + * + * <p> + * This service can be used to create {@code Wire} objects connecting a Producer + * service and a Consumer service. {@code Wire} objects also have wire + * properties that may be specified when a {@code Wire} object is created. The + * Producer and Consumer services may use the {@code Wire} object's properties + * to manage or control their interaction. The use of {@code Wire} object's + * properties by a Producer or Consumer services is optional. + * + * <p> + * Security Considerations. A bundle must have + * {@code ServicePermission[WireAdmin,GET]} to get the Wire Admin service to + * create, modify, find, and delete {@code Wire} objects. + * + * @noimplement + * @author $Id$ + */ +public interface WireAdmin { + /** + * Create a new {@code Wire} object that connects a Producer service to a + * Consumer service. + * + * The Producer service and Consumer service do not have to be registered + * when the {@code Wire} object is created. + * + * <p> + * The {@code Wire} configuration data must be persistently stored. All + * {@code Wire} connections are reestablished when the {@code WireAdmin} + * service is registered. A {@code Wire} can be permanently removed by using + * the {@link #deleteWire(Wire)} method. + * + * <p> + * The {@code Wire} object's properties must have case insensitive + * {@code String} objects as keys (like the Framework). However, the case of + * the key must be preserved. + * + * <p> + * The {@code WireAdmin} service must automatically add the following + * {@code Wire} properties: + * <ul> + * <li>{@link WireConstants#WIREADMIN_PID} set to the value of the + * {@code Wire} object's persistent identity (PID). This value is generated + * by the Wire Admin service when a {@code Wire} object is created.</li> + * <li>{@link WireConstants#WIREADMIN_PRODUCER_PID} set to the value of + * Producer service's PID.</li> + * <li>{@link WireConstants#WIREADMIN_CONSUMER_PID} set to the value of + * Consumer service's PID.</li> + * </ul> + * If the {@code properties} argument already contains any of these keys, + * then the supplied values are replaced with the values assigned by the + * Wire Admin service. + * + * <p> + * The Wire Admin service must broadcast a {@code WireAdminEvent} of type + * {@link WireAdminEvent#WIRE_CREATED} after the new {@code Wire} object + * becomes available from {@link #getWires(String)}. + * + * @param producerPID The {@code service.pid} of the Producer service to be + * connected to the {@code Wire} object. + * @param consumerPID The {@code service.pid} of the Consumer service to be + * connected to the {@code Wire} object. + * @param properties The {@code Wire} object's properties. This argument may + * be {@code null} if the caller does not wish to define any + * {@code Wire} object's properties. + * @return The {@code Wire} object for this connection. + * + * @throws java.lang.IllegalArgumentException If {@code properties} contains + * invalid wire types or case variants of the same key name. + */ + public Wire createWire(String producerPID, String consumerPID, Dictionary properties); + + /** + * Delete a {@code Wire} object. + * + * <p> + * The {@code Wire} object representing a connection between a Producer + * service and a Consumer service must be removed. The persistently stored + * configuration data for the {@code Wire} object must destroyed. The + * {@code Wire} object's method {@link Wire#isValid()} will return + * {@code false} after it is deleted. + * + * <p> + * The Wire Admin service must broadcast a {@code WireAdminEvent} of type + * {@link WireAdminEvent#WIRE_DELETED} after the {@code Wire} object becomes + * invalid. + * + * @param wire The {@code Wire} object which is to be deleted. + */ + public void deleteWire(Wire wire); + + /** + * Update the properties of a {@code Wire} object. + * + * The persistently stored configuration data for the {@code Wire} object is + * updated with the new properties and then the Consumer and Producer + * services will be called at the respective + * {@link Consumer#producersConnected(Wire[])} and + * {@link Producer#consumersConnected(Wire[])} methods. + * + * <p> + * The Wire Admin service must broadcast a {@code WireAdminEvent} of type + * {@link WireAdminEvent#WIRE_UPDATED} after the updated properties are + * available from the {@code Wire} object. + * + * @param wire The {@code Wire} object which is to be updated. + * @param properties The new {@code Wire} object's properties or + * {@code null} if no properties are required. + * + * @throws java.lang.IllegalArgumentException If {@code properties} contains + * invalid wire types or case variants of the same key name. + */ + public void updateWire(Wire wire, Dictionary properties); + + /** + * Return the {@code Wire} objects that match the given {@code filter}. + * + * <p> + * The list of available {@code Wire} objects is matched against the + * specified {@code filter}.{@code Wire} objects which match the + * {@code filter} must be returned. These {@code Wire} objects are not + * necessarily connected. The Wire Admin service should not return invalid + * {@code Wire} objects, but it is possible that a {@code Wire} object is + * deleted after it was placed in the list. + * + * <p> + * The filter matches against the {@code Wire} object's properties including + * {@link WireConstants#WIREADMIN_PRODUCER_PID}, + * {@link WireConstants#WIREADMIN_CONSUMER_PID} and + * {@link WireConstants#WIREADMIN_PID}. + * + * @param filter Filter string to select {@code Wire} objects or + * {@code null} to select all {@code Wire} objects. + * @return An array of {@code Wire} objects which match the {@code filter} + * or {@code null} if no {@code Wire} objects match the + * {@code filter}. + * @throws org.osgi.framework.InvalidSyntaxException If the specified + * {@code filter} has an invalid syntax. + * @see org.osgi.framework.Filter + */ + public Wire[] getWires(String filter) throws InvalidSyntaxException; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/WireAdminEvent.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/WireAdminEvent.java new file mode 100644 index 000000000..665e72cdd --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/WireAdminEvent.java @@ -0,0 +1,267 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.wireadmin; + +import org.osgi.framework.ServiceReference; + +/** + * A Wire Admin Event. + * + * <p> + * {@code WireAdminEvent} objects are delivered to all registered + * {@code WireAdminListener} service objects which specify an interest in the + * {@code WireAdminEvent} type. Events must be delivered in chronological order + * with respect to each listener. For example, a {@code WireAdminEvent} of type + * {@link #WIRE_CONNECTED} must be delivered before a {@code WireAdminEvent} of + * type {@link #WIRE_DISCONNECTED} for a particular {@code Wire} object. + * + * <p> + * A type code is used to identify the type of event. The following event types + * are defined: + * <ul> + * <li>{@link #WIRE_CREATED}</li> + * <li>{@link #WIRE_CONNECTED}</li> + * <li>{@link #WIRE_UPDATED}</li> + * <li>{@link #WIRE_TRACE}</li> + * <li>{@link #WIRE_DISCONNECTED}</li> + * <li>{@link #WIRE_DELETED}</li> + * <li>{@link #PRODUCER_EXCEPTION}</li> + * <li>{@link #CONSUMER_EXCEPTION}</li> + * </ul> + * Additional event types may be defined in the future. + * + * <p> + * Event type values must be unique and disjoint bit values. Event types must be + * defined as a bit in a 32 bit integer and can thus be bitwise OR'ed together. + * <p> + * Security Considerations. {@code WireAdminEvent} objects contain {@code Wire} + * objects. Care must be taken in the sharing of {@code Wire} objects with other + * bundles. + * + * @see WireAdminListener + * @Immutable + * @author $Id$ + */ +public class WireAdminEvent { + /** + * The WireAdmin service which created this event. + */ + private final ServiceReference reference; + /** + * The {@code Wire} object associated with this event. + */ + private final Wire wire; + /** + * Type of this event. + * + * @see #getType() + */ + private final int type; + /** + * Exception associates with this the event. + */ + private final Throwable throwable; + /** + * A Producer service method has thrown an exception. + * + * <p> + * This {@code WireAdminEvent} type indicates that a Producer service method + * has thrown an exception. The {@link WireAdminEvent#getThrowable()} method + * will return the exception that the Producer service method raised. + * + * <p> + * The value of {@code PRODUCER_EXCEPTION} is 0x00000001. + */ + public final static int PRODUCER_EXCEPTION = 0x00000001; + /** + * A Consumer service method has thrown an exception. + * + * <p> + * This {@code WireAdminEvent} type indicates that a Consumer service method + * has thrown an exception. The {@link WireAdminEvent#getThrowable()} method + * will return the exception that the Consumer service method raised. + * + * <p> + * The value of {@code CONSUMER_EXCEPTION} is 0x00000002. + */ + public final static int CONSUMER_EXCEPTION = 0x00000002; + /** + * A {@code Wire} has been created. + * + * <p> + * This {@code WireAdminEvent} type that indicates that a new {@code Wire} + * object has been created. + * + * An event is broadcast when + * {@link WireAdmin#createWire(String, String, java.util.Dictionary)} is + * called. The {@link WireAdminEvent#getWire()} method will return the + * {@code Wire} object that has just been created. + * + * <p> + * The value of {@code WIRE_CREATED} is 0x00000004. + */ + public final static int WIRE_CREATED = 0x00000004; + /** + * A {@code Wire} has been updated. + * + * <p> + * This {@code WireAdminEvent} type that indicates that an existing + * {@code Wire} object has been updated with new properties. + * + * An event is broadcast when + * {@link WireAdmin#updateWire(Wire, java.util.Dictionary)} is called with a + * valid wire. The {@link WireAdminEvent#getWire()} method will return the + * {@code Wire} object that has just been updated. + * + * <p> + * The value of {@code WIRE_UPDATED} is 0x00000008. + */ + public final static int WIRE_UPDATED = 0x00000008; + /** + * A {@code Wire} has been deleted. + * + * <p> + * This {@code WireAdminEvent} type that indicates that an existing wire has + * been deleted. + * + * An event is broadcast when {@link WireAdmin#deleteWire(Wire)} is called + * with a valid wire. {@link WireAdminEvent#getWire()} will return the + * {@code Wire} object that has just been deleted. + * + * <p> + * The value of {@code WIRE_DELETED} is 0x00000010. + */ + public final static int WIRE_DELETED = 0x00000010; + /** + * The {@code WireAdminEvent} type that indicates that an existing + * {@code Wire} object has become connected. + * + * The Consumer object and the Producer object that are associated with the + * {@code Wire} object have both been registered and the {@code Wire} object + * is connected. See {@link Wire#isConnected()} for a description of the + * connected state. This event may come before the + * {@code producersConnected} and {@code consumersConnected} method have + * returned or called to allow synchronous delivery of the events. Both + * methods can cause other {@code WireAdminEvent} s to take place and + * requiring this event to be send before these methods are returned would + * mandate asynchronous delivery. + * + * <p> + * The value of {@code WIRE_CONNECTED} is 0x00000020. + */ + public final static int WIRE_CONNECTED = 0x00000020; + /** + * The {@code WireAdminEvent} type that indicates that an existing + * {@code Wire} object has become disconnected. + * + * The Consumer object or/and Producer object is/are unregistered breaking + * the connection between the two. See {@link Wire#isConnected} for a + * description of the connected state. + * + * <p> + * The value of {@code WIRE_DISCONNECTED} is 0x00000040. + */ + public final static int WIRE_DISCONNECTED = 0x00000040; + /** + * The {@code WireAdminEvent} type that indicates that a new value is + * transferred over the {@code Wire} object. + * + * This event is sent after the Consumer service has been notified by + * calling the {@link Consumer#updated(Wire, Object)} method or the Consumer + * service requested a new value with the {@link Wire#poll()} method. This + * is an advisory event meaning that when this event is received, another + * update may already have occurred and this the {@link Wire#getLastValue()} + * method returns a newer value then the value that was communicated for + * this event. + * + * <p> + * The value of {@code WIRE_TRACE} is 0x00000080. + */ + public final static int WIRE_TRACE = 0x00000080; + + /** + * Constructs a {@code WireAdminEvent} object from the given + * {@code ServiceReference} object, event type, {@code Wire} object and + * exception. + * + * @param reference The {@code ServiceReference} object of the Wire Admin + * service that created this event. + * @param type The event type. See {@link #getType()}. + * @param wire The {@code Wire} object associated with this event. + * @param exception An exception associated with this event. This may be + * {@code null} if no exception is associated with this event. + */ + public WireAdminEvent(ServiceReference reference, int type, Wire wire, Throwable exception) { + this.reference = reference; + this.wire = wire; + this.type = type; + this.throwable = exception; + } + + /** + * Return the {@code ServiceReference} object of the Wire Admin service that + * created this event. + * + * @return The {@code ServiceReference} object for the Wire Admin service + * that created this event. + */ + public ServiceReference getServiceReference() { + return reference; + } + + /** + * Return the {@code Wire} object associated with this event. + * + * @return The {@code Wire} object associated with this event or + * {@code null} when no {@code Wire} object is associated with the + * event. + */ + public Wire getWire() { + return wire; + } + + /** + * Return the type of this event. + * <p> + * The type values are: + * <ul> + * <li>{@link #WIRE_CREATED}</li> + * <li>{@link #WIRE_CONNECTED}</li> + * <li>{@link #WIRE_UPDATED}</li> + * <li>{@link #WIRE_TRACE}</li> + * <li>{@link #WIRE_DISCONNECTED}</li> + * <li>{@link #WIRE_DELETED}</li> + * <li>{@link #PRODUCER_EXCEPTION}</li> + * <li>{@link #CONSUMER_EXCEPTION}</li> + * </ul> + * + * @return The type of this event. + */ + public int getType() { + return type; + } + + /** + * Returns the exception associated with the event, if any. + * + * @return An exception or {@code null} if no exception is associated with + * this event. + */ + public Throwable getThrowable() { + return throwable; + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/WireAdminListener.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/WireAdminListener.java new file mode 100644 index 000000000..0a0f329f6 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/WireAdminListener.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.wireadmin; + +/** + * Listener for Wire Admin Events. + * + * <p> + * {@code WireAdminListener} objects are registered with the Framework service + * registry and are notified with a {@code WireAdminEvent} object when an event + * is broadcast. + * <p> + * {@code WireAdminListener} objects can inspect the received + * {@code WireAdminEvent} object to determine its type, the {@code Wire} object + * with which it is associated, and the Wire Admin service that broadcasts the + * event. + * + * <p> + * {@code WireAdminListener} objects must be registered with a service property + * {@link WireConstants#WIREADMIN_EVENTS} whose value is a bitwise OR of all the + * event types the listener is interested in receiving. + * <p> + * For example: + * + * <pre> + * Integer mask = new Integer(WIRE_TRACE | WIRE_CONNECTED | WIRE_DISCONNECTED); + * Hashtable ht = new Hashtable(); + * ht.put(WIREADMIN_EVENTS, mask); + * context.registerService(WireAdminListener.class.getName(), this, ht); + * </pre> + * + * If a {@code WireAdminListener} object is registered without a service + * property {@link WireConstants#WIREADMIN_EVENTS}, then the + * {@code WireAdminListener} will receive no events. + * + * <p> + * Security Considerations. Bundles wishing to monitor {@code WireAdminEvent} + * objects will require {@code ServicePermission[WireAdminListener,REGISTER]} to + * register a {@code WireAdminListener} service. Since {@code WireAdminEvent} + * objects contain {@code Wire} objects, care must be taken in assigning + * permission to register a {@code WireAdminListener} service. + * + * @see WireAdminEvent + * + * @author $Id$ + */ +public interface WireAdminListener { + /** + * Receives notification of a broadcast {@code WireAdminEvent} object. + * + * The event object will be of an event type specified in this + * {@code WireAdminListener} service's + * {@link WireConstants#WIREADMIN_EVENTS} service property. + * + * @param event The {@code WireAdminEvent} object. + */ + void wireAdminEvent(WireAdminEvent event); +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/WireConstants.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/WireConstants.java new file mode 100644 index 000000000..12b9e446d --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/WireConstants.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.wireadmin; + +/** + * Defines standard names for {@code Wire} properties, wire filter attributes, + * Consumer and Producer service properties. + * + * @noimplement + * @author $Id$ + */ +public interface WireConstants { + /** + * {@code Wire} property key (named {@code wireadmin.pid}) specifying the + * persistent identity (PID) of this {@code Wire} object. + * + * <p> + * Each {@code Wire} object has a PID to allow unique and persistent + * identification of a specific {@code Wire} object. The PID must be + * generated by the {@link WireAdmin} service when the {@code Wire} object + * is created. + * + * <p> + * This wire property is automatically set by the Wire Admin service. The + * value of the property must be of type {@code String}. + */ + public final static String WIREADMIN_PID = "wireadmin.pid"; + /** + * A service registration property for a Producer service that is composite. + * It contains the names of the composite Consumer services it can + * inter-operate with. Inter-operability exists when any name in this array + * matches any name in the array set by the Consumer service. The type of + * this property must be {@code String[]}. + */ + public final static String WIREADMIN_PRODUCER_COMPOSITE = "wireadmin.producer.composite"; + /** + * A service registration property for a Consumer service that is composite. + * It contains the names of the composite Producer services it can cooperate + * with. Inter-operability exists when any name in this array matches any + * name in the array set by the Producer service. The type of this property + * must be {@code String[]}. + */ + public final static String WIREADMIN_CONSUMER_COMPOSITE = "wireadmin.consumer.composite"; + /** + * Service registration property key (named {@code wireadmin.producer.scope} + * ) specifying a list of names that may be used to define the scope of this + * {@code Wire} object. A Producer service should set this service property + * when it can produce more than one kind of value. This property is only + * used during registration, modifying the property must not have any effect + * of the {@code Wire} object's scope. Each name in the given list mist have + * {@code WirePermission[name,PRODUCE]} or else is ignored. The type of this + * service registration property must be {@code String[]}. + * + * @see Wire#getScope() + * @see #WIREADMIN_CONSUMER_SCOPE + */ + public final static String WIREADMIN_PRODUCER_SCOPE = "wireadmin.producer.scope"; + /** + * Service registration property key (named {@code wireadmin.consumer.scope} + * ) specifying a list of names that may be used to define the scope of this + * {@code Wire} object. A {@code Consumer} service should set this service + * property when it can produce more than one kind of value. This property + * is only used during registration, modifying the property must not have + * any effect of the {@code Wire} object's scope. Each name in the given + * list mist have {@code WirePermission[name,CONSUME]} or else is ignored. + * The type of this service registration property must be {@code String[]}. + * + * @see Wire#getScope() + * @see #WIREADMIN_PRODUCER_SCOPE + */ + public final static String WIREADMIN_CONSUMER_SCOPE = "wireadmin.consumer.scope"; + /** + * Matches all scope names. + */ + public final static String WIREADMIN_SCOPE_ALL[] = {"*"}; + /** + * {@code Wire} property key (named {@code wireadmin.producer.pid}) + * specifying the {@code service.pid} of the associated Producer service. + * + * <p> + * This wire property is automatically set by the WireAdmin service. The + * value of the property must be of type {@code String}. + */ + public final static String WIREADMIN_PRODUCER_PID = "wireadmin.producer.pid"; + /** + * {@code Wire} property key (named {@code wireadmin.consumer.pid}) + * specifying the {@code service.pid} of the associated Consumer service. + * + * <p> + * This wire property is automatically set by the Wire Admin service. The + * value of the property must be of type {@code String}. + */ + public final static String WIREADMIN_CONSUMER_PID = "wireadmin.consumer.pid"; + /** + * {@code Wire} property key (named {@code wireadmin.filter}) specifying a + * filter used to control the delivery rate of data between the Producer and + * the Consumer service. + * + * <p> + * This property should contain a filter as described in the {@code Filter} + * class. The filter can be used to specify when an updated value from the + * Producer service should be delivered to the Consumer service. In many + * cases the Consumer service does not need to receive the data with the + * same rate that the Producer service can generate data. This property can + * be used to control the delivery rate. + * <p> + * The filter can use a number of pre-defined attributes that can be used to + * control the delivery of new data values. If the filter produces a match + * upon the wire filter attributes, the Consumer service should be notifed + * of the updated data value. + * <p> + * If the Producer service was registered with the + * {@link #WIREADMIN_PRODUCER_FILTERS} service property indicating that the + * Producer service will perform the data filtering then the {@code Wire} + * object will not perform data filtering. Otherwise, the {@code Wire} + * object must perform basic filtering. Basic filtering includes supporting + * the following standard wire filter attributes: + * <ul> + * <li>{@link #WIREVALUE_CURRENT} - Current value</li> + * <li>{@link #WIREVALUE_PREVIOUS} - Previous value</li> + * <li>{@link #WIREVALUE_DELTA_ABSOLUTE} - Absolute delta</li> + * <li>{@link #WIREVALUE_DELTA_RELATIVE} - Relative delta</li> + * <li>{@link #WIREVALUE_ELAPSED} - Elapsed time</li> + * </ul> + * + * @see org.osgi.framework.Filter + */ + public final static String WIREADMIN_FILTER = "wireadmin.filter"; + /* Wire filter attribute names. */ + /** + * {@code Wire} object's filter attribute (named {@code wirevalue.current}) + * representing the current value. + */ + public final static String WIREVALUE_CURRENT = "wirevalue.current"; + /** + * {@code Wire} object's filter attribute (named {@code wirevalue.previous}) + * representing the previous value. + */ + public final static String WIREVALUE_PREVIOUS = "wirevalue.previous"; + /** + * {@code Wire} object's filter attribute (named + * {@code wirevalue.delta.absolute}) representing the absolute delta. The + * absolute (always positive) difference between the last update and the + * current value (only when numeric). This attribute must not be used when + * the values are not numeric. + */ + public final static String WIREVALUE_DELTA_ABSOLUTE = "wirevalue.delta.absolute"; + /** + * {@code Wire} object's filter attribute (named + * {@code wirevalue.delta.relative}) representing the relative delta. The + * relative difference is |{@code previous}-{@code current} |/| + * {@code current}| (only when numeric). This attribute must not be used + * when the values are not numeric. + */ + public final static String WIREVALUE_DELTA_RELATIVE = "wirevalue.delta.relative"; + /** + * {@code Wire} object's filter attribute (named {@code wirevalue.elapsed}) + * representing the elapsed time, in ms, between this filter evaluation and + * the last update of the {@code Consumer} service. + */ + public final static String WIREVALUE_ELAPSED = "wirevalue.elapsed"; + /* Service registration property key names. */ + /** + * Service Registration property (named {@code wireadmin.producer.filters}). + * A {@code Producer} service registered with this property indicates to the + * Wire Admin service that the Producer service implements at least the + * filtering as described for the {@link #WIREADMIN_FILTER} property. If the + * Producer service is not registered with this property, the {@code Wire} + * object must perform the basic filtering as described in + * {@link #WIREADMIN_FILTER}. + * + * <p> + * The type of the property value is not relevant. Only its presence is + * relevant. + */ + public final static String WIREADMIN_PRODUCER_FILTERS = "wireadmin.producer.filters"; + /** + * Service Registration property (named {@code wireadmin.consumer.flavors}) + * specifying the list of data types understood by this Consumer service. + * + * <p> + * The Consumer service object must be registered with this service + * property. The list must be in the order of preference with the first type + * being the most preferred. The value of the property must be of type + * {@code Class[]}. + */ + public final static String WIREADMIN_CONSUMER_FLAVORS = "wireadmin.consumer.flavors"; + /** + * Service Registration property (named {@code wireadmin.producer.flavors}) + * specifying the list of data types available from this Producer service. + * + * <p> + * The Producer service object should be registered with this service + * property. + * + * <p> + * The value of the property must be of type {@code Class[]}. + */ + public final static String WIREADMIN_PRODUCER_FLAVORS = "wireadmin.producer.flavors"; + /** + * Service Registration property (named {@code wireadmin.events}) specifying + * the {@code WireAdminEvent} type of interest to a Wire Admin Listener + * service. The value of the property is a bitwise OR of all the + * {@code WireAdminEvent} types the Wire Admin Listener service wishes to + * receive and must be of type {@code Integer}. + * + * @see WireAdminEvent + */ + public final static String WIREADMIN_EVENTS = "wireadmin.events"; +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/WirePermission.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/WirePermission.java new file mode 100644 index 000000000..99a7e308b --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/WirePermission.java @@ -0,0 +1,459 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.wireadmin; + +import java.io.IOException; +import java.security.BasicPermission; +import java.security.Permission; +import java.security.PermissionCollection; +import java.util.Enumeration; +import java.util.Hashtable; + +/** + * Permission for the scope of a {@code Wire} object. When a {@code Envelope} + * object is used for communication with the {@code poll} or {@code update} + * method, and the scope is set, then the {@code Wire} object must verify that + * the Consumer service has {@code WirePermission[name,CONSUME]} and the + * Producer service has {@code WirePermission[name,PRODUCE]} for all names in + * the scope. + * <p> + * The names are compared with the normal rules for permission names. This means + * that they may end with a "*" to indicate wildcards. E.g. Door.* indicates all + * scope names starting with the string "Door". The last period is required due + * to the implementations of the {@code BasicPermission} class. + * + * @ThreadSafe + * @author $Id$ + */ +final public class WirePermission extends BasicPermission { + static final long serialVersionUID = -5583709391516569321L; + /** + * The action string for the {@code produce} action. + */ + public static final String PRODUCE = "produce"; + /** + * The action string for the {@code consume} action. + */ + public static final String CONSUME = "consume"; + private final static int ACTION_PRODUCE = 0x00000001; + private final static int ACTION_CONSUME = 0x00000002; + private final static int ACTION_ALL = ACTION_PRODUCE | ACTION_CONSUME; + private final static int ACTION_NONE = 0; + /** + * The actions mask. + */ + private transient int action_mask; + /** + * The actions in canonical form. + * + * @serial + */ + private volatile String actions = null; + + /** + * Create a new WirePermission with the given name (may be wildcard) and + * actions. + * + * @param name Wire name. + * @param actions {@code produce}, {@code consume} (canonical order). + */ + public WirePermission(String name, String actions) { + this(name, parseActions(actions)); + } + + /** + * Package private constructor used by WirePermissionCollection. + * + * @param name class name + * @param mask action mask + */ + WirePermission(String name, int mask) { + super(name); + setTransients(mask); + } + + /** + * Called by constructors and when deserialized. + * + * @param mask action mask + */ + private synchronized void setTransients(int mask) { + if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) { + throw new IllegalArgumentException("invalid action string"); + } + action_mask = mask; + } + + /** + * Returns the current action mask. Used by the WirePermissionCollection + * object. + * + * @return The actions mask. + */ + synchronized int getActionsMask() { + return action_mask; + } + + /** + * Parse action string into action mask. + * + * @param actions Action string. + * @return action mask. + */ + private static int parseActions(String actions) { + boolean seencomma = false; + int mask = ACTION_NONE; + if (actions == null) { + return mask; + } + char[] a = actions.toCharArray(); + int i = a.length - 1; + if (i < 0) + return mask; + while (i != -1) { + char c; + // skip whitespace + while ((i != -1) && ((c = a[i]) == ' ' || c == '\r' || c == '\n' || c == '\f' || c == '\t')) + i--; + // check for the known strings + int matchlen; + if (i >= 6 && (a[i - 6] == 'p' || a[i - 6] == 'P') && (a[i - 5] == 'r' || a[i - 5] == 'R') && (a[i - 4] == 'o' || a[i - 4] == 'O') && (a[i - 3] == 'd' || a[i - 3] == 'D') + && (a[i - 2] == 'u' || a[i - 2] == 'U') && (a[i - 1] == 'c' || a[i - 1] == 'C') && (a[i] == 'e' || a[i] == 'E')) { + matchlen = 7; + mask |= ACTION_PRODUCE; + } else + if (i >= 6 && (a[i - 6] == 'c' || a[i - 6] == 'C') && (a[i - 5] == 'o' || a[i - 5] == 'O') && (a[i - 4] == 'n' || a[i - 4] == 'N') && (a[i - 3] == 's' || a[i - 3] == 'S') + && (a[i - 2] == 'u' || a[i - 2] == 'U') && (a[i - 1] == 'm' || a[i - 1] == 'M') && (a[i] == 'e' || a[i] == 'E')) { + matchlen = 7; + mask |= ACTION_CONSUME; + } else { + // parse error + throw new IllegalArgumentException("invalid permission: " + actions); + } + // make sure we didn't just match the tail of a word + // like "ackbarfregister". Also, skip to the comma. + seencomma = false; + while (i >= matchlen && !seencomma) { + switch (a[i - matchlen]) { + case ',' : + seencomma = true; + /* FALLTHROUGH */ + case ' ' : + case '\r' : + case '\n' : + case '\f' : + case '\t' : + break; + default : + throw new IllegalArgumentException("invalid permission: " + actions); + } + i--; + } + // point i at the location of the comma minus one (or -1). + i -= matchlen; + } + if (seencomma) { + throw new IllegalArgumentException("invalid permission: " + actions); + } + return mask; + } + + /** + * Checks if this {@code WirePermission} object {@code implies} the + * specified permission. + * <P> + * More specifically, this method returns {@code true} if: + * <p> + * <ul> + * <li><i>p</i> is an instanceof the {@code WirePermission} class,</li> + * <li><i>p</i>'s actions are a proper subset of this object's actions, and</li> + * <li><i>p</i>'s name is implied by this object's name. For example, + * {@code java.*} implies {@code java.home}.</li> + * </ul> + * + * @param p The permission to check against. + * + * @return {@code true} if the specified permission is implied by this + * object; {@code false} otherwise. + */ + public boolean implies(Permission p) { + if (p instanceof WirePermission) { + WirePermission requested = (WirePermission) p; + int requestedMask = requested.getActionsMask(); + return ((getActionsMask() & requestedMask) == requestedMask) && super.implies(p); + } + return false; + } + + /** + * Returns the canonical string representation of the actions. Always + * returns present actions in the following order: {@code produce}, + * {@code consume}. + * + * @return The canonical string representation of the actions. + */ + public String getActions() { + String result = actions; + if (result == null) { + StringBuffer sb = new StringBuffer(); + boolean comma = false; + int mask = getActionsMask(); + if ((mask & ACTION_PRODUCE) == ACTION_PRODUCE) { + sb.append(PRODUCE); + comma = true; + } + if ((mask & ACTION_CONSUME) == ACTION_CONSUME) { + if (comma) + sb.append(','); + sb.append(CONSUME); + } + actions = result = sb.toString(); + } + return result; + } + + /** + * Returns a new {@code PermissionCollection} object for storing + * {@code WirePermission} objects. + * + * @return A new {@code PermissionCollection} object suitable for storing + * {@code WirePermission} objects. + */ + public PermissionCollection newPermissionCollection() { + return new WirePermissionCollection(); + } + + /** + * Determines the equalty of two {@code WirePermission} objects. + * + * Checks that specified object has the same name and actions as this + * {@code WirePermission} object. + * + * @param obj The object to test for equality. + * @return true if {@code obj} is a {@code WirePermission}, and has the same + * name and actions as this {@code WirePermission} object; + * {@code false} otherwise. + */ + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof WirePermission)) { + return false; + } + WirePermission wp = (WirePermission) obj; + return (getActionsMask() == wp.getActionsMask()) && getName().equals(wp.getName()); + } + + /** + * Returns the hash code value for this object. + * + * @return Hash code value for this object. + */ + public int hashCode() { + int h = 31 * 17 + getName().hashCode(); + h = 31 * h + getActions().hashCode(); + return h; + } + + /** + * Returns a string describing this {@code WirePermission}. The convention + * is to specify the class name, the permission name, and the actions in the + * following format: '(org.osgi.service.wireadmin.WirePermission + * "name" "actions")'. + * + * @return information about this {@code Permission} object. + */ + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append('('); + sb.append(getClass().getName()); + sb.append(" \""); + sb.append(getName()); + String a = getActions(); + if (a.length() > 0) { + sb.append("\" \""); + sb.append(a); + } + sb.append("\")"); + return sb.toString(); + } + + /** + * WriteObject is called to save the state of the ServicePermission to a + * stream. The actions are serialized, and the superclass takes care of the + * name. + */ + private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { + // Write out the actions. The superclass takes care of the name + // call getActions to make sure actions field is initialized + if (actions == null) + getActions(); + s.defaultWriteObject(); + } + + /** + * readObject is called to restore the state of the ServicePermission from a + * stream. + */ + private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { + // Read in the action, then initialize the rest + s.defaultReadObject(); + setTransients(parseActions(actions)); + } +} + +/** + * A {@code WirePermissionCollection} stores a set of {@code WirePermission} + * permissions. + */ + +final class WirePermissionCollection extends PermissionCollection { + static final long serialVersionUID = 2617521094909826016L; + /** + * Table of permissions. + * + * @GuardedBy this + * @serial + */ + private final Hashtable permissions; + /** + * Boolean saying if "*" is in the collection. + * + * @GuardedBy this + * @serial + */ + private boolean all_allowed; + + /** + * Creates an empty WirePermissionCollection object. + * + */ + public WirePermissionCollection() { + permissions = new Hashtable(); + all_allowed = false; + } + + /** + * Adds a permission to this PermissionCollection. + * + * @param permission The Permission object to add. + * + * @throws IllegalArgumentException If the permission is not a + * WirePermission object. + * + * @throws SecurityException If this PermissionCollection has been marked + * read-only. + */ + public void add(Permission permission) { + if (!(permission instanceof WirePermission)) { + throw new IllegalArgumentException("invalid permission: " + permission); + } + if (isReadOnly()) { + throw new SecurityException("attempt to add a Permission to a " + "readonly PermissionCollection"); + } + WirePermission wp = (WirePermission) permission; + String name = wp.getName(); + synchronized (this) { + WirePermission existing = (WirePermission) permissions.get(name); + if (existing != null) { + int oldMask = existing.getActionsMask(); + int newMask = wp.getActionsMask(); + if (oldMask != newMask) { + permissions.put(name, new WirePermission(name, oldMask | newMask)); + } + } else { + permissions.put(name, wp); + } + if (!all_allowed) { + if (name.equals("*")) { + all_allowed = true; + } + } + } + } + + /** + * Determines if a set of permissions implies the permissions expressed in + * {@code permission}. + * + * @param permission The Permission object to compare. + * + * @return {@code true} if {@code permission} is a proper subset of a + * permission in the set; {@code false} otherwise. + */ + public boolean implies(Permission permission) { + if (!(permission instanceof WirePermission)) { + return false; + } + WirePermission requested = (WirePermission) permission; + WirePermission x; + int desired = requested.getActionsMask(); + int effective = 0; + String name = requested.getName(); + synchronized (this) { + // short circuit if the "*" Permission was added + if (all_allowed) { + x = (WirePermission) permissions.get("*"); + if (x != null) { + effective |= x.getActionsMask(); + if ((effective & desired) == desired) + return true; + } + } + // strategy: + // Check for full match first. Then work our way up the + // name looking for matches on a.b.* + x = (WirePermission) permissions.get(name); + } + if (x != null) { + // we have a direct hit! + effective |= x.getActionsMask(); + if ((effective & desired) == desired) { + return true; + } + } + // work our way up the tree... + int last; + int offset = name.length() - 1; + while ((last = name.lastIndexOf(".", offset)) != -1) { + name = name.substring(0, last + 1) + "*"; + synchronized (this) { + x = (WirePermission) permissions.get(name); + } + if (x != null) { + effective |= x.getActionsMask(); + if ((effective & desired) == desired) { + return (true); + } + } + offset = last - 1; + } + // we don't have to check for "*" as it was already checked + // at the top (all_allowed), so we just return false + return false; + } + + /** + * Returns an enumeration of all the Permission objects in the container. + * + * @return Enumeration of all the Permission objects. + */ + public Enumeration elements() { + return permissions.elements(); + } +} diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/package-info.java b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/package-info.java new file mode 100644 index 000000000..b5af96bb0 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/package-info.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) OSGi Alliance (2010, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Wire Admin Package Version 1.0. + * + * <p> + * Bundles wishing to use this package must list the package in the + * Import-Package header of the bundle's manifest. This package has two types of + * users: the consumers that use the API in this package and the providers that + * implement the API in this package. + * + * <p> + * Example import for consumers using the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.wireadmin; version="[1.0,2.0)"} + * <p> + * Example import for providers implementing the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.wireadmin; version="[1.0,1.1)"} + * + * @version 1.0.1 + * @author $Id$ + */ + +package org.osgi.service.wireadmin; + diff --git a/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/packageinfo b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/packageinfo new file mode 100644 index 000000000..b3d1f97f7 --- /dev/null +++ b/bundles/org.eclipse.osgi.services/src/org/osgi/service/wireadmin/packageinfo @@ -0,0 +1 @@ +version 1.0.1 diff --git a/bundles/org.eclipse.osgi.util/.classpath b/bundles/org.eclipse.osgi.util/.classpath index ad7732cd3..64c5e31b7 100644 --- a/bundles/org.eclipse.osgi.util/.classpath +++ b/bundles/org.eclipse.osgi.util/.classpath @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> - <classpathentry path="" kind="lib" sourcepath="src.zip"/> - <classpathentry path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/OSGi%Minimum-1.2" kind="con"/> - <classpathentry path="org.eclipse.pde.core.requiredPlugins" kind="con"/> - <classpathentry path="bin" kind="output"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="output" path="bin"/> </classpath> diff --git a/bundles/org.eclipse.osgi.util/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.osgi.util/.settings/org.eclipse.jdt.core.prefs index f786cfa0a..db619c076 100644 --- a/bundles/org.eclipse.osgi.util/.settings/org.eclipse.jdt.core.prefs +++ b/bundles/org.eclipse.osgi.util/.settings/org.eclipse.jdt.core.prefs @@ -1,4 +1,3 @@ -#Tue Jun 06 11:23:10 CDT 2006 eclipse.preferences.version=1 org.eclipse.jdt.core.builder.cleanOutputFolder=clean org.eclipse.jdt.core.builder.duplicateResourceTask=warning @@ -7,24 +6,24 @@ org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch org.eclipse.jdt.core.circularClasspath=error org.eclipse.jdt.core.classpath.exclusionPatterns=enabled org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=disabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.3 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.doc.comment.support=enabled org.eclipse.jdt.core.compiler.maxProblemPerUnit=1000 org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning -org.eclipse.jdt.core.compiler.problem.assertIdentifier=ignore +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.autoboxing=ignore org.eclipse.jdt.core.compiler.problem.deprecation=warning org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled org.eclipse.jdt.core.compiler.problem.discouragedReference=error org.eclipse.jdt.core.compiler.problem.emptyStatement=warning -org.eclipse.jdt.core.compiler.problem.enumIdentifier=ignore +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.fieldHiding=warning org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning @@ -71,6 +70,6 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=en org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning -org.eclipse.jdt.core.compiler.source=1.3 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.incompatibleJDKLevel=ignore org.eclipse.jdt.core.incompleteClasspath=error diff --git a/bundles/org.eclipse.osgi.util/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi.util/META-INF/MANIFEST.MF index 0455dd4be..0743c7661 100644 --- a/bundles/org.eclipse.osgi.util/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.osgi.util/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %osgiUtil Bundle-SymbolicName: org.eclipse.osgi.util -Bundle-Version: 3.2.300.qualifier +Bundle-Version: 3.3.0.qualifier Bundle-Description: %osgiUtilDes Bundle-Vendor: %eclipse.org Bundle-Localization: plugin @@ -12,10 +12,8 @@ Export-Package: org.osgi.util.measurement; version="1.0.1", org.osgi.util.position; version="1.0.1", org.osgi.util.xml; version="1.0.1" Import-Package: org.osgi.framework; version=1.1, - javax.xml.parsers; resolution:=optional, + javax.xml.parsers, org.osgi.util.measurement; version="[1.0.1, 1.2)", org.osgi.util.position; version="[1.0.1, 1.2)", org.osgi.util.xml; version="[1.0.1, 1.2)" -Bundle-RequiredExecutionEnvironment: OSGi/Minimum-1.2, - CDC-1.1/Foundation-1.1, - J2SE-1.4 +Bundle-RequiredExecutionEnvironment: J2SE-1.5 diff --git a/bundles/org.eclipse.osgi.util/build.properties b/bundles/org.eclipse.osgi.util/build.properties index 7e2fef041..f11b00703 100644 --- a/bundles/org.eclipse.osgi.util/build.properties +++ b/bundles/org.eclipse.osgi.util/build.properties @@ -9,15 +9,10 @@ # IBM Corporation - initial API and implementation ############################################################################### bin.includes = plugin.properties,\ - org/,\ about.html,\ META-INF/,\ about_files/ -src.includes = src.zip,\ - about.html,\ +src.includes = about.html,\ about_files/ -source.. = . -output.. = . -customBuildCallbacks=customBuildCallbacks.xml -javacSource = 1.5 -javacTarget = 1.5 +source.. = src/ +output.. = bin/ diff --git a/bundles/org.eclipse.osgi.util/customBuildCallbacks.xml b/bundles/org.eclipse.osgi.util/customBuildCallbacks.xml deleted file mode 100644 index d6250e891..000000000 --- a/bundles/org.eclipse.osgi.util/customBuildCallbacks.xml +++ /dev/null @@ -1,162 +0,0 @@ -<!-- ===================================================================== --> -<!-- Custom targets called from a project's generated build.xml --> -<!-- Set customBuildCallbacks=<path/to/this/file> in your build.properties.--> -<!-- ===================================================================== --> -<project name="Build specific targets and properties" default="noDefault"> - - <!-- ===================================================================== --> - <!-- Default target --> - <!-- ===================================================================== --> - <target name="noDefault"> - <echo message="This file must be called with explicit targets" /> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do before the target build.jars --> - <!-- Available parameters : --> - <!-- build.result.folder - folder to contain the build results --> - <!-- ===================================================================== --> - <target name="pre.build.jars"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do after the target build.jars --> - <!-- Available parameters : --> - <!-- build.result.folder - folder to contain the build results --> - <!-- ===================================================================== --> - <target name="post.build.jars"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do before the target build.sources --> - <!-- Available parameters : --> - <!-- build.result.folder - folder to contain the build results --> - <!-- ===================================================================== --> - <target name="pre.build.sources"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do after the target build.sources --> - <!-- Available parameters : --> - <!-- build.result.folder - folder to contain the build results --> - <!-- ===================================================================== --> - <target name="post.build.sources"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do before the compilation target <name> --> - <!-- Substitute "name" with the name of the compilation target, eg @dot --> - <!-- Available parameters : --> - <!-- source.foldern : n = 1 ... N, the source folders --> - <!-- target.folder : where the results of the compilation go --> - <!-- <name>.classpath : name = name of the compilation target. A --> - <!-- reference to the classpath structure. --> - <!-- ===================================================================== --> - <target name="pre.name"> - </target> - - <target name="pre.@dot"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do during the compilation target <name>, after the compile --> - <!-- but before jaring. Substitute "name" with the name of the compilation--> - <!-- target, eg @dot --> - <!-- Available parameters : --> - <!-- source.foldern : n = 1 ... N, the source folders --> - <!-- target.folder : where the results of the compilation go --> - <!-- <name>.classpath : name = name of the compilation target. A --> - <!-- reference to the classpath structure. --> - <!-- ===================================================================== --> - <target name="post.compile.name"> - </target> - - <target name="post.compile.@dot"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do after the compilation target <name> --> - <!-- Substitute "name" with the name of the compilation target, eg @dot --> - <!-- Available parameters : --> - <!-- jar.location - the location of the compilation results --> - <!-- <name>.classpath : name = name of the compilation target. A --> - <!-- reference to the classpath structure. --> - <!-- ===================================================================== --> - <target name="post.name"> - </target> - - <target name="post.@dot"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do before the target gather.bin.parts --> - <!-- Available parameters : --> - <!-- build.result.folder - folder containing the build results --> - <!-- target.folder - destination folder --> - <!-- ===================================================================== --> - <target name="pre.gather.bin.parts"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do after the target gather.bin.parts --> - <!-- Available parameters : --> - <!-- build.result.folder - folder containing the build results --> - <!-- target.folder - destination folder --> - <!-- ===================================================================== --> - <target name="post.gather.bin.parts"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do before the target gather.sources --> - <!-- Available parameters : --> - <!-- destination.temp.folder - destination folder --> - <!-- ===================================================================== --> - <target name="pre.gather.sources"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do after the target gather.sources --> - <!-- Available parameters : --> - <!-- destination.temp.folder - destination folder --> - <!-- ===================================================================== --> - <target name="post.gather.sources"> - <unzip src="${target.folder}/src.zip" dest="${target.folder}" overwrite="false"/> - <delete file="${destination.temp.folder}/src.zip" /> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do before the target gather.logs --> - <!-- Available parameters : --> - <!-- destination.temp.folder - destination folder --> - <!-- ===================================================================== --> - <target name="pre.gather.logs"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do after the target gather.logs --> - <!-- Available parameters : --> - <!-- destination.temp.folder - destination folder --> - <!-- ===================================================================== --> - <target name="post.gather.logs"> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do before the target clean --> - <!-- Available parameters : --> - <!-- destination.temp.folder - destination folder --> - <!-- ===================================================================== --> - <target name="pre.clean"> - <move file="src.zip" tofile="util_src.zip"/> - </target> - - <!-- ===================================================================== --> - <!-- Steps to do after the target clean --> - <!-- Available parameters : --> - <!-- plugin.destination - final destination of the build --> - <!-- build.result.folder - results of the compilation --> - <!-- temp.folder - temporary folder --> - <!-- ===================================================================== --> - <target name="post.clean"> - <move file="util_src.zip" tofile="src.zip"/> - </target> -</project> diff --git a/bundles/org.eclipse.osgi.util/org/osgi/util/measurement/Measurement.class b/bundles/org.eclipse.osgi.util/org/osgi/util/measurement/Measurement.class Binary files differdeleted file mode 100644 index dc157cc49..000000000 --- a/bundles/org.eclipse.osgi.util/org/osgi/util/measurement/Measurement.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.util/org/osgi/util/measurement/State.class b/bundles/org.eclipse.osgi.util/org/osgi/util/measurement/State.class Binary files differdeleted file mode 100644 index 8e13882cd..000000000 --- a/bundles/org.eclipse.osgi.util/org/osgi/util/measurement/State.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.util/org/osgi/util/measurement/Unit.class b/bundles/org.eclipse.osgi.util/org/osgi/util/measurement/Unit.class Binary files differdeleted file mode 100644 index 7968831e7..000000000 --- a/bundles/org.eclipse.osgi.util/org/osgi/util/measurement/Unit.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.util/org/osgi/util/position/Position.class b/bundles/org.eclipse.osgi.util/org/osgi/util/position/Position.class Binary files differdeleted file mode 100644 index 2ff9b049f..000000000 --- a/bundles/org.eclipse.osgi.util/org/osgi/util/position/Position.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.util/org/osgi/util/xml/XMLParserActivator.class b/bundles/org.eclipse.osgi.util/org/osgi/util/xml/XMLParserActivator.class Binary files differdeleted file mode 100644 index 44540fb20..000000000 --- a/bundles/org.eclipse.osgi.util/org/osgi/util/xml/XMLParserActivator.class +++ /dev/null diff --git a/bundles/org.eclipse.osgi.util/pom.xml b/bundles/org.eclipse.osgi.util/pom.xml index 15ecddb61..bee575bd9 100644 --- a/bundles/org.eclipse.osgi.util/pom.xml +++ b/bundles/org.eclipse.osgi.util/pom.xml @@ -19,6 +19,6 @@ </parent> <groupId>org.eclipse.osgi</groupId> <artifactId>org.eclipse.osgi.util</artifactId> - <version>3.2.300-SNAPSHOT</version> + <version>3.3.0-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> </project> diff --git a/bundles/org.eclipse.osgi.util/src.zip b/bundles/org.eclipse.osgi.util/src.zip Binary files differdeleted file mode 100644 index 9d64d7b27..000000000 --- a/bundles/org.eclipse.osgi.util/src.zip +++ /dev/null diff --git a/bundles/org.eclipse.osgi.util/src/org/osgi/util/measurement/Measurement.java b/bundles/org.eclipse.osgi.util/src/org/osgi/util/measurement/Measurement.java new file mode 100644 index 000000000..5d6be0f87 --- /dev/null +++ b/bundles/org.eclipse.osgi.util/src/org/osgi/util/measurement/Measurement.java @@ -0,0 +1,476 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.util.measurement; + +/** + * Represents a value with an error, a unit and a time-stamp. + * + * <p> + * A {@code Measurement} object is used for maintaining the tuple of value, + * error, unit and time-stamp. The value and error are represented as doubles + * and the time is measured in milliseconds since midnight, January 1, 1970 UTC. + * + * <p> + * Mathematic methods are provided that correctly calculate taking the error + * into account. A runtime error will occur when two measurements are used in an + * incompatible way. E.g., when a speed (m/s) is added to a distance (m). The + * measurement class will correctly track changes in unit during multiplication + * and division, always coercing the result to the most simple form. See + * {@link Unit} for more information on the supported units. + * + * <p> + * Errors in the measurement class are absolute errors. Measurement errors + * should use the P95 rule. Actual values must fall in the range value +/- error + * 95% or more of the time. + * + * <p> + * A {@code Measurement} object is immutable in order to be easily shared. + * + * <p> + * Note: This class has a natural ordering that is inconsistent with equals. See + * {@link #compareTo(Object)}. + * + * @Immutable + * @author $Id$ + */ +public class Measurement implements Comparable { + private final double value; + private final double error; + private final long time; + private final Unit unit; + private transient String name; + private transient int hashCode; + + /** + * Create a new {@code Measurement} object. + * + * @param value The value of the {@code Measurement}. + * @param error The error of the {@code Measurement}. + * @param unit The {@code Unit} object in which the value is measured. If + * this argument is {@code null}, then the unit will be set to + * {@link Unit#unity}. + * @param time The time measured in milliseconds since midnight, January 1, + * 1970 UTC. + */ + public Measurement(double value, double error, Unit unit, long time) { + this.value = value; + this.error = Math.abs(error); + this.unit = (unit != null) ? unit : Unit.unity; + this.time = time; + name = null; + hashCode = 0; + } + + /** + * Create a new {@code Measurement} object with a time of zero. + * + * @param value The value of the {@code Measurement}. + * @param error The error of the {@code Measurement}. + * @param unit The {@code Unit} object in which the value is measured. If + * this argument is {@code null}, then the unit will be set to + * {@link Unit#unity}. + */ + public Measurement(double value, double error, Unit unit) { + this(value, error, unit, 0l); + } + + /** + * Create a new {@code Measurement} object with an error of 0.0 and a time + * of zero. + * + * @param value The value of the {@code Measurement}. + * @param unit The {@code Unit} in which the value is measured. If this + * argument is {@code null}, then the unit will be set to + * {@link Unit#unity}. + */ + public Measurement(double value, Unit unit) { + this(value, 0.0d, unit, 0l); + } + + /** + * Create a new {@code Measurement} object with an error of 0.0, a unit of + * {@link Unit#unity} and a time of zero. + * + * @param value The value of the {@code Measurement}. + */ + public Measurement(double value) { + this(value, 0.0d, null, 0l); + } + + /** + * Returns the value of this {@code Measurement} object. + * + * @return The value of this {@code Measurement} object as a double. + */ + public final double getValue() { + return value; + } + + /** + * Returns the error of this {@code Measurement} object. The error is always + * a positive value. + * + * @return The error of this {@code Measurement} as a double. + */ + public final double getError() { + return error; + } + + /** + * Returns the {@code Unit} object of this {@code Measurement} object. + * + * @return The {@code Unit} object of this {@code Measurement} object. + * + * @see Unit + */ + public final Unit getUnit() { + return unit; + } + + /** + * Returns the time at which this {@code Measurement} object was taken. The + * time is measured in milliseconds since midnight, January 1, 1970 UTC, or + * zero when not defined. + * + * @return The time at which this {@code Measurement} object was taken or + * zero. + */ + public final long getTime() { + return time; + } + + /** + * Returns a new {@code Measurement} object that is the product of this + * object multiplied by the specified object. + * + * @param m The {@code Measurement} object that will be multiplied with this + * object. + * @return A new {@code Measurement} that is the product of this object + * multiplied by the specified object. The error and unit of the new + * object are computed. The time of the new object is set to the + * time of this object. + * @throws ArithmeticException If the {@code Unit} objects of this object + * and the specified object cannot be multiplied. + * @see Unit + */ + public Measurement mul(Measurement m) { + double mvalue = m.value; + return new Measurement(value * mvalue, Math.abs(value) * m.error + error * Math.abs(mvalue), unit.mul(m.unit), time); + } + + /** + * Returns a new {@code Measurement} object that is the product of this + * object multiplied by the specified value. + * + * @param d The value that will be multiplied with this object. + * @param u The {@code Unit} of the specified value. + * @return A new {@code Measurement} object that is the product of this + * object multiplied by the specified value. The error and unit of + * the new object are computed. The time of the new object is set to + * the time of this object. + * @throws ArithmeticException If the units of this object and the specified + * value cannot be multiplied. + * @see Unit + */ + public Measurement mul(double d, Unit u) { + return new Measurement(value * d, error * Math.abs(d), unit.mul(u), time); + } + + /** + * Returns a new {@code Measurement} object that is the product of this + * object multiplied by the specified value. + * + * @param d The value that will be multiplied with this object. + * @return A new {@code Measurement} object that is the product of this + * object multiplied by the specified value. The error of the new + * object is computed. The unit and time of the new object is set to + * the unit and time of this object. + */ + public Measurement mul(double d) { + return new Measurement(value * d, error * Math.abs(d), unit, time); + } + + /** + * Returns a new {@code Measurement} object that is the quotient of this + * object divided by the specified object. + * + * @param m The {@code Measurement} object that will be the divisor of this + * object. + * @return A new {@code Measurement} object that is the quotient of this + * object divided by the specified object. The error and unit of the + * new object are computed. The time of the new object is set to the + * time of this object. + * @throws ArithmeticException If the {@code Unit} objects of this object + * and the specified object cannot be divided. + * @see Unit + */ + public Measurement div(Measurement m) { + double mvalue = m.value; + return new Measurement(value / mvalue, (Math.abs(value) * m.error + error * Math.abs(mvalue)) / (mvalue * mvalue), unit.div(m.unit), time); + } + + /** + * Returns a new {@code Measurement} object that is the quotient of this + * object divided by the specified value. + * + * @param d The value that will be the divisor of this object. + * @param u The {@code Unit} object of the specified value. + * @return A new {@code Measurement} that is the quotient of this object + * divided by the specified value. The error and unit of the new + * object are computed. The time of the new object is set to the + * time of this object. + * @throws ArithmeticException If the {@code Unit} objects of this object + * and the specified object cannot be divided. + * @see Unit + */ + public Measurement div(double d, Unit u) { + return new Measurement(value / d, error / Math.abs(d), unit.div(u), time); + } + + /** + * Returns a new {@code Measurement} object that is the quotient of this + * object divided by the specified value. + * + * @param d The value that will be the divisor of this object. + * @return A new {@code Measurement} object that is the quotient of this + * object divided by the specified value. The error of the new + * object is computed. The unit and time of the new object is set to + * the {@code Unit} and time of this object. + */ + public Measurement div(double d) { + return new Measurement(value / d, error / Math.abs(d), unit, time); + } + + /** + * Returns a new {@code Measurement} object that is the sum of this object + * added to the specified object. + * + * The error and unit of the new object are computed. The time of the new + * object is set to the time of this object. + * + * @param m The {@code Measurement} object that will be added with this + * object. + * @return A new {@code Measurement} object that is the sum of this and m. + * @see Unit + * @throws ArithmeticException If the {@code Unit} objects of this object + * and the specified object cannot be added. + */ + public Measurement add(Measurement m) { + return new Measurement(value + m.value, error + m.error, unit.add(m.unit), time); + } + + /** + * Returns a new {@code Measurement} object that is the sum of this object + * added to the specified value. + * + * @param d The value that will be added with this object. + * @param u The {@code Unit} object of the specified value. + * @return A new {@code Measurement} object that is the sum of this object + * added to the specified value. The unit of the new object is + * computed. The error and time of the new object is set to the + * error and time of this object. + * @throws ArithmeticException If the {@code Unit} objects of this object + * and the specified value cannot be added. + * @see Unit + */ + public Measurement add(double d, Unit u) { + return new Measurement(value + d, error, unit.add(u), time); + } + + /** + * Returns a new {@code Measurement} object that is the sum of this object + * added to the specified value. + * + * @param d The value that will be added with this object. + * @return A new {@code Measurement} object that is the sum of this object + * added to the specified value. The error, unit, and time of the + * new object is set to the error, {@code Unit} and time of this + * object. + */ + public Measurement add(double d) { + return new Measurement(value + d, error, unit, time); + } + + /** + * Returns a new {@code Measurement} object that is the subtraction of the + * specified object from this object. + * + * @param m The {@code Measurement} object that will be subtracted from this + * object. + * @return A new {@code Measurement} object that is the subtraction of the + * specified object from this object. The error and unit of the new + * object are computed. The time of the new object is set to the + * time of this object. + * @throws ArithmeticException If the {@code Unit} objects of this object + * and the specified object cannot be subtracted. + * @see Unit + */ + public Measurement sub(Measurement m) { + return new Measurement(value - m.value, error + m.error, unit.sub(m.unit), time); + } + + /** + * Returns a new {@code Measurement} object that is the subtraction of the + * specified value from this object. + * + * @param d The value that will be subtracted from this object. + * @param u The {@code Unit} object of the specified value. + * @return A new {@code Measurement} object that is the subtraction of the + * specified value from this object. The unit of the new object is + * computed. The error and time of the new object is set to the + * error and time of this object. + * @throws ArithmeticException If the {@code Unit} objects of this object + * and the specified object cannot be subtracted. + * @see Unit + */ + public Measurement sub(double d, Unit u) { + return new Measurement(value - d, error, unit.sub(u), time); + } + + /** + * Returns a new {@code Measurement} object that is the subtraction of the + * specified value from this object. + * + * @param d The value that will be subtracted from this object. + * @return A new {@code Measurement} object that is the subtraction of the + * specified value from this object. The error, unit and time of the + * new object is set to the error, {@code Unit} object and time of + * this object. + */ + public Measurement sub(double d) { + return new Measurement(value - d, error, unit, time); + } + + /** + * Returns a {@code String} object representing this {@code Measurement} + * object. + * + * @return a {@code String} object representing this {@code Measurement} + * object. + */ + public String toString() { + String result = name; + if (result == null) { + StringBuffer sb = new StringBuffer(); + sb.append(value); + if (error != 0.0d) { + sb.append(" +/- "); + sb.append(error); + } + String u = unit.toString(); + if (u.length() > 0) { + sb.append(" "); + sb.append(u); + } + result = sb.toString(); + name = result; + } + return result; + } + + /** + * Compares this object with the specified object for order. Returns a + * negative integer, zero, or a positive integer if this object is less + * than, equal to, or greater than the specified object. + * + * <p> + * Note: This class has a natural ordering that is inconsistent with equals. + * For this method, another {@code Measurement} object is considered equal + * if there is some {@code x} such that + * + * <pre> + * getValue() - getError() <= x <= getValue() + getError() + * </pre> + * + * for both {@code Measurement} objects being compared. + * + * @param obj The object to be compared. + * @return A negative integer, zero, or a positive integer if this object is + * less than, equal to, or greater than the specified object. + * + * @throws ClassCastException If the specified object is not of type + * {@code Measurement}. + * @throws ArithmeticException If the unit of the specified + * {@code Measurement} object is not equal to the {@code Unit} + * object of this object. + */ + public int compareTo(Object obj) { + if (this == obj) { + return 0; + } + Measurement that = (Measurement) obj; + if (!unit.equals(that.unit)) { + throw new ArithmeticException("Cannot compare " + this + " and " + that); + } + int result = Double.compare(value, that.value); + if (result == 0) { + return 0; + } + if (result < 0) { + if (Double.compare(value + error, that.value - that.error) >= 0) { + return 0; + } + return -1; + } + if (Double.compare(value - error, that.value + that.error) <= 0) { + return 0; + } + return 1; + } + + /** + * Returns a hash code value for this object. + * + * @return A hash code value for this object. + */ + public int hashCode() { + int h = hashCode; + if (h == 0) { + long bits = Double.doubleToLongBits(value); + h = 31 * 17 + ((int) (bits ^ (bits >>> 32))); + bits = Double.doubleToLongBits(error); + h = 31 * h + ((int) (bits ^ (bits >>> 32))); + h = 31 * h + unit.hashCode(); + hashCode = h; + } + return h; + } + + /** + * Returns whether the specified object is equal to this object. Two + * {@code Measurement} objects are equal if they have same value, error and + * {@code Unit}. + * + * <p> + * Note: This class has a natural ordering that is inconsistent with equals. + * See {@link #compareTo(Object)}. + * + * @param obj The object to compare with this object. + * @return {@code true} if this object is equal to the specified object; + * {@code false} otherwise. + */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Measurement)) { + return false; + } + Measurement that = (Measurement) obj; + return (Double.compare(value, that.value) == 0) && (Double.compare(error, that.error) == 0) && unit.equals(that.unit); + } +} diff --git a/bundles/org.eclipse.osgi.util/src/org/osgi/util/measurement/State.java b/bundles/org.eclipse.osgi.util/src/org/osgi/util/measurement/State.java new file mode 100644 index 000000000..415613f39 --- /dev/null +++ b/bundles/org.eclipse.osgi.util/src/org/osgi/util/measurement/State.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.util.measurement; + +/** + * Groups a state name, value and timestamp. + * + * <p> + * The state itself is represented as an integer and the time is measured in + * milliseconds since midnight, January 1, 1970 UTC. + * + * <p> + * A {@code State} object is immutable so that it may be easily shared. + * + * @Immutable + * @author $Id$ + */ +public class State { + private final int value; + private final long time; + private final String name; + + /** + * Create a new {@code State} object. + * + * @param value The value of the state. + * @param name The name of the state. + * @param time The time measured in milliseconds since midnight, January 1, + * 1970 UTC. + */ + public State(int value, String name, long time) { + this.value = value; + this.name = name; + this.time = time; + } + + /** + * Create a new {@code State} object with a time of 0. + * + * @param value The value of the state. + * @param name The name of the state. + */ + public State(int value, String name) { + this(value, name, 0); + } + + /** + * Returns the value of this {@code State}. + * + * @return The value of this {@code State} object. + */ + public final int getValue() { + return value; + } + + /** + * Returns the time with which this {@code State} was created. + * + * @return The time with which this {@code State} was created. The time is + * measured in milliseconds since midnight, January 1, 1970 UTC. + */ + public final long getTime() { + return time; + } + + /** + * Returns the name of this {@code State}. + * + * @return The name of this {@code State} object. + */ + public final String getName() { + return name; + } + + /** + * Returns a {@code String} object representing this object. + * + * @return a {@code String} object representing this object. + */ + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append(value); + if (name != null) { + sb.append(" \""); + sb.append(name); + sb.append("\""); + } + return sb.toString(); + } + + /** + * Returns a hash code value for this object. + * + * @return A hash code value for this object. + */ + public int hashCode() { + int hash = 31 * 17 + value; + if (name != null) { + hash = 31 * hash + name.hashCode(); + } + return hash; + } + + /** + * Return whether the specified object is equal to this object. Two + * {@code State} objects are equal if they have same value and name. + * + * @param obj The object to compare with this object. + * @return {@code true} if this object is equal to the specified object; + * {@code false} otherwise. + */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof State)) { + return false; + } + State that = (State) obj; + if (value != that.value) { + return false; + } + if (name == that.name) { + return true; + } + if (name == null) { + return false; + } + return name.equals(that.name); + } +} diff --git a/bundles/org.eclipse.osgi.util/src/org/osgi/util/measurement/Unit.java b/bundles/org.eclipse.osgi.util/src/org/osgi/util/measurement/Unit.java new file mode 100644 index 000000000..e97563d26 --- /dev/null +++ b/bundles/org.eclipse.osgi.util/src/org/osgi/util/measurement/Unit.java @@ -0,0 +1,477 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.util.measurement; + +import java.util.Hashtable; + +/** + * A unit system for measurements. + * + * This class contains definitions of the most common SI units. + * <p> + * + * <p> + * This class only support exponents for the base SI units in the range -64 to + * +63. Any operation which produces an exponent outside of this range will + * result in a {@code Unit} object with undefined exponents. + * + * @Immutable + * @author $Id$ + */ +/* + * This local class maintains the information about units. It can calculate new + * units when two values are multiplied, divided, added or subtracted. <p> The + * unit works with the 7 basic SI types + rad + up to 2^6 custom types. For each + * type, the unit keeps a bit mask with the exponents of the basic types. Eg. + * m/s is m = 1, s = -1. Multiplying one unit with another means that the bit + * masks are added, dividing means that the bit masks are subtracted. <p> This + * class can handle any reasonable combination of SI units. However, it will + * always try to coerce results back into the basic set. E.g. when you do V*A + * you should get W and not m2.kg/s3 . Only when the existing types do not match + * does the unit fallback to the expanded form. <p> This class uses offset + * arithmetic. This means that the exponents are stored in an long. The special + * field is used for units that should not be arithmetically divided or + * multiplied, like longitude and lattitude. These special units can however, be + * divided and multiplied by the basic 7 constants of the SI, e.g. deg/s. + */ +public class Unit { + private final static long UNITY = createType(0, 0, 0, 0, 0, 0, 0, 0, 0); + private final static long ZERO = 0x40L; + private final static long MASK = 0x7fL; + private final static int m_SHIFT = 0; + private final static int s_SHIFT = 7; + private final static int kg_SHIFT = 14; + private final static int K_SHIFT = 21; + private final static int A_SHIFT = 28; + private final static int mol_SHIFT = 35; + private final static int cd_SHIFT = 42; + private final static int rad_SHIFT = 49; + private final static int x_SHIFT = 56; + private final static long x_MASK = MASK << x_SHIFT; + /** No Unit (Unity) */ + public final static Unit unity = new Unit("", UNITY); // Unity + /* SI Base Units */ + /** The length unit meter (m) */ + public final static Unit m = new Unit("m", createType(0, 0, 0, 0, 0, 0, 0, 0, 1)); // Distance + // meter + /** The time unit second (s) */ + public final static Unit s = new Unit("s", createType(0, 0, 0, 0, 0, 0, 0, 1, 0)); // Time + // Seconds + // s + /** The mass unit kilogram (kg) */ + public final static Unit kg = new Unit("kg", createType(0, 0, 0, 0, 0, 0, 1, 0, 0)); // Mass + // kilogram + // kg + /** The temperature unit kelvin (K) */ + public final static Unit K = new Unit("K", createType(0, 0, 0, 0, 0, 1, 0, 0, 0)); // Temperature + // kelvin + // K + /** The electric current unit ampere (A) */ + public final static Unit A = new Unit("A", createType(0, 0, 0, 0, 1, 0, 0, 0, 0)); // Current + // ampere + // A + /** The amount of substance unit mole (mol) */ + public final static Unit mol = new Unit("mol", createType(0, 0, 0, 1, 0, 0, 0, 0, 0)); // Substance + // mole + // mol + /** The luminous intensity unit candela (cd) */ + public final static Unit cd = new Unit("cd", createType(0, 0, 1, 0, 0, 0, 0, 0, 0)); // Light + // candela + // cd + /* SI Derived Units */ + /** The speed unit meter per second (m/s) */ + public final static Unit m_s = new Unit("m/s", createType(0, 0, 0, 0, 0, 0, 0, -1, 1)); // Speed + // m/s + /** The acceleration unit meter per second squared (m/s<sup>2</sup>) */ + public final static Unit m_s2 = new Unit("m/s2", createType(0, 0, 0, 0, 0, 0, 0, -2, 1)); // Acceleration + // m/s^2 + /** The area unit square meter (m<sup>2</sup>) */ + public final static Unit m2 = new Unit("m2", createType(0, 0, 0, 0, 0, 0, 0, 0, 2)); // Surface + // m^2 + /** The volume unit cubic meter (m<sup>3</sup>) */ + public final static Unit m3 = new Unit("m3", createType(0, 0, 0, 0, 0, 0, 0, 0, 3)); // Volume + // m^3 + /** + * The frequency unit hertz (Hz). + * <p> + * hertz is expressed in SI units as 1/s + */ + public final static Unit Hz = new Unit("Hz", createType(0, 0, 0, 0, 0, 0, 0, -1, 0)); // Frequency + // 1/s + /** + * The force unit newton (N). + * <p> + * N is expressed in SI units as m·kg/s<sup>2</sup> + */ + public final static Unit N = new Unit("N", createType(0, 0, 0, 0, 0, 0, 1, -2, 1)); // Force + // newton + // (m*kg)/s^2 + /** + * The pressure unit pascal (Pa). + * <p> + * Pa is equal to N/m<sup>2</sup> or is expressed in SI units as + * kg/m·s<sup>2</sup> + */ + public final static Unit Pa = new Unit("Pa", createType(0, 0, 0, 0, 0, 0, 1, -2, -1)); // Pressure + // pascal + // kg/(m*s^2) + /** + * The energy unit joule (J). + * <p> + * joule is equal to N·m or is expressed in SI units as + * m<sup>2</sup>·kg/s<sup>2</sup> + */ + public final static Unit J = new Unit("J", createType(0, 0, 0, 0, 0, 0, 1, -2, 2)); // Energy + // joule + // (m^2*kg)/s^2 + /** + * The power unit watt (W). + * <p> + * watt is equal to J/s or is expressed in SI units as + * m<sup>2</sup>·kg/s<sup>3</sup> + */ + public final static Unit W = new Unit("W", createType(0, 0, 0, 0, 0, 0, 1, -3, 2)); // Power + // watt + // (m^2*kg)/s^3 + /** + * The electric charge unit coulomb (C). + * <p> + * coulomb is expressed in SI units as s·A + */ + public final static Unit C = new Unit("C", createType(0, 0, 0, 0, 1, 0, 0, 1, 0)); // Charge + // coulumb + // s*A + /** + * The electric potential difference unit volt (V). + * <p> + * volt is equal to W/A or is expressed in SI units as + * m<sup>2</sup>·kg/s<sup>3</sup>·A + */ + public final static Unit V = new Unit("V", createType(0, 0, 0, 0, -1, 0, 1, -3, 2)); // El. + // Potent. + // volt + // (m^2*kg)/(s^3*A) + /** + * The capacitance unit farad (F). + * <p> + * farad is equal to C/V or is expressed in SI units as + * s<sup>4</sup>·A<sup>2</sup>/m<sup>2</sup>·kg + */ + public final static Unit F = new Unit("F", createType(0, 0, 0, 0, 2, 0, -1, 4, -2)); // Capacitance + // farad + // (s^4*A^2)/(m^2*kg) + /** + * The electric resistance unit ohm. + * <p> + * ohm is equal to V/A or is expressed in SI units as + * m<sup>2</sup>·kg/s<sup>3</sup>·A<sup>2</sup> + */ + public final static Unit Ohm = new Unit("Ohm", createType(0, 0, 0, 0, -2, 0, 1, -3, 2)); // Resistance + // ohm + // (m^2*kg)/(s^3*A^2) + /** + * The electric conductance unit siemens (S). + * <p> + * siemens is equal to A/V or is expressed in SI units as + * s<sup>3</sup>·A<sup>2</sup>/m<sup>2</sup>·kg + */ + public final static Unit S = new Unit("S", createType(0, 0, 0, 0, 2, 0, -1, 3, -2)); // Conductance + // siemens + // (s^3*A^2)/(m^2*kg) + /** + * The magnetic flux unit weber (Wb). + * <p> + * weber is equal to V·s or is expressed in SI units as + * m<sup>2</sup>·kg/s<sup>2</sup>·A + */ + public final static Unit Wb = new Unit("Wb", createType(0, 0, 0, 0, -1, 0, 1, -2, 2)); // Magn. + // Flux + // weber + // (m^2*kg)/(s^2*A) + /** + * The magnetic flux density unit tesla (T). + * <p> + * tesla is equal to Wb/m<sup>2</sup> or is expressed in SI units as + * kg/s<sup>2</sup>·A + */ + public final static Unit T = new Unit("T", createType(0, 0, 0, 0, -1, 0, 1, -2, 0)); // Magn. + // Flux + // Dens. + // tesla + // kg/(s^2*A) + /** + * The illuminance unit lux (lx). + * <p> + * lux is expressed in SI units as cd/m<sup>2</sup> + */ + public final static Unit lx = new Unit("lx", createType(0, 0, 1, 0, 0, 0, 0, 0, -2)); // Illuminace + // lux + // cd/m^2 + /** + * The absorbed dose unit gray (Gy). + * <p> + * Gy is equal to J/kg or is expressed in SI units as + * m<sup>2</sup>/s<sup>2</sup> + */ + public final static Unit Gy = new Unit("Gy", createType(0, 0, 0, 0, 0, 0, 0, -2, 2)); // Absorbed + // dose + // gray + // m^2/s^2 + /** + * The catalytic activity unit katal (kat). + * <p> + * katal is expressed in SI units as mol/s + */ + public final static Unit kat = new Unit("kat", createType(0, 0, 0, 1, 0, 0, 0, -1, 0)); // Catalytic + // Act. + // katal + // mol/s + /** The angle unit radians (rad) */ + public final static Unit rad = new Unit("rad", createType(0, 1, 0, 0, 0, 0, 0, 0, 0)); // Angle + // radians + // rad + /** + * An array containing all units defined. The first seven items must be m, + * s, kg, K, A, mol, cd, rad in this order! + */ + private final static Unit[] allUnits = new Unit[] {m, s, kg, K, A, mol, cd, rad, m_s, m_s2, m2, m3, Hz, N, Pa, J, W, C, V, F, Ohm, S, Wb, T, lx, Gy, kat, unity}; + + /* @GuardedBy("this") */ + private static Hashtable base; + private final String name; + private final long type; + + /** + * Creates a new {@code Unit} instance. + * + * @param name the name of the {@code Unit} + * @param type the type of the {@code Unit} + */ + private Unit(String name, long type) { + if (name == null) { + name = computeName(type); + } + this.name = name; + this.type = type; + // System.out.println( name + " " + Long.toHexString( type ) ); + } + + /** + * Create a type field from the base SI unit exponent values. + * + */ + private static long createType(int _x, int _rad, int _cd, int _mol, int _A, int _K, int _kg, int _s, int _m) { + return (((ZERO + _m) & MASK) << m_SHIFT) | (((ZERO + _s) & MASK) << s_SHIFT) | (((ZERO + _kg) & MASK) << kg_SHIFT) | (((ZERO + _K) & MASK) << K_SHIFT) | (((ZERO + _A) & MASK) << A_SHIFT) + | (((ZERO + _mol) & MASK) << mol_SHIFT) | (((ZERO + _cd) & MASK) << cd_SHIFT) | (((ZERO + _rad) & MASK) << rad_SHIFT) | (((long) _x) << x_SHIFT); + } + + /** + * Checks whether this {@code Unit} object is equal to the specified + * {@code Unit} object. The {@code Unit} objects are considered equal if + * their exponents are equal. + * + * @param obj the {@code Unit} object that should be checked for equality + * + * @return true if the specified {@code Unit} object is equal to this + * {@code Unit} object. + */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Unit)) { + return false; + } + return ((Unit) obj).type == type; + } + + /** + * Returns the hash code for this object. + * + * @return This object's hash code. + */ + public int hashCode() { + return 31 * 17 + (int) (type ^ (type >>> 32)); + } + + /** + * Returns a new {@code Unit} that is the multiplication of this + * {@code Unit} and the {@code Unit} specified + * + * @param that the {@code Unit} that will be multiplied with this + * {@code Unit} + * + * @return a new {@code Unit} that is the multiplication of this + * {@code Unit} and the {@code Unit} specified + * + * @throws RuntimeException if both {@code Unit} s are special + * + * @see Unit#isSpecial() + */ + Unit mul(Unit that) { + if (this.isSpecial() && that.isSpecial()) { + throw new ArithmeticException("Cannot multiply " + this + " with " + that); + } + return find(this.type - UNITY + that.type); + } + + /** + * Returns a new {@code Unit} that is the division of this {@code Unit} and + * the {@code Unit} specified + * + * @param that the {@code Unit} that this {@code Unit} will be divided with + * @return a new {@code Unit} that is the division of this {@code Unit} and + * the {@code Unit} specified + * + * @throws RuntimeException if both {@code Unit} s are special + * + * @see Unit#isSpecial() + */ + Unit div(Unit that) { + if (this.isSpecial() && that.isSpecial()) { + if (this.type == that.type) { + return Unit.unity; + } + throw new ArithmeticException("Cannot divide " + this + " by " + that); + } + return find(this.type - that.type + UNITY); + } + + /** + * Returns a new {@code Unit} that is the addition of this {@code Unit} and + * the {@code Unit} specified. + * + * @param that the {@code Unit} that should be added to this {@code Unit} + * + * @return a new {@code Unit} that is the addition of this {@code Unit} and + * the {@code Unit} specified. + * + * @throws RuntimeException if the two {@code Unit} s are not the same + */ + Unit add(Unit that) { + if (!this.equals(that)) { + throw new ArithmeticException("Cannot add " + this + " to " + that); + } + return this; + } + + /** + * Returns a new {@code Unit} that is the subtraction between this + * {@code Unit} and the {@code Unit} specified. + * + * @param that the {@code Unit} that will be subtracted from this + * {@code Unit} + * @return a new {@code Unit} that is the subtraction between this + * {@code Unit} and the {@code Unit} specified. + * + * @throws RuntimeException if the {@code Unit} specified is not the same as + * this {@code Unit} + */ + Unit sub(Unit that) { + if (!this.equals(that)) { + throw new ArithmeticException("Cannot subtract " + that + " from " + this); + } + return this; + } + + /** + * Finds a {@code Unit} based on a type. If the {@code Unit} is not found, + * it will be created and added to the list of all units under a null name. + * + * @param type the type of the {@code Unit} to find + * + * @return the {@code Unit} + */ + static synchronized Unit find(long type) { + if (base == null) { + int size = allUnits.length; + base = new Hashtable(size << 1); + for (int i = 0; i < size; i++) { + base.put(allUnits[i], allUnits[i]); + } + } + Unit unit = new Unit(null, type); + Unit out = (Unit) base.get(unit); + if (out == null) { + base.put(unit, unit); + out = unit; + } + return out; + } + + /** + * Returns a {@code String} object representing the {@code Unit} + * + * @return A {@code String} object representing the {@code Unit} + */ + public String toString() { + return name; + } + + private static String computeName(long type) { + int _m = (int) (((type >> m_SHIFT) & MASK) - ZERO); + int _s = (int) (((type >> s_SHIFT) & MASK) - ZERO); + int _kg = (int) (((type >> kg_SHIFT) & MASK) - ZERO); + int _K = (int) (((type >> K_SHIFT) & MASK) - ZERO); + int _A = (int) (((type >> A_SHIFT) & MASK) - ZERO); + int _mol = (int) (((type >> mol_SHIFT) & MASK) - ZERO); + int _cd = (int) (((type >> cd_SHIFT) & MASK) - ZERO); + int _rad = (int) (((type >> rad_SHIFT) & MASK) - ZERO); + StringBuffer numerator = new StringBuffer(); + StringBuffer denominator = new StringBuffer(); + addSIname(_m, "m", numerator, denominator); + addSIname(_s, "s", numerator, denominator); + addSIname(_kg, "kg", numerator, denominator); + addSIname(_K, "K", numerator, denominator); + addSIname(_A, "A", numerator, denominator); + addSIname(_mol, "mol", numerator, denominator); + addSIname(_cd, "cd", numerator, denominator); + addSIname(_rad, "rad", numerator, denominator); + if (denominator.length() > 0) { + if (numerator.length() == 0) { + numerator.append("1"); + } + numerator.append("/"); + numerator.append(denominator.toString()); + } + return numerator.toString(); + } + + private static void addSIname(int si, String name, StringBuffer numerator, StringBuffer denominator) { + if (si != 0) { + StringBuffer sb = (si > 0) ? numerator : denominator; + if (sb.length() > 0) { + sb.append("*"); + } + sb.append(name); + int power = Math.abs(si); + if (power > 1) { + sb.append("^"); + sb.append(power); + } + } + } + + /** + * Checks whether the unit has a special type, i.e. not a SI unit. + * + * @return true if the type is special, otherwise false. + */ + private boolean isSpecial() { + return (type & x_MASK) != 0; + } +} diff --git a/bundles/org.eclipse.osgi.util/src/org/osgi/util/measurement/package-info.java b/bundles/org.eclipse.osgi.util/src/org/osgi/util/measurement/package-info.java new file mode 100644 index 000000000..7603bac0b --- /dev/null +++ b/bundles/org.eclipse.osgi.util/src/org/osgi/util/measurement/package-info.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) OSGi Alliance (2010, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Measurement Package Version 1.0. + * + * <p> + * Bundles wishing to use this package must list the package in the + * Import-Package header of the bundle's manifest. + * + * <p> + * Example import for consumers using the API in this package: + * <p> + * {@code Import-Package: org.osgi.util.measurement; version="[1.0,2.0)"} + * + * @version 1.0.1 + * @author $Id$ + */ + +package org.osgi.util.measurement; + diff --git a/bundles/org.eclipse.osgi.util/src/org/osgi/util/measurement/packageinfo b/bundles/org.eclipse.osgi.util/src/org/osgi/util/measurement/packageinfo new file mode 100644 index 000000000..c2664475c --- /dev/null +++ b/bundles/org.eclipse.osgi.util/src/org/osgi/util/measurement/packageinfo @@ -0,0 +1 @@ +version 1.0.1
\ No newline at end of file diff --git a/bundles/org.eclipse.osgi.util/src/org/osgi/util/position/Position.java b/bundles/org.eclipse.osgi.util/src/org/osgi/util/position/Position.java new file mode 100644 index 000000000..0e637b36c --- /dev/null +++ b/bundles/org.eclipse.osgi.util/src/org/osgi/util/position/Position.java @@ -0,0 +1,232 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.util.position; + +import org.osgi.util.measurement.Measurement; +import org.osgi.util.measurement.Unit; + +/** + * Position represents a geographic location, based on the WGS84 System (World + * Geodetic System 1984). + * <p> + * The {@code org.osgi.util.measurement.Measurement} class is used to represent + * the values that make up a position. + * <p> + * <p> + * A given position object may lack any of it's components, i.e. the altitude + * may not be known. Such missing values will be represented by null. + * <p> + * Position does not override the implementation of either equals() or + * hashCode() because it is not clear how missing values should be handled. It + * is up to the user of a position to determine how best to compare two position + * objects. A {@code Position} object is immutable. + * + * @Immutable + * @author $Id$ + */ +public class Position { + private final Measurement altitude; + private final Measurement longitude; + private final Measurement latitude; + private final Measurement speed; + private final Measurement track; + + /** + * Constructs a {@code Position} object with the given values. + * + * @param lat a {@code Measurement} object specifying the latitude in + * radians, or null + * @param lon a {@code Measurement} object specifying the longitude in + * radians, or null + * @param alt a {@code Measurement} object specifying the altitude in + * meters, or null + * @param speed a {@code Measurement} object specifying the speed in meters + * per second, or null + * @param track a {@code Measurement} object specifying the track in + * radians, or null + */ + public Position(Measurement lat, Measurement lon, Measurement alt, Measurement speed, Measurement track) { + if (lat != null) { + if (!Unit.rad.equals(lat.getUnit())) { + throw new IllegalArgumentException("Invalid Latitude"); + } + } + if (lon != null) { + if (!Unit.rad.equals(lon.getUnit())) { + throw new IllegalArgumentException("Invalid Longitude"); + } + } + if (alt != null) { + if (!Unit.m.equals(alt.getUnit())) { + throw new IllegalArgumentException("Invalid Altitude"); + } + } + if (speed != null) { + if (!Unit.m_s.equals(speed.getUnit())) { + throw new IllegalArgumentException("Invalid Speed"); + } + } + if (track != null) { + if (!Unit.rad.equals(track.getUnit())) { + throw new IllegalArgumentException("Invalid Track"); + } + } + + /* + * Verify the longitude and latitude parameters so they fit the normal + * coordinate system. A latitude is between -90 (south) and +90 (north). + * A longitude is between -180 (Western hemisphere) and +180 (eastern + * hemisphere). This method first normalizes the latitude and longitude + * between +/- 180. If the |latitude| > 90, then the longitude is added + * 180 and the latitude is normalized to fit +/-90. (Example are with + * degrees though radians are used.) No normalization takes place when + * either lon or lat is null. + */ + normalizeLatLon: { + if (lat == null || lon == null) { + break normalizeLatLon; + } + double dlat = lat.getValue(); + double dlon = lon.getValue(); + if (dlon >= -LON_RANGE && dlon < LON_RANGE && dlat >= -LAT_RANGE && dlat <= LAT_RANGE) { + break normalizeLatLon; + } + dlon = normalize(dlon, LON_RANGE); + dlat = normalize(dlat, LAT_RANGE * 2.0D); // First over 180 degree + // Check if we have to move to other side of the earth + if (dlat > LAT_RANGE || dlat < -LAT_RANGE) { + dlon = normalize(dlon - LON_RANGE, LON_RANGE); + dlat = normalize((LAT_RANGE * 2.0D) - dlat, LAT_RANGE); + } + lon = new Measurement(dlon, lon.getError(), lon.getUnit(), lon.getTime()); + lat = new Measurement(dlat, lat.getError(), lat.getUnit(), lat.getTime()); + } + + /* + * Normalize track to be a value such that: 0 <= value < +2PI. This + * corresponds to 0 deg to +360 deg. 0 is North, 0.5PI is East, PI is + * South, 1.5PI is West + */ + normalizeTrack: { + if (track == null) { + break normalizeTrack; + } + double dtrack = track.getValue(); + if ((0.0D <= dtrack) && (dtrack < TRACK_RANGE)) { + break normalizeTrack; /* value is already normalized */ + } + dtrack %= TRACK_RANGE; + if (dtrack < 0.0D) { + dtrack += TRACK_RANGE; + } + track = new Measurement(dtrack, track.getError(), track.getUnit(), track.getTime()); + } + + this.latitude = lat; + this.longitude = lon; + this.altitude = alt; + this.speed = speed; + this.track = track; + } + + /** + * Returns the altitude of this position in meters. + * + * @return a {@code Measurement} object in {@code Unit.m} representing the + * altitude in meters above the ellipsoid {@code null} if the + * altitude is not known. + */ + public Measurement getAltitude() { + return altitude; + } + + /** + * Returns the longitude of this position in radians. + * + * @return a {@code Measurement} object in {@code Unit.rad} representing the + * longitude, or {@code null} if the longitude is not known. + */ + public Measurement getLongitude() { + return longitude; + } + + /** + * Returns the latitude of this position in radians. + * + * @return a {@code Measurement} object in {@code Unit.rad} representing the + * latitude, or {@code null} if the latitude is not known.. + */ + public Measurement getLatitude() { + return latitude; + } + + /** + * Returns the ground speed of this position in meters per second. + * + * @return a {@code Measurement} object in {@code Unit.m_s} representing the + * speed, or {@code null} if the speed is not known.. + */ + public Measurement getSpeed() { + return speed; + } + + /** + * Returns the track of this position in radians as a compass heading. The + * track is the extrapolation of previous previously measured positions to a + * future position. + * + * @return a {@code Measurement} object in {@code Unit.rad} representing the + * track, or {@code null} if the track is not known.. + */ + public Measurement getTrack() { + return track; + } + + private static final double LON_RANGE = Math.PI; + private static final double LAT_RANGE = Math.PI / 2.0D; + + /** + * This function normalizes the a value according to a range. This is not + * simple modulo (as I thought when I started), but requires some special + * handling. For positive numbers we subtract 2*range from the number so + * that end up between -/+ range. For negative numbers we add this value. + * For example, if the value is 270 and the range is +/- 180. Then sign=1 so + * the (int) factor becomes 270+180/360 = 1. This means that 270-360=-90 is + * the result. (degrees are only used to make it easier to understand, this + * function is agnostic for radians/degrees). The result will be in + * [range,range> The algorithm is not very fast, but it handling the + * [> ranges made it very messy using integer arithmetic, and this is + * very readable. Note that it is highly unlikely that this method is called + * in normal situations. Normally input values to position are already + * normalized because they come from a GPS. And this is much more readable. + * + * @param value The value that needs adjusting + * @param range -range = < value < range + */ + private static double normalize(double value, double range) { + double twiceRange = 2.0D * range; + while (value >= range) { + value -= twiceRange; + } + while (value < -range) { + value += twiceRange; + } + return value; + } + + private static final double TRACK_RANGE = Math.PI * 2.0D; +} diff --git a/bundles/org.eclipse.osgi.util/src/org/osgi/util/position/package-info.java b/bundles/org.eclipse.osgi.util/src/org/osgi/util/position/package-info.java new file mode 100644 index 000000000..63af1b6e6 --- /dev/null +++ b/bundles/org.eclipse.osgi.util/src/org/osgi/util/position/package-info.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) OSGi Alliance (2010, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Position Package Version 1.0. + * + * <p> + * Bundles wishing to use this package must list the package in the + * Import-Package header of the bundle's manifest. + * + * <p> + * Example import for consumers using the API in this package: + * <p> + * {@code Import-Package: org.osgi.util.position; version="[1.0,2.0)"} + * + * @version 1.0.1 + * @author $Id$ + */ + +package org.osgi.util.position; + diff --git a/bundles/org.eclipse.osgi.util/src/org/osgi/util/position/packageinfo b/bundles/org.eclipse.osgi.util/src/org/osgi/util/position/packageinfo new file mode 100644 index 000000000..c2664475c --- /dev/null +++ b/bundles/org.eclipse.osgi.util/src/org/osgi/util/position/packageinfo @@ -0,0 +1 @@ +version 1.0.1
\ No newline at end of file diff --git a/bundles/org.eclipse.osgi.util/src/org/osgi/util/xml/XMLParserActivator.java b/bundles/org.eclipse.osgi.util/src/org/osgi/util/xml/XMLParserActivator.java new file mode 100644 index 000000000..c73b3c061 --- /dev/null +++ b/bundles/org.eclipse.osgi.util/src/org/osgi/util/xml/XMLParserActivator.java @@ -0,0 +1,479 @@ +/* + * Copyright (c) OSGi Alliance (2002, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.util.xml; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.FactoryConfigurationError; +import javax.xml.parsers.SAXParserFactory; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceFactory; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; + +/** + * A BundleActivator class that allows any JAXP compliant XML Parser to register + * itself as an OSGi parser service. + * + * Multiple JAXP compliant parsers can concurrently register by using this + * BundleActivator class. Bundles who wish to use an XML parser can then use the + * framework's service registry to locate available XML Parsers with the desired + * characteristics such as validating and namespace-aware. + * + * <p> + * The services that this bundle activator enables a bundle to provide are: + * <ul> + * <li>{@code javax.xml.parsers.SAXParserFactory}({@link #SAXFACTORYNAME})</li> + * <li>{@code javax.xml.parsers.DocumentBuilderFactory}( {@link #DOMFACTORYNAME} + * )</li> + * </ul> + * + * <p> + * The algorithm to find the implementations of the abstract parsers is derived + * from the JAR file specifications, specifically the Services API. + * <p> + * An XMLParserActivator assumes that it can find the class file names of the + * factory classes in the following files: + * <ul> + * <li>{@code /META-INF/services/javax.xml.parsers.SAXParserFactory} is a file + * contained in a jar available to the runtime which contains the implementation + * class name(s) of the SAXParserFactory.</li> + * <li>{@code /META-INF/services/javax.xml.parsers.DocumentBuilderFactory} is a + * file contained in a jar available to the runtime which contains the + * implementation class name(s) of the {@code DocumentBuilderFactory}</li> + * </ul> + * <p> + * If either of the files does not exist, {@code XMLParserActivator} assumes + * that the parser does not support that parser type. + * + * <p> + * {@code XMLParserActivator} attempts to instantiate both the + * {@code SAXParserFactory} and the {@code DocumentBuilderFactory}. It registers + * each factory with the framework along with service properties: + * <ul> + * <li>{@link #PARSER_VALIDATING}- indicates if this factory supports validating + * parsers. It's value is a {@code Boolean}.</li> + * <li>{@link #PARSER_NAMESPACEAWARE}- indicates if this factory supports + * namespace aware parsers It's value is a {@code Boolean}.</li> + * </ul> + * <p> + * Individual parser implementations may have additional features, properties, + * or attributes which could be used to select a parser with a filter. These can + * be added by extending this class and overriding the {@code setSAXProperties} + * and {@code setDOMProperties} methods. + * + * @ThreadSafe + * @author $Id$ + */ +public class XMLParserActivator implements BundleActivator, ServiceFactory { + /** Context of this bundle */ + private volatile BundleContext context; + /** + * Filename containing the SAX Parser Factory Class name. Also used as the + * basis for the {@code SERVICE_PID} registration property. + */ + public static final String SAXFACTORYNAME = "javax.xml.parsers.SAXParserFactory"; + /** + * Filename containing the DOM Parser Factory Class name. Also used as the + * basis for the {@code SERVICE_PID} registration property. + */ + public static final String DOMFACTORYNAME = "javax.xml.parsers.DocumentBuilderFactory"; + /** Path to the factory class name files */ + private static final String PARSERCLASSFILEPATH = "/META-INF/services/"; + /** Fully qualified path name of SAX Parser Factory Class Name file */ + public static final String SAXCLASSFILE = PARSERCLASSFILEPATH + SAXFACTORYNAME; + /** Fully qualified path name of DOM Parser Factory Class Name file */ + public static final String DOMCLASSFILE = PARSERCLASSFILEPATH + DOMFACTORYNAME; + /** SAX Factory Service Description */ + private static final String SAXFACTORYDESCRIPTION = "A JAXP Compliant SAX Parser"; + /** DOM Factory Service Description */ + private static final String DOMFACTORYDESCRIPTION = "A JAXP Compliant DOM Parser"; + /** + * Service property specifying if factory is configured to support + * validating parsers. The value is of type {@code Boolean}. + */ + public static final String PARSER_VALIDATING = "parser.validating"; + /** + * Service property specifying if factory is configured to support namespace + * aware parsers. The value is of type {@code Boolean}. + */ + public static final String PARSER_NAMESPACEAWARE = "parser.namespaceAware"; + /** + * Key for parser factory name property - this must be saved in the parsers + * properties hashtable so that the parser factory can be instantiated from + * a ServiceReference + */ + private static final String FACTORYNAMEKEY = "parser.factoryname"; + + /** + * Called when this bundle is started so the Framework can perform the + * bundle-specific activities necessary to start this bundle. This method + * can be used to register services or to allocate any resources that this + * bundle needs. + * + * <p> + * This method must complete and return to its caller in a timely manner. + * + * <p> + * This method attempts to register a SAX and DOM parser with the + * Framework's service registry. + * + * @param context The execution context of the bundle being started. + * @throws java.lang.Exception If this method throws an exception, this + * bundle is marked as stopped and the Framework will remove this + * bundle's listeners, unregister all services registered by this + * bundle, and release all services used by this bundle. + */ + public void start(BundleContext context) throws Exception { + this.context = context; + Bundle parserBundle = context.getBundle(); + // check for sax parsers + registerSAXParsers(getParserFactoryClassNames(parserBundle.getResource(SAXCLASSFILE))); + // check for dom parsers + registerDOMParsers(getParserFactoryClassNames(parserBundle.getResource(DOMCLASSFILE))); + } + + /** + * This method has nothing to do as all active service registrations will + * automatically get unregistered when the bundle stops. + * + * @param context The execution context of the bundle being stopped. + * @throws java.lang.Exception If this method throws an exception, the + * bundle is still marked as stopped, and the Framework will remove + * the bundle's listeners, unregister all services registered by the + * bundle, and release all services used by the bundle. + */ + public void stop(BundleContext context) throws Exception { + // framework will automatically unregister the parser services + } + + /** + * Given the URL for a file, reads and returns the parser class names. There + * may be multiple classes specified in this file, one per line. There may + * also be comment lines in the file, which begin with "#". + * + * @param parserUrl The URL of the service file containing the parser class + * names + * @return A List of strings containing the parser class names. + * @throws IOException if there is a problem reading the URL input stream + */ + private List getParserFactoryClassNames(URL parserUrl) throws IOException { + if (parserUrl == null) { + return Collections.EMPTY_LIST; + } + List v = new ArrayList(1); + String parserFactoryClassName = null; + InputStream is = parserUrl.openStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + while (true) { + parserFactoryClassName = br.readLine(); + if (parserFactoryClassName == null) { + break; // end of file reached + } + String pfcName = parserFactoryClassName.trim(); + if (pfcName.length() == 0) { + continue; // blank line + } + int commentIdx = pfcName.indexOf("#"); + if (commentIdx == 0) { // comment line + continue; + } else + if (commentIdx < 0) { // no comment on this line + v.add(pfcName); + } else { + v.add(pfcName.substring(0, commentIdx).trim()); + } + } + return v; + } + + /** + * Register SAX Parser Factory Services with the framework. + * + * @param parserFactoryClassNames - a {@code List} of {@code String} objects + * containing the names of the parser Factory Classes + * @throws FactoryConfigurationError if thrown from {@code getFactory} + */ + private void registerSAXParsers(List parserFactoryClassNames) throws FactoryConfigurationError { + Iterator e = parserFactoryClassNames.iterator(); + int index = 0; + while (e.hasNext()) { + String parserFactoryClassName = (String) e.next(); + // create a sax parser factory just to get it's default + // properties. It will never be used since + // this class will operate as a service factory and give each + // service requestor it's own SaxParserFactory + SAXParserFactory factory = (SAXParserFactory) getFactory(parserFactoryClassName); + Hashtable properties = new Hashtable(7); + // figure out the default properties of the parser + setDefaultSAXProperties(factory, properties, index); + // store the parser factory class name in the properties so that + // it can be retrieved when getService is called + // to return a parser factory + properties.put(FACTORYNAMEKEY, parserFactoryClassName); + // register the factory as a service + context.registerService(SAXFACTORYNAME, this, properties); + index++; + } + } + + /** + * <p> + * Set the SAX Parser Service Properties. By default, the following + * properties are set: + * <ul> + * <li>{@code SERVICE_DESCRIPTION}</li> + * <li>{@code SERVICE_PID}</li> + * <li>{@code PARSER_VALIDATING}- instantiates a parser and queries it to + * find out whether it is validating or not</li> + * <li>{@code PARSER_NAMESPACEAWARE}- instantiates a parser and queries it + * to find out whether it is namespace aware or not</li> + * <ul> + * + * @param factory The {@code SAXParserFactory} object + * @param props {@code Hashtable} of service properties. + */ + private void setDefaultSAXProperties(SAXParserFactory factory, Hashtable props, int index) { + props.put(Constants.SERVICE_DESCRIPTION, SAXFACTORYDESCRIPTION); + props.put(Constants.SERVICE_PID, SAXFACTORYNAME + "." + context.getBundle().getBundleId() + "." + index); + setSAXProperties(factory, props); + } + + /** + * <p> + * Set the customizable SAX Parser Service Properties. + * + * <p> + * This method attempts to instantiate a validating parser and a namespace + * aware parser to determine if the parser can support those features. The + * appropriate properties are then set in the specified properties object. + * + * <p> + * This method can be overridden to add additional SAX2 features and + * properties. If you want to be able to filter searches of the OSGi service + * registry, this method must put a key, value pair into the properties + * object for each feature or property. For example, + * + * properties.put("http://www.acme.com/features/foo", Boolean.TRUE); + * + * @param factory - the SAXParserFactory object + * @param properties - the properties object for the service + */ + public void setSAXProperties(SAXParserFactory factory, Hashtable properties) { + // check if this parser can be configured to validate + boolean validating = true; + factory.setValidating(true); + factory.setNamespaceAware(false); + try { + factory.newSAXParser(); + } catch (Exception pce_val) { + validating = false; + } + // check if this parser can be configured to be namespaceaware + boolean namespaceaware = true; + factory.setValidating(false); + factory.setNamespaceAware(true); + try { + factory.newSAXParser(); + } catch (Exception pce_nsa) { + namespaceaware = false; + } + // set the factory values + factory.setValidating(validating); + factory.setNamespaceAware(namespaceaware); + // set the OSGi service properties + properties.put(PARSER_NAMESPACEAWARE, new Boolean(namespaceaware)); + properties.put(PARSER_VALIDATING, new Boolean(validating)); + } + + /** + * Register DOM Parser Factory Services with the framework. + * + * @param parserFactoryClassNames - a {@code List} of {@code String} objects + * containing the names of the parser Factory Classes + * @throws FactoryConfigurationError if thrown from {@code getFactory} + */ + private void registerDOMParsers(List parserFactoryClassNames) throws FactoryConfigurationError { + Iterator e = parserFactoryClassNames.iterator(); + int index = 0; + while (e.hasNext()) { + String parserFactoryClassName = (String) e.next(); + // create a dom parser factory just to get it's default + // properties. It will never be used since + // this class will operate as a service factory and give each + // service requestor it's own DocumentBuilderFactory + DocumentBuilderFactory factory = (DocumentBuilderFactory) getFactory(parserFactoryClassName); + Hashtable properties = new Hashtable(7); + // figure out the default properties of the parser + setDefaultDOMProperties(factory, properties, index); + // store the parser factory class name in the properties so that + // it can be retrieved when getService is called + // to return a parser factory + properties.put(FACTORYNAMEKEY, parserFactoryClassName); + // register the factory as a service + context.registerService(DOMFACTORYNAME, this, properties); + index++; + } + } + + /** + * Set the DOM parser service properties. + * + * By default, the following properties are set: + * <ul> + * <li>{@code SERVICE_DESCRIPTION}</li> + * <li>{@code SERVICE_PID}</li> + * <li>{@code PARSER_VALIDATING}</li> + * <li>{@code PARSER_NAMESPACEAWARE}</li> + * <ul> + * + * @param factory The {@code DocumentBuilderFactory} object + * @param props {@code Hashtable} of service properties. + */ + private void setDefaultDOMProperties(DocumentBuilderFactory factory, Hashtable props, int index) { + props.put(Constants.SERVICE_DESCRIPTION, DOMFACTORYDESCRIPTION); + props.put(Constants.SERVICE_PID, DOMFACTORYNAME + "." + context.getBundle().getBundleId() + "." + index); + setDOMProperties(factory, props); + } + + /** + * <p> + * Set the customizable DOM Parser Service Properties. + * + * <p> + * This method attempts to instantiate a validating parser and a namespace + * aware parser to determine if the parser can support those features. The + * appropriate properties are then set in the specified props object. + * + * <p> + * This method can be overridden to add additional DOM2 features and + * properties. If you want to be able to filter searches of the OSGi service + * registry, this method must put a key, value pair into the properties + * object for each feature or property. For example, + * + * properties.put("http://www.acme.com/features/foo", Boolean.TRUE); + * + * @param factory - the DocumentBuilderFactory object + * @param props - Hashtable of service properties. + */ + public void setDOMProperties(DocumentBuilderFactory factory, Hashtable props) { + // check if this parser can be configured to validate + boolean validating = true; + factory.setValidating(true); + factory.setNamespaceAware(false); + try { + factory.newDocumentBuilder(); + } catch (Exception pce_val) { + validating = false; + } + // check if this parser can be configured to be namespaceaware + boolean namespaceaware = true; + factory.setValidating(false); + factory.setNamespaceAware(true); + try { + factory.newDocumentBuilder(); + } catch (Exception pce_nsa) { + namespaceaware = false; + } + // set the factory values + factory.setValidating(validating); + factory.setNamespaceAware(namespaceaware); + // set the OSGi service properties + props.put(PARSER_VALIDATING, new Boolean(validating)); + props.put(PARSER_NAMESPACEAWARE, new Boolean(namespaceaware)); + } + + /** + * Given a parser factory class name, instantiate that class. + * + * @param parserFactoryClassName A {@code String} object containing the name + * of the parser factory class + * @return a parserFactoryClass Object + * @pre parserFactoryClassName!=null + */ + private Object getFactory(String parserFactoryClassName) throws FactoryConfigurationError { + try { + return context.getBundle().loadClass(parserFactoryClassName).newInstance(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new FactoryConfigurationError(e); + } + } + + /** + * Creates a new XML Parser Factory object. + * + * <p> + * A unique XML Parser Factory object is returned for each call to this + * method. + * + * <p> + * The returned XML Parser Factory object will be configured for validating + * and namespace aware support as specified in the service properties of the + * specified ServiceRegistration object. + * + * This method can be overridden to configure additional features in the + * returned XML Parser Factory object. + * + * @param bundle The bundle using the service. + * @param registration The {@code ServiceRegistration} object for the + * service. + * @return A new, configured XML Parser Factory object or null if a + * configuration error was encountered + */ + public Object getService(Bundle bundle, ServiceRegistration registration) { + ServiceReference sref = registration.getReference(); + String parserFactoryClassName = (String) sref.getProperty(FACTORYNAMEKEY); + // need to set factory properties + Object factory = getFactory(parserFactoryClassName); + if (factory instanceof SAXParserFactory) { + ((SAXParserFactory) factory).setValidating(((Boolean) sref.getProperty(PARSER_VALIDATING)).booleanValue()); + ((SAXParserFactory) factory).setNamespaceAware(((Boolean) sref.getProperty(PARSER_NAMESPACEAWARE)).booleanValue()); + } else { + if (factory instanceof DocumentBuilderFactory) { + ((DocumentBuilderFactory) factory).setValidating(((Boolean) sref.getProperty(PARSER_VALIDATING)).booleanValue()); + ((DocumentBuilderFactory) factory).setNamespaceAware(((Boolean) sref.getProperty(PARSER_NAMESPACEAWARE)).booleanValue()); + } + } + return factory; + } + + /** + * Releases a XML Parser Factory object. + * + * @param bundle The bundle releasing the service. + * @param registration The {@code ServiceRegistration} object for the + * service. + * @param service The XML Parser Factory object returned by a previous call + * to the {@code getService} method. + */ + public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) { + } +} diff --git a/bundles/org.eclipse.osgi.util/src/org/osgi/util/xml/package-info.java b/bundles/org.eclipse.osgi.util/src/org/osgi/util/xml/package-info.java new file mode 100644 index 000000000..8d3c57bb5 --- /dev/null +++ b/bundles/org.eclipse.osgi.util/src/org/osgi/util/xml/package-info.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) OSGi Alliance (2010, 2013). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * XML Parser Package Version 1.0. + * + * <p> + * Bundles wishing to use this package must list the package in the + * Import-Package header of the bundle's manifest. + * + * <p> + * Example import for consumers using the API in this package: + * <p> + * {@code Import-Package: org.osgi.util.xml; version="[1.0,2.0)"} + * + * @version 1.0.1 + * @author $Id$ + */ + +package org.osgi.util.xml; + diff --git a/bundles/org.eclipse.osgi.util/src/org/osgi/util/xml/packageinfo b/bundles/org.eclipse.osgi.util/src/org/osgi/util/xml/packageinfo new file mode 100644 index 000000000..c2664475c --- /dev/null +++ b/bundles/org.eclipse.osgi.util/src/org/osgi/util/xml/packageinfo @@ -0,0 +1 @@ +version 1.0.1
\ No newline at end of file |