001/*
002 *  Copyright 2011 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.odf.inputdata;
017
018import java.io.IOException;
019import java.io.InputStream;
020import java.util.HashSet;
021import java.util.Set;
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.DefaultConfiguration;
027import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.cocoon.ProcessingException;
031import org.apache.excalibur.source.Source;
032import org.apache.excalibur.source.SourceResolver;
033import org.xml.sax.ContentHandler;
034import org.xml.sax.SAXException;
035
036import org.ametys.core.util.IgnoreRootHandler;
037import org.ametys.runtime.plugin.ExtensionPoint;
038import org.ametys.runtime.plugin.component.AbstractThreadSafeComponentExtensionPoint;
039
040/**
041 * This {@link ExtensionPoint} handles the pool of available {@link ContentInputData}.
042 */
043public class ContentInputDataExtensionPoint extends AbstractThreadSafeComponentExtensionPoint<ContentInputData> implements Configurable
044{
045    /** Avalon role */
046    public static final String ROLE = ContentInputDataExtensionPoint.class.getName();
047    
048    private SourceResolver _resolver;
049    
050    private Set<String> _inputDataRoles;
051    
052    @Override
053    public void service(ServiceManager serviceManager) throws ServiceException
054    {
055        super.service(serviceManager);
056        _resolver = (SourceResolver) serviceManager.lookup(SourceResolver.ROLE);
057    }
058    
059    @Override
060    public void configure(Configuration configuration) throws ConfigurationException
061    {
062        _inputDataRoles = new HashSet<>();
063        
064        // Replace with the default configuration variable when RUNTIME-611 is implemented.
065        Configuration conf = getExternalConfiguration();
066        
067        for (Configuration inputDataConfiguration : conf.getChildren("content-input-data"))
068        {
069            String role = inputDataConfiguration.getValue(null);
070            _inputDataRoles.add(role);
071        }
072    }
073    
074    @Override
075    public void initializeExtensions() throws Exception
076    {
077        super.initializeExtensions();
078        
079        for (String inputDataRole : _inputDataRoles)
080        {
081            ContentInputData inputData = getExtension(inputDataRole);
082            
083            if (inputData == null)
084            {
085                throw new RuntimeException("Unknown ROLE for content input data: " + inputDataRole);
086            }
087        }
088    }
089    
090    /**
091     * SAX all the input data.
092     * @param handler the content handler to SAX into.
093     * @throws SAXException if an error occurs while SAXing.
094     * @throws ProcessingException if an error occurs while processing.
095     */
096    public void toSAX(ContentHandler handler) throws SAXException, ProcessingException
097    {
098        for (String inputDataRole : _inputDataRoles)
099        {
100            ContentInputData inputData = getExtension(inputDataRole);
101            
102            inputData.toSAX(new IgnoreRootHandler(handler));
103        }
104    }
105    
106    /**
107     * Get the component configuration as a Configuration object.
108     * @return the component Configuration.
109     * @throws ConfigurationException if an error occurs
110     */
111    protected Configuration getExternalConfiguration() throws ConfigurationException
112    {
113        String configFileName = "context://WEB-INF/param/inputdata-content.xml";
114        
115        Configuration conf = new DefaultConfiguration("input-data-collection");
116        
117        Source configSource = null;
118        
119        try 
120        {
121            configSource = _resolver.resolveURI(configFileName);
122            if (configSource.exists())
123            {
124                try (InputStream configStream = configSource.getInputStream())
125                {
126                    conf = new DefaultConfigurationBuilder().build(configStream);
127                }
128            }
129            return conf;
130        }
131        catch (IOException e)
132        {
133            throw new ConfigurationException("Error trying to read the content input data configuration file.", e);
134        }
135        catch (SAXException e)
136        {
137            throw new ConfigurationException("Error trying to read the content input data configuration file.", e);
138        }
139        finally
140        {
141            _resolver.release(configSource);
142        }
143    }
144}