001: /*
002: * Copyright 2007 Gerd Ziegler (www.gerdziegler.de)
003: * Licensed under the Apache License, Version 2.0 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at
006: * http://www.apache.org/licenses/LICENSE-2.0
007: * Unless required by applicable law or agreed to in writing,
008: * software distributed under the License is distributed on an
009: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
010: * either express or implied. See the License for the specific
011: * language governing permissions and limitations under the License.
012: * @author www.gerdziegler.de
013: */
014:
015: package org.ztemplates.render;
016:
017: import java.lang.reflect.Method;
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.HashMap;
021: import java.util.HashSet;
022: import java.util.List;
023: import java.util.Map;
024: import java.util.Set;
025:
026: import org.apache.log4j.Logger;
027: import org.ztemplates.render.impl.ZReplaceUtil;
028: import org.ztemplates.render.script.ZScriptRepository;
029:
030: public class ZRenderEngine {
031: protected static Logger log = Logger.getLogger(ZRenderEngine.class);
032:
033: private final ZRenderEnvironment renderEnvironment;
034:
035: private final List<ZScript> script = new ArrayList<ZScript>();
036:
037: public ZRenderEngine(ZRenderEnvironment renderEnvironment) {
038: this .renderEnvironment = renderEnvironment;
039: }
040:
041: public String render(Object obj) throws Exception {
042: if (obj == null) {
043: return null;
044: }
045:
046: ZScript scriptAnn = obj.getClass().getAnnotation(ZScript.class);
047: if (scriptAnn != null) {
048: script.add(scriptAnn);
049: }
050:
051: ZRenderer rendererAnnot = obj.getClass().getAnnotation(
052: ZRenderer.class);
053: if (rendererAnnot == null) {
054: return obj.toString();
055: }
056:
057: ZIRenderer renderer = rendererAnnot.value().newInstance();
058: renderer.init(renderEnvironment);
059:
060: Map<String, Object> exposed = getExposed(obj);
061: if (rendererAnnot.cssId() && !exposed.containsKey("cssId")) {
062: String cssId = renderEnvironment.computeCssId(obj
063: .getClass());
064: exposed.put("cssId", cssId);
065: }
066: if (rendererAnnot.contextPath()
067: && !exposed.containsKey("contextPath")) {
068: exposed.put("contextPath", renderEnvironment
069: .getContextPath());
070: }
071:
072: if (rendererAnnot.zscript() && !exposed.containsKey("zscript")) {
073: exposed.put("zscript", computeZScript(script, exposed));
074: }
075:
076: if (rendererAnnot.renderService()
077: && !exposed.containsKey("renderService")) {
078: if (rendererAnnot.zscript()) {
079: String msg = "["
080: + obj.getClass().getName()
081: + " --- invalid values in annotation "
082: + ZRenderer.class.getSimpleName()
083: + " --- cannot expose both 'zscript' and 'renderService']";
084: exposed.put("renderService", msg);
085: } else {
086: exposed.put("renderService", this );
087: }
088: }
089:
090: String ret = renderer.render(obj.getClass(), exposed);
091: return ret;
092: }
093:
094: private String computeZScript(Collection<ZScript> script,
095: Map<String, Object> exposed) throws Exception {
096: StringBuffer sb = new StringBuffer();
097: if (!script.isEmpty()) {
098: ZScriptRepository sr = renderEnvironment
099: .getScriptRepository();
100:
101: List<String> cssSorted = sr.getCssSorted();
102: List<String> javaScriptSorted = sr.getJavaScriptSorted();
103:
104: Set<String> css = new HashSet<String>();
105: Set<String> javaScript = new HashSet<String>();
106:
107: for (ZScript sc : script) {
108: for (ZJavaScript s : sc.javaScript()) {
109: javaScript.add(s.value());
110: }
111: for (ZCss s : sc.css()) {
112: css.add(s.value());
113: }
114: }
115:
116: for (String s : javaScriptSorted) {
117: if (javaScript.contains(s)) {
118: String jsPath = s;
119: if (renderEnvironment.getContextPath() != null
120: && jsPath.startsWith("/")) {
121: jsPath = renderEnvironment.getContextPath()
122: + jsPath;
123: }
124: sb.append("<script type=\"text/javascript\" src=\""
125: + jsPath + "\"></script>");
126: sb.append('\n');
127: }
128: }
129:
130: for (String s : cssSorted) {
131: if (css.contains(s)) {
132: String cssPath = s;
133: if (renderEnvironment.getContextPath() != null
134: && cssPath.startsWith("/")) {
135: cssPath = renderEnvironment.getContextPath()
136: + cssPath;
137: }
138: sb
139: .append("<link rel=\"stylesheet\" type=\"text/css\" href=\""
140: + cssPath + "\"></link>");
141: sb.append('\n');
142: }
143: }
144: }
145:
146: if (renderEnvironment.getContextPath() != null) {
147: String path = "/ztemplates.css";
148: path = renderEnvironment.getContextPath() + path;
149: sb
150: .append("<link rel=\"stylesheet\" type=\"text/css\" href=\""
151: + path + "\"></link>\n");
152: } else {
153: String path = "/ztemplates.css";
154: sb
155: .append("<link rel=\"stylesheet\" type=\"text/css\" href=\""
156: + path + "\"></link>\n");
157: }
158:
159: StringBuffer ret = ZReplaceUtil.replace(sb, exposed);
160: return ret.toString();
161: }
162:
163: public Map<String, Object> getExposed(Object obj) throws Exception {
164: Map<String, Object> values = new HashMap<String, Object>();
165: try {
166: Method onRender = obj.getClass().getDeclaredMethod(
167: "onRender");
168: onRender.invoke(obj);
169: } catch (NoSuchMethodException e) {
170: // OK
171: }
172:
173: for (Method m : obj.getClass().getMethods()) {
174: ZExpose exp = m.getAnnotation(ZExpose.class);
175: if (exp != null) {
176: String key;
177: if (m.getName().startsWith("get")) {
178: key = Character.toLowerCase(m.getName().charAt(3))
179: + m.getName().substring(4);
180: } else if (m.getName().startsWith("is")) {
181: key = Character.toLowerCase(m.getName().charAt(2))
182: + m.getName().substring(3);
183: } else {
184: throw new Exception(
185: "Only getters can be annotated with "
186: + ZExpose.class.getName());
187: }
188:
189: Object val = m.invoke(obj);
190: if (val instanceof ZIStateful) {
191: ZIStateful stateful = (ZIStateful) val;
192: stateful.storeState();
193: }
194: if (exp.render()) {
195: if (val instanceof Collection) {
196: Collection oldVal = (Collection) val;
197: Collection newVal = new ArrayList();
198: for (Object crt : oldVal) {
199: newVal.add(render(crt));
200: }
201: val = newVal;
202: } else {
203: val = render(val);
204: }
205: }
206: values.put(key, val);
207: }
208: }
209:
210: return values;
211: }
212: }
|