001/*
002 *  Copyright 2025 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.trash.observer;
017
018import java.lang.reflect.ParameterizedType;
019import java.util.HashMap;
020import java.util.Map;
021
022import org.apache.avalon.framework.service.ServiceException;
023import org.apache.avalon.framework.service.ServiceManager;
024import org.apache.avalon.framework.service.Serviceable;
025
026import org.ametys.cms.ObservationConstants;
027import org.ametys.core.observation.Event;
028import org.ametys.core.observation.ObservationManager;
029import org.ametys.core.observation.Observer;
030import org.ametys.plugins.repository.AmetysObject;
031import org.ametys.plugins.repository.AmetysObjectResolver;
032import org.ametys.plugins.repository.trash.TrashableAmetysObject;
033
034/**
035 * Abstract observer to send added notification of each object restored by the trash.
036 * @param <T> The type of the restored object
037 */
038@SuppressWarnings("unchecked")
039public abstract class AbstractAmetysObjectAddedObserver<T extends TrashableAmetysObject> implements Observer, Serviceable
040{
041    private AmetysObjectResolver _resolver;
042    private ObservationManager _observationManager;
043    
044    private Class<T> _type;
045    {
046        // Get the <T> class by going up in the implementation until the superclass is this abstract class (AbstractElementType)
047        Class c = this.getClass();
048        while (!c.getSuperclass().equals(AbstractAmetysObjectAddedObserver.class))
049        {
050            c = c.getSuperclass();
051        }
052
053        // The super class is now AbstractElementType, which is Parameterized, so we can get the type arguments
054        _type = (Class<T>) ((ParameterizedType) c.getGenericSuperclass()).getActualTypeArguments()[0];
055    }
056    
057    public void service(ServiceManager manager) throws ServiceException
058    {
059        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
060        _observationManager = (ObservationManager) manager.lookup(ObservationManager.ROLE);
061    }
062
063    public int getPriority()
064    {
065        // Should be launch soon in the process
066        return 500;
067    }
068
069    public boolean supports(Event event)
070    {
071        return event.getId().equals(ObservationConstants.EVENT_TRASH_RESTORED);
072    }
073
074    public void observe(Event event, Map<String, Object> transientVars) throws Exception
075    {
076        T ametysObject = _getAmetysObject(event);
077        if (ametysObject != null)
078        {
079            _observationManager.notify(new Event(getEventId(), event.getIssuer(), getEventParams(ametysObject)));
080        }
081    }
082    
083    /**
084     * Get event identifier to notify.
085     * @return the event id
086     */
087    protected abstract String getEventId();
088    
089    /**
090     * Get the event params to send in the notification.
091     * @param ametysObject The Ametys object on which the event is send
092     * @return the event params as a map
093     */
094    protected Map<String, Object> getEventParams(T ametysObject)
095    {
096        Map<String, Object> eventParams = new HashMap();
097
098        eventParams.put(TrashObserverHelper.ARGS_ORIGIN_RESTORED, true);
099        eventParams.putAll(getAdditionalEventParams(ametysObject));
100        
101        return eventParams;
102    }
103
104    /**
105     * Get the additional event params specific to the child observer to send in the notification.
106     * @param ametysObject The Ametys object on which the event is send
107     * @return the event params as a map
108     */
109    protected abstract Map<String, Object> getAdditionalEventParams(T ametysObject);
110
111    /**
112     * Get the Ametys object and type it from the event arguments.
113     * @param event the event
114     * @return the typed Ametys object or null if not found or not of the parameterized type
115     */
116    private T _getAmetysObject(Event event)
117    {
118        String ametysObjectId = (String) event.getArguments().get(ObservationConstants.ARGS_AMETYS_OBJECT_ID);
119        AmetysObject ametysObject = _resolver.resolveById(ametysObjectId);
120        return _type.isInstance(ametysObject) ? _type.cast(ametysObject) : null;
121    }
122}