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