001/*
002 * (C) Copyright 2014 Nuxeo SA (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-2.1.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 *     Anahide Tchertchian
016 */
017package org.nuxeo.ecm.platform.ui.web.directory;
018
019import java.io.Serializable;
020import java.util.ArrayList;
021import java.util.Collection;
022import java.util.HashMap;
023import java.util.List;
024import java.util.Map;
025
026import javax.el.PropertyNotFoundException;
027import javax.faces.model.ListDataModel;
028import javax.faces.model.SelectItem;
029
030import org.apache.commons.lang.StringUtils;
031import org.apache.commons.logging.Log;
032import org.apache.commons.logging.LogFactory;
033import org.nuxeo.ecm.core.api.DocumentModel;
034import org.nuxeo.ecm.core.api.DocumentModelList;
035import org.nuxeo.ecm.directory.DirectoryException;
036import org.nuxeo.ecm.directory.Session;
037import org.nuxeo.ecm.platform.ui.web.component.SelectItemsFactory;
038import org.nuxeo.ecm.platform.ui.web.component.VariableManager;
039
040/**
041 * @since 6.0
042 */
043public abstract class DirectorySelectItemsFactory extends SelectItemsFactory {
044
045    private static final Log log = LogFactory.getLog(DirectorySelectItemsFactory.class);
046
047    @Override
048    protected abstract String getVar();
049
050    protected abstract String getDirectoryName();
051
052    protected abstract String getFilter();
053
054    protected abstract boolean isDisplayObsoleteEntries();
055
056    protected abstract DirectorySelectItem createSelectItem(String label, Long ordering);
057
058    protected abstract String[] retrieveSelectEntryId();
059
060    protected abstract Object retrieveItemLabel();
061
062    protected abstract String retrieveLabelFromEntry(DocumentModel directoryEntry);
063
064    protected abstract Long retrieveOrderingFromEntry(DocumentModel directoryEntry);
065
066    @SuppressWarnings({ "unchecked", "rawtypes" })
067    public List<DirectorySelectItem> createDirectorySelectItems(Object value, String separator) {
068        Object varValue = saveRequestMapVarValue();
069        try {
070            // build select items
071            List<DirectorySelectItem> items = new ArrayList<DirectorySelectItem>();
072            String dirName = getDirectoryName();
073            if (StringUtils.isBlank(dirName)) {
074                items.add(new DirectorySelectItem("", "ERROR: mising directoryName property "
075                        + "configuration on widget"));
076            } else {
077                try (Session directorySession = DirectorySelectItemFactory.getDirectorySession(dirName)) {
078                    if (directorySession != null) {
079                        if (value instanceof ListDataModel) {
080                            ListDataModel ldm = (ListDataModel) value;
081                            List<Object> entries = (List) ldm.getWrappedData();
082                            for (Object entry : entries) {
083                                DirectorySelectItem res = createSelectItemFrom(directorySession, separator, entry);
084                                if (res != null) {
085                                    items.add(res);
086                                }
087                            }
088                        } else if (value instanceof Collection) {
089                            Collection<Object> collection = (Collection<Object>) value;
090                            for (Object entry : collection) {
091                                DirectorySelectItem res = createSelectItemFrom(directorySession, separator, entry);
092                                if (res != null) {
093                                    items.add(res);
094                                }
095                            }
096                        } else if (value instanceof Object[]) {
097                            Object[] entries = (Object[]) value;
098                            for (Object entry : entries) {
099                                DirectorySelectItem res = createSelectItemFrom(directorySession, separator, entry);
100                                if (res != null) {
101                                    items.add(res);
102                                }
103                            }
104                        }
105                    } else {
106                        items.add(new DirectorySelectItem("", String.format(
107                                "ERROR: mising directorySession for directory '%s'", dirName)));
108                    }
109                }
110            }
111            return items;
112        } finally {
113            restoreRequestMapVarValue(varValue);
114        }
115    }
116
117    @SuppressWarnings("boxing")
118    public List<DirectorySelectItem> createAllDirectorySelectItems() {
119        return createAllDirectorySelectItems(ChainSelect.DEFAULT_KEY_SEPARATOR);
120    }
121
122    /**
123     * @since 7.3
124     */
125    @SuppressWarnings("boxing")
126    public List<DirectorySelectItem> createAllDirectorySelectItems(String separator) {
127        Object varValue = saveRequestMapVarValue();
128        try {
129            List<DirectorySelectItem> items = new ArrayList<DirectorySelectItem>();
130            try (Session directorySession = DirectorySelectItemFactory.getDirectorySession(getDirectoryName())) {
131                if (directorySession != null) {
132                    Map<String, Serializable> filter = new HashMap<String, Serializable>();
133                    if (!isDisplayObsoleteEntries()) {
134                        filter.put("obsolete", 0);
135                    }
136                    if (getFilter() != null) {
137                        filter.put("parentFilter", getFilter());
138                    }
139                    DocumentModelList entries = directorySession.query(filter);
140                    for (DocumentModel entry : entries) {
141                        if (entry != null) {
142                            List<DocumentModel> entryL = new ArrayList<DocumentModel>();
143                            entryL.add(entry);
144                            DirectorySelectItem res = createSelectItemForEntry(entry, separator, entry);
145                            if (res != null) {
146                                items.add(res);
147                            }
148                        }
149                    }
150                } else {
151                    log.error("No session provided for directory, returning empty selection");
152                }
153            }
154            return items;
155        } finally {
156            restoreRequestMapVarValue(varValue);
157        }
158    }
159
160    protected String[] retrieveEntryIdFrom(Object item) {
161        Object varValue = saveRequestMapVarValue();
162        try {
163            putIteratorToRequestParam(item);
164            String[] id = retrieveSelectEntryId();
165            removeIteratorFromRequestParam();
166            return id;
167        } finally {
168            restoreRequestMapVarValue(varValue);
169        }
170    }
171
172    protected DirectorySelectItem createSelectItemForEntry(Object itemValue, DocumentModel ... entries) {
173        return createSelectItemForEntry(itemValue, ChainSelect.DEFAULT_KEY_SEPARATOR, entries);
174    }
175
176    /**
177     * @since 7.4
178     */
179    protected DirectorySelectItem createSelectItemForEntry(Object itemValue, String separator, DocumentModel ... entries) {
180        return createSelectItemForEntry(itemValue, separator, null, entries);
181    }
182
183    /**
184     * @since 7.3
185     */
186    protected DirectorySelectItem createSelectItemForEntry(Object itemValue, String separator, String[] defaultLabels, DocumentModel ... entries) {
187        if (defaultLabels != null && (entries.length != defaultLabels.length)) {
188            throw new IllegalArgumentException("entryIds  must be the same size that entries");
189        }
190        String var = getVar();
191        String varEntry = var + "Entry";
192        Object varEntryExisting = VariableManager.saveRequestMapVarValue(varEntry);
193
194        DirectorySelectItem selectItem = null;
195        try {
196            VariableManager.putVariableToRequestParam(var, itemValue);
197            VariableManager.putVariableToRequestParam(varEntry, entries[entries.length - 1]);
198            String label = "";
199            for (int i = 0; i < entries.length; i++) {
200                final DocumentModel entry = entries[i];
201                if (label.length() != 0) {
202                    label += separator;
203                }
204                if (entry == null && defaultLabels != null) {
205                    label += defaultLabels[i];
206                } else {
207                    label += retrieveLabelFromEntry(entry);
208                }
209            }
210            Long ordering = retrieveOrderingFromEntry(entries[entries.length - 1]);
211            selectItem = createSelectItem(label, ordering);
212            removeIteratorFromRequestParam();
213            VariableManager.removeVariableFromRequestParam(var);
214            VariableManager.removeVariableFromRequestParam(varEntry);
215            if (selectItem != null) {
216                return selectItem;
217            } else if (itemValue instanceof DirectorySelectItem) {
218                // maybe lookup was not necessary
219                return (DirectorySelectItem) itemValue;
220            }
221            return selectItem;
222        } catch (PropertyNotFoundException e) {
223            if (itemValue instanceof DirectorySelectItem) {
224                // maybe lookup was not necessary
225                return (DirectorySelectItem) itemValue;
226            } else {
227                throw e;
228            }
229        } finally {
230            VariableManager.restoreRequestMapVarValue(varEntry, varEntryExisting);
231        }
232
233    }
234
235    protected DirectorySelectItem createSelectItemFrom(Session session, Object entry) {
236        return createSelectItemFrom(session, ChainSelect.DEFAULT_KEY_SEPARATOR, entry);
237    }
238
239    /**
240     * @since 7.3
241     */
242    protected DirectorySelectItem createSelectItemFrom(Session session, String separator, Object entry) {
243        String[] entryIds;
244        if (entry instanceof String) {
245            entryIds = new String[] {(String) entry};
246        } else {
247            // first resolve entry id to be able to lookup
248            // corresponding doc entry
249            entryIds = retrieveEntryIdFrom(entry);
250        }
251        if (entryIds == null || entryIds.length == 0) {
252            return null;
253        }
254        try {
255            DocumentModel[] docEntries = new DocumentModel[entryIds.length];
256            int i = 0;
257            for (String entryId : entryIds) {
258                DocumentModel docEntry = session.getEntry(entryId);
259                docEntries[i] = docEntry;
260                i++;
261            }
262            if (docEntries == null || docEntries.length == 0) {
263                putIteratorToRequestParam(entry);
264                Object labelObject = retrieveItemLabel();
265                String label = labelObject == null ? null : String.valueOf(labelObject);
266                if (StringUtils.isBlank(label) && entry != null) {
267                    label = entry.toString();
268                }
269                DirectorySelectItem item = createSelectItem(label, Long.valueOf(0L));
270                removeIteratorFromRequestParam();
271                return item;
272            }
273            return createSelectItemForEntry(entry, separator, entryIds, docEntries);
274        } catch (DirectoryException e) {
275        }
276        return null;
277    }
278
279    @Override
280    public SelectItem createSelectItem() {
281        throw new IllegalArgumentException("Use createSelectDirectoryItems instead");
282    }
283
284}