001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.i18n; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsProperty; 032import org.opencms.file.CmsPropertyDefinition; 033import org.opencms.file.CmsResource; 034import org.opencms.main.CmsException; 035import org.opencms.main.CmsLog; 036import org.opencms.main.OpenCms; 037import org.opencms.site.CmsSite; 038 039import java.util.Collection; 040import java.util.Collections; 041import java.util.Comparator; 042import java.util.LinkedHashMap; 043import java.util.List; 044import java.util.Locale; 045import java.util.Map; 046import java.util.Set; 047 048import org.apache.commons.logging.Log; 049 050import com.google.common.collect.ArrayListMultimap; 051import com.google.common.collect.Lists; 052import com.google.common.collect.Maps; 053import com.google.common.collect.Multimap; 054import com.google.common.collect.Sets; 055 056/** 057 * Represents a group of resources which are locale variants of each other.<p> 058 */ 059public class CmsLocaleGroup { 060 061 /** The logger instance for this class. */ 062 private static final Log LOG = CmsLog.getLog(CmsLocaleGroup.class); 063 064 /** The CMS context to use. */ 065 private CmsObject m_cms; 066 067 /** The locale cache. */ 068 private Map<CmsResource, Locale> m_localeCache = Maps.newHashMap(); 069 070 /** The 'no translation' setting for this locale group. */ 071 private String m_noTranslation; 072 073 /** The primary resource. */ 074 private CmsResource m_primaryResource; 075 076 /** Map of resources by locale. */ 077 private Multimap<Locale, CmsResource> m_resourcesByLocale = ArrayListMultimap.create(); 078 079 /** The secondary resources. */ 080 private Set<CmsResource> m_secondaryResources; 081 082 /** 083 * Creates a new instance.<p> 084 * 085 * @param cms the CMS context to use 086 * @param primaryResource the primary resource 087 * @param secondaryResources the secondary resources 088 */ 089 public CmsLocaleGroup(CmsObject cms, CmsResource primaryResource, List<CmsResource> secondaryResources) { 090 m_primaryResource = primaryResource; 091 m_secondaryResources = Sets.newHashSet(secondaryResources); 092 m_cms = cms; 093 initLocales(); 094 } 095 096 /** 097 * Gets the list of all resources of this group (primary and secondary).<p> 098 * 099 * @return the list of all resources of this group 100 */ 101 public List<CmsResource> getAllResources() { 102 103 List<CmsResource> result = Lists.newArrayList(); 104 result.add(m_primaryResource); 105 for (CmsResource res : getSecondaryResources()) { 106 result.add(res); 107 } 108 return result; 109 } 110 111 /** 112 * Gets the main locale (i.e. the locale of the primary resource of this group).<p> 113 * 114 * @return the main locale 115 */ 116 public Locale getMainLocale() { 117 118 return m_localeCache.get(m_primaryResource); 119 } 120 121 /** 122 * Gets the primary resource.<p> 123 * 124 * @return the primary resource 125 */ 126 public CmsResource getPrimaryResource() { 127 128 return m_primaryResource; 129 } 130 131 /** 132 * Gets a map which contains the resources of the locale group as keys, indexed by their locale.<p> 133 * 134 * If the locale group contains more than one resource from the same locale,, which one is used a map value is undefined. 135 * 136 * @return the map of resources by locale 137 */ 138 public Map<Locale, CmsResource> getResourcesByLocale() { 139 140 List<CmsResource> resources = Lists.newArrayList(); 141 resources.add(m_primaryResource); 142 resources.addAll(m_secondaryResources); 143 Collections.sort(resources, new Comparator<CmsResource>() { 144 145 public int compare(CmsResource arg0, CmsResource arg1) { 146 147 String path1 = arg0.getRootPath(); 148 String path2 = arg1.getRootPath(); 149 return path2.compareTo(path1); 150 } 151 152 }); 153 Map<Locale, CmsResource> result = new LinkedHashMap<Locale, CmsResource>(); 154 for (CmsResource resource : resources) { 155 result.put(m_localeCache.get(resource), resource); 156 } 157 return result; 158 159 } 160 161 /** 162 * Gets the resources of this group which have the given locale.<p> 163 * 164 * @param locale a locale 165 * @return the collection of resources with the given locale 166 */ 167 public Collection<CmsResource> getResourcesForLocale(Locale locale) { 168 169 return Lists.newArrayList(m_resourcesByLocale.get(locale)); 170 } 171 172 /** 173 * Gets the secondary resources of this group.<p> 174 * 175 * @return the collection of secondary resources 176 */ 177 public Set<CmsResource> getSecondaryResources() { 178 179 return Collections.unmodifiableSet(m_secondaryResources); 180 } 181 182 /** 183 * Checks if this group has a resource with the given locale.<p> 184 * 185 * @param locale the locale 186 * @return true if the group has a resource with the locale 187 */ 188 public boolean hasLocale(Locale locale) { 189 190 return m_resourcesByLocale.containsKey(locale); 191 } 192 193 /** 194 * Checks if the locale group is marked as not translatable for the given locale.<p> 195 * 196 * @param locale a locale 197 * 198 * @return true if the locale group is marked as not translatable for the given locale 199 */ 200 public boolean isMarkedNoTranslation(Locale locale) { 201 202 return (m_noTranslation != null) && CmsLocaleManager.getLocales(m_noTranslation).contains(locale); 203 } 204 205 /** 206 * Checks if the locale group is marked as not translatable for any of the given locales.<p> 207 * 208 * @param locales a set of locales 209 * @return true if the locale group is marked as not translatable for any of the given resources 210 */ 211 public boolean isMarkedNoTranslation(Set<Locale> locales) { 212 213 if (m_noTranslation == null) { 214 return false; 215 } 216 List<Locale> noTranslationLocales = CmsLocaleManager.getLocales(m_noTranslation); 217 for (Locale locale : noTranslationLocales) { 218 if (locales.contains(locale)) { 219 return true; 220 } 221 } 222 return false; 223 } 224 225 /** 226 * Returns true if this is a potential group head, i.e. the locale of the primary resource is the main translation locale configured for the site 227 * in which it is located.<p> 228 * 229 * @return true if this is a potential group head 230 */ 231 public boolean isPotentialGroupHead() { 232 233 CmsSite site = OpenCms.getSiteManager().getSiteForRootPath(m_primaryResource.getRootPath()); 234 if (site == null) { 235 return false; 236 } 237 Locale mainLocale = site.getMainTranslationLocale(null); 238 if (mainLocale == null) { 239 return false; 240 } 241 Locale primaryLocale = getMainLocale(); 242 return mainLocale.equals(primaryLocale); 243 244 } 245 246 /** 247 * Checks if this group is a real group, i.e. consists of more than one resource.<p> 248 * 249 * @return true if this is a real group 250 */ 251 public boolean isRealGroup() { 252 253 return m_secondaryResources.size() > 0; 254 } 255 256 /** 257 * Checks if this is either a real group or a potential group head (i.e. a potential primary resource).<p> 258 * 259 * @return true if this is a real group or a potential group head 260 */ 261 public boolean isRealGroupOrPotentialGroupHead() { 262 263 return isRealGroup() || isPotentialGroupHead(); 264 } 265 266 /** 267 * Gets the locales of the resources from this locale group.<p> 268 * 269 * @return the locales of this locale group 270 */ 271 Set<Locale> getLocales() { 272 273 return Sets.newHashSet(getResourcesByLocale().keySet()); 274 } 275 276 /** 277 * Initializes the locales.<p> 278 * 279 */ 280 private void initLocales() { 281 282 if (!m_localeCache.isEmpty()) { 283 return; 284 } 285 readLocale(m_primaryResource); 286 for (CmsResource resource : m_secondaryResources) { 287 readLocale(resource); 288 } 289 for (Map.Entry<CmsResource, Locale> entry : m_localeCache.entrySet()) { 290 CmsResource key = entry.getKey(); 291 Locale value = entry.getValue(); 292 m_resourcesByLocale.put(value, key); 293 } 294 try { 295 CmsProperty noTranslationProp = m_cms.readPropertyObject( 296 m_primaryResource, 297 CmsPropertyDefinition.PROPERTY_LOCALE_NOTRANSLATION, 298 false); 299 m_noTranslation = noTranslationProp.getValue(); 300 } catch (CmsException e) { 301 LOG.error(e.getLocalizedMessage(), e); 302 303 } 304 } 305 306 /** 307 * Reads the locale for the given resource.<p> 308 * 309 * @param res the locale for the resource 310 */ 311 private void readLocale(CmsResource res) { 312 313 Locale locale = OpenCms.getLocaleManager().getDefaultLocale(m_cms, res); 314 m_localeCache.put(res, locale); 315 } 316 317}