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.plugins.ai.search;
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;
023
024import org.ametys.cms.ObservationConstants;
025import org.ametys.cms.repository.Content;
026import org.ametys.core.observation.Event;
027import org.ametys.core.observation.Observer;
028import org.ametys.plugins.ai.AIHelper;
029import org.ametys.plugins.repository.AmetysObjectIterable;
030import org.ametys.plugins.repository.AmetysObjectResolver;
031import org.ametys.plugins.repository.collection.AmetysObjectCollection;
032import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject;
033import org.ametys.runtime.plugin.component.AbstractLogEnabled;
034
035/**
036 * Observer called when content is deleted to delete useless data from cache
037 */
038public class ContentDeletedObserver extends AbstractLogEnabled implements Observer, Serviceable
039{
040
041    private CacheDAO _cacheDAO;
042    private AmetysObjectResolver _ametysObjectResolver;
043    private AIHelper _aiHelper;
044
045    public int getPriority()
046    {
047        return 0;
048    }
049
050    public boolean supports(Event event)
051    {
052        return (event.getId().equals(org.ametys.cms.ObservationConstants.EVENT_CONTENT_DELETED)
053                || event.getId().equals(org.ametys.web.ObservationConstants.EVENT_SITE_DELETED))
054            && _aiHelper.isEmbeddingSupported();
055    }
056    
057    public void service(ServiceManager manager) throws ServiceException
058    {
059        _cacheDAO = (CacheDAO) manager.lookup(CacheDAO.ROLE);
060        _ametysObjectResolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
061        _aiHelper = (AIHelper) manager.lookup(AIHelper.ROLE);
062    }
063
064    public void observe(Event event, Map<String, Object> transientVars) throws Exception
065    {
066        if (event.getId().equals(org.ametys.cms.ObservationConstants.EVENT_CONTENT_DELETED))
067        {
068            Content content = (Content) event.getArguments().get(ObservationConstants.ARGS_CONTENT);
069            DefaultTraversableAmetysObject cacheNode = _cacheDAO.getCacheContentNode(content, false);
070            if (cacheNode != null)
071            {
072                cacheNode.remove();
073                cacheNode.saveChanges();
074            }
075        }
076        else // Site deleted
077        {
078            String siteName = (String) event.getArguments().get(org.ametys.web.ObservationConstants.ARGS_SITE_NAME);
079            AmetysObjectIterable<DefaultTraversableAmetysObject> query = _ametysObjectResolver.query("//element(*, ametys:ai_cache_content)[@ametys-internal:site='" + siteName + "']");
080            query.forEach(ao -> ao.remove());
081            
082            AmetysObjectCollection cacheRootNode = _cacheDAO.getCacheRootNode();
083            if (cacheRootNode.needsSave())
084            {
085                cacheRootNode.saveChanges();
086            }
087        }
088    }
089}