001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://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.ui.util; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsProperty; 032import org.opencms.file.CmsPropertyDefinition; 033import org.opencms.file.CmsRequestContext; 034import org.opencms.file.CmsResource; 035import org.opencms.file.CmsResourceFilter; 036import org.opencms.file.types.CmsResourceTypeXmlContainerPage; 037import org.opencms.file.types.I_CmsResourceType; 038import org.opencms.gwt.CmsIconUtil; 039import org.opencms.gwt.CmsPropertyEditorHelper; 040import org.opencms.gwt.CmsTemplateFinder; 041import org.opencms.gwt.shared.CmsListInfoBean; 042import org.opencms.gwt.shared.property.CmsPropertiesBean; 043import org.opencms.gwt.shared.property.CmsPropertyChangeSet; 044import org.opencms.gwt.shared.property.CmsPropertyModification; 045import org.opencms.i18n.CmsMessages; 046import org.opencms.main.CmsException; 047import org.opencms.main.CmsLog; 048import org.opencms.main.OpenCms; 049import org.opencms.util.CmsMacroResolver; 050import org.opencms.util.CmsStringUtil; 051import org.opencms.util.CmsUUID; 052import org.opencms.xml.content.CmsXmlContentProperty; 053import org.opencms.xml.content.CmsXmlContentPropertyHelper; 054 055import java.util.ArrayList; 056import java.util.LinkedHashMap; 057import java.util.List; 058import java.util.Locale; 059import java.util.Map; 060 061import org.apache.commons.logging.Log; 062 063import com.google.common.collect.Lists; 064 065/** 066 * Helper class for creating a new resource using the New dialog.<p> 067 */ 068public class CmsNewResourceBuilder { 069 070 /** 071 * Interface for callbacks which should be notified when this helper has created a resource.<p> 072 */ 073 public static interface I_Callback { 074 075 /** 076 * Error handler.<p> 077 * 078 * @param e the exception which was thrown 079 */ 080 void onError(Exception e); 081 082 /** 083 * This should be called after the resource is fully created and its properties have been set.<p> 084 * 085 * @param builder the resource builder 086 */ 087 void onResourceCreated(CmsNewResourceBuilder builder); 088 } 089 090 /** 091 * Property helper subclass which is responsible for loading the initial property data to display in the property 092 * dialog for a resource to be created in the New dialog.<p> 093 */ 094 public class PropertyEditorHelper extends CmsPropertyEditorHelper { 095 096 /** 097 * Creates a new instance.<p> 098 * 099 * @param cms the CMS cntext 100 */ 101 public PropertyEditorHelper(CmsObject cms) { 102 103 super(cms); 104 } 105 106 /** 107 * Loads the data needed for editing the properties of a resource.<p> 108 * 109 * @param id the structure id of the resource (ignored) 110 * 111 * @return the data needed for editing the properties 112 * 113 * @throws CmsException if something goes wrong 114 */ 115 @SuppressWarnings("synthetic-access") 116 @Override 117 public CmsPropertiesBean loadPropertyData(CmsUUID id) throws CmsException { 118 119 CmsObject cms = m_cms; 120 String originalSiteRoot = cms.getRequestContext().getSiteRoot(); 121 CmsPropertiesBean result = new CmsPropertiesBean(); 122 123 result.setReadOnly(false); 124 I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(m_type); 125 List<CmsProperty> typeDefaultProperties = type.getConfiguredDefaultProperties(); 126 result.setFolder(type.isFolder()); 127 result.setContainerPage(m_type.equals(CmsResourceTypeXmlContainerPage.getStaticTypeName())); 128 String sitePath = OpenCms.getResourceManager().getNameGenerator().getNewFileName( 129 m_cms, 130 m_pathWithPattern, 131 5, 132 m_explorerNameGeneration); 133 String rootPath = m_cms.getRequestContext().addSiteRoot(sitePath); 134 Map<String, CmsXmlContentProperty> propertyConfig; 135 Map<String, CmsXmlContentProperty> defaultProperties = getDefaultPropertiesForType(m_type); 136 Map<String, CmsXmlContentProperty> mergedConfig = OpenCms.getADEManager().lookupConfiguration( 137 cms, 138 rootPath).getPropertyConfiguration(defaultProperties); 139 propertyConfig = mergedConfig; 140 141 // Resolve macros in the property configuration 142 propertyConfig = CmsXmlContentPropertyHelper.resolveMacrosInProperties( 143 propertyConfig, 144 CmsMacroResolver.newWorkplaceLocaleResolver(cms)); 145 CmsPropertyEditorHelper.updateWysiwygConfig(propertyConfig, cms, null); 146 147 result.setPropertyDefinitions(new LinkedHashMap<String, CmsXmlContentProperty>(propertyConfig)); 148 try { 149 cms.getRequestContext().setSiteRoot(""); 150 String parentPath = CmsResource.getParentFolder(rootPath); 151 CmsResource parent = cms.readResource(parentPath, CmsResourceFilter.IGNORE_EXPIRATION); 152 List<CmsProperty> parentProperties = cms.readPropertyObjects(parent, true); 153 List<CmsProperty> ownProperties = typeDefaultProperties; 154 result.setOwnProperties(convertProperties(ownProperties)); 155 result.setInheritedProperties(convertProperties(parentProperties)); 156 result.setPageInfo(getPageInfo(sitePath)); 157 List<CmsPropertyDefinition> propDefs = cms.readAllPropertyDefinitions(); 158 List<String> propNames = new ArrayList<String>(); 159 for (CmsPropertyDefinition propDef : propDefs) { 160 if (CmsStringUtil.isEmpty(propDef.getName())) { 161 LOG.warn("Empty property definition name: " + propDef); 162 continue; 163 } 164 propNames.add(propDef.getName()); 165 } 166 CmsTemplateFinder templateFinder = new CmsTemplateFinder(cms); 167 result.setTemplates(templateFinder.getTemplates()); 168 result.setAllProperties(propNames); 169 result.setStructureId(id); 170 result.setSitePath(sitePath); 171 return result; 172 } finally { 173 cms.getRequestContext().setSiteRoot(originalSiteRoot); 174 } 175 } 176 177 /** 178 * Gets the page info bean.<p> 179 * 180 * @param sitePath the site path 181 * @return the page info bean 182 */ 183 private CmsListInfoBean getPageInfo(String sitePath) { 184 185 CmsListInfoBean listInfo = new CmsListInfoBean(); 186 listInfo.setResourceState(CmsResource.STATE_NEW); 187 listInfo.setTitle(CmsResource.getName(sitePath)); 188 listInfo.setSubTitle(sitePath); 189 190 String key = OpenCms.getWorkplaceManager().getExplorerTypeSetting(m_type).getKey(); 191 Locale currentLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms); 192 CmsMessages messages = OpenCms.getWorkplaceManager().getMessages(currentLocale); 193 String resTypeNiceName = messages.key(key); 194 listInfo.addAdditionalInfo( 195 messages.key(org.opencms.workplace.commons.Messages.GUI_LABEL_TYPE_0), 196 resTypeNiceName); 197 listInfo.setBigIconClasses(CmsIconUtil.getIconClasses(m_type, sitePath, false)); 198 listInfo.setResourceType(m_type); 199 return listInfo; 200 } 201 } 202 203 /** The logger instance for this class. */ 204 private static final Log LOG = CmsLog.getLog(CmsNewResourceBuilder.class); 205 206 /** The CMS context. */ 207 CmsObject m_cms; 208 209 /** The resource type name. */ 210 String m_type; 211 212 /** The list of registered callbacks. */ 213 private List<I_Callback> m_callbacks = Lists.newArrayList(); 214 215 /** The created resource (null until this helper has finished creating the resource). */ 216 private CmsResource m_createdResource; 217 218 /** True if explorer name generation is enabled. */ 219 private boolean m_explorerNameGeneration; 220 221 /** The model resource. */ 222 private CmsResource m_modelResource; 223 224 /** The path with name pattern at which the resource should be created. */ 225 private String m_pathWithPattern; 226 227 /** The property changes to save (may be null). */ 228 private CmsPropertyChangeSet m_propChanges; 229 230 /** 231 * Creates a new instance.<p> 232 * 233 * @param cms the CMS context 234 * @throws CmsException if something goes wrong 235 */ 236 public CmsNewResourceBuilder(CmsObject cms) 237 throws CmsException { 238 239 m_cms = OpenCms.initCmsObject(cms); 240 } 241 242 /** 243 * Adds a callback to be notified when the resource is created.<p> 244 * 245 * @param callback the callback 246 */ 247 public void addCallback(I_Callback callback) { 248 249 m_callbacks.add(callback); 250 } 251 252 /** 253 * Triggers the resource creation.<p> 254 * 255 * @return the created resource 256 * 257 * @throws CmsException if something goes wrong 258 */ 259 public CmsResource createResource() throws CmsException { 260 261 CmsRequestContext context = m_cms.getRequestContext(); 262 if (m_modelResource != null) { 263 context.setAttribute(CmsRequestContext.ATTRIBUTE_MODEL, m_modelResource.getRootPath()); 264 } 265 266 String name = null; 267 for (CmsPropertyModification propMod : m_propChanges.getChanges()) { 268 if (propMod.isFileNameProperty()) { 269 name = propMod.getValue(); 270 } 271 } 272 String path = null; 273 if (CmsStringUtil.isEmptyOrWhitespaceOnly(name)) { 274 path = OpenCms.getResourceManager().getNameGenerator().getNewFileName( 275 m_cms, 276 m_pathWithPattern, 277 5, 278 m_explorerNameGeneration); 279 } else { 280 String parent = CmsResource.getParentFolder(m_pathWithPattern); 281 path = CmsStringUtil.joinPaths(parent, name.trim()); 282 } 283 Locale contentLocale = OpenCms.getLocaleManager().getDefaultLocale(m_cms, CmsResource.getFolderPath(path)); 284 context.setAttribute(CmsRequestContext.ATTRIBUTE_NEW_RESOURCE_LOCALE, contentLocale); 285 CmsResource res = m_cms.createResource( 286 path, 287 OpenCms.getResourceManager().getResourceType(m_type), 288 null, 289 new ArrayList<CmsProperty>()); 290 if (m_propChanges != null) { 291 CmsPropertyEditorHelper helper = new CmsPropertyEditorHelper(m_cms); 292 helper.overrideStructureId(res.getStructureId()); 293 helper.saveProperties(m_propChanges); 294 } 295 // Path or other metadata may have changed 296 m_createdResource = m_cms.readResource(res.getStructureId(), CmsResourceFilter.IGNORE_EXPIRATION); 297 try { 298 m_cms.unlockResource(m_createdResource); 299 } catch (CmsException e) { 300 LOG.info(e.getLocalizedMessage(), e); 301 } 302 for (I_Callback callback : m_callbacks) { 303 callback.onResourceCreated(this); 304 } 305 return m_createdResource; 306 } 307 308 /** 309 * Gets the created resource.<p> 310 * 311 * This will null before the resource creation process. 312 * 313 * @return the created resource 314 */ 315 public CmsResource getCreatedResource() { 316 317 return m_createdResource; 318 } 319 320 /** 321 * Loads the property data with which the property dialog for the new resource should be initialized.<p> 322 * 323 * @return the properties bean 324 */ 325 public CmsPropertiesBean getPropertyData() { 326 327 CmsPropertyEditorHelper helper = new PropertyEditorHelper(m_cms); 328 try { 329 CmsPropertiesBean data = helper.loadPropertyData(CmsUUID.getNullUUID()); 330 return data; 331 } catch (Exception e) { 332 throw new RuntimeException(e); 333 } 334 } 335 336 /** 337 * Creates a resource, but doesn't throw any exceptions.<p> 338 * 339 * Exceptions will be passed to the onError method of registered callbacks.<p> 340 * 341 * @return the created resource 342 */ 343 public CmsResource safeCreateResource() { 344 345 try { 346 return createResource(); 347 } catch (Exception e) { 348 for (I_Callback callback : m_callbacks) { 349 callback.onError(e); 350 } 351 return null; 352 } 353 } 354 355 /** 356 * Sets the Explorer name generation mode.<p> 357 * 358 * @param explorerNameGenerationMode the explorer name generation mode 359 */ 360 public void setExplorerNameGeneration(boolean explorerNameGenerationMode) { 361 362 m_explorerNameGeneration = explorerNameGenerationMode; 363 } 364 365 /** 366 * Sets the locale.<p> 367 * 368 * @param locale the locale 369 */ 370 public void setLocale(Locale locale) { 371 372 m_cms.getRequestContext().setLocale(locale); 373 374 } 375 376 /** 377 * Sets the model resource.<p> 378 * 379 * @param modelResource the model resource 380 */ 381 public void setModel(CmsResource modelResource) { 382 383 m_modelResource = modelResource; 384 } 385 386 /** 387 * Sets the creation path containing a number pattern.<p> 388 * 389 * @param destination the creation path 390 */ 391 public void setPatternPath(String destination) { 392 393 m_pathWithPattern = destination; 394 } 395 396 /** 397 * Sets the property changes.<p> 398 * 399 * @param propertyChanges the property changes 400 */ 401 public void setPropertyChanges(CmsPropertyChangeSet propertyChanges) { 402 403 m_propChanges = propertyChanges; 404 } 405 406 /** 407 * Sets the site root of the CMS context.<p> 408 * 409 * @param siteRoot the site root 410 */ 411 public void setSiteRoot(String siteRoot) { 412 413 m_cms.getRequestContext().setSiteRoot(siteRoot); 414 } 415 416 /** 417 * Sets the resource type name.<p> 418 * 419 * @param type the resource type name 420 */ 421 public void setType(String type) { 422 423 m_type = type; 424 } 425}