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