context/src/main/java/net/java/html/BrwsrCtx.java
author Jaroslav Tulach <jtulach@netbeans.org>
Thu, 29 Oct 2015 16:23:48 +0100
changeset 1013 170c4f72938f
parent 1012 c19904646ed8
child 1053 ed4b25eb66f3
permissions -rw-r--r--
Typo: ever -> every
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;
jtulach@886
    50
import org.netbeans.html.context.spi.Contexts.Id;
jaroslav@6
    51
jaroslav@167
    52
/** Represents context where the <code>net.java.html.json.Model</code>
jaroslav@167
    53
 * and other objects
jaroslav@5
    54
 * operate in. The context is usually a particular HTML page in a browser.
jaroslav@167
    55
 * The context is also associated with the actual HTML technology
jaroslav@5
    56
 * in the HTML page - there is likely to be different context for 
jaroslav@5
    57
 * <a href="http://knockoutjs.com">knockout.js</a> and different one
jtulach@886
    58
 * for <a href="http://angularjs.org">angular</a>. Since version 1.1
jtulach@886
    59
 * the content of contexts can be selected by registering
jtulach@886
    60
 * implementations under specific
jtulach@886
    61
 * {@link Id technology identifiers} and requesting them during 
jtulach@886
    62
 * {@link Contexts#newBuilder(java.lang.Object...) construction} of the
jtulach@886
    63
 * context.
jaroslav@5
    64
 *
jtulach@655
    65
 * @author Jaroslav Tulach
jaroslav@5
    66
 */
jaroslav@596
    67
public final class BrwsrCtx implements Executor {
jaroslav@320
    68
    private static final Logger LOG = Logger.getLogger(BrwsrCtx.class.getName());
jaroslav@110
    69
    private final CtxImpl impl;
jaroslav@110
    70
    private BrwsrCtx(CtxImpl impl) {
jaroslav@110
    71
        this.impl = impl;
jaroslav@5
    72
    }
jtulach@945
    73
    /** currently {@link #execute(java.lang.Runnable) activated context} */
jtulach@945
    74
    private static final ThreadLocal<BrwsrCtx> CURRENT = new ThreadLocal<BrwsrCtx>();
jaroslav@6
    75
    static {
jaroslav@110
    76
        new CtxAccssr() {
jaroslav@6
    77
            @Override
jaroslav@110
    78
            protected BrwsrCtx newContext(CtxImpl impl) {
jaroslav@110
    79
                return new BrwsrCtx(impl);
jaroslav@6
    80
            }
jaroslav@6
    81
jaroslav@6
    82
            @Override
jaroslav@110
    83
            protected CtxImpl find(BrwsrCtx context) {
jaroslav@110
    84
                return context.impl;
jaroslav@6
    85
            }
jaroslav@6
    86
        };
jaroslav@6
    87
    }
jaroslav@5
    88
    /** Dummy context without binding to any real browser or technology. 
jaroslav@110
    89
     * Useful for simple unit testing of behavior of various business logic
jaroslav@110
    90
     * code.
jaroslav@5
    91
     */
jaroslav@110
    92
    public static final BrwsrCtx EMPTY = Contexts.newBuilder().build();
jaroslav@39
    93
    
jtulach@569
    94
    
jaroslav@39
    95
    /** Seeks for the default context that is associated with the requesting
jaroslav@39
    96
     * class. If no suitable context is found, a warning message is
jaroslav@574
    97
     * printed and {@link #EMPTY} context is returned. One can enter 
jaroslav@574
    98
     * a context by calling {@link #execute(java.lang.Runnable)}.
jaroslav@39
    99
     * 
jaroslav@39
   100
     * @param requestor the class that makes the request
jaroslav@39
   101
     * @return appropriate context for the request
jaroslav@39
   102
     */
jaroslav@110
   103
    public static BrwsrCtx findDefault(Class<?> requestor) {
jtulach@945
   104
        if (requestor == CtxAccssr.class) {
jtulach@945
   105
            return EMPTY;
jtulach@945
   106
        }
jtulach@569
   107
        BrwsrCtx brwsr = CURRENT.get();
jtulach@569
   108
        if (brwsr != null) {
jtulach@569
   109
            return brwsr;
jtulach@569
   110
        }
jtulach@569
   111
        
jtulach@838
   112
        org.netbeans.html.context.spi.Contexts.Builder cb = Contexts.newBuilder();
jaroslav@574
   113
        boolean found = Contexts.fillInByProviders(requestor, cb);
jaroslav@320
   114
        if (!found) {
jaroslav@320
   115
            LOG.warning("No browser context found. Returning empty technology!");
jaroslav@110
   116
            return EMPTY;
jaroslav@110
   117
        }
jaroslav@110
   118
        return cb.build();
jaroslav@39
   119
    }
jtulach@569
   120
jtulach@790
   121
    /** 
jtulach@790
   122
     * <p>
jtulach@790
   123
     * Runs provided code in the context of this {@link BrwsrCtx}.
jaroslav@574
   124
     * If there is an {@link Executor} {@link Contexts#find(net.java.html.BrwsrCtx, java.lang.Class)  registered in the context}
jaroslav@574
   125
     * it is used to perform the given code. While the code <code>exec</code>
jaroslav@574
   126
     * is running the value of {@link #findDefault(java.lang.Class)} returns
jaroslav@574
   127
     * <code>this</code>. If the executor supports a single thread execution
jaroslav@574
   128
     * policy, it may execute the runnable later (in such case this method
jaroslav@574
   129
     * returns immediately). If the call to this method is done on the right
jaroslav@574
   130
     * thread, the runnable should be executed synchronously.
jtulach@790
   131
     * </p>
jtulach@790
   132
     * <p>
jtulach@790
   133
     * <b>Example Using a Timer</b>
jtulach@790
   134
     * </p>
jaroslav@617
   135
<pre>
jaroslav@617
   136
<b>public final class</b> Periodicaly <b>extends</b> {@link java.util.TimerTask} {
jaroslav@617
   137
    <b>private final</b> {@link BrwsrCtx} ctx;
jaroslav@617
   138
jtulach@652
   139
    <b>private</b> Periodicaly(BrwsrCtx ctx) {
jtulach@652
   140
        // remember the browser context and use it later
jtulach@652
   141
        this.ctx = ctx;
jaroslav@617
   142
    }
jaroslav@617
   143
    
jaroslav@617
   144
    <b>public void</b> run() {
jaroslav@617
   145
        // arrives on wrong thread, needs to be re-scheduled
jaroslav@617
   146
        ctx.{@link #execute(java.lang.Runnable) execute}(new Runnable() {
jaroslav@617
   147
            <b>public void</b> run() {
jaroslav@617
   148
                // code that needs to run in a browser environment
jaroslav@617
   149
            }
jaroslav@617
   150
        });
jaroslav@617
   151
    }
jaroslav@617
   152
jaroslav@617
   153
    // called when your page is ready
jaroslav@617
   154
    <b>public static void</b> onPageLoad(String... args) <b>throws</b> Exception {
jtulach@652
   155
        // the context at the time of page initialization
jtulach@1012
   156
        BrwsrCtx initialCtx = BrwsrCtx.findDefault(Periodicaly.<b>class</b>);
jaroslav@617
   157
        // the task that is associated with context 
jtulach@652
   158
        Periodicaly task = new Periodicaly(initialCtx);
jaroslav@617
   159
        // creates a timer
jaroslav@617
   160
        {@link java.util.Timer} t = new {@link java.util.Timer}("Move the box");
jtulach@1013
   161
        // run the task every 100ms
jaroslav@617
   162
        t.{@link java.util.Timer#scheduleAtFixedRate(java.util.TimerTask, long, long) scheduleAtFixedRate}(task, 0, 100);
jaroslav@617
   163
    }
jaroslav@617
   164
}
jaroslav@617
   165
</pre>    
jtulach@569
   166
     * 
jtulach@569
   167
     * @param exec the code to execute
jtulach@569
   168
     * @since 0.7.6
jtulach@569
   169
     */
jaroslav@596
   170
    @Override public final void execute(final Runnable exec) {
jaroslav@574
   171
        class Wrap implements Runnable {
jaroslav@574
   172
            @Override
jaroslav@574
   173
            public void run() {
jaroslav@574
   174
                BrwsrCtx prev = CURRENT.get();
jaroslav@574
   175
                try {
jaroslav@574
   176
                    CURRENT.set(BrwsrCtx.this);
jaroslav@574
   177
                    exec.run();
jaroslav@574
   178
                } finally {
jaroslav@574
   179
                    CURRENT.set(prev);
jaroslav@574
   180
                }
jaroslav@574
   181
            }
jaroslav@574
   182
        }
jaroslav@574
   183
        Wrap w = new Wrap();
jaroslav@574
   184
        Executor runIn = Contexts.find(this, Executor.class);
jaroslav@574
   185
        if (runIn == null) {
jaroslav@574
   186
            w.run();
jaroslav@574
   187
        } else {
jaroslav@574
   188
            runIn.execute(w);
jtulach@569
   189
        }
jtulach@569
   190
    }
jaroslav@5
   191
}
jaroslav@574
   192