View Javadoc
1   /*
2    * Copyright 2012 Oracle Corporation. All Rights Reserved.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.fatwire.gst.foundation.controller;
17  
18  import static COM.FutureTense.Interfaces.Utilities.goodString;
19  
20  import java.util.Arrays;
21  import java.util.Collections;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Locale;
25  import java.util.Map;
26  import java.util.Map.Entry;
27  
28  import org.apache.commons.lang.StringUtils;
29  import org.apache.commons.logging.Log;
30  
31  import COM.FutureTense.Interfaces.ICS;
32  import COM.FutureTense.Util.ftErrors;
33  import COM.FutureTense.Util.ftMessage;
34  
35  import com.fatwire.gst.foundation.CSRuntimeException;
36  import com.fatwire.gst.foundation.facade.RenderUtils;
37  import com.fatwire.gst.foundation.facade.logging.LogUtil;
38  import com.fatwire.gst.foundation.facade.runtag.render.CallTemplate;
39  import com.fatwire.gst.foundation.facade.runtag.render.CallTemplate.Style;
40  import com.fatwire.gst.foundation.facade.runtag.render.SatellitePage;
41  import com.openmarket.xcelerate.publish.PubConstants;
42  
43  /**
44   * Helper class to be used in an outer wrapper to run the correct childtemplate based on c/cid/site arguments.
45   * 
46   * @author Dolf Dijkstra
47   *
48   */
49  public abstract class BaseRenderPage {
50  
51      public static final String PACKEDARGS = PubConstants.PACKEDARGS.toLowerCase(Locale.US);//"packedargs";
52  
53      public static final List<String> CALLTEMPLATE_EXCLUDE_VARS = Collections.unmodifiableList(Arrays.asList("c", "cid",
54              "eid", "seid", PACKEDARGS, "variant", "context", "pagename", "childpagename", "site", "tid",
55              "SystemAssetsRoot", "rendermode", "cshttp", "errno", "tablename", "empty", "ft_ss", "errdetail", "null"));
56  
57      protected static final Log LOG = LogUtil.getLog(WraRenderPage.class);
58      protected ICS ics;
59  
60      public BaseRenderPage() {
61          super();
62      }
63  
64      protected void callPage(AssetIdWithSite id, String pagename, String packedArgs) {
65          final SatellitePage sp = new SatellitePage(pagename);
66          if (StringUtils.isNotBlank(packedArgs))
67              sp.setPackedArgs(packedArgs);
68          sp.setArgument(PubConstants.c, id.getType());
69          sp.setArgument(PubConstants.cid, id.getId());
70          String[] pc = ics.pageCriteriaKeys(pagename);
71          if (pc != null) {
72              for (String p : pc) {
73                  if (!CALLTEMPLATE_EXCLUDE_VARS.contains(p)) {
74                      // add only if page critera and not excluded
75                      sp.setArgument(p, ics.GetVar(p));
76                  }
77              }
78          }
79          String s = sp.execute(ics);
80          if (s != null) {
81              ics.StreamText(s);
82          }
83  
84      }
85  
86      protected AssetIdWithSite resolveAssetId() {
87          final AssetIdWithSite id;
88          if (goodString(ics.GetVar(PubConstants.c)) && goodString(ics.GetVar(PubConstants.cid)) && goodString(ics.GetVar(PubConstants.site))) {
89              String site = ics.GetVar(PubConstants.site);
90              id = new AssetIdWithSite(ics.GetVar(PubConstants.c), Long.parseLong(ics.GetVar(PubConstants.cid)), site);
91          } else {
92              throw new CSRuntimeException("Missing required param c, cid.", ftErrors.pagenotfound);
93          }
94          return id;
95  
96      }
97  
98      protected void renderPage() {
99          // the preview code path is adding all the additional arguments in
100         // packedargs.
101         // unpack here so we can use
102         String pa = unpackPackedArgs();// ics.GetVar(PubConstants.PACKEDARGS);
103 
104         final AssetIdWithSite id = resolveAssetId();
105         if (id == null || id.getSite() == null) {
106             throw new CSRuntimeException("Asset or site not found: '" + id + "' for url " + ics.pageURL(),
107                     ftErrors.pagenotfound);
108         }
109         if (LOG.isDebugEnabled())
110             LOG.debug("RenderPage found a valid asset and site: " + id);
111 
112         // if childpagename is passed in (preview code path) we use this and do
113         // a render:satellitepage
114         if (ics.GetVar(PubConstants.CHILDPAGENAME) != null) {
115             // preview UI support
116             callPage(id, ics.GetVar(PubConstants.CHILDPAGENAME), pa);
117         } else {
118             // alternatively, render the live logic.
119             // the template is expected to have the layout itself.
120         }
121         LOG.debug("WraRenderPage execution complete");
122 
123     }
124 
125     protected void findAndSetP(final AssetIdWithSite id, final Map<String, String> arguments) {
126         final String pVar = ics.GetVar("p");
127         if (pVar != null && pVar.length() > 0) {
128             arguments.put("p", pVar);
129         }
130     }
131 
132     protected void callTemplate(final AssetIdWithSite id, final String tname) {
133         final CallTemplate ct = new CallTemplate();
134         ct.setSite(id.getSite());
135         ct.setSlotname("wrapper");
136         String tid = ics.GetVar(PubConstants.eid);// renderpage action is intended to be
137                                        // rendered from the controller
138         if (StringUtils.isBlank(tid)) {
139             if (LOG.isDebugEnabled()) {
140                 LOG.debug("CSVar eid is not found, compensating with eid=1. Is this element not a CSElement");
141             }
142             tid = "1";
143         }
144         ct.setTid(tid);
145         ct.setAsset(id);
146         ct.setTname(tname);
147         ct.setContext("");
148         ct.setArgument(PubConstants.site, id.getSite());
149 
150         final String packedargs = ics.GetVar(PACKEDARGS);
151         if (StringUtils.isNotBlank(packedargs)) {
152             if (LOG.isDebugEnabled()) {
153                 LOG.debug("packedargs is " + packedargs);
154             }
155             ct.setPackedargs(massagePackedArgs(packedargs));
156         }
157 
158         // typeless or not...
159         final String targetPagename = tname.startsWith("/") ? (id.getSite() + tname) : (id.getSite() + "/"
160                 + id.getType() + "/" + tname);
161         if (LOG.isDebugEnabled()) {
162             LOG.debug("Target pagename is " + targetPagename);
163         }
164 
165         // create a list of parameters that can be specified as arguments to the
166         // CallTemplate tag.
167         final Map<String, String> arguments = new HashMap<String, String>();
168 
169         // Prime the map with the ics variable scope for the architect to make
170         // the controller as transparent as possible
171         String[] pageKeys = ics.pageCriteriaKeys(targetPagename);
172         if (pageKeys != null) {
173             for (final String pcVarName : pageKeys) {
174                 if (!CALLTEMPLATE_EXCLUDE_VARS.contains(pcVarName) && StringUtils.isNotBlank(ics.GetVar(pcVarName))) {
175                     arguments.put(pcVarName, ics.GetVar(pcVarName));
176                 }
177             }
178         } else {
179             if (LOG.isDebugEnabled()) {
180                 LOG.debug("PageCriteria for " + targetPagename + " is null.");
181             }
182         }
183 
184         // allow users to set their own
185         getCallTemplateArguments(id, arguments);
186 
187         // add them to the tag
188         for (final Entry<String, String> e : arguments.entrySet()) {
189             ct.setArgument(e.getKey(), e.getValue());
190             if (LOG.isTraceEnabled()) {
191                 LOG.trace("CallTemplate param added: " + e.getKey() + "=" + e.getValue());
192             }
193         }
194 
195         // override calltemplate call style
196         imposeCallTemplateStyle(ct, targetPagename);
197 
198         final String s = ct.execute(ics);
199         if (s != null) {
200             ics.StreamText(s);
201         }
202     }
203 
204     /**
205      * This method collects additional arguments for the CallTemplate call. New
206      * arguments are added to the map as name-value pairs.
207      * 
208      * @param id AssetIdWithSite object
209      * @param arguments Map<String,String> containing arguments for the nested
210      *            CallTemplate call
211      */
212     protected void getCallTemplateArguments(AssetIdWithSite id, Map<String, String> arguments) {
213         findAndSetP(id, arguments);
214     }
215 
216     protected Style getCallTemplateCallStyle(String target) {
217         if (RenderUtils.isCacheable(ics, ics.GetVar(ftMessage.PageName))) {
218             // call as element when current is caching.
219             // note that it may be useful to set this to "embedded" in some
220             // cases.
221             // override it in that situation
222             return Style.element;
223         } else if (RenderUtils.isCacheable(ics, target)) {
224             // call as embedded when current is not caching and target is
225             return Style.embedded;
226         } else {
227             // call as element when current is not caching and target is not
228             return Style.element;
229         }
230     }
231 
232     /**
233      * This method allows developers to override the automatically-selected
234      * CallTemplate call style. By default, no override is done and the
235      * CallTemplate class determines the best call style.
236      * 
237      * @param ct CallTemplate tag
238      * @param targetPagename target pagename
239      * @see CallTemplate #setStyle(CallTemplate.Style)
240      */
241     protected void imposeCallTemplateStyle(final CallTemplate ct, final String targetPagename) {
242     }
243 
244     protected String massagePackedArgs(String packedargs) {
245         return packedargs;
246     }
247 
248     /**
249      * Record compositional dependencies that are required for the controller
250      */
251     protected void recordCompositionalDependencies() {
252         RenderUtils.recordBaseCompositionalDependencies(ics);
253     }
254 
255     protected String unpackPackedArgs() {
256         // for RenderPage unpacking and throwing away packedargs seems the
257         // correct thing to do
258         final String packedargs = ics.GetVar(PACKEDARGS);
259         if (StringUtils.isNotBlank(packedargs)) {
260             if (LOG.isDebugEnabled()) {
261                 LOG.debug("packedargs is " + packedargs);
262             }
263             Map<String, String> map = new HashMap<String, String>();
264             ics.decode(packedargs, map);
265             for (Map.Entry<String, String> e : map.entrySet()) {
266                 ics.SetVar(e.getKey(), e.getValue());
267 
268             }
269             ics.RemoveVar(PACKEDARGS);
270         }
271         return packedargs;
272 
273     }
274 
275 }