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