PageRenderTime 21ms CodeModel.GetById 12ms app.highlight 7ms RepoModel.GetById 1ms app.codeStats 0ms

/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
 1package com.google.sitebricks.rendering.control;
 2
 3import com.google.inject.Inject;
 4import com.google.sitebricks.Evaluator;
 5import com.google.sitebricks.Renderable;
 6import com.google.sitebricks.Respond;
 7import com.google.sitebricks.StringBuilderRespond;
 8import com.google.sitebricks.rendering.Decorated;
 9import com.google.sitebricks.routing.PageBook;
10
11import java.util.Collections;
12import java.util.Set;
13
14/**
15 * @author John Patterson (jdpatterson@gmail.com)
16 */
17public class DecorateWidget implements Renderable {
18
19  @Inject
20  private PageBook book;
21
22  private ThreadLocal<Class<?>> templateClassLocal = new ThreadLocal<Class<?>>();
23
24  public static String embedNameFor(Class<?> pageClass) {
25    return pageClass.getName().toLowerCase() + "-extend";
26  }
27
28  public DecorateWidget(WidgetChain chain, String expression, Evaluator evaluator) {
29    // do not need any of the compulsory constructor args
30  }
31
32  @Override
33  public void render(Object bound, Respond respond) {
34
35    Class<?> templateClass;
36    Class<?> previousTemplateClass = templateClassLocal.get();
37    try {
38      if (previousTemplateClass == null) {
39        templateClass = nextDecoratedClassInHierarchy(null, bound.getClass());
40      } else {
41        // get the extension subclass above the last
42        templateClass = nextDecoratedClassInHierarchy(previousTemplateClass, bound.getClass());
43        if (templateClass == null) {
44          throw new IllegalStateException(
45              "Could not find subclass of " + previousTemplateClass.getName() +
46                  " with @Decorated annotation.");
47        }
48      }
49      templateClassLocal.set(templateClass);
50
51      // get the extension page by name
52      PageBook.Page page = book.forName(DecorateWidget.embedNameFor(templateClass));
53
54      // create a dummy respond to collect the output of the embedded page
55      StringBuilderRespond sbrespond = new StringBuilderRespond(bound);
56      EmbeddedRespond embedded = new EmbeddedRespond(null, sbrespond);
57      page.widget().render(bound, embedded);
58
59      // write the head and content to the real respond
60      respond.writeToHead(embedded.toHeadString());
61      respond.write(embedded.toString());
62
63      // free some memory
64      embedded.clear();
65    } finally {
66      // we are finished with this extension
67      if (previousTemplateClass == null) {
68        templateClassLocal.set(null);
69      }
70    }
71  }
72
73  // recursively find the next superclass with an @Decorated annotation
74  private Class<?> nextDecoratedClassInHierarchy(Class<?> previousTemplateClass,
75                                                 Class<?> candidate) {
76    if (candidate == previousTemplateClass) {
77      // terminate the recursion
78      return null;
79    } else if (candidate == Object.class) {
80      // this should never happen - we should terminate recursion first
81      throw new IllegalStateException("Did not find previous extension");
82    } else {
83      boolean isDecorated = candidate.isAnnotationPresent(Decorated.class);
84
85      if (isDecorated)
86        return candidate;
87      else
88        return nextDecoratedClassInHierarchy(previousTemplateClass, candidate.getSuperclass());
89    }
90  }
91
92  @Override
93  public <T extends Renderable> Set<T> collect(Class<T> clazz) {
94    return Collections.emptySet();
95  }
96}