001/*
002 *  Copyright 2026 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.workflow.schedule;
017
018import java.util.Map;
019
020import org.apache.avalon.framework.service.ServiceException;
021import org.apache.avalon.framework.service.ServiceManager;
022import org.apache.avalon.framework.service.Serviceable;
023import org.quartz.JobKey;
024import org.quartz.SchedulerException;
025
026import org.ametys.cms.ObservationConstants;
027import org.ametys.cms.clientsideelement.ScheduleContentPublicationClientSideElement;
028import org.ametys.cms.repository.ModifiableContent;
029import org.ametys.core.observation.AsyncObserver;
030import org.ametys.core.observation.Event;
031import org.ametys.plugins.core.schedule.Scheduler;
032import org.ametys.plugins.repository.AmetysObject;
033import org.ametys.plugins.repository.AmetysObjectResolver;
034import org.ametys.plugins.repository.data.holder.ModifiableDataHolder;
035import org.ametys.plugins.repository.version.ModifiableDataAwareVersionableAmetysObject;
036import org.ametys.runtime.plugin.component.AbstractLogEnabled;
037
038/**
039 * Manage scheduled publication for deleted and restored content
040 */
041public class ScheduledPublicationObserver extends AbstractLogEnabled implements AsyncObserver, Serviceable
042{
043    /** The resolver */
044    protected AmetysObjectResolver _resolver;
045    /** The scheduler */
046    protected Scheduler _scheduler;
047
048    public void service(ServiceManager manager) throws ServiceException
049    {
050        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
051        _scheduler = (Scheduler) manager.lookup(Scheduler.ROLE);
052    }
053    
054    public int getPriority()
055    {
056        return 0;
057    }
058
059    public boolean supports(Event event)
060    {
061        String eventId = event.getId();
062        return ObservationConstants.EVENT_CONTENT_DELETED.equals(eventId)
063            || ObservationConstants.EVENT_TRASH_RESTORED.equals(eventId);
064    }
065
066    public void observe(Event event, Map<String, Object> transientVars) throws Exception
067    {
068        if (ObservationConstants.EVENT_CONTENT_DELETED.equals(event.getId()))
069        {
070            _unschedulePublication(event);
071        }
072        else // if (ObservationConstants.EVENT_TRASH_RESTORED.equals(event.getId()))
073        {
074            String objectId = (String) event.getArguments().get(ObservationConstants.ARGS_AMETYS_OBJECT_ID);
075            AmetysObject object = _resolver.resolveById(objectId);
076            if (object instanceof ModifiableContent content)
077            {
078                _removeSchedulingMetadata(content);
079            }
080        }
081    }
082
083    private void _unschedulePublication(Event event) throws SchedulerException
084    {
085        String contentId = (String) event.getArguments().get(ObservationConstants.ARGS_CONTENT_ID);
086        
087        JobKey jobKey = new JobKey(PublishContentRunnable.getId(contentId), Scheduler.JOB_GROUP);
088        if (_scheduler.getScheduler().checkExists(jobKey))
089        {
090            getLogger().debug("Removing the existing job for publishing {}", contentId);
091            _scheduler.getScheduler().deleteJob(jobKey);
092        }
093        
094        jobKey = new JobKey(UnpublishContentRunnable.getId(contentId), Scheduler.JOB_GROUP);
095        if (_scheduler.getScheduler().checkExists(jobKey))
096        {
097            getLogger().debug("Removing the existing job for unpublishing {}", contentId);
098            _scheduler.getScheduler().deleteJob(jobKey);
099        }
100    }
101
102    private void _removeSchedulingMetadata(ModifiableContent content)
103    {
104        getLogger().debug("Removing the scheduling metadata for {}", content.getId());
105        ModifiableDataHolder unversionedDataHolder = ((ModifiableDataAwareVersionableAmetysObject) content).getUnversionedDataHolder();
106        unversionedDataHolder.removeValue(ScheduleContentPublicationClientSideElement.PUBLISH_ACTION_ID);
107        unversionedDataHolder.removeValue(ScheduleContentPublicationClientSideElement.PUBLISH_DATE);
108        unversionedDataHolder.removeValue(ScheduleContentPublicationClientSideElement.UNPUBLISH_ACTION_ID);
109        unversionedDataHolder.removeValue(ScheduleContentPublicationClientSideElement.UNPUBLISH_DATE);
110        
111        if (content.needsSave())
112        {
113            content.saveChanges();
114        }
115    }
116}