context/src/main/java/net/java/html/BrwsrCtx.java
author Jaroslav Tulach <jtulach@netbeans.org>
Tue, 26 Aug 2014 18:13:30 +0200
changeset 838 bdc3d696dd4a
parent 790 30f20d9c0986
child 886 88d62267a0b5
permissions -rw-r--r--
During the API review process (bug 246133) the reviewers decided that in order to include html4j to NetBeans Platform, we need to stop using org.apidesign namespace and switch to NetBeans one. Repackaging all SPI packages into org.netbeans.html.smthng.spi.
jaroslav@5
     1
/**
jaroslav@358
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
jaroslav@5
     3
 *
jaroslav@551
     4
 * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
jaroslav@5
     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@5
     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@551
    30
 * Software is Oracle. Portions Copyright 2013-2014 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@5
    42
 */
jaroslav@110
    43
package net.java.html;
jaroslav@5
    44
jaroslav@574
    45
import java.util.concurrent.Executor;
jaroslav@320
    46
import java.util.logging.Logger;
jaroslav@362
    47
import org.netbeans.html.context.impl.CtxAccssr;
jaroslav@362
    48
import org.netbeans.html.context.impl.CtxImpl;
jtulach@838
    49
import org.netbeans.html.context.spi.Contexts;
jaroslav@6
    50
jaroslav@167
    51
/** Represents context where the <code>net.java.html.json.Model</code>
jaroslav@167
    52
 * and other objects
jaroslav@5
    53
 * operate in. The context is usually a particular HTML page in a browser.
jaroslav@167
    54
 * The context is also associated with the actual HTML technology
jaroslav@5
    55
 * in the HTML page - there is likely to be different context for 
jaroslav@5
    56
 * <a href="http://knockoutjs.com">knockout.js</a> and different one
jaroslav@5
    57
 * for <a href="http://angularjs.org">angular</a>.
jaroslav@5
    58
 *
jtulach@655
    59
 * @author Jaroslav Tulach
jaroslav@5
    60
 */
jaroslav@596
    61
public final class BrwsrCtx implements Executor {
jaroslav@320
    62
    private static final Logger LOG = Logger.getLogger(BrwsrCtx.class.getName());
jaroslav@110
    63
    private final CtxImpl impl;
jaroslav@110
    64
    private BrwsrCtx(CtxImpl impl) {
jaroslav@110
    65
        this.impl = impl;
jaroslav@5
    66
    }
jaroslav@6
    67
    static {
jaroslav@110
    68
        new CtxAccssr() {
jaroslav@6
    69
            @Override
jaroslav@110
    70
            protected BrwsrCtx newContext(CtxImpl impl) {
jaroslav@110
    71
                return new BrwsrCtx(impl);
jaroslav@6
    72
            }
jaroslav@6
    73
jaroslav@6
    74
            @Override
jaroslav@110
    75
            protected CtxImpl find(BrwsrCtx context) {
jaroslav@110
    76
                return context.impl;
jaroslav@6
    77
            }
jaroslav@6
    78
        };
jaroslav@6
    79
    }
jaroslav@5
    80
    /** Dummy context without binding to any real browser or technology. 
jaroslav@110
    81
     * Useful for simple unit testing of behavior of various business logic
jaroslav@110
    82
     * code.
jaroslav@5
    83
     */
jaroslav@110
    84
    public static final BrwsrCtx EMPTY = Contexts.newBuilder().build();
jaroslav@39
    85
    
jtulach@569
    86
    /** currently {@link #execute(java.lang.Runnable) activated context} */
jtulach@569
    87
    private static final ThreadLocal<BrwsrCtx> CURRENT = new ThreadLocal<BrwsrCtx>();
jtulach@569
    88
    
jaroslav@39
    89
    /** Seeks for the default context that is associated with the requesting
jaroslav@39
    90
     * class. If no suitable context is found, a warning message is
jaroslav@574
    91
     * printed and {@link #EMPTY} context is returned. One can enter 
jaroslav@574
    92
     * a context by calling {@link #execute(java.lang.Runnable)}.
jaroslav@39
    93
     * 
jaroslav@39
    94
     * @param requestor the class that makes the request
jaroslav@39
    95
     * @return appropriate context for the request
jaroslav@39
    96
     */
jaroslav@110
    97
    public static BrwsrCtx findDefault(Class<?> requestor) {
jtulach@569
    98
        BrwsrCtx brwsr = CURRENT.get();
jtulach@569
    99
        if (brwsr != null) {
jtulach@569
   100
            return brwsr;
jtulach@569
   101
        }
jtulach@569
   102
        
jtulach@838
   103
        org.netbeans.html.context.spi.Contexts.Builder cb = Contexts.newBuilder();
jaroslav@574
   104
        boolean found = Contexts.fillInByProviders(requestor, cb);
jaroslav@320
   105
        if (!found) {
jaroslav@320
   106
            LOG.warning("No browser context found. Returning empty technology!");
jaroslav@110
   107
            return EMPTY;
jaroslav@110
   108
        }
jaroslav@110
   109
        return cb.build();
jaroslav@39
   110
    }
jtulach@569
   111
jtulach@790
   112
    /** 
jtulach@790
   113
     * <p>
jtulach@790
   114
     * Runs provided code in the context of this {@link BrwsrCtx}.
jaroslav@574
   115
     * If there is an {@link Executor} {@link Contexts#find(net.java.html.BrwsrCtx, java.lang.Class)  registered in the context}
jaroslav@574
   116
     * it is used to perform the given code. While the code <code>exec</code>
jaroslav@574
   117
     * is running the value of {@link #findDefault(java.lang.Class)} returns
jaroslav@574
   118
     * <code>this</code>. If the executor supports a single thread execution
jaroslav@574
   119
     * policy, it may execute the runnable later (in such case this method
jaroslav@574
   120
     * returns immediately). If the call to this method is done on the right
jaroslav@574
   121
     * thread, the runnable should be executed synchronously.
jtulach@790
   122
     * </p>
jtulach@790
   123
     * <p>
jtulach@790
   124
     * <b>Example Using a Timer</b>
jtulach@790
   125
     * </p>
jaroslav@617
   126
<pre>
jaroslav@617
   127
<b>public final class</b> Periodicaly <b>extends</b> {@link java.util.TimerTask} {
jaroslav@617
   128
    <b>private final</b> {@link BrwsrCtx} ctx;
jaroslav@617
   129
jtulach@652
   130
    <b>private</b> Periodicaly(BrwsrCtx ctx) {
jtulach@652
   131
        // remember the browser context and use it later
jtulach@652
   132
        this.ctx = ctx;
jaroslav@617
   133
    }
jaroslav@617
   134
    
jaroslav@617
   135
    <b>public void</b> run() {
jaroslav@617
   136
        // arrives on wrong thread, needs to be re-scheduled
jaroslav@617
   137
        ctx.{@link #execute(java.lang.Runnable) execute}(new Runnable() {
jaroslav@617
   138
            <b>public void</b> run() {
jaroslav@617
   139
                // code that needs to run in a browser environment
jaroslav@617
   140
            }
jaroslav@617
   141
        });
jaroslav@617
   142
    }
jaroslav@617
   143
jaroslav@617
   144
    // called when your page is ready
jaroslav@617
   145
    <b>public static void</b> onPageLoad(String... args) <b>throws</b> Exception {
jtulach@652
   146
        // the context at the time of page initialization
jtulach@652
   147
        BrwsrCtx initialCtx = BrwsrCtx.findDefault(getClass());
jaroslav@617
   148
        // the task that is associated with context 
jtulach@652
   149
        Periodicaly task = new Periodicaly(initialCtx);
jaroslav@617
   150
        // creates a timer
jaroslav@617
   151
        {@link java.util.Timer} t = new {@link java.util.Timer}("Move the box");
jaroslav@617
   152
        // run the task ever 100ms
jaroslav@617
   153
        t.{@link java.util.Timer#scheduleAtFixedRate(java.util.TimerTask, long, long) scheduleAtFixedRate}(task, 0, 100);
jaroslav@617
   154
    }
jaroslav@617
   155
}
jaroslav@617
   156
</pre>    
jtulach@569
   157
     * 
jtulach@569
   158
     * @param exec the code to execute
jtulach@569
   159
     * @since 0.7.6
jtulach@569
   160
     */
jaroslav@596
   161
    @Override public final void execute(final Runnable exec) {
jaroslav@574
   162
        class Wrap implements Runnable {
jaroslav@574
   163
            @Override
jaroslav@574
   164
            public void run() {
jaroslav@574
   165
                BrwsrCtx prev = CURRENT.get();
jaroslav@574
   166
                try {
jaroslav@574
   167
                    CURRENT.set(BrwsrCtx.this);
jaroslav@574
   168
                    exec.run();
jaroslav@574
   169
                } finally {
jaroslav@574
   170
                    CURRENT.set(prev);
jaroslav@574
   171
                }
jaroslav@574
   172
            }
jaroslav@574
   173
        }
jaroslav@574
   174
        Wrap w = new Wrap();
jaroslav@574
   175
        Executor runIn = Contexts.find(this, Executor.class);
jaroslav@574
   176
        if (runIn == null) {
jaroslav@574
   177
            w.run();
jaroslav@574
   178
        } else {
jaroslav@574
   179
            runIn.execute(w);
jtulach@569
   180
        }
jtulach@569
   181
    }
jaroslav@5
   182
}
jaroslav@574
   183