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 */ 016package org.ametys.cms.search.cocoon; 017 018import java.io.IOException; 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Locale; 024import java.util.Map; 025 026import org.apache.avalon.framework.component.Component; 027import org.apache.commons.lang3.StringUtils; 028import org.xml.sax.ContentHandler; 029import org.xml.sax.SAXException; 030 031import org.ametys.cms.repository.Content; 032import org.ametys.cms.search.model.MetadataResultField; 033import org.ametys.cms.search.model.ResultField; 034import org.ametys.cms.search.model.SystemProperty; 035import org.ametys.plugins.repository.AmetysRepositoryException; 036import org.ametys.runtime.model.Model; 037import org.ametys.runtime.model.ModelItem; 038import org.ametys.runtime.model.View; 039import org.ametys.runtime.model.ViewElement; 040import org.ametys.runtime.model.ViewHelper; 041import org.ametys.runtime.model.ViewItemAccessor; 042import org.ametys.runtime.model.type.DataContext; 043 044/** 045 * Helper to genrate SAX event for result of a search based on the requested result fields. 046 */ 047public class ContentResultSetHelper implements Component 048{ 049 /** Avalon Role. */ 050 public static final String ROLE = ContentResultSetHelper.class.getName(); 051 052 /** 053 * Generates SAX events for the items in the content's view. This method does not check rights. 054 * @param contentHandler the content handler where to SAX into. 055 * @param content the content. 056 * @param view the view. 057 * @param defaultLocale The locale to use to sax localized values such as multilingual content or multilingual string. 058 * Only to be valued if initial content's language is null, otherwise set this parameter to null. 059 * @throws AmetysRepositoryException if an error occurs. 060 * @throws SAXException if an error occurs. 061 * @throws IOException if an error occurs. 062 */ 063 public void viewToSAX(ContentHandler contentHandler, Content content, View view, Locale defaultLocale) throws AmetysRepositoryException, SAXException, IOException 064 { 065 DataContext context = DataContext.newInstance() 066 .withLocale(defaultLocale) 067 .withEmptyValues(false); 068 069 content.dataToSAX(contentHandler, view, context); 070 } 071 072 /** 073 * Generates SAX events for the result fields of a content. This method does not check rights. 074 * @param contentHandler the content handler where to SAX into. 075 * @param content the content. 076 * @param fields the result fields. 077 * @param defaultLocale The locale to use to sax localized values such as multilingual content or multilingual string. 078 * Only to be valued if initial content's language is null, otherwise set this parameter to null. 079 * @throws AmetysRepositoryException if an error occurs. 080 * @throws SAXException if an error occurs. 081 * @throws IOException if an error occurs. 082 * @deprecated use {@link #viewToSAX(ContentHandler, Content, View, Locale)} instead 083 */ 084 @Deprecated 085 public void saxResultFields(ContentHandler contentHandler, Content content, Collection<? extends ResultField> fields, Locale defaultLocale) throws AmetysRepositoryException, SAXException, IOException 086 { 087 View view = _buildViewFromResultFields(fields, content); 088 viewToSAX(contentHandler, content, view, defaultLocale); 089 } 090 091 private View _buildViewFromResultFields(Collection<? extends ResultField> fields, Content content) 092 { 093 List<String> modelItemPaths = new ArrayList<>(); 094 Map<String, SystemProperty> systemPropertiesByPaths = new HashMap<>(); 095 096 // Get all model items from result fields 097 for (ResultField field : fields) 098 { 099 String fieldPath = field instanceof MetadataResultField ? ((MetadataResultField) field).getFieldPath() : field.getId(); 100 ModelItem modelItem = content.getDefinition(fieldPath); 101 if (modelItem instanceof SystemProperty systemProperty) 102 { 103 // System properties are not part of the content model, so they have to be added to the view separately 104 systemPropertiesByPaths.put(fieldPath, systemProperty); 105 } 106 else 107 { 108 modelItemPaths.add(fieldPath); 109 } 110 } 111 112 // Create view with all attributes and properties (not system) 113 View view = View.of(content.getModel(), modelItemPaths.toArray(String[]::new)); 114 115 // Add view items for system properties 116 for (String systemPropertyPath : systemPropertiesByPaths.keySet()) 117 { 118 // Create view items for parents 119 // Created view items respect the model hierarchy 120 int lastIndexOfItemPathSeparator = systemPropertyPath.lastIndexOf(ModelItem.ITEM_PATH_SEPARATOR); 121 String parentPath = lastIndexOfItemPathSeparator > -1 ? systemPropertyPath.substring(0, lastIndexOfItemPathSeparator) : StringUtils.EMPTY; 122 ViewItemAccessor viewItemAccessor = StringUtils.isEmpty(parentPath) ? view : (ViewItemAccessor) ViewHelper.addViewItem(parentPath, view, content.getModel().toArray(Model[]::new)); 123 124 // Create a view element for system property 125 ViewElement systemPropertyViewItem = new ViewElement(); 126 systemPropertyViewItem.setDefinition(systemPropertiesByPaths.get(systemPropertyPath)); 127 128 // Add the view element to the parent view item accessor 129 viewItemAccessor.addViewItem(systemPropertyViewItem); 130 } 131 132 return view; 133 } 134}