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.odf.properties.section.content; 017 018import java.util.Comparator; 019import java.util.HashMap; 020import java.util.LinkedHashMap; 021import java.util.List; 022import java.util.Locale; 023import java.util.Map; 024import java.util.Optional; 025import java.util.function.Predicate; 026 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.avalon.framework.service.Serviceable; 030import org.apache.commons.lang3.LocaleUtils; 031 032import org.ametys.cms.properties.section.AbstractDefaultPropertySection; 033import org.ametys.cms.repository.Content; 034import org.ametys.cms.repository.Content.ReferencingContentsSearch; 035import org.ametys.odf.ODFHelper; 036import org.ametys.odf.ProgramItem; 037import org.ametys.plugins.repository.AmetysObject; 038import org.ametys.plugins.repository.AmetysObjectResolver; 039 040/** 041 * The referencer items for {@link ProgramItem}. 042 * It displays educational paths, children and other references to the content. 043 */ 044public class ProgramItemReferencerSection extends AbstractDefaultPropertySection implements Serviceable 045{ 046 private static final ListProgramItemComparator __LIST_PROGRAM_ITEM_COMPARATOR = new ListProgramItemComparator(); 047 048 private AmetysObjectResolver _resolver; 049 private ODFHelper _odfHelper; 050 051 public void service(ServiceManager smanager) throws ServiceException 052 { 053 _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE); 054 _odfHelper = (ODFHelper) smanager.lookup(ODFHelper.ROLE); 055 } 056 057 public boolean supports(AmetysObject ametysObject) 058 { 059 return ametysObject instanceof ProgramItem; 060 } 061 062 @Override 063 protected Map<String, Object> buildData(AmetysObject ametysObject) 064 { 065 ProgramItem programItem = (ProgramItem) ametysObject; 066 067 Map<String, Object> resultMap = new LinkedHashMap<>(); 068 069 resultMap.put("educationalPaths", _getEducationalPaths(programItem)); 070 resultMap.put("children", _getChildren(programItem)); 071 resultMap.put("otherReferences", _getOtherReferences((Content) ametysObject)); 072 073 return resultMap; 074 } 075 076 private List<List<Map<String, Object>>> _getEducationalPaths(ProgramItem programItem) 077 { 078 // To avoid to return path only with the program item itself 079 if (_odfHelper.hasParentProgramItems(programItem)) 080 { 081 return _odfHelper.getEducationalPaths(programItem) 082 .stream() 083 .map(p -> p.getProgramItems(_resolver)) 084 .sorted(__LIST_PROGRAM_ITEM_COMPARATOR) 085 .map(this::_programItemList2JSON) 086 .toList(); 087 } 088 089 return List.of(); 090 } 091 092 private List<Map<String, Object>> _getChildren(ProgramItem programItem) 093 { 094 return _programItemList2JSON(_odfHelper.getChildProgramItems(programItem)); 095 } 096 097 @SuppressWarnings("unlikely-arg-type") 098 private Map<String, Object> _getOtherReferences(Content content) 099 { 100 Map<String, Object> resultMap = new LinkedHashMap<>(); 101 102 ReferencingContentsSearch referencingContents = content.searchReferencingContents(100); 103 104 ProgramItem programItem = (ProgramItem) content; 105 List<ProgramItem> children2 = _odfHelper.getChildProgramItems(programItem); 106 List<ProgramItem> parents2 = _odfHelper.getParentProgramItems(programItem); 107 108 Locale locale = Optional.of(content) 109 .map(Content::getLanguage) 110 .map(LocaleUtils::toLocale) 111 .orElse(null); 112 113 resultMap.put( 114 "referencingContents", 115 referencingContents.referencingContents() 116 .stream() 117 // Remove direct children 118 .filter(Predicate.not(children2::contains)) 119 // Remove direct parents 120 .filter(Predicate.not(parents2::contains)) 121 .map(c -> _content2JSON(c, locale)) 122 .toList() 123 ); 124 125 if (referencingContents.hasOtherReferences()) 126 { 127 resultMap.put("hasOther", true); 128 } 129 return resultMap; 130 } 131 132 private List<Map<String, Object>> _programItemList2JSON(List<ProgramItem> programItems) 133 { 134 return programItems.stream() 135 .map(this::_programItem2JSON) 136 .toList(); 137 } 138 139 private Map<String, Object> _programItem2JSON(ProgramItem programItem) 140 { 141 Map<String, Object> json = new HashMap<>(); 142 json.put("id", programItem.getId()); 143 json.put("title", ((Content) programItem).getTitle()); 144 json.put("code", programItem.getCode()); 145 return json; 146 } 147 148 private Map<String, Object> _content2JSON(Content content, Locale locale) 149 { 150 return Map.of( 151 "id", content.getId(), 152 "title", content.getTitle(locale) 153 ); 154 } 155 156 /** 157 * Comparator of {@link List} composing of {@link ProgramItem} by title. 158 */ 159 private static final class ListProgramItemComparator implements Comparator<List<ProgramItem>> 160 { 161 public int compare(List<ProgramItem> l1, List<ProgramItem> l2) 162 { 163 int l1Size = l1.size(); 164 int l2Size = l2.size(); 165 166 for (int i = 0; i < l1Size; i++) 167 { 168 if (l2Size <= i) 169 { 170 // l1 is greater than l2 171 return 1; 172 } 173 else 174 { 175 // Compare title 176 int comparing = ((Content) l1.get(i)).getTitle().compareTo(((Content) l2.get(i)).getTitle()); 177 if (comparing != 0) 178 { 179 return comparing; 180 } 181 } 182 } 183 184 // Lists are the same at the end of reading l1 185 // Then compare size of the lists 186 return Integer.compare(l1Size, l2Size); 187 } 188 } 189}