001/*
002 *  Copyright 2023 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.workspaces.initialization;
017
018import java.io.InputStream;
019import java.util.HashMap;
020import java.util.Map;
021import java.util.Optional;
022
023import org.apache.avalon.framework.configuration.Configurable;
024import org.apache.avalon.framework.configuration.Configuration;
025import org.apache.avalon.framework.configuration.ConfigurationException;
026import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.avalon.framework.service.Serviceable;
030import org.apache.commons.lang3.StringUtils;
031import org.apache.excalibur.source.Source;
032
033import org.ametys.core.observation.ObservationManager;
034import org.ametys.core.user.CurrentUserProvider;
035import org.ametys.core.util.filereloader.FileReloader;
036import org.ametys.core.util.filereloader.FileReloaderUtils;
037import org.ametys.plugins.workspaces.PagePopulator;
038import org.ametys.runtime.plugin.component.AbstractLogEnabled;
039import org.ametys.web.repository.page.ModifiableSitemapElement;
040import org.ametys.web.repository.page.Page;
041
042/**
043 * Implementation of {@link PageInitializer} using a configuration to define the page and its content.
044 * 
045 * By default, priority is set to 100
046 */
047public class DefaultStaticPageInitializer extends AbstractLogEnabled implements PageInitializer, Configurable, Serviceable
048{
049    /** the current user provider */
050    protected CurrentUserProvider _currentUserProvider;
051    /** the observation manager */
052    protected ObservationManager _observationManager;
053
054    private PagePopulator _pagePopulator;
055    private Map<String, Configuration> _pageModels = new HashMap<>();
056    private int _priority;
057    private String _path;
058    private FileReloaderUtils _fileReloader;
059
060    public void configure(Configuration configuration) throws ConfigurationException
061    {
062        _path = configuration.getChild("model").getAttribute("path");
063        _priority = configuration.getChild("priority", true).getValueAsInteger(100);
064    }
065
066    public void service(ServiceManager manager) throws ServiceException
067    {
068        _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE);
069        _observationManager = (ObservationManager) manager.lookup(ObservationManager.ROLE);
070        _pagePopulator = (PagePopulator) manager.lookup(PagePopulator.ROLE);
071        _fileReloader = (FileReloaderUtils) manager.lookup(FileReloaderUtils.ROLE);
072    }
073    
074    public int getPriority()
075    {
076        return _priority;
077    }
078    
079    public Optional<? extends Page> createPage(ModifiableSitemapElement parent)
080    {
081        Configuration model = _loadPageModel(parent.getSite().getSkinId());
082        // null if the skin has no model for the given path
083        if (model != null)
084        {
085            try
086            {
087                return _pagePopulator.initPage(parent, model);
088            }
089            catch (ConfigurationException e)
090            {
091                getLogger().error("An error occurred during the page initialization because the configuration was invalid.", e);
092            }
093            catch (Exception e)
094            {
095                getLogger().error("An unexpected error occurred during the page initialization.", e);
096            }
097        }
098        return Optional.empty();
099    }
100
101    private Configuration _loadPageModel(String skinId)
102    {
103        try
104        {
105            String skinPath = StringUtils.replace(_path, "{skinId}", skinId);
106            _fileReloader.updateFile(skinPath, new PageModelReloader(skinPath, this));
107            
108            // The reloader is in charge of storing and updating the model
109            return _pageModels.get(skinPath);
110        }
111        catch (Exception e)
112        {
113            throw new IllegalStateException("No configuration found at path '" + _path + "' for skin '" + skinId + "'.", e);
114        }
115    }
116
117    /**
118     * Store the page model located at a given path
119     * @param path the path to retrieve the model
120     * @param cfg the page model
121     */
122    public void setModel(String path, Configuration cfg)
123    {
124        _pageModels.put(path, cfg);
125    }
126    
127    /**
128     *  File reloader for the page model configuration
129     * @param path the file path.
130     * @param initializer the initializer component
131     */
132    protected static record PageModelReloader(String path, DefaultStaticPageInitializer initializer) implements FileReloader {
133        public void updateFile(String sourceUrl, Source source, InputStream is) throws Exception
134        {
135            if (is != null)
136            {
137                initializer.setModel(path, new DefaultConfigurationBuilder().build(is, source.getURI()));
138            }
139        }
140
141        public String getId(String sourceUrl)
142        {
143            return PageModelReloader.class.getName() + "#" + path;
144        }
145    }
146
147}