Java tutorial
/** * Copyright 2013 Ben Navetta <ben@bennavetta.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.bennavetta.appsite.processing; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.net.URI; import java.nio.channels.Channels; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import com.bennavetta.appsite.file.Resource; import com.bennavetta.appsite.file.ResourceService; import com.bennavetta.appsite.util.DatastoreObjectCache; import com.google.common.base.Strings; import com.google.common.io.ByteStreams; import com.google.common.net.MediaType; import com.netflix.config.DynamicIntProperty; import com.netflix.config.DynamicPropertyFactory; import com.netflix.config.DynamicStringProperty; public class ProcessingController { private Logger log = LoggerFactory.getLogger(getClass()); private Set<Processor> processors = new HashSet<>(); private Set<OutputProcessor> postProcessors = new HashSet<>(); private ResourceService resources; private ErrorHandler error = new ErrorHandler(); private String[] indexPages = DEFAULT_INDEX_PAGES.split(","); private static final String DEFAULT_INDEX_PAGES = "index.html"; @SuppressWarnings("unused") private DynamicStringProperty indexPagesProperty = DynamicPropertyFactory.getInstance() .getStringProperty("index.pages", DEFAULT_INDEX_PAGES, new Runnable() { @Override public void run() { indexPages = indexPagesProperty.get().split(","); } }); private DatastoreObjectCache<RewriteRule> rewriteRules = new DatastoreObjectCache<>(RewriteRule.class, DynamicPropertyFactory.getInstance().getLongProperty("rewrite.cache", 60 * 1000)); private DynamicIntProperty bufferSize = DynamicPropertyFactory.getInstance().getIntProperty("buffer.size", 1024 * 8); public void handle(Request request, Response response, InputStream requestBody, OutputStream responseBody) throws Exception { for (RewriteRule rule : rewriteRules.get()) { if (rule.matches(request.getURI())) { URI rewritten = rule.rewrite(request.getURI()); log.info("Rewriting {} to {}", request.getURI(), rewritten); handle(new RedirectedRequest(rewritten, request), response, requestBody, responseBody); } } Resource resource = Resource.get(request.getURI()); // index pages if (resource == null) { for (String indexPage : indexPages) { String indexUri = URI.create(request.getURI()).relativize(URI.create(indexPage)).toString(); resource = Resource.get(indexUri); if (resource != null) { break; } } } if (resource == null) { resource = Resource.get(error.notFound()); //TODO: put requested page in attributes response.setStatus(HttpStatus.NOT_FOUND); } if (resource != null) { try { log.info("Serving resource {}", resource.getPath()); sendResource(resource, request, response, requestBody, responseBody); } catch (Exception e) { log.error("Exception serving request", e); resource = Resource.get(error.exception()); //TODO: put exception in attributes response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR); sendResource(resource, request, response, requestBody, responseBody); } } else { log.warn("No content found: {}", request.getURI()); // send something to avoid a blank response response.setStatus(HttpStatus.NOT_FOUND); response.setContentType(MediaType.HTML_UTF_8); PrintStream ps = new PrintStream(responseBody); ps.println("<html>"); ps.println("\t<head>"); ps.println("\t\t<title>Page not found</title>"); ps.println("\t</head>"); ps.println("\t<body>"); ps.println("\t\t<h1>Page not found</h1>"); ps.println("\t\t<p>Page " + request.getURI() + " not found</p>"); ps.println("\t</body>"); ps.println("</html>"); } } private void sendResource(Resource resource, Request request, Response response, InputStream requestBody, OutputStream responseBody) throws Exception { InputStream processedStream = null; for (Processor processor : processors) { if (processor.canProcess(resource.getPath(), resource.getMimeType(), request, response)) { log.info("Found processor {} for {}", processor, resource); ByteArrayOutputStream buffer = new ByteArrayOutputStream(bufferSize.get()); //MessageDigest hasher = MessageDigest.getInstance("MD5"); //runProcessor(processor, resource, new DigestOutputStream(buffer, hasher), request, response); runProcessor(processor, resource, buffer, request, response); processedStream = new ByteArrayInputStream(buffer.toByteArray()); break; } } if (processedStream == null) { processedStream = resources.readStream(resource); } boolean wasPostProcessed = false; for (OutputProcessor postProcessor : postProcessors) { if (postProcessor.canPostProcess(resource.getPath(), request, response)) { wasPostProcessed = true; log.debug("Found post-processor {} for {}", postProcessor, resource); postProcessor.postProcess(processedStream, responseBody, request, response); responseBody.flush(); break; } } if (!wasPostProcessed) { ByteStreams.copy(processedStream, responseBody); } } private void runProcessor(Processor processor, Resource resource, OutputStream out, Request request, Response response) throws Exception { try (InputStream in = Channels.newInputStream(resources.read(resource))) { processor.process(resource.getPath(), resource.getMimeType(), in, out, request, response); } } public Set<Processor> getProcessors() { return Collections.unmodifiableSet(processors); } public Set<OutputProcessor> getPostProcessors() { return Collections.unmodifiableSet(postProcessors); } public void registerProcessors(Set<Processor> processors) { this.processors.addAll(processors); } public void register(Processor processor) { this.processors.add(processor); } public void registerPostProcessors(Set<OutputProcessor> postProcessors) { this.postProcessors.addAll(postProcessors); } public void register(OutputProcessor postProcessor) { this.postProcessors.add(postProcessor); } public void setResourceService(ResourceService resourceService) { this.resources = resourceService; } }