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.ade.containerpage; 029 030import org.opencms.ade.configuration.CmsADEConfigData; 031import org.opencms.ade.configuration.CmsElementView; 032import org.opencms.ade.configuration.CmsResourceTypeConfig; 033import org.opencms.ade.configuration.CmsResourceTypeConfig.AddMenuType; 034import org.opencms.ade.configuration.CmsResourceTypeConfig.AddMenuVisibility; 035import org.opencms.ade.galleries.CmsGalleryService; 036import org.opencms.ade.galleries.shared.CmsResourceTypeBean; 037import org.opencms.ade.galleries.shared.CmsResourceTypeBean.Origin; 038import org.opencms.file.CmsObject; 039import org.opencms.file.types.CmsResourceTypeXmlContainerPage; 040import org.opencms.file.types.I_CmsResourceType; 041import org.opencms.main.CmsException; 042import org.opencms.main.CmsLog; 043import org.opencms.main.OpenCms; 044import org.opencms.security.CmsPermissionSet; 045import org.opencms.security.CmsRole; 046import org.opencms.util.CmsUUID; 047import org.opencms.workplace.explorer.CmsExplorerTypeSettings; 048 049import java.util.ArrayList; 050import java.util.Collections; 051import java.util.Comparator; 052import java.util.HashSet; 053import java.util.List; 054import java.util.Map; 055import java.util.Set; 056 057import org.apache.commons.logging.Log; 058 059import com.google.common.collect.ArrayListMultimap; 060import com.google.common.collect.ComparisonChain; 061import com.google.common.collect.Lists; 062import com.google.common.collect.Maps; 063import com.google.common.collect.Multimap; 064import com.google.common.collect.Sets; 065 066/** 067 * Helper class for preparing the resource type lists for gallery and new dialog.<p> 068 * 069*/ 070public class CmsAddDialogTypeHelper { 071 072 /** Logger instance for this class. */ 073 private static final Log LOG = CmsLog.getLog(CmsAddDialogTypeHelper.class); 074 075 /** All types from the ADE config previously processed. */ 076 private Set<String> m_allAdeTypes = Sets.newHashSet(); 077 078 /** Cached type lists. */ 079 private Multimap<CmsUUID, CmsResourceTypeBean> m_cachedTypes; 080 081 /** All types from the ADE config previously included in a result list. */ 082 private Set<String> m_includedAdeTypes = Sets.newHashSet(); 083 084 /** The menu type. */ 085 private AddMenuType m_menuType; 086 087 /** 088 * Creates a new instance.<p> 089 * 090 * @param type the menu type for which we want to build a type list 091 */ 092 public CmsAddDialogTypeHelper(AddMenuType type) { 093 094 LOG.debug("Creating type helper."); 095 m_menuType = type; 096 } 097 098 /** 099 * Gets the precomputed type list for the given view.<p> 100 * 101 * @param view the element view 102 * @return the precomputed type list, or null if the list wasn't precomputed 103 */ 104 public List<CmsResourceTypeBean> getPrecomputedTypes(CmsElementView view) { 105 106 return Lists.newArrayList(m_cachedTypes.get(view.getId())); 107 } 108 109 /** 110 * Creates list of resource type beans for gallery or 'New' dialog.<p> 111 * 112 * @param cms the CMS context 113 * @param folderRootPath the current folder 114 * @param checkViewableReferenceUri the reference uri to use for viewability check 115 * @param elementView the element view 116 * @param checkEnabled object to check whether resource types should be enabled 117 * 118 * @return the list of resource type beans 119 * 120 * @throws CmsException if something goes wrong 121 */ 122 public List<CmsResourceTypeBean> getResourceTypes( 123 CmsObject cms, 124 String folderRootPath, 125 String checkViewableReferenceUri, 126 CmsElementView elementView, 127 I_CmsResourceTypeEnabledCheck checkEnabled) 128 throws CmsException { 129 130 if (elementView == null) { 131 LOG.error("Element view is null"); 132 return Collections.emptyList(); 133 } 134 List<I_CmsResourceType> additionalTypes = Lists.newArrayList(); 135 136 // First store the types in a map, to avoid duplicates 137 Map<String, I_CmsResourceType> additionalTypeMap = Maps.newHashMap(); 138 139 if (elementView.getExplorerType() != null) { 140 List<CmsExplorerTypeSettings> explorerTypes = OpenCms.getWorkplaceManager().getExplorerTypesForView( 141 elementView.getExplorerType().getName()); 142 for (CmsExplorerTypeSettings explorerType : explorerTypes) { 143 if (elementView.isOther() && m_includedAdeTypes.contains(explorerType.getName())) { 144 continue; 145 } 146 additionalTypeMap.put( 147 explorerType.getName(), 148 OpenCms.getResourceManager().getResourceType(explorerType.getName())); 149 } 150 } 151 if (OpenCms.getRoleManager().hasRole(cms, CmsRole.DEVELOPER) && elementView.isOther()) { 152 Set<String> hiddenTypes = new HashSet<String>(m_allAdeTypes); 153 hiddenTypes.removeAll(m_includedAdeTypes); 154 for (String typeName : hiddenTypes) { 155 if (OpenCms.getResourceManager().hasResourceType(typeName)) { 156 additionalTypeMap.put(typeName, OpenCms.getResourceManager().getResourceType(typeName)); 157 } 158 } 159 } 160 additionalTypes.addAll(additionalTypeMap.values()); 161 162 return internalGetResourceTypesFromConfig( 163 cms, 164 folderRootPath, 165 checkViewableReferenceUri, 166 elementView, 167 additionalTypes, 168 checkEnabled); 169 170 } 171 172 /** 173 * Precomputes type lists for multiple views.<p> 174 * 175 * @param cms the CMS context 176 * @param folderRootPath the current folder 177 * @param checkViewableReferenceUri the reference uri to use for viewability check 178 * @param views the views for which to generate the type lists 179 * @param check object to check whether resource types should be enabled 180 */ 181 public void precomputeTypeLists( 182 CmsObject cms, 183 String folderRootPath, 184 String checkViewableReferenceUri, 185 List<CmsElementView> views, 186 I_CmsResourceTypeEnabledCheck check) { 187 188 Multimap<CmsUUID, CmsResourceTypeBean> result = ArrayListMultimap.create(); 189 190 // Sort list to make sure that 'Other types' view is processed last, because we may need to display 191 // types filtered / removed from other views, which we only know once we have processed these views 192 Collections.sort(views, new Comparator<CmsElementView>() { 193 194 public int compare(CmsElementView view0, CmsElementView view1) { 195 196 return ComparisonChain.start().compareFalseFirst(view0.isOther(), view1.isOther()).result(); 197 } 198 }); 199 200 for (CmsElementView view : views) { 201 try { 202 result.putAll( 203 view.getId(), 204 getResourceTypes(cms, folderRootPath, checkViewableReferenceUri, view, check)); 205 } catch (Exception e) { 206 LOG.error(e.getLocalizedMessage(), e); 207 } 208 } 209 m_cachedTypes = result; 210 } 211 212 /** 213 * Function used to check if a given resource type should be excluded from the result.<p> 214 * 215 * @param type the type 216 * 217 * @return true if the given type should be excluded 218 */ 219 protected boolean exclude(CmsResourceTypeBean type) { 220 221 return false; 222 } 223 224 /** 225 * Creates list of resource type beans for gallery or 'New' dialog.<p> 226 * 227 * @param cms the CMS context 228 * @param folderRootPath the current folder 229 * @param checkViewableReferenceUri the reference uri to use for viewability check 230 * @param elementView the view id 231 * @param additionalTypes the additional types to add 232 * @param checkEnabled object to check whether resource types should be enabled 233 * 234 * @return the list of resource type beans 235 * 236 * @throws CmsException if something goes wrong 237 */ 238 private List<CmsResourceTypeBean> internalGetResourceTypesFromConfig( 239 CmsObject cms, 240 String folderRootPath, 241 String checkViewableReferenceUri, 242 CmsElementView elementView, 243 List<I_CmsResourceType> additionalTypes, 244 I_CmsResourceTypeEnabledCheck checkEnabled) 245 throws CmsException { 246 247 CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(cms, folderRootPath); 248 // String uri = cms.getRequestContext().removeSiteRoot(rootFolder); 249 List<I_CmsResourceType> resourceTypes = new ArrayList<I_CmsResourceType>(); 250 Set<String> disabledTypes = new HashSet<String>(); 251 final Set<String> typesAtTheEndOfTheList = Sets.newHashSet(); 252 Set<String> typesFromConfig = Sets.newHashSet(); 253 Map<String, String> createPaths = Maps.newHashMap(); 254 Map<String, String> namePatterns = Maps.newHashMap(); 255 for (CmsResourceTypeConfig typeConfig : config.getResourceTypes()) { 256 m_allAdeTypes.add(typeConfig.getTypeName()); 257 typesFromConfig.add(typeConfig.getTypeName()); 258 boolean isModelGroup = CmsResourceTypeXmlContainerPage.MODEL_GROUP_TYPE_NAME.equals( 259 typeConfig.getTypeName()); 260 try { 261 AddMenuVisibility visibility = typeConfig.getAddMenuVisibility(elementView.getId(), m_menuType); 262 263 if (visibility == AddMenuVisibility.disabled) { 264 continue; 265 } 266 267 if (isModelGroup || (visibility == AddMenuVisibility.fromOtherView)) { 268 typesAtTheEndOfTheList.add(typeConfig.getTypeName()); 269 } 270 if (typeConfig.checkViewable(cms, checkViewableReferenceUri)) { 271 String typeName = typeConfig.getTypeName(); 272 I_CmsResourceType resType = OpenCms.getResourceManager().getResourceType(typeName); 273 resourceTypes.add(resType); 274 if ((checkEnabled != null) && !checkEnabled.checkEnabled(cms, config, resType)) { 275 disabledTypes.add(resType.getTypeName()); 276 } 277 } 278 } catch (Exception e) { 279 LOG.error(e.getLocalizedMessage(), e); 280 } 281 } 282 Set<String> creatableTypes = new HashSet<String>(); 283 for (CmsResourceTypeConfig typeConfig : config.getCreatableTypes(cms, folderRootPath)) { 284 AddMenuVisibility visibility = typeConfig.getAddMenuVisibility(elementView.getId(), m_menuType); 285 if ((AddMenuVisibility.disabled == visibility) 286 || (AddMenuVisibility.createDisabled == visibility) 287 || disabledTypes.contains(typeConfig.getTypeName())) { 288 continue; 289 } 290 createPaths.put(typeConfig.getTypeName(), typeConfig.getFolderPath(cms, folderRootPath)); 291 namePatterns.put(typeConfig.getTypeName(), typeConfig.getNamePattern(false)); 292 String typeName = typeConfig.getTypeName(); 293 creatableTypes.add(typeName); 294 } 295 m_includedAdeTypes.addAll(createPaths.keySet()); 296 CmsGalleryService srv = new CmsGalleryService(); 297 srv.setCms(cms); 298 // we put the types 'imported' from other views at the end of the list. Since the sort is stable, 299 // relative position of other types remains unchanged 300 Collections.sort(resourceTypes, new Comparator<I_CmsResourceType>() { 301 302 public int compare(I_CmsResourceType first, I_CmsResourceType second) { 303 304 return ComparisonChain.start().compare(rank(first), rank(second)).result(); 305 } 306 307 int rank(I_CmsResourceType type) { 308 309 return typesAtTheEndOfTheList.contains(type.getTypeName()) ? 1 : 0; 310 } 311 }); 312 313 Collections.sort(additionalTypes, new Comparator<I_CmsResourceType>() { 314 315 public int compare(I_CmsResourceType type1, I_CmsResourceType type2) { 316 317 CmsExplorerTypeSettings settings1 = OpenCms.getWorkplaceManager().getExplorerTypeSetting( 318 type1.getTypeName()); 319 CmsExplorerTypeSettings settings2 = OpenCms.getWorkplaceManager().getExplorerTypeSetting( 320 type2.getTypeName()); 321 return ComparisonChain.start().compare( 322 settings1.getViewOrder(true), 323 settings2.getViewOrder(true)).compare( 324 parse(settings1.getNewResourceOrder()), 325 parse(settings2.getNewResourceOrder())).result(); 326 327 } 328 329 long parse(String order) { 330 331 try { 332 return Integer.parseInt(order); 333 } catch (NumberFormatException e) { 334 return 9999; 335 } 336 } 337 }); 338 for (I_CmsResourceType addType : additionalTypes) { 339 String typeName = addType.getTypeName(); 340 if (typesFromConfig.contains(typeName) && !elementView.isOther()) { // type was already processed (although it may not be in the result list) 341 continue; 342 } 343 CmsExplorerTypeSettings explorerType = OpenCms.getWorkplaceManager().getExplorerTypeSetting(typeName); 344 CmsPermissionSet permissions = explorerType.getAccess().getPermissions( 345 cms, 346 cms.readResource(checkViewableReferenceUri)); 347 if (permissions.requiresControlPermission() && permissions.requiresViewPermission()) { 348 resourceTypes.add(addType); 349 creatableTypes.add(addType.getTypeName()); 350 } 351 } 352 List<CmsResourceTypeBean> results = srv.buildTypesList(resourceTypes, creatableTypes, disabledTypes, null); 353 for (CmsResourceTypeBean typeBean : results) { 354 if (typesFromConfig.contains(typeBean.getType())) { 355 typeBean.setOrigin(Origin.config); 356 typeBean.setCreatePath(createPaths.get(typeBean.getType())); 357 typeBean.setNamePattern(namePatterns.get(typeBean.getType())); 358 } else { 359 typeBean.setOrigin(Origin.other); 360 } 361 } 362 363 List<CmsResourceTypeBean> filteredResults = Lists.newArrayList(); 364 for (CmsResourceTypeBean result : results) { 365 if (exclude(result)) { 366 continue; 367 } 368 filteredResults.add(result); 369 } 370 371 return filteredResults; 372 373 } 374 375}