From bdcb7ab9396459aabc60e24312f1d9cae6b90cfc Mon Sep 17 00:00:00 2001 From: Maicon Mauricio <64911189+maiconandsilva@users.noreply.github.com> Date: Tue, 9 Aug 2022 13:00:07 -0300 Subject: [PATCH] Make grailsk-common a folder. Remove git submodule --- .gitmodules | 4 - grailszk-common | 1 - grailszk-common/README.md | 4 + grailszk-common/build.gradle | 16 ++ .../zk/GrailsComposerTransformer.java | 48 +++++ .../util/resource/GrailsContentLoader.java | 147 +++++++++++++++ .../web/util/resource/ResourceCaches.java | 169 ++++++++++++++++++ .../web/util/resource/ResourceUtils.java | 42 +++++ .../zkoss/web/util/resource/TagDehyphen.java | 22 +++ .../util/resource/UnicodeBOMInputStream.java | 153 ++++++++++++++++ .../zk/grails/api/AbstractComposersApi.java | 15 ++ .../zk/grails/ui/GrailsComposerFactory.java | 37 ++++ .../ui/SerializableGrailsComposerFactory.java | 35 ++++ .../java/org/zkoss/zk/grails/ui/Versions.java | 17 ++ 14 files changed, 705 insertions(+), 5 deletions(-) delete mode 100644 .gitmodules delete mode 160000 grailszk-common create mode 100644 grailszk-common/README.md create mode 100644 grailszk-common/build.gradle create mode 100644 grailszk-common/src/main/java/org/codehaus/groovy/grails/compiler/zk/GrailsComposerTransformer.java create mode 100644 grailszk-common/src/main/java/org/zkoss/web/util/resource/GrailsContentLoader.java create mode 100644 grailszk-common/src/main/java/org/zkoss/web/util/resource/ResourceCaches.java create mode 100644 grailszk-common/src/main/java/org/zkoss/web/util/resource/ResourceUtils.java create mode 100644 grailszk-common/src/main/java/org/zkoss/web/util/resource/TagDehyphen.java create mode 100644 grailszk-common/src/main/java/org/zkoss/web/util/resource/UnicodeBOMInputStream.java create mode 100644 grailszk-common/src/main/java/org/zkoss/zk/grails/api/AbstractComposersApi.java create mode 100644 grailszk-common/src/main/java/org/zkoss/zk/grails/ui/GrailsComposerFactory.java create mode 100644 grailszk-common/src/main/java/org/zkoss/zk/grails/ui/SerializableGrailsComposerFactory.java create mode 100644 grailszk-common/src/main/java/org/zkoss/zk/grails/ui/Versions.java diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index ee128be..0000000 --- a/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "grailszk-common"] - path = grailszk-common - url = https://github.com/groovyzk/grailszk-common.git - ignore = none diff --git a/grailszk-common b/grailszk-common deleted file mode 160000 index 0ddb6d6..0000000 --- a/grailszk-common +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0ddb6d627a8963792a41e88937ece9c7d1c6f5a7 diff --git a/grailszk-common/README.md b/grailszk-common/README.md new file mode 100644 index 0000000..543db1b --- /dev/null +++ b/grailszk-common/README.md @@ -0,0 +1,4 @@ +# zk-grails-extension + +An extension library for the [zk-grails](https://github.com/zk-groovy/zk-grails) plugin with hooks for accessing and +modifying ZK internals to adapt to the Grails environment. diff --git a/grailszk-common/build.gradle b/grailszk-common/build.gradle new file mode 100644 index 0000000..03dbc6f --- /dev/null +++ b/grailszk-common/build.gradle @@ -0,0 +1,16 @@ +dependencies { + implementation "org.grails:grails-dependencies:$grailsVersion" + implementation "org.grails:grails-core" + implementation "org.grails.plugins:gsp" + implementation "org.zkoss.zk:zk:$zkVersion" + implementation "org.zkoss.zk:zul:$zkVersion" + implementation "org.zkoss.zk:zhtml:$zkVersion" + implementation "org.zkoss.zk:zkplus:$zkVersion" + implementation "org.zkoss.zk:zkbind:$zkVersion" + implementation ("org.zkoss.common:zweb:$zkVersion") { + transitive = true + exclude module: "ResourceCaches" + } + implementation "org.zkoss.common:zel:$zkVersion" + implementation "org.zkoss.common:zcommon:$zkVersion" +} diff --git a/grailszk-common/src/main/java/org/codehaus/groovy/grails/compiler/zk/GrailsComposerTransformer.java b/grailszk-common/src/main/java/org/codehaus/groovy/grails/compiler/zk/GrailsComposerTransformer.java new file mode 100644 index 0000000..52eecc5 --- /dev/null +++ b/grailszk-common/src/main/java/org/codehaus/groovy/grails/compiler/zk/GrailsComposerTransformer.java @@ -0,0 +1,48 @@ +package org.codehaus.groovy.grails.compiler.zk; + +import org.grails.compiler.injection.AbstractGrailsArtefactTransformer; +import org.zkoss.zk.grails.api.AbstractComposersApi; +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.control.SourceUnit; +import java.net.URL; +import java.util.regex.Pattern; + +public class GrailsComposerTransformer extends AbstractGrailsArtefactTransformer { + public static Pattern COMPOSER_PATTERN = Pattern.compile(".+/grails-app/composers/(.+)Composer\\.groovy"); + + public boolean shouldInject(final URL url) { + return url != null && COMPOSER_PATTERN.matcher(url.getFile()).find(); + } + + public String getArtefactType() { + return "Composer"; + } + + protected void performInjectionInternal(final String apiInstanceProperty, final SourceUnit source, + final ClassNode classNode) { + final ClassNode superClass = classNode.getSuperClass(); + String superClassName = ""; + if (superClass == null) { // TODO: Verify this code. Seems wrong. Probably unused. + superClassName = superClass.getName(); + } + + if (!superClassName.equals("java.lang.Object") && !superClassName.equals("groovy.lang.GroovyObject")) { + return; + } + + try { + super.performInjectionInternal(apiInstanceProperty, source, classNode); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public Class getStaticImplementation() { + return null; + } + + public Class getInstanceImplementation() { + return AbstractComposersApi.class; + } +} diff --git a/grailszk-common/src/main/java/org/zkoss/web/util/resource/GrailsContentLoader.java b/grailszk-common/src/main/java/org/zkoss/web/util/resource/GrailsContentLoader.java new file mode 100644 index 0000000..2f6d977 --- /dev/null +++ b/grailszk-common/src/main/java/org/zkoss/web/util/resource/GrailsContentLoader.java @@ -0,0 +1,147 @@ +package org.zkoss.web.util.resource; + +import grails.core.GrailsApplication; +import groovy.lang.Writable; +import groovy.text.Template; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.grails.core.io.DefaultResourceLocator; +import org.grails.gsp.GroovyPagesTemplateEngine; +import org.springframework.context.ApplicationContext; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; +import org.zkoss.util.resource.Locator; +import org.zkoss.web.servlet.Servlets; +import org.zkoss.zk.ui.WebApp; +import org.zkoss.zk.ui.metainfo.PageDefinition; +import org.zkoss.zk.ui.metainfo.PageDefinitions; +import org.zkoss.zk.ui.metainfo.Parser; + +import java.io.*; +import java.net.URL; +import java.util.Map; + +@SuppressWarnings("deprecation") +public class GrailsContentLoader extends ResourceLoader { + private static final String GROOVY_PAGES_TEMPLATE_ENGINE = "groovyPagesTemplateEngine"; + private static final String UTF_8_ENCODING = "UTF-8"; + private static final String CONFIG_OPTION_GSP_ENCODING = "grails.views.gsp.encoding"; + private static final String CONFIG_ZKGRAILS_TAGLIB_DISABLE = "grails.zk.taglib.disabled"; + private static final Log log = LogFactory.getLog(GrailsContentLoader.class); + private final WebApp webApp; + private final ApplicationContext appCtx; + private final GrailsApplication grailsApplication; + private final ResourceUtils resourceUtils; + + public GrailsContentLoader(final WebApp webApp) { + this.webApp = webApp; + final WebApplicationContext ctx = + WebApplicationContextUtils.getRequiredWebApplicationContext(webApp.getServletContext()); + grailsApplication = ctx.getBean("grailsApplication", GrailsApplication.class); + appCtx = grailsApplication.getMainContext(); + appCtx.getBean("grailsResourceLocator", DefaultResourceLocator.class); + resourceUtils = new ResourceUtils(appCtx); + } + + @Override + public PageDefinition load(final ResourceInfo si) throws Exception { + final org.springframework.core.io.Resource springResource = resourceUtils.getResource(si.path); + + if (springResource.exists()) { + log.debug("Load from Spring Resource: " + springResource); + try { + return parse(si.path, springResource, si.extra); + } catch (Throwable e) { + log.debug("Cannot parse ZUL from a Spring Resource", e); + throw (Exception) e; + } + } + + if (si.url != null) { + log.debug("Load from URL: " + si.url); + return parse(si.path, si.url, si.extra); + } + + if (!si.file.exists()) { + log.debug("File " + si.file + " not found"); + return null; + } + + try { + log.debug("Load from File: " + si.file); + return parse(si.path, si.file, si.extra); + } catch (FileNotFoundException ex) { + return null; + } + } + + private StringReader preprocessGSP(final Map config, final long length, final InputStream in) + throws IOException { + log.debug("Enter :: preprocessGSP"); + final GroovyPagesTemplateEngine gsp = (GroovyPagesTemplateEngine) appCtx.getBean(GROOVY_PAGES_TEMPLATE_ENGINE); + log.debug("Got GSP Template bean: " + gsp); + byte[] buffer; + final UnicodeBOMInputStream ubomIn = new UnicodeBOMInputStream(in); + if (ubomIn.getBOM() != UnicodeBOMInputStream.BOM.NONE) { + log.debug("BOM detected"); + ubomIn.skipBOM(); + buffer = new byte[(int)length - ubomIn.getBOM().getBytes().length]; + } + else { + buffer = new byte[(int)length]; + } + final BufferedInputStream bis = new BufferedInputStream(ubomIn); + bis.read(buffer); + String encoding = (String) config.get(CONFIG_OPTION_GSP_ENCODING); + if (encoding == null) { + encoding = UTF_8_ENCODING; + } + String bufferStr = new String(buffer, encoding).replaceAll("@\\{", "\\$\\{'@'\\}\\{"); + bufferStr = TagDehyphen.dehyphen(bufferStr); + + final Template template = gsp.createTemplate(new ByteArrayResource(bufferStr.getBytes(encoding)), false); + final Writable w = template.make(); + final StringWriter sw = new StringWriter(); + w.writeTo(new PrintWriter(sw)); + final String zulSrc = sw.toString().replaceAll("\\#\\{", "\\$\\{"); + final StringReader reader = new StringReader(zulSrc); + log.debug("Returning pre-processed ::: " + reader); + return reader; + } + + private PageDefinition parse(final String path, final org.springframework.core.io.Resource resource, + final Object extra) throws Throwable { + final Map config = grailsApplication.getConfig().flatten(); + final Boolean disable = (Boolean)config.get(CONFIG_ZKGRAILS_TAGLIB_DISABLE); + final Locator locator = (Locator)((extra != null) ? extra : PageDefinitions.getLocator(webApp, path)); + if (disable != null && disable) { + return new Parser(webApp, locator).parse(new InputStreamReader(resource.getInputStream()), path); + } + final StringReader reader = preprocessGSP(config, resource.contentLength(), resource.getInputStream()); + final PageDefinition pgdef = new Parser(webApp, locator).parse(reader, Servlets.getExtension(path)); + pgdef.setRequestPath(path); + return pgdef; + } + + @Override + protected PageDefinition parse(final String path, final URL url, final Object extra) throws Exception { + final Locator locator = (Locator)((extra != null) ? extra : PageDefinitions.getLocator(webApp, path)); + return new Parser(webApp, locator).parse(url, path); + } + + @Override + protected PageDefinition parse(final String path, final File file, final Object extra) throws Exception { + final GrailsApplication grailsApplication = (GrailsApplication) appCtx.getBean("grailsApplication"); + final Map config = grailsApplication.getConfig().flatten(); + final Boolean disable = (Boolean) config.get(CONFIG_ZKGRAILS_TAGLIB_DISABLE); + final Locator locator = (Locator)((extra != null) ? extra : PageDefinitions.getLocator(webApp, path)); + if (disable != null && disable) { + return new Parser(webApp, locator).parse(file, path); + } + final StringReader reader = preprocessGSP(config, file.length(), new FileInputStream(file)); + final PageDefinition pgdef = new Parser(webApp, locator).parse(reader, Servlets.getExtension(path)); + pgdef.setRequestPath(path); + return pgdef; + } +} diff --git a/grailszk-common/src/main/java/org/zkoss/web/util/resource/ResourceCaches.java b/grailszk-common/src/main/java/org/zkoss/web/util/resource/ResourceCaches.java new file mode 100644 index 0000000..64afabe --- /dev/null +++ b/grailszk-common/src/main/java/org/zkoss/web/util/resource/ResourceCaches.java @@ -0,0 +1,169 @@ +/* ResourceCaches.java + + Purpose: + + Description: + + History: + Tue Aug 30 18:31:05 2005, Created by tomyeh + +Copyright (C) 2005 Potix Corporation. All Rights Reserved. + +{{IS_RIGHT + This program is distributed under LGPL Version 2.1 in the hope that + it will be useful, but WITHOUT ANY WARRANTY. +}}IS_RIGHT +*/ +package org.zkoss.web.util.resource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; +import org.zkoss.lang.SystemException; +import org.zkoss.web.servlet.Servlets; + +import javax.servlet.ServletContext; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +import static org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext; + +/** + * Utilities to load (and parse) the Servlet resource. + * Notice that {@link ResourceCache} and {@link ResourceLoader} + * must be used rather than + * {@link org.zkoss.util.resource.ResourceCache} + * and {@link org.zkoss.util.resource.Loader}. + * + *

Usage: + *

    + *
  1. Implements a loader by extending from {@link ResourceLoader}.
  2. + *
  3. Creates a resource cache ({@link ResourceCache}) + * by use of the loader in the previous step.
  4. + *
  5. Invoke {@link #get} to load the resource.
  6. + *
+ * + * @see + * ResourceCaches.java Original class + * + * + * @author tomyeh + */ +public class ResourceCaches { + private static final Logger log = LoggerFactory.getLogger(ResourceCaches.class); + + static { + log.info("Using custom org.zkoss.web.util.resource.ResourceCaches." + + " See https://github.com/zkgroovy/zk-grails/issues/6"); + } + + /** Loads, parses and returns the resource of the specified URI, + * or null if not found. The parser is defined by the loader defined + * in {@link ResourceCache}. + * + * @param cache the resource cache. + * Note: its loader must extend from {@link ResourceLoader}. + * @param path the URI path + * @param extra the extra parameter that will be passed to + * {@link ResourceLoader#parse(String,File,Object)} and + * {@link ResourceLoader#parse(String,URL,Object)} + */ + public static final + V get(ResourceCache cache, ServletContext ctx, String path, Object extra) { + //20050905: Tom Yeh + //We don't need to handle the default name if user specifies only a dir + //because it is handled by the container directly + //And, web developer has to specify in web.xml + URL url = null; + if (path == null || path.length() == 0) path = "/"; + else if (path.charAt(0) != '/') { + if (path.indexOf("://") > 0) { + try { + url = new URL(path); + } catch (MalformedURLException ex) { + throw new SystemException(ex); + } + }else path = '/' + path; + } + + if (url == null) { + if (path.startsWith("/~")) { + final ServletContext ctx0 = ctx; + final String path0 = path; + final int j = path.indexOf('/', 2); + final String ctxpath; + if (j >= 0) { + ctxpath = "/" + path.substring(2, j); + path = path.substring(j); + } else { + ctxpath = "/" + path.substring(2); + path = "/"; + } + + final ExtendletContext extctx = + Servlets.getExtendletContext(ctx, ctxpath.substring(1)); + if (extctx != null) { + url = extctx.getResource(path); +// if (log.isDebugEnabled()) log.debug("Resolving "+path0+" to "+url); + if (url == null) + return null; + try { + return cache.get(new ResourceInfo(path, url, extra)); + } catch (Throwable ex) { + final IOException ioex = getIOException(ex); + if (ioex == null) + throw SystemException.Aide.wrap(ex); + log.warn("Unable to load "+url, ioex); + } + return null; + } + + ctx = ctx.getContext(ctxpath); + if (ctx == null) { //failed +// if (log.isDebugEnabled()) log.debug("Context not found: "+ctxpath); + ctx = ctx0; path = path0;//restore + } + } + + //! replace ServletContext#getRealPath by lines below + final WebApplicationContext applicationContext = getRequiredWebApplicationContext(ctx); + String flnm = new ResourceUtils(applicationContext).getRealPath(path); + + if (flnm != null) { + try { + return cache.get(new ResourceInfo(path, new File(flnm), extra)); + //it is loader's job to check the existence + } catch (Throwable ex) { + final IOException ioex = getIOException(ex); + if (ioex == null) + throw SystemException.Aide.wrap(ex); + log.warn("Unable to load "+flnm, ioex); + } + return null; + } + } + + //try url because some server uses JAR format + try { + if (url == null) + url = ctx.getResource(path); + if (url != null) + return cache.get(new ResourceInfo(path, url, extra)); + } catch (Throwable ex) { + final IOException ioex = getIOException(ex); + if (ioex == null) + throw SystemException.Aide.wrap(ex); + log.warn("Unable to load "+path, ioex); + } + return null; + } + //don't eat exceptions other than IOException + private static IOException getIOException(Throwable ex) { + for (; ex != null; ex = ex.getCause()) + if (ex instanceof IOException) + return (IOException)ex; + return null; + } +} diff --git a/grailszk-common/src/main/java/org/zkoss/web/util/resource/ResourceUtils.java b/grailszk-common/src/main/java/org/zkoss/web/util/resource/ResourceUtils.java new file mode 100644 index 0000000..1f146d0 --- /dev/null +++ b/grailszk-common/src/main/java/org/zkoss/web/util/resource/ResourceUtils.java @@ -0,0 +1,42 @@ +package org.zkoss.web.util.resource; + +import grails.util.Environment; +import org.springframework.context.ApplicationContext; +import org.springframework.core.io.ClassPathResource; + +import java.io.IOException; + +/** + * @author Maicon Mauricio + */ +public class ResourceUtils { + private final ApplicationContext applicationContext; + + public ResourceUtils(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + public org.springframework.core.io.Resource getResource(String path) { + org.springframework.core.io.Resource springResource = + applicationContext.getResource("WEB-INF/classes" + path); + + if (Environment.isDevelopmentEnvironmentAvailable() && !springResource.exists()) { + springResource = applicationContext.getResource("file:./grails-app/zul" + path); + } + + if (!springResource.exists()) { // .zul file might be in a subproject or plugin + springResource = new ClassPathResource(path); + } + return springResource; + } + + public String getRealPath(String path) { + org.springframework.core.io.Resource springResource = getResource(path); + try { + if (springResource.exists()) { + return springResource.getURI().toString(); + } + } catch (IOException ignored) {} + return null; + } +} diff --git a/grailszk-common/src/main/java/org/zkoss/web/util/resource/TagDehyphen.java b/grailszk-common/src/main/java/org/zkoss/web/util/resource/TagDehyphen.java new file mode 100644 index 0000000..cfdc935 --- /dev/null +++ b/grailszk-common/src/main/java/org/zkoss/web/util/resource/TagDehyphen.java @@ -0,0 +1,22 @@ +package org.zkoss.web.util.resource; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Maicon Mauricio + */ +public class TagDehyphen { + private static final Pattern TAG_PATTERN = Pattern.compile("(())"); + + public static String dehyphen(String content) { + Matcher matcher = TAG_PATTERN.matcher(content); + + StringBuffer sb = new StringBuffer(); + while (matcher.find()) { + String tag = matcher.group(1); + matcher.appendReplacement(sb, tag.replaceAll("-", "")); + } + return sb.toString(); + } +} diff --git a/grailszk-common/src/main/java/org/zkoss/web/util/resource/UnicodeBOMInputStream.java b/grailszk-common/src/main/java/org/zkoss/web/util/resource/UnicodeBOMInputStream.java new file mode 100644 index 0000000..e3599ab --- /dev/null +++ b/grailszk-common/src/main/java/org/zkoss/web/util/resource/UnicodeBOMInputStream.java @@ -0,0 +1,153 @@ +package org.zkoss.web.util.resource; + +import java.io.IOException; +import java.io.PushbackInputStream; +import java.io.InputStream; + +public class UnicodeBOMInputStream extends InputStream { + private final PushbackInputStream in; + private final BOM bom; + private boolean skipped; + + public UnicodeBOMInputStream(final InputStream inputStream) throws NullPointerException, IOException { + this.skipped = false; + if (inputStream == null) { + throw new NullPointerException("invalid input stream: null is not allowed"); + } + this.in = new PushbackInputStream(inputStream, 4); + final byte[] bom = new byte[4]; + final int read = this.in.read(bom); + Label_0241: { + switch (read) { + case 4: { + if (bom[0] == -1 && bom[1] == -2 && bom[2] == 0 && bom[3] == 0) { + this.bom = BOM.UTF_32_LE; + break Label_0241; + } + if (bom[0] == 0 && bom[1] == 0 && bom[2] == -2 && bom[3] == -1) { + this.bom = BOM.UTF_32_BE; + break Label_0241; + } + } + case 3: { + if (bom[0] == -17 && bom[1] == -69 && bom[2] == -65) { + this.bom = BOM.UTF_8; + break Label_0241; + } + } + case 2: { + if (bom[0] == -1 && bom[1] == -2) { + this.bom = BOM.UTF_16_LE; + break Label_0241; + } + if (bom[0] == -2 && bom[1] == -1) { + this.bom = BOM.UTF_16_BE; + break Label_0241; + } + break; + } + } + this.bom = BOM.NONE; + } + if (read > 0) { + this.in.unread(bom, 0, read); + } + } + + public final BOM getBOM() { + return this.bom; + } + + public final synchronized UnicodeBOMInputStream skipBOM() throws IOException { + if (!this.skipped) { + this.in.skip(this.bom.bytes.length); + this.skipped = true; + } + return this; + } + + @Override + public int read() throws IOException { + return this.in.read(); + } + + @Override + public int read(final byte[] b) throws IOException, NullPointerException { + return this.in.read(b, 0, b.length); + } + + @Override + public int read(final byte[] b, final int off, final int len) throws IOException, NullPointerException { + return this.in.read(b, off, len); + } + + @Override + public long skip(final long n) throws IOException { + return this.in.skip(n); + } + + @Override + public int available() throws IOException { + return this.in.available(); + } + + @Override + public void close() throws IOException { + this.in.close(); + } + + @Override + public synchronized void mark(final int readlimit) { + this.in.mark(readlimit); + } + + @Override + public synchronized void reset() throws IOException { + this.in.reset(); + } + + @Override + public boolean markSupported() { + return this.in.markSupported(); + } + + public static final class BOM { + public static final BOM NONE; + public static final BOM UTF_8; + public static final BOM UTF_16_LE; + public static final BOM UTF_16_BE; + public static final BOM UTF_32_LE; + public static final BOM UTF_32_BE; + final byte[] bytes; + private final String description; + + @Override + public final String toString() { + return this.description; + } + + public final byte[] getBytes() { + final int length = this.bytes.length; + final byte[] result = new byte[length]; + System.arraycopy(this.bytes, 0, result, 0, length); + return result; + } + + private BOM(final byte[] bom, final String description) { + assert bom != null : "invalid BOM: null is not allowed"; + assert description != null : "invalid description: null is not allowed"; + assert description.length() != 0 : "invalid description: empty string is not allowed"; + this.bytes = bom; + this.description = description; + } + + static { + NONE = new BOM(new byte[0], "NONE"); + UTF_8 = new BOM(new byte[] { -17, -69, -65 }, "UTF-8"); + UTF_16_LE = new BOM(new byte[] { -1, -2 }, "UTF-16 little-endian"); + UTF_16_BE = new BOM(new byte[] { -2, -1 }, "UTF-16 big-endian"); + UTF_32_LE = new BOM(new byte[] { -1, -2, 0, 0 }, "UTF-32 little-endian"); + UTF_32_BE = new BOM(new byte[] { 0, 0, -2, -1 }, "UTF-32 big-endian"); + } + } +} diff --git a/grailszk-common/src/main/java/org/zkoss/zk/grails/api/AbstractComposersApi.java b/grailszk-common/src/main/java/org/zkoss/zk/grails/api/AbstractComposersApi.java new file mode 100644 index 0000000..561ab99 --- /dev/null +++ b/grailszk-common/src/main/java/org/zkoss/zk/grails/api/AbstractComposersApi.java @@ -0,0 +1,15 @@ +package org.zkoss.zk.grails.api; + +import org.zkoss.zk.ui.Component; + +public abstract class AbstractComposersApi { + public abstract Component getRoot(final Object p0); + + public abstract void setRoot(final Object p0, final Object p1); + + public abstract Object $(final Object p0, final String p1); + + public abstract Object $(final Object p0, final Object[] p1); + + public abstract Object $d(final Object p0, final String p1); +} diff --git a/grailszk-common/src/main/java/org/zkoss/zk/grails/ui/GrailsComposerFactory.java b/grailszk-common/src/main/java/org/zkoss/zk/grails/ui/GrailsComposerFactory.java new file mode 100644 index 0000000..65a9a73 --- /dev/null +++ b/grailszk-common/src/main/java/org/zkoss/zk/grails/ui/GrailsComposerFactory.java @@ -0,0 +1,37 @@ +package org.zkoss.zk.grails.ui; + +import grails.core.GrailsApplication; +import org.springframework.context.ApplicationContext; +import javax.servlet.ServletContext; +import org.apache.commons.lang.StringUtils; +import org.springframework.web.context.support.WebApplicationContextUtils; +import org.zkoss.zk.ui.util.Composer; +import org.zkoss.zk.ui.Page; +import org.zkoss.zk.ui.http.SimpleUiFactory; + +public class GrailsComposerFactory extends SimpleUiFactory { + public Composer newComposer(final Page page, final Class klass) { + Versions.versionValidator(); + return (Composer) super.newComposer(page, klass); + } + + public Composer newComposer(final Page page, String className) throws ClassNotFoundException { + Versions.versionValidator(); + final ServletContext servletContext = page.getDesktop().getWebApp().getServletContext(); + final ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext); + final GrailsApplication grailsApplication = (GrailsApplication) ctx.getBean("grailsApplication"); + final ApplicationContext mainContext = grailsApplication.getMainContext(); + final String[] result = className.split("\\."); + final String classNamePart = result[result.length - 1]; + + if (Character.isUpperCase(classNamePart.charAt(0))) { + result[result.length - 1] = StringUtils.uncapitalize(classNamePart); + className = StringUtils.join(result, "."); + } + + if (mainContext.containsBean(className)) { + return (Composer) mainContext.getBean(className); + } + return (Composer) super.newComposer(page, className); + } +} diff --git a/grailszk-common/src/main/java/org/zkoss/zk/grails/ui/SerializableGrailsComposerFactory.java b/grailszk-common/src/main/java/org/zkoss/zk/grails/ui/SerializableGrailsComposerFactory.java new file mode 100644 index 0000000..e2ec58e --- /dev/null +++ b/grailszk-common/src/main/java/org/zkoss/zk/grails/ui/SerializableGrailsComposerFactory.java @@ -0,0 +1,35 @@ +package org.zkoss.zk.grails.ui; + +import grails.core.GrailsApplication; +import org.springframework.context.ApplicationContext; +import javax.servlet.ServletContext; +import org.apache.commons.lang.StringUtils; +import org.springframework.web.context.support.WebApplicationContextUtils; +import org.zkoss.zk.ui.util.Composer; +import org.zkoss.zk.ui.Page; +import org.zkoss.zk.ui.http.SerializableUiFactory; + +public class SerializableGrailsComposerFactory extends SerializableUiFactory { + public Composer newComposer(final Page page, final Class klass) { + Versions.versionValidator(); + return (Composer) super.newComposer(page, klass); + } + + public Composer newComposer(final Page page, String className) throws ClassNotFoundException { + Versions.versionValidator(); + final ServletContext servletContext = page.getDesktop().getWebApp().getServletContext(); + final ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext); + final GrailsApplication grailsApplication = (GrailsApplication) ctx.getBean("grailsApplication"); + final ApplicationContext mainContext = grailsApplication.getMainContext(); + final String[] result = className.split("\\."); + final String classNamePart = result[result.length - 1]; + if (Character.isUpperCase(classNamePart.charAt(0))) { + result[result.length - 1] = StringUtils.uncapitalize(classNamePart); + className = StringUtils.join(result, "."); + } + if (mainContext.containsBean(className)) { + return (Composer) mainContext.getBean(className); + } + return (Composer) super.newComposer(page, className); + } +} diff --git a/grailszk-common/src/main/java/org/zkoss/zk/grails/ui/Versions.java b/grailszk-common/src/main/java/org/zkoss/zk/grails/ui/Versions.java new file mode 100644 index 0000000..abb5169 --- /dev/null +++ b/grailszk-common/src/main/java/org/zkoss/zk/grails/ui/Versions.java @@ -0,0 +1,17 @@ +package org.zkoss.zk.grails.ui; + +import org.zkoss.zk.fn.ZkFns; + +public class Versions { + private static final char ZK6_VERSION = '6'; + + static void versionValidator() { + final String zkVersion = ZkFns.getVersion(); + final char majorZkVersion = zkVersion.charAt(0); + if (majorZkVersion <= ZK6_VERSION) { + throw new RuntimeException( + "ZK version " + zkVersion + " not supported." + + " Support is only granted for versions 6 or above."); + } + } +}