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}