package com.hundsun.jresplus.web.velocity.resolver;
import java.util.Locale;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.context.Context;
import org.springframework.web.servlet.view.velocity.VelocityToolboxView;
import com.hundsun.jresplus.web.contain.Contain;
import com.hundsun.jresplus.web.contain.async.AsynchronousContain;
/**
* @author LeoHu copy by sagahl copy by fish
*
*/
public class FixedVelocityLayoutView extends VelocityToolboxView {
public static final String Seq = "/";
public static final String DefaultLayoutPrefix = "layout/";
public static final String DefaultLayoutName = "default.vm";
public static final String DEFAULT_LAYOUT_URL = DefaultLayoutPrefix
+ DefaultLayoutName;
public static final String DEFAULT_LAYOUT_KEY = "layout";
public static final String DEFAULT_SCREEN_CONTENT_KEY = "screen_content";
private static final ThreadLocal<CharArrayWriterWrapper> screenLocal = new ThreadLocal<CharArrayWriterWrapper>() {
@Override
protected CharArrayWriterWrapper initialValue() {
return new CharArrayWriterWrapper();
}
};
private String layoutUrl = DEFAULT_LAYOUT_URL;
private String layoutKey = DEFAULT_LAYOUT_KEY;
private String screenContentKey = DEFAULT_SCREEN_CONTENT_KEY;
private String layoutPrefix = DEFAULT_LAYOUT_KEY;
private char[] layoutPrefixChars = layoutPrefix.toCharArray();
private String defaultLayoutName = DefaultLayoutName;
private char[] defaultLayoutNameChars = defaultLayoutName.toCharArray();
private char[] screenPrefixChars;
protected Map<Object, Template> layoutTemplateCache;
public void setScreenPrefix(String prefix) {
this.screenPrefixChars = prefix.toCharArray();
}
public void setLayoutUrl(String layoutUrl) {
this.layoutUrl = layoutUrl;
this.layoutPrefix = layoutUrl.substring(0, layoutUrl.indexOf(Seq) + 1);
this.layoutPrefixChars = this.layoutPrefix.toCharArray();
this.defaultLayoutName = layoutUrl
.substring(layoutUrl.indexOf(Seq) + 1);
this.defaultLayoutNameChars = this.defaultLayoutName.toCharArray();
}
public void setLayoutKey(String layoutKey) {
this.layoutKey = layoutKey;
}
public void setScreenContentKey(String screenContentKey) {
this.screenContentKey = screenContentKey;
}
@Override
public boolean checkResource(Locale locale) throws Exception {
return checkResource(getUrl());
}
protected boolean checkResource(String url) throws Exception {
return this.getVelocityEngine().resourceExists(url);
}
private boolean isInContain(Context context) {
Integer cCount = (Integer) context.get(Contain.ContainCounterKey);
if (cCount != null && cCount > 0) {
return true;
}
return false;
}
private boolean isInAsyncContain() {
return AsynchronousContain.isAsyncConext();
}
@Override
protected void doRender(Context context, HttpServletResponse response)
throws Exception {
if (isInAsyncContain()) {
if (logger.isDebugEnabled()) {
logger.debug("in async contain render for:" + this.getUrl());
}
renderCotainContent(context, response);
return;
}
if (isInContain(context)) {
if (logger.isDebugEnabled()) {
logger.debug("in contain render for:" + this.getUrl());
}
renderCotainContent(context, response);
return;
}
renderScreenContent(context);
try {
String layoutUrlToUse = (String) context.get(this.layoutKey);
if (StringUtils.isNotBlank(layoutUrlToUse)) {
if (logger.isDebugEnabled()) {
logger.debug("Screen content template has requested layout ["
+ layoutUrlToUse + "]");
}
mergeTemplate(getTemplate(layoutUrlToUse), context, response);
} else {
if (layoutUrlToUse == null) {
mergeTemplate(findLayoutTemplate(), context, response);
} else {
screenLocal.get().writeTo(response.getWriter());
}
}
} finally {
screenLocal.get().reset();
}
}
protected Template findLayoutTemplate() throws Exception {
Template cached = this.layoutTemplateCache.get(this.getUrl());
if (cached == null) {
cached = this.searchLayoutTemplate();
this.layoutTemplateCache.put(this.getUrl(), cached);
}
return cached;
}
protected final Template searchLayoutTemplate() throws Exception {
boolean debug = logger.isDebugEnabled();
LayoutFinder finder = new LayoutFinder(this.getUrl(),
this.layoutPrefixChars, this.screenPrefixChars,
this.defaultLayoutNameChars);
String url = finder.getSameNameLayoutUrl();
if (checkResource(url)) {
if (debug) {
logger.debug("Find layout template [" + url + "] for:"
+ getUrl());
}
return this.getTemplate(url);
}
while ((url = finder.getLayoutUrl()) != null) {
if (checkResource(url)) {
if (debug) {
logger.debug("Find layout template [" + url + "] for:"
+ getUrl());
}
return this.getTemplate(url);
}
}
return this.getTemplate(this.layoutUrl);
}
private void renderScreenContent(Context velocityContext) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("Rendering screen content template [" + getUrl() + "]");
}
CharArrayWriterWrapper writer = screenLocal.get();
Template screenContentTemplate = getTemplate(getUrl());
screenContentTemplate.merge(velocityContext, writer.getWriter());
velocityContext.put(this.screenContentKey, writer);
}
private void renderCotainContent(Context velocityContext,
HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("Rendering contain content template [" + getUrl()
+ "]");
}
Template cotainContentTemplate = getTemplate(getUrl());
cotainContentTemplate.merge(velocityContext, response.getWriter());
}
@Override
protected void mergeTemplate(Template template, Context context,
HttpServletResponse response) throws Exception {
super.mergeTemplate(template, context, response);
}
@Override
protected boolean isCacheTemplate() {
return false;
}
public void setLayoutTemplateCache(Map<Object, Template> layoutTemplateCache) {
this.layoutTemplateCache = layoutTemplateCache;
}
}