geo/src/main/java/net/java/html/geo/Position.java
author Jaroslav Tulach <jtulach@netbeans.org>
Sat, 02 Aug 2014 12:59:31 +0200
changeset 790 30f20d9c0986
parent 727 66f03ad8f00f
child 842 ebb2428bb7e1
permissions -rw-r--r--
Fixing Javadoc to succeed on JDK8
     1 /**
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
     5  *
     6  * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
     7  * Other names may be trademarks of their respective owners.
     8  *
     9  * The contents of this file are subject to the terms of either the GNU
    10  * General Public License Version 2 only ("GPL") or the Common
    11  * Development and Distribution License("CDDL") (collectively, the
    12  * "License"). You may not use this file except in compliance with the
    13  * License. You can obtain a copy of the License at
    14  * http://www.netbeans.org/cddl-gplv2.html
    15  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    16  * specific language governing permissions and limitations under the
    17  * License.  When distributing the software, include this License Header
    18  * Notice in each file and include the License file at
    19  * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    20  * particular file as subject to the "Classpath" exception as provided
    21  * by Oracle in the GPL Version 2 section of the License file that
    22  * accompanied this code. If applicable, add the following below the
    23  * License Header, with the fields enclosed by brackets [] replaced by
    24  * your own identifying information:
    25  * "Portions Copyrighted [year] [name of copyright owner]"
    26  *
    27  * Contributor(s):
    28  *
    29  * The Original Software is NetBeans. The Initial Developer of the Original
    30  * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
    31  *
    32  * If you wish your version of this file to be governed by only the CDDL
    33  * or only the GPL Version 2, indicate your decision by adding
    34  * "[Contributor] elects to include this software in this distribution
    35  * under the [CDDL or GPL Version 2] license." If you do not indicate a
    36  * single choice of license, a recipient has the option to distribute
    37  * your version of this file under either the CDDL, the GPL Version 2 or
    38  * to extend the choice of license to its licensees as provided above.
    39  * However, if you add GPL Version 2 code and therefore, elected the GPL
    40  * Version 2 license, then the option applies only if the new code is
    41  * made subject to such option by the copyright holder.
    42  */
    43 package net.java.html.geo;
    44 
    45 import java.util.logging.Level;
    46 import java.util.logging.Logger;
    47 import org.netbeans.html.geo.impl.JsG;
    48 
    49 /** Class that represents a geolocation position provided as a callback
    50  * to {@link Handle#onLocation(net.java.html.geo.Position)} method. The
    51  * class getters mimic closely the structure of the position object as
    52  * specified by <a href="http://www.w3.org/TR/geolocation-API/">
    53  * W3C's Geolocation API</a>.
    54  *
    55  * @author Jaroslav Tulach
    56  */
    57 public final class Position {
    58     static final Logger LOG = Logger.getLogger(Position.class.getName());
    59     private final long timestamp;
    60     private final Coordinates coords;
    61 
    62     Position(Object position) {
    63         Object obj = JsG.get(position, "timestamp");
    64         timestamp = obj instanceof Number ? ((Number)obj).longValue() : 0L;
    65         coords = new Coordinates(JsG.get(position, "coords"));
    66     }
    67     
    68     /** The actual location of the position.
    69      * @return non-null coordinates
    70      */
    71     public Coordinates getCoords() {
    72         return coords;
    73     }
    74     
    75     /** The time when the position has been recorded.
    76      * @return time in milliseconds since era (e.g. Jan 1, 1970).
    77      */
    78     public long getTimestamp() {
    79         return timestamp;
    80     }
    81 
    82     /** Actual location of a {@link Position}. 
    83      *  Mimics closely <a href="http://www.w3.org/TR/geolocation-API/">
    84      * W3C's Geolocation API</a>.
    85      */
    86     public static final class Coordinates {
    87         private final Object data;
    88 
    89         Coordinates(Object data) {
    90             this.data = data;
    91         }
    92         
    93         /**
    94          * @return geographic coordinate specified in decimal degrees.
    95          */
    96         public double getLatitude() {
    97             return ((Number)JsG.get(data, "latitude")).doubleValue(); // NOI18N
    98         }
    99 
   100         /**
   101          * @return geographic coordinate specified in decimal degrees.
   102          */
   103         public double getLongitude() {
   104             return ((Number)JsG.get(data, "longitude")).doubleValue(); // NOI18N
   105         } 
   106 
   107         /**
   108          * The accuracy attribute denotes the accuracy level of the latitude 
   109          * and longitude coordinates. It is specified in meters. 
   110          * The value of the accuracy attribute must be a non-negative number.
   111          * 
   112          * @return accuracy in meters
   113          */
   114         public double getAccuracy() {
   115             return ((Number)JsG.get(data, "accuracy")).doubleValue(); // NOI18N
   116         }
   117         
   118         /** Denotes the height of the position, specified in meters above the ellipsoid. 
   119          * If the implementation cannot provide altitude information, 
   120          * the value of this attribute must be null.
   121          * @return value in meters, may return null, if the information is not available 
   122          */
   123         public Double getAltitude() {
   124             return (Double)JsG.get(data, "altitude"); // NOI18N
   125         }
   126         
   127         /**  The altitude accuracy is specified in meters. 
   128          * If the implementation cannot provide altitude information, 
   129          * the value of this attribute must be null. Otherwise, the value 
   130          * must be a non-negative real number.
   131          * @return value in meters; may return null, if the information is not available 
   132          */
   133         public Double getAltitudeAccuracy() {
   134             return (Double)JsG.get(data, "altitudeAccuracy"); // NOI18N
   135         }
   136         
   137         /** @return may return null, if the information is not available */
   138         public Double getHeading() {
   139             return (Double)JsG.get(data, "heading"); // NOI18N
   140         }
   141         
   142         /** @return may return null, if the information is not available */
   143         public Double getSpeed() {
   144             return (Double)JsG.get(data, "speed"); // NOI18N
   145         }
   146     } // end of Coordinates
   147 
   148     /** Rather than subclassing this class directly consider using {@link OnLocation}
   149      * annotation. Such annotation will generate a subclass for you automatically
   150      * with two static methods <code>createQuery</code> and <code>createWatch</code>
   151      * which can be used to obtain instance of this class.
   152      */
   153     public static abstract class Handle {
   154         private final boolean oneTime;
   155         private boolean enableHighAccuracy;
   156         private long timeout;
   157         private long maximumAge;
   158         volatile JsH handle;
   159 
   160         /** Creates new instance of this handle.
   161          * 
   162          * @param oneTime <code>true</code> if the handle represents one time 
   163          *   <em>query</em>. <code>false</code> if it represents a <em>watch</em>
   164          */
   165         protected Handle(boolean oneTime) {
   166             super();
   167             this.oneTime = oneTime;
   168         }
   169 
   170         /** Callback from the implementation when a (new) position has been
   171          * received and identified
   172          * @param p the position
   173          * @throws Throwable if an exception is thrown, it will be logged by the system
   174          */
   175         protected abstract void onLocation(Position p) throws Throwable;
   176 
   177         /** Callback when an error occurs.
   178          * @param ex the exception describing what went wrong
   179          * @throws Throwable if an exception is thrown, it will be logged by the system
   180          */
   181         protected abstract void onError(Exception ex) throws Throwable;
   182         
   183         /** Check whether the location API is supported.
   184          * @return true, if one can call {@link #start}.
   185          */
   186         public final boolean isSupported() {
   187             return JsG.hasGeolocation();
   188         }
   189 
   190         /** Turns on high accuracy mode as specified by the 
   191          * <a href="http://www.w3.org/TR/2012/PR­geolocation­API­20120510/">
   192          * W3C's Geolocation API</a>. By default the mode is disabled.
   193          * @param enable <code>true</code> or <code>false</code>
   194          */
   195         public final void setHighAccuracy(boolean enable) {
   196             this.enableHighAccuracy = enable;
   197         }
   198 
   199         /** The amount of milliseconds to wait for a result.
   200          * By default infinity.
   201          * @param timeout time in milliseconds to wait for a result.
   202          */
   203         public final void setTimeout(long timeout) {
   204             this.timeout = timeout;
   205         }
   206 
   207         /** Sets maximum age of cached results which are acceptable to be
   208          * returned. By default maximum age is set to zero.
   209          * @param age time in milliseconds of acceptable cached results
   210          */
   211         public final void setMaximumAge(long age) {
   212             this.maximumAge = age;
   213         }
   214         
   215         /** Initializes the <em>query</em> or <em>watch</em> request(s) and
   216          * returns immediately. Has no effect if the query has already been
   217          * started. If a problem appears while starting the system,
   218          * it is immediately reported via the {@link #onError(java.lang.Exception)}
   219          * callback. For example, if the {@link #isSupported()} method
   220          * returns <code>false</code> an IllegalStateException is created
   221          * and sent to the {@link #onError(java.lang.Exception) callback} method.
   222          */
   223         public final void start() {
   224             if (handle != null) {
   225                 return;
   226             }
   227             handle = new JsH();
   228             try {
   229                 if (!isSupported()) {
   230                     throw new IllegalStateException("geolocation API not supported");
   231                 }
   232                 handle.start();
   233             } catch (Exception ex) {
   234                 try {
   235                     onError(ex);
   236                 } catch (Throwable thr) {
   237                     LOG.log(Level.INFO, "Problems delivering onError report", thr);
   238                 }
   239             }
   240         }
   241 
   242         /** Stops all pending requests. After this call no further callbacks
   243          * can be obtained. Does nothing if no query or watch was in progress.
   244          */
   245         public final void stop() {
   246             JsH h = handle;
   247             if (h == null) {
   248                 return;
   249             }
   250             handle = null;
   251             h.stop();
   252         }
   253 
   254         private final class JsH extends JsG {
   255             long watch;
   256             
   257             @Override
   258             public void onLocation(Object position) {
   259                 if (handle != this) {
   260                     return;
   261                 }
   262                 if (oneTime) {
   263                     stop();
   264                 }
   265                 try {
   266                     Handle.this.onLocation(new Position(position));
   267                 } catch (Throwable ex) {
   268                     LOG.log(Level.SEVERE, null, ex);
   269                 }
   270             }
   271 
   272             @Override
   273             public void onError(final String message, int code) {
   274                 if (handle != this) {
   275                     return;
   276                 }
   277                 if (oneTime) {
   278                     stop();
   279                 }
   280                 try {
   281                     final Exception err = new Exception(message + " errno: " + code) {
   282                         @Override
   283                         public String getLocalizedMessage() {
   284                             return message;
   285                         }
   286                     };
   287                     Handle.this.onError(err);
   288                 } catch (Throwable ex) {
   289                     LOG.log(Level.SEVERE, null, ex);
   290                 }
   291             }
   292 
   293             final void start() {
   294                 watch = start(oneTime, enableHighAccuracy, timeout, maximumAge);
   295             }
   296 
   297             protected final void stop() {
   298                 super.stop(watch);
   299             }
   300         }
   301     }
   302 }