Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 29 additions & 18 deletions grails-gsp/core/src/main/groovy/org/grails/gsp/GroovyPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -84,6 +83,7 @@ public abstract class GroovyPage extends Script {
public static final String LINK_NAMESPACE = "link";
public static final String TEMPLATE_NAMESPACE = "tmpl";
public static final String PAGE_SCOPE = "pageScope";
private OutputEncodingStackAttributes.Builder attributesBuilder;

public static final Collection<String> RESERVED_NAMES = CollectionUtils.newSet(
OUT,
Expand Down Expand Up @@ -130,23 +130,30 @@ public void setOut(Writer newWriter) {
throw new IllegalStateException("Setting out in page isn't allowed.");
}

public void initRun(Writer target, OutputContext outputContext, GroovyPageMetaInfo metaInfo) {
OutputEncodingStackAttributes.Builder attributesBuilder = new OutputEncodingStackAttributes.Builder();
public void initCommonRun(GroovyPageMetaInfo metaInfo) {
attributesBuilder = new OutputEncodingStackAttributes.Builder();
if (metaInfo != null) {
setJspTags(metaInfo.getJspTags());
setJspTagLibraryResolver(metaInfo.getJspTagLibraryResolver());
setGspTagLibraryLookup(metaInfo.getTagLibraryLookup());
setHtmlParts(metaInfo.getHtmlParts());
setPluginContextPath(metaInfo.getPluginPath());
attributesBuilder.outEncoder(metaInfo.getOutEncoder());
attributesBuilder.staticEncoder(metaInfo.getStaticEncoder());
attributesBuilder.expressionEncoder(metaInfo.getExpressionEncoder());
attributesBuilder.defaultTaglibEncoder(metaInfo.getTaglibEncoder());
setHtmlParts(metaInfo.getHtmlParts());
setHtmlPartsSet(metaInfo.getHtmlPartsSet());
setJspTags(metaInfo.getJspTags());
setJspTagLibraryResolver(metaInfo.getJspTagLibraryResolver());
setGspTagLibraryLookup(metaInfo.getTagLibraryLookup());
setPluginContextPath(metaInfo.getPluginPath());
}
attributesBuilder.allowCreate(true).autoSync(false).pushTop(true);
attributesBuilder.inheritPreviousEncoders(false);
}

public void initRun(Writer target, OutputContext outputContext, GroovyPageMetaInfo metaInfo) {
if (metaInfo != null) {
applyModelFieldsFromBinding(metaInfo.getModelFields());
}
attributesBuilder.allowCreate(true).topWriter(target).autoSync(false).pushTop(true);
attributesBuilder.outputContext(outputContext);
attributesBuilder.inheritPreviousEncoders(false);
attributesBuilder.topWriter(target);
outputStack = OutputEncodingStack.currentStack(attributesBuilder.build());

out = outputStack.getOutWriter();
Expand Down Expand Up @@ -507,6 +514,14 @@ public final void printHtmlPart(final int partNumber) {
staticOut.write(htmlParts[partNumber]);
}

/**
* Shorthand for printHtmlPart to reduce class size
* @param partNumber
*/
public final void h(final int partNumber) {
staticOut.write(htmlParts[partNumber]);
}

/**
* Sets the JSP tags used by this GroovyPage instance
*
Expand All @@ -527,14 +542,10 @@ protected boolean isHtmlPart(String htmlPart) {

public void setHtmlParts(String[] htmlParts) {
this.htmlParts = htmlParts;
this.htmlPartsSet = new HashSet<>();
if (htmlParts != null) {
for (String htmlPart : htmlParts) {
if (htmlPart != null) {
htmlPartsSet.add(System.identityHashCode(htmlPart));
}
}
}
}

public void setHtmlPartsSet(Set<Integer> htmlPartsSet) {
this.htmlPartsSet = htmlPartsSet;
}

public final OutputEncodingStack getOutputStack() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.lang.ref.SoftReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLConnection;
Expand Down Expand Up @@ -67,14 +70,17 @@ public class GroovyPageMetaInfo implements GrailsApplicationAware {
private static final Log LOG = LogFactory.getLog(GroovyPageMetaInfo.class);
private TagLibraryLookup tagLibraryLookup;
private TagLibraryResolver jspTagLibraryResolver;
private ThreadLocal<SoftReference<GroovyPage>> pageInstance = new ThreadLocal<>();

private boolean precompiledMode = false;
private Class<?> pageClass;
private Constructor<?> pageClassConstructor;
private long lastModified;
private InputStream groovySource;
private String contentType;
private int[] lineNumbers;
private String[] htmlParts;
private Set<Integer> htmlPartsSet;
@SuppressWarnings("rawtypes")
private Map jspTags = Collections.emptyMap();
private GroovyPagesException compilationException;
Expand Down Expand Up @@ -115,6 +121,11 @@ public GroovyPageMetaInfo(Class<?> pageClass) {
this();
precompiledMode = true;
this.pageClass = pageClass;
try {
this.pageClassConstructor = pageClass.getConstructor();
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
contentType = (String) ReflectionUtils.getField(ReflectionUtils.findField(pageClass, GroovyPageParser.CONSTANT_NAME_CONTENT_TYPE), null);
jspTags = (Map) ReflectionUtils.getField(ReflectionUtils.findField(pageClass, GroovyPageParser.CONSTANT_NAME_JSP_TAGS), null);
lastModified = (Long) ReflectionUtils.getField(ReflectionUtils.findField(pageClass, GroovyPageParser.CONSTANT_NAME_LAST_MODIFIED), null);
Expand All @@ -133,8 +144,7 @@ public GroovyPageMetaInfo(Class<?> pageClass) {

try {
readHtmlData();
}
catch (IOException e) {
} catch (IOException e) {
throw new RuntimeException("Problem reading html data for page class " + pageClass, e);
}
}
Expand Down Expand Up @@ -217,8 +227,7 @@ private void readHtmlData() throws IOException {
htmlParts[i] = input.readUTF();
}
}
}
finally {
} finally {
IOUtils.closeQuietly(input);
}
}
Expand All @@ -239,8 +248,7 @@ private void readLineNumbers() throws IOException {
for (int i = 0; i < arrayLen; i++) {
lineNumbers[i] = input.readInt();
}
}
finally {
} finally {
IOUtils.closeQuietly(input);
}
}
Expand Down Expand Up @@ -282,8 +290,28 @@ public Class<?> getPageClass() {
return pageClass;
}

public GroovyPage getPageClassInstance() throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
SoftReference<GroovyPage> pageSoftRef = pageInstance.get();
GroovyPage pageCacheEntry = pageSoftRef != null ? pageSoftRef.get() : null;
if (pageCacheEntry == null) {
pageCacheEntry = (GroovyPage) pageClassConstructor.newInstance();
pageCacheEntry.initCommonRun(this);
if (!isModelFieldsMode()) {
pageInstance.set(new SoftReference<>(pageCacheEntry));
}
}
return pageCacheEntry;
}

public void setPageClass(Class<?> pageClass) {
this.pageClass = pageClass;

try {
this.pageClassConstructor = pageClass.getConstructor();
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
pageInstance.set(null);
initializePluginPath();
}

Expand Down Expand Up @@ -323,8 +351,7 @@ private synchronized int[] getPrecompiledLineNumbers() {
if (lineNumbers == null) {
try {
readLineNumbers();
}
catch (IOException e) {
} catch (IOException e) {
LOG.warn("Problem reading precompiled linenumbers", e);
}
}
Expand Down Expand Up @@ -359,6 +386,18 @@ public String[] getHtmlParts() {

public void setHtmlParts(String[] htmlParts) {
this.htmlParts = htmlParts;
this.htmlPartsSet = new HashSet<>();
if (htmlParts != null) {
for (String htmlPart : htmlParts) {
if (htmlPart != null) {
htmlPartsSet.add(System.identityHashCode(htmlPart));
}
}
}
}

Set<Integer> getHtmlPartsSet() {
return this.htmlPartsSet;
}

public void applyLastModifiedFromResource(Resource resource) {
Expand Down Expand Up @@ -394,22 +433,18 @@ private long establishLastModified(Resource resource) {
urlc.setDoInput(false);
urlc.setDoOutput(false);
last = urlc.getLastModified();
}
catch (FileNotFoundException fnfe) {
} catch (FileNotFoundException fnfe) {
last = -1;
}
catch (IOException e) {
} catch (IOException e) {
last = -1;
}
finally {
} finally {
if (urlc != null) {
try {
InputStream is = urlc.getInputStream();
if (is != null) {
is.close();
}
}
catch (IOException e) {
} catch (IOException e) {
// ignore
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
import groovy.lang.Binding;
import groovy.lang.Writable;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import grails.util.Environment;
import org.grails.taglib.AbstractTemplateVariableBinding;
Expand All @@ -47,7 +47,7 @@
* @since 0.5
*/
public class GroovyPageWritable implements Writable {
private static final Log LOG = LogFactory.getLog(GroovyPageWritable.class);
private static final Logger LOG = LoggerFactory.getLogger(GroovyPageWritable.class);
private static final String GSP_NONE_CODEC_NAME = "none";
private GroovyPageMetaInfo metaInfo;
private OutputContextLookup outputContextLookup;
Expand Down Expand Up @@ -101,8 +101,7 @@ protected Writer doWriteTo(OutputContext outputContext, Writer out) throws IOExc
// Set it to TEXT
outputContext.setContentType(GROOVY_SOURCE_CONTENT_TYPE); // must come before response.getOutputStream()
writeGroovySourceToResponse(metaInfo, out);
}
else {
} else {
// Set it to HTML by default
if (metaInfo.getCompilationException() != null) {
throw metaInfo.getCompilationException();
Expand All @@ -125,9 +124,7 @@ protected Writer doWriteTo(OutputContext outputContext, Writer out) throws IOExc
// only try to set content type when evaluating top level GSP
boolean contentTypeAlreadySet = outputContext.isContentTypeAlreadySet();
if (!contentTypeAlreadySet) {
if (LOG.isDebugEnabled()) {
LOG.debug("Writing output with content type: " + metaInfo.getContentType());
}
LOG.debug("Writing output with content type: {}", metaInfo.getContentType());
outputContext.setContentType(metaInfo.getContentType()); // must come before response.getWriter()
}
}
Expand All @@ -136,22 +133,26 @@ protected Writer doWriteTo(OutputContext outputContext, Writer out) throws IOExc
if (hasRequest) {
outputContext.setBinding(binding);
}

Binding existingBinding = null;
GroovyPage page = null;
try {
page = (GroovyPage) metaInfo.getPageClass().newInstance();
page = metaInfo.getPageClassInstance();
existingBinding = page.getBinding();
} catch (Exception e) {
throw new GroovyPagesException("Problem instantiating page class", e);
}

page.setBinding(binding);
binding.setOwner(page);

page.initRun(out, outputContext, metaInfo);

try {
page.run();
}
finally {
} finally {
if (existingBinding != null) {
page.setBinding(existingBinding);
}
page.cleanup();
if (hasRequest) {
if (newParentCreated) {
Expand Down Expand Up @@ -220,13 +221,12 @@ protected void writeInputStreamToResponse(InputStream in, Writer out) throws IOE
Reader reader = new InputStreamReader(in, "UTF-8");
char[] buf = new char[8192];

for (;;) {
for (; ; ) {
int read = reader.read(buf);
if (read <= 0) break;
out.write(buf, 0, read);
}
}
finally {
} finally {
out.close();
in.close();
}
Expand All @@ -249,8 +249,7 @@ protected void writeGroovySourceToResponse(GroovyPageMetaInfo info, Writer out)
try {
try {
in.reset();
}
catch (IOException e) {
} catch (IOException e) {
// ignore
}
BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
Expand Down Expand Up @@ -288,8 +287,7 @@ protected void writeGroovySourceToResponse(GroovyPageMetaInfo info, Writer out)
out.write(line);
out.write('\n');
}
}
finally {
} finally {
out.close();
in.close();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,27 @@ public Template createTemplate(String txt, String pageName) throws IOException {
return createTemplate(new ByteArrayResource(txt.getBytes(StandardCharsets.UTF_8), pageName), pageName, pageName != null);
}

/**
* Creates a Template using the given text for the Template and the given name. The name
* of the template is required
*
* @param txt The URI of the page to create the template for
* @param pageName The name of the page being parsed
* @param cache If the template should be cached
*
* @return The Template instance
* @throws CompilationFailedException
* @throws IOException Thrown if an IO exception occurs creating the Template
*/
public Template createTemplate(String txt, String pageName, boolean cache) throws IOException {
Assert.hasLength(txt, "Argument [txt] cannot be null or blank");
Assert.hasLength(pageName, "Argument [pageName] cannot be null or blank");

return createTemplate(new ByteArrayResource(txt.getBytes(StandardCharsets.UTF_8), pageName), pageName, cache);
}

/**
* Creates a Template using the given text for the Template and the given name. The name
/**
* Creates a Template for the given file
*
Expand Down
Loading
Loading