package knorxx.framework.generator.application; import com.google.common.base.Optional; import com.google.common.collect.Lists; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import knorxx.framework.generator.GenerationRoots; import knorxx.framework.generator.GenerationUnit; import knorxx.framework.generator.library.LibraryDetector; import knorxx.framework.generator.library.LibraryUrls; import knorxx.framework.generator.reloading.annotation.Reloadable; import knorxx.framework.generator.web.KnorxxApplication; import knorxx.framework.generator.web.WebJavaScriptGenerator; import knorxx.framework.generator.web.client.ErrorHandler; import knorxx.framework.generator.web.client.WebPage; import knorxx.framework.generator.web.client.webpage.PageArranger; import knorxx.framework.generator.web.client.webpage.annotation.WebPageArranger; import knorxx.framework.generator.web.server.json.JsonHelper; import knorxx.framework.generator.web.server.rtti.RttiGenerationResult; import knorxx.framework.generator.web.server.rtti.RttiGenerator; import knorxx.framework.generator.web.server.rtti.UrlResolver; import org.joda.time.DateTime; import org.rendersnake.HtmlCanvas; import org.rendersnake.Renderable; /** * * @author sj */ public class KnorxxApplicationGenerator { private final KnorxxApplication knorxxApplication; private final String allowedReloadPackage; private final String allowedGenerationPackage; private final List<Class<?>> webPageClasses; private final LibraryDetector libraryDetector; private final UrlResolver urlResolver; private final JsonHelper jsonHelper; private final knorxx.framework.generator.web.client.JsonHelper javaScriptJsonHelper; private final ErrorHandler javaScriptErrorHandler; private final String jsonRpcUrl; public KnorxxApplicationGenerator(KnorxxApplication knorxxApplication, String allowedReloadPackage, String allowedGenerationPackage, List<Class<?>> webPageClasses, LibraryDetector libraryDetector, UrlResolver urlResolver, JsonHelper jsonHelper, knorxx.framework.generator.web.client.JsonHelper javaScriptJsonHelper, ErrorHandler javaScriptErrorHandler, String jsonRpcUrl) { this.knorxxApplication = knorxxApplication; this.allowedReloadPackage = allowedReloadPackage; this.allowedGenerationPackage = allowedGenerationPackage; this.webPageClasses = webPageClasses; this.libraryDetector = libraryDetector; this.urlResolver = urlResolver; this.jsonHelper = jsonHelper; this.javaScriptJsonHelper = javaScriptJsonHelper; this.javaScriptErrorHandler = javaScriptErrorHandler; this.jsonRpcUrl = jsonRpcUrl; } public ApplicationResult generateWebPage(GenerationRoots generationRoots, Class<?> webPageClass, Optional<Collection<PageArranger>> pageArrangers, String contextPath, PopulatableCache populatableCache) throws IOException { ApplicationResult result = new ApplicationResult(); result.setApplicationName(knorxxApplication.getName()); result.setMainClassName(webPageClass.getName()); result.setErrorHandlerClassName(javaScriptErrorHandler.getClass().getName()); result.setJsonHelperClassName(javaScriptJsonHelper.getClass().getName()); WebJavaScriptGenerator generator = new WebJavaScriptGenerator(generationRoots, allowedGenerationPackage, allowedReloadPackage, contextPath + "/", jsonRpcUrl.substring(1), libraryDetector); GenerationUnit unit = generator.generateAll(Lists.<Class<?>>newArrayList(webPageClass, javaScriptJsonHelper.getClass(), javaScriptErrorHandler.getClass())); result.setLibraryCssUrls(unit.getLibraryUrls().getCssUrls()); result.setLibraryJavaScriptUrls(unit.getLibraryUrls().getJavaScriptUrls()); RttiGenerator rttiGenerator = new RttiGenerator(); RttiGenerationResult rttiGenerationResult = rttiGenerator.getJavaScriptSource( WebPage.class.getPackage().getName() + ".RunTimeTypeInformation", webPageClasses, urlResolver, new DateTime()); LibraryUrls cacheUrls = populatableCache.populate(unit, rttiGenerationResult, urlResolver); result.setCssUrls(cacheUrls.getCssUrls()); result.setJavaScriptUrls(cacheUrls.getJavaScriptUrls()); result.setWebPageModelJson("{}"); if(pageArrangers.isPresent()) { for (PageArranger pageArranger : pageArrangers.get()) { if (webPageClass.getAnnotation(WebPageArranger.class) != null && webPageClass.getAnnotation(WebPageArranger.class).value().getName().equals(pageArranger.getClass().getName())) { Map<String, Object> webPageModel = new HashMap<>(); pageArranger.initialize(webPageModel); result.setWebPageModelJson(jsonHelper.toJson(webPageModel)); HtmlCanvas htmlCanvas = new HtmlCanvas(); renderPageArranger(pageArranger, htmlCanvas, generator.getClassLoader()); result.setPreRenderedHtml(htmlCanvas.toHtml()); break; } } } return result; } private void renderPageArranger(Renderable pageArranger, HtmlCanvas htmlCanvas, ClassLoader classLoader) throws IOException { Method renderOnMethod = null; try { renderOnMethod = pageArranger.getClass().getMethod("renderOn", HtmlCanvas.class); } catch (NoSuchMethodException | SecurityException ex) { throw new IllegalStateException("Can't find the method renderOn(HtmlCanvas) of a PageArranger. " + "This might be cause by an API change!"); } boolean reloadableRenderOn = renderOnMethod.getAnnotation(Reloadable.class) != null; if (reloadableRenderOn) { try { final Object pageArrangerInstance = classLoader.loadClass(pageArranger.getClass().getName()).newInstance(); pageArranger = new Renderable() { @Override public void renderOn(HtmlCanvas html) throws IOException { try { Method renderOnMethod = pageArrangerInstance.getClass().getMethod("renderOn", HtmlCanvas.class); renderOnMethod.invoke(pageArrangerInstance, html); } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { throw new IllegalStateException("Can't call renderOn(HtmlCanvas) on the reloaded PageArranger instance!", ex); } } }; } catch (SecurityException | InstantiationException | IllegalAccessException | ClassNotFoundException ex) { throw new IllegalStateException("Can't instantiate a PageArranger with a renderOn(HtmlCanvas) " + "method marked with @Reloadable! Does it have a default constructor?"); } } pageArranger.renderOn(htmlCanvas); } }