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