001/* 002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others. 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 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.ecm.webapp.tree; 023 024import java.util.HashMap; 025import java.util.List; 026import java.util.Map; 027 028import org.apache.commons.logging.Log; 029import org.apache.commons.logging.LogFactory; 030import org.nuxeo.ecm.core.api.DocumentModel; 031import org.nuxeo.ecm.core.api.Filter; 032import org.nuxeo.ecm.core.api.Sorter; 033import org.nuxeo.ecm.core.api.tree.DefaultDocumentTreeFilter; 034import org.nuxeo.ecm.core.api.tree.DefaultDocumentTreeSorter; 035import org.nuxeo.ecm.core.api.tree.DocumentTreeFilter; 036import org.nuxeo.ecm.core.api.tree.DocumentTreeSorter; 037import org.nuxeo.runtime.model.ComponentContext; 038import org.nuxeo.runtime.model.ComponentInstance; 039import org.nuxeo.runtime.model.DefaultComponent; 040 041/** 042 * Component for tree service, handing registries for trees managing {@link DocumentModel} object. 043 * 044 * @author Anahide Tchertchian 045 */ 046// TODO: refactor to use only one registry 047public class TreeManagerImpl extends DefaultComponent implements TreeManager { 048 049 private static final long serialVersionUID = 1L; 050 051 public static final String NAME = TreeManager.class.getName(); 052 053 public static final String PLUGIN_EXTENSION_POINT = "plugin"; 054 055 private static final Log log = LogFactory.getLog(TreeManager.class); 056 057 protected Map<String, Filter> filters; 058 059 protected Map<String, Filter> leafFilters; 060 061 protected Map<String, Sorter> sorters; 062 063 protected Map<String, String> pageProviderNames; 064 065 @SuppressWarnings("unchecked") 066 @Override 067 public <T> T getAdapter(Class<T> adapter) { 068 if (adapter.isAssignableFrom(TreeManager.class)) { 069 return (T) this; 070 } 071 return null; 072 } 073 074 @Override 075 public void activate(ComponentContext context) { 076 super.activate(context); 077 filters = new HashMap<String, Filter>(); 078 leafFilters = new HashMap<String, Filter>(); 079 sorters = new HashMap<String, Sorter>(); 080 pageProviderNames = new HashMap<String, String>(); 081 } 082 083 @Override 084 public void deactivate(ComponentContext context) { 085 filters = null; 086 leafFilters = null; 087 sorters = null; 088 pageProviderNames = null; 089 super.deactivate(context); 090 } 091 092 @Override 093 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 094 if (PLUGIN_EXTENSION_POINT.equals(extensionPoint)) { 095 TreeManagerPluginDescriptor plugin = (TreeManagerPluginDescriptor) contribution; 096 String name = plugin.getName(); 097 // filter 098 if (filters.containsKey(name)) { 099 // FIXME handle merge? 100 log.info("Overriding filter for plugin " + name); 101 filters.remove(name); 102 } 103 log.info("Registering filter for plugin " + name); 104 filters.put(name, buildFilter(plugin)); 105 // leaf filter 106 if (leafFilters.containsKey(name)) { 107 // FIXME handle merge? 108 log.info("Overriding leaf filter for plugin " + name); 109 leafFilters.remove(name); 110 } 111 log.info("Registering leaf filter for plugin " + name); 112 leafFilters.put(name, buildLeafFilter(plugin)); 113 // sorter 114 if (sorters.containsKey(name)) { 115 // FIXME handle merge? 116 log.info("Overriding sorter for plugin " + name); 117 sorters.remove(name); 118 } 119 log.info("Registering sorter for plugin " + name); 120 sorters.put(name, buildSorter(plugin)); 121 122 // page provider 123 if (pageProviderNames.containsKey(name)) { 124 // FIXME handle merge? 125 log.info("Overriding page provider for plugin " + name); 126 pageProviderNames.remove(name); 127 } 128 log.info("Registering page provider for plugin " + name); 129 pageProviderNames.put(name, plugin.getPageProvider()); 130 } 131 } 132 133 @Override 134 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 135 if (PLUGIN_EXTENSION_POINT.equals(extensionPoint)) { 136 TreeManagerPluginDescriptor plugin = (TreeManagerPluginDescriptor) contribution; 137 String name = plugin.getName(); 138 // filter 139 if (filters.containsKey(name)) { 140 log.info("Unregistering filter for plugin " + name); 141 filters.remove(name); 142 } 143 // leaf filter 144 if (leafFilters.containsKey(name)) { 145 log.info("Unregistering leaf filter for plugin " + name); 146 leafFilters.remove(name); 147 } 148 // sorter 149 if (sorters.containsKey(name)) { 150 log.info("Unregistering sorter for plugin " + name); 151 sorters.remove(name); 152 } 153 // page provider 154 if (pageProviderNames.containsKey(name)) { 155 log.info("Unregistering page provider for plugin " + name); 156 pageProviderNames.remove(name); 157 } 158 } 159 } 160 161 protected Filter buildFilter(TreeManagerPluginDescriptor plugin) { 162 Filter filter = null; 163 164 List<String> includedFacets = plugin.getIncludedFacets(); 165 List<String> excludedFacets = plugin.getExcludedFacets(); 166 List<String> excludedTypes = plugin.getExcludedTypes(); 167 168 String filterClass = plugin.getFilterClassName(); 169 if (filterClass == null || "".equals(filterClass)) { 170 if ((includedFacets == null || includedFacets.isEmpty()) 171 && (excludedFacets == null || excludedFacets.isEmpty()) 172 && (excludedTypes == null || excludedTypes.isEmpty())) { 173 return null; 174 } 175 // built-in filter 176 filter = new DefaultDocumentTreeFilter(); 177 } else { 178 // custom filter 179 try { 180 Object instance = TreeManagerImpl.class.getClassLoader().loadClass(filterClass).newInstance(); 181 if (instance instanceof Filter) { 182 filter = (Filter) instance; 183 } else { 184 log.error(String.format("Class %s should follow %s interface", filterClass, Filter.class.getName())); 185 } 186 } catch (ReflectiveOperationException e) { 187 log.error(e, e); 188 } 189 } 190 191 // setup config when possible 192 if (filter instanceof DocumentTreeFilter) { 193 DocumentTreeFilter treeFilter = (DocumentTreeFilter) filter; 194 treeFilter.setIncludedFacets(includedFacets); 195 treeFilter.setExcludedFacets(excludedFacets); 196 treeFilter.setExcludedTypes(excludedTypes); 197 } 198 199 return filter; 200 } 201 202 protected Filter buildLeafFilter(TreeManagerPluginDescriptor plugin) { 203 String leafFilterClass = plugin.getLeafFilterClassName(); 204 if (leafFilterClass == null || "".equals(leafFilterClass)) { 205 return null; 206 } 207 try { 208 Object instance = TreeManagerImpl.class.getClassLoader().loadClass(leafFilterClass).newInstance(); 209 if (instance instanceof Filter) { 210 return (Filter) instance; 211 } else { 212 log.error(String.format("Class %s should follow %s interface", leafFilterClass, Filter.class.getName())); 213 } 214 } catch (ReflectiveOperationException e) { 215 log.error(e, e); 216 } 217 return null; 218 } 219 220 protected Sorter buildSorter(TreeManagerPluginDescriptor plugin) { 221 Sorter sorter = null; 222 223 String sortPropertyPath = plugin.getSortPropertyPath(); 224 225 String sorterClass = plugin.getSorterClassName(); 226 if (sorterClass == null || "".equals(sorterClass)) { 227 if (sortPropertyPath == null || "".equals(sortPropertyPath)) { 228 return null; 229 } 230 // built-in sorter 231 sorter = new DefaultDocumentTreeSorter(); 232 } else { 233 // custom sorter 234 try { 235 Object instance = TreeManagerImpl.class.getClassLoader().loadClass(sorterClass).newInstance(); 236 if (instance instanceof Sorter) { 237 sorter = (Sorter) instance; 238 } else { 239 log.error(String.format("Class %s should follow %s interface", sorterClass, Sorter.class.getName())); 240 } 241 } catch (ReflectiveOperationException e) { 242 log.error(e, e); 243 } 244 } 245 246 // setup config when possible 247 if (sorter instanceof DocumentTreeSorter) { 248 DocumentTreeSorter treeSorter = (DocumentTreeSorter) sorter; 249 treeSorter.setSortPropertyPath(sortPropertyPath); 250 } 251 252 return sorter; 253 } 254 255 public Filter getFilter(String pluginName) { 256 return filters.get(pluginName); 257 } 258 259 public Filter getLeafFilter(String pluginName) { 260 return leafFilters.get(pluginName); 261 } 262 263 public Sorter getSorter(String pluginName) { 264 return sorters.get(pluginName); 265 } 266 267 @Override 268 public String getPageProviderName(String pluginName) { 269 return pageProviderNames.get(pluginName); 270 } 271 272}