View Javadoc

1   /*
2    * Copyright 2010 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  package com.fatwire.gst.foundation.url;
17  
18  import java.util.Map;
19  
20  import COM.FutureTense.Export.Reference;
21  import COM.FutureTense.Export.ReferenceException;
22  import COM.FutureTense.Interfaces.ICS;
23  import COM.FutureTense.Interfaces.IReference;
24  import COM.FutureTense.Util.ftMessage;
25  
26  import com.fatwire.assetapi.data.AssetId;
27  import com.fatwire.cs.core.uri.Definition;
28  import com.fatwire.gst.foundation.vwebroot.AssetApiVirtualWebrootDao;
29  import com.fatwire.gst.foundation.vwebroot.VirtualWebroot;
30  import com.fatwire.gst.foundation.wra.AssetApiWraCoreFieldDao;
31  import com.fatwire.gst.foundation.wra.VanityAsset;
32  import com.fatwire.gst.foundation.wra.WraCoreFieldDao;
33  import com.openmarket.xcelerate.asset.AssetIdImpl;
34  import com.openmarket.xcelerate.publish.PageRef;
35  import com.openmarket.xcelerate.publish.PubConstants;
36  
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  
40  import static COM.FutureTense.Interfaces.Utilities.goodString;
41  
42  /**
43   * This is the WebReferenceable assets PageRef class. This overrides the default
44   * PageRef, so we can manipulate the arguments that go into the assembler while
45   * we have database access.
46   * <p/>
47   * <p>
48   * It will alter the input args map by adding the derived parameters
49   * <ul>
50   * <li>virtual-webroot</li>
51   * <li>url-path</li>
52   * <li>pagename</li>
53   * </ul>
54   * to the map before calling super.setParameters(args, ics).
55   * <p/>
56   * This modification is ONLY done when
57   * <ol>
58   * <li>the satellite context is Satellite</li>
59   * <li>the app type is Content Server</li>
60   * <li>the environment name is set</li>
61   * <li>the asset is found</li>
62   * <li>the asset has a path set</li>
63   * <li>a virtual webroot can be found for the path set and environment name</li>
64   * </p>
65   * <p>
66   * <ol>
67   * <li>PageRef extends Reference implements IPageRef</li>
68   * <li>Reference implements IReference</li>
69   * <li>interface IPageRef extends IReference</li>
70   * <li>interface IReference extends Definition</li>
71   * </ol>
72   * </p>
73   * 
74   * @author Dolf Dijkstra
75   * @author Tony Field
76   * @see Reference
77   * @see IReference
78   * @see Definition
79   * @since Jun 17, 2010
80   */
81  
82  public class WraPageReference extends PageRef {
83  
84      /**
85       * This logic is quite specific to the GSF so create a dedicated logger.
86       */
87      private static final Log log = LogFactory.getLog(WraPageReference.class.getName());
88  
89      public static final String GST_DISPATCHER = "GST/Dispatcher";
90  
91      /*
92       * (non-Javadoc)
93       * 
94       * @see
95       * com.openmarket.xcelerate.publish.PageRef#setParameters(java.util.Map,
96       * COM.FutureTense.Interfaces.ICS)
97       */
98      @SuppressWarnings({ "rawtypes", "unchecked" })
99      @Override
100     public void setParameters(Map args, ICS ics) throws ReferenceException {
101 
102         if (doVanityUrl(args, ics)) {
103             VanityUrlCalculationContext ctx = getVanityUrlCalculationContext(args, ics, requireWraForVanityUrls());
104 
105             VirtualWebroot vw = ctx.getVirtualWebrootForAsset(args, ics);
106 
107             args.put("virtual-webroot", vw.getEnvironmentVirtualWebroot());
108             args.put("url-path", ctx.getVanityAsset(args, ics).getPath().substring(vw.getMasterVirtualWebroot().length()));
109 
110             // has pagename been set? if not, use default.
111             String pagename = ics.GetProperty(WraPathAssembler.DISPATCHER_PROPNAME, "ServletRequest.properties", true);
112             if (!goodString(pagename)) {
113                 pagename = GST_DISPATCHER;
114             }
115             // pagename or wrapperpage depending on whether or not we're going to use a wrapper.
116             if (args.get(PubConstants.WRAPPERPAGE) != null)
117                 args.put(PubConstants.WRAPPERPAGE, pagename);
118             else
119                 args.put("pagename", pagename);
120         }
121         super.setParameters(args, ics);
122     }
123 
124     /**
125      * Method specifying whether or not vanity URLs are allowed for assets that are just Vanity assets or that have to
126      * be full WRA assets.  This is provided for backward compatibility.  Previously, only WRA assets could have
127      * vanity URLs, but the requirement has been loosened substantially.
128      * @return true for backward-compatibility - meaning that only WRA assets can have vanity URLs.  False if vanity
129      * URLs can be assigned to non-WRAs.
130      */
131     protected boolean requireWraForVanityUrls() {
132         return true;
133     }
134 
135     /**
136      * Determine if we should look up the virtual webroot and url path or not
137      */
138     private boolean doVanityUrl(Map args, ICS ics) {
139 
140         if (log.isDebugEnabled()) {
141             log.debug("checking to see if the URL for this asset should be a vanity url.  asset: "+args.get("c")+":"+args.get("cid"));
142         }
143 
144         if (getSatelliteContext() != SatelliteContext.SATELLITE_SERVER) {
145             log.debug("not applying vanity URL because satellite context is not satellite");
146             return false;
147         }
148 
149         if (!VanityUrlCalculationContext.isGetTemplateUrl(args, ics)) {
150             log.debug("not applying vanity URL because API usage was not found to be the gettemplateurl tag");
151             return false;
152         }
153 
154         VanityUrlCalculationContext ctx = getVanityUrlCalculationContext(args, ics, requireWraForVanityUrls());
155 
156         if (!ctx.isGsfEnvironmentSet(args, ics)) {
157             log.debug("not applying vanity URL because virtual webroot environment is not set");
158             return false;
159         }
160 
161         if (!ctx.isVanityAsset(args, ics)) {
162             if (requireWraForVanityUrls())
163                 log.debug("not applying vanityURL because asset is not a WRA");
164             else
165                 log.debug("not applying vanityURL because asset is not a Vanity Asset");
166             return false;
167         }
168 
169         if (!ctx.hasVirtualWebroot(args, ics)) {
170             log.debug("not applying vanity URL because we could not find a valid virtual webroot in the asset's path field");
171             return false;
172         }
173 
174         log.debug("Asset passed tests and a vanity URL will be created");
175 
176         return true;
177     }
178 
179     /**
180      * Figuring out whether or not we should do vanity URL validation is expensive.  Optimize the process as much
181      * as possible
182      * @param args input params
183      * @param ics ics context
184      * @param requireWraForVanity true to enforce having a WRA for a vanity URL, false to allow just a vanity asset.
185      * @return calcualtion context, containing pointers to heavy objects
186      */
187     private VanityUrlCalculationContext getVanityUrlCalculationContext(Map args, ICS ics, boolean requireWraForVanity) {
188         String c = (String) args.get("c");
189         String cid = (String) args.get("cid");
190         String key = "gsf:vanityUrlCalculationContext:"+c+":"+cid;
191         Object o = ics.GetObj(key);
192         if (o == null) {
193             o = new VanityUrlCalculationContext(c, cid, requireWraForVanity);
194             ics.SetObj(key, o);
195         }
196         return (VanityUrlCalculationContext) o;
197     }
198 
199     /**
200      * Handy context object, which holds expensive objects required when determining if
201      * a vanity URL should be created for an asset, and when actually calculating it.
202      */
203     private static class VanityUrlCalculationContext {
204 
205         private final boolean requireWraFields;
206         private final AssetId assetId;
207         private AssetApiVirtualWebrootDao assetApiVirtualWebrootDao;
208         private WraCoreFieldDao wraCoreFieldDao;
209 
210         boolean checkedForEnvironment = false;
211         private String currentEnvironment;
212 
213         boolean checkedForWebroot = false;
214         VirtualWebroot virtualWebrootForAsset;
215 
216         boolean checkedForVanitySupport = false;
217         VanityAsset vanityAsset;
218 
219         VanityUrlCalculationContext(String c, String cid, boolean requireWraFields) {
220             this.requireWraFields = requireWraFields;
221             assetId = new AssetIdImpl(c, Long.parseLong(cid));
222         }
223 
224         private AssetApiVirtualWebrootDao getAssetApiVirtualWebrootDao(Map args, ICS ics) {
225             if (assetApiVirtualWebrootDao == null) {
226                 assetApiVirtualWebrootDao = new AssetApiVirtualWebrootDao(ics);
227             }
228             return assetApiVirtualWebrootDao;
229         }
230 
231         private WraCoreFieldDao getWraCoreFieldDao(Map args, ICS ics) {
232             if (wraCoreFieldDao == null) {
233                 wraCoreFieldDao = new AssetApiWraCoreFieldDao(ics);
234             }
235             return wraCoreFieldDao;
236         }
237 
238 
239         private boolean isVanityAsset(Map args, ICS ics) {
240            WraCoreFieldDao dao = getWraCoreFieldDao(args, ics);
241            return requireWraFields ? dao.isWebReferenceable(assetId) : dao.isVanityAsset(assetId);
242         }
243 
244         private boolean isGsfEnvironmentSet(Map args, ICS ics) {
245             return getCurrentEnvironment(args, ics) != null;
246         }
247 
248         private String getCurrentEnvironment(Map args, ICS ics) {
249             if (currentEnvironment == null && checkedForEnvironment == false) {
250                 currentEnvironment = getAssetApiVirtualWebrootDao(args, ics).getVirtualWebrootEnvironment();
251                 checkedForEnvironment = true;
252             }
253             return currentEnvironment;
254         }
255 
256         private VanityAsset getVanityAsset(Map args, ICS ics) {
257             if (vanityAsset == null && checkedForVanitySupport == false) {
258                 WraCoreFieldDao dao = getWraCoreFieldDao(args, ics);
259                 vanityAsset = requireWraFields ? dao.getWra(assetId) : dao.getVanityWra(assetId);
260                 checkedForVanitySupport = true;
261             }
262             return vanityAsset;
263         }
264 
265         private boolean hasVirtualWebroot(Map args, ICS ics) {
266             return getVirtualWebrootForAsset(args, ics) != null;
267         }
268 
269         private VirtualWebroot getVirtualWebrootForAsset(Map args, ICS ics) {
270             if (virtualWebrootForAsset == null && checkedForWebroot == false) {
271                 AssetApiVirtualWebrootDao vwdao = getAssetApiVirtualWebrootDao(args, ics);
272                 VanityAsset v = getVanityAsset(args, ics);
273                 virtualWebrootForAsset = vwdao.lookupVirtualWebrootForAsset(v);
274                 checkedForWebroot = true;
275             }
276             return virtualWebrootForAsset;
277         }
278 
279 
280 
281         /**
282          * Check to see if the tag being called is a getTemplateUrl tag. If it is
283          * not, we should not be processing this for special links. Note it's not
284          * that easy to figure this out, and there could be missing pieces here.
285          *
286          * @param args tag args
287          * @return true if it's a gettemplateurl tag, false otherwise.
288          */
289         private static boolean isGetTemplateUrl(Map args, ICS ics) {
290             if (args.get("c") == null)
291                 return false;
292             if (args.get("cid") == null)
293                 return false;
294             String pagename = (String)args.get(ftMessage.PageName);
295             if (pagename == null)
296                 return false;
297             if (pagename.split("/").length < 2)
298                 return false; // need site/type/tname or site/tname at least for a valid URL
299             if (args.get(PubConstants.WRAPPERPAGE) != null)
300                 return true; // wrapper is only supported for GTU calls
301             else {
302                 // possible further checks here just in case
303             }
304             return true;
305         }
306     }
307 }