001: /*
002: * Created on Jul 27, 2005
003: */
004: package uk.org.ponder.rsf.renderer.html;
005:
006: import java.util.HashMap;
007: import java.util.Map;
008:
009: import uk.org.ponder.rsf.components.UIBasicListMember;
010: import uk.org.ponder.rsf.components.UIComponent;
011: import uk.org.ponder.rsf.renderer.ComponentRenderer;
012: import uk.org.ponder.rsf.renderer.RenderSystem;
013: import uk.org.ponder.rsf.renderer.RenderSystemContext;
014: import uk.org.ponder.rsf.renderer.RenderUtil;
015: import uk.org.ponder.rsf.renderer.TagRenderContext;
016: import uk.org.ponder.rsf.renderer.decorator.DecoratorManager;
017: import uk.org.ponder.rsf.renderer.scr.NullRewriteSCR;
018: import uk.org.ponder.rsf.renderer.scr.StaticComponentRenderer;
019: import uk.org.ponder.rsf.renderer.scr.StaticRendererCollection;
020: import uk.org.ponder.rsf.request.FossilizedConverter;
021: import uk.org.ponder.rsf.request.SubmittedValueEntry;
022: import uk.org.ponder.rsf.template.XMLLump;
023: import uk.org.ponder.rsf.template.XMLLumpList;
024: import uk.org.ponder.util.Constants;
025: import uk.org.ponder.util.Logger;
026: import uk.org.ponder.util.UniversalRuntimeException;
027:
028: /**
029: * The implementation of the standard XHTML rendering System. This class is due
030: * for basic refactoring since it contains logic that belongs in a) a "base
031: * System-independent" lookup bean, and b) in a number of individual
032: * ComponentRenderer objects.
033: *
034: * @author Antranig Basman (antranig@caret.cam.ac.uk)
035: *
036: */
037:
038: public class BasicHTMLRenderSystem implements RenderSystem {
039: private StaticRendererCollection scrc;
040: private DecoratorManager decoratormanager;
041: private ComponentRenderer componentRenderer;
042:
043: public void setComponentRenderer(ComponentRenderer componentRenderer) {
044: this .componentRenderer = componentRenderer;
045: }
046:
047: public void setStaticRenderers(StaticRendererCollection scrc) {
048: this .scrc = scrc;
049: }
050:
051: public void setDecoratorManager(DecoratorManager decoratormanager) {
052: this .decoratormanager = decoratormanager;
053: }
054:
055: // two methods for the RenderSystemDecoder interface
056: public void normalizeRequestMap(Map requestparams) {
057: String key = RenderUtil.findCommandParams(requestparams);
058: if (key != null) {
059: String params = key
060: .substring(FossilizedConverter.COMMAND_LINK_PARAMETERS
061: .length());
062: RenderUtil.unpackCommandLink(params, requestparams);
063: requestparams.remove(key);
064: }
065: }
066:
067: public void fixupUIType(SubmittedValueEntry sve) {
068: if (sve.oldvalue instanceof Boolean) {
069: if (sve.newvalue == null)
070: sve.newvalue = Boolean.FALSE;
071: } else if (sve.oldvalue instanceof String[]) {
072: if (sve.newvalue == null)
073: sve.newvalue = new String[] {};
074: } else if (sve.oldvalue instanceof String) {
075: if (sve.newvalue instanceof String
076: && Constants.NULL_STRING.equals(sve.newvalue)
077: || sve.newvalue instanceof String[]
078: && Constants.NULL_STRING
079: .equals(((String[]) sve.newvalue)[0])) {
080: sve.newvalue = null;
081: }
082: }
083: }
084:
085: public void renderDebugMessage(RenderSystemContext rsc,
086: String string) {
087: rsc.pos
088: .print("<span style=\"background-color:#FF466B;color:white;padding:1px;\">");
089: rsc.xmlw.write(string);
090: rsc.pos.print("</span><br/>");
091: }
092:
093: // This method is almost entirely dialect-invariant - awaiting final
094: // factorisation of RenderSystem
095: public int renderComponent(RenderSystemContext rsc,
096: UIComponent torendero, XMLLump lump) {
097: int lumpindex = lump.lumpindex;
098: XMLLump[] lumps = lump.parent.lumps;
099: int nextpos = -1;
100: XMLLump outerendopen = lump.open_end;
101: XMLLump outerclose = lump.close_tag;
102:
103: nextpos = outerclose.lumpindex + 1;
104:
105: XMLLumpList payloadlist = lump.downmap == null ? null
106: : lump.downmap.headsForID(XMLLump.PAYLOAD_COMPONENT);
107: XMLLump payload = payloadlist == null ? null : payloadlist
108: .lumpAt(0);
109:
110: // if there is no peer component, it might still be a static resource holder
111: // that needs URLs rewriting.
112: // we assume there is no payload component here, since there is no producer
113: // ID that might govern selection. So we use "outer" indices.
114: if (torendero == null) {
115: if (lump.rsfID.startsWith(XMLLump.SCR_PREFIX)) {
116: String scrname = lump.rsfID
117: .substring(XMLLump.SCR_PREFIX.length());
118: StaticComponentRenderer scr = scrc.getSCR(scrname);
119: if (scr == null) {
120: Logger.log
121: .info("Warning: unrecognised static component renderer reference with key "
122: + scrname
123: + " at lump "
124: + lump.toString());
125: scr = NullRewriteSCR.instance;
126: }
127: int tagtype = RenderUtil.renderSCR(scr, lump, rsc.xmlw,
128: rsc.collecteds);
129: nextpos = tagtype == ComponentRenderer.LEAF_TAG ? outerclose.lumpindex + 1
130: : outerendopen.lumpindex + 1;
131: } else {
132: if (rsc.debugrender) {
133: renderDebugMessage(rsc,
134: "Leaf component missing which was expected with template id "
135: + lump.rsfID + " at "
136: + lump.toString());
137: }
138: }
139: } else {
140: // else there IS a component and we are going to render it. First make
141: // sure we render any preamble.
142: XMLLump endopen = outerendopen;
143: XMLLump close = outerclose;
144: XMLLump uselump = lump;
145: if (payload != null) {
146: endopen = payload.open_end;
147: close = payload.close_tag;
148: uselump = payload;
149: RenderUtil.dumpTillLump(lumps, lumpindex,
150: payload.lumpindex, rsc.pos);
151: lumpindex = payload.lumpindex;
152: }
153:
154: HashMap attrcopy = new HashMap();
155: attrcopy.putAll(uselump.attributemap);
156: rsc.IDassigner.adjustForID(attrcopy, torendero);
157: decoratormanager.decorate(torendero.decorators, uselump
158: .getTag(), attrcopy);
159: boolean iselide = lump.rsfID
160: .startsWith(XMLLump.ELISION_PREFIX);
161: TagRenderContext rendercontext = new TagRenderContext(
162: attrcopy, uselump, endopen, close, rsc.pos,
163: rsc.xmlw, nextpos, iselide);
164: // ALWAYS dump the tag name, this can never be rewritten. (probably?!)
165: if (!iselide) {
166: rsc.pos.write(uselump.parent.buffer, uselump.start,
167: uselump.length);
168: }
169:
170: if (torendero instanceof UIBasicListMember) {
171: torendero = RenderUtil.resolveListMember(rsc.view,
172: (UIBasicListMember) torendero);
173: }
174: try {
175: componentRenderer.renderComponent(torendero, rsc.view,
176: rendercontext);
177: } catch (Exception e) {
178: throw UniversalRuntimeException.accumulate(e,
179: "Error rendering component "
180: + torendero.getClass()
181: + " with full ID "
182: + torendero.getFullID()
183: + " at template location "
184: + rendercontext.uselump);
185: }
186: // if there is a payload, dump the postamble.
187: if (payload != null) {
188: // the default case is initialised to tag close
189: if (rendercontext.nextpos == nextpos) {
190: RenderUtil.dumpTillLump(lumps, close.lumpindex + 1,
191: outerclose.lumpindex + 1, rsc.pos);
192: }
193: }
194: nextpos = rendercontext.nextpos;
195: }
196:
197: return nextpos;
198: }
199:
200: }
|