View Javadoc
1   /*
2    * Copyright 2008 FatWire 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  
17  package com.fatwire.gst.foundation.facade.fsii;
18  
19  import COM.FutureTense.Interfaces.ICS;
20  
21  import com.fatwire.assetapi.data.AssetData;
22  import com.fatwire.assetapi.data.AssetId;
23  import com.fatwire.gst.foundation.CSRuntimeException;
24  import com.fatwire.gst.foundation.facade.assetapi.AssetDataUtils;
25  import com.fatwire.gst.foundation.facade.assetapi.AssetIdUtils;
26  import com.fatwire.gst.foundation.facade.assetapi.AttributeDataUtils;
27  import com.fatwire.gst.foundation.facade.runtag.TagRunnerRuntimeException;
28  import com.fatwire.gst.foundation.facade.runtag.asset.AssetList;
29  import com.fatwire.gst.foundation.facade.runtag.asset.Children;
30  import com.fatwire.gst.foundation.facade.runtag.asset.GetSubtype;
31  import com.fatwire.gst.foundation.facade.runtag.render.GetTemplateUrl;
32  import com.fatwire.gst.foundation.facade.runtag.siteplan.ListPages;
33  import com.openmarket.xcelerate.asset.AssetIdImpl;
34  
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  
38  /**
39   * Miscellaneous utility library used to access data stored in the site plan or
40   * assets related to the site plan.
41   * <p/>
42   * This module is aware of two special types of page subtypes: Aliases and
43   * Navigatin Placeholders. Aliases are pages that are aliases to other pages
44   * containing the same information in the site plan tree. Navigation
45   * Placeholders are pages that are typically located at the root of the site
46   * plan tree and do not contain any content. They are not content assets but are
47   * organizational in nature.
48   * 
49   * @author Tony Field
50   * @since Nov 17, 2009
51   */
52  public final class SitePlanUtils {
53      private static Log LOG = LogFactory.getLog(SitePlanUtils.class);
54  
55      private SitePlanUtils() {
56      }
57  
58      /**
59       * Return the name of the template assigned to the associated PageDetail
60       * asset. Note that the asset type of the page detail is not fixed - any one
61       * will work.
62       * 
63       * @param ics context
64       * @param p id of page asset
65       * @param assocname name of the association between the page and the page
66       *            detail asset
67       * @return the template name
68       */
69      public static String getPageDetailTemplateForPage(ICS ics, String p, String assocname) {
70          AssetId kid = Children.getSingleAssociation(ics, "Page", resolvePageAlias(ics, p), assocname);
71          return AssetList.getRequiredSingleField(ics, kid.getType(), Long.toString(kid.getId()), "template");
72      }
73  
74      /**
75       * For a given page asset, return the template
76       * 
77       * @param ics context
78       * @param p page asset id
79       * @return template field
80       */
81      public static String getTemplateForPage(ICS ics, String p) {
82          return AssetList.getRequiredSingleField(ics, "Page", p, "template");
83      }
84  
85      /**
86       * Get the specified page detail asset id for the specified page.
87       * 
88       * @param ics context
89       * @param p page asset id
90       * @param assocname name of the association containing the page detail.
91       * @return the assetid
92       */
93      public static AssetId getPageDetailForPage(ICS ics, String p, String assocname) {
94          return Children.getSingleAssociation(ics, "Page", resolvePageAlias(ics, p), assocname);
95      }
96  
97      /**
98       * Return a bean containing the common information found inside a HEAD html
99       * tag.
100      * <p/>
101      * Does not resolve aliases.
102      * 
103      * @param ics context
104      * @param c asset type
105      * @param cid asset id
106      * @param metaKeywordAttribute attribute used to contain meta keywords. must
107      *            be multi-valued
108      * @param metaDescriptionAttribute attribute used to contain description.
109      *            expects single-valued
110      * @param titleAttribute attribute used to contain title. expects
111      *            single-valued.
112      * @return HeadTagData object
113      */
114     public static HeadTagData getStandardHeadData(ICS ics, String c, String cid, String metaKeywordAttribute,
115             String metaDescriptionAttribute, String titleAttribute) {
116         HeadTagData result = new HeadTagData();
117 
118         AssetData data = AssetDataUtils.getAssetData(ics, AssetIdUtils.createAssetId(cid, c), cid,
119                 metaKeywordAttribute, metaDescriptionAttribute, titleAttribute, "description", "name");
120         result.setTitle(AttributeDataUtils.getWithFallback(data, titleAttribute, "description", "name"));
121         result.setDescription(AttributeDataUtils.getWithFallback(data, metaDescriptionAttribute, titleAttribute,
122                 "description", "name"));
123         String kw = AttributeDataUtils.getMultivaluedAsCommaSepString(data.getAttributeData(metaKeywordAttribute));
124         if (kw == null || kw.length() == 0) {
125             kw = AttributeDataUtils.getWithFallback(data, "name");
126         }
127         result.setKeywords(kw);
128         return result;
129     }
130 
131     /**
132      * Get a PageLinkData object from the site plan tree. If the linktext is
133      * derived from an associated asset, specify the association name. If the
134      * linktet is derived from the page asset itself, leave detailAssocName as
135      * null. Either way, the linktext comes from the appropriate asset's
136      * linktextAttr.
137      * <p/>
138      * Links are not populated for Navigation Placeholders, but it is often very
139      * convenient to pass a navigation placeholder into this function in order
140      * to return all children under a specific placeholder.
141      * <p/>
142      * Aliases are resolved.
143      * 
144      * @param ics context
145      * @param p page
146      * @param assocname association name for pageDetail if applicable. May be
147      *            null
148      * @param linktextAttr attribute in associated pagedetail if specified,
149      *            otherwise attribute in page asset
150      * @param tname Template name to link to. Required if links are to work but
151      *            can be omitted if links are not desired.
152      * @param wrapper Wrapper SiteEntry name. Null is allowed.
153      * @param withChildren populate the result with data for children as well
154      * @return PageLinkData
155      */
156     public static PageLinkData getSitePlanAsLinks(ICS ics, final String p, String assocname, String linktextAttr,
157             String tname, String wrapper, boolean withChildren) {
158         PageLinkData pageLinkData = new PageLinkData();
159 
160         pageLinkData.setPageId(new AssetIdImpl("Page", Long.valueOf(p)));
161 
162         // set the subtype
163         pageLinkData.setSubtype(GetSubtype.getSubtype(ics, pageLinkData.getPageId()));
164 
165         // Get the linktext
166         final boolean isNavigationPlaceholder = PAGE_SUBTYPE_NAVIGATION_PLACEHOLDER.equals(pageLinkData.getSubtype());
167         if (assocname == null) {
168             AssetData data = AssetDataUtils.getAssetData(ics,
169                     AssetIdUtils.createAssetId("Page", resolvePageAlias(ics, p)), linktextAttr);
170             pageLinkData.setLinktext(AttributeDataUtils.getWithFallback(data, linktextAttr));
171         } else {
172             LOG.debug("About to load " + assocname + " for Page:" + p);
173             try {
174                 AssetId kid = Children.getSingleAssociation(ics, "Page", resolvePageAlias(ics, p), assocname);
175                 AssetData data = AssetDataUtils.getAssetData(ics, kid, linktextAttr);
176                 pageLinkData.setLinktext(AttributeDataUtils.getWithFallback(data, linktextAttr));
177             } catch (TagRunnerRuntimeException e) {
178                 if (e.getErrno() == -111) {
179                     // nav placeholders get some slack.
180                     if (!isNavigationPlaceholder) {
181                         throw new CSRuntimeException("Missing required association: " + assocname + " for Page:"
182                                 + resolvePageAlias(ics, p), -111);
183                     }
184 
185                 } else {
186                     throw e;
187                 }
188             }
189 
190         }
191 
192         // Do not populate links for Navigation Placeholders.
193         if (!isNavigationPlaceholder && tname != null) {
194             // Get the link
195             if (tname != null) {
196                 // do the link
197                 GetTemplateUrl gtu = new GetTemplateUrl(ics, "Page", p, tname, wrapper, "SitePlanUtils");
198                 gtu.setArgument("p", p); // should this include the alias
199                                          // target?
200                 ics.RemoveVar("gspal-url");
201                 gtu.setOutstr("gspal-url");
202                 gtu.execute(ics);
203                 pageLinkData.setUrl(ics.GetVar("gspal-url"));
204                 ics.RemoveVar("gspal-url");
205             }
206         }
207 
208         // Get the children
209         if (withChildren) {
210             for (AssetId kid : ListPages.getChildPages(ics, pageLinkData.getPageId().getId())) {
211                 // recurse
212                 PageLinkData kidData = getSitePlanAsLinks(ics, Long.toString(kid.getId()), assocname, linktextAttr,
213                         tname, wrapper, withChildren);
214                 pageLinkData.addImmediateChild(kidData);
215             }
216         }
217 
218         return pageLinkData;
219     }
220 
221     /**
222      * Name of the page subtype indicating that this page is NOT rendered on the
223      * site but is instead merely used to group navigation components on the
224      * site.
225      */
226     public static final String PAGE_SUBTYPE_NAVIGATION_PLACEHOLDER = "NavigationPlaceholder";
227 
228     /**
229      * Name of the page subtype indicating that this page is just an alias to
230      * another page.
231      */
232     public static final String PAGE_SUBTYPE_ALIAS = "Alias";
233 
234     /**
235      * Name of the association in an alias page that contains the target page.
236      */
237     public static final String PAGE_SUBTYPE_ASSOCIATION_NAME = "TargetPage";
238 
239     /**
240      * Given an input page, find out if it is an alias or not, and if it is,
241      * return the ID of the target page. If not an alias, the original input is
242      * returned
243      * 
244      * @param ics context
245      * @param p input page id
246      * @return resolved alias page id
247      */
248     public static String resolvePageAlias(ICS ics, final String p) {
249         String subtype = GetSubtype.getSubtype(ics, "Page", p);
250         if (PAGE_SUBTYPE_ALIAS.equals(subtype)) {
251             AssetId target = Children.getSingleAssociation(ics, "Page", p, PAGE_SUBTYPE_ASSOCIATION_NAME);
252             return Long.toString(target.getId());
253         }
254         return p;
255     }
256 }