1.1 --- a/json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java Mon Dec 16 15:48:09 2013 +0100
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,1767 +0,0 @@
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.apidesign.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.apidesign.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.apidesign.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.apidesign.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.apidesign.html.json.impl.SetAndGet<" + className + ">,\n");
1.305 - w.append(" org.apidesign.html.json.impl.Callback<" + className + ">,\n");
1.306 - w.append(" org.apidesign.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.apidesign.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.apidesign.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.apidesign.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.apidesign.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.apidesign.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.apidesign.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.apidesign.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.apidesign.html.json.impl.JSON.charValue(");
1.414 - } else if ("boolean".equals(type)) {
1.415 - w.append("false : (org.apidesign.html.json.impl.JSON.boolValue(");
1.416 - } else {
1.417 - w.append("0 : (org.apidesign.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.apidesign.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.apidesign.html.json.impl.WrapperObject) {\n");
1.450 - w.write(" ((org.apidesign.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.apidesign.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.apidesign.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.apidesign.html.json.impl.JSONList<" + tn + "> prop_" + p.name() + " = new org.apidesign.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.apidesign.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.apidesign.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.apidesign.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.apidesign.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.apidesign.html.json.impl.RcvrJSON {\n" +
1.1062 - " @Override\n" +
1.1063 - " public void onError(org.apidesign.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.apidesign.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.apidesign.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.apidesign.html.json.impl.RcvrJSON {\n" +
1.1133 - " @Override\n" +
1.1134 - " public void onOpen(org.apidesign.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.apidesign.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.apidesign.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.apidesign.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.apidesign.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.apidesign.html.json.impl.JSON.toString(context, ";
1.1239 - }
1.1240 - if (ve.asType().getKind() == TypeKind.DOUBLE) {
1.1241 - toCall = "org.apidesign.html.json.impl.JSON.toNumber(context, ";
1.1242 - toFinish = ".doubleValue()";
1.1243 - }
1.1244 - if (ve.asType().getKind() == TypeKind.INT) {
1.1245 - toCall = "org.apidesign.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.apidesign.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.apidesign.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.apidesign.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 -}