1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.ui.admincentral;
35
36 import info.magnolia.cms.util.ServletUtil;
37
38 import java.io.BufferedWriter;
39 import java.io.IOException;
40 import java.io.OutputStreamWriter;
41 import java.io.PrintWriter;
42 import java.util.List;
43
44 import javax.inject.Inject;
45 import javax.servlet.ServletException;
46 import javax.servlet.ServletOutputStream;
47 import javax.servlet.http.HttpServletRequest;
48 import javax.servlet.http.HttpServletResponse;
49
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 import com.vaadin.server.BootstrapFragmentResponse;
54 import com.vaadin.server.BootstrapListener;
55 import com.vaadin.server.BootstrapPageResponse;
56 import com.vaadin.server.DeploymentConfiguration;
57 import com.vaadin.server.RequestHandler;
58 import com.vaadin.server.ServiceException;
59 import com.vaadin.server.SessionInitEvent;
60 import com.vaadin.server.SessionInitListener;
61 import com.vaadin.server.UIProvider;
62 import com.vaadin.server.VaadinServlet;
63 import com.vaadin.server.VaadinServletRequest;
64 import com.vaadin.server.VaadinServletResponse;
65 import com.vaadin.server.VaadinServletService;
66 import com.vaadin.server.communication.ServletBootstrapHandler;
67 import com.vaadin.shared.ApplicationConstants;
68
69
70
71
72 public class AdmincentralVaadinServlet extends VaadinServlet {
73
74 private static final Logger log = LoggerFactory.getLogger(AdmincentralVaadinServlet.class);
75
76 private static final String ERROR_PAGE_STYLE = "<style>a {color: inherit; text-decoration:none;}" +
77 "html, body {height:100%; margin:0;}" +
78 ".error-message {color:#fff; font-family: Verdana, sans-serif; padding:24px; line-height:1.3; overflow-x:hidden; overflow-y:auto;}" +
79 "h2 {font-size:5em; font-family:DINWebPro, sans-serif; font-weight: normal; margin:0;}" +
80 ".v-button-link {font-size: 2em;} .v-button-link .v-button-caption {text-decoration:none;}" +
81 "#stacktrace {font-family: monospace; display:none; color:#3e5900;}" +
82 ".viewerror {color:#aabf2f;} .v-button-link:hover, .v-button-link:focus {color:#93bac6;}</style>";
83
84
85
86
87 public static final String RESTART_APPLICATION_PARAM = "?restartApplication";
88
89 private UIProvider admincentralUiProvider;
90
91 @Inject
92 public AdmincentralVaadinServlet(UIProvider admincentralUiProvider) {
93 this.admincentralUiProvider = admincentralUiProvider;
94 }
95
96 @Override
97 protected void servletInitialized() throws ServletException {
98 super.servletInitialized();
99 getService().addSessionInitListener(new SessionInitListener() {
100 @Override
101 public void sessionInit(SessionInitEvent event) {
102 event.getSession().addBootstrapListener(new BootstrapListener() {
103
104 @Override
105 public void modifyBootstrapPage(BootstrapPageResponse response) {
106 response.getDocument().head().append("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />");
107 }
108
109 @Override
110 public void modifyBootstrapFragment(BootstrapFragmentResponse response) {
111 }
112 });
113
114
115 if (admincentralUiProvider != null) {
116 event.getSession().addUIProvider(admincentralUiProvider);
117 } else {
118 log.error("Could not inject AdmincentralUIProvider.");
119 }
120 }
121 });
122 }
123
124 @Override
125 protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
126 try {
127 String requestURI = ServletUtil.stripPathParameters(request.getRequestURI());
128 if (requestURI != null && requestURI.endsWith("undefined.cache.js")) {
129 writeUnsupportedBrowserPage(request, response);
130 } else {
131 super.service(request, response);
132 }
133 } catch (Exception e) {
134 log.error("An internal error has occurred in the VaadinServlet.", e);
135 writeServerErrorPage(request, response, e);
136 }
137 }
138
139 @Override
140 protected void criticalNotification(VaadinServletRequest request, VaadinServletResponse response, String caption, String message, String details, String url) throws IOException {
141
142 if (isUidlRequest(request)) {
143 super.criticalNotification(request, response, caption, message, details, url);
144 }
145 }
146
147 private void writeServerErrorPage(HttpServletRequest request, HttpServletResponse response, Exception e) throws IOException {
148 if (!isUidlRequest(request)) {
149
150
151
152 String url = request.getRequestURL().toString() + RESTART_APPLICATION_PARAM;
153 String fragment = request.getParameter("v-loc");
154 if (fragment != null && fragment.indexOf("#") != -1) {
155 url += fragment.substring(fragment.indexOf("#"));
156 }
157
158 StringBuilder output = new StringBuilder();
159
160 output.append(ERROR_PAGE_STYLE);
161 output.append("<div class=\"v-magnolia-shell\" style=\"height:100%;\">" +
162 "<div id=\"main-launcher\"><a href=\"" + url + "\"><img id=\"logo\" src=\"./../VAADIN/themes/admincentraltheme/img/logo-magnolia.svg\" /></a></div>" +
163 "<div class=\"error-message v-shell-viewport-slot\">");
164
165 output.append("<h2>Whoops!</h2>");
166 output.append("<p>The server has encountered an internal error.</p>");
167
168 output.append("<div class=\"v-button v-widget link v-button-link\" tabindex=\"0\" role=\"button\">" +
169 "<a href=\"" + url + "\">[<span class=\"v-button-caption\">Click here to attempt to recover from this</span>]</a></div>");
170
171 output.append("<p>We apologize for any inconvenience caused.</p>");
172
173 output.append("<p>If you keep experiencing difficulties, please contact your system administrator.<br/>" +
174 "Make sure you send along the stack trace below.</p>");
175
176 output.append("<div class=\"v-button v-widget link v-button-link viewerror\" tabindex=\"0\" role=\"button\" onclick=\"var st=document.getElementById('stacktrace');st.style.display=(st.style.display=='block')?'none':'block';\">" +
177 "[<span class=\"v-button-caption\">Click here to show the error's stack trace</span>]</div>");
178 output.append(getStackTrace(e));
179
180 output.append("</div></div>");
181
182
183 output.insert(0, "<html><head><meta charset=\"UTF-8\"/><meta content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" name=\"viewport\"/><title>Magnolia 5</title><link rel=\"stylesheet\" type=\"text/css\" href=\"./../VAADIN/themes/admincentral/styles.css\"/></head><body>");
184 output.append("</body></html>");
185
186
187 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
188 writeResponse(response, "text/html; charset=UTF-8", output.toString());
189 }
190 }
191
192 private void writeUnsupportedBrowserPage(HttpServletRequest request, HttpServletResponse response) throws IOException {
193
194 StringBuilder output = new StringBuilder();
195 output.append(ERROR_PAGE_STYLE);
196 output.append("<div class=\"v-magnolia-shell\" style=\"height:100%;\">" +
197 "<div id=\"main-launcher\"><a href=\"#\"><img id=\"logo\" src=\"./../VAADIN/themes/admincentraltheme/img/logo-magnolia.svg\"></a></div>" +
198 "<div class=\"error-message v-shell-viewport-slot\">" +
199 "<h2>Sorry.</h2>" +
200 "<p>You're trying to use Magnolia 5 on a browser we currently do not support.</p>" +
201 "<p>Please log in using either Firefox, Chrome, Safari or IE8+.<br />" +
202 "We apologize for any inconvenience caused.</p>");
203 output.append("</div></div>");
204
205
206 output.replace(0, output.length(), output.toString().replaceAll("\\\"", "\\\\\\\""));
207 output.insert(0, "document.body.innerHTML = \"");
208 output.append("\";");
209
210 writeResponse(response, "text/javascript; charset=UTF-8", output.toString());
211 }
212
213 private String getStackTrace(Throwable e) {
214 final StringBuilder result = new StringBuilder("<p id=\"stacktrace\">");
215 result.append(e.toString());
216
217
218 for (StackTraceElement element : e.getStackTrace()) {
219 result.append("<br/>");
220 result.append(" at ");
221 result.append(element);
222 }
223 result.append("</p>");
224 return result.toString();
225 }
226
227
228
229
230 private boolean isUidlRequest(HttpServletRequest request) {
231 String prefix = ApplicationConstants.UIDL_PATH + '/';
232 String pathInfo = request.getPathInfo();
233
234 if (pathInfo == null) {
235 return false;
236 }
237
238 if (!prefix.startsWith("/")) {
239 prefix = '/' + prefix;
240 }
241
242 if (pathInfo.startsWith(prefix)) {
243 return true;
244 }
245
246 return false;
247 }
248
249
250
251
252 private void writeResponse(HttpServletResponse response,
253 String contentType, String output) throws IOException {
254 response.setContentType(contentType);
255 final ServletOutputStream out = response.getOutputStream();
256
257 final PrintWriter outWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(out, "UTF-8")));
258 outWriter.print(output);
259 outWriter.flush();
260 outWriter.close();
261 out.flush();
262 }
263
264 @Override
265 protected VaadinServletService createServletService(DeploymentConfiguration deploymentConfiguration) throws ServiceException {
266 VaadinServletService service = new VaadinServletService(this, deploymentConfiguration) {
267
268 @Override
269 protected List<RequestHandler> createRequestHandlers() throws ServiceException {
270 List<RequestHandler> handlers = super.createRequestHandlers();
271 for (int i = 0; i < handlers.size(); i++) {
272 RequestHandler handler = handlers.get(i);
273 if (handler instanceof ServletBootstrapHandler) {
274 handlers.set(i, new ServletBootstrapHandler() {
275
276 @Override
277 protected String getServiceUrl(BootstrapContext context) {
278
279
280
281
282
283
284
285
286
287
288
289 return ServletUtil.getOriginalRequestURI(((VaadinServletRequest)context.getRequest()).getHttpServletRequest());
290 }
291 });
292 break;
293 }
294 }
295 return handlers;
296 }
297 };
298 service.init();
299 return service;
300 }
301 }