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 }