You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by jt...@apache.org on 2017/09/03 12:48:49 UTC

[16/24] incubator-netbeans-html4j git commit: [INFRA-15006] Initial donation of HTML/Java NetBeans API. Equivalent to the content of html4j-donation-review.zip donated as part of ApacheNetBeansDonation1.zip with SHA256 being 7f2ca0f61953a190613c9a0fbcc1b

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/equinox-agentclass-hook/src/main/resources/hookconfigurators.properties
----------------------------------------------------------------------
diff --git a/equinox-agentclass-hook/src/main/resources/hookconfigurators.properties b/equinox-agentclass-hook/src/main/resources/hookconfigurators.properties
new file mode 100644
index 0000000..d9fe69e
--- /dev/null
+++ b/equinox-agentclass-hook/src/main/resources/hookconfigurators.properties
@@ -0,0 +1,44 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+#
+# Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+# Other names may be trademarks of their respective owners.
+#
+# The contents of this file are subject to the terms of either the GNU
+# General Public License Version 2 only ("GPL") or the Common
+# Development and Distribution License("CDDL") (collectively, the
+# "License"). You may not use this file except in compliance with the
+# License. You can obtain a copy of the License at
+# http://www.netbeans.org/cddl-gplv2.html
+# or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+# specific language governing permissions and limitations under the
+# License.  When distributing the software, include this License Header
+# Notice in each file and include the License file at
+# nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the GPL Version 2 section of the License file that
+# accompanied this code. If applicable, add the following below the
+# License Header, with the fields enclosed by brackets [] replaced by
+# your own identifying information:
+# "Portions Copyrighted [year] [name of copyright owner]"
+#
+# Contributor(s):
+#
+# The Original Software is NetBeans. The Initial Developer of the Original
+# Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+#
+# If you wish your version of this file to be governed by only the CDDL
+# or only the GPL Version 2, indicate your decision by adding
+# "[Contributor] elects to include this software in this distribution
+# under the [CDDL or GPL Version 2] license." If you do not indicate a
+# single choice of license, a recipient has the option to distribute
+# your version of this file under either the CDDL, the GPL Version 2 or
+# to extend the choice of license to its licensees as provided above.
+# However, if you add GPL Version 2 code and therefore, elected the GPL
+# Version 2 license, then the option applies only if the new code is
+# made subject to such option by the copyright holder.
+#
+
+hook.configurators=org.netbeans.html.equinox.agentclass.AgentHook

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/pom.xml
----------------------------------------------------------------------
diff --git a/geo/pom.xml b/geo/pom.xml
new file mode 100644
index 0000000..741c6d3
--- /dev/null
+++ b/geo/pom.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+    Copyright 2013-2016 Oracle and/or its affiliates. All rights reserved.
+
+    Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+    Other names may be trademarks of their respective owners.
+
+    The contents of this file are subject to the terms of either the GNU
+    General Public License Version 2 only ("GPL") or the Common
+    Development and Distribution License("CDDL") (collectively, the
+    "License"). You may not use this file except in compliance with the
+    License. You can obtain a copy of the License at
+    http://www.netbeans.org/cddl-gplv2.html
+    or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+    specific language governing permissions and limitations under the
+    License.  When distributing the software, include this License Header
+    Notice in each file and include the License file at
+    nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+    particular file as subject to the "Classpath" exception as provided
+    by Oracle in the GPL Version 2 section of the License file that
+    accompanied this code. If applicable, add the following below the
+    License Header, with the fields enclosed by brackets [] replaced by
+    your own identifying information:
+    "Portions Copyrighted [year] [name of copyright owner]"
+
+    Contributor(s):
+
+    The Original Software is NetBeans. The Initial Developer of the Original
+    Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+
+    If you wish your version of this file to be governed by only the CDDL
+    or only the GPL Version 2, indicate your decision by adding
+    "[Contributor] elects to include this software in this distribution
+    under the [CDDL or GPL Version 2] license." If you do not indicate a
+    single choice of license, a recipient has the option to distribute
+    your version of this file under either the CDDL, the GPL Version 2 or
+    to extend the choice of license to its licensees as provided above.
+    However, if you add GPL Version 2 code and therefore, elected the GPL
+    Version 2 license, then the option applies only if the new code is
+    made subject to such option by the copyright holder.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.netbeans.html</groupId>
+    <artifactId>pom</artifactId>
+    <version>2.0-SNAPSHOT</version>
+  </parent>
+  <groupId>org.netbeans.html</groupId>
+  <artifactId>net.java.html.geo</artifactId>
+  <version>2.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+  <name>Geolocation API</name>
+  <url>http://maven.apache.org</url>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <publicPackages>net.java.html.geo,org.netbeans.html.geo.spi</publicPackages>
+  </properties>
+  <build>
+      <plugins>
+          <plugin>
+              <groupId>org.apache.felix</groupId>
+              <artifactId>maven-bundle-plugin</artifactId>
+          </plugin>
+          <plugin>
+              <groupId>org.netbeans.html</groupId>
+              <artifactId>html4j-maven-plugin</artifactId>
+          </plugin>
+      </plugins>
+  </build>
+  <dependencies>
+      <dependency>
+          <groupId>org.testng</groupId>
+          <artifactId>testng</artifactId>
+      </dependency>
+    <dependency>
+      <groupId>org.netbeans.api</groupId>
+      <artifactId>org-openide-util-lookup</artifactId>
+      <type>jar</type>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.netbeans.html</groupId>
+      <artifactId>net.java.html.boot</artifactId>
+      <version>${project.version}</version>
+      <type>jar</type>
+    </dependency>
+  </dependencies>
+    <description>Find out where your Java program running in an HTML page is!</description>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/net/java/html/geo/OnLocation.java
----------------------------------------------------------------------
diff --git a/geo/src/main/java/net/java/html/geo/OnLocation.java b/geo/src/main/java/net/java/html/geo/OnLocation.java
new file mode 100644
index 0000000..07dc8a6
--- /dev/null
+++ b/geo/src/main/java/net/java/html/geo/OnLocation.java
@@ -0,0 +1,96 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package net.java.html.geo;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Generates a handle which can configure, {@link Position.Handle#start() start}
+ * and {@link Position.Handle#stop() stop} requests for obtaining current
+ * location of the application/device/user. Put the {@link OnLocation} annotation
+ * on top of a (non-private) method in your class which takes one argument
+ * {@link Position}. Based on name of your method (unless a class name is
+ * directly specified via {@link #className()} attribute) a handle class is
+ * generated. For example if your method name is <code>callMeWhenYouKnowWhereYouAre</code>
+ * a package private class <code>CallMeWhenYouKnowWhereYouAreHandle</code> will
+ * be generated in the same package. One can use its <code>createQuery</code>
+ * and <code>createWatch</code> static method to get one time/repeated time
+ * instance of a {@link Position.Handle handle}. After configuring the
+ * {@link Position.Handle handle} via its setter methods, one can 
+ * {@link Position.Handle#start() start} the location request.
+ * <p>
+ * In case something goes wrong a method in the same class named {@link #onError()}
+ * can be specified (should take one {@link Exception} parameter). 
+ * <p>
+ * The overall behavior of the system mimics <a href="http://www.w3.org/TR/geolocation-API/">
+ * W3C's Geolocation API</a>.
+ *
+ * @author Jaroslav Tulach
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.METHOD)
+public @interface OnLocation {
+    /** Name of the {@link Position.Handle handle} class to generate. By
+     * default the name is derived from the name of annotated method by
+     * capitalizing the first character and appending <code>Handle</code>.
+     * <p>
+     * The generated class contains two static methods: <code>createQuery</code>
+     * and <code>createWatch</code> which take no parameters if this method 
+     * is static or one parameter (of this class) if this method is instance
+     * one. Both static methods return {@link Position.Handle}.
+     * 
+     * @return string suitable for a new class in the same package
+     */
+    public String className() default "";
+    
+    /** Name of a method in this class which should be called in case of 
+     * an error. The method has to be non-private and take {@link Exception} 
+     * parameter. If this method is not specified, the exception is just
+     * printed to console.
+     * 
+     * @return name of method in this class
+     */
+    public String onError() default "";
+}

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/net/java/html/geo/Position.java
----------------------------------------------------------------------
diff --git a/geo/src/main/java/net/java/html/geo/Position.java b/geo/src/main/java/net/java/html/geo/Position.java
new file mode 100644
index 0000000..4f2edb8
--- /dev/null
+++ b/geo/src/main/java/net/java/html/geo/Position.java
@@ -0,0 +1,383 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package net.java.html.geo;
+
+import java.util.Collections;
+import java.util.ServiceLoader;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.geo.impl.Accessor;
+import org.netbeans.html.geo.impl.JsGLProvider;
+import org.netbeans.html.geo.spi.GLProvider;
+
+/** Class that represents a geolocation position provided as a callback
+ * to {@link Handle#onLocation(net.java.html.geo.Position)} method. The
+ * class getters mimic closely the structure of the position object as
+ * specified by <a href="http://www.w3.org/TR/geolocation-API/">
+ * W3C's Geolocation API</a>.
+ *
+ * @author Jaroslav Tulach
+ */
+public final class Position {
+    static final Logger LOG = Logger.getLogger(Position.class.getName());
+    private final long timestamp;
+    private final Coordinates coords;
+
+    public Position(long timestamp, Coordinates coords) {
+        this.timestamp = timestamp;
+        this.coords = coords;
+    }
+    
+    /** The actual location of the position.
+     * @return non-null coordinates
+     */
+    public Coordinates getCoords() {
+        return coords;
+    }
+    
+    /** The time when the position has been recorded.
+     * @return time in milliseconds since era (e.g. Jan 1, 1970).
+     */
+    public long getTimestamp() {
+        return timestamp;
+    }
+
+    /** Actual location of a {@link Position}. 
+     *  Mimics closely <a href="http://www.w3.org/TR/geolocation-API/">
+     * W3C's Geolocation API</a>.
+     */
+    public static abstract class Coordinates {
+        protected Coordinates() {
+            if (!getClass().getName().equals("org.netbeans.html.geo.spi.CoordImpl")) {
+                throw new IllegalStateException();
+            }
+        }
+        
+        /**
+         * @return geographic coordinate specified in decimal degrees.
+         */
+        public abstract double getLatitude();
+
+        /**
+         * @return geographic coordinate specified in decimal degrees.
+         */
+        public abstract double getLongitude();
+
+        /**
+         * The accuracy attribute denotes the accuracy level of the latitude 
+         * and longitude coordinates. It is specified in meters. 
+         * The value of the accuracy attribute must be a non-negative number.
+         * 
+         * @return accuracy in meters
+         */
+        public abstract double getAccuracy();
+        
+        /** Denotes the height of the position, specified in meters above the ellipsoid. 
+         * If the implementation cannot provide altitude information, 
+         * the value of this attribute must be null.
+         * @return value in meters, may return null, if the information is not available 
+         */
+        public abstract Double getAltitude();
+        
+        /**  The altitude accuracy is specified in meters. 
+         * If the implementation cannot provide altitude information, 
+         * the value of this attribute must be null. Otherwise, the value 
+         * must be a non-negative real number.
+         * @return value in meters; may return null, if the information is not available 
+         */
+        public abstract Double getAltitudeAccuracy();
+        
+        /** Denotes the direction of travel of the device and 
+         * is specified in degrees 
+         * counting clockwise relative to the true north. 
+         * 
+         * @return value from 0 to 360 - may return <code>null</code>, 
+         *   if the information is not available 
+         */
+        public abstract Double getHeading();
+        
+        /** Denotes the magnitude of the horizontal component of the 
+         * device's current velocity and is specified in meters per second.
+         * 
+         * @return may return null, if the information is not available 
+         */
+        public abstract Double getSpeed();
+    } // end of Coordinates
+
+    /** Rather than subclassing this class directly consider using {@link OnLocation}
+     * annotation. Such annotation will generate a subclass for you automatically
+     * with two static methods <code>createQuery</code> and <code>createWatch</code>
+     * which can be used to obtain instance of this class.
+     */
+    public static abstract class Handle {
+        private final boolean oneTime;
+        private boolean enableHighAccuracy;
+        private long timeout;
+        private long maximumAge;
+        volatile JsH<?> handle;
+
+        /** Creates new instance of this handle.
+         * 
+         * @param oneTime <code>true</code> if the handle represents one time 
+         *   <em>query</em>. <code>false</code> if it represents a <em>watch</em>
+         */
+        protected Handle(boolean oneTime) {
+            super();
+            this.oneTime = oneTime;
+        }
+
+        /** Callback from the implementation when a (new) position has been
+         * received and identified
+         * @param p the position
+         * @throws Throwable if an exception is thrown, it will be logged by the system
+         */
+        protected abstract void onLocation(Position p) throws Throwable;
+
+        /** Callback when an error occurs.
+         * @param ex the exception describing what went wrong
+         * @throws Throwable if an exception is thrown, it will be logged by the system
+         */
+        protected abstract void onError(Exception ex) throws Throwable;
+        
+        /** Check whether the location API is supported.
+         * @return true, if one can call {@link #start}.
+         */
+        public final boolean isSupported() {
+            JsH<?> p = seekProviders(null, null);
+            if (p != null) {
+                p.stop();
+                return true;
+            }
+            return false;
+        }
+
+        /** Turns on high accuracy mode as specified by the 
+         * <a href="http://www.w3.org/TR/2012/PR­geolocation­API­20120510/">
+         * W3C's Geolocation API</a>. By default the mode is disabled.
+         * @param enable <code>true</code> or <code>false</code>
+         */
+        public final void setHighAccuracy(boolean enable) {
+            this.enableHighAccuracy = enable;
+        }
+
+        /** The amount of milliseconds to wait for a result.
+         * By default infinity.
+         * @param timeout time in milliseconds to wait for a result.
+         */
+        public final void setTimeout(long timeout) {
+            this.timeout = timeout;
+        }
+
+        /** Sets maximum age of cached results which are acceptable to be
+         * returned. By default maximum age is set to zero.
+         * @param age time in milliseconds of acceptable cached results
+         */
+        public final void setMaximumAge(long age) {
+            this.maximumAge = age;
+        }
+        
+        /** Initializes the <em>query</em> or <em>watch</em> request(s) and
+         * returns immediately. Has no effect if the query has already been
+         * started. If a problem appears while starting the system,
+         * it is immediately reported via the {@link #onError(java.lang.Exception)}
+         * callback. For example, if the {@link #isSupported()} method
+         * returns <code>false</code> an IllegalStateException is created
+         * and sent to the {@link #onError(java.lang.Exception) callback} method.
+         */
+        public final void start() {
+            if (handle != null) {
+                return;
+            }
+            
+            Exception[] problem = { null };
+            StringBuilder sb = new StringBuilder();
+            sb.append("[");
+            JsH<?> h = seekProviders(sb, problem);
+            sb.append("\n]");
+            try {
+                if (problem[0] != null) {
+                    onError(problem[0]);
+                    return;
+                }
+                if (h == null) {
+                    onError(new IllegalStateException("geolocation API not supported. Among providers: " + sb));
+                }
+                synchronized (this) {
+                    if (handle != null) {
+                        onError(new IllegalStateException("Parallel request"));
+                    }
+                    handle = h;
+                }
+            } catch (Throwable thr) {
+                LOG.log(Level.INFO, "Problems delivering onError report", thr);
+            }
+        }
+
+        private JsH<?> seekProviders(StringBuilder sb, Exception[] problem) {
+            BrwsrCtx ctx = BrwsrCtx.findDefault(getClass());
+            JsH<?> h = seekProviders(Contexts.find(ctx, GLProvider.class), null, sb, problem);
+            if (h == null) {
+                h = seekProviders(null, ServiceLoader.load(GLProvider.class), sb, problem);
+            }
+            if (h == null) {
+                h = seekProviders(new JsGLProvider(), null, sb, problem);
+            }
+            return h;
+        }
+
+        private JsH<?> seekProviders(
+            GLProvider single, Iterable<GLProvider> set,
+            StringBuilder sb, Exception[] problem
+        ) {
+            if (set == null) {
+                if (single == null) {
+                    return null;
+                }
+                set = Collections.singleton(single);
+            }
+            JsH<?> h = null;
+            for (GLProvider<?,?> p : set) {
+                if (sb != null) {
+                    if (sb.length() > 1) {
+                        sb.append(',');
+                    }
+                    sb.append("\n  ").append(p.getClass().getName());
+                }
+                try {
+                    h = createHandle(p);
+                } catch (Exception ex) {
+                    LOG.log(Level.INFO, "Problems when starting " + p.getClass().getName(), ex);
+                    if (problem != null && problem[0] == null) {
+                        problem[0] = ex;
+                    }
+                }
+                if (h != null) {
+                    break;
+                }
+            }
+            return h;
+        }
+
+        /** Stops all pending requests. After this call no further callbacks
+         * can be obtained. Does nothing if no query or watch was in progress.
+         */
+        public final void stop() {
+            JsH h;
+            synchronized (this) {
+                h = handle;
+                if (h == null) {
+                    return;
+                }
+                handle = null;
+            }
+            h.stop();
+        }
+        
+        private <Watch> JsH<Watch> createHandle(GLProvider<?,Watch> p) {
+            JsH<Watch> temp = new JsH<Watch>(p);
+            return temp.watch == null ? null : temp;
+        }
+
+        private final class JsH<Watch> extends Accessor {
+            private final Watch watch;
+            private final GLProvider<?, Watch> provider;
+            
+            public JsH(GLProvider<?, Watch> p) {
+                super(true);
+                this.watch = Accessor.SPI.start(p, this, oneTime, enableHighAccuracy, timeout, maximumAge);
+                this.provider = p;
+            }
+            
+            @Override
+            public void onLocation(Position position) {
+                if (handle != this) {
+                    return;
+                }
+                if (oneTime) {
+                    stop();
+                }
+                try {
+                    Handle.this.onLocation(position);
+                } catch (Throwable ex) {
+                    LOG.log(Level.SEVERE, null, ex);
+                }
+            }
+
+            @Override
+            public void onError(Exception err) {
+                if (handle != this) {
+                    return;
+                }
+                if (oneTime) {
+                    stop();
+                }
+                try {
+                    Handle.this.onError(err);
+                } catch (Throwable ex) {
+                    LOG.log(Level.SEVERE, null, ex);
+                }
+            }
+
+            protected final void stop() {
+                Accessor.SPI.stop(provider, watch);
+            }
+
+            @Override
+            public <Watch> Watch start(
+                GLProvider<?, Watch> p, Accessor peer,
+                boolean oneTime, boolean enableHighAccuracy,
+                long timeout, long maximumAge
+            ) {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public <Watch> void stop(GLProvider<?, Watch> p, Watch w) {
+                throw new UnsupportedOperationException();
+            }
+
+        } // end of JsH
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/net/java/html/geo/doc-files/GeoDuke.png
----------------------------------------------------------------------
diff --git a/geo/src/main/java/net/java/html/geo/doc-files/GeoDuke.png b/geo/src/main/java/net/java/html/geo/doc-files/GeoDuke.png
new file mode 100644
index 0000000..56826a1
Binary files /dev/null and b/geo/src/main/java/net/java/html/geo/doc-files/GeoDuke.png differ

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/net/java/html/geo/package.html
----------------------------------------------------------------------
diff --git a/geo/src/main/java/net/java/html/geo/package.html b/geo/src/main/java/net/java/html/geo/package.html
new file mode 100644
index 0000000..bf9c6ab
--- /dev/null
+++ b/geo/src/main/java/net/java/html/geo/package.html
@@ -0,0 +1,74 @@
+<!--
+
+    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+    Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+
+    Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+    Other names may be trademarks of their respective owners.
+
+    The contents of this file are subject to the terms of either the GNU
+    General Public License Version 2 only ("GPL") or the Common
+    Development and Distribution License("CDDL") (collectively, the
+    "License"). You may not use this file except in compliance with the
+    License. You can obtain a copy of the License at
+    http://www.netbeans.org/cddl-gplv2.html
+    or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+    specific language governing permissions and limitations under the
+    License.  When distributing the software, include this License Header
+    Notice in each file and include the License file at
+    nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+    particular file as subject to the "Classpath" exception as provided
+    by Oracle in the GPL Version 2 section of the License file that
+    accompanied this code. If applicable, add the following below the
+    License Header, with the fields enclosed by brackets [] replaced by
+    your own identifying information:
+    "Portions Copyrighted [year] [name of copyright owner]"
+
+    Contributor(s):
+
+    The Original Software is NetBeans. The Initial Developer of the Original
+    Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+
+    If you wish your version of this file to be governed by only the CDDL
+    or only the GPL Version 2, indicate your decision by adding
+    "[Contributor] elects to include this software in this distribution
+    under the [CDDL or GPL Version 2] license." If you do not indicate a
+    single choice of license, a recipient has the option to distribute
+    your version of this file under either the CDDL, the GPL Version 2 or
+    to extend the choice of license to its licensees as provided above.
+    However, if you add GPL Version 2 code and therefore, elected the GPL
+    Version 2 license, then the option applies only if the new code is
+    made subject to such option by the copyright holder.
+
+-->
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Geolocation API for Java</title>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+        <meta name="viewport" content="width=device-width">
+    </head>
+    <body>
+        <span id="geoduke"></span>
+        <div>
+        HTML Geo API for Java provides <a href="OnLocation.html">annotation based way</a> of
+        obtaining geolocation information from a browser or any other 
+        device capable of providing it.
+        The primary way to use this API is to 
+        create a non-private method and annotate it with <a href="OnLocation.html">@OnLocation</a>
+        annotation.
+        </div>
+        <img src="doc-files/GeoDuke.png" alt="Illustrative picture"/>
+        <script type="text/javascript">
+            var s = document.getElementById("geoduke");
+            var i = document.createElement("img");
+            i.width = 120;
+            i.height = 60;
+            i.align = 'right';
+            i.src="doc-files/GeoDuke.png";
+            i.alt="Illustrative picture";
+            s.appendChild(i);
+        </script>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/org/netbeans/html/geo/impl/Accessor.java
----------------------------------------------------------------------
diff --git a/geo/src/main/java/org/netbeans/html/geo/impl/Accessor.java b/geo/src/main/java/org/netbeans/html/geo/impl/Accessor.java
new file mode 100644
index 0000000..e394c95
--- /dev/null
+++ b/geo/src/main/java/org/netbeans/html/geo/impl/Accessor.java
@@ -0,0 +1,76 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.geo.impl;
+
+import net.java.html.geo.Position;
+import org.netbeans.html.geo.spi.GLProvider;
+
+/** Connection between API and SPI parts of the module.
+ *
+ * @author Jaroslav Tulach <jt...@netbeans.org>
+ */
+public abstract class Accessor {
+    public static Accessor SPI;
+    static {
+        JsGLProvider initGLProviderClass = new JsGLProvider();
+    }
+    
+    protected Accessor(boolean api) {
+        if (!api) {
+            assert SPI == null;
+            SPI = this;
+        }
+    }
+    
+    public abstract <Watch> Watch start(
+        GLProvider<?, Watch> p, Accessor peer,
+        boolean oneTime, boolean enableHighAccuracy,
+        long timeout, long maximumAge
+    );
+    
+    public abstract <Watch> void stop(GLProvider<?, Watch> p, Watch w);
+    
+    public abstract void onError(Exception ex);
+
+    public abstract void onLocation(Position position);
+}

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/org/netbeans/html/geo/impl/GeoProcessor.java
----------------------------------------------------------------------
diff --git a/geo/src/main/java/org/netbeans/html/geo/impl/GeoProcessor.java b/geo/src/main/java/org/netbeans/html/geo/impl/GeoProcessor.java
new file mode 100644
index 0000000..ff2635e
--- /dev/null
+++ b/geo/src/main/java/org/netbeans/html/geo/impl/GeoProcessor.java
@@ -0,0 +1,290 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.geo.impl;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic;
+import javax.tools.JavaFileObject;
+import net.java.html.geo.OnLocation;
+import net.java.html.geo.Position;
+import net.java.html.geo.Position.Handle;
+import org.openide.util.lookup.ServiceProvider;
+
+/** Annotation processor to generate callbacks from {@link Handle} class.
+ *
+ * @author Jaroslav Tulach
+ */
+@ServiceProvider(service=Processor.class)
+@SupportedSourceVersion(SourceVersion.RELEASE_6)
+@SupportedAnnotationTypes({
+    "net.java.html.geo.OnLocation"
+})
+public final class GeoProcessor extends AbstractProcessor {
+    private static final Logger LOG = Logger.getLogger(GeoProcessor.class.getName());
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        boolean ok = true;
+        for (Element e : roundEnv.getElementsAnnotatedWith(OnLocation.class)) {
+            if (!processLocation(e)) {
+                ok = false;
+            }
+        }
+        return ok;
+    }
+
+    private void error(String msg, Element e) {
+        processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e);
+    }
+    
+    private boolean processLocation(Element e) {
+        if (e.getKind() != ElementKind.METHOD) {
+            return false;
+        }
+        ExecutableElement me = (ExecutableElement) e;
+        OnLocation ol = e.getAnnotation(OnLocation.class);
+        if (ol == null) {
+            return true;
+        }
+        if (me.getModifiers().contains(Modifier.PRIVATE)) {
+            error("Method annotated by @OnLocation cannot be private", e);
+            return false;
+        }
+        TypeMirror positionClass = processingEnv.getElementUtils().getTypeElement(Position.class.getName()).asType();
+        final List<? extends VariableElement> params = me.getParameters();
+        if (params.size() < 1 || !params.get(0).asType().equals(positionClass)) {
+            error("Method annotated by @OnLocation first argument must be net.java.html.geo.Position!", e);
+            return false;
+        }
+        String className = ol.className();
+        if (className.isEmpty()) {
+            String n = e.getSimpleName().toString();
+            if (n.isEmpty()) {
+                error("Empty method name", e);
+                return false;
+            }
+            final String firstLetter = n.substring(0, 1).toUpperCase(Locale.ENGLISH);
+            className = firstLetter + n.substring(1) + "Handle";
+        }
+        TypeElement te = (TypeElement)e.getEnclosingElement();
+        PackageElement pe = (PackageElement) te.getEnclosingElement();
+        final String pkg = pe.getQualifiedName().toString();
+        final String fqn = pkg + "." + className;
+        final boolean isStatic = me.getModifiers().contains(Modifier.STATIC);
+        String sep;
+        try {
+            JavaFileObject fo = processingEnv.getFiler().createSourceFile(fqn, e);
+            Writer w = fo.openWriter();
+            w.append("package ").append(pkg).append(";\n");
+            w.append("class ").append(className).append(" extends net.java.html.geo.Position.Handle {\n");
+            if (!isStatic) {
+                w.append("  private final ").append(te.getSimpleName()).append(" $i;\n");
+            }
+            for (int i = 1; i < params.size(); i++) {
+                final VariableElement p = params.get(i);
+                w.append("  private final ").append(p.asType().toString()).append(" ").append(p.getSimpleName()).append(";\n");
+            }
+            w.append("  private ").append(className).append("(boolean oneTime");
+            w.append(", ").append(te.getSimpleName()).append(" i");
+            for (int i = 1; i < params.size(); i++) {
+                final VariableElement p = params.get(i);
+                w.append(", ").append(p.asType().toString()).append(" ").append(p.getSimpleName());
+            }
+            w.append(") {\n    super(oneTime);\n");
+            if (!isStatic) {
+                w.append("    this.$i = i;\n");
+            }
+            for (int i = 1; i < params.size(); i++) {
+                final VariableElement p = params.get(i);
+                w.append("  this.").append(p.getSimpleName()).append(" = ").append(p.getSimpleName()).append(";\n");
+            }
+            w.append("}\n");
+            w.append("  static net.java.html.geo.Position.Handle createQuery(");
+            String inst;
+            if (!isStatic) {
+                w.append(te.getSimpleName()).append(" instance");
+                inst = "instance";
+                sep = ", ";
+            } else {
+                inst = "null";
+                sep = "";
+            }
+            for (int i = 1; i < params.size(); i++) {
+                final VariableElement p = params.get(i);
+                w.append(sep).append(p.asType().toString()).append(" ").append(p.getSimpleName());
+                sep = ", ";
+            }
+            w.append(") { return new ").append(className).append("(true, ").append(inst);
+            for (int i = 1; i < params.size(); i++) {
+                final VariableElement p = params.get(i);
+                w.append(", ").append(p.getSimpleName());
+            }
+            w.append("); }\n");
+            w.append("  static net.java.html.geo.Position.Handle createWatch(");
+            if (!isStatic) {
+                w.append(te.getSimpleName()).append(" instance");
+                sep = ", ";
+            } else {
+                sep = "";
+            }
+            for (int i = 1; i < params.size(); i++) {
+                final VariableElement p = params.get(i);
+                w.append(sep).append(p.asType().toString()).append(" ").append(p.getSimpleName());
+            }
+            w.append(") { return new ").append(className).append("(false, ").append(inst);
+            for (int i = 1; i < params.size(); i++) {
+                final VariableElement p = params.get(i);
+                w.append(", ").append(p.getSimpleName());
+            }
+            w.append("); }\n");
+            w.append("  @Override protected void onError(Exception t) throws Throwable {\n");
+            if (ol.onError().isEmpty()) {
+                w.append("    t.printStackTrace();");
+            } else {
+                if (!findOnError(me, te, ol.onError(), isStatic)) {
+                    return false;
+                }
+                if (isStatic) {
+                    w.append("    ").append(te.getSimpleName()).append(".");
+                } else {
+                    w.append("    $i.");
+                }
+                w.append(ol.onError()).append("(t");
+                for (int i = 1; i < params.size(); i++) {
+                    final VariableElement p = params.get(i);
+                    w.append(", ").append(p.getSimpleName());
+                }
+                w.append(");\n");
+            }
+            w.append("  }\n");
+            w.append("  @Override protected void onLocation(net.java.html.geo.Position p) throws Throwable {\n");
+            if (isStatic) {
+                w.append("    ").append(te.getSimpleName()).append(".");
+            } else {
+                w.append("    $i.");
+            }
+            w.append(me.getSimpleName()).append("(p");
+            for (int i = 1; i < params.size(); i++) {
+                final VariableElement p = params.get(i);
+                w.append(", ").append(p.getSimpleName());
+            }
+            w.append(");\n");
+            w.append("  }\n");
+            w.append("}\n");
+            w.close();
+        } catch (IOException ex) {
+            Logger.getLogger(GeoProcessor.class.getName()).log(Level.SEVERE, null, ex);
+            error("Can't write handler class: " + ex.getMessage(), e);
+            return false;
+        }
+        
+        return true;
+    }
+
+    private boolean findOnError(ExecutableElement errElem, TypeElement te, String name, boolean onlyStatic) {
+        String err = null;
+        METHODS: for (Element e : te.getEnclosedElements()) {
+            if (e.getKind() != ElementKind.METHOD) {
+                continue;
+            }
+            if (!e.getSimpleName().contentEquals(name)) {
+                continue;
+            }
+            if (onlyStatic && !e.getModifiers().contains(Modifier.STATIC)) {
+                errElem = (ExecutableElement) e;
+                err = "Would have to be static";
+                continue;
+            }
+            ExecutableElement ee = (ExecutableElement) e;
+            TypeMirror excType = processingEnv.getElementUtils().getTypeElement(Exception.class.getName()).asType();
+            final List<? extends VariableElement> params = ee.getParameters(); 
+            if (params.size() < 1 || 
+                !processingEnv.getTypeUtils().isAssignable(excType, ee.getParameters().get(0).asType())
+            ) {
+                errElem = (ExecutableElement) e;
+                err = "Error method first argument needs to be Exception";
+                continue;
+            }
+            final List<? extends Element> origParams = errElem.getParameters();
+            if (params.size() != origParams.size()) {
+                errElem = (ExecutableElement) e;
+                err = "Error method must have the same parameters as @OnLocation one";
+                continue;
+            }
+            for (int i = 1; i < origParams.size(); i++) {
+                final TypeMirror t1 = params.get(i).asType();
+                final TypeMirror t2 = origParams.get(i).asType();
+                if (!processingEnv.getTypeUtils().isSameType(t1, t2)) {
+                    errElem = (ExecutableElement) e;
+                    err = "Error method must have the same parameters as @OnLocation one";
+                    continue METHODS;
+                }
+            }
+            return true;
+        }
+        if (err == null) {
+            err = "Cannot find " + name + "(Exception) method in this class";
+        }
+        error(err, errElem);
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/org/netbeans/html/geo/impl/JsGLProvider.java
----------------------------------------------------------------------
diff --git a/geo/src/main/java/org/netbeans/html/geo/impl/JsGLProvider.java b/geo/src/main/java/org/netbeans/html/geo/impl/JsGLProvider.java
new file mode 100644
index 0000000..f7578a8
--- /dev/null
+++ b/geo/src/main/java/org/netbeans/html/geo/impl/JsGLProvider.java
@@ -0,0 +1,154 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.geo.impl;
+
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.geo.spi.GLProvider;
+
+/** Implementation class to deal with browser's <code>navigator.geolocation</code> 
+ * object.
+ *
+ * @author Jaroslav Tulach
+ */
+public final class JsGLProvider extends GLProvider<Object, Long> {
+    public JsGLProvider() {
+    }
+    
+    @JavaScriptBody(args = {}, body = "return !!navigator.geolocation;")
+    private static boolean hasGeolocation() {
+        return false;
+    }
+
+    @JavaScriptBody(
+        args = { "c", "onlyOnce", "enableHighAccuracy", "timeout", "maximumAge" }, 
+        javacall = true, 
+        body = 
+        "var self = this;\n" +
+        "var ok = function (position) {\n" +
+        "  self.@org.netbeans.html.geo.impl.JsGLProvider::onLocation(Ljava/lang/Object;Ljava/lang/Object;)(c, position);\n" +
+        "};\n" +
+        "var fail = function (error) {\n" +
+        "  self.@org.netbeans.html.geo.impl.JsGLProvider::onError(Ljava/lang/Object;Ljava/lang/String;I)(c, error.message, error.code);\n" +
+        "};\n" +
+        "var options = {};\n" +
+        "options.enableHighAccuracy = enableHighAccuracy;\n" +
+        "if (timeout >= 0) options.timeout = timeout;\n" +
+        "if (maximumAge >= 0) options.maximumAge = maximumAge;\n" +
+        "if (onlyOnce) {\n" +
+        "  navigator.geolocation.getCurrentPosition(ok, fail, options);\n" +
+        "  return 0;\n" +
+        "} else {\n" +
+        "  return navigator.geolocation.watchPosition(ok, fail, options);\n" +
+        "}\n"
+    )
+    private long doStart(
+        Query c,
+        boolean onlyOnce, 
+        boolean enableHighAccuracy,
+        long timeout,
+        long maximumAge
+    ) {
+        return -1;
+    }
+    
+    protected void stop(long watch) {
+    }
+
+    @Override
+    public Long start(Query c) {
+        if (!hasGeolocation()) {
+            return null;
+        }
+        return doStart(c, c.isOneTime(), c.isHighAccuracy(), c.getTimeout(), c.getMaximumAge());
+    }
+    
+    final void onLocation(Object c, Object p) {
+        callback((Query)c, timeStamp(p), p, null);
+    }
+    
+    final void onError(Object c, final String msg, int code) {
+        final Exception err = new Exception(msg + " errno: " + code) {
+            @Override
+            public String getLocalizedMessage() {
+                return msg;
+            }
+        };
+        callback((Query)c, 0L, null, err);
+    }
+
+    @Override
+    @JavaScriptBody(args = {"watch"}, body = "navigator.geolocation.clearWatch(watch);")
+    public native void stop(Long watch);
+
+    @JavaScriptBody(args = { "p" }, body = "return p.timestamp;")
+    private static native long timeStamp(Object position);
+
+    @Override
+    @JavaScriptBody(args = { "coords" }, body = "return coords.coords.latitude;")
+    protected native double latitude(Object coords);
+
+    @Override
+    @JavaScriptBody(args = { "coords" }, body = "return coords.coords.longitude;")
+    protected native double longitude(Object coords);
+
+    @Override
+    @JavaScriptBody(args = { "coords" }, body = "return coords.coords.accuracy;")
+    protected native double accuracy(Object coords);
+
+    @Override
+    @JavaScriptBody(args = {"coords"}, body = "return coords.coords.altitude ? coords.coords.altitude : null;")
+    protected native Double altitude(Object coords);
+
+    @Override
+    @JavaScriptBody(args = {"coords"}, body = "return coords.coords.altitudeAccuracy ? coords.coords.altitudeAccuracy : null;")
+    protected native Double altitudeAccuracy(Object coords);
+
+    @Override
+    @JavaScriptBody(args = {"coords"}, body = "return coords.coords.heading ? coords.coords.heading : null;")
+    protected native Double heading(Object coords);
+
+    @Override
+    @JavaScriptBody(args = {"coords"}, body = "return coords.coords.speed ? coords.coords.speed : null;")
+    protected native Double speed(Object coords);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/org/netbeans/html/geo/spi/CoordImpl.java
----------------------------------------------------------------------
diff --git a/geo/src/main/java/org/netbeans/html/geo/spi/CoordImpl.java b/geo/src/main/java/org/netbeans/html/geo/spi/CoordImpl.java
new file mode 100644
index 0000000..b0f0a14
--- /dev/null
+++ b/geo/src/main/java/org/netbeans/html/geo/spi/CoordImpl.java
@@ -0,0 +1,87 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.geo.spi;
+
+import net.java.html.geo.Position;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class CoordImpl<Coords> extends Position.Coordinates {
+    private final Coords data;
+    private final GLProvider<Coords, ?> provider;
+
+    CoordImpl(Coords data, GLProvider<Coords, ?> p) {
+        this.data = data;
+        this.provider = p;
+    }
+
+    @Override public double getLatitude() {
+        return provider.latitude(data);
+    }
+
+    @Override public double getLongitude() {
+        return provider.longitude(data);
+    }
+
+    @Override public double getAccuracy() {
+        return provider.accuracy(data);
+    }
+
+    @Override public Double getAltitude() {
+        return provider.altitude(data);
+    }
+
+    @Override public Double getAltitudeAccuracy() {
+        return provider.altitudeAccuracy(data);
+    }
+
+    @Override public Double getHeading() {
+        return provider.heading(data);
+    }
+
+    @Override public Double getSpeed() {
+        return provider.speed(data);
+    }
+} // end of CoordImpl

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/org/netbeans/html/geo/spi/GLProvider.java
----------------------------------------------------------------------
diff --git a/geo/src/main/java/org/netbeans/html/geo/spi/GLProvider.java b/geo/src/main/java/org/netbeans/html/geo/spi/GLProvider.java
new file mode 100644
index 0000000..6ea1346
--- /dev/null
+++ b/geo/src/main/java/org/netbeans/html/geo/spi/GLProvider.java
@@ -0,0 +1,306 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.geo.spi;
+
+import net.java.html.BrwsrCtx;
+import net.java.html.geo.Position;
+import net.java.html.geo.Position.Handle;
+import net.java.html.geo.Position.Coordinates;
+import org.netbeans.html.context.spi.Contexts.Builder;
+import org.netbeans.html.geo.impl.Accessor;
+import org.openide.util.lookup.ServiceProvider;
+
+/** SPI for those who wish to provide their own way of obtaining geolocation.
+ * Subclass this class, implement its method and register it into the system.
+ * You can either use {@link ServiceProvider} to register globally, or 
+ * one can register into {@link BrwsrCtx} (via 
+ * {@link Builder#register(java.lang.Class, java.lang.Object, int) context builder}).
+ * <p>
+ * There is default system provider (used as a fallback) based on 
+ * <a href="http://www.w3.org/TR/geolocation-API/">
+ * W3C's Geolocation</a> specification - if you are running inside a
+ * browser that supports such standard and you are satisfied with its
+ * behavior, you don't have to register anything.
+ * <p>
+ * The provider serves two purposes: 
+ * <ol>
+ *   <li>
+ *     It handles a geolocation request and creates a "watch" to represent it -
+ *     to do so implement the {@link #start(org.netbeans.html.geo.spi.GLProvider.Query) start} 
+ *     method and the {@link #stop(java.lang.Object) stop} method.
+ *   </li>
+ *   <li>
+ *     Once the location is found, the provider needs to 
+ *     {@link #callback(org.netbeans.html.geo.spi.GLProvider.Query, long, java.lang.Object, java.lang.Exception)  call back}
+ *     with appropriate location information which can be extracted
+ *     later via {@link #latitude(java.lang.Object)} {@link #longitude(java.lang.Object)}, and
+ *     other methods in this that also need to be implemented.
+ *   </li>
+ * </ol>
+ * <p>
+ * The provider is based on a 
+ * <a href="http://wiki.apidesign.org/wiki/Singletonizer" target="_blank">singletonizer</a> 
+ * pattern (applied twice)
+ * and as such one is only required to subclass just the {@link GLProvider} 
+ * and otherwise has freedom choosing what classes to use
+ * to represent coordinates and watches. For example if it is enough to use
+ * an array for coordinates and a long number for a watch, one can do:
+ * <pre>
+ * <b>public final class</b> MyGeoProvider extends {@link GLProvider}&lt;Double[], Long&gt; {
+ *   <em>// somehow implement the methods</em>
+ * }
+ * </pre>
+ *
+ * @author Jaroslav Tulach
+ * @param <Watch> your chosen type to represent one query (one time) or watch (repeated) request -
+ *   this type is used in {@link #start(org.netbeans.html.geo.spi.GLProvider.Query) start}
+ *   and {@link #stop(java.lang.Object) stop} methods.
+ * 
+ * @param <Coords> your chosen type to represent geolocation coordinates -
+ *   use in many methods in this class like {@link #latitude(java.lang.Object)} and
+ *   {@link #longitude(java.lang.Object)}.
+ * 
+ * @since 1.0
+ */
+public abstract class GLProvider<Coords,Watch> {
+    static {
+        Accessor initChannel = new Accessor(false) {
+            @Override
+            public <Watch> Watch start(GLProvider<?, Watch> p, Accessor peer, boolean oneTime, boolean enableHighAccuracy, long timeout, long maximumAge) {
+                return p.start(new Query(peer, oneTime, enableHighAccuracy, timeout, maximumAge));
+            }
+            
+            @Override
+            public <Watch> void stop(GLProvider<?, Watch> p, Watch w) {
+                p.stop(w);
+            }
+            
+            @Override
+            public void onError(Exception ex) {
+                throw new UnsupportedOperationException();
+            }
+            
+            @Override
+            public void onLocation(Position position) {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+    /** Start obtaining geolocation.
+     * When the client {@link Handle#start() requests location} (and
+     * your provider is found) this method should initialize the request or 
+     * return <code>null</code> to give chance to another provider.
+     * 
+     * @param c the query describing the request and
+     *   to {@link #callback(org.netbeans.html.geo.spi.GLProvider.Query, long, java.lang.Object, java.lang.Exception)  use when location is found} -
+     *    keep it, you'll need it later
+     * 
+     * @return an object representing the request (so it can be {@link #stop(java.lang.Object) stopped} later)
+     *   or <code>null</code> if this provider was unable to start the request
+     */
+    protected abstract Watch start(Query c);
+    
+    /** Called when a geolocation request should be stopped.
+     * 
+     * @param watch the watch returned when {@link #start(org.netbeans.html.geo.spi.GLProvider.Query) starting}
+     *   the request
+     */
+    protected abstract void stop(Watch watch);
+
+    /** Invoke this method when your provider obtained requested location.
+     * This single method is used for notification of success (when <code>ex</code>
+     * argument is <code>null</code> and <code>position</code> is provided) or 
+     * a failure (when <code>ex</code> argument is non-<code>null</code>).
+     * A successful requests leads in a call to {@link Handle#onLocation(net.java.html.geo.Position)}
+     * while an error report leads to a call to {@link Handle#onError(java.lang.Exception)}.
+     * The actual call is sent to {@link BrwsrCtx#execute(java.lang.Runnable)} of
+     * context recorded when the {@link Query} was created to guarantee it
+     * happens on the right browser thread - however it may happen "later"
+     * when this method has already finished.
+     * 
+     * @param c the query as provided when {@link #start(org.netbeans.html.geo.spi.GLProvider.Query) starting}
+     *   the request
+     * @param timestamp milliseconds since epoch when the location has been obtained
+     * @param position your own, internal, representation of geolocation
+     *   coordinates - will be passed back to other methods of this class
+     *   like {@link #latitude(java.lang.Object)} and {@link #longitude(java.lang.Object)}.
+     *   Can be <code>null</code> if <code>ex</code> is non-<code>null</code>
+     * @param ex an exception to signal an error - should be <code>null</code>
+     *   when one notifies the successfully obtained <code>position</code>
+     */
+    protected final void callback(
+        final Query c,
+        final long timestamp, final Coords position,
+        final Exception ex
+    ) {
+        c.ctx.execute(new Runnable() {
+            @Override
+            public void run() {
+                if (ex == null) {
+                    c.peer.onLocation(new Position(timestamp, new CoordImpl<Coords>(position, GLProvider.this)));
+                } else {
+                    c.peer.onError(ex);
+                }
+            }
+        });
+    }
+
+    /** Extracts value for {@link Coordinates#getLatitude()}.
+     * @param coords your own internal representation of coordinates.
+     * @return geographic coordinate specified in decimal degrees.
+     */
+    protected abstract double latitude(Coords coords);
+    
+    /** Extracts value for {@link Coordinates#getLatitude()}.
+     * @param coords your own internal representation of coordinates.
+     * @return geographic coordinate specified in decimal degrees.
+     */
+    protected abstract double longitude(Coords coords);
+    
+    /** Extracts value for {@link Coordinates#getLatitude()}.
+     * The accuracy attribute denotes the accuracy level of the latitude 
+     * and longitude coordinates.
+     * 
+     * @param coords your own internal representation of coordinates.
+     * @return accuracy in meters
+     */
+    protected abstract double accuracy(Coords coords);
+    
+    /** Extracts value for {@link Coordinates#getAltitude()}.
+     * Denotes the height of the position, specified in meters above the ellipsoid.
+     * 
+     * @param coords your own internal representation of coordinates.
+     * @return value in meters, may return null, if the information is not available
+     */
+    protected abstract Double altitude(Coords coords);
+    
+    /** Extracts value for {@link Coordinates#getAltitudeAccuracy()} -
+     * the altitude accuracy is specified in meters. 
+     * 
+     * @param coords your own internal representation of coordinates.
+     * @return value in meters; may return null, if the information is not available
+     */
+    protected abstract Double altitudeAccuracy(Coords coords);
+    
+    /** Extracts value for {@link Coordinates#getHeading()}.
+     * Denotes the magnitude of the horizontal component of the 
+     * device's current velocity and is specified in meters per second.
+     * 
+     * @param coords your own internal representation of coordinates.
+     * @return may return null, if the information is not available 
+     */
+    protected abstract Double heading(Coords coords);
+    
+    /** Extracts value for {@link Coordinates#getSpeed()}.
+     * Denotes the magnitude of the horizontal component of the 
+     * device's current velocity and is specified in meters per second.
+     * 
+     * @param coords your own internal representation of coordinates.
+     * @return may return null, if the information is not available
+     */
+    protected abstract Double speed(Coords coords);
+    
+    /** Holds parameters describing the location query and is used by {@link GLProvider} to notify back
+     * results of its findings.
+     */
+    public static final class Query {
+        private final boolean oneTime;
+        private final boolean enableHighAccuracy;
+        private final long timeout;
+        private final long maximumAge;
+        private final BrwsrCtx ctx;
+        final Accessor peer;
+
+        Query(Accessor peer, boolean oneTime, boolean enableHighAccuracy, long timeout, long maximumAge) {
+            this.peer = peer;
+            this.oneTime = oneTime;
+            this.enableHighAccuracy = enableHighAccuracy;
+            this.timeout = timeout;
+            this.maximumAge = maximumAge;
+            ctx = BrwsrCtx.findDefault(Query.class);
+        }
+        
+        /**
+         * Is this one time or repeated request? Mimics value provided in
+         * {@link Handle constructor}.
+         *
+         * @return true if this is one time request, false if the request is
+         * permanent (up until {@link Handle#stop() } is called).
+         */
+        public final boolean isOneTime() {
+            return oneTime;
+        }
+
+        /**
+         * Turns on high accuracy mode as specified by the
+         * <a href="http://www.w3.org/TR/2012/PR­geolocation­API­20120510/">
+         * W3C's Geolocation API</a>. By default the mode is disabled. Mimics
+         * value of {@link Handle#setHighAccuracy(boolean)}.
+         *
+         * @return enable <code>true</code> or <code>false</code>
+         */
+        public final boolean isHighAccuracy() {
+            return this.enableHighAccuracy;
+        }
+
+        /**
+         * The amount of milliseconds to wait for a result. Mimics value of
+         * {@link Handle#setTimeout(long)}.
+         *
+         * @return time in milliseconds to wait for a result.
+         */
+        public final long getTimeout() {
+            return this.timeout;
+        }
+
+        /**
+         * Sets maximum age of cached results which are acceptable to be
+         * returned. Mimics value of {@link Handle#setMaximumAge(long)}.
+         *
+         * @return time in milliseconds of acceptable cached results
+         */
+        public final long getMaximumAge() {
+            return this.maximumAge;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/org/netbeans/html/geo/spi/package.html
----------------------------------------------------------------------
diff --git a/geo/src/main/java/org/netbeans/html/geo/spi/package.html b/geo/src/main/java/org/netbeans/html/geo/spi/package.html
new file mode 100644
index 0000000..6eb717c
--- /dev/null
+++ b/geo/src/main/java/org/netbeans/html/geo/spi/package.html
@@ -0,0 +1,59 @@
+<!--
+
+    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+    Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+
+    Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+    Other names may be trademarks of their respective owners.
+
+    The contents of this file are subject to the terms of either the GNU
+    General Public License Version 2 only ("GPL") or the Common
+    Development and Distribution License("CDDL") (collectively, the
+    "License"). You may not use this file except in compliance with the
+    License. You can obtain a copy of the License at
+    http://www.netbeans.org/cddl-gplv2.html
+    or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+    specific language governing permissions and limitations under the
+    License.  When distributing the software, include this License Header
+    Notice in each file and include the License file at
+    nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+    particular file as subject to the "Classpath" exception as provided
+    by Oracle in the GPL Version 2 section of the License file that
+    accompanied this code. If applicable, add the following below the
+    License Header, with the fields enclosed by brackets [] replaced by
+    your own identifying information:
+    "Portions Copyrighted [year] [name of copyright owner]"
+
+    Contributor(s):
+
+    The Original Software is NetBeans. The Initial Developer of the Original
+    Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+
+    If you wish your version of this file to be governed by only the CDDL
+    or only the GPL Version 2, indicate your decision by adding
+    "[Contributor] elects to include this software in this distribution
+    under the [CDDL or GPL Version 2] license." If you do not indicate a
+    single choice of license, a recipient has the option to distribute
+    your version of this file under either the CDDL, the GPL Version 2 or
+    to extend the choice of license to its licensees as provided above.
+    However, if you add GPL Version 2 code and therefore, elected the GPL
+    Version 2 license, then the option applies only if the new code is
+    made subject to such option by the copyright holder.
+
+-->
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Geolocation SPI</title>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+        <meta name="viewport" content="width=device-width">
+    </head>
+    <body>
+        <div>
+            Service provider interfaces for those willing to 
+            {@link org.netbeans.html.geo.spi.GLProvider provide their own way}
+            of obtaining proper geolocation.
+        </div>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/test/java/net/java/html/geo/OnLocationTest.java
----------------------------------------------------------------------
diff --git a/geo/src/test/java/net/java/html/geo/OnLocationTest.java b/geo/src/test/java/net/java/html/geo/OnLocationTest.java
new file mode 100644
index 0000000..544d8c4
--- /dev/null
+++ b/geo/src/test/java/net/java/html/geo/OnLocationTest.java
@@ -0,0 +1,137 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package net.java.html.geo;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/** Testing correctness of the generated code.
+ */
+public class OnLocationTest {
+    static int cnt;
+    static @OnLocation void onLocation(Position p) {
+        assertNotNull(p, "Position object provided");
+        cnt++;
+    }
+
+    @Test public void createOneTimeQueryStatic() {
+        net.java.html.geo.Position.Handle h = OnLocationHandle.createQuery();
+        h.setHighAccuracy(false);
+        h.setTimeout(1000L);
+        h.setMaximumAge(1000L);
+        if (h.isSupported()) h.start();
+        h.stop();
+    }
+    
+    @Test public void onLocationHandleCallback() throws Throwable {
+        net.java.html.geo.Position.Handle h = OnLocationHandle.createQuery();
+        cnt = 0;
+        h.onLocation(new Position(0L, null));
+        assertEquals(cnt, 1, "The callback has been made");
+    }
+
+    @Test public void createRepeatableWatchStatic() {
+        net.java.html.geo.Position.Handle h = OnLocationHandle.createQuery();
+        h.setHighAccuracy(false);
+        h.setTimeout(1000L);
+        h.setMaximumAge(1000L);
+        if (h.isSupported()) h.start();
+        h.stop();
+    }
+
+    int instCnt;
+    Throwable instT;
+    @OnLocation(onError = "someError") void instance(Position p) throws Error {
+        assertNotNull(p, "Some position passed in");
+        instCnt++;
+    }
+    void someError(Throwable t) throws Exception {
+        instT = t;
+        instCnt++;
+    }
+    
+    @Test public void createOneTimeQueryInstance() {
+        OnLocationTest t = new OnLocationTest();
+        
+        net.java.html.geo.Position.Handle h = InstanceHandle.createQuery(t);
+        h.setHighAccuracy(false);
+        h.setTimeout(1000L);
+        h.setMaximumAge(1000L);
+        if (h.isSupported()) h.start();
+        h.stop();
+    }
+    
+    @Test public void onInstanceCallback() throws Throwable {
+        OnLocationTest t = new OnLocationTest();
+        net.java.html.geo.Position.Handle h = InstanceHandle.createWatch(t);
+        h.onLocation(new Position(0L, null));
+        assertEquals(t.instCnt, 1, "One callback made");
+    }
+
+    @Test public void onInstanceError() throws Throwable {
+        net.java.html.geo.Position.Handle h = InstanceHandle.createWatch(this);
+        InterruptedException e = new InterruptedException();
+        h.onError(e);
+        assertEquals(instCnt, 1, "One callback made");
+        assertEquals(instT, e, "The same exception passed in");
+    }
+
+    @Test public void createRepeatableWatch() {
+        OnLocationTest t = new OnLocationTest();
+        
+        net.java.html.geo.Position.Handle h = InstanceHandle.createWatch(t);
+        h.setHighAccuracy(false);
+        h.setTimeout(1000L);
+        h.setMaximumAge(1000L);
+        if (h.isSupported()) h.start();
+        h.stop();
+    }
+    
+    @OnLocation(onError = "errParam") void withParam(Position pos, int param) {
+        instCnt = param;
+    }
+    
+    void errParam(Exception ex, int param) {
+        instCnt = param;
+    }
+}