001/* 002 * Copyright 2016 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.ametys.web.transformation.xslt; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.net.MalformedURLException; 022import java.util.ArrayList; 023import java.util.Arrays; 024import java.util.Collection; 025import java.util.Collections; 026import java.util.HashMap; 027import java.util.Iterator; 028import java.util.List; 029import java.util.Map; 030 031import org.apache.avalon.framework.service.ServiceException; 032import org.apache.avalon.framework.service.ServiceManager; 033import org.apache.cocoon.components.ContextHelper; 034import org.apache.cocoon.environment.Request; 035import org.apache.cocoon.environment.Response; 036import org.apache.commons.lang.StringUtils; 037import org.apache.excalibur.source.SourceResolver; 038import org.apache.excalibur.source.impl.FileSource; 039import org.w3c.dom.Element; 040import org.w3c.dom.Node; 041import org.w3c.dom.NodeList; 042 043import org.ametys.cms.repository.Content; 044import org.ametys.cms.transformation.ImageResolverHelper; 045import org.ametys.core.right.RightManager; 046import org.ametys.core.util.I18nUtils; 047import org.ametys.core.util.dom.AmetysNodeList; 048import org.ametys.core.util.dom.EmptyElement; 049import org.ametys.core.util.dom.FileElement; 050import org.ametys.core.util.dom.MapElement; 051import org.ametys.core.util.dom.MapElement.MapNode; 052import org.ametys.core.util.dom.StringElement; 053import org.ametys.plugins.explorer.resources.ResourceCollection; 054import org.ametys.plugins.explorer.resources.dom.ResourceCollectionElement; 055import org.ametys.plugins.repository.AmetysObject; 056import org.ametys.plugins.repository.AmetysObjectIterable; 057import org.ametys.plugins.repository.AmetysObjectResolver; 058import org.ametys.plugins.repository.UnknownAmetysObjectException; 059import org.ametys.plugins.repository.metadata.CompositeMetadata; 060import org.ametys.plugins.repository.metadata.CompositeMetadata.MetadataType; 061import org.ametys.plugins.repository.metadata.UnknownMetadataException; 062import org.ametys.runtime.parameter.ParameterHelper; 063import org.ametys.web.URIPrefixHandler; 064import org.ametys.web.WebConstants; 065import org.ametys.web.renderingcontext.RenderingContext; 066import org.ametys.web.renderingcontext.RenderingContextHandler; 067import org.ametys.web.repository.content.WebContent; 068import org.ametys.web.repository.dom.PageElement; 069import org.ametys.web.repository.dom.SitemapElement; 070import org.ametys.web.repository.page.Page; 071import org.ametys.web.repository.page.Zone; 072import org.ametys.web.repository.page.ZoneItem; 073import org.ametys.web.repository.site.Site; 074import org.ametys.web.repository.site.SiteManager; 075import org.ametys.web.repository.sitemap.Sitemap; 076import org.ametys.web.service.ServiceExtensionPoint; 077import org.ametys.web.service.ServiceParameter; 078import org.ametys.web.service.ServiceParameterOrRepeater; 079import org.ametys.web.service.ServiceParameterRepeater; 080import org.ametys.web.site.SiteConfigurationExtensionPoint; 081 082/** 083 * Helper component to be used from XSL stylesheets. 084 */ 085public class AmetysXSLTHelper extends org.ametys.cms.transformation.xslt.AmetysXSLTHelper 086{ 087 private static SiteManager _siteManager; 088 private static RenderingContextHandler _renderingContextHandler; 089 private static SiteConfigurationExtensionPoint _siteConf; 090 private static RightManager _rightManager; 091 private static URIPrefixHandler _prefixHandler; 092 private static SourceResolver _sourceResolver; 093 private static ServiceExtensionPoint _serviceEP; 094 095 @Override 096 public void service(ServiceManager manager) throws ServiceException 097 { 098 _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE); 099 _renderingContextHandler = (RenderingContextHandler) manager.lookup(RenderingContextHandler.ROLE); 100 _siteConf = (SiteConfigurationExtensionPoint) manager.lookup(SiteConfigurationExtensionPoint.ROLE); 101 _rightManager = (RightManager) manager.lookup(RightManager.ROLE); 102 _ametysObjectResolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 103 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 104 _prefixHandler = (URIPrefixHandler) manager.lookup(URIPrefixHandler.ROLE); 105 _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE); 106 _serviceEP = (ServiceExtensionPoint) manager.lookup(ServiceExtensionPoint.ROLE); 107 } 108 109 /** 110 * Returns the current URI prefix, depending on the rendering context. 111 * @return the current URI prefix. 112 */ 113 public static String uriPrefix() 114 { 115 return _prefixHandler.getUriPrefix(); 116 } 117 118 /** 119 * Returns the URI prefix corresponding to the current site, depending on the rendering context. 120 * @return the URI prefix corresponding to the current site. 121 */ 122 public static String siteUriPrefix() 123 { 124 Request request = ContextHelper.getRequest(_context); 125 String siteName = (String) request.getAttribute("site"); 126 return _prefixHandler.getUriPrefix(siteName); 127 } 128 129 /** 130 * Returns the absolute URI prefix, depending on the rendering context. 131 * @return the absolute URI prefix. 132 */ 133 public static String absoluteUriPrefix() 134 { 135 return _prefixHandler.getAbsoluteUriPrefix(); 136 } 137 138 /** 139 * Returns the absolute URI prefix corresponding to the current site, depending on the rendering context. 140 * @return the absolute URI prefix corresponding to the current site. 141 */ 142 public static String absoluteSiteUriPrefix() 143 { 144 Request request = ContextHelper.getRequest(_context); 145 String siteName = (String) request.getAttribute("site"); 146 return _prefixHandler.getAbsoluteUriPrefix(siteName); 147 } 148 149 /** 150 * Returns the absolute URI prefix corresponding to the given site, depending on the rendering context. 151 * @param siteName The site name. Can be null to get the current site. 152 * @return the absolute URI prefix corresponding to the current site. 153 */ 154 public static String absoluteSiteUriPrefix(String siteName) 155 { 156 if (StringUtils.isEmpty(siteName)) 157 { 158 return absoluteSiteUriPrefix(); 159 } 160 return _prefixHandler.getAbsoluteUriPrefix(siteName); 161 } 162 163 /** 164 * Returns the current skin name. 165 * @return the current skin name. 166 */ 167 public static String skin() 168 { 169 Request request = ContextHelper.getRequest(_context); 170 return (String) request.getAttribute("skin"); 171 } 172 173 /** 174 * Returns the current template name. 175 * @return the current template name. 176 */ 177 public static String template() 178 { 179 Request request = ContextHelper.getRequest(_context); 180 return (String) request.getAttribute("template"); 181 } 182 183 /** 184 * Returns the current sitemap name. 185 * @return the current sitemap name. 186 */ 187 public static String lang() 188 { 189 Request request = ContextHelper.getRequest(_context); 190 return (String) request.getAttribute("sitemapLanguage"); 191 } 192 193 /** 194 * Returns the current sitemap name. 195 * @param pageId The page identifier to get sitemap on 196 * @return the current sitemap name. 197 */ 198 public static String lang(String pageId) 199 { 200 try 201 { 202 Page page = _getPage(pageId); 203 return page.getSitemapName(); 204 } 205 catch (UnknownAmetysObjectException e) 206 { 207 _logger.error("Can not get sitemap lang on page '" + pageId + "'", e); 208 return ""; 209 } 210 } 211 212 /** 213 * Computes the URI for the given resource in the current site's skin.<br> 214 * If the URI is requested by the front-office, it will be absolutized. 215 * @param path the resource path. 216 * @return the URI for the given resource. 217 */ 218 public static String skinURL(String path) 219 { 220 Request request = ContextHelper.getRequest(_context); 221 String siteName = (String) request.getAttribute("site"); 222 Site site = _siteManager.getSite(siteName); 223 String skin = (String) request.getAttribute("skin"); 224 225 String resourcePath = "/skins/" + skin + "/resources/" + path; 226 227 return _getResourceURL(request, site, resourcePath); 228 } 229 230 /** 231 * Computes the URI for the given image with a given heigth and width in the current site's skin.<br> 232 * If the URI is requested by the front-office, it will be absolutized. 233 * @param path the resource path 234 * @param height the height for the resource to get 235 * @param width the width for the resource to get 236 * @return the URI of the given resource 237 */ 238 public static String skinImageURL(String path, int height, int width) 239 { 240 String skinPath = skinURL(path); 241 return StringUtils.substringBeforeLast(skinPath, ".") + "_" + height + "x" + width + "." + StringUtils.substringAfterLast(skinPath, "."); 242 } 243 244 /** 245 * Computes the base 64 representation of the image at the specified path. <br> 246 * @param path the path of the image 247 * @return the base 64-encoded image 248 * @throws IOException if an error occurs while trying to get the file 249 */ 250 public static String skinImageBase64 (String path) throws IOException 251 { 252 FileSource source = (FileSource) _sourceResolver.resolveURI("skin://resources/" + path); 253 return _getResourceBase64(source); 254 } 255 256 /** 257 * Computes the URI for the given image with a given heigth and width in the current site's skin.<br> 258 * If the URI is requested by the front-office, it will be absolutized. 259 * @param path the resource path 260 * @param maxHeight the maximum height for the resource to get 261 * @param maxWidth the maximum width for the resource to get 262 * @return the URI of the given resource 263 */ 264 public static String skinBoundedImageURL(String path, int maxHeight, int maxWidth) 265 { 266 String skinPath = skinURL(path); 267 return StringUtils.substringBeforeLast(skinPath, ".") + "_max" + maxHeight + "x" + maxWidth + "." + StringUtils.substringAfterLast(skinPath, "."); 268 } 269 270 /** 271 * Computes the URI for the given resource in the current template.<br> 272 * If the URI is requested by the front-office, it will be absolutized. 273 * @param path the resource path. 274 * @return the URI for the given resource. 275 */ 276 public static String templateURL(String path) 277 { 278 Request request = ContextHelper.getRequest(_context); 279 String siteName = (String) request.getAttribute("site"); 280 Site site = _siteManager.getSite(siteName); 281 String skin = (String) request.getAttribute("skin"); 282 String template = (String) request.getAttribute("template"); 283 284 String resourcePath = "/skins/" + skin + "/templates/" + template + "/resources/" + path; 285 286 return _getResourceURL(request, site, resourcePath); 287 } 288 289 /** 290 * Computes the URI for the given resource in the given plugin.<br> 291 * If the URI is requested by the front-office, it will be absolutized. 292 * @param plugin the plugin name. 293 * @param path the resource path. 294 * @return the URI for the given resource. 295 */ 296 public static String pluginResourceURL(String plugin, String path) 297 { 298 Request request = ContextHelper.getRequest(_context); 299 String siteName = (String) request.getAttribute("site"); 300 Site site = _siteManager.getSite(siteName); 301 302 String resourcePath = "/plugins/" + plugin + "/resources/" + path; 303 304 return _getResourceURL(request, site, resourcePath); 305 } 306 307 /** 308 * Computes the base 64 representation of the image at the specified path in the given plugin.<br> 309 * @param plugin the plugin's name. 310 * @param path the resource path. 311 * @return the base 64 encoding for the given resource. 312 * @throws IOException if an error occurs when trying to get the file 313 * @throws MalformedURLException if the url is invalid 314 */ 315 public static String pluginImageBase64(String plugin, String path) throws MalformedURLException, IOException 316 { 317 FileSource source = (FileSource) _sourceResolver.resolveURI("plugin:" + plugin + "://resources/" + path); 318 return _getResourceBase64(source); 319 } 320 321 322 private static String _getResourceURL(Request request, Site site, String resourcePath) 323 { 324 String prefix; 325 switch (_renderingContextHandler.getRenderingContext()) 326 { 327 case FRONT: 328 String[] aliases = site.getUrlAliases(); 329 int position = Math.abs(resourcePath.hashCode()) % aliases.length; 330 prefix = position == 0 ? siteUriPrefix() : aliases[position]; 331 return prefix + resourcePath; 332 333 default: 334 prefix = StringUtils.trimToEmpty((String) request.getAttribute(WebConstants.PATH_PREFIX)); 335 return request.getContextPath() + prefix + resourcePath; 336 } 337 } 338 339 /** 340 * Get the base 64 encoding for the given source 341 * @param source the source 342 * @return the base 64 encoding of the source 343 */ 344 private static String _getResourceBase64(FileSource source) 345 { 346 if (source.exists()) 347 { 348 349 try (InputStream dataIs = source.getInputStream()) 350 { 351 return ImageResolverHelper.resolveImageAsBase64(dataIs, source.getMimeType(), 0, 0, 0, 0); 352 } 353 catch (Exception e) 354 { 355 throw new IllegalStateException(e); 356 } 357 } 358 359 return ""; 360 } 361 362 /** 363 * Returns the current {@link RenderingContext}. 364 * @return the current {@link RenderingContext}. 365 */ 366 public static String renderingContext() 367 { 368 return _renderingContextHandler.getRenderingContext().toString(); 369 } 370 371 /** 372 * Return the name of the zone beeing handled 373 * @param defaultValue If no page is handled currently, this value is returned (can be null, empty...) 374 * @return the name or the default value (so can be null or empty) 375 */ 376 public static String zone(String defaultValue) 377 { 378 Request request = ContextHelper.getRequest(_context); 379 380 return StringUtils.defaultIfEmpty((String) request.getAttribute(Zone.class.getName()), defaultValue); 381 } 382 383 /** 384 * Return the value of a site parameter as a String. 385 * @param parameter the parameter ID. 386 * @return the parameter value as a String. 387 */ 388 public static String siteParameter(String parameter) 389 { 390 Request request = ContextHelper.getRequest(_context); 391 392 String siteName = (String) request.getAttribute("site"); 393 if (StringUtils.isBlank(siteName)) 394 { 395 // In BO xsl 396 siteName = (String) request.getAttribute("siteName"); 397 } 398 399 return siteParameter(siteName, parameter); 400 } 401 402 /** 403 * Return the value of a site parameter as a String. 404 * @param siteName the site name 405 * @param parameter the parameter ID. 406 * @return the parameter value as a String. 407 */ 408 public static String siteParameter(String siteName, String parameter) 409 { 410 try 411 { 412 return _siteConf.getUntypedValue(siteName, parameter); 413 } 414 catch (Exception e) 415 { 416 String message = "Error retrieving the value of the site parameter " + parameter; 417 _logger.error(message, e); 418 throw new RuntimeException(message, e); 419 } 420 } 421 422 /** 423 * Get the service parameters as a {@link Node}. 424 * @return the service parameters as a {@link Node}. 425 */ 426 public static Node serviceParameters() 427 { 428 Request request = ContextHelper.getRequest(_context); 429 ZoneItem zoneItem = (ZoneItem) request.getAttribute(ZoneItem.class.getName()); 430 CompositeMetadata parameters = zoneItem.getServiceParameters(); 431 432 String serviceId = zoneItem.getServiceId(); 433 434 Map<String, MapNode> paramValues = new HashMap<>(); 435 436 for (String paramName : parameters.getMetadataNames()) 437 { 438 ServiceParameterOrRepeater paramDef = _serviceEP.getExtension(serviceId).getParameters().get(paramName); 439 if (paramDef != null && parameters.hasMetadata(paramName)) 440 { 441 paramValues.putAll(_getParameterValue(paramName, parameters, paramDef, "")); 442 } 443 } 444 445 return new MapElement("serviceParameters", paramValues); 446 } 447 448 /** 449 * Returns the value of the given parameter for the current service, or the empty string if the parameter does not exist. 450 * @param parameter the parameter name. 451 * @return the value of the given parameter for the current service. 452 */ 453 public static Node serviceParameter(String parameter) 454 { 455 return serviceParameter(parameter, ""); 456 } 457 458 /** 459 * Returns the value of the given parameter for the current service, or the provided default value if the parameter does not exist. 460 * @param parameter the parameter name or path. 461 * @param defaultValue the default value. Note that default value is ignored if the parameter is a composite parameter. 462 * @return the value of the given parameter for the current service. 463 */ 464 public static Node serviceParameter(String parameter, String defaultValue) 465 { 466 Request request = ContextHelper.getRequest(_context); 467 ZoneItem zoneItem = (ZoneItem) request.getAttribute(ZoneItem.class.getName()); 468 CompositeMetadata parameters = zoneItem.getServiceParameters(); 469 470 String serviceId = zoneItem.getServiceId(); 471 ServiceParameterOrRepeater paramDef = _serviceEP.getExtension(serviceId).getParameters().get(parameter); 472 473 if (paramDef == null) 474 { 475 // The parameter is unknown 476 if (StringUtils.isEmpty(defaultValue)) 477 { 478 return null; 479 } 480 else 481 { 482 return new StringElement(parameter, Collections.EMPTY_MAP, defaultValue); 483 } 484 } 485 486 Map<String, MapNode> value = _getParameterValue(parameter, parameters, paramDef, defaultValue); 487 488 if (!value.containsKey(parameter)) 489 { 490 return null; 491 } 492 else if (paramDef instanceof ServiceParameterRepeater || (paramDef instanceof ServiceParameter && ((ServiceParameter) paramDef).isMultiple())) 493 { 494 MapNode node = value.get(parameter); 495 @SuppressWarnings("unchecked") 496 Map<String, ? extends Object> values = (Map<String, ? extends Object>) node.getValue(); 497 return new MapElement(parameter, node.getAttributes(), values); 498 } 499 else 500 { 501 return new StringElement(parameter, value.get(parameter).getAttributes(), (String) value.get(parameter).getValue()); 502 } 503 } 504 505 private static String _convertTagName(String name) 506 { 507 char c = name.charAt(0); 508 if (c >= '0' && c <= '9') 509 { 510 String hex = Integer.toHexString(c); 511 return "_x" + StringUtils.leftPad(hex, 4, '0') + "_" + name.substring(1); 512 } 513 else 514 { 515 return name; 516 } 517 } 518 519 private static Map<String, MapNode> _getParameterValue(String paramName, CompositeMetadata parentMetadata, ServiceParameterOrRepeater paramDef, String defaultValue) 520 { 521 Map<String, MapNode> paramValues = new HashMap<>(); 522 523 if (paramDef instanceof ServiceParameterRepeater) 524 { 525 if (!parentMetadata.hasMetadata(paramName)) 526 { 527 return paramValues; 528 } 529 530 Map<String, String> attributes = new HashMap<>(); 531 attributes.put("name", paramName); 532 attributes.put("type", MetadataType.COMPOSITE.name().toLowerCase()); 533 534 Map<String, Object> children = new HashMap<>(); 535 536 CompositeMetadata compositeMetadata = parentMetadata.getCompositeMetadata(paramName); 537 String[] entryNames = compositeMetadata.getMetadataNames(); 538 for (String entryName : entryNames) 539 { 540 Map<String, Object> entryValue = new HashMap<>(); 541 542 for (String childParamName : ((ServiceParameterRepeater) paramDef).getChildrenParameters().keySet()) 543 { 544 ServiceParameter childParamDef = ((ServiceParameterRepeater) paramDef).getChildrenParameters().get(childParamName); 545 // Default value is ignored if parameter is a composite metadata 546 Map<String, MapNode> childParamValues = _getParameterValue(childParamName, compositeMetadata.getCompositeMetadata(entryName), childParamDef, ""); 547 entryValue.putAll(childParamValues); 548 } 549 550 Map<String, String> entryAttributes = new HashMap<>(); 551 entryAttributes.put("name", entryName); 552 entryAttributes.put("type", MetadataType.COMPOSITE.name().toLowerCase()); 553 554 MapNode entryNode = new MapNode(entryValue, entryAttributes); 555 children.put(_convertTagName(entryName), entryNode); 556 } 557 558 MapNode node = new MapNode(children, attributes); 559 paramValues.put(paramName, node); 560 } 561 else 562 { 563 if (!parentMetadata.hasMetadata(paramName) && StringUtils.isEmpty(defaultValue)) 564 { 565 return paramValues; 566 } 567 568 Map<String, String> attributes = new HashMap<>(); 569 attributes.put("name", paramName); 570 attributes.put("type", ParameterHelper.typeToString(((ServiceParameter) paramDef).getType())); 571 572 if (((ServiceParameter) paramDef).isMultiple()) 573 { 574 Map<String, Object> values = new HashMap<>(); 575 values.put("value", Arrays.asList(parentMetadata.getStringArray(paramName, new String[] {defaultValue}))); 576 577 MapNode node = new MapNode(values, attributes); 578 paramValues.put(paramName, node); 579 } 580 else 581 { 582 String value = parentMetadata.getString(paramName, defaultValue); 583 if (StringUtils.isEmpty(value)) 584 { 585 value = defaultValue; 586 } 587 MapNode node = new MapNode(value, attributes); 588 paramValues.put(paramName, node); 589 } 590 } 591 592 return paramValues; 593 } 594 595 /** 596 * Returns the current site 597 * @return the current site 598 */ 599 public static String site() 600 { 601 Request request = ContextHelper.getRequest(_context); 602 return (String) request.getAttribute("site"); 603 } 604 605 /** 606 * Returns the current site 607 * @param pageId The identifier ot the page 608 * @return the current site 609 */ 610 public static String site(String pageId) 611 { 612 try 613 { 614 Page page = _getPage(pageId); 615 return page.getSiteName(); 616 } 617 catch (UnknownAmetysObjectException e) 618 { 619 _logger.error("Can not get site on page '" + pageId + "'", e); 620 return ""; 621 } 622 } 623 624 /** 625 * Return the current sitemap as a {@link Node}. 626 * @return the current sitemap. 627 */ 628 public static Node sitemap() 629 { 630 Request request = ContextHelper.getRequest(_context); 631 Sitemap sitemap = (Sitemap) request.getAttribute(Sitemap.class.getName()); 632 633 if (sitemap == null) 634 { 635 // Try to get sitemap from content 636 Content content = (Content) request.getAttribute(Content.class.getName()); 637 if (content instanceof WebContent) 638 { 639 sitemap = ((WebContent) content).getSite().getSitemap(content.getLanguage()); 640 } 641 } 642 643 if (sitemap == null) 644 { 645 return new EmptyElement("sitemap"); 646 } 647 648 Page page = (Page) request.getAttribute(Page.class.getName()); 649 650 return new SitemapElement(sitemap, page != null ? page.getPathInSitemap() : null, _rightManager, _renderingContextHandler, _currentUserProvider.getUser()); 651 } 652 653 /** 654 * Return the subsitemap of the given page as a {@link Node}. 655 * @param pageId The root page 656 * @return The page as node. 657 */ 658 public static Node sitemap(String pageId) 659 { 660 Page rootPage = null; 661 try 662 { 663 rootPage = _ametysObjectResolver.resolveById(pageId); 664 } 665 catch (UnknownAmetysObjectException e) 666 { 667 return new EmptyElement("page"); 668 } 669 670 Request request = ContextHelper.getRequest(_context); 671 Page page = (Page) request.getAttribute(Page.class.getName()); 672 673 return new PageElement(rootPage, _rightManager, _renderingContextHandler, page != null ? page.getPathInSitemap() : null, _currentUserProvider.getUser()); 674 } 675 676 /** 677 * Computes the breadcrumb of the current page. 678 * @return a NodeList containing all ancestor pages, rooted at the sitemap. 679 */ 680 public static NodeList breadcrumb() 681 { 682 Request request = ContextHelper.getRequest(_context); 683 Page page = (Page) request.getAttribute(Page.class.getName()); 684 685 List<Element> result = new ArrayList<>(); 686 687 AmetysObject parent = page.getParent(); 688 while (parent instanceof Page) 689 { 690 Element node = new StringElement("page", (Map<String, String>) null, parent.getId()); 691 result.add(node); 692 parent = parent.getParent(); 693 } 694 695 Collections.reverse(result); 696 return new AmetysNodeList(result); 697 } 698 699 /** 700 * Returns a DOM {@link Element} representing files and folder of the resources explorer, 701 * under the {@link ResourceCollection} corresponding to the given id. 702 * @param collectionId the id of the root {@link ResourceCollection}. 703 * @return an Element containing files and folders. 704 */ 705 public static Node resourcesById(String collectionId) 706 { 707 ResourceCollection collection = _ametysObjectResolver.resolveById(collectionId); 708 return new ResourceCollectionElement(collection); 709 } 710 711 /** 712 * Returns a DOM {@link Element} representing files and folder of the resources explorer, 713 * under the {@link ResourceCollection} corresponding to the given path. <br> 714 * This path is intended to be relative to the current site's resource explorer. 715 * @param path the path of the root {@link ResourceCollection}, relative to the current site's resource explorer. 716 * @return an Element containing files and folders or null if the specified resource does not exist. 717 */ 718 public static Node resourcesByPath(String path) 719 { 720 Request request = ContextHelper.getRequest(_context); 721 String siteName = (String) request.getAttribute("site"); 722 Site site = _siteManager.getSite(siteName); 723 724 try 725 { 726 ResourceCollection collection = site.getRootResources().getChild(path); 727 return new ResourceCollectionElement(collection); 728 } 729 catch (UnknownAmetysObjectException ex) 730 { 731 return null; 732 } 733 } 734 735 /** 736 * Returns a DOM {@link Element} representing files and folder of a skin directory. <br> 737 * This path is intended to be relative to the current skin's 'resources' directory. 738 * @param path the path of the root {@link ResourceCollection}, relative to the current skin's 'resources' directory. Can be a file path to test its existance. 739 * @return an Element containing files and folders. node name is 'collection' or 'resource' with an attribute 'name'. Return null if the path does not exits. 740 * @throws IOException if an error occured while listing files. 741 */ 742 public static Node skinResources(String path) throws IOException 743 { 744 FileSource source = (FileSource) _sourceResolver.resolveURI("skin://resources/" + path); 745 if (source.exists()) 746 { 747 return new FileElement(source.getFile()); 748 } 749 else 750 { 751 return null; 752 } 753 } 754 755 //************************* 756 // Page methods 757 //************************* 758 759 private static String _getMetadata(CompositeMetadata cm, String metadataName) 760 { 761 int i = metadataName.indexOf("/"); 762 if (i == -1) 763 { 764 return cm.getString(metadataName); 765 } 766 else 767 { 768 return _getMetadata(cm.getCompositeMetadata(metadataName.substring(0, i)), metadataName.substring(i + 1)); 769 } 770 } 771 772 private static Page _getPage(String sitename, String lang, String path) 773 { 774 Site site = _siteManager.getSite(sitename); 775 Sitemap sitemap = site.getSitemap(lang); 776 return sitemap.getChild(path); 777 } 778 779 private static Page _getPage(String id) 780 { 781 return _ametysObjectResolver.resolveById(id); 782 } 783 784 /** 785 * Get the site name of a page. 786 * @param pageId The page id. 787 * @return The name or empty if the page does not exist. 788 */ 789 public static String pageSiteName(String pageId) 790 { 791 try 792 { 793 Page page = _getPage(pageId); 794 return page.getSiteName(); 795 } 796 catch (UnknownAmetysObjectException e) 797 { 798 _logger.error("Can not get site name on page with id '" + pageId + "'", e); 799 return ""; 800 } 801 } 802 803 /** 804 * Get the title of a page. 805 * @param sitename the site name. 806 * @param lang the sitemap name. 807 * @param path the page path. 808 * @return The name or empty if the meta or the page does not exist. 809 */ 810 public static String pageTitle(String sitename, String lang, String path) 811 { 812 try 813 { 814 Page page = _getPage(sitename, lang, path); 815 return page.getTitle(); 816 } 817 catch (UnknownAmetysObjectException e) 818 { 819 _logger.error("Can not get title on page '" + sitename + "/" + lang + "/" + path + "'", e); 820 return ""; 821 } 822 } 823 824 /** 825 * Get the title of a page. 826 * @param pageId The page id. 827 * @return The name or empty if the meta or the page does not exist. 828 */ 829 public static String pageTitle(String pageId) 830 { 831 try 832 { 833 Page page = _getPage(pageId); 834 return page.getTitle(); 835 } 836 catch (UnknownAmetysObjectException e) 837 { 838 _logger.error("Can not get title on page with id '" + pageId + "'", e); 839 return ""; 840 } 841 } 842 843 /** 844 * Get the long title of a page 845 * @param sitename the site name 846 * @param lang the page's language 847 * @param path the page's path 848 * @return The name or empty if the meta or the page does not exist 849 */ 850 public static String pageLongTitle(String sitename, String lang, String path) 851 { 852 try 853 { 854 Page page = _getPage(sitename, lang, path); 855 return page.getLongTitle(); 856 } 857 catch (UnknownAmetysObjectException e) 858 { 859 _logger.error("Can not get long title on page '" + sitename + "/" + lang + "/" + path + "'", e); 860 return ""; 861 } 862 } 863 /** 864 * Get the long title of a page 865 * @param pageId The page id 866 * @return The name or empty if the meta or the page does not exist 867 */ 868 public static String pageLongTitle(String pageId) 869 { 870 try 871 { 872 Page page = _getPage(pageId); 873 return page.getLongTitle(); 874 } 875 catch (UnknownAmetysObjectException e) 876 { 877 _logger.error("Can not get long title on page with id '" + pageId + "'", e); 878 return ""; 879 } 880 } 881 882 /** 883 * Get the meta of a page 884 * @param sitename the site name 885 * @param lang the page's language 886 * @param path the page's path 887 * @param metadataName The meta name (/ for composite) 888 * @return The name or empty if the meta or the page does not exist 889 */ 890 public static String pageMetadata(String sitename, String lang, String path, String metadataName) 891 { 892 try 893 { 894 Page page = _getPage(sitename, lang, path); 895 try 896 { 897 return _getMetadata(page.getMetadataHolder(), metadataName); 898 } 899 catch (UnknownMetadataException e) 900 { 901 _logger.error("Can not get meta '" + metadataName + "' on page with id '" + page.getId() + "'", e); 902 return ""; 903 } 904 } 905 catch (UnknownAmetysObjectException e) 906 { 907 _logger.error("Can not get meta '" + metadataName + "' on page '" + sitename + "/" + lang + "/" + path + "'", e); 908 return ""; 909 } 910 } 911 912 /** 913 * Get the meta of a page 914 * @param pageId The page id 915 * @param metadataName The meta name (/ for composite) 916 * @return The name or empty if the meta or the page does not exist 917 */ 918 public static String pageMetadata(String pageId, String metadataName) 919 { 920 try 921 { 922 Page page = _getPage(pageId); 923 try 924 { 925 return _getMetadata(page.getMetadataHolder(), metadataName); 926 } 927 catch (UnknownMetadataException e) 928 { 929 _logger.error("Can not get meta '" + metadataName + "' on page with id '" + page.getId() + "'", e); 930 return ""; 931 } 932 } 933 catch (UnknownAmetysObjectException e) 934 { 935 _logger.error("Can not get meta '" + metadataName + "' on page with id '" + pageId + "'", e); 936 return ""; 937 } 938 } 939 940 /** 941 * Returns true if the given page is visible into navigation elements 942 * @param pageId the page id. 943 * @return true if the page is visible 944 */ 945 public static boolean pageIsVisible (String pageId) 946 { 947 try 948 { 949 Page page = _getPage(pageId); 950 return page.isVisible(); 951 } 952 catch (UnknownAmetysObjectException e) 953 { 954 _logger.error("Can not get visibility status on page with id '" + pageId + "'", e); 955 return false; 956 } 957 } 958 959 /** 960 * Returns true if the given page is visible into navigation elements 961 * @param sitename the site name 962 * @param lang the page's language 963 * @param path the page's path 964 * @return true if the page is visible 965 */ 966 public static boolean pageIsVisible (String sitename, String lang, String path) 967 { 968 try 969 { 970 Page page = _getPage(sitename, lang, path); 971 return page.isVisible(); 972 } 973 catch (UnknownAmetysObjectException e) 974 { 975 _logger.error("Can not get visibility status on page with id '" + sitename + "/" + lang + "/" + path + "'", e); 976 return false; 977 } 978 } 979 980 /** 981 * Returns true if the given page has restricted access. 982 * @param pageId the page id. 983 * @return true if the page exists and has restricted access. 984 */ 985 public static boolean pageHasRestrictedAccess(String pageId) 986 { 987 try 988 { 989 Page page = _getPage(pageId); 990 return !_rightManager.hasAnonymousReadAccess(page); 991 } 992 catch (UnknownAmetysObjectException e) 993 { 994 _logger.error("Can not get page access info on page with id '" + pageId + "'", e); 995 return false; 996 } 997 } 998 999 /** 1000 * Returns true if the given page has restricted access. 1001 * @param sitename the site name 1002 * @param lang the page's language 1003 * @param path the page's path 1004 * @return true if the page exists and has restricted access. 1005 */ 1006 public static boolean pageHasRestrictedAccess(String sitename, String lang, String path) 1007 { 1008 try 1009 { 1010 Page page = _getPage(sitename, lang, path); 1011 return !_rightManager.hasAnonymousReadAccess(page); 1012 } 1013 catch (UnknownAmetysObjectException e) 1014 { 1015 _logger.error("Can not get page access info on page with id '" + sitename + "/" + lang + "/" + path + "'", e); 1016 return false; 1017 } 1018 } 1019 1020 /** 1021 * Returns the path of the current page, relative to the sitemap's root. 1022 * @return the path of the current Page, or empty if there's no current page. 1023 */ 1024 public static String pagePath() 1025 { 1026 Request request = ContextHelper.getRequest(_context); 1027 Page page = (Page) request.getAttribute(Page.class.getName()); 1028 1029 return page == null ? "" : page.getPathInSitemap(); 1030 } 1031 1032 /** 1033 * Returns the path in sitemap of a page 1034 * @param pageId The id of page 1035 * @return the path of the Page, or empty if not exists 1036 */ 1037 public static String pagePath(String pageId) 1038 { 1039 try 1040 { 1041 Page page = _getPage(pageId); 1042 return page.getPathInSitemap(); 1043 } 1044 catch (UnknownAmetysObjectException e) 1045 { 1046 _logger.error("Can not get title on page with id '" + pageId + "'", e); 1047 return ""; 1048 } 1049 } 1050 1051 /** 1052 * Returns the id of the current page. 1053 * @return the id of the current Page, or empty if there's no current page. 1054 */ 1055 public static String pageId() 1056 { 1057 Request request = ContextHelper.getRequest(_context); 1058 Page page = (Page) request.getAttribute(Page.class.getName()); 1059 1060 return page == null ? "" : page.getId(); 1061 } 1062 1063 /** 1064 * Determines if the current zone item or (if there is no current zone item) the current page is cacheable 1065 * This method is only valid for a page. 1066 * @return true if the current zone item or page is cacheable. 1067 */ 1068 public static boolean isCacheable() 1069 { 1070 Request request = ContextHelper.getRequest(_context); 1071 if (request.getAttribute("IsZoneItemCacheable") != null) 1072 { 1073 return (Boolean) request.getAttribute("IsZoneItemCacheable"); 1074 } 1075 1076 // The method was called from the skin, out of a zone item 1077 Response response = ContextHelper.getResponse(_context); 1078 if (response.containsHeader("X-Ametys-Cacheable")) 1079 { 1080 return true; 1081 } 1082 return false; 1083 } 1084 1085 /** 1086 * Returns the id of pages referencing the content and for which the Front-office user can access 1087 * @param contentId The content's id 1088 * @return The pages' id 1089 */ 1090 public static NodeList accessibleReferencedPages (String contentId) 1091 { 1092 RenderingContext renderingContext = _renderingContextHandler.getRenderingContext(); 1093 boolean inBackOffice = renderingContext == RenderingContext.BACK || renderingContext == RenderingContext.PREVIEW; 1094 1095 List<StringElement> pages = new ArrayList<>(); 1096 1097 Content content = _ametysObjectResolver.resolveById(contentId); 1098 if (content instanceof WebContent) 1099 { 1100 Collection<ZoneItem> zoneItems = ((WebContent) content).getReferencingZoneItems(); 1101 1102 for (ZoneItem zoneItem : zoneItems) 1103 { 1104 String metadataSetName = zoneItem.getMetadataSetName(); 1105 Page page = zoneItem.getZone().getPage(); 1106 1107 if (inBackOffice || _rightManager.hasReadAccess(_currentUserProvider.getUser(), page)) 1108 { 1109 Map<String, String> attrs = new HashMap<>(); 1110 attrs.put("id", page.getId()); 1111 attrs.put("metadataSetName", metadataSetName); 1112 pages.add(new StringElement("page", attrs)); 1113 } 1114 } 1115 } 1116 1117 return new AmetysNodeList(pages); 1118 } 1119 1120 /** 1121 * Returns the id of pages referencing the content 1122 * @param contentId The content's id 1123 * @return The pages' id 1124 */ 1125 public static NodeList referencedPages (String contentId) 1126 { 1127 List<StringElement> pages = new ArrayList<>(); 1128 1129 Content content = _ametysObjectResolver.resolveById(contentId); 1130 if (content instanceof WebContent) 1131 { 1132 Collection<ZoneItem> zoneItems = ((WebContent) content).getReferencingZoneItems(); 1133 1134 for (ZoneItem zoneItem : zoneItems) 1135 { 1136 String metadataSetName = zoneItem.getMetadataSetName(); 1137 Page page = zoneItem.getZone().getPage(); 1138 1139 Map<String, String> attrs = new HashMap<>(); 1140 attrs.put("id", page.getId()); 1141 attrs.put("metadataSetName", metadataSetName); 1142 pages.add(new StringElement("page", attrs)); 1143 } 1144 } 1145 1146 return new AmetysNodeList(pages); 1147 } 1148 1149 /** 1150 * Returns the ids of the pages 1151 * @param sitename The site id 1152 * @param lang The language code 1153 * @param tag The tag id 1154 * @return Array of pages ids 1155 */ 1156 public static NodeList findPagesIdsByTag(String sitename, String lang, String tag) 1157 { 1158 String xpath = String.format("//element(*, ametys:page)[@ametys-internal:tags='%s' and @ametys:site='%s' and @ametys:sitemap='%s']", tag.replaceAll("'", "''"), sitename.replaceAll("'", "''"), lang.replaceAll("'", "''")); 1159 AmetysObjectIterable<Page> pages = _ametysObjectResolver.query(xpath); 1160 Iterator<Page> it = pages.iterator(); 1161 1162 List<StringElement> list = new ArrayList<>(); 1163 while (it.hasNext()) 1164 { 1165 list.add(new StringElement("page", "id", it.next().getId())); 1166 } 1167 return new AmetysNodeList(list); 1168 } 1169 1170 /** 1171 * Returns the ids of the pages 1172 * @param tag The tag id 1173 * @return Array of pages ids 1174 */ 1175 public static NodeList findPagesIdsByTag(String tag) 1176 { 1177 Request request = ContextHelper.getRequest(_context); 1178 String siteName = (String) request.getAttribute("site"); 1179 1180 String lang = (String) request.getAttribute("sitemapLanguage"); 1181 if (lang == null) 1182 { 1183 // Try to get current language from content 1184 Content content = (Content) request.getAttribute(Content.class.getName()); 1185 if (content != null) 1186 { 1187 lang = content.getLanguage(); 1188 } 1189 } 1190 1191 return findPagesIdsByTag(siteName, lang, tag); 1192 } 1193}