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.cms.repository;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.HashMap;
021import java.util.Map;
022import java.util.Optional;
023
024import org.ametys.cms.data.ContentDataHelper;
025import org.ametys.cms.data.ContentSynchronizationContext;
026import org.ametys.cms.data.ContentSynchronizationResult;
027import org.ametys.cms.data.ContentValue;
028import org.ametys.cms.data.ReferencedContents;
029import org.ametys.plugins.repository.data.holder.impl.DefaultModifiableModelAwareDataHolder;
030import org.ametys.plugins.repository.data.holder.values.SynchronizationContext;
031import org.ametys.plugins.repository.data.holder.values.SynchronizationResult;
032import org.ametys.plugins.repository.data.repositorydata.ModifiableRepositoryData;
033import org.ametys.runtime.model.ModelItemContainer;
034import org.ametys.runtime.model.ViewItemContainer;
035import org.ametys.runtime.model.exception.BadItemTypeException;
036import org.ametys.runtime.model.exception.UndefinedItemPathException;
037
038/**
039 * Implementation modifiable data holder for content
040 */
041public class ModifiableContentDataHolder extends DefaultModifiableModelAwareDataHolder
042{
043    /** the content */
044    protected ModifiableContent _content;
045    
046    /** the content data helper */
047    protected ContentDataHelper _contentDataHelper;
048    
049    /**
050     * Creates a modifiable content data holder
051     * @param content the content
052     * @param contentDataHelper the content data helper
053     * @param repositoryData the repository data to use
054     * @param itemContainers the model containers to use to get information about definitions. Must match the given repository data. A repository data can have several item containers. For example, a content can have several content types.
055     */
056    public ModifiableContentDataHolder(ModifiableContent content, ContentDataHelper contentDataHelper, ModifiableRepositoryData repositoryData, Collection<? extends ModelItemContainer> itemContainers)
057    {
058        super(repositoryData, Optional.empty(), Optional.of(content), itemContainers);
059        _content = content;
060        _contentDataHelper = contentDataHelper;
061    }
062    
063    @Override
064    public <T extends SynchronizationResult> T synchronizeValues(ViewItemContainer viewItemContainer, Map<String, Object> values, SynchronizationContext context) throws UndefinedItemPathException, BadItemTypeException
065    {
066        Collection<ReferencedContents> allReferencedContents = new ArrayList<>();
067        if (context instanceof ContentSynchronizationContext)
068        {
069            ContentSynchronizationContext contentContext = (ContentSynchronizationContext) context;
070            if (contentContext.invertRelationsEnabled())
071            {
072                allReferencedContents.addAll(contentContext.getReferencedContents()
073                        .orElseGet(() -> _contentDataHelper.collectReferencedContents(viewItemContainer, _content, values, contentContext)));
074            }
075        }
076        
077        T result = super.synchronizeValues(viewItemContainer, values, context);
078        
079        if (result instanceof ContentSynchronizationResult)
080        {
081            Map<String, ModifiableContent> modifiedContents = new HashMap<>();
082            
083            for (ReferencedContents referencedContents : allReferencedContents)
084            {
085                String invertRelationPath = referencedContents.getDefinition().getInvertRelationPath();
086                modifiedContents.putAll(ContentDataHelper.manageInvertRelations(invertRelationPath, referencedContents.getAddedContents(), _content.getId(), ContentDataHelper::addInvertRelation, modifiedContents, context.getExternalizableDataContext()));
087                modifiedContents.putAll(ContentDataHelper.manageInvertRelations(invertRelationPath, referencedContents.getRemovedContents(), _content.getId(), ContentDataHelper::removeInvertRelation, modifiedContents, context.getExternalizableDataContext()));
088                
089                Map<ContentValue, Collection<String>> thirdPartyContents = new HashMap<>();
090                for (Map.Entry<ContentValue, ContentValue> thirdPartyContent : referencedContents.getThirdPartyContents().entrySet())
091                {
092                    thirdPartyContents.computeIfAbsent(thirdPartyContent.getValue(), __ -> new ArrayList<>()).add(thirdPartyContent.getKey().getContentId());
093                }
094                modifiedContents.putAll(ContentDataHelper.manageInvertRelations(referencedContents.getDefinition().getPath(), thirdPartyContents, ContentDataHelper::removeInvertRelation, modifiedContents, context.getExternalizableDataContext()));
095            }
096            
097            ((ContentSynchronizationResult) result).addModifiedContents(modifiedContents.values());
098        }
099        
100        return result;
101    }
102    
103    @SuppressWarnings("unchecked")
104    @Override
105    protected <T extends SynchronizationContext> T _createSynchronizationContextInstance()
106    {
107        return (T) ContentSynchronizationContext.newInstance();
108    }
109    
110    @SuppressWarnings("unchecked")
111    @Override
112    protected <T extends SynchronizationResult> T _createSetValueResultInstance()
113    {
114        return (T) new ContentSynchronizationResult();
115    }
116}