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