/*
* (C) Copyright 2011 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Contributors:
* Anahide Tchertchian <at@nuxeo.com>
* Thomas Roger <troger@nuxeo.com>
*/
package org.nuxeo.ecm.webapp.directory;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.faces.context.FacesContext;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.core.Events;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.international.StatusMessage;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelComparator;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.ecm.core.api.NuxeoPrincipal;
import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl;
import org.nuxeo.ecm.directory.BaseSession;
import org.nuxeo.ecm.directory.DirectoryDeleteConstraintException;
import org.nuxeo.ecm.directory.Session;
import org.nuxeo.ecm.directory.api.DirectoryService;
import org.nuxeo.ecm.directory.api.DirectoryDeleteConstraint;
import org.nuxeo.ecm.directory.api.ui.DirectoryUI;
import org.nuxeo.ecm.directory.api.ui.DirectoryUIManager;
import org.nuxeo.ecm.platform.actions.ActionContext;
import org.nuxeo.ecm.platform.actions.ejb.ActionManager;
import org.nuxeo.ecm.platform.actions.jsf.JSFActionContext;
import org.nuxeo.ecm.platform.ui.web.directory.DirectoryHelper;
import org.nuxeo.ecm.platform.ui.web.util.SeamContextHelper;
import org.nuxeo.ecm.webapp.helpers.EventNames;
/**
* Manages directories editable by administrators.
*
* @author Anahide Tchertchian
*/
@Name("directoryUIActions")
@Scope(ScopeType.CONVERSATION)
public class DirectoryUIActionsBean implements Serializable {
private static final long serialVersionUID = 1L;
public static final String DIRECTORY_DEFAULT_VIEW = "view_directory";
@In(create = true)
protected transient DirectoryUIManager directoryUIManager;
// FIXME: use a business delegate
protected transient DirectoryService dirService;
@In(create = true, required = false)
protected transient FacesMessages facesMessages;
@In(create = true)
protected Map<String, String> messages;
@In(create = true, required = false)
protected transient ActionManager actionManager;
@In(create = true)
private transient NuxeoPrincipal currentNuxeoPrincipal;
protected List<String> directoryNames;
protected DirectoryUI currentDirectoryInfo;
protected DocumentModelList currentDirectoryEntries;
protected DocumentModel selectedDirectoryEntry;
protected boolean showAddForm = false;
protected DocumentModel creationDirectoryEntry;
protected String selectedDirectoryName;
@Begin(join = true)
@Create
public void initialize() {
initDirService();
}
private void initDirService() {
if (dirService == null) {
dirService = DirectoryHelper.getDirectoryService();
}
}
public List<String> getDirectoryNames() {
if (directoryNames == null) {
directoryNames = directoryUIManager.getDirectoryNames();
if (directoryNames.size() > 0) {
// preserve selected directory if present
if (selectedDirectoryName == null || !directoryNames.contains(selectedDirectoryName)) {
selectedDirectoryName = directoryNames.get(0);
}
selectDirectory();
}
}
return directoryNames;
}
public String getSelectedDirectoryName() {
return selectedDirectoryName;
}
public void setSelectedDirectoryName(String selectedDirectoryName) {
this.selectedDirectoryName = selectedDirectoryName;
}
public void selectDirectory() {
resetSelectedDirectoryData();
currentDirectoryInfo = directoryUIManager.getDirectoryInfo(selectedDirectoryName);
}
public DirectoryUI getCurrentDirectory() {
return currentDirectoryInfo;
}
public DocumentModelList getCurrentDirectoryEntries() {
if (currentDirectoryEntries == null) {
currentDirectoryEntries = new DocumentModelListImpl();
String dirName = currentDirectoryInfo.getName();
try (Session dirSession = dirService.open(dirName)) {
Map<String, Serializable> emptyMap = Collections.emptyMap();
Set<String> emptySet = Collections.emptySet();
DocumentModelList entries = dirSession.query(emptyMap, emptySet, null, true);
if (entries != null && !entries.isEmpty()) {
currentDirectoryEntries.addAll(entries);
}
// sort
String sortField = currentDirectoryInfo.getSortField();
if (sortField == null) {
sortField = dirService.getDirectoryIdField(dirName);
}
// sort
Map<String, String> orderBy = new HashMap<String, String>();
orderBy.put(sortField, DocumentModelComparator.ORDER_ASC);
Collections.sort(currentDirectoryEntries,
new DocumentModelComparator(dirService.getDirectorySchema(dirName), orderBy));
}
}
return currentDirectoryEntries;
}
public void resetSelectedDirectoryData() {
currentDirectoryInfo = null;
currentDirectoryEntries = null;
resetSelectedDirectoryEntry();
resetCreateDirectoryEntry();
}
public boolean getShowAddForm() {
return showAddForm;
}
public void toggleShowAddForm() {
showAddForm = !showAddForm;
}
public DocumentModel getCreationDirectoryEntry() {
if (creationDirectoryEntry == null) {
String dirName = currentDirectoryInfo.getName();
String schema = dirService.getDirectorySchema(dirName);
creationDirectoryEntry = BaseSession.createEntryModel(null, schema, null, null);
}
return creationDirectoryEntry;
}
public void createDirectoryEntry() {
String dirName = currentDirectoryInfo.getName();
try (Session dirSession = dirService.open(dirName)) {
// check if entry already exists
String schema = dirService.getDirectorySchema(dirName);
String idField = dirService.getDirectoryIdField(dirName);
Object id = creationDirectoryEntry.getProperty(schema, idField);
if (id instanceof String && dirSession.hasEntry((String) id)) {
facesMessages.add(StatusMessage.Severity.ERROR,
messages.get("vocabulary.entry.identifier.already.exists"));
return;
}
dirSession.createEntry(creationDirectoryEntry);
resetCreateDirectoryEntry();
// invalidate directory entries list
currentDirectoryEntries = null;
Events.instance().raiseEvent(EventNames.DIRECTORY_CHANGED, dirName);
facesMessages.add(StatusMessage.Severity.INFO, messages.get("vocabulary.entry.added"));
}
}
public void resetCreateDirectoryEntry() {
creationDirectoryEntry = null;
showAddForm = false;
}
public void selectDirectoryEntry(String entryId) {
String dirName = currentDirectoryInfo.getName();
try (Session dirSession = dirService.open(dirName)) {
selectedDirectoryEntry = dirSession.getEntry(entryId);
}
}
public DocumentModel getSelectedDirectoryEntry() {
return selectedDirectoryEntry;
}
public void resetSelectedDirectoryEntry() {
selectedDirectoryEntry = null;
}
public void editSelectedDirectoryEntry() {
String dirName = currentDirectoryInfo.getName();
try (Session dirSession = dirService.open(dirName)) {
dirSession.updateEntry(selectedDirectoryEntry);
selectedDirectoryEntry = null;
// invalidate directory entries list
currentDirectoryEntries = null;
Events.instance().raiseEvent(EventNames.DIRECTORY_CHANGED, dirName);
facesMessages.add(StatusMessage.Severity.INFO, messages.get("vocabulary.entry.edited"));
}
}
public void deleteDirectoryEntry(String entryId) {
String dirName = currentDirectoryInfo.getName();
List<DirectoryDeleteConstraint> deleteConstraints = currentDirectoryInfo.getDeleteConstraints();
if (deleteConstraints != null && !deleteConstraints.isEmpty()) {
for (DirectoryDeleteConstraint deleteConstraint : deleteConstraints) {
if (!deleteConstraint.canDelete(dirService, entryId)) {
facesMessages.add(StatusMessage.Severity.ERROR,
messages.get("feedback.directory.deleteEntry.constraintError"));
return;
}
}
}
try (Session dirSession = dirService.open(dirName)) {
try {
dirSession.deleteEntry(entryId);
// invalidate directory entries list
currentDirectoryEntries = null;
Events.instance().raiseEvent(EventNames.DIRECTORY_CHANGED, dirName);
facesMessages.add(StatusMessage.Severity.INFO, messages.get("vocabulary.entry.deleted"));
} catch (DirectoryDeleteConstraintException e) {
facesMessages.add(StatusMessage.Severity.ERROR,
messages.get("feedback.directory.deleteEntry.constraintError"));
}
}
}
public boolean isReadOnly(String directoryName) {
boolean isReadOnly;
try (Session dirSession = dirService.open(directoryName)) {
// Check Directory ReadOnly Status
boolean dirReadOnly = dirSession.isReadOnly();
// Check DirectoryUI ReadOnly Status
boolean dirUIReadOnly;
DirectoryUI dirInfo = directoryUIManager.getDirectoryInfo(directoryName);
if (dirInfo == null) {
// assume read-only
dirUIReadOnly = true;
} else {
dirUIReadOnly = Boolean.TRUE.equals(dirInfo.isReadOnly());
}
isReadOnly = dirReadOnly || dirUIReadOnly;
}
return isReadOnly;
}
protected ActionContext createDirectoryActionContext() {
return createDirectoryActionContext(selectedDirectoryName);
}
protected ActionContext createDirectoryActionContext(String directoryName) {
FacesContext faces = FacesContext.getCurrentInstance();
if (faces == null) {
throw new IllegalArgumentException("Faces context is null");
}
ActionContext ctx = new JSFActionContext(faces);
ctx.putLocalVariable("SeamContext", new SeamContextHelper());
ctx.putLocalVariable("directoryName", directoryName);
ctx.setCurrentPrincipal(currentNuxeoPrincipal);
return ctx;
}
public boolean checkContextualDirectoryFilter(String filterName) {
return actionManager.checkFilter(filterName, createDirectoryActionContext());
}
/**
* @since 5.9.1
*/
public boolean checkContextualDirectoryFilter(String filterName, String directoryName) {
return actionManager.checkFilter(filterName, createDirectoryActionContext(directoryName));
}
@Observer(value = { EventNames.FLUSH_EVENT }, create = false)
@BypassInterceptors
public void onHotReloadFlush() {
directoryNames = null;
resetSelectedDirectoryData();
}
}