001/* 002 * Copyright 2024 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.web.properties.section.page; 017 018import java.util.ArrayList; 019import java.util.HashMap; 020import java.util.HashSet; 021import java.util.LinkedHashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.Set; 025 026import javax.jcr.Node; 027import javax.jcr.NodeIterator; 028import javax.jcr.RepositoryException; 029 030import org.apache.avalon.framework.service.ServiceException; 031import org.apache.avalon.framework.service.ServiceManager; 032import org.apache.avalon.framework.service.Serviceable; 033import org.apache.commons.lang3.LocaleUtils; 034 035import org.ametys.cms.content.references.OutgoingReferencesHelper; 036import org.ametys.cms.properties.section.AbstractDefaultPropertySection; 037import org.ametys.cms.repository.Content; 038import org.ametys.plugins.repository.AmetysObject; 039import org.ametys.plugins.repository.AmetysObjectResolver; 040import org.ametys.plugins.repository.jcr.JCRAmetysObject; 041import org.ametys.web.repository.content.WebContent; 042import org.ametys.web.repository.page.Page; 043 044/** 045 * Section displaying references to the page. 046 */ 047public class PageReferencerSection extends AbstractDefaultPropertySection implements Serviceable 048{ 049 private AmetysObjectResolver _resolver; 050 051 public void service(ServiceManager manager) throws ServiceException 052 { 053 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 054 } 055 056 public boolean supports(AmetysObject ametysObject) 057 { 058 return ametysObject instanceof Page; 059 } 060 061 @Override 062 protected Map<String, Object> buildData(AmetysObject ametysObject) 063 { 064 Map<String, Object> resultMap = new LinkedHashMap<>(); 065 066 Page page = (Page) ametysObject; 067 resultMap.put("contents", _incomingContents(page)); 068 resultMap.put("pages", _incomingPages(page)); 069 070 return resultMap; 071 } 072 073 private List<Map<String, Object>> _incomingContents(Page page) 074 { 075 List<Map<String, Object>> json = new ArrayList<>(); 076 077 if (page instanceof JCRAmetysObject ametysObject) 078 { 079 // Avoid duplicates 080 Set<Content> refContents = new HashSet<>(); 081 082 try 083 { 084 NodeIterator results = OutgoingReferencesHelper.getContentOutgoingReferences(ametysObject, "page"); 085 while (results.hasNext()) 086 { 087 Node node = results.nextNode(); 088 089 try 090 { 091 Node contentNode = node.getParent() // go up towards node 'ametys-internal:outgoing-references 092 .getParent() // go up towards node 'ametys-internal:root-outgoing-references 093 .getParent(); // go up towards node of the content 094 Content refContent = _resolver.resolve(contentNode, false); 095 096 if (refContents.add(refContent)) 097 { 098 Map<String, Object> contentJson = new HashMap<>(); 099 contentJson.put("id", refContent.getId()); 100 contentJson.put("title", refContent.getTitle(LocaleUtils.toLocale(page.getSitemapName()))); 101 if (refContent instanceof WebContent webContent) 102 { 103 contentJson.put( 104 "pages", 105 webContent.getReferencingPages() 106 .stream() 107 .map(this::_page2JSON) 108 .toList() 109 ); 110 } 111 112 json.add(contentJson); 113 } 114 } 115 catch (RepositoryException e) 116 { 117 getLogger().error("Impossible to get the linked content in the node {}", node.getPath()); 118 } 119 } 120 } 121 catch (RepositoryException e) 122 { 123 // Should not happen 124 } 125 } 126 127 return json; 128 } 129 130 private List<Map<String, Object>> _incomingPages(Page page) 131 { 132 String query = "//element(*, ametys:page)[@ametys-internal:type = 'LINK' and @ametys-internal:url='" + page.getId() + "']"; 133 return _resolver.<Page>query(query) 134 .stream() 135 .map(this::_page2JSON) 136 .toList(); 137 } 138 139 private Map<String, Object> _page2JSON(Page page) 140 { 141 return Map.of( 142 "id", page.getId(), 143 "title", page.getTitle() 144 ); 145 } 146}