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.runtag.asset;
18  
19  import static COM.FutureTense.Interfaces.Utilities.goodString;
20  
21  import java.text.ParseException;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collection;
25  import java.util.Date;
26  import java.util.List;
27  
28  import org.apache.commons.lang.StringUtils;
29  import org.apache.commons.lang.time.DateUtils;
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  
33  import COM.FutureTense.Cache.CacheManager;
34  import COM.FutureTense.Interfaces.ICS;
35  import COM.FutureTense.Interfaces.IList;
36  
37  import com.fatwire.assetapi.data.AssetData;
38  import com.fatwire.assetapi.data.AssetId;
39  import com.fatwire.gst.foundation.IListUtils;
40  import com.fatwire.gst.foundation.facade.assetapi.AssetDataUtils;
41  import com.fatwire.gst.foundation.facade.assetapi.AssetIdIList;
42  import com.fatwire.gst.foundation.facade.assetapi.AssetIdUtils;
43  import com.fatwire.gst.foundation.facade.assetapi.AttributeDataUtils;
44  import com.fatwire.gst.foundation.facade.assetapi.asset.PreviewContext;
45  import com.fatwire.gst.foundation.facade.sql.IListIterable;
46  import com.fatwire.gst.foundation.facade.sql.Row;
47  import com.openmarket.xcelerate.publish.PubConstants;
48  
49  /**
50   * Filters assets via startdate/enddate.
51   * <p/>
52   * NOTE: This class calls a public yet internal function inside the JSP tag. No
53   * guarantees can therefore exist as to its compatibility across patch versions.
54   * The core function, however, is exceptionally slow to begin with, so caution
55   * should be exercised when using this function.
56   * <p/>
57   * 
58   * @author Tony Field
59   * @author Dolf Dijkstra
60   * @since Jun 23, 2010
61   */
62  public final class FilterAssetsByDate {
63      private static final Log LOG = LogFactory.getLog(FilterAssetsByDate.class);
64  
65      private static String[] jdbcDateFormatStrings = { "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss.SSS" };
66  
67      /**
68       * Filter a single asset, checking to see if it's valid on the given date.
69       * If no date is specified, then the date used is the one used by the
70       * FilterAssetsByDate tag when no parameter is specified
71       * 
72       * @param ics context
73       * @param id input asset
74       * @param date override date
75       * @return true if the asset is valid, false otherwise.
76       */
77      public static boolean isValidOnDate(ICS ics, AssetId id, Date date) {
78  
79          AssetId[] out = filter(ics, date, id);
80  
81          if (out == null)
82              throw new IllegalStateException("Tag executed successfully but no outlist was returned");
83          if (out.length == 0) {
84              if (LOG.isTraceEnabled()) {
85                  LOG.trace("Asset " + id + " is not valid on the effective date.");
86              }
87              return false; // no matches
88          }
89          String c = out[0].getType();
90          if (!id.getType().equals(c)) {
91              throw new IllegalStateException("Output asset is not the right type: in:" + id + ", out:" + c);
92          }
93          long cid = out[0].getId();
94  
95          boolean result = id.getId() == cid;
96  
97          if (LOG.isTraceEnabled()) {
98              LOG.trace("Asset " + id + " is " + (result ? "" : "not ") + "valid on the effective date.");
99          }
100         return result;
101     }
102 
103     /**
104      * Filter a array of asset, checking to see if they're valid on the given
105      * date. If no date is specified, then the date used is the one used by the
106      * FilterAssetsByDate tag when no parameter is specified
107      * 
108      * @param ics context
109      * @param date override date
110      * @param id array of assetids
111      * @return the array of asset filtered for the date.
112      */
113     public static AssetId[] filter(ICS ics, Date date, AssetId... id) {
114         Collection<AssetId> ret = filter(ics, date, Arrays.asList(id));
115         return ret.toArray(new AssetId[ret.size()]);
116     }
117 
118     /**
119      * Filter a collection of assets, checking to see if they're valid on the
120      * given date. If no date is specified, then the date used is the one used
121      * by the FilterAssetsByDate tag when no parameter is specified
122      * 
123      * @param ics ics context
124      * @param date override date
125      * @param list Collection of assetids.
126      * @return the Collection of asset filtered for the date.
127      */
128     public static Collection<AssetId> filter(ICS ics, Date date, Collection<AssetId> list) {
129         if (LOG.isTraceEnabled()) {
130             LOG.trace("Checking to see if asset " + list + " is valid on "
131                     + (date == null ? "the site preview date, (assuming site preview is enabled)." : date));
132         }
133         ics.ClearErrno();
134 
135         final String inListName = IListUtils.generateRandomListName("FilterAssetByDateInputList-");
136         IList inlist = new AssetIdIList(inListName, list);
137 
138         final String outListName = IListUtils.generateRandomListName("FilterAssetsByDateOutputList-");
139 
140         String sdate = date == null ? null : com.fatwire.cs.core.db.Util.formatJdbcDate(date);
141         int i = com.openmarket.xcelerate.jsp.asset.FilterAssetsByDate.filter(inlist, outListName, sdate, ics);
142         if (i < 0 && i != -500) {
143             LOG.info("Errno set by com.openmarket.xcelerate.jsp.asset.FilterAssetsByDate.filter() while attempting to filter assets "
144                     + list + " by date: " + sdate + "(null date is ok). Errno: " + ics.GetErrno());
145             // note the above tag behaves erratically and errno is unreliable
146         }
147         ics.ClearErrno();
148         IList out = ics.GetList(outListName);
149         ics.RegisterList(outListName, null); // tidy up!
150 
151         if (out == null)
152             throw new IllegalStateException("Tag executed successfully but no outlist was returned");
153 
154         List<AssetId> olist = new ArrayList<AssetId>();
155 
156         boolean previewEnabled = PreviewContext.isSitePreviewEnabled(ics);
157 
158         for (Row row : new IListIterable(out)) {
159             AssetId id = AssetIdUtils.createAssetId(row.getString("assettype"), row.getLong("assetid"));
160             olist.add(id);
161             if (previewEnabled)
162                 logDependancy(ics, id);
163         }
164 
165         return olist;
166     }
167 
168     static private void logDependancy(ICS ics, AssetId id) {
169 
170         if (PreviewContext.isSitePreviewDelivery(ics)) {
171             final AssetData pageData = AssetDataUtils.getAssetData(ics, id, "startdate", "enddate");
172 
173             if (pageData != null) {
174                 String sdate = AttributeDataUtils.asString(pageData.getAttributeData("startdate"));
175                 String edate = AttributeDataUtils.asString(pageData.getAttributeData("enddate"));
176 
177                 if (StringUtils.isNotBlank(sdate) || StringUtils.isNotBlank(edate)) {
178                     CacheManager.RecordItem(ics,
179                             PubConstants.CACHE_PREFIX + id.getId() + PubConstants.SEPARATOR + id.getType(), null,
180                             sdate, edate);
181                 } else
182                     CacheManager.RecordItem(ics,
183                             PubConstants.CACHE_PREFIX + id.getId() + PubConstants.SEPARATOR + id.getType());
184             }
185         } else {
186             CacheManager
187                     .RecordItem(ics, PubConstants.CACHE_PREFIX + id.getId() + PubConstants.SEPARATOR + id.getType());
188         }
189         ics.ClearErrno();
190 
191     }
192 
193     /**
194      * Method to check to see if a date falls between two dates. The comparison
195      * date is a Date object, or null, in which case the current date is used.
196      * The boundary dates are JDBC format dates, and can be null, indication the
197      * dates aren't boudned.
198      * 
199      * @param startDateJdbc start date in jdbc format or null
200      * @param effectiveDate comparison date or null to use current date
201      * @param endDateJdbc end date in jdbc format
202      * @return true if the date is in the valid range; false otherwise.
203      */
204     public static boolean isDateWithinRange(String startDateJdbc, Date effectiveDate, String endDateJdbc) {
205         final Date startDate = goodString(startDateJdbc) ? parseJdbcDate(startDateJdbc) : null;
206         final Date endDate = goodString(endDateJdbc) ? parseJdbcDate(endDateJdbc) : null;
207         return isDateWithinRange(startDate, effectiveDate, endDate);
208     }
209 
210     /**
211      * Method to check to see if a date falls between two dates. The comparison
212      * date is a Date object, or null, in which case the current date is used.
213      * The boundary dates can be null, indication the dates aren't bounded.
214      * 
215      * @param startDate start date or null
216      * @param effectiveDate comparison date or null to use current date
217      * @param endDate end date or null
218      * @return true if the date is in the valid range; false otherwise.
219      */
220     public static boolean isDateWithinRange(Date startDate, Date effectiveDate, Date endDate) {
221         if (startDate == null && endDate == null) {
222             return true;
223         } else {
224             if (effectiveDate == null)
225                 effectiveDate = new Date();
226 
227             if (startDate == null) {
228                 return effectiveDate.before(endDate) || effectiveDate.equals(endDate);
229             } else if (endDate == null) {
230                 return startDate.before(effectiveDate) || startDate.equals(effectiveDate);
231             } else {
232                 return startDate.before(effectiveDate) && effectiveDate.before(endDate);
233             }
234         }
235     }
236 
237     /**
238      * Given an input string in JDBC form, parse it and return a date object.
239      * 
240      * @param string jdbc date string in the form yyyy-MM-dd HH:mm:ss
241      * @return Date
242      * @throws IllegalArgumentException on failure
243      */
244     public static Date parseJdbcDate(String string) {
245         try {
246             return DateUtils.parseDate(string, jdbcDateFormatStrings);
247         } catch (ParseException e) {
248             throw new IllegalArgumentException("Failure parsing string " + string, e);
249         }
250     }
251 }