/*
* (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* Contributors:
* Nuxeo - initial API and implementation
*
* $Id$
*/
package org.nuxeo.ecm.platform.ui.web.directory;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.faces.context.FacesContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.common.utils.i18n.I18NUtils;
import org.nuxeo.ecm.core.api.ClientException;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.ecm.directory.DirectoryException;
import org.nuxeo.ecm.directory.Session;
import org.nuxeo.ecm.directory.api.DirectoryService;
import org.nuxeo.runtime.api.Framework;
/**
* @author <a href="mailto:glefter@nuxeo.com">George Lefter</a>
*
*/
public final class DirectoryHelper {
private static final Log log = LogFactory.getLog(DirectoryHelper.class);
/** Directory with a parent column. */
public static final String XVOCABULARY_TYPE = "xvocabulary";
public static final String[] VOCABULARY_TYPES = {"vocabulary",
XVOCABULARY_TYPE };
private static final String[] displayOptions = {"id", "label",
"idAndLabel" };
private static DirectoryHelper instance;
private static DirectoryService service;
private DirectoryHelper() {
}
public static DirectoryHelper instance() {
if (null == instance) {
instance = new DirectoryHelper();
}
return instance;
}
public boolean hasParentColumn(String directoryName) {
try {
return XVOCABULARY_TYPE.equals(getService()
.getDirectorySchema(directoryName));
} catch (DirectoryException e) {
// GR: our callers can't throw anything. Better to catch here, then
log.error("Could not retrieve schema name for directory: "
+ directoryName, e);
return false;
}
}
public DirectorySelectItem getSelectItem(String directoryName, Map<String, Serializable> filter) {
List<DirectorySelectItem> items = getSelectItems(directoryName, filter);
if (items.size() > 1) {
log.warn("More than one entry found in directory " + directoryName + " and filter:");
for (Map.Entry<String, Serializable> e: filter.entrySet()) {
log.warn(String.format("%s=%s", e.getKey(), e.getValue()));
}
} else if (items.isEmpty()) {
return null;
}
return items.get(0);
}
public List<DirectorySelectItem> getSelectItems(String directoryName,
Map<String, Serializable> filter) {
return getSelectItems(directoryName, filter, Boolean.FALSE);
}
public List<DirectorySelectItem> getSelectItems(String directoryName,
Map<String, Serializable> filter, Boolean localize) {
List<DirectorySelectItem> list = new LinkedList<DirectorySelectItem>();
Set<String> emptySet = Collections.emptySet();
Map<String, String> orderBy = new LinkedHashMap<String, String>();
FacesContext context = FacesContext.getCurrentInstance();
// an extended schema also has parent field
Session session = null;
try {
String schema = getService().getDirectorySchema(directoryName);
session = getService().open(directoryName);
if (session == null) {
throw new ClientException("could not open session on directory: "
+ directoryName);
}
// adding sorting support
// XXX It seems that this ordering is obsolete as
// DirectoryAwareComponent made it's own (NXP-7349)
if (schema.equals(VOCABULARY_TYPES[0])
|| schema.equals(VOCABULARY_TYPES[1])) {
orderBy.put("ordering", "asc");
orderBy.put("id", "asc");
}
DocumentModelList docModelList = session.query(filter, emptySet,
orderBy);
for (DocumentModel docModel : docModelList) {
String id = (String) docModel.getProperty(schema, "id");
String label = (String) docModel.getProperty(schema, "label");
long ordering = (Long)docModel.getProperty(schema, "ordering");
if (Boolean.TRUE.equals(localize)) {
label = translate(context, label);
}
DirectorySelectItem item = new DirectorySelectItem(id, label, ordering);
list.add(item);
}
} catch (ClientException e) {
throw new RuntimeException(
"failed to build option list for directory "
+ directoryName, e);
} finally {
try {
if (session != null) {
session.close();
}
} catch (ClientException ce) {
log.error("Could not close directory session", ce);
}
}
return list;
}
public static DirectoryService getDirectoryService() {
return instance().getService();
}
public static List<DirectorySelectItem> getSelectItems(
VocabularyEntryList directoryValues, Map<String, Serializable> filter) {
return getSelectItems(directoryValues, filter, Boolean.FALSE);
}
public static List<DirectorySelectItem> getSelectItems(
VocabularyEntryList directoryValues, Map<String, Serializable> filter, Boolean localize) {
List<DirectorySelectItem> list = new ArrayList<DirectorySelectItem>();
// in obsolete filter we have either null (include obsoletes)
// or 0 (don't include obsoletes)
boolean obsolete = filter.get("obsolete") == null;
String parentFilter = (String) filter.get("parent");
FacesContext context = FacesContext.getCurrentInstance();
for (VocabularyEntry entry : directoryValues.getEntries()) {
if (!obsolete && Boolean.TRUE.equals(entry.getObsolete())) {
continue;
}
String parent = entry.getParent();
if (parentFilter == null) {
if (parent != null) {
continue;
}
} else if (!parentFilter.equals(parent)) {
continue;
}
String idValue = (String) filter.get("id");
if (idValue != null && !idValue.equals(entry.getId())) {
continue;
}
String id = entry.getId();
String label = entry.getLabel();
if (Boolean.TRUE.equals(localize)) {
label = translate(context, label);
}
DirectorySelectItem item = new DirectorySelectItem(id, label);
list.add(item);
}
return list;
}
public static String getOptionValue(String optionId, String optionLabel,
String display, boolean displayIdAndLabel,
String displayIdAndLabelSeparator) {
StringBuilder displayValue = new StringBuilder();
if (display != null && !"".equals(display)) {
if (display.equals(displayOptions[0])) {
displayValue.append(optionId);
} else if (display.equals(displayOptions[1])) {
displayValue.append(optionLabel);
} else if (display.equals(displayOptions[2])) {
displayValue.append(optionId).append(displayIdAndLabelSeparator).append(
optionLabel);
} else {
displayValue.append(optionLabel);
}
} else if (displayIdAndLabel) {
displayValue.append(optionId).append(displayIdAndLabelSeparator).append(
optionLabel);
} else {
displayValue.append(optionLabel);
}
return displayValue.toString();
}
private static DocumentModel getEntryThrows(String directoryName, String entryId)
throws ClientException {
DirectoryService dirService = getDirectoryService();
if (dirService == null) {
throw new ClientException("Could not lookup DirectoryService");
}
Session session = dirService.open(directoryName);
DocumentModel entry;
try {
entry = session.getEntry(entryId);
} finally {
try {
session.close();
} catch (ClientException e) {
log.warn("Could not close a session on directory "
+ directoryName, e);
}
}
return entry;
}
/**
* Returns the entry with given id from specified directory.
* <p>
* Method to use from components, since JSF base class that we extend don't allow
* to throw proper exceptions.
*
* @param directoryName
* @param entryId
* @return the entry, or null in case of exception in callees.
*/
public static DocumentModel getEntry(String directoryName, String entryId) {
try {
return getEntryThrows(directoryName, entryId);
} catch (ClientException e) {
log.error(String.format(
"Error retrieving the entry (dirname=%s, entryId=%s)",
directoryName, entryId), e);
return null;
}
}
protected static String translate(FacesContext context, String label) {
String bundleName = context.getApplication().getMessageBundle();
Locale locale = context.getViewRoot().getLocale();
label = I18NUtils.getMessageString(bundleName, label, null, locale);
return label;
}
protected DirectoryService getService() {
if (service == null) {
DirectoryService dirService = Framework.getLocalService(DirectoryService.class);
if (dirService == null) {
try {
dirService = Framework.getService(DirectoryService.class);
} catch (Exception e) {
log.error("Can't find Directory Service", e);
}
} else {
return dirService; // don't cache local service pointer
}
service = dirService;
}
return service;
}
}