001/* 002 * Copyright 2023 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.model.properties; 017 018import java.util.Collection; 019import java.util.Collections; 020import java.util.Map; 021import java.util.Optional; 022import java.util.Set; 023import java.util.stream.Stream; 024 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.avalon.framework.service.Serviceable; 028import org.apache.cocoon.ProcessingException; 029import org.xml.sax.ContentHandler; 030import org.xml.sax.SAXException; 031 032import org.ametys.cms.contenttype.ContentType; 033import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 034import org.ametys.cms.contenttype.ContentTypesHelper; 035import org.ametys.cms.data.ContentValue; 036import org.ametys.cms.data.ametysobject.ModelAwareDataAwareAmetysObject; 037import org.ametys.cms.data.type.ModelItemTypeConstants; 038import org.ametys.cms.model.ContentElementDefinition; 039import org.ametys.cms.repository.ModifiableContent; 040import org.ametys.core.util.XMLUtils; 041import org.ametys.runtime.model.DefinitionContext; 042import org.ametys.runtime.model.ModelItem; 043 044/** 045 * Abstract class for content property 046 * @param <X> type of ametys object supported by this property 047 */ 048public abstract class AbstractContentProperty<X extends ModelAwareDataAwareAmetysObject> extends AbstractProperty<ContentValue, X> implements ContentElementDefinition, Serviceable 049{ 050 private ContentTypeExtensionPoint _contentTypeExtensionPoint; 051 private ContentTypesHelper _contentTypesHelper; 052 053 public void service(ServiceManager manager) throws ServiceException 054 { 055 _contentTypesHelper = (ContentTypesHelper) manager.lookup(ContentTypesHelper.ROLE); 056 _contentTypeExtensionPoint = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE); 057 } 058 059 @Override 060 protected String _getTypeId() 061 { 062 return ModelItemTypeConstants.CONTENT_ELEMENT_TYPE_ID; 063 } 064 065 public String getCriterionWidget() 066 { 067 return "edition.select-content"; 068 } 069 070 public void setContentTypeId(String contentTypeId) 071 { 072 throw new UnsupportedOperationException("Setting the content type is not supported on " + getClass() + ", it is defined by the property itself."); 073 } 074 075 public Collection< ? extends ModelItem> getModelItems() 076 { 077 if (_contentTypeExtensionPoint.hasExtension(getContentTypeId())) 078 { 079 ContentType contentType = _contentTypeExtensionPoint.getExtension(getContentTypeId()); 080 return contentType.getModelItems(); 081 } 082 else 083 { 084 return Collections.singleton(_contentTypesHelper.getTitleAttributeDefinition()); 085 } 086 } 087 088 @Override 089 protected Map<String, Object> _toJSON(DefinitionContext context) throws ProcessingException 090 { 091 Map<String, Object> result = super._toJSON(context); 092 result.put("contentType", getContentTypeId()); 093 return result; 094 } 095 096 @Override 097 public void toSAX(ContentHandler contentHandler, DefinitionContext context) throws SAXException 098 { 099 super.toSAX(contentHandler, context); 100 XMLUtils.createElementIfNotNull(contentHandler, "contentType", getContentTypeId()); 101 } 102 103 @Override 104 public Object getValue(X dataHolder) 105 { 106 Set<? extends ModifiableContent> contents = _getLinkedContents(dataHolder); 107 108 return isMultiple() 109 ? _transformToContentValueArray(contents) 110 : Optional.ofNullable(contents) 111 .map(Set::stream) 112 .orElseGet(Stream::empty) 113 .findFirst() 114 .orElse(null); 115 } 116 117 /** 118 * Get the linked contents to index. 119 * @param dataHolder The data holder 120 * @return The linked contents 121 */ 122 protected abstract Set<? extends ModifiableContent> _getLinkedContents(X dataHolder); 123 124 private ContentValue[] _transformToContentValueArray(Set<? extends ModifiableContent> contents) 125 { 126 if (contents == null) 127 { 128 return null; 129 } 130 131 return contents.stream() 132 .map(ContentValue::new) 133 .toArray(ContentValue[]::new); 134 } 135}