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}