Skip to content

Commit 8ba2097

Browse files
committed
1 parent 183929e commit 8ba2097

16 files changed

Lines changed: 73 additions & 30 deletions

File tree

pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
********************************************
1919
* version history
2020
********************************************
21+
1.3.13
22+
* #347 Add annotation to allow developer specify a handler method's template shall not be cached
23+
* #346 Template not found in `prod` mode
24+
2125
1.3.12
2226
* #345 Support in memory cache of uploaded file when size not exceeds threshold
2327
* #344 Support `*` in integer value configuration

src/main/java/act/app/ActionContext.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ public class ActionContext extends ActContext.Base<ActionContext> implements Des
9494
private boolean disableCors;
9595
private boolean disableCsrf;
9696
private Boolean hasTemplate;
97+
private $.Visitor<H.Format> templateChangeListener;
9798
private H.Status forceResponseStatus;
9899
private boolean cacheEnabled;
99100
private MissingAuthenticationHandler forceMissingAuthenticationHandler;
@@ -228,9 +229,17 @@ public Map<String, Object> renderArgs() {
228229
@Override
229230
public ActionContext templatePath(String templatePath) {
230231
hasTemplate = null;
232+
if (null != templateChangeListener) {
233+
templateChangeListener.visit(accept());
234+
}
231235
return super.templatePath(templatePath);
232236
}
233237

238+
public ActionContext templateChangeListener($.Visitor<H.Format> listener) {
239+
this.templateChangeListener = $.notNull(listener);
240+
return this;
241+
}
242+
234243
public RequestHandler handler() {
235244
return handler;
236245
}

src/main/java/act/app/App.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,10 +1196,7 @@ private void loadRoutes() {
11961196

11971197
private void loadBuiltInRoutes() {
11981198
router().addMapping(H.Method.GET, "/asset/", new StaticResourceGetter("asset"), RouteSource.BUILD_IN);
1199-
StaticResourceGetter actAssets = new StaticResourceGetter("asset/~/act");
1200-
router().addMapping(H.Method.GET, "/~/asset/", actAssets, RouteSource.BUILD_IN);
1201-
// TODO drop the following routes in 2.0
1202-
router().addMapping(H.Method.GET, "/asset/act/", actAssets, RouteSource.BUILD_IN);
1199+
router().addMapping(H.Method.GET, "/~/asset/", new StaticResourceGetter("asset/~act"), RouteSource.BUILD_IN);
12031200
router().addContext("act.", "/~");
12041201
if (config.cliOverHttp()) {
12051202
Router router = router(AppConfig.PORT_CLI_OVER_HTTP);

src/main/java/act/handler/builtin/controller/impl/ReflectedHandlerInvoker.java

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,13 @@ public class ReflectedHandlerInvoker<M extends HandlerMethodMetaInfo> extends De
8484
private MethodAccess methodAccess;
8585
private M handler;
8686
private int handlerIndex;
87-
private ConcurrentMap<H.Format, Boolean> templateCache = new ConcurrentHashMap<>();
87+
private ConcurrentMap<H.Format, Boolean> templateAvailabilityCache = new ConcurrentHashMap<>();
88+
private $.Visitor<H.Format> templateChangeListener = new $.Visitor<H.Format>() {
89+
@Override
90+
public void visit(H.Format format) throws Osgl.Break {
91+
templateAvailabilityCache.remove(format);
92+
}
93+
};
8894
protected Method method; //
8995
private ParamValueLoaderService paramLoaderService;
9096
private JsonDTOClassManager jsonDTOClassManager;
@@ -111,6 +117,7 @@ public class ReflectedHandlerInvoker<M extends HandlerMethodMetaInfo> extends De
111117
private Map<Integer, String> outputParams;
112118
private boolean hasOutputVar;
113119
private String templateContext;
120+
private boolean noTemplateCache;
114121
private MissingAuthenticationHandler missingAuthenticationHandler;
115122
private MissingAuthenticationHandler csrfFailureHandler;
116123

@@ -143,6 +150,7 @@ private ReflectedHandlerInvoker(M handlerMetaInfo, App app) {
143150

144151
sessionFree = method.isAnnotationPresent(SessionFree.class);
145152
express = method.isAnnotationPresent(NonBlock.class);
153+
noTemplateCache = method.isAnnotationPresent(Template.NoCache.class);
146154

147155
paramCount = handler.paramCount();
148156
paramSpecs = jsonDTOClassManager.beanSpecs(controllerClass, method);
@@ -230,6 +238,11 @@ public Result handle(ActionContext context) throws Exception {
230238
return ActNotFound.get();
231239
}
232240

241+
context.templateChangeListener(templateChangeListener);
242+
if (noTemplateCache) {
243+
context.disableTemplateCaching();
244+
}
245+
233246
String urlContext = this.controller.contextPath();
234247
if (S.notBlank(urlContext)) {
235248
context.urlContext(urlContext);
@@ -242,17 +255,16 @@ public Result handle(ActionContext context) throws Exception {
242255
preventDoubleSubmission(context);
243256
processForceResponse(context);
244257
ensureJsonDTOGenerated(context);
245-
Object controller = controllerInstance(context);
246258

259+
Object controller = controllerInstance(context);
247260

248261
/*
249262
* We will send back response immediately when param validation
250-
* failed in the following cases:
251-
* a) this is a data endpoint and accept JSON data
252-
* b) there is no template associated with the endpoint
253-
* TODO: fix me - if method use arbitrary templates, then this check will fail
263+
* failed in either of the following cases:
264+
* 1) this is an ajax call
265+
* 2) the accept content type is **NOT** html
254266
*/
255-
boolean failOnViolation = context.acceptJson() || checkTemplate(context);
267+
boolean failOnViolation = context.isAjax() || context.accept() != H.Format.HTML;
256268

257269
Object[] params = params(controller, context);
258270

@@ -264,19 +276,9 @@ public Result handle(ActionContext context) throws Exception {
264276
try {
265277
return invoke(handler, context, controller, params);
266278
} finally {
267-
268279
if (hasOutputVar) {
269280
fillOutputVariables(controller, params, context);
270281
}
271-
272-
if (null == context.hasTemplate()) {
273-
// template path has been reset by app logic
274-
templateCache.remove(context.accept());
275-
}
276-
// ensure template is loaded as
277-
// request handler might change the
278-
// template path
279-
checkTemplate(context);
280282
}
281283
}
282284

@@ -628,15 +630,18 @@ public boolean checkTemplate(ActionContext context) {
628630
//we don't check template on interceptors
629631
return false;
630632
}
633+
H.Format fmt = context.accept();
634+
if (noTemplateCache || Act.isDev()) {
635+
return probeTemplate(fmt, context);
636+
}
631637
Boolean hasTemplate = context.hasTemplate();
632638
if (null != hasTemplate) {
633639
return hasTemplate;
634640
}
635-
H.Format fmt = context.accept();
636-
hasTemplate = templateCache.get(fmt);
637-
if (null == hasTemplate || Act.isDev()) {
641+
hasTemplate = templateAvailabilityCache.get(fmt);
642+
if (null == hasTemplate) {
638643
hasTemplate = probeTemplate(fmt, context);
639-
templateCache.putIfAbsent(fmt, hasTemplate);
644+
templateAvailabilityCache.putIfAbsent(fmt, hasTemplate);
640645
}
641646
context.setHasTemplate(hasTemplate);
642647
return hasTemplate;

src/main/java/act/util/ActContext.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ abstract class Base<CTX extends Base> extends DestroyableBase implements ActCont
148148
private Locale locale;
149149
private int fieldOutputVarCount;
150150
private S.Buffer strBuf;
151+
private boolean noTemplateCache;
151152

152153
// (violation.propertyPath, violation)
153154
private Map<String, ConstraintViolation> violations;
@@ -241,9 +242,16 @@ public Template cachedTemplate() {
241242
return template;
242243
}
243244

245+
public CTX disableTemplateCaching() {
246+
this.noTemplateCache = true;
247+
return me();
248+
}
249+
244250
@Override
245251
public CTX cacheTemplate(Template template) {
246-
this.template = template;
252+
if (!noTemplateCache) {
253+
this.template = template;
254+
}
247255
return me();
248256
}
249257

src/main/java/act/view/Template.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,30 @@
2323
import act.app.ActionContext;
2424
import act.mail.MailerContext;
2525

26+
import java.lang.annotation.ElementType;
27+
import java.lang.annotation.Retention;
28+
import java.lang.annotation.RetentionPolicy;
29+
import java.lang.annotation.Target;
30+
2631
/**
2732
* A Template represents a resource that can be merged with {@link ActionContext application context}
2833
* and output the result
2934
*/
3035
public interface Template {
36+
37+
/**
38+
* Notify framework not to cache template for this handler method.
39+
*
40+
* If developer can change template path in the logic of handler method,
41+
* caching template could cause trouble (i.e. it uses the template of first run).
42+
* In this case developer must annotate the handler method with `@Template.NoCache`
43+
* annotation
44+
*/
45+
@Retention(RetentionPolicy.RUNTIME)
46+
@Target(ElementType.METHOD)
47+
@interface NoCache {
48+
}
49+
3150
void merge(ActionContext context);
3251

3352
String render(ActionContext context);

src/main/java/act/view/View.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public boolean appliedTo(ActContext context) {
6868
* @param context the view context
6969
* @return the template instance or {@code null} if template not found
7070
*/
71+
// TODO it shall not need context to load template, revise this interface to remove it
7172
protected abstract Template loadTemplate(String resourcePath, ActContext context);
7273

7374
/**

src/main/java/act/view/ViewManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,12 @@ public View view(String name) {
108108
}
109109

110110
public Template load(ActContext context) {
111-
AppConfig config = context.config();
112111
Template cached = context.cachedTemplate();
113112
if (null != cached) {
114113
return cached;
115114
}
116115

116+
AppConfig config = context.config();
117117
TemplatePathResolver resolver = config.templatePathResolver();
118118

119119
String path = resolver.resolve(context);

src/main/java/act/view/rythm/RythmView.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ public class RythmView extends View {
5151

5252
public static final String ID = "rythm";
5353

54-
ConcurrentMap<App, RythmEngine> engines = new ConcurrentHashMap<App, RythmEngine>();
55-
ConcurrentMap<String, Template> templates = new ConcurrentHashMap<String, Template>();
56-
ConcurrentMap<String, String> missings = new ConcurrentHashMap<String, String>();
54+
ConcurrentMap<App, RythmEngine> engines = new ConcurrentHashMap<>();
55+
ConcurrentMap<String, Template> templates = new ConcurrentHashMap<>();
56+
ConcurrentMap<String, String> missings = new ConcurrentHashMap<>();
5757

5858
private boolean isDev;
5959

File renamed without changes.

0 commit comments

Comments
 (0)