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