2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 2013-2013 Oracle and/or its affiliates. All rights reserved.
6 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7 * Other names may be trademarks of their respective owners.
9 * The contents of this file are subject to the terms of either the GNU
10 * General Public License Version 2 only ("GPL") or the Common
11 * Development and Distribution License("CDDL") (collectively, the
12 * "License"). You may not use this file except in compliance with the
13 * License. You can obtain a copy of the License at
14 * http://www.netbeans.org/cddl-gplv2.html
15 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16 * specific language governing permissions and limitations under the
17 * License. When distributing the software, include this License Header
18 * Notice in each file and include the License file at
19 * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
20 * particular file as subject to the "Classpath" exception as provided
21 * by Oracle in the GPL Version 2 section of the License file that
22 * accompanied this code. If applicable, add the following below the
23 * License Header, with the fields enclosed by brackets [] replaced by
24 * your own identifying information:
25 * "Portions Copyrighted [year] [name of copyright owner]"
29 * The Original Software is NetBeans. The Initial Developer of the Original
30 * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
32 * If you wish your version of this file to be governed by only the CDDL
33 * or only the GPL Version 2, indicate your decision by adding
34 * "[Contributor] elects to include this software in this distribution
35 * under the [CDDL or GPL Version 2] license." If you do not indicate a
36 * single choice of license, a recipient has the option to distribute
37 * your version of this file under either the CDDL, the GPL Version 2 or
38 * to extend the choice of license to its licensees as provided above.
39 * However, if you add GPL Version 2 code and therefore, elected the GPL
40 * Version 2 license, then the option applies only if the new code is
41 * made subject to such option by the copyright holder.
43 package org.apidesign.html.json.spi;
45 import java.util.Collection;
46 import java.util.List;
47 import net.java.html.BrwsrCtx;
48 import org.netbeans.html.json.impl.Bindings;
49 import org.netbeans.html.json.impl.JSON;
50 import org.netbeans.html.json.impl.JSONList;
51 import org.netbeans.html.json.impl.RcvrJSON;
52 import org.netbeans.html.json.impl.RcvrJSON.MsgEvnt;
56 * @author Jaroslav Tulach <jtulach@netbeans.org>
59 public final class Proto {
60 private final Object obj;
61 private final Type type;
62 private final net.java.html.BrwsrCtx context;
63 private boolean locked;
64 private org.netbeans.html.json.impl.Bindings ko;
66 Proto(Object obj, Type type, BrwsrCtx context) {
69 this.context = context;
72 public BrwsrCtx getContext() {
76 public void acquireLock() throws IllegalStateException {
77 if (locked) throw new IllegalStateException();
81 public void checkLock() throws IllegalStateException {
82 if (locked) throw new IllegalStateException();
85 public void releaseLock() {
89 public void valueHasMutated(String propName) {
91 ko.valueHasMutated(propName);
95 public void applyBindings() {
96 initBindings().applyBindings();
99 public void runInBrowser(Runnable run) {
100 JSON.runInBrowser(context, run);
103 public void initTo(Collection<?> to, Object array) {
105 throw new IllegalStateException();
107 if (to instanceof JSONList) {
108 ((JSONList)to).init(array);
110 JSONList.init(to, array);
114 public void extract(Object json, String[] props, Object[] values) {
115 JSON.extract(context, json, props, values);
118 public <T> T read(Class<T> modelClass, Object data) {
119 return JSON.read(context, modelClass, data);
122 // XXX: Don't expose internal type
123 public Bindings initBindings() {
125 Bindings b = Bindings.apply(context, obj);
126 PropertyBinding[] pb = new PropertyBinding[type.propertyNames.length];
127 for (int i = 0; i < pb.length; i++) {
128 pb[i] = b.registerProperty(
129 type.propertyNames[i], i, obj, type, type.propertyReadOnly[i]
132 FunctionBinding[] fb = new FunctionBinding[type.functions.length];
133 for (int i = 0; i < fb.length; i++) {
134 fb[i] = FunctionBinding.registerFunction(
135 type.functions[i], i, obj, type
139 b.finish(obj, pb, fb);
144 // XXX: Don't expose internal type
145 public Bindings getBindings() {
149 // XXX: Can be hidden too
150 public void onChange(int index) {
151 type.onChange(obj, index);
154 public void loadJSON(final int index,
155 String urlBefore, String urlAfter, String method,
158 class Rcvr extends RcvrJSON {
160 protected void onMessage(MsgEvnt msg) {
161 type.onMessage(obj, index, 1, msg.getValues());
165 protected void onError(MsgEvnt msg) {
166 type.onMessage(obj, index, 2, msg.getException());
169 JSON.loadJSON(context, new Rcvr(), urlBefore, urlAfter, method, data);
172 public String toString(Object data, String propName) {
173 return JSON.toString(context, data, propName);
175 public Number toNumber(Object data, String propName) {
176 return JSON.toNumber(context, data, propName);
179 public <T> T toModel(Class<T> type, Object data, String propName) {
180 return JSON.toModel(context, type, data, propName);
183 public <T> List<T> createList(String propName, int onChange, String... dependingProps) {
184 return new JSONList<T>(this, propName, onChange, dependingProps);
187 public <T> void cloneList(Collection<T> to, BrwsrCtx ctx, Collection<T> from) {
188 Boolean isModel = null;
190 if (isModel == null) {
191 isModel = JSON.isModel(t.getClass());
194 to.add(JSON.bindTo(t, ctx));
201 /** Functionality used by the code generated by annotation
202 * processor for the {@link net.java.html.json.Model} annotation.
204 * @param <Model> the generated class
207 public static abstract class Type<Model> {
208 private final Class<Model> clazz;
209 private final String[] propertyNames;
210 private final boolean[] propertyReadOnly;
211 private final String[] functions;
214 Class<Model> clazz, Class<?> modelFor, int properties, int functions
216 assert getClass().getName().endsWith("$Html4JavaType");
217 assert getClass().getDeclaringClass() == clazz;
219 this.propertyNames = new String[properties];
220 this.propertyReadOnly = new boolean[properties];
221 this.functions = new String[functions];
222 JSON.register(clazz, this);
225 protected final void registerProperty(String name, int index, boolean readOnly) {
226 assert propertyNames[index] == null;
227 propertyNames[index] = name;
228 propertyReadOnly[index] = readOnly;
231 protected final void registerFunction(String name, int index) {
232 assert functions[index] == null;
233 functions[index] = name;
236 public Proto protoFor(Object obj, BrwsrCtx context) {
237 return new Proto(obj, this, context);
240 // XXX: should be protected
241 public abstract void setValue(Model model, int index, Object value);
242 public abstract Object getValue(Model model, int index);
243 public abstract void call(Model model, int index, Object data, Object event);
244 public abstract Model cloneTo(Object model, BrwsrCtx ctx);
245 public abstract Model read(BrwsrCtx c, Object json);
246 public abstract void onChange(Model model, int index);
247 public abstract Proto protoFor(Object object);
253 * @param type 0 - onOpen, 1 - onMessage, 2 - onError, 3 - onClose
256 public abstract void onMessage(Model model, int index, int type, Object data);
258 public <T> void copyJSON(BrwsrCtx context, Object[] src, Class<T> destType, T[] dest) {
259 for (int i = 0; i < src.length && i < dest.length; i++) {
260 dest[i] = org.netbeans.html.json.impl.JSON.read(context, destType, src[i]);
265 // Various support methods the generated classes use
268 /** Compares two objects that can be converted to integers.
269 * @return true if they are the same
271 public final boolean isSame(int a, int b) {
275 /** Compares two objects that can be converted to (floating point)
277 * @return true if they are the same
279 public final boolean isSame(double a, double b) {
283 /** Compares two objects for being the same - e.g. either <code>==</code>
284 * or <code>equals</code>.
285 * @return true if they are equals
287 public final boolean isSame(Object a, Object b) {
291 if (a == null || b == null) {
297 /** Cumulative hash function. Adds hashcode of the object to the
299 * @param o the object (or <code>null</code>)
300 * @param h the previous value of the hash
301 * @return new hash - the old one xor the object's one
303 public final int hashPlus(Object o, int h) {
304 return o == null ? h : h ^ o.hashCode();
307 /** Converts an object to its JSON value.
309 * @param obj the object to convert
310 * @return JSON representation of the object
312 public final String toJSON(Object obj) {
313 return JSON.toJSON(obj);
316 /** Converts the value to string.
318 * @param val the value
319 * @return the converted value
321 public final String stringValue(Object val) {
322 return JSON.stringValue(val);
325 /** Converts the value to number.
327 * @param val the value
328 * @return the converted value
330 public final Number numberValue(Object val) {
331 return JSON.numberValue(val);
334 /** Converts the value to character.
336 * @param val the value
337 * @return the converted value
339 public final Character charValue(Object val) {
340 return JSON.charValue(val);
343 /** Converts the value to boolean.
345 * @param val the value
346 * @return the converted value
348 public final Boolean boolValue(Object val) {
349 return JSON.boolValue(val);
352 /** Extracts value of specific type from given object.
354 * @param <T> the type of object one is interested in
355 * @param type the type
356 * @param val the object to convert to type
357 * @return the converted value
359 public final <T> T extractValue(Class<T> type, Object val) {
360 if (Number.class.isAssignableFrom(type)) {
361 val = numberValue(val);
363 if (Boolean.class == type) {
364 val = boolValue(val);
366 if (String.class == type) {
367 val = stringValue(val);
369 if (Character.class == type) {
370 val = charValue(val);
372 if (Integer.class == type) {
373 val = val instanceof Number ? ((Number) val).intValue() : 0;
375 if (Long.class == type) {
376 val = val instanceof Number ? ((Number) val).longValue() : 0;
378 if (Short.class == type) {
379 val = val instanceof Number ? ((Number) val).shortValue() : 0;
381 if (Byte.class == type) {
382 val = val instanceof Number ? ((Number) val).byteValue() : 0;
384 if (Double.class == type) {
385 val = val instanceof Number ? ((Number) val).doubleValue() : Double.NaN;
387 if (Float.class == type) {
388 val = val instanceof Number ? ((Number) val).floatValue() : Float.NaN;
390 return type.cast(val);