Introducing @Component annotation, adding basic annotation and providing its (reflection based) implementation in ko4j module.
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/json/src/main/java/net/java/html/json/Component.java Tue Dec 15 23:19:35 2015 +0100
1.3 @@ -0,0 +1,77 @@
1.4 +/**
1.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
1.6 + *
1.7 + * Copyright 2013-2014 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-2014 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 net.java.html.json;
1.47 +
1.48 +import java.lang.annotation.ElementType;
1.49 +import java.lang.annotation.Retention;
1.50 +import java.lang.annotation.RetentionPolicy;
1.51 +import java.lang.annotation.Target;
1.52 +
1.53 +/** Defines a reusable piece of code and UI. Put the annotation on a
1.54 + * method that accepts a class generated by the {@link Model} annotation
1.55 + * and returns another class generated with the help of the
1.56 + * {@link Model} annotation. The first annotation describes the
1.57 + * input parameters. The latter one the internal structure of the
1.58 + * {@link #template() declarative UI snippet}.
1.59 + */
1.60 +@Target(ElementType.METHOD)
1.61 +@Retention(RetentionPolicy.SOURCE)
1.62 +public @interface Component {
1.63 + /**
1.64 + * Gives the component a name.
1.65 + * @return name that one uses from the UI to reference this component
1.66 + */
1.67 + public String name();
1.68 + /**
1.69 + * Location of associated file with UI. Usually (but not always) a fragment
1.70 + * of HTML that
1.71 + * @return
1.72 + */
1.73 + public String template();
1.74 + /**
1.75 + * Technologies that should be preferred when processing the
1.76 + * {@link #template} of this component.
1.77 + * @return ids of technologies to prefer inside of the component
1.78 + */
1.79 + public String[] techIds() default {};
1.80 +}
2.1 --- a/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java Mon Dec 14 06:10:54 2015 +0100
2.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java Tue Dec 15 23:19:35 2015 +0100
2.3 @@ -58,6 +58,7 @@
2.4 import java.util.LinkedHashSet;
2.5 import java.util.List;
2.6 import java.util.Map;
2.7 +import java.util.Properties;
2.8 import java.util.ResourceBundle;
2.9 import java.util.Set;
2.10 import java.util.WeakHashMap;
2.11 @@ -78,6 +79,7 @@
2.12 import javax.lang.model.element.ElementKind;
2.13 import javax.lang.model.element.ExecutableElement;
2.14 import javax.lang.model.element.Modifier;
2.15 +import javax.lang.model.element.Name;
2.16 import javax.lang.model.element.PackageElement;
2.17 import javax.lang.model.element.TypeElement;
2.18 import javax.lang.model.element.VariableElement;
2.19 @@ -90,6 +92,8 @@
2.20 import javax.lang.model.util.Types;
2.21 import javax.tools.Diagnostic;
2.22 import javax.tools.FileObject;
2.23 +import javax.tools.StandardLocation;
2.24 +import net.java.html.json.Component;
2.25 import net.java.html.json.ComputedProperty;
2.26 import net.java.html.json.Function;
2.27 import net.java.html.json.Model;
2.28 @@ -113,7 +117,8 @@
2.29 "net.java.html.json.OnReceive",
2.30 "net.java.html.json.OnPropertyChange",
2.31 "net.java.html.json.ComputedProperty",
2.32 - "net.java.html.json.Property"
2.33 + "net.java.html.json.Property",
2.34 + "net.java.html.json.Component"
2.35 })
2.36 public final class ModelProcessor extends AbstractProcessor {
2.37 private static final Logger LOG = Logger.getLogger(ModelProcessor.class.getName());
2.38 @@ -127,6 +132,11 @@
2.39 ok = false;
2.40 }
2.41 }
2.42 + for (Element e : roundEnv.getElementsAnnotatedWith(Component.class)) {
2.43 + if (!processComponent(e)) {
2.44 + ok = false;
2.45 + }
2.46 + }
2.47 if (roundEnv.processingOver()) {
2.48 models.clear();
2.49 for (Map.Entry<Element, Prprt[]> entry : verify.entrySet()) {
2.50 @@ -2191,4 +2201,44 @@
2.51 return null;
2.52 }
2.53
2.54 + private boolean processComponent(Element e) {
2.55 + try {
2.56 + Component c = e.getAnnotation(Component.class);
2.57 + if (c == null) {
2.58 + return false;
2.59 + }
2.60 + if (e.getKind() != ElementKind.METHOD) {
2.61 + error("@Component can only annotate a method", e);
2.62 + return false;
2.63 + }
2.64 + ExecutableElement ee = (ExecutableElement) e;
2.65 + if (ee.getParameters().size() != 1) {
2.66 + error("Method annotated by @Component needs to take one @Model generated parameter", e);
2.67 + return false;
2.68 + }
2.69 + FileObject def = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/html+java/components/" + c.name(), e);
2.70 + OutputStreamWriter w = new OutputStreamWriter(def.openOutputStream());
2.71 + Properties p = new Properties();
2.72 + final TypeMirror typeParam = ee.getParameters().get(0).asType();
2.73 + String fqnParam;
2.74 + if (typeParam.getKind() == TypeKind.ERROR) {
2.75 + fqnParam = findPkgName(ee) + "." + typeParam;
2.76 + } else {
2.77 + final TypeElement elem = (TypeElement) processingEnv.getTypeUtils().asElement(typeParam);
2.78 + fqnParam = processingEnv.getElementUtils().getBinaryName(elem).toString();
2.79 + }
2.80 + p.setProperty("paramName", fqnParam);
2.81 + p.setProperty("methodName", e.getSimpleName().toString());
2.82 + TypeElement clazz = (TypeElement)e.getEnclosingElement();
2.83 + final String fqn = clazz.getQualifiedName().toString();
2.84 + p.setProperty("className", fqn);
2.85 + p.setProperty("template", findPkgName(e).replace('.', '/') + '/' + c.template());
2.86 + p.store(w, "Generated by " + e);
2.87 + w.close();
2.88 + return true;
2.89 + } catch (IOException ex) {
2.90 + error(ex.getMessage(), e);
2.91 + return false;
2.92 + }
2.93 + }
2.94 }
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/json/src/test/java/net/java/html/json/ComponentTest.java Tue Dec 15 23:19:35 2015 +0100
3.3 @@ -0,0 +1,59 @@
3.4 +/**
3.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3.6 + *
3.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
3.8 + *
3.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
3.10 + * Other names may be trademarks of their respective owners.
3.11 + *
3.12 + * The contents of this file are subject to the terms of either the GNU
3.13 + * General Public License Version 2 only ("GPL") or the Common
3.14 + * Development and Distribution License("CDDL") (collectively, the
3.15 + * "License"). You may not use this file except in compliance with the
3.16 + * License. You can obtain a copy of the License at
3.17 + * http://www.netbeans.org/cddl-gplv2.html
3.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
3.19 + * specific language governing permissions and limitations under the
3.20 + * License. When distributing the software, include this License Header
3.21 + * Notice in each file and include the License file at
3.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
3.23 + * particular file as subject to the "Classpath" exception as provided
3.24 + * by Oracle in the GPL Version 2 section of the License file that
3.25 + * accompanied this code. If applicable, add the following below the
3.26 + * License Header, with the fields enclosed by brackets [] replaced by
3.27 + * your own identifying information:
3.28 + * "Portions Copyrighted [year] [name of copyright owner]"
3.29 + *
3.30 + * Contributor(s):
3.31 + *
3.32 + * The Original Software is NetBeans. The Initial Developer of the Original
3.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
3.34 + *
3.35 + * If you wish your version of this file to be governed by only the CDDL
3.36 + * or only the GPL Version 2, indicate your decision by adding
3.37 + * "[Contributor] elects to include this software in this distribution
3.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
3.39 + * single choice of license, a recipient has the option to distribute
3.40 + * your version of this file under either the CDDL, the GPL Version 2 or
3.41 + * to extend the choice of license to its licensees as provided above.
3.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
3.43 + * Version 2 license, then the option applies only if the new code is
3.44 + * made subject to such option by the copyright holder.
3.45 + */
3.46 +package net.java.html.json;
3.47 +
3.48 +public class ComponentTest {
3.49 + @Model(className = "CompParams", properties = {
3.50 + })
3.51 + static final class ParamsCntrl {
3.52 + }
3.53 + @Model(className = "CompModel", properties = {
3.54 + })
3.55 + static final class ModelCntrl {
3.56 + }
3.57 +
3.58 + @Component(name = "test-cmp", template = "next.html")
3.59 + static CompModel makeComponent(CompParams p) {
3.60 + return null;
3.61 + }
3.62 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/ComponentLoader.java Tue Dec 15 23:19:35 2015 +0100
4.3 @@ -0,0 +1,155 @@
4.4 +/**
4.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4.6 + *
4.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
4.8 + *
4.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
4.10 + * Other names may be trademarks of their respective owners.
4.11 + *
4.12 + * The contents of this file are subject to the terms of either the GNU
4.13 + * General Public License Version 2 only ("GPL") or the Common
4.14 + * Development and Distribution License("CDDL") (collectively, the
4.15 + * "License"). You may not use this file except in compliance with the
4.16 + * License. You can obtain a copy of the License at
4.17 + * http://www.netbeans.org/cddl-gplv2.html
4.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
4.19 + * specific language governing permissions and limitations under the
4.20 + * License. When distributing the software, include this License Header
4.21 + * Notice in each file and include the License file at
4.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
4.23 + * particular file as subject to the "Classpath" exception as provided
4.24 + * by Oracle in the GPL Version 2 section of the License file that
4.25 + * accompanied this code. If applicable, add the following below the
4.26 + * License Header, with the fields enclosed by brackets [] replaced by
4.27 + * your own identifying information:
4.28 + * "Portions Copyrighted [year] [name of copyright owner]"
4.29 + *
4.30 + * Contributor(s):
4.31 + *
4.32 + * The Original Software is NetBeans. The Initial Developer of the Original
4.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
4.34 + *
4.35 + * If you wish your version of this file to be governed by only the CDDL
4.36 + * or only the GPL Version 2, indicate your decision by adding
4.37 + * "[Contributor] elects to include this software in this distribution
4.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
4.39 + * single choice of license, a recipient has the option to distribute
4.40 + * your version of this file under either the CDDL, the GPL Version 2 or
4.41 + * to extend the choice of license to its licensees as provided above.
4.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
4.43 + * Version 2 license, then the option applies only if the new code is
4.44 + * made subject to such option by the copyright holder.
4.45 + */
4.46 +package org.netbeans.html.ko4j;
4.47 +
4.48 +import java.io.ByteArrayOutputStream;
4.49 +import java.io.IOException;
4.50 +import java.io.InputStream;
4.51 +import java.lang.reflect.Method;
4.52 +import java.net.URL;
4.53 +import java.util.Enumeration;
4.54 +import java.util.Properties;
4.55 +import net.java.html.BrwsrCtx;
4.56 +import net.java.html.js.JavaScriptBody;
4.57 +import net.java.html.json.Models;
4.58 +
4.59 +final class ComponentLoader {
4.60 + @JavaScriptBody(args = {}, wait4js = false, javacall = true, body =
4.61 + "var myLoader = {\n" +
4.62 + "};\n" +
4.63 + "myLoader.getConfig = function(name, callback) { \n" +
4.64 + " function myClbk(config) {\n" +
4.65 + " console.log('myClbk: ' + config.ko4j + ' ' + config.properties);\n" +
4.66 + " callback(config);\n" +
4.67 + " }\n" +
4.68 + " @org.netbeans.html.ko4j.ComponentLoader::loadConfig(Ljava/lang/String;Ljava/lang/Object;)(name, myClbk);\n" +
4.69 + "}\n" +
4.70 + "myLoader.loadComponent = function(name, componentConfig, callback) {\n" +
4.71 + " console.log('loadComponent: ' + componentConfig.ko4j + ' ' + componentConfig.properties);\n" +
4.72 + " callback(null);\n" +
4.73 + "}\n" +
4.74 + "myLoader.loadTemplate = function(name, templateConfig, callback) {\n" +
4.75 + " console.log('loadTemplate: ' + templateConfig.ko4j + ' ' + templateConfig.properties);\n" +
4.76 + " if (templateConfig !== null) {\n" +
4.77 + " @org.netbeans.html.ko4j.ComponentLoader::loadTemplate(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)(name, templateConfig, callback);\n" +
4.78 + " } else {\n" +
4.79 + " callback(null);\n" +
4.80 + " }\n" +
4.81 + "}\n" +
4.82 + "myLoader.loadViewModel = function(name, config, callback) { \n" +
4.83 + " console.log('loadViewModel ' + name + ' temp: ' + config);\n" +
4.84 + " var f = function(params, info) {\n" +
4.85 + " if (!params) params = null;\n" +
4.86 + " return @org.netbeans.html.ko4j.ComponentLoader::loadViewModel(Ljava/lang/String;Ljava/util/Properties;Ljava/lang/Object;Ljava/lang/Object;)(name, config, params, info);\n" +
4.87 + " };\n" +
4.88 + " callback(f);\n" +
4.89 + "}\n" +
4.90 + "ko.components.loaders.unshift(myLoader);\n"
4.91 + )
4.92 + public static native void initialize();
4.93 +
4.94 + static void loadConfig(String name, Object callback) throws IOException {
4.95 + System.err.println("config for " + name);
4.96 + Enumeration<URL> en = ComponentLoader.class.getClassLoader().getResources("META-INF/html+java/components/" + name);
4.97 + while (en.hasMoreElements()) {
4.98 + URL u = en.nextElement();
4.99 + InputStream is = u.openStream();
4.100 + Properties p = new Properties();
4.101 + p.load(is);
4.102 + is.close();
4.103 + callbackConfig(callback, p, p.getProperty("template"));
4.104 + return;
4.105 + }
4.106 + callbackConfig(callback, null, null);
4.107 + }
4.108 + static void loadTemplate(String name, String template, Object callback) throws IOException {
4.109 + InputStream is = ComponentLoader.class.getClassLoader().getResourceAsStream(template);
4.110 + ByteArrayOutputStream os = new ByteArrayOutputStream();
4.111 + for (;;) {
4.112 + int ch = is.read();
4.113 + if (ch == -1) {
4.114 + break;
4.115 + }
4.116 + os.write(ch);
4.117 + }
4.118 + is.close();
4.119 + String text = os.toString("UTF-8");
4.120 + callbackTemplate(callback, text);
4.121 + }
4.122 +
4.123 + @JavaScriptBody(args = { "callback", "param", "template" }, body =
4.124 + "callback(param ? {\n"
4.125 + + " 'ko4j': true,\n"
4.126 + + " 'viewModel': param,\n"
4.127 + + " 'template': template\n"
4.128 + + " } : null);", wait4js = false)
4.129 + private static native void callbackConfig(Object callback, Properties param, String template);
4.130 +
4.131 + @JavaScriptBody(args = { "callback", "param" }, body = "callback(ko.utils.parseHtmlFragment(param));", wait4js = false)
4.132 + private static native void callbackTemplate(Object callback, String param);
4.133 +
4.134 + static Object loadViewModel(String name, Properties props, Object params, Object config) throws IOException {
4.135 + Object res = null;
4.136 + try {
4.137 + String paramName = props.getProperty("paramName");
4.138 + Class<?> paramType = Class.forName(paramName);
4.139 + String className = props.getProperty("className");
4.140 + Class<?> classType = Class.forName(className);
4.141 + Method m = classType.getMethod(props.getProperty("methodName"), paramType);
4.142 +
4.143 + BrwsrCtx ctx = BrwsrCtx.findDefault(ComponentLoader.class);
4.144 + Object data;
4.145 + if (params == null) {
4.146 + data = paramType.newInstance();
4.147 + } else {
4.148 + data = Models.fromRaw(ctx, paramType, params);
4.149 + }
4.150 + m.setAccessible(true);
4.151 + res = m.invoke(null, data);
4.152 + props.put(res, res);
4.153 + } catch (Exception ex) {
4.154 + throw new IOException(ex);
4.155 + }
4.156 + return Models.toRaw(res);
4.157 + }
4.158 +}
5.1 --- a/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java Mon Dec 14 06:10:54 2015 +0100
5.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java Tue Dec 15 23:19:35 2015 +0100
5.3 @@ -148,6 +148,10 @@
5.4 Object model, String prop, Object oldValue, Object newValue
5.5 );
5.6
5.7 + static Object applyBindings(String id, Object bindings) {
5.8 + ComponentLoader.initialize();
5.9 + return applyBindings0(id, bindings);
5.10 + }
5.11 @JavaScriptBody(args = { "id", "bindings" }, body =
5.12 "var d = window['document'];\n" +
5.13 "var e = id ? d['getElementById'](id) : d['body'];\n" +
5.14 @@ -155,7 +159,7 @@
5.15 "ko['applyBindings'](bindings, e);\n" +
5.16 "return bindings['ko4j'];\n"
5.17 )
5.18 - native static Object applyBindings(String id, Object bindings);
5.19 + private native static Object applyBindings0(String id, Object bindings);
5.20
5.21 @JavaScriptBody(args = { "cnt" }, body =
5.22 "var arr = new Array(cnt);\n" +