/* * Copyright 2012 Jason Miller * * 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 jj.document; import static jj.server.ServerLocation.*; import static jj.document.DocumentScriptEnvironment.*; import javax.inject.Inject; import javax.inject.Singleton; import com.google.inject.AbstractModule; import com.google.inject.Injector; import jj.document.servable.DocumentRequestProcessor; import jj.execution.TaskRunner; import jj.http.server.HttpServerRequest; import jj.http.server.HttpServerResponse; import jj.http.server.RouteProcessor; import jj.http.server.ServableResource; import jj.http.server.resource.StaticResource; import jj.http.server.uri.Route; import jj.http.server.uri.RouteMatch; import jj.http.server.uri.URIMatch; import jj.resource.ResourceFinder; import jj.resource.ResourceTask; import jj.resource.ResourceThread; /** * @author jason * */ @Singleton public class DocumentScriptEnvironmentRouteProcessor implements RouteProcessor { private final ResourceFinder resourceFinder; private final TaskRunner taskRunner; private final Injector parentInjector; @Inject DocumentScriptEnvironmentRouteProcessor(final ResourceFinder resourceFinder, final TaskRunner taskRunner, final Injector parentInjector) { this.resourceFinder = resourceFinder; this.taskRunner = taskRunner; this.parentInjector = parentInjector; } @Override public void process(final RouteMatch routeMatch, final HttpServerRequest request, final HttpServerResponse response) { Route route = routeMatch.route(); DocumentScriptEnvironment dse = findDocumentScriptEnvironment(route.mapping()); if (dse == null) { taskRunner.execute(new ResourceTask("Loading document script at " + route.mapping()) { @Override protected void run() throws Exception { preloadResources(); DocumentScriptEnvironment dse = resourceFinder.loadResource(DocumentScriptEnvironment.class, Virtual, route.mapping()); serve(dse, request, response); } }); } else { serve(dse, request, response); } } @ResourceThread @Override public <T extends ServableResource> T loadResource(final Class<T> resourceClass, final URIMatch uriMatch, final Route route) { assert resourceClass == DocumentScriptEnvironment.class; return resourceFinder.loadResource(resourceClass, Virtual, route.mapping()); } private void preloadResources() { // since we're in the IO thread already and we might need this stuff soon, as a small // optimization to avoid jumping right back into the I/O thread after dispatching this // into the script thread, we just "prime the pump" resourceFinder.loadResource(StaticResource.class, Assets, JJ_JS); resourceFinder.loadResource(StaticResource.class, Assets, JQUERY_JS); } private DocumentScriptEnvironment findDocumentScriptEnvironment(String name) { return resourceFinder.findResource(DocumentScriptEnvironment.class, Virtual, name); } private void serve(DocumentScriptEnvironment dse, HttpServerRequest request, HttpServerResponse response) { if (dse == null) { response.sendNotFound(); } else if (dse.initializationDidError()) { response.error(dse.initializationError()); } else { parentInjector.createChildInjector(new AbstractModule() { @Override protected void configure() { bind(DocumentScriptEnvironment.class).toInstance(dse); bind(HttpServerRequest.class).toInstance(request); bind(HttpServerResponse.class).toInstance(response); } }).getInstance(DocumentRequestProcessor.class).process(); } } }