/sitebricks/src/main/java/com/google/sitebricks/rendering/control/DecorateWidget.java
http://github.com/dhanji/sitebricks · Java · 96 lines · 67 code · 16 blank · 13 comment · 14 complexity · fcb072571f42e65c700066a90b398f8b MD5 · raw file
- package com.google.sitebricks.rendering.control;
-
- import com.google.inject.Inject;
- import com.google.sitebricks.Evaluator;
- import com.google.sitebricks.Renderable;
- import com.google.sitebricks.Respond;
- import com.google.sitebricks.StringBuilderRespond;
- import com.google.sitebricks.rendering.Decorated;
- import com.google.sitebricks.routing.PageBook;
-
- import java.util.Collections;
- import java.util.Set;
-
- /**
- * @author John Patterson (jdpatterson@gmail.com)
- */
- public class DecorateWidget implements Renderable {
-
- @Inject
- private PageBook book;
-
- private ThreadLocal<Class<?>> templateClassLocal = new ThreadLocal<Class<?>>();
-
- public static String embedNameFor(Class<?> pageClass) {
- return pageClass.getName().toLowerCase() + "-extend";
- }
-
- public DecorateWidget(WidgetChain chain, String expression, Evaluator evaluator) {
- // do not need any of the compulsory constructor args
- }
-
- @Override
- public void render(Object bound, Respond respond) {
-
- Class<?> templateClass;
- Class<?> previousTemplateClass = templateClassLocal.get();
- try {
- if (previousTemplateClass == null) {
- templateClass = nextDecoratedClassInHierarchy(null, bound.getClass());
- } else {
- // get the extension subclass above the last
- templateClass = nextDecoratedClassInHierarchy(previousTemplateClass, bound.getClass());
- if (templateClass == null) {
- throw new IllegalStateException(
- "Could not find subclass of " + previousTemplateClass.getName() +
- " with @Decorated annotation.");
- }
- }
- templateClassLocal.set(templateClass);
-
- // get the extension page by name
- PageBook.Page page = book.forName(DecorateWidget.embedNameFor(templateClass));
-
- // create a dummy respond to collect the output of the embedded page
- StringBuilderRespond sbrespond = new StringBuilderRespond(bound);
- EmbeddedRespond embedded = new EmbeddedRespond(null, sbrespond);
- page.widget().render(bound, embedded);
-
- // write the head and content to the real respond
- respond.writeToHead(embedded.toHeadString());
- respond.write(embedded.toString());
-
- // free some memory
- embedded.clear();
- } finally {
- // we are finished with this extension
- if (previousTemplateClass == null) {
- templateClassLocal.set(null);
- }
- }
- }
-
- // recursively find the next superclass with an @Decorated annotation
- private Class<?> nextDecoratedClassInHierarchy(Class<?> previousTemplateClass,
- Class<?> candidate) {
- if (candidate == previousTemplateClass) {
- // terminate the recursion
- return null;
- } else if (candidate == Object.class) {
- // this should never happen - we should terminate recursion first
- throw new IllegalStateException("Did not find previous extension");
- } else {
- boolean isDecorated = candidate.isAnnotationPresent(Decorated.class);
-
- if (isDecorated)
- return candidate;
- else
- return nextDecoratedClassInHierarchy(previousTemplateClass, candidate.getSuperclass());
- }
- }
-
- @Override
- public <T extends Renderable> Set<T> collect(Class<T> clazz) {
- return Collections.emptySet();
- }
- }