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