Skip to content

Commit 9d1cea9

Browse files
committed
Fix pebble caches in dev #400
1 parent 5638a55 commit 9d1cea9

File tree

2 files changed

+128
-87
lines changed

2 files changed

+128
-87
lines changed

jooby-pebble/src/main/java/org/jooby/pebble/Pebble.java

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222

2323
import java.util.function.BiConsumer;
2424
import java.util.function.Consumer;
25+
import java.util.function.Function;
2526

2627
import org.jooby.Env;
2728
import org.jooby.Jooby;
2829
import org.jooby.Renderer;
2930

31+
import com.google.common.cache.Cache;
3032
import com.google.common.cache.CacheBuilder;
3133
import com.google.common.cache.CacheBuilderSpec;
3234
import com.google.inject.Binder;
@@ -35,8 +37,6 @@
3537
import com.mitchellbosecke.pebble.loader.ClasspathLoader;
3638
import com.mitchellbosecke.pebble.loader.Loader;
3739
import com.typesafe.config.Config;
38-
import com.typesafe.config.ConfigFactory;
39-
import com.typesafe.config.ConfigValueFactory;
4040

4141
/**
4242
* <h1>pebble</h1>
@@ -127,6 +127,9 @@
127127
*/
128128
public class Pebble implements Jooby.Module {
129129

130+
/** Default cache size on prod . */
131+
private static final int MAX_SIZE = 100;
132+
130133
private BiConsumer<PebbleEngine.Builder, Config> callback;
131134

132135
private PebbleEngine.Builder pebble;
@@ -182,23 +185,37 @@ public Pebble doWith(final Consumer<PebbleEngine.Builder> callback) {
182185
return doWith((p, c) -> callback.accept(p));
183186
}
184187

188+
@SuppressWarnings({"unchecked", "rawtypes" })
185189
@Override
186190
public void configure(final Env env, final Config conf, final Binder binder) {
187-
/** Template cache. */
191+
/**
192+
* This control pebble caches: template and tags.
193+
*
194+
* It always on and we always set a template/tags cache, we don't let pebble to apply defaults.
195+
*
196+
* In development <code>env.name=dev</code> we set a Guava cache with maxSize=0. This allow us
197+
* to reload templates without restarting the application.
198+
*/
199+
pebble.cacheActive(true);
200+
201+
/**
202+
* Cache builder:
203+
* 1. if there is a custom cache, then use it (regardless of application env)
204+
* 2. when missing, we set a default cache for dev or prod.
205+
*/
188206
String mode = env.name();
189-
pebble.cacheActive(!mode.equals("dev"));
190-
if (mode.equals("dev") || conf.getString("pebble.cache").isEmpty()) {
191-
pebble.templateCache(null);
192-
} else {
193-
pebble.templateCache(CacheBuilder.from(conf.getString("pebble.cache")).build());
194-
}
207+
Function<String, Cache> cache = path -> {
208+
if (conf.hasPath(path)) {
209+
return CacheBuilder.from(conf.getString(path)).build();
210+
}
211+
// dev vs prod:
212+
return CacheBuilder.newBuilder().maximumSize("dev".equals(mode) ? 0 : MAX_SIZE).build();
213+
};
214+
/** Template cache. */
215+
pebble.templateCache(cache.apply("pebble.cache"));
195216

196217
/** Tag cache. */
197-
if (mode.equals("dev") || conf.getString("pebble.tagCache").isEmpty()) {
198-
pebble.tagCache(null);
199-
} else {
200-
pebble.tagCache(CacheBuilder.from(conf.getString("pebble.tagCache")).build());
201-
}
218+
pebble.tagCache(cache.apply("pebble.tagCache"));
202219

203220
/** locale. */
204221
pebble.defaultLocale(env.locale());
@@ -216,13 +233,6 @@ public void configure(final Env env, final Config conf, final Binder binder) {
216233
.toInstance(new PebbleRenderer(pebble));
217234
}
218235

219-
@Override
220-
public Config config() {
221-
return ConfigFactory.empty(Pebble.class.getName())
222-
.withValue("pebble.cache", ConfigValueFactory.fromAnyRef("maximumSize=200"))
223-
.withValue("pebble.tagCache", ConfigValueFactory.fromAnyRef("maximumSize=200"));
224-
}
225-
226236
private static Loader<String> loader(final String prefix, final String suffix) {
227237
Loader<String> loader = new ClasspathLoader();
228238
loader.setPrefix(prefix);

jooby-pebble/src/test/java/org/jooby/pebble/PebbleTest.java

Lines changed: 97 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.jooby.pebble;
22

33
import static org.easymock.EasyMock.expect;
4-
import static org.junit.Assert.assertEquals;
54
import static org.junit.Assert.assertNotNull;
65

76
import java.util.Locale;
@@ -37,6 +36,7 @@ public class PebbleTest {
3736
PebbleEngine.Builder pebble = unit.constructor(PebbleEngine.Builder.class)
3837
.build();
3938

39+
expect(pebble.cacheActive(true)).andReturn(pebble);
4040
expect(pebble.loader(unit.get(ClasspathLoader.class))).andReturn(pebble);
4141

4242
unit.registerMock(PebbleEngine.Builder.class, pebble);
@@ -49,16 +49,6 @@ public class PebbleTest {
4949
unit.registerMock(ClasspathLoader.class, loader);
5050
};
5151

52-
private Block noCache = unit -> {
53-
PebbleEngine.Builder pebble = unit.get(PebbleEngine.Builder.class);
54-
expect(pebble.templateCache(null)).andReturn(pebble);
55-
};
56-
57-
private Block noTagCache = unit -> {
58-
PebbleEngine.Builder pebble = unit.get(PebbleEngine.Builder.class);
59-
expect(pebble.tagCache(null)).andReturn(pebble);
60-
};
61-
6252
private Block build = unit -> {
6353
PebbleEngine.Builder pebble = unit.get(PebbleEngine.Builder.class);
6454
expect(pebble.build()).andReturn(unit.get(PebbleEngine.class));
@@ -89,15 +79,22 @@ public class PebbleTest {
8979
expect(Multibinder.newSetBinder(unit.get(Binder.class), Renderer.class)).andReturn(rmb);
9080
};
9181

82+
private Block cacheStatic = unit -> {
83+
unit.mockStatic(CacheBuilder.class);
84+
};
85+
9286
@Test
9387
public void basic() throws Exception {
9488
Locale locale = Locale.getDefault();
9589
new MockUnit(Env.class, Config.class, Binder.class, PebbleEngine.class)
9690
.expect(defLoader)
9791
.expect(newEngine)
9892
.expect(env("dev", locale))
99-
.expect(noCache)
100-
.expect(noTagCache)
93+
.expect(cacheStatic)
94+
.expect(cache("pebble.cache", null))
95+
.expect(cache(0))
96+
.expect(cache("pebble.tagCache", null))
97+
.expect(tagCache(0))
10198
.expect(locale(locale))
10299
.expect(build)
103100
.expect(bindEngine)
@@ -109,47 +106,48 @@ public void basic() throws Exception {
109106
}
110107

111108
@Test
112-
public void doWithFull() throws Exception {
109+
public void proddef() throws Exception {
113110
Locale locale = Locale.getDefault();
114-
CountDownLatch latch = new CountDownLatch(1);
115111
new MockUnit(Env.class, Config.class, Binder.class, PebbleEngine.class)
116112
.expect(defLoader)
117113
.expect(newEngine)
118-
.expect(env("dev", locale))
119-
.expect(noCache)
120-
.expect(noTagCache)
114+
.expect(env("prod", locale))
115+
.expect(cacheStatic)
116+
.expect(cache("pebble.cache", null))
117+
.expect(cache(100))
118+
.expect(cache("pebble.tagCache", null))
119+
.expect(tagCache(100))
121120
.expect(locale(locale))
122121
.expect(build)
123122
.expect(bindEngine)
124123
.expect(renderer)
125124
.run(unit -> {
126-
new Pebble(".html").doWith((b, c) -> {
127-
assertNotNull(b);
128-
assertNotNull(c);
129-
latch.countDown();
130-
})
125+
new Pebble()
131126
.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
132127
});
133-
latch.await();
134128
}
135129

136130
@Test
137-
public void doWith1() throws Exception {
131+
public void doWithFull() throws Exception {
138132
Locale locale = Locale.getDefault();
139133
CountDownLatch latch = new CountDownLatch(1);
140134
new MockUnit(Env.class, Config.class, Binder.class, PebbleEngine.class)
141135
.expect(defLoader)
142136
.expect(newEngine)
143137
.expect(env("dev", locale))
144-
.expect(noCache)
145-
.expect(noTagCache)
138+
.expect(cacheStatic)
139+
.expect(cache("pebble.cache", null))
140+
.expect(cache(0))
141+
.expect(cache("pebble.tagCache", null))
142+
.expect(tagCache(0))
146143
.expect(locale(locale))
147144
.expect(build)
148145
.expect(bindEngine)
149146
.expect(renderer)
150147
.run(unit -> {
151-
new Pebble().doWith(b -> {
148+
new Pebble(".html").doWith((b, c) -> {
152149
assertNotNull(b);
150+
assertNotNull(c);
153151
latch.countDown();
154152
})
155153
.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
@@ -158,30 +156,30 @@ public void doWith1() throws Exception {
158156
}
159157

160158
@Test
161-
public void prodNoCache() throws Exception {
159+
public void doWith1() throws Exception {
162160
Locale locale = Locale.getDefault();
161+
CountDownLatch latch = new CountDownLatch(1);
163162
new MockUnit(Env.class, Config.class, Binder.class, PebbleEngine.class)
164163
.expect(defLoader)
165164
.expect(newEngine)
166-
.expect(env("prod", locale))
167-
.expect(unit -> {
168-
Config conf = unit.get(Config.class);
169-
expect(conf.getString("pebble.cache")).andReturn("");
170-
})
171-
.expect(noCache)
172-
.expect(unit -> {
173-
Config conf = unit.get(Config.class);
174-
expect(conf.getString("pebble.tagCache")).andReturn("");
175-
})
176-
.expect(noTagCache)
165+
.expect(env("dev", locale))
166+
.expect(cacheStatic)
167+
.expect(cache("pebble.cache", null))
168+
.expect(cache(0))
169+
.expect(cache("pebble.tagCache", null))
170+
.expect(tagCache(0))
177171
.expect(locale(locale))
178172
.expect(build)
179173
.expect(bindEngine)
180174
.expect(renderer)
181175
.run(unit -> {
182-
new Pebble()
176+
new Pebble().doWith(b -> {
177+
assertNotNull(b);
178+
latch.countDown();
179+
})
183180
.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
184181
});
182+
latch.await();
185183
}
186184

187185
@SuppressWarnings({"unchecked", "rawtypes" })
@@ -192,26 +190,10 @@ public void prod() throws Exception {
192190
.expect(defLoader)
193191
.expect(newEngine)
194192
.expect(env("prod", locale))
195-
.expect(unit -> {
196-
Config conf = unit.get(Config.class);
197-
expect(conf.getString("pebble.cache")).andReturn("maximumSize=200").times(2);
198-
})
199-
.expect(unit -> {
200-
unit.mockStatic(CacheBuilder.class);
201-
}).expect(unit -> {
202-
Cache<Object, PebbleTemplate> cache = unit.mock(Cache.class);
203-
204-
CacheBuilder cachebuilder = unit.mock(CacheBuilder.class);
205-
expect(CacheBuilder.from("maximumSize=200")).andReturn(cachebuilder);
206-
expect(cachebuilder.build()).andReturn(cache);
207-
208-
PebbleEngine.Builder pebble = unit.get(PebbleEngine.Builder.class);
209-
expect(pebble.templateCache(cache)).andReturn(pebble);
210-
})
211-
.expect(unit -> {
212-
Config conf = unit.get(Config.class);
213-
expect(conf.getString("pebble.tagCache")).andReturn("maximumSize=100").times(2);
214-
})
193+
.expect(cache("pebble.cache", "maximumSize=200"))
194+
.expect(cacheStatic)
195+
.expect(cacheBuilder(200))
196+
.expect(cache("pebble.tagCache", "maximumSize=100"))
215197
.expect(unit -> {
216198
Cache<BaseTagCacheKey, Object> cache = unit.mock(Cache.class);
217199

@@ -232,11 +214,19 @@ public void prod() throws Exception {
232214
});
233215
}
234216

235-
@Test
236-
public void conf() throws Exception {
237-
Config config = new Pebble().config();
238-
assertEquals("maximumSize=200", config.getString("pebble.cache"));
239-
assertEquals("maximumSize=200", config.getString("pebble.tagCache"));
217+
@SuppressWarnings({"unchecked", "rawtypes" })
218+
private Block cacheBuilder(final int maxSize) {
219+
return unit -> {
220+
Cache<Object, PebbleTemplate> cache = unit.mock(Cache.class);
221+
unit.registerMock(Cache.class, cache);
222+
223+
CacheBuilder cachebuilder = unit.mock(CacheBuilder.class);
224+
expect(CacheBuilder.from("maximumSize=" + maxSize)).andReturn(cachebuilder);
225+
expect(cachebuilder.build()).andReturn(cache);
226+
227+
PebbleEngine.Builder pebble = unit.get(PebbleEngine.Builder.class);
228+
expect(pebble.templateCache(cache)).andReturn(pebble);
229+
};
240230
}
241231

242232
private Block locale(final Locale locale) {
@@ -246,11 +236,52 @@ private Block locale(final Locale locale) {
246236
};
247237
}
248238

239+
private Block cache(final String path, final String value) {
240+
return unit -> {
241+
Config conf = unit.get(Config.class);
242+
boolean has = value != null;
243+
expect(conf.hasPath(path)).andReturn(has);
244+
if (has) {
245+
expect(conf.getString(path)).andReturn(value);
246+
}
247+
};
248+
}
249+
249250
private Block env(final String name, final Locale locale) {
250251
return unit -> {
251252
Env env = unit.get(Env.class);
252253
expect(env.name()).andReturn(name);
253254
expect(env.locale()).andReturn(locale);
254255
};
255256
}
257+
258+
@SuppressWarnings({"unchecked", "rawtypes" })
259+
private Block cache(final int size) {
260+
return unit -> {
261+
Cache<Object, PebbleTemplate> cache = unit.mock(Cache.class);
262+
263+
CacheBuilder cachebuilder = unit.mock(CacheBuilder.class);
264+
expect(CacheBuilder.newBuilder()).andReturn(cachebuilder);
265+
expect(cachebuilder.maximumSize(size)).andReturn(cachebuilder);
266+
expect(cachebuilder.build()).andReturn(cache);
267+
268+
PebbleEngine.Builder pebble = unit.get(PebbleEngine.Builder.class);
269+
expect(pebble.templateCache(cache)).andReturn(pebble);
270+
};
271+
}
272+
273+
@SuppressWarnings({"unchecked", "rawtypes" })
274+
private Block tagCache(final int size) {
275+
return unit -> {
276+
Cache<BaseTagCacheKey, Object> cache = unit.mock(Cache.class);
277+
278+
CacheBuilder cachebuilder = unit.mock(CacheBuilder.class);
279+
expect(CacheBuilder.newBuilder()).andReturn(cachebuilder);
280+
expect(cachebuilder.maximumSize(size)).andReturn(cachebuilder);
281+
expect(cachebuilder.build()).andReturn(cache);
282+
283+
PebbleEngine.Builder pebble = unit.get(PebbleEngine.Builder.class);
284+
expect(pebble.tagCache(cache)).andReturn(pebble);
285+
};
286+
}
256287
}

0 commit comments

Comments
 (0)