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 import info.magnolia.event.EventBus;
38 import info.magnolia.event.SystemEventBus;
39 import info.magnolia.objectfactory.Components;
40 import info.magnolia.objectfactory.guice.GuiceComponentProvider;
41 import info.magnolia.ui.framework.ioc.MagnoliaUiGuiceComponentProviderFactory;
42 import info.magnolia.ui.framework.ioc.SessionStore;
43
44 import java.io.BufferedWriter;
45 import java.io.IOException;
46 import java.io.OutputStreamWriter;
47 import java.io.PrintWriter;
48 import java.util.List;
49
50 import javax.inject.Inject;
51 import javax.servlet.ServletException;
52 import javax.servlet.ServletOutputStream;
53 import javax.servlet.http.HttpServletRequest;
54 import javax.servlet.http.HttpServletResponse;
55
56 import org.apache.commons.lang3.StringEscapeUtils;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 import com.google.inject.name.Names;
61 import com.vaadin.server.BootstrapFragmentResponse;
62 import com.vaadin.server.BootstrapListener;
63 import com.vaadin.server.BootstrapPageResponse;
64 import com.vaadin.server.DeploymentConfiguration;
65 import com.vaadin.server.RequestHandler;
66 import com.vaadin.server.ServiceException;
67 import com.vaadin.server.UIProvider;
68 import com.vaadin.server.VaadinServlet;
69 import com.vaadin.server.VaadinServletRequest;
70 import com.vaadin.server.VaadinServletResponse;
71 import com.vaadin.server.VaadinServletService;
72 import com.vaadin.server.VaadinSession;
73 import com.vaadin.server.communication.ServletBootstrapHandler;
74 import com.vaadin.shared.ApplicationConstants;
75
76
77
78
79 public class AdmincentralVaadinServlet extends VaadinServlet {
80
81 private static final Logger log = LoggerFactory.getLogger(AdmincentralVaadinServlet.class);
82
83 private static final String ERROR_PAGE_STYLE = "<style>a {color: inherit; text-decoration:none;}" +
84 "html, body {height:100%; margin:0;}" +
85 ".error-message {color:#fff; font-family: Verdana, sans-serif; padding:24px; line-height:1.3; overflow-x:hidden; overflow-y:auto;}" +
86 "h2 {font-size:5em; font-family:DINWebPro, sans-serif; font-weight: normal; margin:0;}" +
87 ".v-button-link {font-size: 2em;} .v-button-link .v-button-caption {text-decoration:none;}" +
88 "#stacktrace {font-family: monospace; display:none; color:#3e5900;}" +
89 ".viewerror {color:#aabf2f;} .v-button-link:hover, .v-button-link:focus {color:#93bac6;}</style>";
90
91
92
93
94 public static final String RESTART_APPLICATION_PARAM = "?restartApplication";
95
96 private UIProvider admincentralUiProvider;
97 private final MagnoliaUiGuiceComponentProviderFactory uiGuiceComponentProviderFactory;
98 private GuiceComponentProvider guiceComponentProvider;
99
100 @Inject
101 public AdmincentralVaadinServlet(UIProvider admincentralUiProvider, MagnoliaUiGuiceComponentProviderFactory uiGuiceComponentProviderFactory) {
102 this.admincentralUiProvider = admincentralUiProvider;
103 this.uiGuiceComponentProviderFactory = uiGuiceComponentProviderFactory;
104 }
105
106 @Override
107 protected void servletInitialized() throws ServletException {
108 super.servletInitialized();
109 this.guiceComponentProvider = uiGuiceComponentProviderFactory.create();
110
111 final EventBus systemEventBus = Components.getComponentWithAnnotation(EventBus.class, Names.named(SystemEventBus.NAME));
112 VaadinServlet.getCurrent().getServletContext().setAttribute("componentProvider", guiceComponentProvider);
113
114 getService().addSessionInitListener(event -> {
115 final VaadinSession session = event.getSession();
116 session.setAttribute(SessionStore.class, new SessionStore(session, systemEventBus));
117 session.addBootstrapListener(new BootstrapListener() {
118
119 @Override
120 public void modifyBootstrapPage(BootstrapPageResponse response) {
121 response.getDocument().head().append("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />");
122 }
123
124 @Override
125 public void modifyBootstrapFragment(BootstrapFragmentResponse response) {}
126 });
127
128
129 if (admincentralUiProvider != null) {
130 session.addUIProvider(admincentralUiProvider);
131 } else {
132 log.error("Could not inject AdmincentralUIProvider.");
133 }
134 });
135 }
136
137 @Override
138 protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
139 try {
140 Components.pushProvider(this.guiceComponentProvider);
141 super.service(request, response);
142 } catch (Exception e) {
143 log.error("An internal error has occurred in the VaadinServlet.", e);
144 writeServerErrorPage(request, response, e);
145 } finally {
146 Components.popProvider();
147 }
148 }
149
150 @Override
151 protected void criticalNotification(VaadinServletRequest request, VaadinServletResponse response, String caption, String message, String details, String url) throws IOException {
152
153 if (isUidlRequest(request)) {
154 super.criticalNotification(request, response, caption, message, details, url);
155 }
156 }
157
158 private void writeServerErrorPage(HttpServletRequest request, HttpServletResponse response, Exception e) throws IOException {
159 if (!isUidlRequest(request)) {
160
161
162
163 String url = request.getRequestURL().toString() + RESTART_APPLICATION_PARAM;
164 String fragment = request.getParameter("v-loc");
165 if (fragment != null && fragment.indexOf("#") != -1) {
166 fragment = fragment.substring(fragment.indexOf("#"));
167
168
169 if (fragment.equals(StringEscapeUtils.escapeHtml4(fragment))) {
170 url += fragment;
171 }
172 }
173
174 final StringBuilder output = new StringBuilder();
175 output.append(ERROR_PAGE_STYLE)
176 .append("<div class=\"v-magnolia-shell\" style=\"height:100%;\">")
177 .append("<div id=\"main-launcher\"><a href=\"" + url + "\"><img id=\"logo\" src=\"./../VAADIN/themes/admincentraltheme/img/logo-magnolia.svg\" /></a></div>")
178 .append("<div class=\"error-message v-shell-viewport-slot\">")
179
180 .append("<h2>Whoops!</h2>")
181 .append("<p>The server has encountered an internal error.</p>")
182
183 .append("<div class=\"v-button v-widget link v-button-link\" tabindex=\"0\" role=\"button\">")
184 .append("<a href=\"" + url + "\">[<span class=\"v-button-caption\">Click here to attempt to recover from this</span>]</a></div>")
185
186 .append("<p>We apologize for any inconvenience caused.</p>")
187 .append("<p>If you keep experiencing difficulties, please contact your system administrator.</p>")
188 .append("<p>Please check your log files for the complete stack trace.</p>");
189
190 output.append("</div></div>");
191
192
193 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>");
194 output.append("</body></html>");
195
196
197 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
198 writeResponse(response, "text/html; charset=UTF-8", output.toString());
199 }
200 }
201
202
203
204
205 private boolean isUidlRequest(HttpServletRequest request) {
206 String prefix = ApplicationConstants.UIDL_PATH + '/';
207 String pathInfo = request.getPathInfo();
208
209 if (pathInfo == null) {
210 return false;
211 }
212
213 if (!prefix.startsWith("/")) {
214 prefix = '/' + prefix;
215 }
216
217 return pathInfo.startsWith(prefix);
218 }
219
220
221
222
223 private void writeResponse(HttpServletResponse response,
224 String contentType, String output) throws IOException {
225 response.setContentType(contentType);
226 final ServletOutputStream out = response.getOutputStream();
227
228 final PrintWriter outWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(out, "UTF-8")));
229 outWriter.print(output);
230 outWriter.flush();
231 outWriter.close();
232 out.flush();
233 }
234
235 @Override
236 protected VaadinServletService createServletService(DeploymentConfiguration deploymentConfiguration) throws ServiceException {
237 VaadinServletService service = new VaadinServletService(this, deploymentConfiguration) {
238
239 @Override
240 protected List<RequestHandler> createRequestHandlers() throws ServiceException {
241 List<RequestHandler> handlers = super.createRequestHandlers();
242 for (int i = 0; i < handlers.size(); i++) {
243 RequestHandler handler = handlers.get(i);
244 if (handler instanceof ServletBootstrapHandler) {
245 handlers.set(i, new ServletBootstrapHandler() {
246
247 @Override
248 protected String getServiceUrl(BootstrapContext context) {
249
250
251
252
253
254
255
256
257
258
259
260 return ServletUtil.getOriginalRequestURI(((VaadinServletRequest)context.getRequest()).getHttpServletRequest());
261 }
262 });
263 break;
264 }
265 }
266 return handlers;
267 }
268 };
269 service.init();
270 return service;
271 }
272 }