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.plugins.odfsync.apogee.scc;
017
018import java.util.Optional;
019import java.util.Set;
020
021import org.apache.avalon.framework.component.Component;
022import org.apache.avalon.framework.context.Context;
023import org.apache.avalon.framework.context.ContextException;
024import org.apache.avalon.framework.context.Contextualizable;
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.components.ContextHelper;
029import org.apache.cocoon.environment.Request;
030import org.slf4j.Logger;
031
032import org.ametys.cms.repository.Content;
033import org.ametys.cms.repository.ModifiableContent;
034import org.ametys.cms.repository.ModifiableDefaultContent;
035import org.ametys.odf.ODFHelper;
036import org.ametys.odf.ProgramItem;
037import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollectionDAO;
038import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollectionHelper;
039
040/**
041 * Helper for Apogee Synchronizable Contents Collections.
042 */
043public class ApogeeSynchronizableContentsCollectionHelper implements Serviceable, Component, Contextualizable
044{
045    /** The Avalon Role */
046    public static final String ROLE = ApogeeSynchronizableContentsCollectionHelper.class.getName();
047 
048    /** Request attribute name to store handle contents during import or synchronization. */
049    public static final String HANDLE_CONTENTS = AbstractApogeeSynchronizableContentsCollection.class.getName() + "$handleContents";
050    
051    /** Request attribute name to store handle parent contents during import or synchronization. */
052    public static final String HANDLE_PARENT_CONTENTS = AbstractApogeeSynchronizableContentsCollection.class.getName() + "$handleParentContents";
053    
054    /** SCC DAO */
055    protected SynchronizableContentsCollectionHelper _sccHelper;
056    
057    /** The ODF Helper */
058    protected ODFHelper _odfHelper;
059    
060    /** SCC DAO */
061    protected SynchronizableContentsCollectionDAO _sccDAO;
062    
063    /** Context */
064    protected Context _context;
065    
066    @Override
067    public void service(ServiceManager smanager) throws ServiceException
068    {
069        _odfHelper = (ODFHelper) smanager.lookup(ODFHelper.ROLE);
070        _sccHelper = (SynchronizableContentsCollectionHelper) smanager.lookup(SynchronizableContentsCollectionHelper.ROLE);
071        _sccDAO = (SynchronizableContentsCollectionDAO) smanager.lookup(SynchronizableContentsCollectionDAO.ROLE);
072    }
073    
074    public void contextualize(Context context) throws ContextException
075    {
076        _context = context;
077    }
078    
079    /**
080     * Synchronize the content or its children if the content has no Apogee SCC
081     * @param content the content
082     * @param logger the logger
083     */
084    public void synchronizeContent(ModifiableContent content, Logger logger)
085    {
086        Optional<AbstractApogeeSynchronizableContentsCollection> childSCC = getContentSCC(content, logger);
087        // The content has a SCC, so synchronize it
088        if (childSCC.isPresent())
089        {
090            try
091            {
092                childSCC.get().synchronizeContent((ModifiableDefaultContent) content, logger);
093            }
094            catch (Exception e)
095            {
096                logger.error("An error occurred synchronized content '{}' ({}) from SCC '{}'", content.getTitle(), content.getId(), childSCC.get().getId(), e);
097            }
098        }
099        // The content is manually created, so search in deeper children
100        else if (addToHandleContents(content.getId()))
101        {
102            for (ProgramItem syncChild : _odfHelper.getChildProgramItems((ProgramItem) content))
103            {
104                synchronizeContent((ModifiableDefaultContent) syncChild, logger);
105            }
106        }
107    }
108    
109    /**
110     * Get the Apogee SCC for the content if it exists
111     * @param content The content to search on
112     * @param logger the logger
113     * @return the Apogee SCC
114     */
115    public Optional<AbstractApogeeSynchronizableContentsCollection> getContentSCC(Content content, Logger logger)
116    {
117        try
118        {
119            return _sccHelper.getSynchronizableCollectionIds(content)
120                .stream()
121                .map(_sccDAO::getSynchronizableContentsCollection)
122                .filter(AbstractApogeeSynchronizableContentsCollection.class::isInstance)
123                .map(AbstractApogeeSynchronizableContentsCollection.class::cast)
124                .findFirst();
125        }
126        catch (Exception e)
127        {
128            logger.error("An error occurred getting ametys-internal:scc property", e);
129        }
130        
131        return Optional.empty();
132    }
133    
134    /**
135     * Add the content ID to the handle contents list.
136     * @param contentId Content ID
137     * @return <code>true</code> if the content ID have been added, <code>false</code> is returned if the content ID already exists in the handle contents list.
138     */
139    public boolean addToHandleContents(String contentId)
140    {
141        return _addContentToRequestAttribute(contentId, HANDLE_CONTENTS);
142    }
143    
144    /**
145     * Add the content ID to the handle parent contents list.
146     * @param contentId Content ID
147     * @return <code>true</code> if the content ID have been added, <code>false</code> is returned if the content ID already exists in the handle parent contents list.
148     */
149    public boolean addToHandleParentContents(String contentId)
150    {
151        return _addContentToRequestAttribute(contentId, HANDLE_PARENT_CONTENTS);
152    }
153    
154    private boolean _addContentToRequestAttribute(String contentId, String attributeName)
155    {
156        Request request = ContextHelper.getRequest(_context);
157        @SuppressWarnings("unchecked")
158        Set<String> handleContents = (Set<String>) request.getAttribute(attributeName);
159        boolean added = handleContents.add(contentId);
160        request.setAttribute(attributeName, handleContents);
161        return added;
162    }
163}