diff --git a/pom.xml b/pom.xml index bf2c651e..7fab9be7 100644 --- a/pom.xml +++ b/pom.xml @@ -282,9 +282,9 @@ - google-snapshots - Sonatype OSS Nexus Snapshots - https://oss.sonatype.org/content/repositories/google-snapshots + ${snapshots.id} + ${snapshots.name} + ${snapshots.url} google-with-staging diff --git a/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/Custom.java b/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/Custom.java new file mode 100644 index 00000000..99621635 --- /dev/null +++ b/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/Custom.java @@ -0,0 +1,19 @@ +package com.google.sitebricks.example; + +public class Custom { + + private String encap; + + public Custom() { + encap = "encapsulated valuev"; + } + + public Custom(String value) { + encap = value; + } + + @Override + public String toString() { + return encap.toString(); + } +} diff --git a/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/CustomConverter.java b/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/CustomConverter.java new file mode 100644 index 00000000..f9345862 --- /dev/null +++ b/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/CustomConverter.java @@ -0,0 +1,36 @@ +package com.google.sitebricks.example; + +import com.google.sitebricks.At; +import com.google.sitebricks.http.Get; +import com.google.sitebricks.http.Post; + +@At("/customConvertion") +public class CustomConverter { + + public static final String INITIAL_VALUE = "initial value"; + private Custom custom; + + public CustomConverter() { + custom = new Custom(INITIAL_VALUE); + } + + @Get + public void get() { + System.out.println("custom converter sample. woot!"); + } + + @Post + public void post() { + System.out.println("posted custom value: " + custom); + } + + public Custom getTestValue() { + return custom; + } + + public void setTestValue(Custom value) { + System.out.println("*************************** " + value); + custom = value; + } + +} diff --git a/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/CustomToStringConverter.java b/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/CustomToStringConverter.java new file mode 100644 index 00000000..8c3de169 --- /dev/null +++ b/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/CustomToStringConverter.java @@ -0,0 +1,17 @@ +package com.google.sitebricks.example; + +import com.google.sitebricks.conversion.Converter; + +public class CustomToStringConverter implements Converter { + + @Override + public Custom to(String source) { + return new Custom(source); + } + + @Override + public String from(Custom target) { + return target.toString(); + } + +} diff --git a/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/PageWithReply.java b/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/PageWithReply.java new file mode 100644 index 00000000..4ff0830b --- /dev/null +++ b/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/PageWithReply.java @@ -0,0 +1,13 @@ +package com.google.sitebricks.example; + +import com.google.sitebricks.headless.Reply; +import com.google.sitebricks.http.Get; + +public class PageWithReply { + + @Get + public Object get() { + return Reply.saying().status(678); + + } +} diff --git a/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/SitebricksConfig.java b/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/SitebricksConfig.java index 40111d41..04f6840f 100644 --- a/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/SitebricksConfig.java +++ b/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/SitebricksConfig.java @@ -23,6 +23,8 @@ import java.util.Locale; import java.util.Map; +import org.apache.velocity.runtime.directive.VelocimacroProxy; + /** * @author Dhanji R. Prasanna (dhanji@gmail.com) */ @@ -62,6 +64,7 @@ protected void configureSitebricks() { install(new StatModule("/stats")); converter(new DateConverters.DateStringConverter(DEFAULT_DATE_TIME_FORMAT)); + converter(new CustomToStringConverter()); install(new AwareModule() { @Override @@ -82,6 +85,7 @@ private void bindExplicitly() { at("/repeat").show(Repeat.class); at("/showif").show(ShowIf.class); at("/dynamic.js").show(DynamicJs.class); + at("/pageWithReply").show(PageWithReply.class); at("/conversion").show(Conversion.class); @@ -109,6 +113,8 @@ private void bindExplicitly() { // templating by extension at("/template").show(DecoratedPage.class); + at("/velocitySample").show(VelocitySample.class); + at("/customConvertion").show(CustomConverter.class); embed(HelloWorld.class).as("Hello"); } diff --git a/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/VelocitySample.java b/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/VelocitySample.java new file mode 100644 index 00000000..00e64b9d --- /dev/null +++ b/sitebricks-acceptance-tests/src/main/java/com/google/sitebricks/example/VelocitySample.java @@ -0,0 +1,21 @@ +package com.google.sitebricks.example; + +import com.google.sitebricks.http.Get; + +public class VelocitySample { + + public static final String MSG = "Yaba Daba Doo!"; + + @Get + public void get() { + System.out.println("velocity sample. woot!"); + } + + public String getName() { + return "fred flinstone"; + } + + public String getMessage() { + return MSG; + } +} diff --git a/sitebricks-acceptance-tests/src/main/resources/CustomConverter.html b/sitebricks-acceptance-tests/src/main/resources/CustomConverter.html new file mode 100644 index 00000000..2a96231c --- /dev/null +++ b/sitebricks-acceptance-tests/src/main/resources/CustomConverter.html @@ -0,0 +1,16 @@ + + +custom conversion sample + + +

velocity sample

+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/sitebricks-acceptance-tests/src/main/resources/PageWithReply.html b/sitebricks-acceptance-tests/src/main/resources/PageWithReply.html new file mode 100644 index 00000000..3ab84e84 --- /dev/null +++ b/sitebricks-acceptance-tests/src/main/resources/PageWithReply.html @@ -0,0 +1,5 @@ + + +

for this test, the template will never be displayed because the page get method will always return a non-200 status code Reply

+ + \ No newline at end of file diff --git a/sitebricks-acceptance-tests/src/main/resources/VelocitySample.vm b/sitebricks-acceptance-tests/src/main/resources/VelocitySample.vm new file mode 100644 index 00000000..aefe3361 --- /dev/null +++ b/sitebricks-acceptance-tests/src/main/resources/VelocitySample.vm @@ -0,0 +1,11 @@ + + +velocity sample + + +

velocity sample

+

$page.name

+

$page.message

+ + + \ No newline at end of file diff --git a/sitebricks-acceptance-tests/src/main/resources/velocity.properties b/sitebricks-acceptance-tests/src/main/resources/velocity.properties new file mode 100644 index 00000000..3ca9dd56 --- /dev/null +++ b/sitebricks-acceptance-tests/src/main/resources/velocity.properties @@ -0,0 +1,2 @@ +resource.loader = class +class.resource.loader.class = org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader \ No newline at end of file diff --git a/sitebricks-acceptance-tests/src/test/java/com/google/sitebricks/acceptance/CustomConverterAcceptanceTest.java b/sitebricks-acceptance-tests/src/test/java/com/google/sitebricks/acceptance/CustomConverterAcceptanceTest.java new file mode 100644 index 00000000..a12d1896 --- /dev/null +++ b/sitebricks-acceptance-tests/src/test/java/com/google/sitebricks/acceptance/CustomConverterAcceptanceTest.java @@ -0,0 +1,30 @@ +package com.google.sitebricks.acceptance; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.testng.annotations.Test; + +import com.google.sitebricks.acceptance.page.CustomConversionPage; +import com.google.sitebricks.acceptance.util.AcceptanceTest; +import com.google.sitebricks.example.CustomConverter; + +@Test(suiteName = AcceptanceTest.SUITE) +public class CustomConverterAcceptanceTest { + + public void hasConvertedTypes() { + WebDriver driver = AcceptanceTest.createWebDriver(); + CustomConversionPage page = CustomConversionPage.open(driver); + + WebElement testValueInputField = page.getTestValue(); + String testValue = testValueInputField.getAttribute("value"); + assert testValue.equals(CustomConverter.INITIAL_VALUE) : "expected " + CustomConverter.INITIAL_VALUE + " but was " + testValue; + + + String expected = "new value from test"; + testValueInputField.sendKeys(expected); + testValueInputField.submit(); + System.out.println(driver.getPageSource()); + + assert testValueInputField.getAttribute("value").equals(CustomConverter.INITIAL_VALUE + expected) : "expected " + CustomConverter.INITIAL_VALUE + expected + " but was " + testValue; + } +} diff --git a/sitebricks-acceptance-tests/src/test/java/com/google/sitebricks/acceptance/PageWithReplyAcceptanceTest.java b/sitebricks-acceptance-tests/src/test/java/com/google/sitebricks/acceptance/PageWithReplyAcceptanceTest.java new file mode 100644 index 00000000..ca807f51 --- /dev/null +++ b/sitebricks-acceptance-tests/src/test/java/com/google/sitebricks/acceptance/PageWithReplyAcceptanceTest.java @@ -0,0 +1,23 @@ +package com.google.sitebricks.acceptance; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; + +import org.testng.annotations.Test; + +import com.google.sitebricks.acceptance.util.AcceptanceTest; + +@Test(suiteName = AcceptanceTest.SUITE) +public class PageWithReplyAcceptanceTest { + + public void shouldReturnCustomStatusCode() throws IOException { + URL url = new URL(AcceptanceTest.BASE_URL + "/pageWithReply"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + int expected = 678; + int actual = connection.getResponseCode(); + + assert actual == expected : "expected custom response code '" + expected + "' but was '" + actual + "'"; + } +} diff --git a/sitebricks-acceptance-tests/src/test/java/com/google/sitebricks/acceptance/VelocitySampleAcceptanceTest.java b/sitebricks-acceptance-tests/src/test/java/com/google/sitebricks/acceptance/VelocitySampleAcceptanceTest.java new file mode 100644 index 00000000..72be5382 --- /dev/null +++ b/sitebricks-acceptance-tests/src/test/java/com/google/sitebricks/acceptance/VelocitySampleAcceptanceTest.java @@ -0,0 +1,24 @@ +package com.google.sitebricks.acceptance; + +import org.openqa.selenium.WebDriver; +import org.testng.annotations.Test; + +import com.google.sitebricks.acceptance.page.VelocitySamplePage; +import com.google.sitebricks.acceptance.util.AcceptanceTest; + +@Test(suiteName = AcceptanceTest.SUITE) +public class VelocitySampleAcceptanceTest { + + public void shouldRenderDynamicTextFromVelocitySample() { + WebDriver driver = AcceptanceTest.createWebDriver(); + VelocitySamplePage page = VelocitySamplePage.open(driver, "/velocitySample"); + + assertVelocitySampleContent(page); + } + + private void assertVelocitySampleContent(VelocitySamplePage page) { + String title = page.getTitle(); + assert title.equals("velocity sample") : title + " != \"velocity sample\"\n" + page.getContent(); + assert page.hasMessage() : "did not have dynamic text"; + } +} diff --git a/sitebricks-acceptance-tests/src/test/java/com/google/sitebricks/acceptance/page/CustomConversionPage.java b/sitebricks-acceptance-tests/src/test/java/com/google/sitebricks/acceptance/page/CustomConversionPage.java new file mode 100644 index 00000000..a7aaccf3 --- /dev/null +++ b/sitebricks-acceptance-tests/src/test/java/com/google/sitebricks/acceptance/page/CustomConversionPage.java @@ -0,0 +1,22 @@ +package com.google.sitebricks.acceptance.page; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.PageFactory; + +import com.google.sitebricks.acceptance.util.AcceptanceTest; + +public class CustomConversionPage { + + private WebElement testValue; + + public static CustomConversionPage open(WebDriver driver) { + driver.get(AcceptanceTest.BASE_URL + "/customConvertion"); + return PageFactory.initElements(driver, CustomConversionPage.class); + } + + public WebElement getTestValue() { + return testValue; + } + +} diff --git a/sitebricks-acceptance-tests/src/test/java/com/google/sitebricks/acceptance/page/VelocitySamplePage.java b/sitebricks-acceptance-tests/src/test/java/com/google/sitebricks/acceptance/page/VelocitySamplePage.java new file mode 100644 index 00000000..ae49ecde --- /dev/null +++ b/sitebricks-acceptance-tests/src/test/java/com/google/sitebricks/acceptance/page/VelocitySamplePage.java @@ -0,0 +1,33 @@ +package com.google.sitebricks.acceptance.page; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.support.PageFactory; + +import com.google.sitebricks.acceptance.util.AcceptanceTest; +import com.google.sitebricks.example.VelocitySample; + +public class VelocitySamplePage { + private final WebDriver driver; + + public VelocitySamplePage(WebDriver driver) { + this.driver = driver; + } + + public static VelocitySamplePage open(WebDriver driver, String url) { + driver.get(AcceptanceTest.BASE_URL + url); + return PageFactory.initElements(driver, VelocitySamplePage.class); + } + + public String getTitle() { + return driver.getTitle(); + } + + public boolean hasMessage() { +// System.out.println(driver.getPageSource()); + return driver.getPageSource().contains(VelocitySample.MSG); + } + + public String getContent() { + return driver.getPageSource(); + } +} diff --git a/sitebricks-async/pom.xml b/sitebricks-async/pom.xml index 1d38cb05..d4a66bb1 100644 --- a/sitebricks-async/pom.xml +++ b/sitebricks-async/pom.xml @@ -41,9 +41,9 @@ standard Nexus OSS repository infrastructure --> - google-snapshots - Sonatype OSS Nexus Snapshots - https://oss.sonatype.org/content/repositories/google-snapshots + ${snapshots.id} + ${snapshots.name} + ${snapshots.url} google-with-staging diff --git a/sitebricks/pom.xml b/sitebricks/pom.xml index 8c2173e3..9aee8ed5 100644 --- a/sitebricks/pom.xml +++ b/sitebricks/pom.xml @@ -16,6 +16,22 @@ jdk15 test + + org.apache.velocity + velocity + 1.7 + + + org.apache.velocity + velocity-tools + 2.0 + + + oro + oro + 2.0.8 + runtime + com.google.sitebricks sitebricks-converter @@ -132,13 +148,30 @@ + + + + + org.apache.maven.plugins + maven-source-plugin + + + + jar + + + + + + + - google-snapshots - Sonatype OSS Nexus Snapshots - https://oss.sonatype.org/content/repositories/google-snapshots + ${snapshots.id} + ${snapshots.name} + ${snapshots.url} google-with-staging diff --git a/sitebricks/src/main/java/com/google/sitebricks/ScanAndCompileBootstrapper.java b/sitebricks/src/main/java/com/google/sitebricks/ScanAndCompileBootstrapper.java index 50a1a41d..2a5aab5e 100644 --- a/sitebricks/src/main/java/com/google/sitebricks/ScanAndCompileBootstrapper.java +++ b/sitebricks/src/main/java/com/google/sitebricks/ScanAndCompileBootstrapper.java @@ -115,12 +115,14 @@ public void start() { } private void extendedPages(Set pagesToCompile) { + Set pageExtensions = Sets.newHashSet(); for (Page page : pagesToCompile) { if (page.pageClass().isAnnotationPresent(Decorated.class)) { // recursively add extension pages - analyseExtension(pagesToCompile, page.pageClass()); + analyseExtension(pageExtensions, page.pageClass()); } } + pagesToCompile.addAll(pageExtensions); } //processes all explicit bindings, including static resources. @@ -206,8 +208,9 @@ private Set scanPagesToCompile(Set> set) { return pagesToCompile; } - private void analyseExtension(Set pagesToCompile, Class extendClass) { + private void analyseExtension(Set pagesToCompile, final Class extendClassArgument) { // store the page with a special page name used by ExtendWidget + Class extendClass = extendClassArgument; pagesToCompile.add(pageBook.decorate(extendClass)); // recursively analyse super class @@ -221,7 +224,7 @@ else if (extendClass.isAnnotationPresent(Show.class)) { return; } } - throw new IllegalStateException("Could not find super class annotated with @Show"); + throw new IllegalStateException("Could not find super class annotated with @Show on parent of class: " + extendClassArgument); } private void compilePages(Set pagesToCompile) { diff --git a/sitebricks/src/main/java/com/google/sitebricks/Template.java b/sitebricks/src/main/java/com/google/sitebricks/Template.java index 27bf3014..68e6b828 100644 --- a/sitebricks/src/main/java/com/google/sitebricks/Template.java +++ b/sitebricks/src/main/java/com/google/sitebricks/Template.java @@ -21,7 +21,7 @@ public String getText() { } public static enum Kind { - HTML, XML, FLAT, MVEL, FREEMARKER; + HTML, XML, FLAT, MVEL, FREEMARKER, VELOCITY; /** * Returns whether a given template should be treated as html, xml or flat @@ -36,6 +36,8 @@ else if (template.endsWith(".mvel")) return MVEL; else if (template.endsWith(".fml")) return FREEMARKER; + else if (template.endsWith(".vm")) + return VELOCITY; else return FLAT; } diff --git a/sitebricks/src/main/java/com/google/sitebricks/TemplateLoader.java b/sitebricks/src/main/java/com/google/sitebricks/TemplateLoader.java index 2566d2d1..f0ff815c 100644 --- a/sitebricks/src/main/java/com/google/sitebricks/TemplateLoader.java +++ b/sitebricks/src/main/java/com/google/sitebricks/TemplateLoader.java @@ -16,7 +16,7 @@ public class TemplateLoader { private final Provider context; private final String[] fileNameTemplates = new String[] { "%s.html", "%s.xhtml", "%s.xml", - "%s.txt", "%s.fml", "%s.mvel" }; + "%s.txt", "%s.fml", "%s.mvel", "%s.vm" }; @Inject public TemplateLoader(Provider context) { diff --git a/sitebricks/src/main/java/com/google/sitebricks/compiler/Compilers.java b/sitebricks/src/main/java/com/google/sitebricks/compiler/Compilers.java index 684f5683..055dd6e4 100644 --- a/sitebricks/src/main/java/com/google/sitebricks/compiler/Compilers.java +++ b/sitebricks/src/main/java/com/google/sitebricks/compiler/Compilers.java @@ -23,6 +23,8 @@ public interface Compilers { Renderable compileMvel(Class page, String template); Renderable compileFreemarker( Class page, String text ); + + Renderable compileVelocity(Class page, String template); /** * Performs static analysis of the given page class to diff --git a/sitebricks/src/main/java/com/google/sitebricks/compiler/StandardCompilers.java b/sitebricks/src/main/java/com/google/sitebricks/compiler/StandardCompilers.java index 087c53ea..db0e1aeb 100644 --- a/sitebricks/src/main/java/com/google/sitebricks/compiler/StandardCompilers.java +++ b/sitebricks/src/main/java/com/google/sitebricks/compiler/StandardCompilers.java @@ -1,5 +1,9 @@ package com.google.sitebricks.compiler; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Map; + import com.google.inject.Inject; import com.google.inject.Singleton; import com.google.sitebricks.Bricks; @@ -9,6 +13,9 @@ import com.google.sitebricks.Template; import com.google.sitebricks.TemplateLoader; import com.google.sitebricks.compiler.template.MvelTemplateCompiler; +import com.google.sitebricks.compiler.template.VelocityContextProvider; +import com.google.sitebricks.compiler.template.VelocityEngineProvider; +import com.google.sitebricks.compiler.template.VelocityTemplateCompiler; import com.google.sitebricks.compiler.template.freemarker.FreemarkerTemplateCompiler; import com.google.sitebricks.headless.Reply; import com.google.sitebricks.rendering.Decorated; @@ -16,10 +23,6 @@ import com.google.sitebricks.routing.PageBook; import com.google.sitebricks.routing.SystemMetrics; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.Map; - /** * A factory for internal template compilers. * @@ -32,15 +35,20 @@ class StandardCompilers implements Compilers { private final SystemMetrics metrics; private final Map> httpMethods; private final TemplateLoader loader; +private final VelocityEngineProvider velocityEngineProvider; +private final VelocityContextProvider velocityContextProvider; @Inject public StandardCompilers(WidgetRegistry registry, PageBook pageBook, SystemMetrics metrics, - @Bricks Map> httpMethods, TemplateLoader loader) { + @Bricks Map> httpMethods, TemplateLoader loader, VelocityEngineProvider velocityEngineProvider, + VelocityContextProvider velocityContextProvider) { this.registry = registry; this.pageBook = pageBook; this.metrics = metrics; this.httpMethods = httpMethods; this.loader = loader; + this.velocityEngineProvider = velocityEngineProvider; + this.velocityContextProvider = velocityContextProvider; } public Renderable compileXml(Class page, String template) { @@ -67,6 +75,11 @@ public Renderable compileMvel(Class page, String template) { public Renderable compileFreemarker( Class page, String template ) { return new FreemarkerTemplateCompiler(page).compile(template); } + + @Override + public Renderable compileVelocity(Class page, String template) { + return new VelocityTemplateCompiler(velocityEngineProvider, velocityContextProvider).compile(template); + } // TODO(dhanji): Feedback errors as return rather than throwing. public void analyze(Class page) { @@ -151,8 +164,10 @@ public Renderable compile(Class templateClass) { case FREEMARKER: widget = compileFreemarker(templateClass, template.getText()); break; + case VELOCITY: + widget = compileVelocity(templateClass, template.getText()); + break; } return widget; } - } diff --git a/sitebricks/src/main/java/com/google/sitebricks/compiler/template/VelocityContextProvider.java b/sitebricks/src/main/java/com/google/sitebricks/compiler/template/VelocityContextProvider.java new file mode 100644 index 00000000..63a0000a --- /dev/null +++ b/sitebricks/src/main/java/com/google/sitebricks/compiler/template/VelocityContextProvider.java @@ -0,0 +1,22 @@ +package com.google.sitebricks.compiler.template; + +import javax.inject.Provider; +import javax.inject.Singleton; + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.tools.ToolManager; + +public class VelocityContextProvider implements Provider { + + @Override + @Singleton + public VelocityContext get() { + try { + ToolManager velocityToolManager = new ToolManager(); + velocityToolManager.configure("velocity-tools.xml"); + return new VelocityContext(velocityToolManager.createContext()); + } catch (RuntimeException e) { + return new VelocityContext(); + } + } +} diff --git a/sitebricks/src/main/java/com/google/sitebricks/compiler/template/VelocityEngineProvider.java b/sitebricks/src/main/java/com/google/sitebricks/compiler/template/VelocityEngineProvider.java new file mode 100644 index 00000000..270339a7 --- /dev/null +++ b/sitebricks/src/main/java/com/google/sitebricks/compiler/template/VelocityEngineProvider.java @@ -0,0 +1,32 @@ +package com.google.sitebricks.compiler.template; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import javax.inject.Singleton; + +import org.apache.velocity.app.VelocityEngine; + +import com.google.inject.Provider; + + +public class VelocityEngineProvider implements Provider { + + @Override + @Singleton + public VelocityEngine get() { + Properties properties = new Properties(); + try { + InputStream propertyStream = getClass().getResourceAsStream("/velocity.properties"); + if (propertyStream != null) + properties.load(propertyStream); + } catch (IOException e) { + throw new RuntimeException(e); + } + + VelocityEngine velocityEngine = new VelocityEngine(properties); + return velocityEngine; + } + +} diff --git a/sitebricks/src/main/java/com/google/sitebricks/compiler/template/VelocityTemplateCompiler.java b/sitebricks/src/main/java/com/google/sitebricks/compiler/template/VelocityTemplateCompiler.java new file mode 100644 index 00000000..4278d737 --- /dev/null +++ b/sitebricks/src/main/java/com/google/sitebricks/compiler/template/VelocityTemplateCompiler.java @@ -0,0 +1,44 @@ +package com.google.sitebricks.compiler.template; + +import java.io.StringWriter; +import java.util.Set; + +import javax.inject.Inject; + +import org.apache.velocity.VelocityContext; + +import com.google.common.collect.ImmutableSet; +import com.google.sitebricks.Renderable; +import com.google.sitebricks.Respond; + +public class VelocityTemplateCompiler { + + private final VelocityEngineProvider provider; + private final VelocityContextProvider velocityContextProvider; + + @Inject + public VelocityTemplateCompiler(VelocityEngineProvider provider, VelocityContextProvider velocityContextProvider) { + this.provider = provider; + this.velocityContextProvider = velocityContextProvider; + } + + public Renderable compile(final String templateContent) { + + return new Renderable() { + + @Override + public void render(Object bound, Respond respond) { + VelocityContext context = velocityContextProvider.get(); + context.put("page", bound); + StringWriter writer = new StringWriter(); + provider.get().evaluate(context, writer, "", templateContent); + respond.write(writer.toString()); + } + + @Override + public Set collect(Class clazz) { + return ImmutableSet.of(); + } + }; + } +} diff --git a/sitebricks/src/main/java/com/google/sitebricks/rendering/control/DecorateWidget.java b/sitebricks/src/main/java/com/google/sitebricks/rendering/control/DecorateWidget.java index 3e487b46..69490a1a 100644 --- a/sitebricks/src/main/java/com/google/sitebricks/rendering/control/DecorateWidget.java +++ b/sitebricks/src/main/java/com/google/sitebricks/rendering/control/DecorateWidget.java @@ -22,7 +22,12 @@ public class DecorateWidget implements Renderable { private ThreadLocal> templateClassLocal = new ThreadLocal>(); public static String embedNameFor(Class pageClass) { - return pageClass.getName().toLowerCase() + "-extend"; + String lowerCaseClassName = pageClass.getName().toLowerCase(); + int indexOf = lowerCaseClassName.indexOf("$$enhancerbyguice"); + if (indexOf > 0) { + lowerCaseClassName = lowerCaseClassName.substring(0, indexOf); + } + return lowerCaseClassName + "-extend"; } public DecorateWidget(WidgetChain chain, String expression, Evaluator evaluator){ diff --git a/sitebricks/src/main/java/com/google/sitebricks/rendering/control/EmbeddedRespondFactory.java b/sitebricks/src/main/java/com/google/sitebricks/rendering/control/EmbeddedRespondFactory.java index 74857d2d..cc010649 100644 --- a/sitebricks/src/main/java/com/google/sitebricks/rendering/control/EmbeddedRespondFactory.java +++ b/sitebricks/src/main/java/com/google/sitebricks/rendering/control/EmbeddedRespondFactory.java @@ -10,9 +10,9 @@ * @author Dhanji R. Prasanna (dhanji@gmail com) */ @Immutable class EmbeddedRespondFactory { - private final Respond respond = new StringBuilderRespond(new Object()); public EmbeddedRespond get(Map arguments) { + Respond respond = new StringBuilderRespond(new Object()); return new EmbeddedRespond(arguments, respond); } } diff --git a/sitebricks/src/main/java/com/google/sitebricks/routing/DefaultPageBook.java b/sitebricks/src/main/java/com/google/sitebricks/routing/DefaultPageBook.java index f3199fd5..17c3d928 100644 --- a/sitebricks/src/main/java/com/google/sitebricks/routing/DefaultPageBook.java +++ b/sitebricks/src/main/java/com/google/sitebricks/routing/DefaultPageBook.java @@ -1,5 +1,24 @@ package com.google.sitebricks.routing; +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicReference; + +import net.jcip.annotations.GuardedBy; +import net.jcip.annotations.ThreadSafe; + +import org.jetbrains.annotations.Nullable; + +import com.google.common.base.Objects; import com.google.common.base.Preconditions; import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; @@ -25,22 +44,6 @@ import com.google.sitebricks.http.negotiate.Negotiation; import com.google.sitebricks.rendering.Strings; import com.google.sitebricks.rendering.control.DecorateWidget; -import net.jcip.annotations.GuardedBy; -import net.jcip.annotations.ThreadSafe; -import org.jetbrains.annotations.Nullable; - -import java.lang.annotation.Annotation; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicReference; /** * contains active uri/widget mappings @@ -597,13 +600,20 @@ public boolean equals(Object o) { Page that = (Page) o; - return this.clazz.equals(that.pageClass()); + return this.clazz.equals(that.pageClass()) && isDecorated() == that.isDecorated(); } @Override public int hashCode() { return clazz.hashCode(); } + + @Override + public String toString() { + return Objects.toStringHelper(PageTuple.class).add("clazz", clazz).add("isDecorated", extension) + .add("uri", uri).toString(); + } + } private static class MethodTuple implements Action { diff --git a/sitebricks/src/main/java/com/google/sitebricks/routing/WidgetRoutingDispatcher.java b/sitebricks/src/main/java/com/google/sitebricks/routing/WidgetRoutingDispatcher.java index 9a19f9cc..9ebc2728 100644 --- a/sitebricks/src/main/java/com/google/sitebricks/routing/WidgetRoutingDispatcher.java +++ b/sitebricks/src/main/java/com/google/sitebricks/routing/WidgetRoutingDispatcher.java @@ -1,5 +1,9 @@ package com.google.sitebricks.routing; +import java.io.IOException; + +import net.jcip.annotations.Immutable; + import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; @@ -8,12 +12,10 @@ import com.google.sitebricks.binding.FlashCache; import com.google.sitebricks.binding.RequestBinder; import com.google.sitebricks.headless.HeadlessRenderer; +import com.google.sitebricks.headless.Reply; import com.google.sitebricks.headless.Request; import com.google.sitebricks.rendering.resource.ResourcesService; import com.google.sitebricks.routing.PageBook.Page; -import net.jcip.annotations.Immutable; - -import java.io.IOException; /** * @author Dhanji R. Prasanna (dhanji@gmail.com) @@ -29,9 +31,8 @@ class WidgetRoutingDispatcher implements RoutingDispatcher { @Inject public WidgetRoutingDispatcher(PageBook book, RequestBinder binder, - ResourcesService resourcesService, - Provider flashCacheProvider, - HeadlessRenderer headlessRenderer) { + ResourcesService resourcesService, + Provider flashCacheProvider, HeadlessRenderer headlessRenderer) { this.headlessRenderer = headlessRenderer; this.book = book; this.binder = binder; @@ -42,7 +43,7 @@ public WidgetRoutingDispatcher(PageBook book, RequestBinder binder, public Object dispatch(Request request, Events event) throws IOException { String uri = request.path(); - //first try dispatching as a static resource service + // first try dispatching as a static resource service Respond respond = resourcesService.serve(uri); if (null != respond) @@ -62,24 +63,22 @@ public Object dispatch(Request request, Events event) throws IOException { if (null == page) page = book.get(uri); - //could not dispatch as there was no match + // could not dispatch as there was no match if (null == page) return null; final Object instance = page.instantiate(); if (page.isHeadless()) { return bindAndReply(request, page, instance); - } else { - respond = new StringBuilderRespond(instance); - - //fire events and render reponders - bindAndRespond(request, page, respond, instance); } - return respond; + // fire events and render reponders + return bindAndRespond(request, page, instance, uri); + } - private Object bindAndReply(Request request, Page page, Object instance) throws IOException { + private Object bindAndReply(Request request, Page page, Object instance) + throws IOException { // bind request (sets request params, etc). binder.bind(request, instance); @@ -87,15 +86,16 @@ private Object bindAndReply(Request request, Page page, Object instance) throws return fireEvent(request, page, instance); } - private void bindAndRespond(Request request, PageBook.Page page, Respond respond, - Object instance) { - //bind request + private Object bindAndRespond(Request request, PageBook.Page page, + Object instance, String uri) throws IOException { + Respond respond = new StringBuilderRespond(instance); + // bind request binder.bind(request, instance); - //fire get/post events + // fire get/post events final Object redirect = fireEvent(request, page, instance); - //render to respond + // render to respond if (null != redirect) { if (redirect instanceof String) @@ -105,19 +105,28 @@ else if (redirect instanceof Class) { // should never be null coz it is validated on compile. respond.redirect(contextualize(request, targetPage.getUri())); + } else if (redirect instanceof Reply) { + // page wants to be headless + return redirect; } else { // Handle page-chaining driven redirection. PageBook.Page targetPage = book.forInstance(redirect); + String redirectUri = targetPage.getUri(); + if (redirect == instance) { + redirectUri = uri; + } // should never be null coz it will be validated at compile time. - flashCacheProvider.get().put(targetPage.getUri(), targetPage); + flashCacheProvider.get().put(redirectUri, targetPage); // Send to the canonical address of the page. This is also // verified at compile, not be a variablized matcher. - respond.redirect(contextualize(request, targetPage.getUri())); + respond.redirect(contextualize(request, redirectUri)); } - } else + } else { page.widget().render(instance, respond); + } + return respond; } // We're sure the request parameter map is a Map diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 54345fd9..c8deb8d4 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -44,9 +44,9 @@ - google-snapshots - Sonatype OSS Nexus Snapshots - https://oss.sonatype.org/content/repositories/google-snapshots + ${snapshots.id} + ${snapshots.name} + ${snapshots.url} google-with-staging diff --git a/stat/pom.xml b/stat/pom.xml index 0387240a..02e913dc 100644 --- a/stat/pom.xml +++ b/stat/pom.xml @@ -76,9 +76,9 @@ - google-snapshots - Sonatype OSS Nexus Snapshots - https://oss.sonatype.org/content/repositories/google-snapshots + ${snapshots.id} + ${snapshots.name} + ${snapshots.url} google-with-staging