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