001/* 002 * Copyright 2020 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 */ 016package org.ametys.plugins.webcontentio.archive; 017 018import java.io.IOException; 019import java.io.InputStream; 020import java.nio.file.Path; 021import java.util.Comparator; 022import java.util.List; 023import java.util.Map; 024import java.util.Optional; 025import java.util.function.Function; 026import java.util.stream.Collectors; 027import java.util.stream.IntStream; 028 029import javax.jcr.Node; 030import javax.jcr.RepositoryException; 031import javax.xml.parsers.DocumentBuilder; 032import javax.xml.transform.TransformerException; 033 034import org.apache.commons.lang3.StringUtils; 035import org.apache.commons.lang3.tuple.Pair; 036import org.apache.xpath.XPathAPI; 037import org.apache.xpath.objects.XObject; 038import org.slf4j.Logger; 039import org.w3c.dom.Document; 040import org.w3c.dom.Element; 041import org.w3c.dom.NodeList; 042import org.xml.sax.SAXException; 043 044import org.ametys.cms.repository.Content; 045import org.ametys.core.util.LambdaUtils; 046import org.ametys.plugins.contentio.archive.ArchiveHandler; 047import org.ametys.plugins.contentio.archive.Archivers; 048import org.ametys.plugins.contentio.archive.Archivers.AmetysObjectNotImportedException; 049import org.ametys.plugins.contentio.archive.ImportGlobalFailException; 050import org.ametys.plugins.contentio.archive.ImportReport; 051import org.ametys.plugins.contentio.archive.ImportReport.ImportError; 052import org.ametys.plugins.contentio.archive.Merger; 053import org.ametys.plugins.contentio.archive.UnitaryImporter; 054import org.ametys.plugins.contentio.archive.ZipEntryHelper; 055import org.ametys.plugins.repository.data.extractor.xml.ModelAwareXMLValuesExtractor; 056import org.ametys.plugins.repository.data.extractor.xml.ModelLessXMLValuesExtractor; 057import org.ametys.plugins.repository.data.extractor.xml.XMLValuesExtractorAdditionalDataGetter; 058import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder; 059import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject; 060import org.ametys.plugins.repository.jcr.JCRAmetysObject; 061import org.ametys.runtime.model.View; 062import org.ametys.web.repository.page.ModifiablePage; 063import org.ametys.web.repository.page.ModifiableZone; 064import org.ametys.web.repository.page.ModifiableZoneItem; 065import org.ametys.web.repository.page.Page.LinkType; 066import org.ametys.web.repository.page.Page.PageType; 067import org.ametys.web.repository.page.PagesContainer; 068import org.ametys.web.repository.page.ZoneItem.ZoneType; 069import org.ametys.web.repository.page.jcr.DefaultPage; 070import org.ametys.web.repository.site.Site; 071import org.ametys.web.repository.sitemap.Sitemap; 072import org.ametys.web.service.Service; 073 074import com.google.common.io.MoreFiles; 075 076class SitemapImporter 077{ 078 final ImportReport _report = new ImportReport(); 079 private final SitesArchiver _siteArchiver; 080 private final Site _site; 081 private final Path _sitemapFolderPath; 082 private final Path _sitemapFilePath; 083 private final Path _zipArchivePath; 084 private final Merger _merger; 085 private final Logger _logger; 086 private final DocumentBuilder _builder; 087 private Sitemap _sitemap; 088 private final UnitarySitemapImporter _unitarySitemapImporter = new UnitarySitemapImporter(); 089 090 SitemapImporter(SitesArchiver siteArchiver, Site site, Path sitemapPath, Path zipArchivePath, Merger merger, Logger logger, DocumentBuilder builder) 091 { 092 _siteArchiver = siteArchiver; 093 _site = site; 094 _sitemapFolderPath = sitemapPath; 095 _sitemapFilePath = _sitemapFolderPath.resolveSibling(_sitemapFolderPath.getFileName() + ".xml"); 096 _zipArchivePath = zipArchivePath; 097 _merger = merger; 098 _logger = logger; 099 _builder = builder; 100 } 101 102 private class UnitarySitemapImporter implements UnitaryImporter<Sitemap> 103 { 104 @Override 105 public String objectNameForLogs() 106 { 107 return "Sitemap"; 108 } 109 110 @Override 111 public Document getPropertiesXml(Path zipEntryPath) throws Exception 112 { 113 return _getPropertiesXml(zipEntryPath); 114 } 115 116 @Override 117 public String retrieveId(Document propertiesXml) throws Exception 118 { 119 return Archivers.xpathEvalNonEmpty("sitemap/@id", propertiesXml); 120 } 121 122 @Override 123 public Sitemap create(Path zipEntryPath, String id, Document propertiesXml) throws AmetysObjectNotImportedException, ImportGlobalFailException, Exception 124 { 125 return _createChildSitemap(id, propertiesXml); 126 } 127 128 @Override 129 public ImportReport getReport() 130 { 131 return _report; 132 } 133 } 134 135 private class UnitaryPageImporter implements UnitaryImporter<Node> 136 { 137 private Document _propertiesXml; 138 139 UnitaryPageImporter(Document propertiesXml) 140 { 141 _propertiesXml = propertiesXml; 142 } 143 144 @Override 145 public String objectNameForLogs() 146 { 147 return "Page"; 148 } 149 150 @Override 151 public Document getPropertiesXml(Path zipEntryPath) throws Exception 152 { 153 return _propertiesXml; 154 } 155 156 @Override 157 public String retrieveId(Document propertiesXml) throws Exception 158 { 159 return Archivers.xpathEvalNonEmpty("page/@id", propertiesXml); 160 } 161 162 @Override 163 public Node create(Path zipEntryPath, String id, Document propertiesXml) throws AmetysObjectNotImportedException, Exception 164 { 165 Node pageNode = _createPage(zipEntryPath, id, propertiesXml); 166 _createPageAcl(pageNode, zipEntryPath); 167 Archivers.unitarySave(pageNode, _logger); 168 return pageNode; 169 } 170 171 @Override 172 public ImportReport getReport() 173 { 174 return _report; 175 } 176 } 177 178 void importSitemap() throws RepositoryException, IOException 179 { 180 boolean sitemapImported = _fillSitemap(); 181 if (sitemapImported) 182 { 183 _importAllPages(); 184 } 185 } 186 187 private boolean _fillSitemap() throws RepositoryException, IOException 188 { 189 Optional<Sitemap> optionalSitemap = _unitarySitemapImporter.unitaryImport(_zipArchivePath, _sitemapFilePath, _merger, _logger); 190 if (optionalSitemap.isEmpty()) 191 { 192 // potentially, sitemap was not imported => it was already logged in error level 193 // but fail, do not import pages 194 return false; 195 } 196 197 _sitemap = optionalSitemap.get(); 198 _createSitemapAcl(); 199 try 200 { 201 Archivers.unitarySave(_sitemap.getNode(), _logger); 202 return true; 203 } 204 catch (AmetysObjectNotImportedException e) 205 { 206 // potentially, sitemap was not imported => it was already logged in error level 207 // but fail, do not import pages 208 return false; 209 } 210 } 211 212 private Sitemap _createChildSitemap(String id, Document propertiesXml) throws AmetysObjectNotImportedException, Exception 213 { 214 String sitemapName = Archivers.xpathEvalNonEmpty("sitemap/@name", propertiesXml); 215 _logger.info("Creating a Sitemap object for '{}' file (lang={})", _sitemapFilePath, sitemapName); 216 String uuid = StringUtils.substringAfter(id, "://"); 217 Node sitemapNode = _createChildSitemap(uuid, sitemapName); 218 Sitemap sitemap = _resolveSitemap(sitemapNode); 219 _setSitemapAttributes(sitemap, propertiesXml); 220 Archivers.unitarySave(sitemapNode, _logger); 221 222 return sitemap; 223 } 224 225 private Node _createChildSitemap(String uuid, String sitemapName) throws RepositoryException 226 { 227 // Create a Node with JCR primary type "sitemap" 228 // But then call 'replaceNodeWithDesiredUuid' to have it with the desired UUID (srcNode will be removed) 229 Sitemap srcSitemap = _site.addSitemap(sitemapName); 230 Node srcNode = srcSitemap.getNode(); 231 Node nodeWithDesiredUuid = Archivers.replaceNodeWithDesiredUuid(srcNode, uuid); 232 return nodeWithDesiredUuid; 233 } 234 235 private Sitemap _resolveSitemap(Node node) 236 { 237 return _siteArchiver._sitemapFactory.getAmetysObject(node, null); 238 } 239 240 private void _setSitemapAttributes(Sitemap sitemap, Document propertiesXml) throws TransformerException, RepositoryException 241 { 242 _setAmetysInternalProperties(sitemap, propertiesXml, "sitemap"); 243 } 244 245 private void _createSitemapAcl() throws RepositoryException, IOException 246 { 247 Node node = _sitemap.getNode(); 248 String zipEntryPath = new StringBuilder(ArchiveHandler.METADATA_PREFIX) 249 .append(StringUtils.strip(_sitemapFolderPath.toString(), "/")) 250 .append("/") 251 .append(SitesArchiver.__ACL_ZIP_ENTRY_FILENAME) 252 .toString(); 253 _logger.debug("Trying to import ACL node for Sitemap '{}', from ACL XML file '{}', if it exists", node, zipEntryPath); 254 Archivers.importAcl(node, _zipArchivePath, _merger, zipEntryPath, _logger); 255 } 256 257 private void _createPageAcl(Node pageNode, Path pagePath) throws RepositoryException, IOException 258 { 259 String zipEntryPath = new StringBuilder(ArchiveHandler.METADATA_PREFIX) 260 .append(StringUtils.strip(pagePath.getParent().toString(), "/")) 261 .append("/") 262 .append(MoreFiles.getNameWithoutExtension(pagePath)) 263 .append("/") 264 .append(SitesArchiver.__ACL_ZIP_ENTRY_FILENAME) 265 .toString(); 266 _logger.debug("Trying to import ACL node for Page '{}', from ACL XML file '{}', if it exists", pageNode, zipEntryPath); 267 Archivers.importAcl(pageNode, _zipArchivePath, _merger, zipEntryPath, _logger); 268 } 269 270 private void _importAllPages() throws IOException 271 { 272 Pair<Path, Document>[] pageXmlFiles = ZipEntryHelper.zipFileTree( 273 _zipArchivePath, 274 Optional.of(_sitemapFolderPath.toString()), 275 (p, attrs) -> attrs.isRegularFile()) 276 .map(path -> Pair.of(path, _getNullablePagePropertiesXml(path))) 277 // filter out XML properties files which are not present (likely due to an error reading them) 278 .filter(pathAndXml -> pathAndXml.getRight() != null) 279 .sorted(_pageComparator()) 280 .toArray(Pair[]::new); 281 282 for (Pair<Path, Document> pagePathAndXml : pageXmlFiles) 283 { 284 Path pagePath = pagePathAndXml.getLeft(); 285 Document propertiesXml = pagePathAndXml.getRight(); 286 _importPage(pagePath, propertiesXml); 287 } 288 } 289 290 private Comparator<Pair<Path, Document>> _pageComparator() 291 { 292 // Sort by path name count, i.e. /foo/bar.xml should be before /foo/bar/baz.xml 293 // Thus, it will ensure parent pages are created when processing a specific XML page file 294 Comparator<Path> firstComparator = Comparator.comparingInt(Path::getNameCount); 295 296 // Sort by the complete string representation of the parent Path 297 // Just for debug purposes 298 // So as to export /foo/aaa/one then /foo/aaa/two and then /foo/zzz/one 299 // Instead of /foo/aaa/one then /foo/zzz/one and then /foo/aaa/two 300 Comparator<Path> secondComparator = Comparator.comparing(path -> path.getParent().toString()); 301 302 // Sort by order, to keep the order of sibling pages 303 Comparator<Document> thirdComparator = Comparator.comparingInt(this::_getOrder); 304 305 return Comparator.comparing(Pair<Path, Document>::getLeft, firstComparator) 306 .thenComparing(Comparator.comparing(Pair<Path, Document>::getLeft, secondComparator)) 307 .thenComparing(Comparator.comparing(Pair<Path, Document>::getRight, thirdComparator)); 308 } 309 310 private int _getOrder(Document propertiesXml) 311 { 312 try 313 { 314 return Integer.parseInt(Archivers.xpathEvalNonEmpty("page/@order", propertiesXml)); 315 } 316 catch (NumberFormatException | AmetysObjectNotImportedException | TransformerException e) 317 { 318 throw new LambdaUtils.LambdaException(e); 319 } 320 } 321 322 private void _importPage(Path page, Document propertiesXml) throws ImportGlobalFailException 323 { 324 new UnitaryPageImporter(propertiesXml) 325 .unitaryImport(_zipArchivePath, page, _merger, _logger); 326 } 327 328 private Document _getNullablePagePropertiesXml(Path page) 329 { 330 try 331 { 332 return _getPropertiesXml(page); 333 } 334 catch (Exception e) 335 { 336 _logger.error("An unexpected exception occured when trying to import page for '{}!{}'.", _zipArchivePath, page, e); 337 _report.addError(new ImportError(e)); 338 return null; 339 } 340 } 341 342 private Document _getPropertiesXml(Path pageOrSitemap) 343 { 344 String zipEntryPath = pageOrSitemap.toString(); 345 try (InputStream stream = ZipEntryHelper.zipEntryFileInputStream(_zipArchivePath, zipEntryPath)) 346 { 347 Document doc = _builder.parse(stream); 348 return doc; 349 } 350 catch (SAXException | IOException e) 351 { 352 throw new RuntimeException(String.format("The exported page/sitemap '%s' could not be read properly.", pageOrSitemap), e); 353 } 354 } 355 356 private Node _createPage(Path pagePath, String id, Document propertiesXml) throws AmetysObjectNotImportedException, Exception 357 { 358 Path parentPageOrSitemap = pagePath.getParent(); 359 String parentRelPath = _relativePath(parentPageOrSitemap); 360 Node parentNode = _retrieveParentPagesContainer(parentRelPath).getNode(); 361 String uuid = StringUtils.substringAfter(id, "://"); 362 String pageName = MoreFiles.getNameWithoutExtension(pagePath); 363 _logger.info("Creating a Page object for '{}' file (id={}, name={}, parent={})", pagePath, id, pageName, parentNode); 364 365 Node pageNode = _createChildPage(parentNode, uuid, pageName); 366 ModifiablePage createdPage = _resolvePage(pageNode); 367 _setPageAttributes(createdPage, propertiesXml); 368 _setTags(createdPage, propertiesXml); 369 _setZones(createdPage, propertiesXml); 370 Archivers.unitarySave(pageNode, _logger); 371 372 ImportReport importAttachmentReport = _setPageAttachments(createdPage, pagePath); 373 _report.addFrom(importAttachmentReport); 374 375 return pageNode; 376 } 377 378 private String _relativePath(Path pageOrSitemap) 379 { 380 // for instance, _sitemapFolderPath="/sites/45/7d/www/pages/fr" 381 // relPath=pageOrSitemap.toString()="/sites/45/7d/www/pages/fr/foo/bar" 382 // it should return "foo/bar" 383 384 // for instance, _sitemapFolderPath="/sites/45/7d/www/pages/fr" 385 // relPath=pageOrSitemap.toString()=""/sites/45/7d/www/pages/fr" 386 // it should return "" 387 388 // Cannot use _sitemapFolderPath.relativize(pageOrSitemap) as the two ZipPaths do not have the same FileSystem reference :-( 389 // (created with different calls to ZipEntryHelper) 390 String relPath = StringUtils.substringAfter(pageOrSitemap.toString(), _sitemapFolderPath.toString()); 391 relPath = StringUtils.strip(relPath, "/"); 392 return relPath; 393 } 394 395 private DefaultTraversableAmetysObject _retrieveParentPagesContainer(String relPath) 396 { 397 return relPath.isEmpty() 398 ? _sitemap 399 : _siteArchiver._defaultPageFactory.getChild(_sitemap, relPath); 400 } 401 402 private Node _createChildPage(Node parentNode, String uuid, String pageName) throws RepositoryException 403 { 404 // Create a Node with JCR primary type "ametys:defaultPage" 405 // But then call 'replaceNodeWithDesiredUuid' to have it with the desired UUID (srcNode will be removed) 406 Node srcNode = parentNode.addNode(pageName, "ametys:defaultPage"); 407 Node nodeWithDesiredUuid = Archivers.replaceNodeWithDesiredUuid(srcNode, uuid); 408 return nodeWithDesiredUuid; 409 } 410 411 private ModifiablePage _resolvePage(Node node) 412 { 413 return _siteArchiver._defaultPageFactory.getAmetysObject(node, null); 414 } 415 416 private void _setPageAttributes(ModifiablePage page, Document propertiesXml) throws AmetysObjectNotImportedException, TransformerException, Exception 417 { 418 String title = Archivers.xpathEvalNonEmpty("page/@title", propertiesXml); 419 page.setTitle(title); 420 421 String longTitle = Archivers.xpathEvalNonEmpty("page/@long-title", propertiesXml); 422 page.setLongTitle(longTitle); 423 424 PageType type = PageType.valueOf(Archivers.xpathEvalNonEmpty("page/@type", propertiesXml)); 425 page.setType(type); 426 427 switch (type) 428 { 429 case LINK: 430 String url = Archivers.xpathEvalNonEmpty("page/@url", propertiesXml); 431 LinkType urlType = LinkType.valueOf(Archivers.xpathEvalNonEmpty("page/@urlType", propertiesXml)); 432 page.setURL(urlType, url); 433 break; 434 case CONTAINER: 435 String template = Archivers.xpathEvalNonEmpty("page/@template", propertiesXml); 436 page.setTemplate(template); 437 break; 438 default: 439 break; 440 } 441 442 _setAmetysInternalProperties(page, propertiesXml, "page"); 443 444 Element pageAttributesElement = (Element) XPathAPI.selectSingleNode(propertiesXml, "page/attributes"); 445 Map<String, Object> values = new ModelLessXMLValuesExtractor(pageAttributesElement, (dataPath, dataType) -> Optional.empty(), _siteArchiver._pageDataTypeExtensionPoint) 446 .extractValues(); 447 448 page.synchronizeValues(values); 449 } 450 451 private void _setAmetysInternalProperties(PagesContainer pagesContainer, Document propertiesXml, String rootTagName) throws TransformerException, RepositoryException 452 { 453 if (pagesContainer instanceof JCRAmetysObject) 454 { 455 Node pagesContainerNode = ((JCRAmetysObject) pagesContainer).getNode(); 456 String xpath = String.format("%s/internal/*", rootTagName); 457 NodeList nodeList = XPathAPI.selectNodeList(propertiesXml, xpath); 458 Function<org.w3c.dom.Node, String> getInternalPropertyName = org.w3c.dom.Node::getNodeName; 459 Function<org.w3c.dom.Node, String> getInternalPropertyValue = org.w3c.dom.Node::getTextContent; 460 461 Map<String, List<String>> internalPropertiesToSet = IntStream.range(0, nodeList.getLength()) 462 .mapToObj(nodeList::item) 463 .collect(Collectors.groupingBy( 464 getInternalPropertyName, 465 Collectors.mapping( 466 getInternalPropertyValue, 467 Collectors.toList()))); 468 469 for (Map.Entry<String, List<String>> internalProperty : internalPropertiesToSet.entrySet()) 470 { 471 String internalPropertyName = internalProperty.getKey(); 472 List<String> internalPropertyValue = internalProperty.getValue(); 473 _logger.debug("Adding to '{}' internal property '{}' with value '{}'", pagesContainer, internalPropertyName, internalPropertyValue); 474 pagesContainerNode.setProperty(internalPropertyName, internalPropertyValue.toArray(String[]::new)); 475 } 476 } 477 } 478 479 private void _setTags(ModifiablePage page, Document propertiesXml) throws TransformerException 480 { 481 NodeList nodeList = XPathAPI.selectNodeList(propertiesXml, "page/tags/*"); 482 String[] tags = IntStream.range(0, nodeList.getLength()) 483 .mapToObj(nodeList::item) 484 .map(org.w3c.dom.Node::getNodeName) 485 .toArray(String[]::new); 486 for (String tag : tags) 487 { 488 _logger.debug("Tagging page '{}' with tag '{}'", page, tag); 489 page.tag(tag); 490 } 491 } 492 493 private ImportReport _setPageAttachments(ModifiablePage page, Path pagePath) throws IOException, RepositoryException 494 { 495 if (page instanceof DefaultPage) 496 { 497 Node pageNode = ((DefaultPage) page).getNode(); 498 499 // in case ametys-internal:attachments is already created 500 if (pageNode.hasNode(DefaultPage.ATTACHMENTS_NODE_NAME)) 501 { 502 pageNode.getNode(DefaultPage.ATTACHMENTS_NODE_NAME).remove(); 503 } 504 505 String commonPrefix = new StringBuilder() 506 .append(ArchiveHandler.METADATA_PREFIX) 507 .append(StringUtils.strip(pagePath.getParent().toString(), "/")) 508 .append("/") 509 .append(MoreFiles.getNameWithoutExtension(pagePath)) 510 .append("/") 511 .append("_attachments") 512 .append("/") 513 .toString(); 514 return _siteArchiver._resourcesArchiverHelper.importCollection(commonPrefix, pageNode, _zipArchivePath, _merger); 515 } 516 517 return new ImportReport(); 518 } 519 520 private void _setZones(ModifiablePage page, Document propertiesXml) throws TransformerException, AmetysObjectNotImportedException, Exception 521 { 522 NodeList zoneNodeList = XPathAPI.selectNodeList(propertiesXml, "page/pageContents/zone"); 523 for (int i = 0; i < zoneNodeList.getLength(); i++) 524 { 525 org.w3c.dom.Node zoneNode = zoneNodeList.item(i); 526 _setZone(page, zoneNode); 527 } 528 } 529 530 private void _setZone(ModifiablePage page, org.w3c.dom.Node zoneNode) throws TransformerException, AmetysObjectNotImportedException, Exception 531 { 532 String zoneName = Archivers.xpathEvalNonEmpty("@name", zoneNode); 533 ModifiableZone zone = page.createZone(zoneName); 534 535 Element zoneAttributesElement = (Element) XPathAPI.selectSingleNode(zoneNode, "attributes"); 536 Map<String, Object> values = new ModelLessXMLValuesExtractor(zoneAttributesElement, (dataPath, dataType) -> Optional.empty(), _siteArchiver._pageDataTypeExtensionPoint) 537 .extractValues(); 538 zone.synchronizeValues(values); 539 540 NodeList zoneItemNodeList = XPathAPI.selectNodeList(zoneNode, "zoneItem"); 541 for (int i = 0; i < zoneItemNodeList.getLength(); i++) 542 { 543 org.w3c.dom.Node zoneItemNode = zoneItemNodeList.item(i); 544 _setZoneItem(zone, zoneItemNode); 545 } 546 } 547 548 private void _setZoneItem(ModifiableZone zone, org.w3c.dom.Node zoneItemNode) throws TransformerException, Exception 549 { 550 ModifiableZoneItem zoneItem = zone.addZoneItem(); 551 ZoneType zoneType = ZoneType.valueOf(Archivers.xpathEvalNonEmpty("@type", zoneItemNode)); 552 zoneItem.setType(zoneType); 553 _setZoneItemAttributes(zoneItem, zoneItemNode); 554 555 switch (zoneType) 556 { 557 case CONTENT: 558 _setZoneItemContent(zoneItem, zoneItemNode); 559 break; 560 case SERVICE: 561 String serviceId = Archivers.xpathEvalNonEmpty("@serviceId", zoneItemNode); 562 zoneItem.setServiceId(serviceId); 563 _setZoneItemServiceParams(zoneItem, zoneItemNode, serviceId); 564 break; 565 default: 566 break; 567 } 568 } 569 570 private void _setZoneItemAttributes(ModifiableZoneItem zoneItem, org.w3c.dom.Node zoneItemNode) throws TransformerException, Exception 571 { 572 Element zoneItemAttributesElement = (Element) XPathAPI.selectSingleNode(zoneItemNode, "attributes"); 573 Map<String, Object> values = new ModelLessXMLValuesExtractor(zoneItemAttributesElement, (dataPath, type) -> Optional.empty(), _siteArchiver._pageDataTypeExtensionPoint) 574 .extractValues(); 575 zoneItem.synchronizeValues(values); 576 } 577 578 private void _setZoneItemContent(ModifiableZoneItem zoneItem, org.w3c.dom.Node zoneItemNode) throws TransformerException, AmetysObjectNotImportedException 579 { 580 String contentId = Archivers.xpathEvalNonEmpty("@contentId", zoneItemNode); 581 if (_siteArchiver._resolver.hasAmetysObjectForId(contentId)) 582 { 583 Content content = _siteArchiver._resolver.resolveById(contentId); 584 zoneItem.setContent(content); 585 } 586 XObject viewNameXObject = XPathAPI.eval(zoneItemNode, "@viewName"); 587 if (viewNameXObject.getType() != XObject.CLASS_NULL) 588 { 589 String viewName = viewNameXObject.str(); 590 zoneItem.setViewName(viewName); 591 } 592 } 593 594 private void _setZoneItemServiceParams(ModifiableZoneItem zoneItem, org.w3c.dom.Node zoneItemNode, String serviceId) throws Exception 595 { 596 Element serviceParamsElement = (Element) XPathAPI.selectSingleNode(zoneItemNode, "serviceParameters"); 597 Service service = _getService(serviceId); 598 if (service == null) 599 { 600 String message = String.format("Service with id '%s' for ZoneItem \"%s\" does not exist", serviceId, zoneItem); 601 _logger.error(message); 602 _report.addError(new ImportError(new Exception(message))); 603 } 604 else 605 { 606 XMLValuesExtractorAdditionalDataGetter additionalDataGetter = (dataPath, type) -> Optional.empty(); 607 View view = View.of(service); 608 Map<String, Object> values = new ModelAwareXMLValuesExtractor(serviceParamsElement, additionalDataGetter, service) 609 .extractValues(view); 610 611 ModifiableModelAwareDataHolder serviceParametersDataHolder = zoneItem.getServiceParameters(); 612 serviceParametersDataHolder.synchronizeValues(view, values); 613 } 614 } 615 616 private Service _getService(String serviceId) 617 { 618 return _siteArchiver._serviceExtensionPoint.getExtension(serviceId); 619 } 620}