/*
* Copyright 2014 the original author or authors.
*
* 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 bootdragon.demo;
import java.io.IOException;
import java.util.concurrent.Executors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import org.springframework.core.task.support.TaskExecutorAdapter;
import org.springframework.stereotype.Component;
import org.springframework.util.concurrent.ListenableFuture;
import bootdragon.demo.preview.PreviewGif;
import bootdragon.demo.preview.PreviewGifFactory;
import bootdragon.demo.sourcecode.DemoSourceCode;
import bootdragon.demo.sourcecode.DemoSourceCodeFactory;
import bootdragon.demo.sourcecode.DemoSourceCodeRepository;
/**
* Process {@link DemoRequest}s to create demo applications. Demos are created within a
* single thread executor (demos are never created in parallel). A
* {@link DemoCreatorListener} can be used to update a UI during creation.
*
* @author Phillip Webb
*/
@Component
public class DemoCreator {
private static Logger logger = LoggerFactory.getLogger(DemoCreator.class);
private final DemoCreatorListener listener;
private final DemoSourceCodeFactory sourceCodeFactory;
private final PreviewGifFactory previewFactory;
private final DemoSourceCodeRepository sourceCodeRepository;
private final AsyncListenableTaskExecutor executor;
@Autowired
public DemoCreator(DemoCreatorListener listener,
DemoSourceCodeFactory sourceCodeFactory, PreviewGifFactory previewFactory,
DemoSourceCodeRepository sourceCodeRepository) {
this.listener = listener;
this.sourceCodeFactory = sourceCodeFactory;
this.previewFactory = previewFactory;
this.sourceCodeRepository = sourceCodeRepository;
this.executor = new TaskExecutorAdapter(Executors.newSingleThreadExecutor());
}
/**
* Add the given request to the executor queue, returning a {@link ListenableFuture}
* that may be used to detect completion.
* @param request the request
* @return a {@link ListenableFuture} for the created {@link Demo}
*/
public ListenableFuture<Demo> addRequest(DemoRequest request) {
logger.debug("Added request for {} from {}", request.getUser(),
request.getSource());
return this.executor.submitListenable(() -> handleRequest(request));
}
private Demo handleRequest(DemoRequest request) throws Exception {
logger.info("Handling request for {} from {}", request.getUser(),
request.getSource());
this.listener.start(request);
try {
Demo demo = createDemo(request);
this.listener.finish(demo);
logger.debug("Handled request for {} from {}", request.getUser(),
request.getSource());
return demo;
}
catch (Exception ex) {
logger.error("Unable to handler request", ex);
listener.error(ex);
throw ex;
}
}
private Demo createDemo(DemoRequest request) throws IOException {
DemoSourceCode sourceCode = this.sourceCodeFactory.createSourceCode(request);
PreviewGif preview = this.previewFactory.createPreview(request, sourceCode);
String sourceCodeUri = this.sourceCodeRepository.save(sourceCode);
return new Demo(request, sourceCode, sourceCodeUri, preview);
}
}