Cache FreeMarker templates
This commit is contained in:
parent
5dafad71ac
commit
ea1f10361a
11 changed files with 71 additions and 19 deletions
|
@ -51,6 +51,7 @@ public class FreeMarkerAccountProvider implements AccountProvider {
|
||||||
private boolean audit;
|
private boolean audit;
|
||||||
private boolean passwordUpdateSupported;
|
private boolean passwordUpdateSupported;
|
||||||
private ProviderSession session;
|
private ProviderSession session;
|
||||||
|
private FreeMarkerUtil freeMarker;
|
||||||
|
|
||||||
public static enum MessageType {SUCCESS, WARNING, ERROR}
|
public static enum MessageType {SUCCESS, WARNING, ERROR}
|
||||||
|
|
||||||
|
@ -59,8 +60,9 @@ public class FreeMarkerAccountProvider implements AccountProvider {
|
||||||
private String message;
|
private String message;
|
||||||
private MessageType messageType;
|
private MessageType messageType;
|
||||||
|
|
||||||
public FreeMarkerAccountProvider(ProviderSession session) {
|
public FreeMarkerAccountProvider(ProviderSession session, FreeMarkerUtil freeMarker) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
this.freeMarker = freeMarker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccountProvider setUriInfo(UriInfo uriInfo) {
|
public AccountProvider setUriInfo(UriInfo uriInfo) {
|
||||||
|
@ -134,7 +136,7 @@ public class FreeMarkerAccountProvider implements AccountProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String result = FreeMarkerUtil.processTemplate(attributes, Templates.getTemplate(page), theme);
|
String result = freeMarker.processTemplate(attributes, Templates.getTemplate(page), theme);
|
||||||
return Response.status(status).type(MediaType.TEXT_HTML).entity(result).build();
|
return Response.status(status).type(MediaType.TEXT_HTML).entity(result).build();
|
||||||
} catch (FreeMarkerException e) {
|
} catch (FreeMarkerException e) {
|
||||||
logger.error("Failed to process template", e);
|
logger.error("Failed to process template", e);
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.keycloak.account.freemarker;
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.account.AccountProvider;
|
import org.keycloak.account.AccountProvider;
|
||||||
import org.keycloak.account.AccountProviderFactory;
|
import org.keycloak.account.AccountProviderFactory;
|
||||||
|
import org.keycloak.freemarker.FreeMarkerUtil;
|
||||||
import org.keycloak.provider.ProviderSession;
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
@ -12,17 +13,21 @@ import javax.ws.rs.core.UriInfo;
|
||||||
*/
|
*/
|
||||||
public class FreeMarkerAccountProviderFactory implements AccountProviderFactory {
|
public class FreeMarkerAccountProviderFactory implements AccountProviderFactory {
|
||||||
|
|
||||||
|
private FreeMarkerUtil freeMarker;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AccountProvider create(ProviderSession providerSession) {
|
public AccountProvider create(ProviderSession providerSession) {
|
||||||
return new FreeMarkerAccountProvider(providerSession);
|
return new FreeMarkerAccountProvider(providerSession, freeMarker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Config.Scope config) {
|
public void init(Config.Scope config) {
|
||||||
|
freeMarker = new FreeMarkerUtil();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
freeMarker = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -3,35 +3,58 @@ package org.keycloak.freemarker;
|
||||||
import freemarker.cache.URLTemplateLoader;
|
import freemarker.cache.URLTemplateLoader;
|
||||||
import freemarker.template.Configuration;
|
import freemarker.template.Configuration;
|
||||||
import freemarker.template.Template;
|
import freemarker.template.Template;
|
||||||
import freemarker.template.TemplateException;
|
import org.keycloak.Config;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class FreeMarkerUtil {
|
public class FreeMarkerUtil {
|
||||||
|
|
||||||
public static String processTemplate(Object data, String templateName, Theme theme) throws FreeMarkerException {
|
private Map<String, Template> cache;
|
||||||
Writer out = new StringWriter();
|
|
||||||
Configuration cfg = new Configuration();
|
|
||||||
|
|
||||||
|
public FreeMarkerUtil() {
|
||||||
|
if (Config.scope("theme").getBoolean("cacheTemplates", false)) {
|
||||||
|
cache = Collections.synchronizedMap(new HashMap<String, Template>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String processTemplate(Object data, String templateName, Theme theme) throws FreeMarkerException {
|
||||||
try {
|
try {
|
||||||
cfg.setTemplateLoader(new ThemeTemplateLoader(theme));
|
Template template;
|
||||||
Template template = cfg.getTemplate(templateName);
|
if (cache != null) {
|
||||||
|
String key = theme.getName() + "/" + templateName;
|
||||||
|
template = cache.get(key);
|
||||||
|
if (template == null) {
|
||||||
|
template = getTemplate(templateName, theme);
|
||||||
|
cache.put(key, template);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
template = getTemplate(templateName, theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer out = new StringWriter();
|
||||||
template.process(data, out);
|
template.process(data, out);
|
||||||
|
return out.toString();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new FreeMarkerException("Failed to process template " + templateName, e);
|
throw new FreeMarkerException("Failed to process template " + templateName, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return out.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ThemeTemplateLoader extends URLTemplateLoader {
|
private Template getTemplate(String templateName, Theme theme) throws IOException {
|
||||||
|
Configuration cfg = new Configuration();
|
||||||
|
cfg.setTemplateLoader(new ThemeTemplateLoader(theme));
|
||||||
|
return cfg.getTemplate(templateName);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThemeTemplateLoader extends URLTemplateLoader {
|
||||||
|
|
||||||
private Theme theme;
|
private Theme theme;
|
||||||
|
|
||||||
|
|
|
@ -30,11 +30,13 @@ public class FreeMarkerEmailProvider implements EmailProvider {
|
||||||
private static final Logger log = Logger.getLogger(FreeMarkerEmailProvider.class);
|
private static final Logger log = Logger.getLogger(FreeMarkerEmailProvider.class);
|
||||||
|
|
||||||
private ProviderSession session;
|
private ProviderSession session;
|
||||||
|
private FreeMarkerUtil freeMarker;
|
||||||
private RealmModel realm;
|
private RealmModel realm;
|
||||||
private UserModel user;
|
private UserModel user;
|
||||||
|
|
||||||
public FreeMarkerEmailProvider(ProviderSession session) {
|
public FreeMarkerEmailProvider(ProviderSession session, FreeMarkerUtil freeMarker) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
this.freeMarker = freeMarker;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -81,7 +83,7 @@ public class FreeMarkerEmailProvider implements EmailProvider {
|
||||||
Theme theme = themeManager.createTheme(realm.getEmailTheme(), Theme.Type.EMAIL);
|
Theme theme = themeManager.createTheme(realm.getEmailTheme(), Theme.Type.EMAIL);
|
||||||
|
|
||||||
String subject = theme.getMessages().getProperty(subjectKey);
|
String subject = theme.getMessages().getProperty(subjectKey);
|
||||||
String body = FreeMarkerUtil.processTemplate(attributes, template, theme);
|
String body = freeMarker.processTemplate(attributes, template, theme);
|
||||||
|
|
||||||
send(subject, body);
|
send(subject, body);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.keycloak.email.freemarker;
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.email.EmailProvider;
|
import org.keycloak.email.EmailProvider;
|
||||||
import org.keycloak.email.EmailProviderFactory;
|
import org.keycloak.email.EmailProviderFactory;
|
||||||
|
import org.keycloak.freemarker.FreeMarkerUtil;
|
||||||
import org.keycloak.provider.ProviderSession;
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,17 +11,21 @@ import org.keycloak.provider.ProviderSession;
|
||||||
*/
|
*/
|
||||||
public class FreeMarkerEmailProviderFactory implements EmailProviderFactory {
|
public class FreeMarkerEmailProviderFactory implements EmailProviderFactory {
|
||||||
|
|
||||||
|
private FreeMarkerUtil freeMarker;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EmailProvider create(ProviderSession providerSession) {
|
public EmailProvider create(ProviderSession providerSession) {
|
||||||
return new FreeMarkerEmailProvider(providerSession);
|
return new FreeMarkerEmailProvider(providerSession, freeMarker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Config.Scope config) {
|
public void init(Config.Scope config) {
|
||||||
|
freeMarker = new FreeMarkerUtil();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
freeMarker = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -64,6 +64,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
||||||
private MultivaluedMap<String, String> formData;
|
private MultivaluedMap<String, String> formData;
|
||||||
|
|
||||||
private ProviderSession session;
|
private ProviderSession session;
|
||||||
|
private FreeMarkerUtil freeMarker;
|
||||||
private RealmModel realm;
|
private RealmModel realm;
|
||||||
|
|
||||||
private UserModel user;
|
private UserModel user;
|
||||||
|
@ -72,8 +73,9 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
||||||
|
|
||||||
private UriInfo uriInfo;
|
private UriInfo uriInfo;
|
||||||
|
|
||||||
public FreeMarkerLoginFormsProvider(ProviderSession session) {
|
public FreeMarkerLoginFormsProvider(ProviderSession session, FreeMarkerUtil freeMarker) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
this.freeMarker = freeMarker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoginFormsProvider setRealm(RealmModel realm) {
|
public LoginFormsProvider setRealm(RealmModel realm) {
|
||||||
|
@ -210,7 +212,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String result = FreeMarkerUtil.processTemplate(attributes, Templates.getTemplate(page), theme);
|
String result = freeMarker.processTemplate(attributes, Templates.getTemplate(page), theme);
|
||||||
return Response.status(status).type(MediaType.TEXT_HTML).entity(result).build();
|
return Response.status(status).type(MediaType.TEXT_HTML).entity(result).build();
|
||||||
} catch (FreeMarkerException e) {
|
} catch (FreeMarkerException e) {
|
||||||
logger.error("Failed to process template", e);
|
logger.error("Failed to process template", e);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.keycloak.login.freemarker;
|
package org.keycloak.login.freemarker;
|
||||||
|
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.freemarker.FreeMarkerUtil;
|
||||||
import org.keycloak.login.LoginFormsProvider;
|
import org.keycloak.login.LoginFormsProvider;
|
||||||
import org.keycloak.login.LoginFormsProviderFactory;
|
import org.keycloak.login.LoginFormsProviderFactory;
|
||||||
import org.keycloak.provider.ProviderSession;
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
@ -10,17 +11,21 @@ import org.keycloak.provider.ProviderSession;
|
||||||
*/
|
*/
|
||||||
public class FreeMarkerLoginFormsProviderFactory implements LoginFormsProviderFactory {
|
public class FreeMarkerLoginFormsProviderFactory implements LoginFormsProviderFactory {
|
||||||
|
|
||||||
|
private FreeMarkerUtil freeMarker;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoginFormsProvider create(ProviderSession providerSession) {
|
public LoginFormsProvider create(ProviderSession providerSession) {
|
||||||
return new FreeMarkerLoginFormsProvider(providerSession);
|
return new FreeMarkerLoginFormsProvider(providerSession, freeMarker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Config.Scope config) {
|
public void init(Config.Scope config) {
|
||||||
|
freeMarker = new FreeMarkerUtil();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
freeMarker = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -28,4 +33,6 @@ public class FreeMarkerLoginFormsProviderFactory implements LoginFormsProviderFa
|
||||||
return "freemarker";
|
return "freemarker";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -39,7 +39,7 @@
|
||||||
<google.zxing.version>2.2</google.zxing.version>
|
<google.zxing.version>2.2</google.zxing.version>
|
||||||
<google.client.version>1.14.1-beta</google.client.version>
|
<google.client.version>1.14.1-beta</google.client.version>
|
||||||
<winzipaes.version>1.0.1</winzipaes.version>
|
<winzipaes.version>1.0.1</winzipaes.version>
|
||||||
<freemarker.version>2.3.19</freemarker.version>
|
<freemarker.version>2.3.20</freemarker.version>
|
||||||
<twitter4j.version>3.0.5</twitter4j.version>
|
<twitter4j.version>3.0.5</twitter4j.version>
|
||||||
<selenium.version>2.35.0</selenium.version>
|
<selenium.version>2.35.0</selenium.version>
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
"theme": {
|
"theme": {
|
||||||
"default": "keycloak",
|
"default": "keycloak",
|
||||||
"staticMaxAge": 2592000,
|
"staticMaxAge": 2592000,
|
||||||
|
"cacheTemplates": true,
|
||||||
"folder": {
|
"folder": {
|
||||||
"dir": "${jboss.server.config.dir}/themes"
|
"dir": "${jboss.server.config.dir}/themes"
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,6 +131,10 @@ public class KeycloakServer {
|
||||||
System.setProperty("keycloak.theme.dir", file(dir.getAbsolutePath(), "forms", "common-themes", "src", "main", "resources", "theme").getAbsolutePath());
|
System.setProperty("keycloak.theme.dir", file(dir.getAbsolutePath(), "forms", "common-themes", "src", "main", "resources", "theme").getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!System.getProperties().containsKey("keycloak.theme.cacheTemplates")) {
|
||||||
|
System.setProperty("keycloak.theme.cacheTemplates", "false");
|
||||||
|
}
|
||||||
|
|
||||||
config.setResourcesHome(dir.getAbsolutePath());
|
config.setResourcesHome(dir.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
"theme": {
|
"theme": {
|
||||||
"default": "keycloak",
|
"default": "keycloak",
|
||||||
"staticMaxAge": 2592000,
|
"staticMaxAge": 2592000,
|
||||||
|
"cacheTemplates": "${keycloak.theme.cacheTemplates:true}",
|
||||||
"folder": {
|
"folder": {
|
||||||
"dir": "${keycloak.theme.dir}"
|
"dir": "${keycloak.theme.dir}"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue