001/*
002 *  Copyright 2015 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.contentstree;
017
018import java.io.InputStream;
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.HashSet;
022import java.util.Set;
023
024import org.apache.avalon.framework.configuration.Configurable;
025import org.apache.avalon.framework.configuration.Configuration;
026import org.apache.avalon.framework.configuration.ConfigurationException;
027import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.avalon.framework.service.Serviceable;
031import org.apache.commons.lang3.StringUtils;
032import org.apache.excalibur.source.Source;
033import org.apache.excalibur.source.SourceResolver;
034
035import org.ametys.cms.contenttype.ContentTypeExtensionPoint;
036import org.ametys.runtime.plugin.component.PluginAware;
037
038/**
039 * Static implementation based on configuration. See doc for template.
040 */
041public class StaticTreeConfiguration implements TreeConfiguration, Configurable, Serviceable, PluginAware
042{
043    /** The ui tool role */
044    protected String _uiToolRole;
045    /** The collection of elements */ 
046    protected Set<TreeConfigurationElements> _elements;
047    /** The content type extension point */
048    protected ContentTypeExtensionPoint _contentTypesEP;
049    /** The excalibur source resolver */
050    protected SourceResolver _sourceResolver;
051    /** The plugin name */
052    protected String _pluginName;
053    /** The extension id */
054    protected String _id;
055    
056    private Configuration _configuration;
057
058    @Override
059    public String getId()
060    {
061        return _id;
062    }
063    
064    @Override
065    public void setPluginInfo(String pluginName, String featureName, String id)
066    {
067        _pluginName = pluginName;
068    }
069    
070    @Override
071    public void service(ServiceManager manager) throws ServiceException
072    {
073        _contentTypesEP = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE);
074        _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
075    }
076    
077    @Override
078    public void configure(Configuration initialConfiguration) throws ConfigurationException
079    {
080        _id = initialConfiguration.getAttribute("id");
081        
082        _configuration = _getDeportedConfiguration(initialConfiguration);
083    }
084    
085    private void _lazyConfigure()
086    {
087        if (_configuration != null)
088        {
089            try
090            {
091                _uiToolRole = _configuration.getAttribute("id");
092                _elements = new HashSet<>();
093                
094                for (Configuration contentTypeConfiguration : _configuration.getChild("elements").getChildren("content-type"))
095                {
096                    Collection<TreeConfigurationContentType> contentTypesInfo = getContentTypesInfos(contentTypeConfiguration.getChild("ids"));
097                    Collection<TreeConfigurationElementsChild> childNodes = getChildNodes(contentTypeConfiguration.getChild("children"));
098                    
099                    TreeConfigurationElements element = new TreeConfigurationElements(contentTypesInfo, childNodes);
100                    _elements.add(element);
101                }
102                
103                _configuration = null;
104            }
105            catch (ConfigurationException e)
106            {
107                throw new IllegalStateException("An error occured while configuring tree '" + _id + "'", e);
108            }
109        }
110    }
111
112    private Configuration _getDeportedConfiguration(Configuration initialConfiguration) throws ConfigurationException
113    {
114        String treeConfigURL = initialConfiguration.getChild("tree-config").getValue();
115        Source treeConfigSource = null;
116        try
117        {
118            treeConfigSource = _sourceResolver.resolveURI(treeConfigURL, "plugin:" + _pluginName + "://", null);
119            
120            try (InputStream is = treeConfigSource.getInputStream())
121            {
122                return new DefaultConfigurationBuilder().build(is);
123            }
124        }
125        catch (Exception e)
126        {
127            throw new ConfigurationException("Cannot open the file '" + treeConfigURL + "'", initialConfiguration, e);
128        }
129        finally
130        {
131            _sourceResolver.release(treeConfigSource);
132        }
133    }
134
135    /**
136     * Get the child nodes
137     * @param configuration The configuration
138     * @return the child nodes
139     * @throws ConfigurationException if configuration is invalid
140     */
141    protected Collection<TreeConfigurationElementsChild> getChildNodes(Configuration configuration) throws ConfigurationException
142    {
143        Collection<TreeConfigurationElementsChild> childnodes = new ArrayList<>();
144        
145        for (Configuration childConfiguration : configuration.getChildren())
146        {
147            if (StringUtils.equals(childConfiguration.getName(), "metadata"))
148            {
149                String id = childConfiguration.getAttribute("id");
150                
151                TreeConfigurationElementsChild child = new AttributeTreeConfigurationElementsChild(id);
152                childnodes.add(child);
153            }
154            else
155            {
156                throw new ConfigurationException("Unknown child of type '" + childConfiguration.getName() + "'", childConfiguration); 
157            }
158        }
159        
160        return childnodes;
161    }
162
163    /**
164     * Get the contents infos using a configuration
165     * @param configuration the configuration
166     * @return the contents infos using a configuration
167     * @throws ConfigurationException if an error occurred
168     */
169    protected Collection<TreeConfigurationContentType> getContentTypesInfos(Configuration configuration) throws ConfigurationException
170    {
171        Collection<TreeConfigurationContentType> contentTypesInfo = new ArrayList<>();
172
173        boolean elementsCanBeRoot = configuration.getAttributeAsBoolean("can-be-root", false);
174        boolean elementsInherit = configuration.getAttributeAsBoolean("inherit", false);
175        String elementsBusMessageType = configuration.getAttribute("bus-message-type", "content");
176        
177        for (Configuration idConfiguration : configuration.getChildren("id"))
178        {
179            TreeConfigurationContentType contentTypeInfo = getContentTypeInfo(idConfiguration, elementsCanBeRoot, elementsInherit, elementsBusMessageType);
180            contentTypesInfo.add(contentTypeInfo);
181        }
182        
183        return contentTypesInfo;
184    }
185    
186    /**
187     * Get the content info using a configuration
188     * @param configuration The configuration
189     * @param defaultCanBeRoot default value for root property
190     * @param defaultInherit default value for inherit property
191     * @param defaultBusMessageType default type of message
192     * @return the content info using a configuration 
193     * @throws ConfigurationException if the configuration is invalid
194     */
195    protected TreeConfigurationContentType getContentTypeInfo(Configuration configuration, boolean defaultCanBeRoot, boolean defaultInherit, String defaultBusMessageType) throws ConfigurationException
196    {
197        boolean canBeRoot = configuration.getAttributeAsBoolean("can-be-root", defaultCanBeRoot);
198        String mainContentTypeId = configuration.getValue();
199        
200        Collection<String> typesIds = new ArrayList<>();
201        typesIds.add(mainContentTypeId);
202        
203        boolean inherit = configuration.getAttributeAsBoolean("inherit", defaultInherit);
204        if (inherit)
205        {
206            typesIds.addAll(_contentTypesEP.getSubTypes(mainContentTypeId));
207        }
208        
209        String busMessageType = configuration.getAttribute("bus-message-type", defaultBusMessageType);
210        
211        return new TreeConfigurationContentType(canBeRoot, typesIds, busMessageType);
212    }
213    
214    @Override
215    public String getUIToolRole()
216    {
217        _lazyConfigure();
218        return _uiToolRole;
219    }
220
221    @Override
222    public Set<TreeConfigurationElements> getElements()
223    {
224        _lazyConfigure();
225        return _elements;
226    }
227
228}