View Javadoc
1   /**
2    * Copyright By Grandsoft Company Limited.  
3    * 2014年5月19日 下午9:45:14
4    */
5   package gboat2.base.plugin.struts.freemarker;
6   
7   import java.io.File;
8   import java.io.IOException;
9   import java.util.List;
10  
11  import org.apache.commons.lang3.ObjectUtils;
12  import org.apache.struts2.StrutsConstants;
13  import org.apache.struts2.components.template.Template;
14  import org.apache.struts2.components.template.TemplateEngine;
15  import org.apache.struts2.views.freemarker.FreemarkerThemeTemplateLoader;
16  
17  import com.opensymphony.xwork2.inject.Inject;
18  import com.opensymphony.xwork2.util.logging.Logger;
19  import com.opensymphony.xwork2.util.logging.LoggerFactory;
20  
21  import freemarker.cache.FileTemplateLoader;
22  import freemarker.cache.MultiTemplateLoader;
23  import freemarker.cache.TemplateLoader;
24  import gboat2.base.bridge.debug.DefaultDebugHook;
25  import gboat2.base.bridge.exception.DefaultGboatNestedException;
26  
27  /**
28   * Gboat 平台自定义 Struts2 标签模板管理器,需要结合 {@link GboatFreemarkerManager} 一起使用。
29   * <pre>
30   * 在 struts-plugin.xml 中添加了如下配置:
31   * <code>&lt;bean class="gboat2.base.plugin.struts.freemarker.GboatThemeTemplateLoader" /&gt;</code>
32   * </pre>
33   * @date 2014年5月19日
34   * @author <a href="mailto:[email protected]">何明旺</a>
35   * @since 3.0.0-SNAPSHOT
36   */
37  public class GboatThemeTemplateLoader extends FreemarkerThemeTemplateLoader {
38  
39      protected String gboatViewResourcePath;
40      protected MultiTemplateLoader sourceTemplateLoader;
41      
42      // Injected
43      protected String themeExpansionToken;
44      protected TemplateEngine templateEngine;
45      
46  
47      private static final Logger LOG = LoggerFactory.getLogger(GboatThemeTemplateLoader.class);
48  
49      public GboatThemeTemplateLoader() {
50          super();
51          
52          String view = "gboat2.base.view";
53          DefaultDebugHook debugHook = DefaultDebugHook.getInstance();
54          if(debugHook.isBundleDebugEnabled(view)) { // gboat2.base.view 开启了调试模式时,读取其资源文件存放的根目录
55              gboatViewResourcePath = debugHook.getResourcesAbsolutPath(view);    
56              try {
57                  sourceTemplateLoader = new MultiTemplateLoader(new TemplateLoader[] {
58                          new FileTemplateLoader(new File(gboatViewResourcePath), true)
59                      });
60              } catch (IOException e) {
61                  throw new DefaultGboatNestedException(e);
62              }
63          }
64      }
65      
66      @Override
67      public Object findTemplateSource(String name) throws IOException {
68          int tokenIndex = (name == null) ? -1 : name.indexOf(themeExpansionToken);
69          if (tokenIndex < 0) {
70              return  ObjectUtils.defaultIfNull(findTemplateSourceFromSourceFile(name), getParentTemplateLoader().findTemplateSource(name));
71          }
72  
73          int themeEndIndex = name.indexOf('/', tokenIndex);
74          if (themeEndIndex < 0) {
75              return ObjectUtils.defaultIfNull(findTemplateSourceFromSourceFile(name), getParentTemplateLoader().findTemplateSource(name));
76          }
77  
78          Template template = new Template(
79              name.substring(0, tokenIndex - 1), 
80              name.substring(tokenIndex + themeExpansionToken.length(), themeEndIndex), 
81              name.substring(themeEndIndex + 1));
82          
83          List<Template> possibleTemplates = template.getPossibleTemplates(templateEngine);
84          for (Template possibleTemplate : possibleTemplates) {
85              Object templateSource = findTemplateSourceFromSourceFile(possibleTemplate.toString());
86              if (templateSource != null)
87                  return templateSource;
88              
89              templateSource = getParentTemplateLoader().findTemplateSource(
90                      possibleTemplate.toString().substring(1));
91              if (templateSource != null) {
92                  return templateSource;
93              }
94          }
95          String parentTheme = (String) templateEngine.getThemeProps(template).get("parent");
96          if (parentTheme == null) {
97              // no parent theme, no way to fetch parent template
98              return null;
99          }
100         String parentName = "/" + template.getDir() + "/" + themeExpansionToken + parentTheme + "/" + template.getName();
101         return ObjectUtils.defaultIfNull(findTemplateSourceFromSourceFile(name), this.findTemplateSource(parentName));
102     }
103     
104     private Object findTemplateSourceFromSourceFile (String name) {
105         // gboatViewResourcePath 为 null,表示没有开启调试模式
106         if(gboatViewResourcePath == null)
107             return null;
108         
109         File sourceFile = new File(gboatViewResourcePath, name);
110         if(sourceFile.isFile()){ // 如果存在对应的源代码文件,则从源代码文件中读取
111             try {
112                 return  sourceTemplateLoader.findTemplateSource(name);
113             } catch (IOException e) {
114                 LOG.warn("读取标签模板的源文件 [#0] 失败。", e, sourceFile.getAbsolutePath());
115             }
116         }
117         return null;
118     }
119 
120     @Inject(StrutsConstants.STRUTS_UI_THEME_EXPANSION_TOKEN)
121     public void setUIThemeExpansionToken(String token) {
122         themeExpansionToken = token;
123     }
124 
125     @Inject("ftl")
126     public void setTemplateEngine(TemplateEngine templateEngine) {
127         this.templateEngine = templateEngine;
128     }
129 
130 }