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.galleries; 029 030import org.opencms.ade.configuration.CmsADEConfigData; 031import org.opencms.ade.galleries.shared.CmsImageInfoBean; 032import org.opencms.ade.galleries.shared.CmsPoint; 033import org.opencms.ade.galleries.shared.CmsResourceInfoBean; 034import org.opencms.ade.galleries.shared.rpc.I_CmsPreviewService; 035import org.opencms.file.CmsFile; 036import org.opencms.file.CmsObject; 037import org.opencms.file.CmsProperty; 038import org.opencms.file.CmsPropertyDefinition; 039import org.opencms.file.CmsResource; 040import org.opencms.file.CmsResourceFilter; 041import org.opencms.file.CmsVfsResourceNotFoundException; 042import org.opencms.file.history.I_CmsHistoryResource; 043import org.opencms.file.types.CmsResourceTypeImage; 044import org.opencms.file.types.CmsResourceTypeXmlContent; 045import org.opencms.file.types.I_CmsResourceType; 046import org.opencms.gwt.CmsGwtService; 047import org.opencms.gwt.CmsIconUtil; 048import org.opencms.gwt.CmsRpcException; 049import org.opencms.i18n.CmsLocaleManager; 050import org.opencms.jsp.util.CmsJspStandardContextBean; 051import org.opencms.loader.CmsImageScaler; 052import org.opencms.lock.CmsLock; 053import org.opencms.main.CmsException; 054import org.opencms.main.CmsLog; 055import org.opencms.main.CmsPermalinkResourceHandler; 056import org.opencms.main.OpenCms; 057import org.opencms.ui.components.CmsResourceIcon; 058import org.opencms.util.CmsMacroResolver; 059import org.opencms.util.CmsStringUtil; 060import org.opencms.workplace.CmsWorkplaceMessages; 061import org.opencms.workplace.explorer.CmsExplorerTypeSettings; 062import org.opencms.workplace.explorer.CmsResourceUtil; 063import org.opencms.xml.containerpage.CmsContainerBean; 064import org.opencms.xml.containerpage.CmsContainerElementBean; 065import org.opencms.xml.containerpage.CmsContainerPageBean; 066import org.opencms.xml.containerpage.CmsFormatterBean; 067import org.opencms.xml.containerpage.CmsFormatterConfiguration; 068import org.opencms.xml.containerpage.I_CmsFormatterBean; 069import org.opencms.xml.content.CmsXmlContentProperty; 070import org.opencms.xml.content.CmsXmlContentPropertyHelper; 071 072import java.util.Collections; 073import java.util.Date; 074import java.util.HashMap; 075import java.util.Iterator; 076import java.util.LinkedHashMap; 077import java.util.List; 078import java.util.Locale; 079import java.util.Map; 080import java.util.Map.Entry; 081import java.util.regex.Matcher; 082import java.util.regex.Pattern; 083 084import javax.servlet.http.HttpServletRequest; 085import javax.servlet.http.HttpServletResponse; 086 087import org.apache.commons.logging.Log; 088 089import com.google.common.collect.Lists; 090 091/** 092 * Handles all RPC services related to the gallery preview dialog.<p> 093 * 094 * @since 8.0.0 095 */ 096public class CmsPreviewService extends CmsGwtService implements I_CmsPreviewService { 097 098 /** Regex used to parse the image.focalpoint property. */ 099 public static final Pattern PATTERN_FOCAL_POINT = Pattern.compile(" *([0-9]+) *, *([0-9]+) *"); 100 101 /** The logger instance for this class. */ 102 private static final Log LOG = CmsLog.getLog(CmsPreviewService.class); 103 104 /** Serialization uid. */ 105 private static final long serialVersionUID = -8175522641937277445L; 106 107 /** 108 * Renders the preview content for the given resource and locale.<p> 109 * 110 * @param request the current servlet request 111 * @param response the current servlet response 112 * @param cms the cms context 113 * @param resource the resource 114 * @param locale the content locale 115 * 116 * @return the rendered HTML preview content 117 */ 118 public static String getPreviewContent( 119 HttpServletRequest request, 120 HttpServletResponse response, 121 CmsObject cms, 122 CmsResource resource, 123 Locale locale) { 124 125 try { 126 if (CmsResourceTypeXmlContent.isXmlContent(resource)) { 127 CmsADEConfigData adeConfig = OpenCms.getADEManager().lookupConfiguration( 128 cms, 129 cms.getRequestContext().getRootUri()); 130 131 CmsFormatterConfiguration formatters = adeConfig.getFormatters(cms, resource); 132 I_CmsFormatterBean formatter = formatters.getPreviewFormatter(); 133 if (formatter != null) { 134 CmsObject tempCms = OpenCms.initCmsObject(cms); 135 tempCms.getRequestContext().setLocale(locale); 136 CmsResource formatterResource = tempCms.readResource(formatter.getJspStructureId()); 137 request.setAttribute(CmsJspStandardContextBean.ATTRIBUTE_CMS_OBJECT, tempCms); 138 CmsJspStandardContextBean standardContext = CmsJspStandardContextBean.getInstance(request); 139 140 Map<String, String> settings = new HashMap<>(); 141 for (Map.Entry<String, CmsXmlContentProperty> entry : formatter.getSettings(adeConfig).entrySet()) { 142 CmsXmlContentProperty settingConfig = entry.getValue(); 143 String defaultValue = settingConfig.getDefault(); 144 if (defaultValue != null) { 145 settings.put(entry.getKey(), settingConfig.getDefault()); 146 } 147 } 148 149 CmsContainerElementBean element = new CmsContainerElementBean( 150 resource.getStructureId(), 151 formatter.getJspStructureId(), 152 settings, 153 false); 154 if ((resource instanceof I_CmsHistoryResource) && (resource instanceof CmsFile)) { 155 element.setHistoryFile((CmsFile)resource); 156 } 157 element.initResource(tempCms); 158 CmsContainerBean containerBean = new CmsContainerBean( 159 "PREVIEW", 160 CmsFormatterBean.PREVIEW_TYPE, 161 null, 162 true, 163 1, 164 Collections.<CmsContainerElementBean> emptyList()); 165 containerBean.setWidth(String.valueOf(CmsFormatterBean.PREVIEW_WIDTH)); 166 167 standardContext.setContainer(containerBean); 168 standardContext.setElement(element); 169 standardContext.setEdited(true); 170 standardContext.setPage( 171 new CmsContainerPageBean(Collections.<CmsContainerBean> singletonList(containerBean))); 172 String encoding = response.getCharacterEncoding(); 173 return (new String( 174 OpenCms.getResourceManager().getLoader( 175 formatterResource).dump(tempCms, formatterResource, null, locale, request, response), 176 encoding)).trim(); 177 } 178 } 179 } catch (Exception e) { 180 LOG.warn(e.getLocalizedMessage(), e); 181 } 182 return null; 183 } 184 185 /** 186 * Reads the focal point from a resource.<p> 187 * 188 * @param cms the CMS context to use 189 * @param resource the resource 190 * @return the focal point (or null, if the focal point property is not set or contains an invalid value) 191 * 192 * @throws CmsException if something goes wrong 193 */ 194 public static CmsPoint readFocalPoint(CmsObject cms, CmsResource resource) throws CmsException { 195 196 CmsProperty focalPointProp = cms.readPropertyObject( 197 resource, 198 CmsPropertyDefinition.PROPERTY_IMAGE_FOCAL_POINT, 199 false); 200 CmsPoint focalPoint = null; 201 if (!focalPointProp.isNullProperty()) { 202 String focalPointVal = focalPointProp.getValue(); 203 Matcher matcher = PATTERN_FOCAL_POINT.matcher(focalPointVal); 204 if (matcher.matches()) { 205 int fx = Integer.parseInt(matcher.group(1)); 206 int fy = Integer.parseInt(matcher.group(2)); 207 focalPoint = new CmsPoint(fx, fy); 208 209 } 210 } 211 return focalPoint; 212 } 213 214 /** 215 * @see org.opencms.ade.galleries.shared.rpc.I_CmsPreviewService#getImageInfo(java.lang.String, java.lang.String) 216 */ 217 public CmsImageInfoBean getImageInfo(String resourcePath, String locale) throws CmsRpcException { 218 219 CmsObject cms = getCmsObject(); 220 CmsImageInfoBean resInfo = new CmsImageInfoBean(); 221 try { 222 int pos = resourcePath.indexOf("?"); 223 String resName = resourcePath; 224 if (pos > -1) { 225 resName = resourcePath.substring(0, pos); 226 } 227 CmsResource resource = readResourceFromCurrentOrRootSite(cms, resName); 228 readResourceInfo(cms, resource, resInfo, locale); 229 resInfo.setViewLink( 230 CmsStringUtil.joinPaths( 231 OpenCms.getSystemInfo().getOpenCmsContext(), 232 CmsPermalinkResourceHandler.PERMALINK_HANDLER, 233 resource.getStructureId().toString())); 234 resInfo.setHash(resource.getStructureId().hashCode()); 235 CmsImageScaler scaler = new CmsImageScaler(cms, resource); 236 int height = -1; 237 int width = -1; 238 if (scaler.isValid()) { 239 height = scaler.getHeight(); 240 width = scaler.getWidth(); 241 } 242 CmsPoint focalPoint = readFocalPoint(cms, resource); 243 resInfo.setFocalPoint(focalPoint); 244 245 resInfo.setHeight(height); 246 resInfo.setWidth(width); 247 CmsProperty property = cms.readPropertyObject(resource, CmsPropertyDefinition.PROPERTY_COPYRIGHT, false); 248 if (!property.isNullProperty()) { 249 resInfo.setCopyright(property.getValue()); 250 } 251 } catch (Exception e) { 252 error(e); 253 } 254 return resInfo; 255 } 256 257 /** 258 * @see org.opencms.ade.galleries.shared.rpc.I_CmsPreviewService#getResourceInfo(java.lang.String, java.lang.String) 259 */ 260 public CmsResourceInfoBean getResourceInfo(String resourcePath, String locale) throws CmsRpcException { 261 262 CmsObject cms = getCmsObject(); 263 CmsResourceInfoBean resInfo = new CmsResourceInfoBean(); 264 try { 265 int pos = resourcePath.indexOf("?"); 266 String resName = resourcePath; 267 if (pos > -1) { 268 resName = resourcePath.substring(0, pos); 269 } 270 CmsResource resource = readResourceFromCurrentOrRootSite(cms, resName); 271 readResourceInfo(cms, resource, resInfo, locale); 272 } catch (CmsException e) { 273 error(e); 274 } 275 return resInfo; 276 } 277 278 /** 279 * Retrieves the resource information and puts it into the provided resource info bean.<p> 280 * 281 * @param cms the initialized cms object 282 * @param resource the resource 283 * @param resInfo the resource info bean 284 * @param locale the content locale 285 * 286 * @throws CmsException if something goes wrong 287 */ 288 public void readResourceInfo(CmsObject cms, CmsResource resource, CmsResourceInfoBean resInfo, String locale) 289 throws CmsException { 290 291 I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(resource.getTypeId()); 292 Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms); 293 resInfo.setTitle(resource.getName()); 294 resInfo.setStructureId(resource.getStructureId()); 295 resInfo.setDescription(CmsWorkplaceMessages.getResourceTypeName(wpLocale, type.getTypeName())); 296 resInfo.setResourcePath(cms.getSitePath(resource)); 297 resInfo.setResourceType(type.getTypeName()); 298 resInfo.setBigIconClasses( 299 CmsIconUtil.getIconClasses(CmsIconUtil.getDisplayType(cms, resource), resource.getName(), false)); 300 // set the default file and detail type info 301 String detailType = CmsResourceIcon.getDefaultFileOrDetailType(cms, resource); 302 if (detailType != null) { 303 resInfo.setSmallIconClasses(CmsIconUtil.getIconClasses(detailType, null, true)); 304 } 305 resInfo.setSize((resource.getLength() / 1024) + " kb"); 306 resInfo.setLastModified(new Date(resource.getDateLastModified())); 307 resInfo.setNoEditReason(new CmsResourceUtil(cms, resource).getNoEditReason(wpLocale, true)); 308 // reading default explorer-type properties 309 CmsExplorerTypeSettings setting = OpenCms.getWorkplaceManager().getExplorerTypeSetting(type.getTypeName()); 310 List<String> properties; 311 String rootPathForConfig = cms.getRequestContext().getRootUri(); 312 CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(cms, rootPathForConfig); 313 Map<String, CmsXmlContentProperty> propConfig = config.getPropertyConfigurationAsMap(); 314 CmsMacroResolver resolver = new CmsMacroResolver(); 315 resolver.setCmsObject(cms); 316 resolver.setMessages(OpenCms.getWorkplaceManager().getMessages(wpLocale)); 317 propConfig = CmsXmlContentPropertyHelper.resolveMacrosInProperties(propConfig, resolver); 318 Map<String, String> niceNames = new HashMap<>(); 319 for (CmsXmlContentProperty propEntry : propConfig.values()) { 320 String niceName = propEntry.getNiceName(); 321 if (niceName != null) { 322 niceNames.put(propEntry.getName(), niceName); 323 } 324 } 325 if (OpenCms.getResourceManager().matchResourceType( 326 CmsResourceTypeImage.getStaticTypeName(), 327 resource.getTypeId())) { 328 properties = Lists.newArrayList( 329 CmsPropertyDefinition.PROPERTY_TITLE, 330 CmsPropertyDefinition.PROPERTY_COPYRIGHT, 331 CmsPropertyDefinition.PROPERTY_DESCRIPTION); 332 } else { 333 properties = setting.getProperties(); 334 String reference = setting.getReference(); 335 while ((properties.size() == 0) && !CmsStringUtil.isEmptyOrWhitespaceOnly(reference)) { 336 // looking up properties from referenced explorer types if properties list is empty 337 setting = OpenCms.getWorkplaceManager().getExplorerTypeSetting(reference); 338 properties = setting.getProperties(); 339 reference = setting.getReference(); 340 } 341 } 342 Map<String, String> props = new LinkedHashMap<String, String>(); 343 Iterator<String> propIt = properties.iterator(); 344 while (propIt.hasNext()) { 345 String propertyName = propIt.next(); 346 CmsProperty property = cms.readPropertyObject(resource, propertyName, false); 347 if (!property.isNullProperty()) { 348 props.put(property.getName(), property.getValue()); 349 } else { 350 props.put(propertyName, null); 351 } 352 } 353 resInfo.setProperties(props); 354 resInfo.setPropertyNiceNames(niceNames); 355 resInfo.setPreviewContent(getPreviewContent(cms, resource, CmsLocaleManager.getLocale(locale))); 356 } 357 358 /** 359 * @see org.opencms.ade.galleries.shared.rpc.I_CmsPreviewService#updateImageProperties(java.lang.String, java.lang.String, java.util.Map) 360 */ 361 public CmsImageInfoBean updateImageProperties(String resourcePath, String locale, Map<String, String> properties) 362 throws CmsRpcException { 363 364 try { 365 saveProperties(resourcePath, properties); 366 } catch (CmsException e) { 367 error(e); 368 } 369 return getImageInfo(resourcePath, locale); 370 } 371 372 /** 373 * @see org.opencms.ade.galleries.shared.rpc.I_CmsPreviewService#updateResourceProperties(java.lang.String, java.lang.String, java.util.Map) 374 */ 375 public CmsResourceInfoBean updateResourceProperties( 376 String resourcePath, 377 String locale, 378 Map<String, String> properties) 379 throws CmsRpcException { 380 381 try { 382 saveProperties(resourcePath, properties); 383 } catch (CmsException e) { 384 error(e); 385 } 386 return getResourceInfo(resourcePath, locale); 387 } 388 389 /** 390 * Renders the preview content for the given resource and locale.<p> 391 * 392 * @param cms the cms context 393 * @param resource the resource 394 * @param locale the content locale 395 * 396 * @return the rendered HTML preview content 397 */ 398 private String getPreviewContent(CmsObject cms, CmsResource resource, Locale locale) { 399 400 return getPreviewContent(getRequest(), getResponse(), cms, resource, locale); 401 } 402 403 /** 404 * Tries to read a resource either from the current site or from the root site.<p> 405 * 406 * @param cms the CMS context to use 407 * @param name the resource path 408 * 409 * @return the resource which was read 410 * @throws CmsException if something goes wrong 411 */ 412 private CmsResource readResourceFromCurrentOrRootSite(CmsObject cms, String name) throws CmsException { 413 414 CmsResource resource = null; 415 try { 416 resource = cms.readResource(name, CmsResourceFilter.IGNORE_EXPIRATION); 417 } catch (CmsVfsResourceNotFoundException e) { 418 String originalSiteRoot = cms.getRequestContext().getSiteRoot(); 419 try { 420 cms.getRequestContext().setSiteRoot(""); 421 resource = cms.readResource(name, CmsResourceFilter.IGNORE_EXPIRATION); 422 } finally { 423 cms.getRequestContext().setSiteRoot(originalSiteRoot); 424 } 425 426 } 427 return resource; 428 } 429 430 /** 431 * Saves the given properties to the resource.<p> 432 * 433 * @param resourcePath the resource path 434 * @param properties the properties 435 * 436 * @throws CmsException if something goes wrong 437 */ 438 private void saveProperties(String resourcePath, Map<String, String> properties) throws CmsException { 439 440 CmsResource resource; 441 CmsObject cms = getCmsObject(); 442 int pos = resourcePath.indexOf("?"); 443 String resName = resourcePath; 444 if (pos > -1) { 445 resName = resourcePath.substring(0, pos); 446 } 447 resource = cms.readResource(resName); 448 449 if (properties != null) { 450 for (Entry<String, String> entry : properties.entrySet()) { 451 String propertyName = entry.getKey(); 452 String propertyValue = entry.getValue(); 453 if (CmsStringUtil.isEmptyOrWhitespaceOnly(propertyValue)) { 454 propertyValue = ""; 455 } 456 try { 457 CmsProperty currentProperty = cms.readPropertyObject(resource, propertyName, false); 458 // detect if property is a null property or not 459 if (currentProperty.isNullProperty()) { 460 // create new property object and set key and value 461 currentProperty = new CmsProperty(); 462 currentProperty.setName(propertyName); 463 if (OpenCms.getWorkplaceManager().isDefaultPropertiesOnStructure()) { 464 // set structure value 465 currentProperty.setStructureValue(propertyValue); 466 currentProperty.setResourceValue(null); 467 } else { 468 // set resource value 469 currentProperty.setStructureValue(null); 470 currentProperty.setResourceValue(propertyValue); 471 } 472 } else if (currentProperty.getStructureValue() != null) { 473 // structure value has to be updated 474 currentProperty.setStructureValue(propertyValue); 475 currentProperty.setResourceValue(null); 476 } else { 477 // resource value has to be updated 478 currentProperty.setStructureValue(null); 479 currentProperty.setResourceValue(propertyValue); 480 } 481 CmsLock lock = cms.getLock(resource); 482 if (lock.isUnlocked()) { 483 // lock resource before operation 484 cms.lockResource(resName); 485 } 486 // write the property to the resource 487 cms.writePropertyObject(resName, currentProperty); 488 // unlock the resource 489 cms.unlockResource(resName); 490 } catch (CmsException e) { 491 // writing the property failed, log error 492 log(e.getLocalizedMessage()); 493 } 494 } 495 } 496 } 497 498}