You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by aa...@apache.org on 2017/07/28 00:11:06 UTC
[5/8] hadoop git commit: HADOOP-11875. [JDK9] Adding a second copy of
Hamlet without _ as a one-character identifier.
http://git-wip-us.apache.org/repos/asf/hadoop/blob/38c6fa5c/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/hamlet2/HamletGen.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/hamlet2/HamletGen.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/hamlet2/HamletGen.java
new file mode 100644
index 0000000..c6ca93c
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/hamlet2/HamletGen.java
@@ -0,0 +1,449 @@
+/**
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package org.apache.hadoop.yarn.webapp.hamlet2;
+
+import com.google.common.collect.Sets;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.util.StringUtils;
+import org.apache.hadoop.yarn.webapp.WebAppException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Generates a specific hamlet implementation class from a spec class
+ * using a generic hamlet implementation class.
+ */
+@InterfaceAudience.LimitedPrivate({"YARN", "MapReduce"})
+public class HamletGen {
+ static final Logger LOG = LoggerFactory.getLogger(HamletGen.class);
+ static final Options opts = new Options();
+ static {
+ opts.addOption("h", "help", false, "Print this help message").
+ addOption("s", "spec-class", true,
+ "The class that holds the spec interfaces. e.g. HamletSpec").
+ addOption("i", "impl-class", true,
+ "An implementation class. e.g. HamletImpl").
+ addOption("o", "output-class", true, "Output class name").
+ addOption("p", "output-package", true, "Output package name");
+ };
+
+ static final Pattern elementRegex = Pattern.compile("^[A-Z][A-Z0-9]*$");
+
+ int bytes = 0;
+ PrintWriter out;
+ final Set<String> endTagOptional = Sets.newHashSet();
+ final Set<String> inlineElements = Sets.newHashSet();
+ Class<?> top; // html top-level interface
+ String hamlet; // output class simple name;
+ boolean topMode;
+
+ /**
+ * Generate a specific Hamlet implementation from a spec.
+ * @param specClass holds hamlet interfaces. e.g. {@link HamletSpec}
+ * @param implClass a generic hamlet implementation. e.g. {@link HamletImpl}
+ * @param outputName name of the output class. e.g. {@link Hamlet}
+ * @param outputPkg package name of the output class.
+ * @throws IOException
+ */
+ public void generate(Class<?> specClass, Class<?> implClass,
+ String outputName, String outputPkg) throws IOException {
+ LOG.info("Generating {} using {} and {}", new Object[]{outputName,
+ specClass, implClass});
+ out = new PrintWriter(outputName +".java", "UTF-8");
+ hamlet = basename(outputName);
+ String pkg = pkgName(outputPkg, implClass.getPackage().getName());
+ puts(0, "// Generated by HamletGen. Do NOT edit!\n",
+ "package ", pkg, ";\n",
+ "import java.io.PrintWriter;\n",
+ "import java.util.EnumSet;\n",
+ "import static java.util.EnumSet.*;\n",
+ "import static ", implClass.getName(), ".EOpt.*;\n",
+ "import org.apache.hadoop.yarn.webapp.SubView;");
+ String implClassName = implClass.getSimpleName();
+ if (!implClass.getPackage().getName().equals(pkg)) {
+ puts(0, "import ", implClass.getName(), ';');
+ }
+ puts(0, "\n",
+ "public class ", hamlet, " extends ", implClassName,
+ " implements ", specClass.getSimpleName(), "._Html {\n",
+ " public ", hamlet, "(PrintWriter out, int nestLevel,",
+ " boolean wasInline) {\n",
+ " super(out, nestLevel, wasInline);\n",
+ " }\n\n", // inline is context sensitive
+ " static EnumSet<EOpt> opt(boolean endTag, boolean inline, ",
+ "boolean pre) {\n",
+ " EnumSet<EOpt> opts = of(ENDTAG);\n",
+ " if (!endTag) opts.remove(ENDTAG);\n",
+ " if (inline) opts.add(INLINE);\n",
+ " if (pre) opts.add(PRE);\n",
+ " return opts;\n",
+ " }");
+ initLut(specClass);
+ genImpl(specClass, implClassName, 1);
+ LOG.info("Generating {} methods", hamlet);
+ genMethods(hamlet, top, 1);
+ puts(0, "}");
+ out.close();
+ LOG.info("Wrote {} bytes to {}.java", bytes, outputName);
+ }
+
+ String basename(String path) {
+ return path.substring(path.lastIndexOf('/') + 1);
+ }
+
+ String pkgName(String pkg, String defaultPkg) {
+ if (pkg == null || pkg.isEmpty()) return defaultPkg;
+ return pkg;
+ }
+
+ void initLut(Class<?> spec) {
+ endTagOptional.clear();
+ inlineElements.clear();
+ for (Class<?> cls : spec.getClasses()) {
+ Annotation a = cls.getAnnotation(HamletSpec.Element.class);
+ if (a != null && !((HamletSpec.Element) a).endTag()) {
+ endTagOptional.add(cls.getSimpleName());
+ }
+ if (cls.getSimpleName().equals("Inline")) {
+ for (Method method : cls.getMethods()) {
+ String retName = method.getReturnType().getSimpleName();
+ if (isElement(retName)) {
+ inlineElements.add(retName);
+ }
+ }
+ }
+ }
+ }
+
+ void genImpl(Class<?> spec, String implClassName, int indent) {
+ String specName = spec.getSimpleName();
+ for (Class<?> cls : spec.getClasses()) {
+ String className = cls.getSimpleName();
+ if (cls.isInterface()) {
+ genFactoryMethods(cls, indent);
+ }
+ if (isElement(className)) {
+ LOG.info("Generating class {}<T>", className);
+ puts(indent, "\n",
+ "public class ", className, "<T extends __>",
+ " extends EImp<T> implements ", specName, ".", className, " {\n",
+ " public ", className, "(String name, T parent,",
+ " EnumSet<EOpt> opts) {\n",
+ " super(name, parent, opts);\n",
+ " }");
+ genMethods(className, cls, indent + 1);
+ puts(indent, "}");
+ } else if (className.equals("_Html")) {
+ top = cls;
+ }
+ }
+ }
+
+ void genFactoryMethods(Class<?> cls, int indent) {
+ for (Method method : cls.getDeclaredMethods()) {
+ String retName = method.getReturnType().getSimpleName();
+ String methodName = method.getName();
+ if (methodName.charAt(0) == '$') continue;
+ if (isElement(retName) && method.getParameterTypes().length == 0) {
+ genFactoryMethod(retName, methodName, indent);
+ }
+ }
+ }
+
+ void genMethods(String className, Class<?> cls, int indent) {
+ topMode = (top != null && cls.equals(top));
+ for (Method method : cls.getMethods()) {
+ String retName = method.getReturnType().getSimpleName();
+ if (method.getName().charAt(0) == '$') {
+ genAttributeMethod(className, method, indent);
+ } else if (isElement(retName)) {
+ genNewElementMethod(className, method, indent);
+ } else {
+ genCurElementMethod(className, method, indent);
+ }
+ }
+ }
+
+ void genAttributeMethod(String className, Method method, int indent) {
+ String methodName = method.getName();
+ String attrName = methodName.substring(1).replace("__", "-");
+ Type[] params = method.getGenericParameterTypes();
+ echo(indent, "\n",
+ "@Override\n",
+ "public ", className, topMode ? " " : "<T> ", methodName, "(");
+ if (params.length == 0) {
+ puts(0, ") {");
+ puts(indent,
+ " addAttr(\"", attrName, "\", null);\n",
+ " return this;\n", "}");
+ } else if (params.length == 1) {
+ String typeName = getTypeName(params[0]);
+ puts(0, typeName, " value) {");
+ if (typeName.equals("EnumSet<LinkType>")) {
+ puts(indent,
+ " addRelAttr(\"", attrName, "\", value);\n",
+ " return this;\n", "}");
+ } else if (typeName.equals("EnumSet<Media>")) {
+ puts(indent,
+ " addMediaAttr(\"", attrName, "\", value);\n",
+ " return this;\n", "}");
+ } else {
+ puts(indent,
+ " addAttr(\"", attrName, "\", value);\n",
+ " return this;\n", "}");
+ }
+ } else {
+ throwUnhandled(className, method);
+ }
+ }
+
+ String getTypeName(Type type) {
+ if (type instanceof Class<?>) {
+ return ((Class<?>)type).getSimpleName();
+ }
+ ParameterizedType pt = (ParameterizedType) type;
+ return ((Class<?>)pt.getRawType()).getSimpleName() +"<"+
+ ((Class<?>)pt.getActualTypeArguments()[0]).getSimpleName() +">";
+ }
+
+ void genFactoryMethod(String retName, String methodName, int indent) {
+ puts(indent, "\n",
+ "private <T extends __> ", retName, "<T> ", methodName,
+ "__(T e, boolean inline) {\n",
+ " return new ", retName, "<T>(\"", StringUtils.toLowerCase(retName),
+ "\", e, opt(", !endTagOptional.contains(retName), ", inline, ",
+ retName.equals("PRE"), ")); }");
+ }
+
+ void genNewElementMethod(String className, Method method, int indent) {
+ String methodName = method.getName();
+ String retName = method.getReturnType().getSimpleName();
+ Class<?>[] params = method.getParameterTypes();
+ echo(indent, "\n",
+ "@Override\n",
+ "public ", retName, "<", className, topMode ? "> " : "<T>> ",
+ methodName, "(");
+ if (params.length == 0) {
+ puts(0, ") {");
+ puts(indent,
+ topMode ? "" : " closeAttrs();\n",
+ " return ", StringUtils.toLowerCase(retName), "__" + "(this, ",
+ isInline(className, retName), ");\n", "}");
+ } else if (params.length == 1) {
+ puts(0, "String selector) {");
+ puts(indent,
+ " return setSelector(", methodName, "(), selector);\n", "}");
+ } else {
+ throwUnhandled(className, method);
+ }
+ }
+
+ boolean isInline(String container, String className) {
+ if ((container.equals("BODY") || container.equals(hamlet) ||
+ container.equals("HEAD") || container.equals("HTML")) &&
+ (className.equals("INS") || className.equals("DEL") ||
+ className.equals("SCRIPT"))) {
+ return false;
+ }
+ return inlineElements.contains(className);
+ }
+
+ void genCurElementMethod(String className, Method method, int indent) {
+ String methodName = method.getName();
+ Class<?>[] params = method.getParameterTypes();
+ if (topMode || params.length > 0) {
+ echo(indent, "\n",
+ "@Override\n",
+ "public ", className, topMode ? " " : "<T> ", methodName, "(");
+ }
+ if (params.length == 0) {
+ if (topMode) {
+ puts(0, ") {");
+ puts(indent, " return this;\n", "}");
+ }
+ } else if (params.length == 1) {
+ if (methodName.equals("base")) {
+ puts(0, "String href) {");
+ puts(indent,
+ " return base().$href(href).__();\n", "}");
+ } else if (methodName.equals("script")) {
+ puts(0, "String src) {");
+ puts(indent,
+ " return setScriptSrc(script(), src).__();\n", "}");
+ } else if (methodName.equals("style")) {
+ puts(0, "Object... lines) {");
+ puts(indent,
+ " return style().$type(\"text/css\").__(lines).__();\n", "}");
+ } else if (methodName.equals("img")) {
+ puts(0, "String src) {");
+ puts(indent,
+ " return ", methodName, "().$src(src).__();\n", "}");
+ } else if (methodName.equals("br") || methodName.equals("hr") ||
+ methodName.equals("col")) {
+ puts(0, "String selector) {");
+ puts(indent,
+ " return setSelector(", methodName, "(), selector).__();\n", "}");
+ } else if (methodName.equals("link")) {
+ puts(0, "String href) {");
+ puts(indent,
+ " return setLinkHref(", methodName, "(), href).__();\n", "}");
+ } else if (methodName.equals("__")) {
+ if (params[0].getSimpleName().equals("Class")) {
+ puts(0, "Class<? extends SubView> cls) {");
+ puts(indent,
+ " ", topMode ? "subView" : "_v", "(cls);\n",
+ " return this;\n", "}");
+ } else {
+ puts(0, "Object... lines) {");
+ puts(indent,
+ " _p(", needsEscaping(className), ", lines);\n",
+ " return this;\n", "}");
+ }
+ } else if (methodName.equals("_r")) {
+ puts(0, "Object... lines) {");
+ puts(indent,
+ " _p(false, lines);\n",
+ " return this;\n", "}");
+ } else {
+ puts(0, "String cdata) {");
+ puts(indent,
+ " return ", methodName, "().__(cdata).__();\n", "}");
+ }
+ } else if (params.length == 2) {
+ if (methodName.equals("meta")) {
+ puts(0, "String name, String content) {");
+ puts(indent,
+ " return meta().$name(name).$content(content).__();\n", "}");
+ } else if (methodName.equals("meta_http")) {
+ puts(0, "String header, String content) {");
+ puts(indent,
+ " return meta().$http_equiv(header).$content(content).__();\n",
+ "}");
+ } else if (methodName.equals("a")) {
+ puts(0, "String href, String anchorText) {");
+ puts(indent,
+ " return a().$href(href).__(anchorText).__();\n", "}");
+ } else if (methodName.equals("bdo")) {
+ puts(0, "Dir dir, String cdata) {");
+ puts(indent, " return bdo().$dir(dir).__(cdata).__();\n", "}");
+ } else if (methodName.equals("label")) {
+ puts(0, "String forId, String cdata) {");
+ puts(indent, " return label().$for(forId).__(cdata).__();\n", "}");
+ } else if (methodName.equals("param")) {
+ puts(0, "String name, String value) {");
+ puts(indent,
+ " return param().$name(name).$value(value).__();\n", "}");
+ } else {
+ puts(0, "String selector, String cdata) {");
+ puts(indent,
+ " return setSelector(", methodName,
+ "(), selector).__(cdata).__();\n", "}");
+ }
+ } else if (params.length == 3) {
+ if (methodName.equals("a")) {
+ puts(0, "String selector, String href, String anchorText) {");
+ puts(indent,
+ " return setSelector(a(), selector)",
+ ".$href(href).__(anchorText).__();\n", "}");
+ }
+ } else {
+ throwUnhandled(className, method);
+ }
+ }
+
+ static boolean needsEscaping(String eleName) {
+ return !eleName.equals("SCRIPT") && !eleName.equals("STYLE");
+ }
+
+ static void throwUnhandled(String className, Method method) {
+ throw new WebAppException("Unhandled " + className + "#" + method);
+ }
+
+ void echo(int indent, Object... args) {
+ String prev = null;
+ for (Object o : args) {
+ String s = String.valueOf(o);
+ if (!s.isEmpty() && !s.equals("\n") &&
+ (prev == null || prev.endsWith("\n"))) {
+ indent(indent);
+ }
+ prev = s;
+ out.print(s);
+ bytes += s.length();
+ }
+ }
+
+ void indent(int indent) {
+ for (int i = 0; i < indent; ++i) {
+ out.print(" ");
+ bytes += 2;
+ }
+ }
+
+ void puts(int indent, Object... args) {
+ echo(indent, args);
+ out.println();
+ ++bytes;
+ }
+
+ boolean isElement(String s) {
+ return elementRegex.matcher(s).matches();
+ }
+
+ public static void main(String[] args) throws Exception {
+ CommandLine cmd = new GnuParser().parse(opts, args);
+ if (cmd.hasOption("help")) {
+ new HelpFormatter().printHelp("Usage: hbgen [OPTIONS]", opts);
+ return;
+ }
+ // defaults
+ Class<?> specClass = HamletSpec.class;
+ Class<?> implClass = HamletImpl.class;
+ String outputClass = "HamletTmp";
+ String outputPackage = implClass.getPackage().getName();
+ if (cmd.hasOption("spec-class")) {
+ specClass = Class.forName(cmd.getOptionValue("spec-class"));
+ }
+ if (cmd.hasOption("impl-class")) {
+ implClass = Class.forName(cmd.getOptionValue("impl-class"));
+ }
+ if (cmd.hasOption("output-class")) {
+ outputClass = cmd.getOptionValue("output-class");
+ }
+ if (cmd.hasOption("output-package")) {
+ outputPackage = cmd.getOptionValue("output-package");
+ }
+ new HamletGen().generate(specClass, implClass, outputClass, outputPackage);
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/38c6fa5c/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/hamlet2/HamletImpl.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/hamlet2/HamletImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/hamlet2/HamletImpl.java
new file mode 100644
index 0000000..995e9fb
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/hamlet2/HamletImpl.java
@@ -0,0 +1,385 @@
+/**
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package org.apache.hadoop.yarn.webapp.hamlet2;
+
+import com.google.common.base.Joiner;
+import static com.google.common.base.Preconditions.*;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Iterables;
+
+import java.io.PrintWriter;
+import java.util.EnumSet;
+import static java.util.EnumSet.*;
+import java.util.Iterator;
+
+import static org.apache.commons.lang.StringEscapeUtils.*;
+import static org.apache.hadoop.yarn.webapp.hamlet2.HamletImpl.EOpt.*;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.yarn.webapp.SubView;
+import org.apache.hadoop.yarn.webapp.WebAppException;
+
+
+/**
+ * A simple unbuffered generic hamlet implementation.
+ *
+ * Zero copy but allocation on every element, which could be
+ * optimized to use a thread-local element pool.
+ *
+ * Prints HTML as it builds. So the order is important.
+ */
+@InterfaceAudience.Private
+public class HamletImpl extends HamletSpec {
+ private static final String INDENT_CHARS = " ";
+ private static final Splitter SS = Splitter.on('.').
+ omitEmptyStrings().trimResults();
+ private static final Joiner SJ = Joiner.on(' ');
+ private static final Joiner CJ = Joiner.on(", ");
+ static final int S_ID = 0;
+ static final int S_CLASS = 1;
+
+ int nestLevel;
+ int indents; // number of indent() called. mostly for testing.
+ private final PrintWriter out;
+ private final StringBuilder sb = new StringBuilder(); // not shared
+ private boolean wasInline = false;
+
+ /**
+ * Element options. (whether it needs end tag, is inline etc.)
+ */
+ public enum EOpt {
+ /** needs end(close) tag */
+ ENDTAG,
+ /** The content is inline */
+ INLINE,
+ /** The content is preformatted */
+ PRE
+ };
+
+ /**
+ * The base class for elements
+ * @param <T> type of the parent (containing) element for the element
+ */
+ public class EImp<T extends __> implements _Child {
+ private final String name;
+ private final T parent; // short cut for parent element
+ private final EnumSet<EOpt> opts; // element options
+
+ private boolean started = false;
+ private boolean attrsClosed = false;
+
+ EImp(String name, T parent, EnumSet<EOpt> opts) {
+ this.name = name;
+ this.parent = parent;
+ this.opts = opts;
+ }
+
+ @Override
+ public T __() {
+ closeAttrs();
+ --nestLevel;
+ printEndTag(name, opts);
+ return parent;
+ }
+
+ protected void _p(boolean quote, Object... args) {
+ closeAttrs();
+ for (Object s : args) {
+ if (!opts.contains(PRE)) {
+ indent(opts);
+ }
+ out.print(quote ? escapeHtml(String.valueOf(s))
+ : String.valueOf(s));
+ if (!opts.contains(INLINE) && !opts.contains(PRE)) {
+ out.println();
+ }
+ }
+ }
+
+ protected void _v(Class<? extends SubView> cls) {
+ closeAttrs();
+ subView(cls);
+ }
+
+ protected void closeAttrs() {
+ if (!attrsClosed) {
+ startIfNeeded();
+ ++nestLevel;
+ out.print('>');
+ if (!opts.contains(INLINE) && !opts.contains(PRE)) {
+ out.println();
+ }
+ attrsClosed = true;
+ }
+ }
+
+ protected void addAttr(String name, String value) {
+ checkState(!attrsClosed, "attribute added after content");
+ startIfNeeded();
+ printAttr(name, value);
+ }
+
+ protected void addAttr(String name, Object value) {
+ addAttr(name, String.valueOf(value));
+ }
+
+ protected void addMediaAttr(String name, EnumSet<Media> media) {
+ // 6.13 comma-separated list
+ addAttr(name, CJ.join(media));
+ }
+
+ protected void addRelAttr(String name, EnumSet<LinkType> types) {
+ // 6.12 space-separated list
+ addAttr(name, SJ.join(types));
+ }
+
+ private void startIfNeeded() {
+ if (!started) {
+ printStartTag(name, opts);
+ started = true;
+ }
+ }
+
+ protected void _inline(boolean choice) {
+ if (choice) {
+ opts.add(INLINE);
+ } else {
+ opts.remove(INLINE);
+ }
+ }
+
+ protected void _endTag(boolean choice) {
+ if (choice) {
+ opts.add(ENDTAG);
+ } else {
+ opts.remove(ENDTAG);
+ }
+ }
+
+ protected void _pre(boolean choice) {
+ if (choice) {
+ opts.add(PRE);
+ } else {
+ opts.remove(PRE);
+ }
+ }
+ }
+
+ public class Generic<T extends __> extends EImp<T> implements PCData {
+ Generic(String name, T parent, EnumSet<EOpt> opts) {
+ super(name, parent, opts);
+ }
+
+ public Generic<T> _inline() {
+ super._inline(true);
+ return this;
+ }
+
+ public Generic<T> _noEndTag() {
+ super._endTag(false);
+ return this;
+ }
+
+ public Generic<T> _pre() {
+ super._pre(true);
+ return this;
+ }
+
+ public Generic<T> _attr(String name, String value) {
+ addAttr(name, value);
+ return this;
+ }
+
+ public Generic<Generic<T>> _elem(String name, EnumSet<EOpt> opts) {
+ closeAttrs();
+ return new Generic<Generic<T>>(name, this, opts);
+ }
+
+ public Generic<Generic<T>> elem(String name) {
+ return _elem(name, of(ENDTAG));
+ }
+
+ @Override
+ public Generic<T> __(Object... lines) {
+ _p(true, lines);
+ return this;
+ }
+
+ @Override
+ public Generic<T> _r(Object... lines) {
+ _p(false, lines);
+ return this;
+ }
+ }
+
+ public HamletImpl(PrintWriter out, int nestLevel, boolean wasInline) {
+ this.out = out;
+ this.nestLevel = nestLevel;
+ this.wasInline = wasInline;
+ }
+
+ public int nestLevel() {
+ return nestLevel;
+ }
+
+ public boolean wasInline() {
+ return wasInline;
+ }
+
+ public void setWasInline(boolean state) {
+ wasInline = state;
+ }
+
+ public PrintWriter getWriter() {
+ return out;
+ }
+
+ /**
+ * Create a root-level generic element.
+ * Mostly for testing purpose.
+ * @param <T> type of the parent element
+ * @param name of the element
+ * @param opts {@link EOpt element options}
+ * @return the element
+ */
+ public <T extends __>
+ Generic<T> root(String name, EnumSet<EOpt> opts) {
+ return new Generic<T>(name, null, opts);
+ }
+
+ public <T extends __> Generic<T> root(String name) {
+ return root(name, of(ENDTAG));
+ }
+
+ protected void printStartTag(String name, EnumSet<EOpt> opts) {
+ indent(opts);
+ sb.setLength(0);
+ out.print(sb.append('<').append(name).toString()); // for easier mock test
+ }
+
+ protected void indent(EnumSet<EOpt> opts) {
+ if (opts.contains(INLINE) && wasInline) {
+ return;
+ }
+ if (wasInline) {
+ out.println();
+ }
+ wasInline = opts.contains(INLINE) || opts.contains(PRE);
+ for (int i = 0; i < nestLevel; ++i) {
+ out.print(INDENT_CHARS);
+ }
+ ++indents;
+ }
+
+ protected void printEndTag(String name, EnumSet<EOpt> opts) {
+ if (!opts.contains(ENDTAG)) {
+ return;
+ }
+ if (!opts.contains(PRE)) {
+ indent(opts);
+ } else {
+ wasInline = opts.contains(INLINE);
+ }
+ sb.setLength(0);
+ out.print(sb.append("</").append(name).append('>').toString()); // ditto
+ if (!opts.contains(INLINE)) {
+ out.println();
+ }
+ }
+
+ protected void printAttr(String name, String value) {
+ sb.setLength(0);
+ sb.append(' ').append(name);
+ if (value != null) {
+ sb.append("=\"").append(escapeHtml(value)).append("\"");
+ }
+ out.print(sb.toString());
+ }
+
+ /**
+ * Sub-classes should override this to do something interesting.
+ * @param cls the sub-view class
+ */
+ protected void subView(Class<? extends SubView> cls) {
+ indent(of(ENDTAG)); // not an inline view
+ sb.setLength(0);
+ out.print(sb.append('[').append(cls.getName()).append(']').toString());
+ out.println();
+ }
+
+ /**
+ * Parse selector into id and classes
+ * @param selector in the form of (#id)?(.class)*
+ * @return an two element array [id, "space-separated classes"].
+ * Either element could be null.
+ * @throws WebAppException when both are null or syntax error.
+ */
+ public static String[] parseSelector(String selector) {
+ String[] result = new String[]{null, null};
+ Iterable<String> rs = SS.split(selector);
+ Iterator<String> it = rs.iterator();
+ if (it.hasNext()) {
+ String maybeId = it.next();
+ if (maybeId.charAt(0) == '#') {
+ result[S_ID] = maybeId.substring(1);
+ if (it.hasNext()) {
+ result[S_CLASS] = SJ.join(Iterables.skip(rs, 1));
+ }
+ } else {
+ result[S_CLASS] = SJ.join(rs);
+ }
+ return result;
+ }
+ throw new WebAppException("Error parsing selector: "+ selector);
+ }
+
+ /**
+ * Set id and/or class attributes for an element.
+ * @param <E> type of the element
+ * @param e the element
+ * @param selector Haml form of "(#id)?(.class)*"
+ * @return the element
+ */
+ public static <E extends CoreAttrs> E setSelector(E e, String selector) {
+ String[] res = parseSelector(selector);
+ if (res[S_ID] != null) {
+ e.$id(res[S_ID]);
+ }
+ if (res[S_CLASS] != null) {
+ e.$class(res[S_CLASS]);
+ }
+ return e;
+ }
+
+ public static <E extends LINK> E setLinkHref(E e, String href) {
+ if (href.endsWith(".css")) {
+ e.$rel("stylesheet"); // required in html5
+ }
+ e.$href(href);
+ return e;
+ }
+
+ public static <E extends SCRIPT> E setScriptSrc(E e, String src) {
+ if (src.endsWith(".js")) {
+ e.$type("text/javascript"); // required in html4
+ }
+ e.$src(src);
+ return e;
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org