// Don't cache if a user is logged in
dontCache = true;
}
final RenderContext renderContext = RenderContext.getInstance(request, response, getEffectiveLocale(request));
renderContext.setResourceProvider(config.getResourceProvider());
final EditMode edit = renderContext.getEditMode(user);
DOMNode rootElement = null;
AbstractNode dataNode = null;
String[] uriParts = PathHelper.getParts(path);
if ((uriParts == null) || (uriParts.length == 0)) {
// find a visible page
rootElement = findIndexPage(securityContext);
logger.log(Level.FINE, "No path supplied, trying to find index page");
} else {
if (rootElement == null) {
rootElement = findPage(securityContext, request, path);
} else {
dontCache = true;
}
}
if (rootElement == null) { // No page found
// Look for a file
File file = findFile(securityContext, request, path);
if (file != null) {
streamFile(securityContext, file, request, response, edit);
return;
}
// store remaining path parts in request
Matcher matcher = threadLocalUUIDMatcher.get();
boolean requestUriContainsUuids = false;
for (int i = 0; i < uriParts.length; i++) {
request.setAttribute(uriParts[i], i);
matcher.reset(uriParts[i]);
// set to "true" if part matches UUID pattern
requestUriContainsUuids |= matcher.matches();
}
if (!requestUriContainsUuids) {
// Try to find a data node by name
dataNode = findFirstNodeByName(securityContext, request, path);
} else {
dataNode = findNodeByUuid(securityContext, PathHelper.getName(path));
}
if (dataNode != null && !(dataNode instanceof Linkable)) {
// Last path part matches a data node
// Remove last path part and try again searching for a page
// clear possible entry points
request.removeAttribute(POSSIBLE_ENTRY_POINTS);
rootElement = findPage(securityContext, request, StringUtils.substringBeforeLast(path, PathHelper.PATH_SEP));
renderContext.setDetailsDataObject(dataNode);
// Start rendering on data node
if (rootElement == null && dataNode instanceof DOMNode) {
rootElement = ((DOMNode) dataNode);
}
}
}
// Still nothing found, do error handling
if (rootElement == null) {
// Check if security context has set an 401 status
if (response.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) {
try {
UiAuthenticator.writeUnauthorized(response);
} catch (IllegalStateException ise) {
}
} else {
rootElement = notFound(response, securityContext);
}
}
if (rootElement == null) {
return;
}
if (EditMode.WIDGET.equals(edit) || dontCache) {
setNoCacheHeaders(response);
}
if (!securityContext.isVisible(rootElement)) {
rootElement = notFound(response, securityContext);
if (rootElement == null) {
return;
}
}
if (securityContext.isVisible(rootElement)) {
if (!EditMode.WIDGET.equals(edit) && !dontCache && notModifiedSince(request, response, rootElement, dontCache)) {
ServletOutputStream out = response.getOutputStream();
out.flush();
//response.flushBuffer();
out.close();
} else {
// prepare response
response.setCharacterEncoding("UTF-8");
String contentType = rootElement.getProperty(Page.contentType);
if (contentType == null) {
// Default
contentType = "text/html;charset=UTF-8";
}
if (contentType.equals("text/html")) {
contentType = contentType.concat(";charset=UTF-8");
}
response.setContentType(contentType);
response.setHeader("Strict-Transport-Security", "max-age=60");
response.setHeader("X-Content-Type-Options", "nosniff");
response.setHeader("X-Frame-Options", "SAMEORIGIN");
response.setHeader("X-XSS-Protection", "1; mode=block");
// async or not?
boolean isAsync = HttpService.parseBoolean(Services.getBaseConfiguration().getProperty(HttpService.ASYNC), true);
if (isAsync) {
final AsyncContext async = request.startAsync();
final ServletOutputStream out = async.getResponse().getOutputStream();
final AtomicBoolean finished = new AtomicBoolean(false);
final DOMNode rootNode = rootElement;
threadPool.submit(new Runnable() {
@Override
public void run() {
try (final Tx tx = app.tx()) {
//final long start = System.currentTimeMillis();
// render
rootNode.render(securityContext, renderContext, 0);
finished.set(true);
//final long end = System.currentTimeMillis();
//System.out.println("Done in " + (end-start) + " ms");
tx.success();
} catch (Throwable t) {
t.printStackTrace();
final String errorMsg = t.getMessage();
try {
//response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, errorMsg);
finished.set(true);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
});
// start output write listener
out.setWriteListener(new WriteListener() {
@Override
public void onWritePossible() throws IOException {
try {
final Queue<String> queue = renderContext.getBuffer().getQueue();
while (out.isReady()) {
String buffer = null;
synchronized(queue) {
buffer = queue.poll();
}
if (buffer != null) {
out.print(buffer);
} else {
if (finished.get()) {
async.complete();
response.setStatus(HttpServletResponse.SC_OK);
// prevent this block from being called again
break;
}
Thread.sleep(1);
}
}
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
});
} else {
final StringRenderBuffer buffer = new StringRenderBuffer();
renderContext.setBuffer(buffer);
// render
rootElement.render(securityContext, renderContext, 0);
response.getOutputStream().write(buffer.getBuffer().toString().getBytes("utf-8"));