You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by er...@apache.org on 2006/03/29 23:05:18 UTC

svn commit: r389891 [7/9] - in /incubator/felix/trunk/org.osgi.compendium: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/osgi/ src/main/java/org/osgi/service/ src/main/java/org/osgi/service/cm/ src/main/java/org/osgi/service/com...

Added: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Measurement.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Measurement.java?rev=389891&view=auto
==============================================================================
--- incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Measurement.java (added)
+++ incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Measurement.java Wed Mar 29 13:05:08 2006
@@ -0,0 +1,480 @@
+/*
+ * $Header: /cvshome/build/org.osgi.util.measurement/src/org/osgi/util/measurement/Measurement.java,v 1.12 2006/03/14 01:19:37 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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</code> 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</code> 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}.
+ * 
+ * @version $Revision: 1.12 $
+ */
+public class Measurement implements Comparable {
+	/* package private so it can be accessed by Unit */
+	final double	value;
+	final double	error;
+	final long		time;
+	final Unit		unit;
+	private transient String	name;
+
+	/**
+	 * Create a new <code>Measurement</code> object.
+	 * 
+	 * @param value The value of the <code>Measurement</code>.
+	 * @param error The error of the <code>Measurement</code>.
+	 * @param unit The <code>Unit</code> object in which the value is measured. If
+	 *        this argument is <code>null</code>, 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;
+	}
+
+	/**
+	 * Create a new <code>Measurement</code> object with a time of zero.
+	 * 
+	 * @param value The value of the <code>Measurement</code>.
+	 * @param error The error of the <code>Measurement</code>.
+	 * @param unit The <code>Unit</code> object in which the value is measured. If
+	 *        this argument is <code>null</code>, 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</code> object with an error of 0.0 and a
+	 * time of zero.
+	 * 
+	 * @param value The value of the <code>Measurement</code>.
+	 * @param unit The <code>Unit</code> in which the value is measured. If this
+	 *        argument is <code>null</code>, 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</code> 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</code>.
+	 */
+	public Measurement(double value) {
+		this(value, 0.0d, null, 0l);
+	}
+
+	/**
+	 * Returns the value of this <code>Measurement</code> object.
+	 * 
+	 * @return The value of this <code>Measurement</code> object as a double.
+	 */
+	public final double getValue() {
+		return value;
+	}
+
+	/**
+	 * Returns the error of this <code>Measurement</code> object. The error is
+	 * always a positive value.
+	 * 
+	 * @return The error of this <code>Measurement</code> as a double.
+	 */
+	public final double getError() {
+		return error;
+	}
+
+	/**
+	 * Returns the <code>Unit</code> object of this <code>Measurement</code> object.
+	 * 
+	 * @return The <code>Unit</code> object of this <code>Measurement</code> object.
+	 * 
+	 * @see Unit
+	 */
+	public final Unit getUnit() {
+		return unit;
+	}
+
+	/**
+	 * Returns the time at which this <code>Measurement</code> 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</code> object was taken or
+	 *         zero.
+	 */
+	public final long getTime() {
+		return time;
+	}
+
+	/**
+	 * Returns a new <code>Measurement</code> object that is the product of this
+	 * object multiplied by the specified object.
+	 * 
+	 * @param m The <code>Measurement</code> object that will be multiplied with
+	 *        this object.
+	 * @return A new <code>Measurement</code> 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</code> 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</code> 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</code> of the specified value.
+	 * @return A new <code>Measurement</code> 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</code> 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</code> 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</code> object that is the quotient of this
+	 * object divided by the specified object.
+	 * 
+	 * @param m The <code>Measurement</code> object that will be the divisor of
+	 *        this object.
+	 * @return A new <code>Measurement</code> 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</code> 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</code> 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</code> object of the specified value.
+	 * @return A new <code>Measurement</code> 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</code> 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</code> 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</code> 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</code> 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</code> 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</code> object that will be added with this
+	 *        object.
+	 * @return A new <code>Measurement</code> object that is the sum of this and
+	 *         m.
+	 * @see Unit
+	 * @throws ArithmeticException If the <code>Unit</code> 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</code> 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</code> object of the specified value.
+	 * @return A new <code>Measurement</code> 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</code> 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</code> 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</code> 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</code> and time of
+	 *         this object.
+	 */
+	public Measurement add(double d) {
+		return new Measurement(value + d, error, unit, time);
+	}
+
+	/**
+	 * Returns a new <code>Measurement</code> object that is the subtraction of
+	 * the specified object from this object.
+	 * 
+	 * @param m The <code>Measurement</code> object that will be subtracted from
+	 *        this object.
+	 * @return A new <code>Measurement</code> 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</code> 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</code> 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</code> object of the specified value.
+	 * @return A new <code>Measurement</code> 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</code> 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</code> 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</code> 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</code> object and
+	 *         time of this object.
+	 */
+	public Measurement sub(double d) {
+		return new Measurement(value - d, error, unit, time);
+	}
+
+	/**
+	 * Returns a <code>String</code> object representing this <code>Measurement</code>
+	 * object.
+	 * 
+	 * @return a <code>String</code> object representing this <code>Measurement</code>
+	 *         object.
+	 */
+	public String toString() {
+		if (name == 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);
+			}
+			name = sb.toString();
+		}
+		return name;
+	}
+
+	/**
+	 * 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</code> object is considered
+	 * equal if there is some <code>x</code> such that
+	 * 
+	 * <pre>
+	 * getValue() - getError() &lt;= x &lt;= getValue() + getError()
+	 * </pre>
+	 * 
+	 * for both <code>Measurement</code> 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</code>.
+	 * @throws ArithmeticException If the unit of the specified
+	 *         <code>Measurement</code> object is not equal to the <code>Unit</code>
+	 *         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);
+		}
+		if (value == that.value) {
+			return 0;
+		}
+		if (value < that.value) {
+			if ((value + error) >= (that.value - that.error)) {
+				return 0;
+			}
+			else {
+				return -1;
+			}
+		}
+		else {
+			if ((value - error) <= (that.value + that.error)) {
+				return 0;
+			}
+			else {
+				return 1;
+			}
+		}
+	}
+
+	/**
+	 * Returns a hash code value for this object.
+	 * 
+	 * @return A hash code value for this object.
+	 */
+	public int hashCode() {
+		long bits = Double.doubleToLongBits(value + error);
+		return ((int) (bits ^ (bits >>> 32))) ^ unit.hashCode();
+	}
+
+	/**
+	 * Returns whether the specified object is equal to this object. Two
+	 * <code>Measurement</code> objects are equal if they have same value, error
+	 * and <code>Unit</code>.
+	 * 
+	 * <p>
+	 * Note: This class has a natural ordering that is inconsistent with equals.
+	 * See {@link #compareTo}.
+	 * 
+	 * @param obj The object to compare with this object.
+	 * @return <code>true</code> if this object is equal to the specified object;
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean equals(Object obj) {
+		if (this == obj) {
+			return true;
+		}
+		if (!(obj instanceof Measurement)) {
+			return false;
+		}
+		Measurement that = (Measurement) obj;
+		return (value == that.value) && (error == that.error)
+				&& unit.equals(that.unit);
+	}
+}

Propchange: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Measurement.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/State.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/State.java?rev=389891&view=auto
==============================================================================
--- incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/State.java (added)
+++ incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/State.java Wed Mar 29 13:05:08 2006
@@ -0,0 +1,145 @@
+/*
+ * $Header: /cvshome/build/org.osgi.util.measurement/src/org/osgi/util/measurement/State.java,v 1.7 2006/03/14 01:19:37 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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</code> object is immutable so that it may be easily shared.
+ * 
+ * @version $Revision: 1.7 $
+ */
+public class State {
+	final int		value;
+	final long		time;
+	final String	name;
+
+	/**
+	 * Create a new <code>State</code> 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</code> 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</code>.
+	 * 
+	 * @return The value of this <code>State</code> object.
+	 */
+	public final int getValue() {
+		return value;
+	}
+
+	/**
+	 * Returns the time with which this <code>State</code> was created.
+	 * 
+	 * @return The time with which this <code>State</code> 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</code>.
+	 * 
+	 * @return The name of this <code>State</code> object.
+	 */
+	public final String getName() {
+		return name;
+	}
+
+	/**
+	 * Returns a <code>String</code> object representing this object.
+	 * 
+	 * @return a <code>String</code> 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 = value;
+		if (name != null) {
+			hash ^= name.hashCode();
+		}
+		return hash;
+	}
+
+	/**
+	 * Return whether the specified object is equal to this object. Two
+	 * <code>State</code> objects are equal if they have same value and name.
+	 * 
+	 * @param obj The object to compare with this object.
+	 * @return <code>true</code> if this object is equal to the specified object;
+	 *         <code>false</code> 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);
+	}
+}

Propchange: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/State.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Unit.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Unit.java?rev=389891&view=auto
==============================================================================
--- incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Unit.java (added)
+++ incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Unit.java Wed Mar 29 13:05:08 2006
@@ -0,0 +1,525 @@
+/*
+ * $Header: /cvshome/build/org.osgi.util.measurement/src/org/osgi/util/measurement/Unit.java,v 1.14 2006/03/14 01:19:37 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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</code> object with undefined exponents.
+ * 
+ * @version $Revision: 1.14 $
+ */
+/*
+ * 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&#183;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&#183;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&#183;m or is expressed in SI units as m <sup>2
+	 * </sup>&#183;kg/s <sup>2
+	 */
+	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>&#183;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&#183;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>&#183;kg/s <sup>3 </sup>&#183;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>&#183;A <sup>2 </sup>/m <sup>2 </sup>&#183;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>&#183;kg/s <sup>3 </sup>&#183;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>&#183;A <sup>2 </sup>/m <sup>2 </sup>&#183;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&#183;s or is expressed in SI units as m <sup>2
+	 * </sup>&#183;kg/s <sup>2 </sup>&#183;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>&#183;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			};
+	private static Hashtable	base;
+	private String				name;
+	private long				type;
+
+	/**
+	 * Creates a new <code>Unit</code> instance.
+	 * 
+	 * @param name the name of the <code>Unit</code>
+	 * @param type the type of the <code>Unit</code>
+	 */
+	private Unit(String name, long 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</code> object is equal to the specified
+	 * <code>Unit</code> object. The <code>Unit</code> objects are considered equal
+	 * if their exponents are equal.
+	 * 
+	 * @param obj the <code>Unit</code> object that should be checked for equality
+	 * 
+	 * @return true if the specified <code>Unit</code> object is equal to this
+	 *         <code>Unit</code> 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 (int) ((type >>> 32) ^ type);
+	}
+
+	/**
+	 * Returns a new <code>Unit</code> that is the multiplication of this
+	 * <code>Unit</code> and the <code>Unit</code> specified
+	 * 
+	 * @param that the <code>Unit</code> that will be multiplied with this
+	 *        <code>Unit</code>
+	 * 
+	 * @return a new <code>Unit</code> that is the multiplication of this
+	 *         <code>Unit</code> and the <code>Unit</code> specified
+	 * 
+	 * @throws RuntimeException if both <code>Unit</code> 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</code> that is the division of this <code>Unit</code>
+	 * and the <code>Unit</code> specified
+	 * 
+	 * @param that the <code>Unit</code> that this <code>Unit</code> will be divided
+	 *        with
+	 * @return a new <code>Unit</code> that is the division of this <code>Unit</code>
+	 *         and the <code>Unit</code> specified
+	 * 
+	 * @throws RuntimeException if both <code>Unit</code> 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</code> that is the addition of this <code>Unit</code>
+	 * and the <code>Unit</code> specified.
+	 * 
+	 * @param that the <code>Unit</code> that should be added to this
+	 *        <code>Unit</code>
+	 * 
+	 * @return a new <code>Unit</code> that is the addition of this <code>Unit</code>
+	 *         and the <code>Unit</code> specified.
+	 * 
+	 * @throws RuntimeException if the two <code>Unit</code> 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</code> that is the subtraction between this
+	 * <code>Unit</code> and the <code>Unit</code> specified.
+	 * 
+	 * @param that the <code>Unit</code> that will be subtracted from this
+	 *        <code>Unit</code>
+	 * @return a new <code>Unit</code> that is the subtraction between this
+	 *         <code>Unit</code> and the <code>Unit</code> specified.
+	 * 
+	 * @throws RuntimeException if the <code>Unit</code> specified is not the same
+	 *         as this <code>Unit</code>
+	 */
+	Unit sub(Unit that) {
+		if (!this.equals(that)) {
+			throw new ArithmeticException("Cannot subtract " + that + " from "
+					+ this);
+		}
+		return this;
+	}
+
+	/**
+	 * Finds a <code>Unit</code> based on a type. If the <code>Unit</code> 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</code> to find
+	 * 
+	 * @return the <code>Unit</code>
+	 */
+	static Unit find(long type) {
+		if (base == null) {
+			synchronized (Unit.class) {
+				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</code> object representing the <code>Unit</code>
+	 * 
+	 * @return A <code>String</code> object representing the <code>Unit</code>
+	 */
+	public String toString() {
+		if (name == null) {
+			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((Object) denominator); /*
+														 * we use (Object) to
+														 * avoid using new 1.4
+														 * method
+														 * append(StringBuffer)
+														 */
+			}
+			name = numerator.toString();
+		}
+		return name;
+	}
+
+	private 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;
+	}
+}

Propchange: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Unit.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/package.html
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/package.html?rev=389891&view=auto
==============================================================================
--- incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/package.html (added)
+++ incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/package.html Wed Mar 29 13:05:08 2006
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.util.measurement/src/org/osgi/util/measurement/package.html,v 1.4 2005/05/27 01:25:29 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Measurement Package. Specification Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.util.measurement; version=1.0
+</pre>
+</BODY>

Propchange: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/packageinfo
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/packageinfo?rev=389891&view=auto
==============================================================================
--- incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/packageinfo (added)
+++ incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/packageinfo Wed Mar 29 13:05:08 2006
@@ -0,0 +1 @@
+version 1.0
\ No newline at end of file

Propchange: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/packageinfo
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/Position.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/Position.java?rev=389891&view=auto
==============================================================================
--- incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/Position.java (added)
+++ incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/Position.java Wed Mar 29 13:05:08 2006
@@ -0,0 +1,236 @@
+/*
+ * $Header: /cvshome/build/org.osgi.util.position/src/org/osgi/util/position/Position.java,v 1.7 2006/03/14 01:20:44 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.*;
+
+/**
+ * Position represents a geographic location, based on the WGS84 System (World
+ * Geodetic System 1984).
+ * <p>
+ * The <code>org.osgi.util.measurement.Measurement</code> 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</code> object is immutable.
+ */
+public class Position {
+	private Measurement	altitude;
+	private Measurement	longitude;
+	private Measurement	latitude;
+	private Measurement	speed;
+	private Measurement	track;
+
+	/**
+	 * Contructs a <code>Position</code> object with the given values.
+	 * 
+	 * @param lat a <code>Measurement</code> object specifying the latitude in
+	 *        radians, or null
+	 * @param lon a <code>Measurement</code> object specifying the longitude in
+	 *        radians, or null
+	 * @param alt a <code>Measurement</code> object specifying the altitude in
+	 *        meters, or null
+	 * @param speed a <code>Measurement</code> object specifying the speed in
+	 *        meters per second, or null
+	 * @param track a <code>Measurement</code> 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");
+			}
+			this.latitude = lat;
+		}
+		if (lon != null) {
+			if (!Unit.rad.equals(lon.getUnit())) {
+				throw new IllegalArgumentException("Invalid Longitude");
+			}
+			this.longitude = lon;
+		}
+		normalizeLatLon();
+		if (alt != null) {
+			if (!Unit.m.equals(alt.getUnit())) {
+				throw new IllegalArgumentException("Invalid Altitude");
+			}
+			this.altitude = alt;
+		}
+		if (speed != null) {
+			if (!Unit.m_s.equals(speed.getUnit())) {
+				throw new IllegalArgumentException("Invalid Speed");
+			}
+			this.speed = speed;
+		}
+		if (track != null) {
+			if (!Unit.rad.equals(track.getUnit())) {
+				throw new IllegalArgumentException("Invalid Track");
+			}
+			this.track = normalizeTrack(track);
+		}
+	}
+
+	/**
+	 * Returns the altitude of this position in meters.
+	 * 
+	 * @return a <code>Measurement</code> object in <code>Unit.m</code> representing
+	 *         the altitude in meters above the ellipsoid <code>null</code> if the
+	 *         altitude is not known.
+	 */
+	public Measurement getAltitude() {
+		return altitude;
+	}
+
+	/**
+	 * Returns the longitude of this position in radians.
+	 * 
+	 * @return a <code>Measurement</code> object in <code>Unit.rad</code>
+	 *         representing the longitude, or <code>null</code> if the longitude
+	 *         is not known.
+	 */
+	public Measurement getLongitude() {
+		return longitude;
+	}
+
+	/**
+	 * Returns the latitude of this position in radians.
+	 * 
+	 * @return a <code>Measurement</code> object in <code>Unit.rad</code>
+	 *         representing the latitude, or <code>null</code> 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</code> object in <code>Unit.m_s</code>
+	 *         representing the speed, or <code>null</code> 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</code> object in <code>Unit.rad</code>
+	 *         representing the track, or <code>null</code> 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;
+
+	/**
+	 * Verify the longitude and latitude parameters so they fit the normal
+	 * coordinate system. A latitude is between -90 (south) and +90 (north). A 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) <br>
+	 * No normalization takes place when either lon or lat is null.
+	 */
+	private void normalizeLatLon() {
+		if (longitude == null || latitude == null)
+			return;
+		double dlon = longitude.getValue();
+		double dlat = latitude.getValue();
+		if (dlon >= -LON_RANGE && dlon < LON_RANGE && dlat >= -LAT_RANGE
+				&& dlat <= LAT_RANGE)
+			return;
+		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);
+		}
+		longitude = new Measurement(dlon, longitude.getError(), longitude
+				.getUnit(), longitude.getTime());
+		latitude = new Measurement(dlat, latitude.getError(), latitude
+				.getUnit(), latitude.getTime());
+	}
+
+	/**
+	 * 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&gt; The algorithm is not very fast, but it handling the
+	 * [&gt; 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 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;
+
+	/**
+	 * Normalize track to be a value such that: 0 <= value < +2PI. This
+	 * corresponds to 0 deg to +360 deg. 0 is North 0.5*PI is East PI is South
+	 * 1.5*PI is West
+	 * 
+	 * @param track Value to be normalized
+	 * @return Normalized value
+	 */
+	private Measurement normalizeTrack(Measurement track) {
+		double value = track.getValue();
+		if ((0.0D <= value) && (value < TRACK_RANGE)) {
+			return track; /* value is already normalized */
+		}
+		value %= TRACK_RANGE;
+		if (value < 0.0D) {
+			value += TRACK_RANGE;
+		}
+		return new Measurement(value, track.getError(), track.getUnit(), track
+				.getTime());
+	}
+}

Propchange: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/Position.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/package.html
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/package.html?rev=389891&view=auto
==============================================================================
--- incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/package.html (added)
+++ incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/package.html Wed Mar 29 13:05:08 2006
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.util.position/src/org/osgi/util/position/package.html,v 1.2 2004/12/01 19:00:53 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Position Package. Specification Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.util.position; version=1.0
+</pre>
+</BODY>

Propchange: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/packageinfo
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/packageinfo?rev=389891&view=auto
==============================================================================
--- incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/packageinfo (added)
+++ incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/packageinfo Wed Mar 29 13:05:08 2006
@@ -0,0 +1 @@
+version 1.0
\ No newline at end of file

Propchange: incubator/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/packageinfo
------------------------------------------------------------------------------
    svn:eol-style = native