1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java Mon Dec 16 16:59:43 2013 +0100
1.3 @@ -0,0 +1,1767 @@
1.4 +/**
1.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
1.6 + *
1.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
1.8 + *
1.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
1.10 + * Other names may be trademarks of their respective owners.
1.11 + *
1.12 + * The contents of this file are subject to the terms of either the GNU
1.13 + * General Public License Version 2 only ("GPL") or the Common
1.14 + * Development and Distribution License("CDDL") (collectively, the
1.15 + * "License"). You may not use this file except in compliance with the
1.16 + * License. You can obtain a copy of the License at
1.17 + * http://www.netbeans.org/cddl-gplv2.html
1.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
1.19 + * specific language governing permissions and limitations under the
1.20 + * License. When distributing the software, include this License Header
1.21 + * Notice in each file and include the License file at
1.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
1.23 + * particular file as subject to the "Classpath" exception as provided
1.24 + * by Oracle in the GPL Version 2 section of the License file that
1.25 + * accompanied this code. If applicable, add the following below the
1.26 + * License Header, with the fields enclosed by brackets [] replaced by
1.27 + * your own identifying information:
1.28 + * "Portions Copyrighted [year] [name of copyright owner]"
1.29 + *
1.30 + * Contributor(s):
1.31 + *
1.32 + * The Original Software is NetBeans. The Initial Developer of the Original
1.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
1.34 + *
1.35 + * If you wish your version of this file to be governed by only the CDDL
1.36 + * or only the GPL Version 2, indicate your decision by adding
1.37 + * "[Contributor] elects to include this software in this distribution
1.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
1.39 + * single choice of license, a recipient has the option to distribute
1.40 + * your version of this file under either the CDDL, the GPL Version 2 or
1.41 + * to extend the choice of license to its licensees as provided above.
1.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
1.43 + * Version 2 license, then the option applies only if the new code is
1.44 + * made subject to such option by the copyright holder.
1.45 + */
1.46 +package org.netbeans.html.json.impl;
1.47 +
1.48 +import java.io.IOException;
1.49 +import java.io.OutputStreamWriter;
1.50 +import java.io.StringWriter;
1.51 +import java.io.Writer;
1.52 +import java.lang.annotation.AnnotationTypeMismatchException;
1.53 +import java.lang.annotation.IncompleteAnnotationException;
1.54 +import java.lang.reflect.Method;
1.55 +import java.util.ArrayList;
1.56 +import java.util.Arrays;
1.57 +import java.util.Collection;
1.58 +import java.util.Collections;
1.59 +import java.util.HashMap;
1.60 +import java.util.HashSet;
1.61 +import java.util.LinkedHashSet;
1.62 +import java.util.List;
1.63 +import java.util.Map;
1.64 +import java.util.ResourceBundle;
1.65 +import java.util.Set;
1.66 +import java.util.WeakHashMap;
1.67 +import java.util.logging.Level;
1.68 +import java.util.logging.Logger;
1.69 +import javax.annotation.processing.AbstractProcessor;
1.70 +import javax.annotation.processing.Completion;
1.71 +import javax.annotation.processing.Completions;
1.72 +import javax.annotation.processing.ProcessingEnvironment;
1.73 +import javax.annotation.processing.Processor;
1.74 +import javax.annotation.processing.RoundEnvironment;
1.75 +import javax.annotation.processing.SupportedAnnotationTypes;
1.76 +import javax.annotation.processing.SupportedSourceVersion;
1.77 +import javax.lang.model.SourceVersion;
1.78 +import javax.lang.model.element.AnnotationMirror;
1.79 +import javax.lang.model.element.AnnotationValue;
1.80 +import javax.lang.model.element.Element;
1.81 +import javax.lang.model.element.ElementKind;
1.82 +import javax.lang.model.element.ExecutableElement;
1.83 +import javax.lang.model.element.Modifier;
1.84 +import javax.lang.model.element.PackageElement;
1.85 +import javax.lang.model.element.TypeElement;
1.86 +import javax.lang.model.element.VariableElement;
1.87 +import javax.lang.model.type.ArrayType;
1.88 +import javax.lang.model.type.DeclaredType;
1.89 +import javax.lang.model.type.MirroredTypeException;
1.90 +import javax.lang.model.type.TypeKind;
1.91 +import javax.lang.model.type.TypeMirror;
1.92 +import javax.lang.model.util.Elements;
1.93 +import javax.lang.model.util.Types;
1.94 +import javax.tools.Diagnostic;
1.95 +import javax.tools.FileObject;
1.96 +import net.java.html.json.ComputedProperty;
1.97 +import net.java.html.json.Model;
1.98 +import net.java.html.json.Function;
1.99 +import net.java.html.json.ModelOperation;
1.100 +import net.java.html.json.OnPropertyChange;
1.101 +import net.java.html.json.OnReceive;
1.102 +import net.java.html.json.Property;
1.103 +import org.openide.util.lookup.ServiceProvider;
1.104 +
1.105 +/** Annotation processor to process {@link Model @Model} annotations and
1.106 + * generate appropriate model classes.
1.107 + *
1.108 + * @author Jaroslav Tulach <jtulach@netbeans.org>
1.109 + */
1.110 +@ServiceProvider(service=Processor.class)
1.111 +@SupportedSourceVersion(SourceVersion.RELEASE_6)
1.112 +@SupportedAnnotationTypes({
1.113 + "net.java.html.json.Model",
1.114 + "net.java.html.json.ModelOperation",
1.115 + "net.java.html.json.Function",
1.116 + "net.java.html.json.OnReceive",
1.117 + "net.java.html.json.OnPropertyChange",
1.118 + "net.java.html.json.ComputedProperty",
1.119 + "net.java.html.json.Property"
1.120 +})
1.121 +public final class ModelProcessor extends AbstractProcessor {
1.122 + private static final Logger LOG = Logger.getLogger(ModelProcessor.class.getName());
1.123 + private final Map<Element,String> models = new WeakHashMap<Element,String>();
1.124 + private final Map<Element,Prprt[]> verify = new WeakHashMap<Element,Prprt[]>();
1.125 + @Override
1.126 + public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
1.127 + boolean ok = true;
1.128 + for (Element e : roundEnv.getElementsAnnotatedWith(Model.class)) {
1.129 + if (!processModel(e)) {
1.130 + ok = false;
1.131 + }
1.132 + }
1.133 + if (roundEnv.processingOver()) {
1.134 + models.clear();
1.135 + for (Map.Entry<Element, Prprt[]> entry : verify.entrySet()) {
1.136 + TypeElement te = (TypeElement)entry.getKey();
1.137 + String fqn = processingEnv.getElementUtils().getBinaryName(te).toString();
1.138 + Element finalElem = processingEnv.getElementUtils().getTypeElement(fqn);
1.139 + if (finalElem == null) {
1.140 + continue;
1.141 + }
1.142 + Prprt[] props;
1.143 + Model m = finalElem.getAnnotation(Model.class);
1.144 + if (m == null) {
1.145 + continue;
1.146 + }
1.147 + props = Prprt.wrap(processingEnv, finalElem, m.properties());
1.148 + for (Prprt p : props) {
1.149 + boolean[] isModel = { false };
1.150 + boolean[] isEnum = { false };
1.151 + boolean[] isPrimitive = { false };
1.152 + String t = checkType(p, isModel, isEnum, isPrimitive);
1.153 + if (isEnum[0]) {
1.154 + continue;
1.155 + }
1.156 + if (isPrimitive[0]) {
1.157 + continue;
1.158 + }
1.159 + if (isModel[0]) {
1.160 + continue;
1.161 + }
1.162 + if ("java.lang.String".equals(t)) {
1.163 + continue;
1.164 + }
1.165 + error("The type " + t + " should be defined by @Model annotation", entry.getKey());
1.166 + }
1.167 + }
1.168 + verify.clear();
1.169 + }
1.170 + return ok;
1.171 + }
1.172 +
1.173 + private void error(String msg, Element e) {
1.174 + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e);
1.175 + }
1.176 +
1.177 + private boolean processModel(Element e) {
1.178 + boolean ok = true;
1.179 + Model m = e.getAnnotation(Model.class);
1.180 + if (m == null) {
1.181 + return true;
1.182 + }
1.183 + String pkg = findPkgName(e);
1.184 + Writer w;
1.185 + String className = m.className();
1.186 + models.put(e, className);
1.187 + try {
1.188 + StringWriter body = new StringWriter();
1.189 + List<String> propsGetSet = new ArrayList<String>();
1.190 + List<String> functions = new ArrayList<String>();
1.191 + Map<String, Collection<String>> propsDeps = new HashMap<String, Collection<String>>();
1.192 + Map<String, Collection<String>> functionDeps = new HashMap<String, Collection<String>>();
1.193 + Prprt[] props = createProps(e, m.properties());
1.194 +
1.195 + if (!generateComputedProperties(body, props, e.getEnclosedElements(), propsGetSet, propsDeps)) {
1.196 + ok = false;
1.197 + }
1.198 + if (!generateOnChange(e, propsDeps, props, className, functionDeps)) {
1.199 + ok = false;
1.200 + }
1.201 + if (!generateProperties(e, body, props, propsGetSet, propsDeps, functionDeps)) {
1.202 + ok = false;
1.203 + }
1.204 + if (!generateFunctions(e, body, className, e.getEnclosedElements(), functions)) {
1.205 + ok = false;
1.206 + }
1.207 + if (!generateReceive(e, body, className, e.getEnclosedElements(), functions)) {
1.208 + ok = false;
1.209 + }
1.210 + if (!generateOperation(e, body, className, e.getEnclosedElements())) {
1.211 + ok = false;
1.212 + }
1.213 + FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e);
1.214 + w = new OutputStreamWriter(java.openOutputStream());
1.215 + try {
1.216 + w.append("package " + pkg + ";\n");
1.217 + w.append("import net.java.html.json.*;\n");
1.218 + w.append("public final class ").append(className).append(" implements Cloneable {\n");
1.219 + w.append(" private boolean locked;\n");
1.220 + w.append(" private net.java.html.BrwsrCtx context;\n");
1.221 + w.append(" private org.netbeans.html.json.impl.Bindings[] ko = { null };\n");
1.222 + w.append(body.toString());
1.223 + w.append(" private static Class<" + inPckName(e) + "> modelFor() { return null; }\n");
1.224 + w.append(" private ").append(className).append("(net.java.html.BrwsrCtx context) {\n");
1.225 + w.append(" this.context = context;\n");
1.226 + w.append(" };\n");
1.227 + w.append(" public ").append(className).append("() {\n");
1.228 + w.append(" this(net.java.html.BrwsrCtx.findDefault(").append(className).append(".class));\n");
1.229 + for (Prprt p : props) {
1.230 + if (p.array()) {
1.231 + continue;
1.232 + }
1.233 + boolean[] isModel = {false};
1.234 + boolean[] isEnum = {false};
1.235 + boolean isPrimitive[] = {false};
1.236 + String tn = checkType(p, isModel, isEnum, isPrimitive);
1.237 + if (isModel[0]) {
1.238 + w.write(" prop_" + p.name() + " = new " + tn + "();\n");
1.239 + }
1.240 + }
1.241 + w.append(" };\n");
1.242 + if (props.length > 0) {
1.243 + w.append(" public ").append(className).append("(");
1.244 + Prprt firstArray = null;
1.245 + String sep = "";
1.246 + for (Prprt p : props) {
1.247 + if (p.array()) {
1.248 + if (firstArray == null) {
1.249 + firstArray = p;
1.250 + }
1.251 + continue;
1.252 + }
1.253 + String tn = typeName(e, p);
1.254 + w.write(sep);
1.255 + w.write(tn);
1.256 + w.write(" " + p.name());
1.257 + sep = ", ";
1.258 + }
1.259 + if (firstArray != null) {
1.260 + String tn;
1.261 + boolean[] isModel = {false};
1.262 + boolean[] isEnum = {false};
1.263 + boolean isPrimitive[] = {false};
1.264 + tn = checkType(firstArray, isModel, isEnum, isPrimitive);
1.265 + w.write(sep);
1.266 + w.write(tn);
1.267 + w.write("... " + firstArray.name());
1.268 + }
1.269 + w.append(") {\n");
1.270 + w.append(" this(net.java.html.BrwsrCtx.findDefault(").append(className).append(".class));\n");
1.271 + for (Prprt p : props) {
1.272 + if (p.array()) {
1.273 + continue;
1.274 + }
1.275 + w.write(" this.prop_" + p.name() + " = " + p.name() + ";\n");
1.276 + }
1.277 + if (firstArray != null) {
1.278 + w.write(" this.prop_" + firstArray.name() + ".init(" + firstArray.name() + ");\n");
1.279 + }
1.280 + w.append(" };\n");
1.281 + }
1.282 + w.append(" private org.netbeans.html.json.impl.Bindings intKnckt() {\n");
1.283 + w.append(" if (ko[0] != null) return ko[0];\n");
1.284 + w.append(" ko[0] = org.netbeans.html.json.impl.Bindings.apply(context, this);\n");
1.285 + {
1.286 + w.append(" org.apidesign.html.json.spi.PropertyBinding[] propArr = {\n");
1.287 + for (int i = 0; i < propsGetSet.size(); i += 5) {
1.288 + w.append(" ko[0].registerProperty(\"").append(propsGetSet.get(i)).append("\", this, new P(");
1.289 + w.append((i / 5) + "), " + (propsGetSet.get(i + 2) == null) + "),\n");
1.290 + }
1.291 + w.append(" };\n");
1.292 + }
1.293 + {
1.294 + w.append(" org.apidesign.html.json.spi.FunctionBinding[] funcArr = {\n");
1.295 + for (int i = 0; i < functions.size(); i += 2) {
1.296 + w.append(" ko[0].registerFunction(\"").append(functions.get(i)).append("\", this, new P(");
1.297 + w.append((i / 2) + ")),\n");
1.298 + }
1.299 + w.append(" };\n");
1.300 + }
1.301 + w.append(" ko[0].finish(this, propArr, funcArr);\n");
1.302 + w.append(" return ko[0];\n");
1.303 + w.append(" };\n");
1.304 + w.append(" private static final class P implements org.netbeans.html.json.impl.SetAndGet<" + className + ">,\n");
1.305 + w.append(" org.netbeans.html.json.impl.Callback<" + className + ">,\n");
1.306 + w.append(" org.netbeans.html.json.impl.FromJSON<" + className + "> {\n");
1.307 + w.append(" private final int type;\n");
1.308 + w.append(" P(int t) { type = t; };\n");
1.309 + w.append(" public void setValue(" + className + " data, Object value) {\n");
1.310 + w.append(" switch (type) {\n");
1.311 + for (int i = 0; i < propsGetSet.size(); i += 5) {
1.312 + final String set = propsGetSet.get(i + 2);
1.313 + String tn = propsGetSet.get(i + 4);
1.314 + String btn = findBoxedType(tn);
1.315 + if (btn != null) {
1.316 + tn = btn;
1.317 + }
1.318 + if (set != null) {
1.319 + w.append(" case " + (i / 5) + ": data." + strip(set) + "(org.netbeans.html.json.impl.JSON.extractValue(" + tn + ".class, value)); return;\n");
1.320 + }
1.321 + }
1.322 + w.append(" }\n");
1.323 + w.append(" }\n");
1.324 + w.append(" public Object getValue(" + className + " data) {\n");
1.325 + w.append(" switch (type) {\n");
1.326 + for (int i = 0; i < propsGetSet.size(); i += 5) {
1.327 + final String get = propsGetSet.get(i + 1);
1.328 + if (get != null) {
1.329 + w.append(" case " + (i / 5) + ": return data." + strip(get) + "();\n");
1.330 + }
1.331 + }
1.332 + w.append(" }\n");
1.333 + w.append(" throw new UnsupportedOperationException();\n");
1.334 + w.append(" }\n");
1.335 + w.append(" public void call(" + className + " model, Object data, Object ev) {\n");
1.336 + w.append(" switch (type) {\n");
1.337 + for (int i = 0; i < functions.size(); i += 2) {
1.338 + final String name = functions.get(i);
1.339 + w.append(" case " + (i / 2) + ": model." + name + "(data, ev); return;\n");
1.340 + }
1.341 + w.append(" }\n");
1.342 + w.append(" throw new UnsupportedOperationException();\n");
1.343 + w.append(" }\n");
1.344 + w.append(" public Class<" + className + "> factoryFor() { return " + className + ".class; }\n");
1.345 + w.append(" public " + className + " read(net.java.html.BrwsrCtx c, Object json) { return new " + className + "(c, json); }\n");
1.346 + w.append(" public " + className + " cloneTo(Object o, net.java.html.BrwsrCtx c) { return ((" + className + ")o).clone(c); }\n");
1.347 + w.append(" }\n");
1.348 + w.append(" static { org.netbeans.html.json.impl.JSON.register(new P(0)); }\n");
1.349 + w.append(" private ").append(className).append("(net.java.html.BrwsrCtx c, Object json) {\n");
1.350 + w.append(" this.context = c;\n");
1.351 + int values = 0;
1.352 + for (int i = 0; i < propsGetSet.size(); i += 5) {
1.353 + Prprt p = findPrprt(props, propsGetSet.get(i));
1.354 + if (p == null) {
1.355 + continue;
1.356 + }
1.357 + values++;
1.358 + }
1.359 + w.append(" Object[] ret = new Object[" + values + "];\n");
1.360 + w.append(" org.netbeans.html.json.impl.JSON.extract(context, json, new String[] {\n");
1.361 + for (int i = 0; i < propsGetSet.size(); i += 5) {
1.362 + Prprt p = findPrprt(props, propsGetSet.get(i));
1.363 + if (p == null) {
1.364 + continue;
1.365 + }
1.366 + w.append(" \"").append(propsGetSet.get(i)).append("\",\n");
1.367 + }
1.368 + w.append(" }, ret);\n");
1.369 + for (int i = 0, cnt = 0, prop = 0; i < propsGetSet.size(); i += 5) {
1.370 + final String pn = propsGetSet.get(i);
1.371 + Prprt p = findPrprt(props, pn);
1.372 + if (p == null) {
1.373 + continue;
1.374 + }
1.375 + boolean[] isModel = { false };
1.376 + boolean[] isEnum = { false };
1.377 + boolean isPrimitive[] = { false };
1.378 + String type = checkType(props[prop++], isModel, isEnum, isPrimitive);
1.379 + if (p.array()) {
1.380 + w.append(" if (ret[" + cnt + "] instanceof Object[]) {\n");
1.381 + w.append(" for (Object e : ((Object[])ret[" + cnt + "])) {\n");
1.382 + if (isModel[0]) {
1.383 + w.append(" this.prop_").append(pn).append(".add(org.netbeans.html.json.impl.JSON.read");
1.384 + w.append("(c, " + type + ".class, e));\n");
1.385 + } else if (isEnum[0]) {
1.386 + w.append(" this.prop_").append(pn);
1.387 + w.append(".add(e == null ? null : ");
1.388 + w.append(type).append(".valueOf(org.netbeans.html.json.impl.JSON.stringValue(e)));\n");
1.389 + } else {
1.390 + if (isPrimitive(type)) {
1.391 + w.append(" this.prop_").append(pn).append(".add(org.netbeans.html.json.impl.JSON.numberValue(e).");
1.392 + w.append(type).append("Value());\n");
1.393 + } else {
1.394 + w.append(" this.prop_").append(pn).append(".add((");
1.395 + w.append(type).append(")e);\n");
1.396 + }
1.397 + }
1.398 + w.append(" }\n");
1.399 + w.append(" }\n");
1.400 + } else {
1.401 + if (isEnum[0]) {
1.402 + w.append(" try {\n");
1.403 + w.append(" this.prop_").append(pn);
1.404 + w.append(" = ret[" + cnt + "] == null ? null : ");
1.405 + w.append(type).append(".valueOf(org.netbeans.html.json.impl.JSON.stringValue(ret[" + cnt + "]));\n");
1.406 + w.append(" } catch (IllegalArgumentException ex) {\n");
1.407 + w.append(" ex.printStackTrace();\n");
1.408 + w.append(" }\n");
1.409 + } else if (isPrimitive(type)) {
1.410 + w.append(" this.prop_").append(pn);
1.411 + w.append(" = ret[" + cnt + "] == null ? ");
1.412 + if ("char".equals(type)) {
1.413 + w.append("0 : (org.netbeans.html.json.impl.JSON.charValue(");
1.414 + } else if ("boolean".equals(type)) {
1.415 + w.append("false : (org.netbeans.html.json.impl.JSON.boolValue(");
1.416 + } else {
1.417 + w.append("0 : (org.netbeans.html.json.impl.JSON.numberValue(");
1.418 + }
1.419 + w.append("ret[" + cnt + "])).");
1.420 + w.append(type).append("Value();\n");
1.421 + } else if (isModel[0]) {
1.422 + w.append(" this.prop_").append(pn).append(" = org.netbeans.html.json.impl.JSON.read");
1.423 + w.append("(c, " + type + ".class, ");
1.424 + w.append("ret[" + cnt + "]);\n");
1.425 + }else {
1.426 + w.append(" this.prop_").append(pn);
1.427 + w.append(" = (").append(type).append(')');
1.428 + w.append("ret[" + cnt + "];\n");
1.429 + }
1.430 + }
1.431 + cnt++;
1.432 + }
1.433 + w.append(" };\n");
1.434 + writeToString(props, w);
1.435 + writeClone(className, props, w);
1.436 + w.write(" /** Activates this model instance in the current {@link \n"
1.437 + + "net.java.html.json.Models#bind(java.lang.Object, net.java.html.BrwsrCtx) browser context}. \n"
1.438 + + "In case of using Knockout technology, this means to \n"
1.439 + + "bind JSON like data in this model instance with Knockout tags in \n"
1.440 + + "the surrounding HTML page.\n"
1.441 + + "*/\n"
1.442 + );
1.443 + w.write(" public " + className + " applyBindings() {\n");
1.444 + w.write(" intKnckt().applyBindings();\n");
1.445 + w.write(" return this;\n");
1.446 + w.write(" }\n");
1.447 + w.write(" public boolean equals(Object o) {\n");
1.448 + w.write(" if (o == this) return true;\n");
1.449 + w.write(" if (o instanceof org.netbeans.html.json.impl.WrapperObject) {\n");
1.450 + w.write(" ((org.netbeans.html.json.impl.WrapperObject)o).setRealObject(intKnckt().koData());\n");
1.451 + w.write(" return false;\n");
1.452 + w.write(" }\n");
1.453 + w.write(" if (!(o instanceof " + className + ")) return false;\n");
1.454 + w.write(" " + className + " p = (" + className + ")o;\n");
1.455 + for (Prprt p : props) {
1.456 + w.write(" if (!org.netbeans.html.json.impl.JSON.isSame(prop_" + p.name() + ", p.prop_" + p.name() + ")) return false;\n");
1.457 + }
1.458 + w.write(" return true;\n");
1.459 + w.write(" }\n");
1.460 + w.write(" public int hashCode() {\n");
1.461 + w.write(" int h = " + className + ".class.getName().hashCode();\n");
1.462 + for (Prprt p : props) {
1.463 + w.write(" h = org.netbeans.html.json.impl.JSON.hashPlus(prop_" + p.name() + ", h);\n");
1.464 + }
1.465 + w.write(" return h;\n");
1.466 + w.write(" }\n");
1.467 + w.write("}\n");
1.468 + } finally {
1.469 + w.close();
1.470 + }
1.471 + } catch (IOException ex) {
1.472 + error("Can't create " + className + ".java", e);
1.473 + return false;
1.474 + }
1.475 + return ok;
1.476 + }
1.477 +
1.478 + private boolean generateProperties(
1.479 + Element where,
1.480 + Writer w, Prprt[] properties,
1.481 + Collection<String> props,
1.482 + Map<String,Collection<String>> deps,
1.483 + Map<String,Collection<String>> functionDeps
1.484 + ) throws IOException {
1.485 + boolean ok = true;
1.486 + for (Prprt p : properties) {
1.487 + final String tn;
1.488 + tn = typeName(where, p);
1.489 + String[] gs = toGetSet(p.name(), tn, p.array());
1.490 + String castTo;
1.491 +
1.492 + if (p.array()) {
1.493 + w.write(" private org.netbeans.html.json.impl.JSONList<" + tn + "> prop_" + p.name() + " = new org.netbeans.html.json.impl.JSONList<" + tn + ">(ko, \""
1.494 + + p.name() + "\"");
1.495 + Collection<String> dependants = deps.get(p.name());
1.496 + if (dependants != null) {
1.497 + for (String depProp : dependants) {
1.498 + w.write(", ");
1.499 + w.write('\"');
1.500 + w.write(depProp);
1.501 + w.write('\"');
1.502 + }
1.503 + }
1.504 + w.write(")");
1.505 +
1.506 + dependants = functionDeps.get(p.name());
1.507 + if (dependants != null) {
1.508 + w.write(".onChange(new Runnable() { public void run() {\n");
1.509 + for (String call : dependants) {
1.510 + w.append(" ").append(call);
1.511 + }
1.512 + w.write(" }})");
1.513 + }
1.514 + w.write(";\n");
1.515 +
1.516 + castTo = "java.util.List";
1.517 + w.write(" public java.util.List<" + tn + "> " + gs[0] + "() {\n");
1.518 + w.write(" if (locked) throw new IllegalStateException();\n");
1.519 + w.write(" return prop_" + p.name() + ";\n");
1.520 + w.write(" }\n");
1.521 + } else {
1.522 + castTo = tn;
1.523 + w.write(" private " + tn + " prop_" + p.name() + ";\n");
1.524 + w.write(" public " + tn + " " + gs[0] + "() {\n");
1.525 + w.write(" if (locked) throw new IllegalStateException();\n");
1.526 + w.write(" return prop_" + p.name() + ";\n");
1.527 + w.write(" }\n");
1.528 + w.write(" public void " + gs[1] + "(" + tn + " v) {\n");
1.529 + w.write(" if (locked) throw new IllegalStateException();\n");
1.530 + w.write(" if (org.netbeans.html.json.impl.JSON.isSame(prop_" + p.name() + ", v)) return;\n");
1.531 + w.write(" prop_" + p.name() + " = v;\n");
1.532 + w.write(" org.netbeans.html.json.impl.Bindings b = ko[0];\n");
1.533 + w.write(" if (b != null) {\n");
1.534 + w.write(" b.valueHasMutated(\"" + p.name() + "\");\n");
1.535 + Collection<String> dependants = deps.get(p.name());
1.536 + if (dependants != null) {
1.537 + for (String depProp : dependants) {
1.538 + w.write(" b.valueHasMutated(\"" + depProp + "\");\n");
1.539 + }
1.540 + }
1.541 + w.write(" }\n");
1.542 + dependants = functionDeps.get(p.name());
1.543 + if (dependants != null) {
1.544 + for (String call : dependants) {
1.545 + w.append(" ").append(call);
1.546 + }
1.547 + }
1.548 + w.write(" }\n");
1.549 + }
1.550 +
1.551 + props.add(p.name());
1.552 + props.add(gs[2]);
1.553 + props.add(gs[3]);
1.554 + props.add(gs[0]);
1.555 + props.add(castTo);
1.556 + }
1.557 + return ok;
1.558 + }
1.559 +
1.560 + private boolean generateComputedProperties(
1.561 + Writer w, Prprt[] fixedProps,
1.562 + Collection<? extends Element> arr, Collection<String> props,
1.563 + Map<String,Collection<String>> deps
1.564 + ) throws IOException {
1.565 + boolean ok = true;
1.566 + for (Element e : arr) {
1.567 + if (e.getKind() != ElementKind.METHOD) {
1.568 + continue;
1.569 + }
1.570 + if (e.getAnnotation(ComputedProperty.class) == null) {
1.571 + continue;
1.572 + }
1.573 + if (!e.getModifiers().contains(Modifier.STATIC)) {
1.574 + error("Method " + e.getSimpleName() + " has to be static when annotated by @ComputedProperty", e);
1.575 + ok = false;
1.576 + continue;
1.577 + }
1.578 + ExecutableElement ee = (ExecutableElement)e;
1.579 + final TypeMirror rt = ee.getReturnType();
1.580 + final Types tu = processingEnv.getTypeUtils();
1.581 + TypeMirror ert = tu.erasure(rt);
1.582 + String tn = fqn(ert, ee);
1.583 + boolean array = false;
1.584 + final TypeMirror toCheck;
1.585 + if (tn.equals("java.util.List")) {
1.586 + array = true;
1.587 + toCheck = ((DeclaredType)rt).getTypeArguments().get(0);
1.588 + } else {
1.589 + toCheck = rt;
1.590 + }
1.591 +
1.592 + final String sn = ee.getSimpleName().toString();
1.593 +
1.594 + if (toCheck.getKind().isPrimitive()) {
1.595 + // OK
1.596 + } else {
1.597 + TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
1.598 + TypeMirror enumType = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType();
1.599 +
1.600 + if (tu.isSubtype(toCheck, stringType)) {
1.601 + // OK
1.602 + } else if (tu.isSubtype(tu.erasure(toCheck), tu.erasure(enumType))) {
1.603 + // OK
1.604 + } else if (isModel(toCheck)) {
1.605 + // OK
1.606 + } else {
1.607 + ok = false;
1.608 + error(sn + " cannot return " + toCheck, e);
1.609 + }
1.610 + }
1.611 +
1.612 + String[] gs = toGetSet(sn, tn, array);
1.613 +
1.614 + w.write(" public " + tn + " " + gs[0] + "() {\n");
1.615 + w.write(" if (locked) throw new IllegalStateException();\n");
1.616 + int arg = 0;
1.617 + for (VariableElement pe : ee.getParameters()) {
1.618 + final String dn = pe.getSimpleName().toString();
1.619 +
1.620 + if (!verifyPropName(pe, dn, fixedProps)) {
1.621 + ok = false;
1.622 + }
1.623 +
1.624 + final String dt = fqn(pe.asType(), ee);
1.625 + String[] call = toGetSet(dn, dt, false);
1.626 + w.write(" " + dt + " arg" + (++arg) + " = ");
1.627 + w.write(call[0] + "();\n");
1.628 +
1.629 + Collection<String> depends = deps.get(dn);
1.630 + if (depends == null) {
1.631 + depends = new LinkedHashSet<String>();
1.632 + deps.put(dn, depends);
1.633 + }
1.634 + depends.add(sn);
1.635 + }
1.636 + w.write(" try {\n");
1.637 + w.write(" locked = true;\n");
1.638 + w.write(" return " + fqn(ee.getEnclosingElement().asType(), ee) + '.' + e.getSimpleName() + "(");
1.639 + String sep = "";
1.640 + for (int i = 1; i <= arg; i++) {
1.641 + w.write(sep);
1.642 + w.write("arg" + i);
1.643 + sep = ", ";
1.644 + }
1.645 + w.write(");\n");
1.646 + w.write(" } finally {\n");
1.647 + w.write(" locked = false;\n");
1.648 + w.write(" }\n");
1.649 + w.write(" }\n");
1.650 +
1.651 + props.add(e.getSimpleName().toString());
1.652 + props.add(gs[2]);
1.653 + props.add(null);
1.654 + props.add(gs[0]);
1.655 + props.add(tn);
1.656 + }
1.657 +
1.658 + return ok;
1.659 + }
1.660 +
1.661 + private static String[] toGetSet(String name, String type, boolean array) {
1.662 + String n = Character.toUpperCase(name.charAt(0)) + name.substring(1);
1.663 + String bck2brwsrType = "L" + type.replace('.', '_') + "_2";
1.664 + if ("int".equals(type)) {
1.665 + bck2brwsrType = "I";
1.666 + }
1.667 + if ("double".equals(type)) {
1.668 + bck2brwsrType = "D";
1.669 + }
1.670 + String pref = "get";
1.671 + if ("boolean".equals(type)) {
1.672 + pref = "is";
1.673 + bck2brwsrType = "Z";
1.674 + }
1.675 + final String nu = n.replace('.', '_');
1.676 + if (array) {
1.677 + return new String[] {
1.678 + "get" + n,
1.679 + null,
1.680 + "get" + nu + "__Ljava_util_List_2",
1.681 + null
1.682 + };
1.683 + }
1.684 + return new String[]{
1.685 + pref + n,
1.686 + "set" + n,
1.687 + pref + nu + "__" + bck2brwsrType,
1.688 + "set" + nu + "__V" + bck2brwsrType
1.689 + };
1.690 + }
1.691 +
1.692 + private String typeName(Element where, Prprt p) {
1.693 + String ret;
1.694 + boolean[] isModel = { false };
1.695 + boolean[] isEnum = { false };
1.696 + boolean isPrimitive[] = { false };
1.697 + ret = checkType(p, isModel, isEnum, isPrimitive);
1.698 + if (p.array()) {
1.699 + String bt = findBoxedType(ret);
1.700 + if (bt != null) {
1.701 + return bt;
1.702 + }
1.703 + }
1.704 + return ret;
1.705 + }
1.706 +
1.707 + private static String findBoxedType(String ret) {
1.708 + if (ret.equals("boolean")) {
1.709 + return Boolean.class.getName();
1.710 + }
1.711 + if (ret.equals("byte")) {
1.712 + return Byte.class.getName();
1.713 + }
1.714 + if (ret.equals("short")) {
1.715 + return Short.class.getName();
1.716 + }
1.717 + if (ret.equals("char")) {
1.718 + return Character.class.getName();
1.719 + }
1.720 + if (ret.equals("int")) {
1.721 + return Integer.class.getName();
1.722 + }
1.723 + if (ret.equals("long")) {
1.724 + return Long.class.getName();
1.725 + }
1.726 + if (ret.equals("float")) {
1.727 + return Float.class.getName();
1.728 + }
1.729 + if (ret.equals("double")) {
1.730 + return Double.class.getName();
1.731 + }
1.732 + return null;
1.733 + }
1.734 +
1.735 + private boolean verifyPropName(Element e, String propName, Prprt[] existingProps) {
1.736 + StringBuilder sb = new StringBuilder();
1.737 + String sep = "";
1.738 + for (Prprt Prprt : existingProps) {
1.739 + if (Prprt.name().equals(propName)) {
1.740 + return true;
1.741 + }
1.742 + sb.append(sep);
1.743 + sb.append('"');
1.744 + sb.append(Prprt.name());
1.745 + sb.append('"');
1.746 + sep = ", ";
1.747 + }
1.748 + error(
1.749 + propName + " is not one of known properties: " + sb
1.750 + , e
1.751 + );
1.752 + return false;
1.753 + }
1.754 +
1.755 + private static String findPkgName(Element e) {
1.756 + for (;;) {
1.757 + if (e.getKind() == ElementKind.PACKAGE) {
1.758 + return ((PackageElement)e).getQualifiedName().toString();
1.759 + }
1.760 + e = e.getEnclosingElement();
1.761 + }
1.762 + }
1.763 +
1.764 + private boolean generateFunctions(
1.765 + Element clazz, StringWriter body, String className,
1.766 + List<? extends Element> enclosedElements, List<String> functions
1.767 + ) {
1.768 + for (Element m : enclosedElements) {
1.769 + if (m.getKind() != ElementKind.METHOD) {
1.770 + continue;
1.771 + }
1.772 + ExecutableElement e = (ExecutableElement)m;
1.773 + Function onF = e.getAnnotation(Function.class);
1.774 + if (onF == null) {
1.775 + continue;
1.776 + }
1.777 + if (!e.getModifiers().contains(Modifier.STATIC)) {
1.778 + error("@OnFunction method needs to be static", e);
1.779 + return false;
1.780 + }
1.781 + if (e.getModifiers().contains(Modifier.PRIVATE)) {
1.782 + error("@OnFunction method cannot be private", e);
1.783 + return false;
1.784 + }
1.785 + if (e.getReturnType().getKind() != TypeKind.VOID) {
1.786 + error("@OnFunction method should return void", e);
1.787 + return false;
1.788 + }
1.789 + String n = e.getSimpleName().toString();
1.790 + body.append(" private void ").append(n).append("(Object data, Object ev) {\n");
1.791 + body.append(" ").append(((TypeElement)clazz).getQualifiedName()).append(".").append(n).append("(");
1.792 + body.append(wrapParams(e, null, className, "ev", "data"));
1.793 + body.append(");\n");
1.794 + body.append(" }\n");
1.795 +
1.796 + functions.add(n);
1.797 + functions.add(n + "__VLjava_lang_Object_2Ljava_lang_Object_2");
1.798 + }
1.799 + return true;
1.800 + }
1.801 +
1.802 + private boolean generateOnChange(Element clazz, Map<String,Collection<String>> propDeps,
1.803 + Prprt[] properties, String className,
1.804 + Map<String, Collection<String>> functionDeps
1.805 + ) {
1.806 + for (Element m : clazz.getEnclosedElements()) {
1.807 + if (m.getKind() != ElementKind.METHOD) {
1.808 + continue;
1.809 + }
1.810 + ExecutableElement e = (ExecutableElement) m;
1.811 + OnPropertyChange onPC = e.getAnnotation(OnPropertyChange.class);
1.812 + if (onPC == null) {
1.813 + continue;
1.814 + }
1.815 + for (String pn : onPC.value()) {
1.816 + if (findPrprt(properties, pn) == null && findDerivedFrom(propDeps, pn).isEmpty()) {
1.817 + error("No Prprt named '" + pn + "' in the model", clazz);
1.818 + return false;
1.819 + }
1.820 + }
1.821 + if (!e.getModifiers().contains(Modifier.STATIC)) {
1.822 + error("@OnPrprtChange method needs to be static", e);
1.823 + return false;
1.824 + }
1.825 + if (e.getModifiers().contains(Modifier.PRIVATE)) {
1.826 + error("@OnPrprtChange method cannot be private", e);
1.827 + return false;
1.828 + }
1.829 + if (e.getReturnType().getKind() != TypeKind.VOID) {
1.830 + error("@OnPrprtChange method should return void", e);
1.831 + return false;
1.832 + }
1.833 + String n = e.getSimpleName().toString();
1.834 +
1.835 +
1.836 + for (String pn : onPC.value()) {
1.837 + StringBuilder call = new StringBuilder();
1.838 + call.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("(");
1.839 + call.append(wrapPropName(e, className, "name", pn));
1.840 + call.append(");\n");
1.841 +
1.842 + Collection<String> change = functionDeps.get(pn);
1.843 + if (change == null) {
1.844 + change = new ArrayList<String>();
1.845 + functionDeps.put(pn, change);
1.846 + }
1.847 + change.add(call.toString());
1.848 + for (String dpn : findDerivedFrom(propDeps, pn)) {
1.849 + change = functionDeps.get(dpn);
1.850 + if (change == null) {
1.851 + change = new ArrayList<String>();
1.852 + functionDeps.put(dpn, change);
1.853 + }
1.854 + change.add(call.toString());
1.855 + }
1.856 + }
1.857 + }
1.858 + return true;
1.859 + }
1.860 +
1.861 + private boolean generateOperation(Element clazz,
1.862 + StringWriter body, String className,
1.863 + List<? extends Element> enclosedElements
1.864 + ) {
1.865 + for (Element m : enclosedElements) {
1.866 + if (m.getKind() != ElementKind.METHOD) {
1.867 + continue;
1.868 + }
1.869 + ExecutableElement e = (ExecutableElement)m;
1.870 + ModelOperation mO = e.getAnnotation(ModelOperation.class);
1.871 + if (mO == null) {
1.872 + continue;
1.873 + }
1.874 + if (!e.getModifiers().contains(Modifier.STATIC)) {
1.875 + error("@ModelOperation method needs to be static", e);
1.876 + return false;
1.877 + }
1.878 + if (e.getModifiers().contains(Modifier.PRIVATE)) {
1.879 + error("@ModelOperation method cannot be private", e);
1.880 + return false;
1.881 + }
1.882 + if (e.getReturnType().getKind() != TypeKind.VOID) {
1.883 + error("@ModelOperation method should return void", e);
1.884 + return false;
1.885 + }
1.886 + List<String> args = new ArrayList<String>();
1.887 + {
1.888 + body.append(" public void ").append(m.getSimpleName()).append("(");
1.889 + String sep = "";
1.890 + boolean checkFirst = true;
1.891 + for (VariableElement ve : e.getParameters()) {
1.892 + final TypeMirror type = ve.asType();
1.893 + CharSequence simpleName;
1.894 + if (type.getKind() == TypeKind.DECLARED) {
1.895 + simpleName = ((DeclaredType)type).asElement().getSimpleName();
1.896 + } else {
1.897 + simpleName = type.toString();
1.898 + }
1.899 + if (simpleName.toString().equals(className)) {
1.900 + checkFirst = false;
1.901 + } else {
1.902 + if (checkFirst) {
1.903 + error("First parameter of @ModelOperation method must be " + className, m);
1.904 + return false;
1.905 + }
1.906 + args.add(ve.getSimpleName().toString());
1.907 + body.append(sep).append("final ");
1.908 + body.append(ve.asType().toString()).append(" ");
1.909 + body.append(ve.toString());
1.910 + sep = ", ";
1.911 + }
1.912 + }
1.913 + body.append(") {\n");
1.914 + body.append(" org.netbeans.html.json.impl.JSON.runInBrowser(this.context, new Runnable() { public void run() {\n");
1.915 + body.append(" ").append(clazz.getSimpleName()).append(".").append(m.getSimpleName()).append("(");
1.916 + body.append(className).append(".this");
1.917 + for (String s : args) {
1.918 + body.append(", ").append(s);
1.919 + }
1.920 + body.append(");\n");
1.921 + body.append(" }});\n");
1.922 + body.append(" }\n");
1.923 + }
1.924 +
1.925 + }
1.926 + return true;
1.927 + }
1.928 +
1.929 +
1.930 + private boolean generateReceive(
1.931 + Element clazz, StringWriter body, String className,
1.932 + List<? extends Element> enclosedElements, List<String> functions
1.933 + ) {
1.934 + for (Element m : enclosedElements) {
1.935 + if (m.getKind() != ElementKind.METHOD) {
1.936 + continue;
1.937 + }
1.938 + ExecutableElement e = (ExecutableElement)m;
1.939 + OnReceive onR = e.getAnnotation(OnReceive.class);
1.940 + if (onR == null) {
1.941 + continue;
1.942 + }
1.943 + if (!e.getModifiers().contains(Modifier.STATIC)) {
1.944 + error("@OnReceive method needs to be static", e);
1.945 + return false;
1.946 + }
1.947 + if (e.getModifiers().contains(Modifier.PRIVATE)) {
1.948 + error("@OnReceive method cannot be private", e);
1.949 + return false;
1.950 + }
1.951 + if (e.getReturnType().getKind() != TypeKind.VOID) {
1.952 + error("@OnReceive method should return void", e);
1.953 + return false;
1.954 + }
1.955 + if (!onR.jsonp().isEmpty() && !"GET".equals(onR.method())) {
1.956 + error("JSONP works only with GET transport method", e);
1.957 + }
1.958 + String dataMirror = findDataSpecified(e, onR);
1.959 + if ("PUT".equals(onR.method()) && dataMirror == null) {
1.960 + error("PUT method needs to specify a data() class", e);
1.961 + return false;
1.962 + }
1.963 + if ("POST".equals(onR.method()) && dataMirror == null) {
1.964 + error("POST method needs to specify a data() class", e);
1.965 + return false;
1.966 + }
1.967 + String modelClass = null;
1.968 + boolean expectsList = false;
1.969 + List<String> args = new ArrayList<String>();
1.970 + {
1.971 + for (VariableElement ve : e.getParameters()) {
1.972 + TypeMirror modelType = null;
1.973 + final TypeMirror type = ve.asType();
1.974 + CharSequence simpleName;
1.975 + if (type.getKind() == TypeKind.DECLARED) {
1.976 + simpleName = ((DeclaredType)type).asElement().getSimpleName();
1.977 + } else {
1.978 + simpleName = type.toString();
1.979 + }
1.980 + if (simpleName.toString().equals(className)) {
1.981 + args.add(className + ".this");
1.982 + } else if (isModel(ve.asType())) {
1.983 + modelType = ve.asType();
1.984 + } else if (ve.asType().getKind() == TypeKind.ARRAY) {
1.985 + modelType = ((ArrayType)ve.asType()).getComponentType();
1.986 + expectsList = true;
1.987 + } else if (ve.asType().toString().equals("java.lang.String")) {
1.988 + modelType = ve.asType();
1.989 + }
1.990 + if (modelType != null) {
1.991 + if (modelClass != null) {
1.992 + error("There can be only one model class among arguments", e);
1.993 + } else {
1.994 + modelClass = modelType.toString();
1.995 + if (expectsList) {
1.996 + args.add("arr");
1.997 + } else {
1.998 + args.add("arr[0]");
1.999 + }
1.1000 + }
1.1001 + }
1.1002 + }
1.1003 + }
1.1004 + if (modelClass == null) {
1.1005 + error("The method needs to have one @Model class as parameter", e);
1.1006 + }
1.1007 + String n = e.getSimpleName().toString();
1.1008 + if ("WebSocket".equals(onR.method())) {
1.1009 + body.append(" /** Performs WebSocket communication. Call with <code>null</code> data parameter\n");
1.1010 + body.append(" * to open the connection (even if not required). Call with non-null data to\n");
1.1011 + body.append(" * send messages to server. Call again with <code>null</code> data to close the socket.\n");
1.1012 + body.append(" */\n");
1.1013 + }
1.1014 + body.append(" public void ").append(n).append("(");
1.1015 + StringBuilder urlBefore = new StringBuilder();
1.1016 + StringBuilder urlAfter = new StringBuilder();
1.1017 + String jsonpVarName = null;
1.1018 + {
1.1019 + String sep = "";
1.1020 + boolean skipJSONP = onR.jsonp().isEmpty();
1.1021 + for (String p : findParamNames(e, onR.url(), onR.jsonp(), urlBefore, urlAfter)) {
1.1022 + if (!skipJSONP && p.equals(onR.jsonp())) {
1.1023 + skipJSONP = true;
1.1024 + jsonpVarName = p;
1.1025 + continue;
1.1026 + }
1.1027 + body.append(sep);
1.1028 + body.append("String ").append(p);
1.1029 + sep = ", ";
1.1030 + }
1.1031 + if (!skipJSONP) {
1.1032 + error(
1.1033 + "Name of jsonp attribute ('" + onR.jsonp() +
1.1034 + "') is not used in url attribute '" + onR.url() + "'", e
1.1035 + );
1.1036 + }
1.1037 + if (dataMirror != null) {
1.1038 + body.append(sep).append(dataMirror.toString()).append(" data");
1.1039 + }
1.1040 + }
1.1041 + body.append(") {\n");
1.1042 + boolean webSocket = onR.method().equals("WebSocket");
1.1043 + if (webSocket) {
1.1044 + if (generateWSReceiveBody(body, onR, e, clazz, className, expectsList, modelClass, n, args, urlBefore, jsonpVarName, urlAfter, dataMirror)) {
1.1045 + return false;
1.1046 + }
1.1047 + body.append(" }\n");
1.1048 + body.append(" private org.netbeans.html.json.impl.JSON.WS ws_" + e.getSimpleName() + ";\n");
1.1049 + } else {
1.1050 + if (generateJSONReceiveBody(body, onR, e, clazz, className, expectsList, modelClass, n, args, urlBefore, jsonpVarName, urlAfter, dataMirror)) {
1.1051 + return false;
1.1052 + }
1.1053 + body.append(" }\n");
1.1054 + }
1.1055 + }
1.1056 + return true;
1.1057 + }
1.1058 +
1.1059 + private boolean generateJSONReceiveBody(StringWriter body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List<String> args, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror) {
1.1060 + body.append(
1.1061 + " class ProcessResult extends org.netbeans.html.json.impl.RcvrJSON {\n" +
1.1062 + " @Override\n" +
1.1063 + " public void onError(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" +
1.1064 + " Exception value = ev.getException();\n"
1.1065 + );
1.1066 + if (onR.onError().isEmpty()) {
1.1067 + body.append(
1.1068 + " value.printStackTrace();\n"
1.1069 + );
1.1070 + } else {
1.1071 + if (!findOnError(e, ((TypeElement)clazz), onR.onError(), className)) {
1.1072 + return true;
1.1073 + }
1.1074 + body.append(" ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("(");
1.1075 + body.append(className).append(".this, value);\n");
1.1076 + }
1.1077 + body.append(
1.1078 + " }\n" +
1.1079 + " @Override\n" +
1.1080 + " public void onMessage(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n"
1.1081 + );
1.1082 + if (expectsList) {
1.1083 + body.append(
1.1084 + " " + modelClass + "[] arr = new " + modelClass + "[ev.dataSize()];\n"
1.1085 + );
1.1086 + } else {
1.1087 + body.append(
1.1088 + " " + modelClass + "[] arr = { null };\n"
1.1089 + );
1.1090 + }
1.1091 + body.append(
1.1092 + " ev.dataRead(context, " + modelClass + ".class, arr);\n"
1.1093 + );
1.1094 + {
1.1095 + body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("(");
1.1096 + String sep = "";
1.1097 + for (String arg : args) {
1.1098 + body.append(sep);
1.1099 + body.append(arg);
1.1100 + sep = ", ";
1.1101 + }
1.1102 + body.append(");\n");
1.1103 + }
1.1104 + body.append(
1.1105 + " }\n" +
1.1106 + " }\n"
1.1107 + );
1.1108 + body.append(" ProcessResult pr = new ProcessResult();\n");
1.1109 + body.append(" org.netbeans.html.json.impl.JSON.loadJSON(context, pr,\n ");
1.1110 + body.append(urlBefore).append(", ");
1.1111 + if (jsonpVarName != null) {
1.1112 + body.append(urlAfter);
1.1113 + } else {
1.1114 + body.append("null");
1.1115 + }
1.1116 + if (!"GET".equals(onR.method()) || dataMirror != null) {
1.1117 + body.append(", \"").append(onR.method()).append('"');
1.1118 + if (dataMirror != null) {
1.1119 + body.append(", data");
1.1120 + } else {
1.1121 + body.append(", null");
1.1122 + }
1.1123 + } else {
1.1124 + body.append(", null, null");
1.1125 + }
1.1126 + body.append(");\n");
1.1127 + return false;
1.1128 + }
1.1129 +
1.1130 + private boolean generateWSReceiveBody(StringWriter body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List<String> args, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror) {
1.1131 + body.append(
1.1132 + " class ProcessResult extends org.netbeans.html.json.impl.RcvrJSON {\n" +
1.1133 + " @Override\n" +
1.1134 + " public void onOpen(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n"
1.1135 + );
1.1136 + body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("(");
1.1137 + {
1.1138 + String sep = "";
1.1139 + for (String arg : args) {
1.1140 + body.append(sep);
1.1141 + if (arg.startsWith("arr")) {
1.1142 + body.append("null");
1.1143 + } else {
1.1144 + body.append(arg);
1.1145 + }
1.1146 + sep = ", ";
1.1147 + }
1.1148 + }
1.1149 + body.append(");\n");
1.1150 + body.append(
1.1151 + " }\n" +
1.1152 + " @Override\n" +
1.1153 + " public void onError(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" +
1.1154 + " Exception value = ev.getException();\n"
1.1155 + );
1.1156 + if (onR.onError().isEmpty()) {
1.1157 + body.append(
1.1158 + " value.printStackTrace();\n"
1.1159 + );
1.1160 + } else {
1.1161 + if (!findOnError(e, ((TypeElement)clazz), onR.onError(), className)) {
1.1162 + return true;
1.1163 + }
1.1164 + body.append(" ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("(");
1.1165 + body.append(className).append(".this, value);\n");
1.1166 + }
1.1167 + body.append(
1.1168 + " }\n" +
1.1169 + " @Override\n" +
1.1170 + " public void onMessage(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n"
1.1171 + );
1.1172 + if (expectsList) {
1.1173 + body.append(
1.1174 + " " + modelClass + "[] arr = new " + modelClass + "[ev.dataSize()];\n"
1.1175 + );
1.1176 + } else {
1.1177 + body.append(
1.1178 + " " + modelClass + "[] arr = { null };\n"
1.1179 + );
1.1180 + }
1.1181 + body.append(
1.1182 + " ev.dataRead(context, " + modelClass + ".class, arr);\n"
1.1183 + );
1.1184 + {
1.1185 + body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("(");
1.1186 + String sep = "";
1.1187 + for (String arg : args) {
1.1188 + body.append(sep);
1.1189 + body.append(arg);
1.1190 + sep = ", ";
1.1191 + }
1.1192 + body.append(");\n");
1.1193 + }
1.1194 + body.append(
1.1195 + " }\n"
1.1196 + );
1.1197 + if (!onR.onError().isEmpty()) {
1.1198 + body.append(
1.1199 + " @Override\n"
1.1200 + + " public void onClose(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n"
1.1201 + );
1.1202 + body.append(" ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("(");
1.1203 + body.append(className).append(".this, null);\n");
1.1204 + body.append(
1.1205 + " }\n"
1.1206 + );
1.1207 + }
1.1208 + body.append(" }\n");
1.1209 + body.append(" if (this.ws_").append(e.getSimpleName()).append(" == null) {\n");
1.1210 + body.append(" ProcessResult pr = new ProcessResult();\n");
1.1211 + body.append(" this.ws_").append(e.getSimpleName());
1.1212 + body.append("= org.netbeans.html.json.impl.JSON.openWS(context, pr,\n ");
1.1213 + body.append(urlBefore).append(", data);\n");
1.1214 + body.append(" } else {\n");
1.1215 + body.append(" this.ws_").append(e.getSimpleName()).append(".send(context, ").append(urlBefore).append(", data);\n");
1.1216 + body.append(" }\n");
1.1217 + return false;
1.1218 + }
1.1219 +
1.1220 + private CharSequence wrapParams(
1.1221 + ExecutableElement ee, String id, String className, String evName, String dataName
1.1222 + ) {
1.1223 + TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
1.1224 + StringBuilder params = new StringBuilder();
1.1225 + boolean first = true;
1.1226 + for (VariableElement ve : ee.getParameters()) {
1.1227 + if (!first) {
1.1228 + params.append(", ");
1.1229 + }
1.1230 + first = false;
1.1231 + String toCall = null;
1.1232 + String toFinish = null;
1.1233 + if (ve.asType() == stringType) {
1.1234 + if (ve.getSimpleName().contentEquals("id")) {
1.1235 + params.append('"').append(id).append('"');
1.1236 + continue;
1.1237 + }
1.1238 + toCall = "org.netbeans.html.json.impl.JSON.toString(context, ";
1.1239 + }
1.1240 + if (ve.asType().getKind() == TypeKind.DOUBLE) {
1.1241 + toCall = "org.netbeans.html.json.impl.JSON.toNumber(context, ";
1.1242 + toFinish = ".doubleValue()";
1.1243 + }
1.1244 + if (ve.asType().getKind() == TypeKind.INT) {
1.1245 + toCall = "org.netbeans.html.json.impl.JSON.toNumber(context, ";
1.1246 + toFinish = ".intValue()";
1.1247 + }
1.1248 + if (dataName != null && ve.getSimpleName().contentEquals(dataName) && isModel(ve.asType())) {
1.1249 + toCall = "org.netbeans.html.json.impl.JSON.toModel(context, " + ve.asType() + ".class, ";
1.1250 + }
1.1251 +
1.1252 + if (toCall != null) {
1.1253 + params.append(toCall);
1.1254 + if (dataName != null && ve.getSimpleName().contentEquals(dataName)) {
1.1255 + params.append(dataName);
1.1256 + params.append(", null");
1.1257 + } else {
1.1258 + if (evName == null) {
1.1259 + final StringBuilder sb = new StringBuilder();
1.1260 + sb.append("Unexpected string parameter name.");
1.1261 + if (dataName != null) {
1.1262 + sb.append(" Try \"").append(dataName).append("\"");
1.1263 + }
1.1264 + error(sb.toString(), ee);
1.1265 + }
1.1266 + params.append(evName);
1.1267 + params.append(", \"");
1.1268 + params.append(ve.getSimpleName().toString());
1.1269 + params.append("\"");
1.1270 + }
1.1271 + params.append(")");
1.1272 + if (toFinish != null) {
1.1273 + params.append(toFinish);
1.1274 + }
1.1275 + continue;
1.1276 + }
1.1277 + String rn = fqn(ve.asType(), ee);
1.1278 + int last = rn.lastIndexOf('.');
1.1279 + if (last >= 0) {
1.1280 + rn = rn.substring(last + 1);
1.1281 + }
1.1282 + if (rn.equals(className)) {
1.1283 + params.append(className).append(".this");
1.1284 + continue;
1.1285 + }
1.1286 + error(
1.1287 + "The annotated method can only accept " + className + " argument or argument named 'data'",
1.1288 + ee
1.1289 + );
1.1290 + }
1.1291 + return params;
1.1292 + }
1.1293 +
1.1294 +
1.1295 + private CharSequence wrapPropName(
1.1296 + ExecutableElement ee, String className, String propName, String propValue
1.1297 + ) {
1.1298 + TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
1.1299 + StringBuilder params = new StringBuilder();
1.1300 + boolean first = true;
1.1301 + for (VariableElement ve : ee.getParameters()) {
1.1302 + if (!first) {
1.1303 + params.append(", ");
1.1304 + }
1.1305 + first = false;
1.1306 + if (ve.asType() == stringType) {
1.1307 + if (propName != null && ve.getSimpleName().contentEquals(propName)) {
1.1308 + params.append('"').append(propValue).append('"');
1.1309 + } else {
1.1310 + error("Unexpected string parameter name. Try \"" + propName + "\".", ee);
1.1311 + }
1.1312 + continue;
1.1313 + }
1.1314 + String rn = fqn(ve.asType(), ee);
1.1315 + int last = rn.lastIndexOf('.');
1.1316 + if (last >= 0) {
1.1317 + rn = rn.substring(last + 1);
1.1318 + }
1.1319 + if (rn.equals(className)) {
1.1320 + params.append(className).append(".this");
1.1321 + continue;
1.1322 + }
1.1323 + error(
1.1324 + "@OnPrprtChange method can only accept String or " + className + " arguments",
1.1325 + ee);
1.1326 + }
1.1327 + return params;
1.1328 + }
1.1329 +
1.1330 + private boolean isModel(TypeMirror tm) {
1.1331 + if (tm.getKind() == TypeKind.ERROR) {
1.1332 + return true;
1.1333 + }
1.1334 + final Element e = processingEnv.getTypeUtils().asElement(tm);
1.1335 + if (e == null) {
1.1336 + return false;
1.1337 + }
1.1338 + for (Element ch : e.getEnclosedElements()) {
1.1339 + if (ch.getKind() == ElementKind.METHOD) {
1.1340 + ExecutableElement ee = (ExecutableElement)ch;
1.1341 + if (ee.getParameters().isEmpty() && ee.getSimpleName().contentEquals("modelFor")) {
1.1342 + return true;
1.1343 + }
1.1344 + }
1.1345 + }
1.1346 + return models.values().contains(e.getSimpleName().toString());
1.1347 + }
1.1348 +
1.1349 + private void writeToString(Prprt[] props, Writer w) throws IOException {
1.1350 + w.write(" public String toString() {\n");
1.1351 + w.write(" StringBuilder sb = new StringBuilder();\n");
1.1352 + w.write(" sb.append('{');\n");
1.1353 + String sep = "";
1.1354 + for (Prprt p : props) {
1.1355 + w.write(sep);
1.1356 + w.append(" sb.append('\"').append(\"" + p.name() + "\")");
1.1357 + w.append(".append('\"').append(\":\");\n");
1.1358 + w.append(" sb.append(org.netbeans.html.json.impl.JSON.toJSON(prop_");
1.1359 + w.append(p.name()).append("));\n");
1.1360 + sep = " sb.append(',');\n";
1.1361 + }
1.1362 + w.write(" sb.append('}');\n");
1.1363 + w.write(" return sb.toString();\n");
1.1364 + w.write(" }\n");
1.1365 + }
1.1366 + private void writeClone(String className, Prprt[] props, Writer w) throws IOException {
1.1367 + w.write(" public " + className + " clone() {\n");
1.1368 + w.write(" return clone(context);\n");
1.1369 + w.write(" }\n");
1.1370 + w.write(" private " + className + " clone(net.java.html.BrwsrCtx ctx) {\n");
1.1371 + w.write(" " + className + " ret = new " + className + "(ctx);\n");
1.1372 + for (Prprt p : props) {
1.1373 + if (!p.array()) {
1.1374 + boolean isModel[] = { false };
1.1375 + boolean isEnum[] = { false };
1.1376 + boolean isPrimitive[] = { false };
1.1377 + checkType(p, isModel, isEnum, isPrimitive);
1.1378 + if (!isModel[0]) {
1.1379 + w.write(" ret.prop_" + p.name() + " = prop_" + p.name() + ";\n");
1.1380 + continue;
1.1381 + }
1.1382 + w.write(" ret.prop_" + p.name() + " = prop_" + p.name() + " == null ? null : prop_" + p.name() + ".clone();\n");
1.1383 + } else {
1.1384 + w.write(" ret.prop_" + p.name() + ".cloneAll(ctx, prop_" + p.name() + ");\n");
1.1385 + }
1.1386 + }
1.1387 +
1.1388 + w.write(" return ret;\n");
1.1389 + w.write(" }\n");
1.1390 + }
1.1391 +
1.1392 + private String inPckName(Element e) {
1.1393 + StringBuilder sb = new StringBuilder();
1.1394 + while (e.getKind() != ElementKind.PACKAGE) {
1.1395 + if (sb.length() == 0) {
1.1396 + sb.append(e.getSimpleName());
1.1397 + } else {
1.1398 + sb.insert(0, '.');
1.1399 + sb.insert(0, e.getSimpleName());
1.1400 + }
1.1401 + e = e.getEnclosingElement();
1.1402 + }
1.1403 + return sb.toString();
1.1404 + }
1.1405 +
1.1406 + private String fqn(TypeMirror pt, Element relative) {
1.1407 + if (pt.getKind() == TypeKind.ERROR) {
1.1408 + final Elements eu = processingEnv.getElementUtils();
1.1409 + PackageElement pckg = eu.getPackageOf(relative);
1.1410 + return pckg.getQualifiedName() + "." + pt.toString();
1.1411 + }
1.1412 + return pt.toString();
1.1413 + }
1.1414 +
1.1415 + private String checkType(Prprt p, boolean[] isModel, boolean[] isEnum, boolean[] isPrimitive) {
1.1416 + TypeMirror tm;
1.1417 + try {
1.1418 + String ret = p.typeName(processingEnv);
1.1419 + TypeElement e = processingEnv.getElementUtils().getTypeElement(ret);
1.1420 + if (e == null) {
1.1421 + isModel[0] = true;
1.1422 + isEnum[0] = false;
1.1423 + isPrimitive[0] = false;
1.1424 + return ret;
1.1425 + }
1.1426 + tm = e.asType();
1.1427 + } catch (MirroredTypeException ex) {
1.1428 + tm = ex.getTypeMirror();
1.1429 + }
1.1430 + tm = processingEnv.getTypeUtils().erasure(tm);
1.1431 + if (isPrimitive[0] = tm.getKind().isPrimitive()) {
1.1432 + isEnum[0] = false;
1.1433 + isModel[0] = false;
1.1434 + return tm.toString();
1.1435 + }
1.1436 + final Element e = processingEnv.getTypeUtils().asElement(tm);
1.1437 + if (e.getKind() == ElementKind.CLASS && tm.getKind() == TypeKind.ERROR) {
1.1438 + isModel[0] = true;
1.1439 + isEnum[0] = false;
1.1440 + return e.getSimpleName().toString();
1.1441 + }
1.1442 +
1.1443 + final Model m = e == null ? null : e.getAnnotation(Model.class);
1.1444 + String ret;
1.1445 + if (m != null) {
1.1446 + ret = findPkgName(e) + '.' + m.className();
1.1447 + isModel[0] = true;
1.1448 + models.put(e, m.className());
1.1449 + } else if (findModelForMthd(e)) {
1.1450 + ret = ((TypeElement)e).getQualifiedName().toString();
1.1451 + isModel[0] = true;
1.1452 + } else {
1.1453 + ret = tm.toString();
1.1454 + }
1.1455 + TypeMirror enm = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType();
1.1456 + enm = processingEnv.getTypeUtils().erasure(enm);
1.1457 + isEnum[0] = processingEnv.getTypeUtils().isSubtype(tm, enm);
1.1458 + return ret;
1.1459 + }
1.1460 +
1.1461 + private static boolean findModelForMthd(Element clazz) {
1.1462 + if (clazz == null) {
1.1463 + return false;
1.1464 + }
1.1465 + for (Element e : clazz.getEnclosedElements()) {
1.1466 + if (e.getKind() == ElementKind.METHOD) {
1.1467 + ExecutableElement ee = (ExecutableElement)e;
1.1468 + if (
1.1469 + ee.getSimpleName().contentEquals("modelFor") &&
1.1470 + ee.getParameters().isEmpty()
1.1471 + ) {
1.1472 + return true;
1.1473 + }
1.1474 + }
1.1475 + }
1.1476 + return false;
1.1477 + }
1.1478 +
1.1479 + private Iterable<String> findParamNames(
1.1480 + Element e, String url, String jsonParam, StringBuilder... both
1.1481 + ) {
1.1482 + List<String> params = new ArrayList<String>();
1.1483 + int wasJSON = 0;
1.1484 +
1.1485 + for (int pos = 0; ;) {
1.1486 + int next = url.indexOf('{', pos);
1.1487 + if (next == -1) {
1.1488 + both[wasJSON].append('"')
1.1489 + .append(url.substring(pos))
1.1490 + .append('"');
1.1491 + return params;
1.1492 + }
1.1493 + int close = url.indexOf('}', next);
1.1494 + if (close == -1) {
1.1495 + error("Unbalanced '{' and '}' in " + url, e);
1.1496 + return params;
1.1497 + }
1.1498 + final String paramName = url.substring(next + 1, close);
1.1499 + params.add(paramName);
1.1500 + if (paramName.equals(jsonParam) && !jsonParam.isEmpty()) {
1.1501 + both[wasJSON].append('"')
1.1502 + .append(url.substring(pos, next))
1.1503 + .append('"');
1.1504 + wasJSON = 1;
1.1505 + } else {
1.1506 + both[wasJSON].append('"')
1.1507 + .append(url.substring(pos, next))
1.1508 + .append("\" + ").append(paramName).append(" + ");
1.1509 + }
1.1510 + pos = close + 1;
1.1511 + }
1.1512 + }
1.1513 +
1.1514 + private static Prprt findPrprt(Prprt[] properties, String propName) {
1.1515 + for (Prprt p : properties) {
1.1516 + if (propName.equals(p.name())) {
1.1517 + return p;
1.1518 + }
1.1519 + }
1.1520 + return null;
1.1521 + }
1.1522 +
1.1523 + private boolean isPrimitive(String type) {
1.1524 + return
1.1525 + "int".equals(type) ||
1.1526 + "double".equals(type) ||
1.1527 + "long".equals(type) ||
1.1528 + "short".equals(type) ||
1.1529 + "byte".equals(type) ||
1.1530 + "char".equals(type) ||
1.1531 + "boolean".equals(type) ||
1.1532 + "float".equals(type);
1.1533 + }
1.1534 +
1.1535 + private static Collection<String> findDerivedFrom(Map<String, Collection<String>> propsDeps, String derivedProp) {
1.1536 + Set<String> names = new HashSet<String>();
1.1537 + for (Map.Entry<String, Collection<String>> e : propsDeps.entrySet()) {
1.1538 + if (e.getValue().contains(derivedProp)) {
1.1539 + names.add(e.getKey());
1.1540 + }
1.1541 + }
1.1542 + return names;
1.1543 + }
1.1544 +
1.1545 + private Prprt[] createProps(Element e, Property[] arr) {
1.1546 + Prprt[] ret = Prprt.wrap(processingEnv, e, arr);
1.1547 + Prprt[] prev = verify.put(e, ret);
1.1548 + if (prev != null) {
1.1549 + error("Two sets of properties for ", e);
1.1550 + }
1.1551 + return ret;
1.1552 + }
1.1553 +
1.1554 + private static String strip(String s) {
1.1555 + int indx = s.indexOf("__");
1.1556 + if (indx >= 0) {
1.1557 + return s.substring(0, indx);
1.1558 + } else {
1.1559 + return s;
1.1560 + }
1.1561 + }
1.1562 +
1.1563 + private String findDataSpecified(ExecutableElement e, OnReceive onR) {
1.1564 + try {
1.1565 + return onR.data().getName();
1.1566 + } catch (MirroredTypeException ex) {
1.1567 + final TypeMirror tm = ex.getTypeMirror();
1.1568 + String name;
1.1569 + final Element te = processingEnv.getTypeUtils().asElement(tm);
1.1570 + if (te.getKind() == ElementKind.CLASS && tm.getKind() == TypeKind.ERROR) {
1.1571 + name = te.getSimpleName().toString();
1.1572 + } else {
1.1573 + name = tm.toString();
1.1574 + }
1.1575 + return "java.lang.Object".equals(name) ? null : name;
1.1576 + } catch (Exception ex) {
1.1577 + // fallback
1.1578 + }
1.1579 +
1.1580 + AnnotationMirror found = null;
1.1581 + for (AnnotationMirror am : e.getAnnotationMirrors()) {
1.1582 + if (am.getAnnotationType().toString().equals(OnReceive.class.getName())) {
1.1583 + found = am;
1.1584 + }
1.1585 + }
1.1586 + if (found == null) {
1.1587 + return null;
1.1588 + }
1.1589 +
1.1590 + for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : found.getElementValues().entrySet()) {
1.1591 + ExecutableElement ee = entry.getKey();
1.1592 + AnnotationValue av = entry.getValue();
1.1593 + if (ee.getSimpleName().contentEquals("data")) {
1.1594 + List<? extends Object> values = getAnnoValues(processingEnv, e, found);
1.1595 + for (Object v : values) {
1.1596 + String sv = v.toString();
1.1597 + if (sv.startsWith("data = ") && sv.endsWith(".class")) {
1.1598 + return sv.substring(7, sv.length() - 6);
1.1599 + }
1.1600 + }
1.1601 + return "error";
1.1602 + }
1.1603 + }
1.1604 + return null;
1.1605 + }
1.1606 +
1.1607 + static List<? extends Object> getAnnoValues(ProcessingEnvironment pe, Element e, AnnotationMirror am) {
1.1608 + try {
1.1609 + Class<?> trees = Class.forName("com.sun.tools.javac.api.JavacTrees");
1.1610 + Method m = trees.getMethod("instance", ProcessingEnvironment.class);
1.1611 + Object instance = m.invoke(null, pe);
1.1612 + m = instance.getClass().getMethod("getPath", Element.class, AnnotationMirror.class);
1.1613 + Object path = m.invoke(instance, e, am);
1.1614 + m = path.getClass().getMethod("getLeaf");
1.1615 + Object leaf = m.invoke(path);
1.1616 + m = leaf.getClass().getMethod("getArguments");
1.1617 + return (List) m.invoke(leaf);
1.1618 + } catch (Exception ex) {
1.1619 + return Collections.emptyList();
1.1620 + }
1.1621 + }
1.1622 +
1.1623 + private static class Prprt {
1.1624 + private final Element e;
1.1625 + private final AnnotationMirror tm;
1.1626 + private final Property p;
1.1627 +
1.1628 + public Prprt(Element e, AnnotationMirror tm, Property p) {
1.1629 + this.e = e;
1.1630 + this.tm = tm;
1.1631 + this.p = p;
1.1632 + }
1.1633 +
1.1634 + String name() {
1.1635 + return p.name();
1.1636 + }
1.1637 +
1.1638 + boolean array() {
1.1639 + return p.array();
1.1640 + }
1.1641 +
1.1642 + String typeName(ProcessingEnvironment env) {
1.1643 + RuntimeException ex;
1.1644 + try {
1.1645 + return p.type().getName();
1.1646 + } catch (IncompleteAnnotationException e) {
1.1647 + ex = e;
1.1648 + } catch (AnnotationTypeMismatchException e) {
1.1649 + ex = e;
1.1650 + }
1.1651 + for (Object v : getAnnoValues(env, e, tm)) {
1.1652 + String s = v.toString().replace(" ", "");
1.1653 + if (s.startsWith("type=") && s.endsWith(".class")) {
1.1654 + return s.substring(5, s.length() - 6);
1.1655 + }
1.1656 + }
1.1657 + throw ex;
1.1658 + }
1.1659 +
1.1660 +
1.1661 + static Prprt[] wrap(ProcessingEnvironment pe, Element e, Property[] arr) {
1.1662 + if (arr.length == 0) {
1.1663 + return new Prprt[0];
1.1664 + }
1.1665 +
1.1666 + if (e.getKind() != ElementKind.CLASS) {
1.1667 + throw new IllegalStateException("" + e.getKind());
1.1668 + }
1.1669 + TypeElement te = (TypeElement)e;
1.1670 + List<? extends AnnotationValue> val = null;
1.1671 + for (AnnotationMirror an : te.getAnnotationMirrors()) {
1.1672 + for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : an.getElementValues().entrySet()) {
1.1673 + if (entry.getKey().getSimpleName().contentEquals("properties")) {
1.1674 + val = (List)entry.getValue().getValue();
1.1675 + break;
1.1676 + }
1.1677 + }
1.1678 + }
1.1679 + if (val == null || val.size() != arr.length) {
1.1680 + pe.getMessager().printMessage(Diagnostic.Kind.ERROR, "" + val, e);
1.1681 + return new Prprt[0];
1.1682 + }
1.1683 + Prprt[] ret = new Prprt[arr.length];
1.1684 + BIG: for (int i = 0; i < ret.length; i++) {
1.1685 + AnnotationMirror am = (AnnotationMirror)val.get(i).getValue();
1.1686 + ret[i] = new Prprt(e, am, arr[i]);
1.1687 +
1.1688 + }
1.1689 + return ret;
1.1690 + }
1.1691 + }
1.1692 +
1.1693 + @Override
1.1694 + public Iterable<? extends Completion> getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) {
1.1695 + final Level l = Level.FINE;
1.1696 + LOG.log(l, " element: {0}", element);
1.1697 + LOG.log(l, " annotation: {0}", annotation);
1.1698 + LOG.log(l, " member: {0}", member);
1.1699 + LOG.log(l, " userText: {0}", userText);
1.1700 + LOG.log(l, "str: {0}", annotation.getAnnotationType().toString());
1.1701 + if (annotation.getAnnotationType().toString().equals(OnReceive.class.getName())) {
1.1702 + if (member.getSimpleName().contentEquals("method")) {
1.1703 + return Arrays.asList(
1.1704 + methodOf("GET"),
1.1705 + methodOf("POST"),
1.1706 + methodOf("PUT"),
1.1707 + methodOf("DELETE"),
1.1708 + methodOf("HEAD"),
1.1709 + methodOf("WebSocket")
1.1710 + );
1.1711 + }
1.1712 + }
1.1713 +
1.1714 + return super.getCompletions(element, annotation, member, userText);
1.1715 + }
1.1716 +
1.1717 + private static final Completion methodOf(String method) {
1.1718 + ResourceBundle rb = ResourceBundle.getBundle("org.netbeans.html.json.impl.Bundle");
1.1719 + return Completions.of('"' + method + '"', rb.getString("MSG_Completion_" + method));
1.1720 + }
1.1721 +
1.1722 + private boolean findOnError(ExecutableElement errElem, TypeElement te, String name, String className) {
1.1723 + String err = null;
1.1724 + METHODS:
1.1725 + for (Element e : te.getEnclosedElements()) {
1.1726 + if (e.getKind() != ElementKind.METHOD) {
1.1727 + continue;
1.1728 + }
1.1729 + if (!e.getSimpleName().contentEquals(name)) {
1.1730 + continue;
1.1731 + }
1.1732 + if (!e.getModifiers().contains(Modifier.STATIC)) {
1.1733 + errElem = (ExecutableElement) e;
1.1734 + err = "Would have to be static";
1.1735 + continue;
1.1736 + }
1.1737 + ExecutableElement ee = (ExecutableElement) e;
1.1738 + TypeMirror excType = processingEnv.getElementUtils().getTypeElement(Exception.class.getName()).asType();
1.1739 + final List<? extends VariableElement> params = ee.getParameters();
1.1740 + boolean error = false;
1.1741 + if (params.size() != 2) {
1.1742 + error = true;
1.1743 + } else {
1.1744 + String firstType = params.get(0).asType().toString();
1.1745 + int lastDot = firstType.lastIndexOf('.');
1.1746 + if (lastDot != -1) {
1.1747 + firstType = firstType.substring(lastDot + 1);
1.1748 + }
1.1749 + if (!firstType.equals(className)) {
1.1750 + error = true;
1.1751 + }
1.1752 + if (!processingEnv.getTypeUtils().isAssignable(excType, params.get(1).asType())) {
1.1753 + error = true;
1.1754 + }
1.1755 + }
1.1756 + if (error) {
1.1757 + errElem = (ExecutableElement) e;
1.1758 + err = "Error method first argument needs to be " + className + " and second Exception";
1.1759 + continue;
1.1760 + }
1.1761 + return true;
1.1762 + }
1.1763 + if (err == null) {
1.1764 + err = "Cannot find " + name + "(" + className + ", Exception) method in this class";
1.1765 + }
1.1766 + error(err, errElem);
1.1767 + return false;
1.1768 + }
1.1769 +
1.1770 +}