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/org.eclipse.osgi.util | |
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/org.eclipse.osgi.util')
23 files changed, 1931 insertions, 187 deletions
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 |