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.taglib;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.Collections;
21  import java.util.Enumeration;
22  import java.util.List;
23  import java.util.Locale;
24  
25  import COM.FutureTense.Interfaces.ICS;
26  
27  import com.fatwire.assetapi.data.AssetId;
28  import com.fatwire.gst.foundation.facade.mda.DimensionUtils;
29  import com.fatwire.gst.foundation.facade.mda.LocaleUtils;
30  import com.fatwire.mda.Dimension;
31  import com.fatwire.mda.DimensionException;
32  import com.fatwire.mda.DimensionFilterInstance;
33  import com.fatwire.mda.DimensionManager;
34  import com.fatwire.mda.DimensionSetInstance;
35  
36  import org.apache.commons.logging.Log;
37  import org.apache.commons.logging.LogFactory;
38  
39  /**
40   * simple tag for translating an asset
41   *
42   * @author Tony Field
43   * @since 2011-11-28
44   */
45  public abstract class MultilingualGsfSimpleTag extends GsfSimpleTag {
46      protected static final Log LOG = LogFactory.getLog("com.fatwire.gst.foundation.taglib");
47  
48      private String dimensionSetName = null;
49      private long dimensionSetId = -1L;
50      private String localeName = null;
51      private long localeId = -1L;
52  
53      public final void setDimset(String s) {
54          try {
55              dimensionSetId = Long.parseLong(s);
56          } catch (NumberFormatException e) {
57              dimensionSetName = s;
58              dimensionSetId = -1L;
59          }
60      }
61  
62      public final void setLocale(String s) {
63          try {
64              localeId = Long.parseLong(s);
65          } catch (NumberFormatException e) {
66              localeName = s;
67              localeId = -1L;
68          }
69      }
70  
71      /**
72       * Return a dimension filter instance corresponding to the dimension set specified by the user (or discovered by
73       * the tag).  The dimension filter is configured with the preferred dimensions of the user (also onfigured).
74       *
75       * The preferred locales are identified by checking the following locations, in the order specified:
76       * 1) set by the locale attribute by id of locale
77       * 2) set by locale attribute by name of locale
78       * 3) detected by finding the locale dimension id in the ics variable "locale"
79       * 4) detected by finding the locale name in the ics variable "locale"
80       * 5) detected by finding the locale dimension id in the ics session variable "locale"
81       * 6) detected by finding the locale name in the ics session variable "locale"
82       * 7) detected by reading the Accept-Language header
83       *
84       * The dimension set is identified by checking in the following places, in order:
85       * 1) set by the dimset attribute by name of dimension set
86       * 2) set by dimset attribute by the id of the dimension set
87       * 3) looked up by finding the site name in the ics variable "site" and loading the single dimension set associated with that site
88       *
89       * @return a dimension filter, configured with the set preferred locales, or null, if either the dimenion set or the
90       * preferred dimensions could not be found (with extensive errors)
91       */
92      protected final DimensionFilterInstance getDimensionFilter() {
93          ICS ics = getICS();
94          DimensionFilterInstance filter;
95          try {
96              Collection<AssetId> preferredLocales = getPreferredLocales();
97              DimensionSetInstance dimSet = getDimensionSet();
98              filter = DimensionUtils.getDimensionFilter(DimensionUtils.getDM(ics), preferredLocales, dimSet);
99              if (LOG.isDebugEnabled()) {
100                 LOG.debug("Multilingual-enabled tag located dimension filter: " + filter + " in dimensionSet " + dimSet + " with preferred locales: " + preferredLocales + " ");
101             }
102         } catch (DimensionException e) {
103             LOG.error("Multilingual-enabled tag could not locate dimension filter", e);
104             filter = null;
105         } catch (RuntimeException e) {
106             LOG.error("Multilingual-enabled tag could not locate dimension filter", e);
107             filter = null;
108         }
109         return filter;
110     }
111 
112     /**
113      * Get the locale that the user explicitly specified.  If not set, null is returned.
114      * @return the id of the locale that the user explicitly set.  Handles setting by name or assetid.
115      */
116     protected final AssetId getExplicitlySpecifiedLocale() {
117         ICS ics = getICS();
118         // first, check for explicitly specified by ID
119         if (localeId != -1L) {
120             DimensionManager dm = DimensionUtils.getDM(ics);
121             Dimension d = dm.loadDimension(localeId);
122             if (d != null) {
123                 LOG.trace("Preferred locale explicitly set to " + localeId);
124                 return d.getId();
125             }
126         }
127 
128         // next, check for explicitly specified by name
129         if (localeName != null) {
130             Dimension d = DimensionUtils.getDimensionForName(ics, localeName);
131             if (d != null) {
132                 LOG.trace("Preferred locale explicitly set to " + localeName);
133                 return d.getId();
134             }
135         }
136         return null;
137     }
138     /**
139      * Get the ordered list of preferred locales that the user wants.  Multiple attempts are made to figure out the right locale.
140      * @return collection of asset identifiers of the preferred locales 
141      */
142     protected final Collection<AssetId> getPreferredLocales() {
143         AssetId result = getExplicitlySpecifiedLocale();
144         if (result != null) return Collections.singleton(result);
145 
146         ICS ics = getICS();
147 
148         // next, check for implicitly specified by ID using locale variable
149         String localeVar = getICS().GetVar("locale");
150         try {
151             long localeIdFromVar = Long.parseLong(localeVar);
152             DimensionManager dm = DimensionUtils.getDM(ics);
153             Dimension d = dm.loadDimension(localeIdFromVar);
154             if (d != null) {
155                 LOG.trace("Preferred locale detected in ICS context using 'locale' variable: " + localeIdFromVar);
156                 return Collections.singletonList(d.getId());
157             }
158         } catch (NumberFormatException e) {
159             // maybe it's a locale name...
160             try {
161                 Dimension d = DimensionUtils.getDimensionForName(ics, localeVar);
162                 if (d != null) {
163                     LOG.trace("Preferred locale detected in ICS context using 'locale' variable: " + localeVar);
164                     return Collections.singletonList(d.getId());
165                 }
166             } catch (Exception ex) {
167                 // nope... don't worry, we'll find it....
168             }
169         }
170 
171         // next, check for implicitly specified by ID using locale session variable
172         String localeSSVar = getICS().GetSSVar("locale");
173         try {
174             long localeIdFromSSVar = Long.parseLong(localeSSVar);
175             DimensionManager dm = DimensionUtils.getDM(ics);
176             Dimension d = dm.loadDimension(localeIdFromSSVar);
177             if (d != null) {
178                 LOG.trace("Preferred locale detected in ICS context using 'locale' session variable: " + localeIdFromSSVar);
179                 return Collections.singletonList(d.getId());
180             }
181         } catch (NumberFormatException e) {
182             // maybe it's a locale name...
183             try {
184                 Dimension d = DimensionUtils.getDimensionForName(ics, localeSSVar);
185                 if (d != null) {
186                     LOG.trace("Preferred locale detected in ICS context using 'locale' session variable: " + localeSSVar);
187                     return Collections.singletonList(d.getId());
188                 }
189             } catch (Exception ex) {
190                 // nope... don't worry, we'll find it....
191             }
192         }
193 
194         // finally, get the locale from the servlet request's Accept-Language header..
195         List<AssetId> preferredLocales = new ArrayList<AssetId>();
196         @SuppressWarnings({ "rawtypes", "deprecation" })
197         Enumeration locales = ics.getIServlet().getServletRequest().getLocales();
198         while (locales.hasMoreElements()) {
199             Locale locale = (Locale) locales.nextElement();
200             if (locale != null) {
201                 String localeName = locale.toString();
202                 if (localeName != null && localeName.length() > 0) {
203                     try {
204                         Dimension dimension = DimensionUtils.getDimensionForName(ics, localeName);
205                         preferredLocales.add(dimension.getId());
206                         LOG.trace("Found registered locale in user's Accept-Language header (or default): " + localeName);
207                     } catch (RuntimeException e) {
208                         // don't care if the dimension is not in the system - they probably won't all be there
209                         // and we're guessing anyway, so it's okay.
210                         LOG.trace("Found a locale in the user's Accept-Language header, but it was not registered as a dimension: " + localeName + " (this is not usually an error)", e);
211                     }
212                 }
213             }
214         }
215         return preferredLocales;
216     }
217 
218     private final DimensionSetInstance getDimensionSet() {
219         if (dimensionSetName != null) {
220             return LocaleUtils.getDimensionSet(getICS(), dimensionSetName);
221         }
222         if (dimensionSetId != -1L) {
223             return LocaleUtils.getDimensionSet(getICS(), dimensionSetId);
224         }
225         try {
226             ICS ics = getICS();
227             String site = ics.GetVar("site");
228             if (site != null && site.length() > 0) {
229                 long discoveredId = LocaleUtils.locateDimensionSetForSite(ics, site);
230                 LOG.trace("Auto-discovered dimension set because there is only one in site " + site + ": DimensionSet:" + discoveredId);
231                 return LocaleUtils.getDimensionSet(ics, discoveredId);
232             }
233         } catch (RuntimeException e) {
234             LOG.trace("Could not auto-discovered dimensionset: " + e);
235         }
236         throw new IllegalArgumentException("DimensionSet not found");
237     }
238 }