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  package tools.gsf.facade.mda;
17  
18  import COM.FutureTense.Interfaces.FTValList;
19  import COM.FutureTense.Interfaces.ICS;
20  import com.fatwire.assetapi.data.AssetId;
21  import com.fatwire.cs.core.db.PreparedStmt;
22  import com.fatwire.cs.core.db.StatementParam;
23  import com.fatwire.mda.Dimension;
24  import com.fatwire.mda.DimensionException;
25  import com.fatwire.mda.DimensionFilterInstance;
26  import com.fatwire.mda.DimensionManager;
27  import com.fatwire.mda.DimensionSetInstance;
28  import com.fatwire.mda.DimensionableAssetManager;
29  import com.fatwire.system.Session;
30  import com.fatwire.system.SessionFactory;
31  import com.openmarket.xcelerate.asset.AssetIdImpl;
32  import org.apache.commons.lang3.StringUtils;
33  import org.slf4j.Logger;
34  import org.slf4j.LoggerFactory;
35  import tools.gsf.facade.runtag.asset.AssetLoadByName;
36  import tools.gsf.facade.runtag.render.LogDep;
37  import tools.gsf.facade.sql.IListIterable;
38  import tools.gsf.facade.sql.Row;
39  import tools.gsf.facade.sql.SqlHelper;
40  
41  import java.util.ArrayList;
42  import java.util.Arrays;
43  import java.util.Collection;
44  import java.util.Collections;
45  import java.util.Enumeration;
46  import java.util.List;
47  import java.util.Locale;
48  
49  public class DefaultLocaleService implements LocaleService {
50      private static final Logger LOG = LoggerFactory.getLogger("tools.gsf.facade.mda.DefaultLocaleService");
51  
52      /**
53       * the variable name for the id of the current Dimension
54       */
55  
56      private final String localeVar;
57  
58      /**
59       * the variable name for the current requested language
60       */
61  
62      private final String langVar;
63  
64      private final ICS ics;
65  
66      private Session session;
67  
68      /**
69       * Constructor with "lang" and "locale" as variable names for langVar and
70       * localeVar.
71       *
72       * @param ics Content Server context object
73       */
74      public DefaultLocaleService(final ICS ics) {
75          this(ics, "lang", "locale");
76      }
77  
78      /**
79       * Constructor.
80       *
81       * @param ics       Content Server context object
82       * @param langVar   the name of the ics variable for the current 'language',
83       *                  as in en_US.
84       * @param localeVar the name of the ics variable for the current dimension
85       *                  id.
86       */
87      public DefaultLocaleService(ICS ics, String langVar, String localeVar) {
88          if (ics == null) {
89              throw new IllegalArgumentException("ICS must not be null.");
90          }
91  
92          this.ics = ics;
93          this.langVar = langVar;
94          this.localeVar = localeVar;
95  
96      }
97  
98      /*
99       * (non-Javadoc)
100      * 
101      * @see
102      * tools.gsf.facade.mda.LocaleService#findTranslation(java
103      * .lang.String, java.lang.String, java.lang.String, java.lang.String)
104      */
105     @Override
106     public AssetId findTranslation(final String c, final String cid, final String site,
107                                    final String preferredLocaleDimensionId) {
108         return findTranslation(new AssetIdImpl(c, Long.parseLong(cid)), site,
109                 Long.parseLong(preferredLocaleDimensionId));
110     }
111 
112     /*
113      * (non-Javadoc)
114      * 
115      * @see
116      * tools.gsf.facade.mda.LocaleService#findTranslation(com
117      * .fatwire.assetapi.data.AssetId, java.lang.String, long)
118      */
119 
120     @Override
121     public AssetId findTranslation(final AssetId id, final String site, final long preferredDimension) {
122 
123         final long dimensionSetId = locateDimensionSetForSite(site);
124 
125         return findTranslation(id, preferredDimension, dimensionSetId);
126     }
127 
128     /*
129      * (non-Javadoc)
130      * 
131      * @see
132      * tools.gsf.facade.mda.LocaleService#findTranslation(com
133      * .fatwire.assetapi.data.AssetId, long, long)
134      */
135 
136     @Override
137     public AssetId findTranslation(final AssetId id, final long preferredDimension, final long dimensionSetId) {
138         if (id == null) {
139             throw new IllegalArgumentException("Required Asset ID missing");
140         }
141 
142         if (_isInputAssetDimensionPreferred(id, preferredDimension)) {
143             LOG.debug("Input dimension is already in the preferred dimension.  Not invoking dimension set filter.  Asset: "
144                     + id + ", dimension: " + preferredDimension);
145             return id;
146         } else {
147             LOG.debug("About to look for translations.  Input asset id: " + id + ", dimension set: " + dimensionSetId
148                     + ", preferred dimension: " + preferredDimension);
149         }
150 
151         // *****************************************************************************
152         // The core business logic of this helper class is encapsulated in these
153         // 3 lines
154         final DimensionSetInstance dimset = _getDimensionSet(dimensionSetId);
155         return findTranslation(id, preferredDimension, dimset);
156 
157     }
158 
159     /*
160      * (non-Javadoc)
161      * 
162      * @see
163      * tools.gsf.facade.mda.LocaleService#findTranslation(com
164      * .fatwire.assetapi.data.AssetId, long, java.lang.String)
165      */
166 
167     @Override
168     public AssetId findTranslation(final AssetId id, final long preferredDimension, final String dimensionSetName) {
169         if (id == null) {
170             throw new IllegalArgumentException("Required Asset ID missing");
171         }
172         final Dimension locale = getLocaleForAsset(id);
173 
174         if (locale == null) {
175             LOG.debug("Asset is not localized.  Not invoking dimension set filter.  Asset: " + id);
176             return id;
177         }
178         if (locale.getId().getId() == preferredDimension) {
179             LOG.debug("Input dimension is already in the preferred dimension.  Not invoking dimension set filter.  Asset: "
180                     + id + ", dimension: " + preferredDimension);
181             return id;
182         } else {
183             LOG.debug("About to look for translations.  Input asset id: " + id + ", dimension set: " + dimensionSetName
184                     + ", preferred dimension: " + preferredDimension);
185         }
186 
187         // *****************************************************************************
188         // The core business logic of this helper class is encapsulated in these
189         // 3 lines
190         final DimensionSetInstance dimset = getDimensionSet(dimensionSetName);
191 
192         return findTranslation(id, preferredDimension, dimset);
193     }
194 
195     /*
196      * (non-Javadoc)
197      * 
198      * @see
199      * tools.gsf.facade.mda.LocaleService#findTranslation(com
200      * .fatwire.assetapi.data.AssetId, long,
201      * com.fatwire.mda.DimensionSetInstance)
202      */
203 
204     @Override
205     public AssetId findTranslation(final AssetId id, final long preferredDimension, final DimensionSetInstance dimset) {
206 
207         final DimensionFilterInstance filter = _getPopulatedDimensionFilter(dimset, preferredDimension);
208         AssetId translated = findTranslation(id, filter);
209         if (translated == null) {
210             LOG.warn("No translation found for asset " + id + " in dimension set " + dimset.getId() + " for dimension "
211                     + preferredDimension + ".");
212         }
213         return translated;
214     }
215 
216     // ///////////////////////////////////////////////////////////////////////////
217     // Helper functions
218 
219     private boolean _isInputAssetDimensionPreferred(final AssetId id, final long preferredDimension) {
220         final Dimension dim = getLocaleForAsset(id);
221         if (dim == null) {
222             return true; // if locale not found, tell that the asset is expected
223         }
224         // locale
225         return dim.getId().getId() == preferredDimension;
226     }
227 
228     private static final PreparedStmt FIND_DIMSET_FOR_SITE_PREPAREDSTMT = new PreparedStmt(
229             "select ds.id as id from DimensionSet ds, Publication p, AssetPublication ap where p.name = ? and p.id = ap.pubid and ap.assetid = ds.id and ds.status != 'VO' order by ds.updateddate",
230             Arrays.asList("DimensionSet", "AssetPublication", "Publication"));
231 
232     static {
233         FIND_DIMSET_FOR_SITE_PREPAREDSTMT.setElement(0, "Publication", "name");
234     }
235 
236     /**
237      * Locates a single dimension set in a site. If no match is found, an
238      * exception is thrown. If more than one match is found, an exception is
239      * thrown.
240      *
241      * @param site site containing a dimension set
242      * @return DimensionSet ID
243      */
244     public long locateDimensionSetForSite(final String site) {
245         if (StringUtils.isBlank(site)) {
246             throw new IllegalArgumentException("Required site name missing");
247         }
248         final StatementParam params = FIND_DIMSET_FOR_SITE_PREPAREDSTMT.newParam();
249         params.setString(0, site);
250         final IListIterable list = SqlHelper.select(ics, FIND_DIMSET_FOR_SITE_PREPAREDSTMT, params);
251 
252         final int numRows = list.size();
253         if (numRows == 0) {
254             throw new IllegalStateException(
255                     "A DimensionSet has not been defined for site '"
256                             + site
257                             + "'. Cannot determine any translation unless some locales (Dimensions) are enabled for that site. Aborting operation.");
258         }
259         if (numRows > 1) {
260             final StringBuilder msg = new StringBuilder("More than one dimension set found in site " + site
261                     + ".  Exactly one is expected.  Dimension set ids: ");
262             for (final Row row : list) {
263                 final String id = row.getString("id");
264                 LogDep.logDep(ics, "DimensionSet", id);
265                 msg.append(id).append(" ");
266             }
267             throw new IllegalStateException(msg.append(".").toString());
268         }
269 
270         final String id = list.iterator().next().getString("id");
271         LogDep.logDep(ics, "DimensionSet", id);
272         return Long.parseLong(id);
273     }
274 
275     private DimensionFilterInstance _getPopulatedDimensionFilter(final DimensionSetInstance dimset,
276                                                                  final long dimensionId) {
277 
278         // Set the filter's preferred dimension
279         // Equivalent to:
280         // %><dimensionset:asset assettype="Dimension"
281         // assetid="<%=localeDimensionId%>" /><%
282         final Dimension preferredDimension = getDM().loadDimension(dimensionId);
283         if (preferredDimension == null) {
284             throw new RuntimeException("Attempted to load Dimension with id " + dimensionId + " but it came back null");
285         }
286         return _getPopulatedDimensionFilter(dimset, preferredDimension);
287     }
288 
289     private DimensionFilterInstance _getPopulatedDimensionFilter(final DimensionSetInstance dimset,
290                                                                  final Dimension preferredDimension) {
291         DimensionFilterInstance filter;
292         try {
293             filter = dimset.getFilter();
294         } catch (final DimensionException e) {
295             throw new RuntimeException("Could not get Dimension Filter from DimensionSet", e);
296         }
297 
298         filter.setDimensonPreference(Collections.singletonList(preferredDimension));
299         return filter;
300     }
301 
302     private DimensionSetInstance _getDimensionSet(final long dimSetId) {
303         final String DIMSET_OBJ_NAME = "LocaleUtils:findTranslation:theDimensionSet:DimensionSet";
304         // Load the site-specific DimensionSet asset
305         ics.SetObj(DIMSET_OBJ_NAME, null); // clear first
306         final FTValList args = new FTValList();
307         args.put("NAME", DIMSET_OBJ_NAME);
308         args.put("TYPE", "DimensionSet");
309         args.put("OBJECTID", Long.toString(dimSetId));
310         args.put("EDITABLE", "FALSE");
311         ics.runTag("ASSET.LOAD", args);
312 
313         if (ics.GetErrno() < 0) {
314             throw new IllegalStateException("Could not load dimension set.  Errno: " + ics.GetErrno());
315         }
316 
317         final Object o = ics.GetObj(DIMSET_OBJ_NAME);
318         ics.SetObj(DIMSET_OBJ_NAME, null);
319         if (o == null) {
320             throw new IllegalStateException("Could not load dimension set but we got no errno... unexpected...");
321         }
322 
323         DimensionSetInstance dimset;
324         if (o instanceof DimensionSetInstance) {
325             dimset = (DimensionSetInstance) o;
326         } else {
327             throw new IllegalStateException("Loaded an asset that is not a DimensionSetInstance.");
328         }
329         return dimset;
330     }
331 
332     /*
333      * (non-Javadoc)
334      * 
335      * @see
336      * tools.gsf.facade.mda.LocaleService#getDimensionSet(java
337      * .lang.String)
338      */
339 
340     @Override
341     public DimensionSetInstance getDimensionSet(final String name) {
342         final String DIMSET_OBJ_NAME = "LocaleUtils:findTranslation:theDimensionSet:DimensionSet";
343         ics.SetObj(DIMSET_OBJ_NAME, null);
344         final AssetLoadByName a = new AssetLoadByName();
345         a.setAssetType("DimensionSet");
346         a.setAssetName(name);
347         a.setEditable(false);
348         a.setName(DIMSET_OBJ_NAME);
349         a.execute(ics);
350 
351         if (ics.GetErrno() < 0) {
352             throw new IllegalStateException("Could not load dimension set.  Errno: " + ics.GetErrno());
353         }
354 
355         final Object o = ics.GetObj(DIMSET_OBJ_NAME);
356         ics.SetObj(DIMSET_OBJ_NAME, null);
357         if (o == null) {
358             throw new IllegalStateException("Could not load dimension set but we got no errno... unexpected...");
359         }
360 
361         DimensionSetInstance dimset;
362         if (o instanceof DimensionSetInstance) {
363             dimset = (DimensionSetInstance) o;
364         } else {
365             throw new IllegalStateException("Loaded an asset that is not a DimensionSetInstance");
366         }
367         return dimset;
368     }
369 
370     private DimensionableAssetManager dam;
371 
372     /**
373      * Shorthand function for returning the DimensionableAssetManager.
374      *
375      * @return DimensionableAssetManager
376      */
377     public DimensionableAssetManager getDAM() {
378         if (dam == null) {
379             dam = getManager(DimensionableAssetManager.class);
380         }
381         return dam;
382     }
383 
384     private DimensionManager dm;
385 
386     /**
387      * Shorthand function for returning the DimensionManager.
388      *
389      * @return DimensionManager
390      */
391     protected DimensionManager getDM() {
392         if (dm == null) {
393             dm = getManager(DimensionManager.class);
394         }
395         return dm;
396     }
397 
398     /*
399      * (non-Javadoc)
400      * 
401      * @see
402      * tools.gsf.facade.mda.LocaleService#getLocaleForAsset
403      * (com.fatwire.assetapi.data.AssetId)
404      */
405 
406     @Override
407     public Dimension getLocaleForAsset(final AssetId id) {
408         final Collection<Dimension> dims = getDAM().getDimensionsForAsset(id);
409         for (final Dimension dim : dims) {
410             if ("locale".equalsIgnoreCase(dim.getGroup())) {
411                 return dim;
412             }
413         }
414         return null;
415     }
416 
417     /*
418      * (non-Javadoc)
419      * 
420      * @see
421      * tools.gsf.facade.mda.LocaleService#getDimensionIdForName
422      * (java.lang.String)
423      */
424 
425     @Override
426     public long getDimensionIdForName(final String name) {
427         final AssetId id = getDimensionAssetIdForName(name);
428         return id == null ? -1 : id.getId();
429     }
430 
431     /*
432      * (non-Javadoc)
433      * 
434      * @see "tools.gsf.facade.mda.LocaleService#"
435      * getDimensionAssetIdForName(java.lang.String)
436      */
437 
438     @Override
439     public AssetId getDimensionAssetIdForName(final String name) {
440         final Dimension dim = getDimensionForName(name);
441         return dim == null ? null : dim.getId();
442     }
443 
444     /*
445      * (non-Javadoc)
446      * 
447      * @see
448      * tools.gsf.facade.mda.LocaleService#getDimensionForName
449      * (java.lang.String)
450      */
451 
452     @Override
453     public Dimension getDimensionForName(final String name) {
454         return getDM().loadDimension(name);
455 
456     }
457 
458     /*
459      * (non-Javadoc)
460      * 
461      * @see
462      * tools.gsf.facade.mda.LocaleService#getNameForDimensionId
463      * (long)
464      */
465 
466     @Override
467     public String getNameForDimensionId(final long dimensionid) {
468         final Dimension dim = getDM().loadDimension(dimensionid);
469         return dim == null ? null : dim.getName();
470     }
471 
472     protected Session getSession() {
473         if (session == null) {
474             session = SessionFactory.getSession(ics);
475 
476         }
477         return session;
478     }
479 
480     @SuppressWarnings("unchecked")
481     protected <T> T getManager(final Class<T> c) {
482         return (T) getSession().getManager(c.getName());
483     }
484 
485     @Override
486     public AssetId findTranslation(AssetId id, DimensionFilterInstance filter) {
487         // Get the relatives using the appropriate filter
488         final Collection<AssetId> relatives = getDAM().getRelatives(id, filter, "Locale");
489         // *****************************************************************************
490 
491         // make the result pretty
492         if (relatives == null) {
493             LOG.debug("No translation found for asset " + id + ".");
494             return null;
495         } else {
496             switch (relatives.size()) {
497                 case 0: {
498                     LOG.debug("No translation found for " + id + ".");
499                     // Note May 4, 2010 by Tony Field - this had been changed to
500                     // return the input ID but that
501                     // is incorrect. The contract clearly states that null is to
502                     // be returned if no matching
503                     // relatives are found. When null is returned and it is not
504                     // expected, often the incorrect
505                     // dimension filter is configured.
506                     return null;
507                 }
508                 case 1: {
509                     final AssetId relative = relatives.iterator().next();
510                     LOG.trace("LocaleUtils.findTranslation: RELATIVE FOUND... " + relative.getType() + " '"
511                             + relative.getId() + "' // errno = " + ics.GetErrno());
512                     return relative;
513 
514                 }
515                 default: {
516                     throw new IllegalStateException("found more than one translation for asset " + id
517                             + " and that is not supposed to be possible.");
518                 }
519             }
520         }
521     }
522 
523     /**
524      * Return a dimension filter instance corresponding to the dimension set
525      * specified by the user (or discovered by the tag). The dimension filter is
526      * configured with the preferred dimensions of the user (also configured).
527      * <p>
528      * The preferred locales are identified by checking the following locations,
529      * in the order specified:
530      * <ol>
531      * <li>set by the lang attribute by locale name
532      * <li>detected by finding the locale dimension id in the ics variable
533      * "locale"
534      * <li>detected by finding the locale name in the ics variable "locale"
535      * <li>detected by finding the locale dimension id in the ics session
536      * variable "locale"
537      * <li>detected by finding the locale name in the ics session variable
538      * "locale"
539      * <li>detected by reading the Accept-Language header
540      * </ol>
541      * The dimension set is identified by checking in the following places, in
542      * order:
543      * <ol>
544      * <li>set by the dimset attribute by name of dimension set
545      * <li>set by dimset attribute by the id of the dimension set
546      * <li>looked up by finding the site name in the ics variable "site" and
547      * loading the single dimension set associated with that site
548      * </ol>
549      *
550      * @return a dimension filter, configured with the set preferred locales, or
551      * null, if either the dimension set or the preferred dimensions
552      * could not be found (with extensive errors)
553      */
554     public DimensionFilterInstance getDimensionFilter(String site) {
555 
556         DimensionFilterInstance filter;
557         try {
558             DimensionSetInstance dimSet = locateDimensionSetInstanceForSite(site);
559             if (dimSet == null) {
560                 if (LOG.isTraceEnabled()) {
561                     LOG.trace("no DimensionSet returned from getDimensionSet().");
562                 }
563                 return null;
564             }
565             Collection<AssetId> preferredLocales = getPreferredLocales();
566 
567             filter = DimensionUtils.getDimensionFilter(DimensionUtils.getDM(ics), preferredLocales, dimSet);
568             if (LOG.isDebugEnabled()) {
569                 LOG.debug("Located dimension filter: " + filter + " in dimensionSet " + dimSet
570                         + " with preferred locales: " + preferredLocales + " ");
571             }
572         } catch (DimensionException e) {
573             LOG.error("Could not locate dimension filter", e);
574             filter = null;
575         } catch (RuntimeException e) {
576             LOG.error("Could not locate dimension filter", e);
577             filter = null;
578         }
579         return filter;
580     }
581 
582     /**
583      * Get the locale that the user explicitly specified. If not set, null is
584      * returned.
585      *
586      * @return the id of the locale that the user explicitly set. Handles
587      * setting by name or assetid.
588      */
589     protected final AssetId getExplicitlySpecifiedLocale() {
590 
591         String localeName = ics.GetVar(langVar);
592         // check for explicitly specified by name
593         if (StringUtils.isNotBlank(localeName)) {
594             Dimension d = DimensionUtils.getDimensionForName(ics, localeName);
595             if (d != null) {
596                 LOG.trace("Preferred locale explicitly set to " + localeName);
597                 return d.getId();
598             }
599         }
600         return null;
601     }
602 
603     /**
604      * Get the ordered list of preferred locales that the user wants. Multiple
605      * attempts are made to figure out the right locale.
606      *
607      * @return collection of asset identifiers of the preferred locales
608      */
609     protected final Collection<AssetId> getPreferredLocales() {
610         AssetId result = getExplicitlySpecifiedLocale();
611         if (result != null) {
612             return Collections.singleton(result);
613         }
614 
615         // next, check for implicitly specified by ID using locale variable
616         String l = ics.GetVar(localeVar);
617         try {
618             long localeIdFromVar = Long.parseLong(l);
619             DimensionManager dm = DimensionUtils.getDM(ics);
620             Dimension d = dm.loadDimension(localeIdFromVar);
621             if (d != null) {
622                 LOG.trace("Preferred locale detected in ICS context using 'locale' variable: " + localeIdFromVar);
623                 return Collections.singletonList(d.getId());
624             }
625         } catch (NumberFormatException e) {
626             // maybe it's a locale name...
627             try {
628                 Dimension d = DimensionUtils.getDimensionForName(ics, localeVar);
629                 if (d != null) {
630                     LOG.trace("Preferred locale detected in ICS context using 'locale' variable: " + localeVar);
631                     return Collections.singletonList(d.getId());
632                 }
633             } catch (Exception ex) {
634                 // nope... don't worry, we'll find it....
635             }
636         }
637 
638         // next, check for implicitly specified by ID using locale session
639         // variable
640         String localeSSVar = ics.GetSSVar(localeVar);
641         try {
642             long localeIdFromSSVar = Long.parseLong(localeSSVar);
643             DimensionManager dm = DimensionUtils.getDM(ics);
644             Dimension d = dm.loadDimension(localeIdFromSSVar);
645             if (d != null) {
646                 LOG.trace("Preferred locale detected in ICS context using 'locale' session variable: "
647                         + localeIdFromSSVar);
648                 return Collections.singletonList(d.getId());
649             }
650         } catch (NumberFormatException e) {
651             // maybe it's a locale name...
652             try {
653                 Dimension d = DimensionUtils.getDimensionForName(ics, localeSSVar);
654                 if (d != null) {
655                     LOG.trace("Preferred locale detected in ICS context using 'locale' session variable: "
656                             + localeSSVar);
657                     return Collections.singletonList(d.getId());
658                 }
659             } catch (Exception ex) {
660                 // nope... don't worry, we'll find it....
661             }
662         }
663 
664         // finally, get the locale from the servlet request's Accept-Language
665         // header..
666         List<AssetId> preferredLocales = new ArrayList<AssetId>();
667         @SuppressWarnings({"rawtypes", "deprecation"})
668         Enumeration locales = ics.getIServlet().getServletRequest().getLocales();
669         while (locales.hasMoreElements()) {
670             Locale locale = (Locale) locales.nextElement();
671             if (locale != null) {
672                 String localeName = locale.toString();
673                 if (localeName != null && localeName.length() > 0) {
674                     try {
675                         Dimension dimension = DimensionUtils.getDimensionForName(ics, localeName);
676                         if (dimension != null) {
677                             preferredLocales.add(dimension.getId());
678                             LOG.trace("Found registered locale in user's Accept-Language header (or default): "
679                                     + localeName);
680                         }
681                     } catch (RuntimeException e) {
682                         // don't care if the dimension is not in the system -
683                         // they probably won't all be there
684                         // and we're guessing anyway, so it's okay.
685                         LOG.trace(
686                                 "Found a locale in the user's Accept-Language header, but it was not registered as a dimension: "
687                                         + localeName + " (this is not usually an error)", e);
688                     }
689                 }
690             }
691         }
692         return preferredLocales;
693     }
694 
695     /**
696      * Returns the DimensionSetInstance. This implementation expects one
697      * DimensionSet enabled for the current site.
698      *
699      * @param site current site
700      * @return dimension set instance
701      */
702     public final DimensionSetInstance locateDimensionSetInstanceForSite(String site) {
703         try {
704             if (StringUtils.isNotBlank(site)) {
705                 long discoveredId = locateDimensionSetForSite(site);
706                 LOG.trace("Auto-discovered dimension set because there is only one in site " + site + ": DimensionSet:"
707                         + discoveredId);
708                 return _getDimensionSet(discoveredId);
709             }
710         } catch (RuntimeException e) {
711             if (LOG.isTraceEnabled()) {
712                 LOG.trace("Could not auto-discover dimensionset: " + e);
713             }
714         }
715         return null;
716     }
717 }