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