001/*
002 *  Copyright 2013 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.search.ui.model;
017
018import java.io.File;
019import java.io.FileInputStream;
020import java.io.InputStream;
021import java.util.HashSet;
022import java.util.Set;
023
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.Constants;
031import org.apache.cocoon.environment.Context;
032
033import org.ametys.cms.contenttype.ContentType;
034import org.ametys.cms.contenttype.ContentTypeExtensionPoint;
035import org.ametys.runtime.plugin.Feature;
036import org.ametys.runtime.plugin.Plugin;
037import org.ametys.runtime.plugin.component.AbstractThreadSafeComponentExtensionPoint;
038
039/**
040 * Extension point for {@link SearchUIModel}s.
041 */
042public class SearchUIModelExtensionPoint extends AbstractThreadSafeComponentExtensionPoint<SearchUIModel>
043{
044    /** The component role */
045    public static final String ROLE = SearchUIModelExtensionPoint.class.getName();
046    
047    private ContentTypeExtensionPoint _cTypeEP;
048    
049    private Set<String> _filesLoaded;
050    
051    /**
052     * Create the instance
053     */
054    public SearchUIModelExtensionPoint()
055    {
056        super();
057        _filesLoaded = new HashSet<>();
058    }
059    
060    @Override
061    public void service(ServiceManager manager) throws ServiceException
062    {
063        super.service(manager);
064        _cTypeEP = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE);
065    }
066    
067    @Override
068    public void addExtension(String id, String pluginName, String featureName, Configuration configuration) throws ConfigurationException
069    {
070        if (_filesLoaded.contains(id))
071        {
072            getLogger().warn("The search model extension '" + id + "' from feature '" + pluginName + "/" + featureName + "' will be ignored. It has already been loaded from the file in WEB-INF/param/search/" + id.substring("search-ui.".length()) + ".xml");
073        }
074        else
075        {
076            super.addExtension(id, pluginName, featureName, configuration);
077        }
078    }
079    
080    @Override
081    public void initialize() throws Exception
082    {
083        super.initialize();
084        
085        try
086        {
087            Context ctx = (Context) _context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
088            
089            File root = new File(ctx.getRealPath("/WEB-INF/param/search"));
090            
091            if (root.exists())
092            {
093                File[] files = root.listFiles(file -> !file.isDirectory() && file.getName().endsWith(".xml"));
094                
095                for (File modelFile : files)
096                {
097                    String fileName = modelFile.getName();
098                    String id = "search-ui." + fileName.substring(0, fileName.lastIndexOf('.'));
099                    _filesLoaded.add(id);
100                    
101                    if (super.hasExtension(id))
102                    {
103                        throw new IllegalArgumentException("The search tool model of id " + id + " at " + modelFile.getAbsolutePath() + " is already declared.");
104                    }
105                    
106                    try (InputStream is = new FileInputStream(modelFile))
107                    {
108                        
109                        DefaultConfiguration conf = new DefaultConfiguration("extension");
110                        
111                        Configuration c = new DefaultConfigurationBuilder(true).build(is, modelFile.toURI().toString());
112                        
113                        conf.setAttribute("id", id);
114                        conf.addChild(c);
115                        
116                        addComponent(Plugin.DEFAULT_NAME, Feature.DEFAULT_NAME, id, StaticSearchUIModel.class, conf);
117                    }
118                    catch (Exception e)
119                    {
120                        getLogger().error("Error initializing search model '" + id + "' from file '" + modelFile.getAbsolutePath() + "'.", e);
121                    }
122                }
123            }
124            
125            // TODO Provide a component to generate SearchModel corresponding to contents on the fly?
126            Set<String> cTypeIds = _cTypeEP.getExtensionsIds();
127            for (String cTypeId : cTypeIds)
128            {
129                ContentType cType = _cTypeEP.getExtension(cTypeId);
130                if (cType != null && cType.isReferenceTable())
131                {
132                    String id = "reference-table-search-ui." + cTypeId;
133                    DefaultConfiguration conf = new DefaultConfiguration("extension");
134                    conf.setAttribute("id", id);
135                    
136                    DefaultConfiguration cTypeConf = new DefaultConfiguration("contentType");
137                    cTypeConf.setValue(cTypeId);
138                    conf.addChild(cTypeConf);
139                    
140                    addComponent(Plugin.DEFAULT_NAME, Feature.DEFAULT_NAME, id, ReferenceTableSearchUIModel.class, conf);
141                }
142            }
143        }
144        catch (Exception e)
145        {
146            getLogger().error("Unable to initialize search tool models", e);
147        }
148    }
149}