WIP:thymeproxy
[maven-thymeleaf-skin] / src / main / java / de / juplo / thymeproxy / Application.java
1 package de.juplo.thymeproxy;
2
3 import de.juplo.thymeleaf.JuploDialect;
4 import java.util.HashMap;
5 import java.util.Locale;
6 import java.util.Map;
7 import javax.servlet.http.HttpServletRequest;
8 import javax.servlet.http.HttpServletResponse;
9 import org.apache.http.HttpStatus;
10 import org.apache.http.impl.client.CloseableHttpClient;
11 import org.springframework.beans.factory.annotation.Autowired;
12 import org.springframework.boot.SpringApplication;
13 import org.springframework.boot.autoconfigure.SpringBootApplication;
14 import org.springframework.boot.autoconfigure.web.BasicErrorController;
15 import org.springframework.boot.autoconfigure.web.ErrorAttributes;
16 import org.springframework.boot.autoconfigure.web.ErrorController;
17 import org.springframework.boot.autoconfigure.web.ErrorProperties;
18 import org.springframework.boot.autoconfigure.web.ServerProperties;
19 import org.springframework.context.annotation.Bean;
20 import org.springframework.core.Ordered;
21 import org.springframework.core.env.Environment;
22 import org.springframework.http.MediaType;
23 import org.springframework.web.servlet.ModelAndView;
24 import org.springframework.web.servlet.View;
25 import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
26 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
27 import org.springframework.web.servlet.mvc.UrlFilenameViewController;
28 import org.thymeleaf.exceptions.TemplateInputException;
29 import org.thymeleaf.resourceresolver.IResourceResolver;
30 import org.thymeleaf.resourceresolver.UrlResourceResolver;
31 import org.thymeleaf.spring4.view.ThymeleafViewResolver;
32 import org.thymeleaf.templateresolver.TemplateResolver;
33
34
35 @SpringBootApplication
36 public class Application extends WebMvcConfigurerAdapter
37 {
38   @Autowired
39   private ServerProperties properties;
40
41
42   @Bean
43   public RegexUrlHandlerMapping proxiedHandlerMapping(
44       ProxyHttpRequestHandler proxy,
45       UrlFilenameViewController views
46       )
47   {
48     RegexUrlHandlerMapping mapping = new RegexUrlHandlerMapping();
49     mapping.setOrder(Ordered.HIGHEST_PRECEDENCE);
50     Map<String, Object> mappings = new HashMap<>();
51     mappings.put("/img/.+", proxy);
52     mappings.put("/css/.+", proxy);
53     mappings.put("/js/.+", proxy);
54     mappings.put("/fonts/.+", proxy);
55     mappings.put("/.*\\.html", views);
56     mapping.setUrlMap(mappings);
57         return mapping;
58   }
59
60   @Bean
61   public ProxyHttpRequestHandler proxyHttpRequestHandler(
62       CloseableHttpClient client,
63       Environment env
64       )
65   {
66     ProxyHttpRequestHandler handler = new ProxyHttpRequestHandler();
67     handler.setClient(client);
68     handler.setOrigin(env.getProperty("thymeproxy.origin"));
69     handler.setTtl(30000l);
70     return handler;
71   }
72
73   @Bean
74   public UrlFilenameViewController urlFilenameViewController()
75   {
76     return new UrlFilenameViewController();
77   }
78
79   @Bean
80   public TemplateResolver defaultTemplateResolver(
81       IResourceResolver resources,
82       Environment env
83       )
84   {
85     TemplateResolver resolver = new TemplateResolver();
86     resolver.setResourceResolver(resources);
87     resolver.setPrefix("http://localhost:8080/thymeleaf/");
88     resolver.setSuffix(".html");
89     resolver.setTemplateMode("HTML5");
90     resolver.setCharacterEncoding("UTF-8");
91     resolver.setCacheable(Boolean.valueOf(env.getProperty("thymeproxy.cacheable")));
92     return resolver;
93   }
94
95   @Bean
96   public TemplateResolver jsonTemplateResolver(
97       IResourceResolver resources,
98       Environment env
99       )
100   {
101     TemplateResolver resolver = new TemplateResolver();
102     resolver.setResourceResolver(resources);
103     resolver.setPrefix("http://localhost:8080/thymeleaf/");
104     resolver.setSuffix(".json");
105     resolver.setTemplateMode("JSON");
106     resolver.setCharacterEncoding("UTF-8");
107     resolver.setCacheable(Boolean.valueOf(env.getProperty("thymeproxy.cacheable")));
108     return resolver;
109   }
110
111   @Bean
112   public UrlResourceResolver thymeleafResourceResolver()
113   {
114     return new UrlResourceResolver();
115   }
116
117   @Bean
118   public JuploDialect juploDialect()
119   {
120     return new JuploDialect();
121   }
122
123   @Bean
124   public View error(ThymeleafViewResolver resolver) throws Exception
125   {
126     return resolver.resolveViewName("templates/500", Locale.getDefault());
127   }
128
129   @Bean
130   public ErrorController errorController(ErrorAttributes errorAttributes)
131   {
132     return new CustomErrorController(errorAttributes, properties.getError());
133   }
134
135
136   @Override
137   public void addViewControllers(ViewControllerRegistry registry)
138   {
139     registry.addViewController("/").setViewName("forward:index.html");
140   }
141
142
143   public static void main(String[] args)
144   {
145     SpringApplication.run(Application.class, args);
146   }
147
148
149   static class CustomErrorController extends BasicErrorController
150   {
151     public final static String TEMPLATE_INPUT_EXCEPTION =
152         TemplateInputException.class.getCanonicalName();
153
154
155     CustomErrorController(
156         ErrorAttributes errorAttributes,
157         ErrorProperties errorProperties
158         )
159     {
160       super(errorAttributes, errorProperties);
161     }
162
163
164     @Override
165     public ModelAndView errorHtml(
166         HttpServletRequest request,
167         HttpServletResponse response
168         )
169     {
170       Map<String, Object> model =
171           getErrorAttributes(
172               request,
173               isIncludeStackTrace(request, MediaType.TEXT_HTML)
174               );
175
176       String view;
177
178       switch ((String)model.get("exception"))
179       {
180         case "org.thymeleaf.exceptions.TemplateInputException":
181           response.setStatus(HttpStatus.SC_NOT_FOUND);
182           view = "templates/404";
183           break;
184
185         default:
186           response.setStatus(getStatus(request).value());
187           view = "templates/500";
188           break;
189       }
190
191       return new ModelAndView(view, model);
192     }
193   }
194 }