/*
* (C) Copyright 2006-2015 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:
* Nuxeo - initial API and implementation
*
*/
package org.nuxeo.ecm.directory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelComparator;
import org.nuxeo.ecm.directory.api.DirectoryDeleteConstraint;
import org.nuxeo.runtime.metrics.MetricsService;
import com.codahale.metrics.Counter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.SharedMetricRegistries;
public abstract class AbstractDirectory implements Directory {
public final BaseDirectoryDescriptor descriptor;
protected DirectoryFieldMapper fieldMapper;
protected final Map<String, List<Reference>> references = new HashMap<>();
// simple cache system for entry lookups, disabled by default
protected final DirectoryCache cache;
// @since 5.7
protected final MetricRegistry registry = SharedMetricRegistries.getOrCreate(MetricsService.class.getName());
protected final Counter sessionCount;
protected final Counter sessionMaxCount;
private List<String> types = new ArrayList<String>();
protected AbstractDirectory(BaseDirectoryDescriptor descriptor) {
this.descriptor = descriptor;
// is the directory visible in the ui
if (descriptor.types != null) {
this.types = Arrays.asList(descriptor.types);
}
if (!descriptor.template && doSanityChecks()) {
if (StringUtils.isEmpty(descriptor.idField)) {
throw new DirectoryException("idField configuration is missing for directory: " + getName());
}
if (StringUtils.isEmpty(descriptor.schemaName)) {
throw new DirectoryException("schema configuration is missing for directory " + getName());
}
}
cache = new DirectoryCache(getName());
sessionCount = registry.counter(MetricRegistry.name("nuxeo", "directories", getName(), "sessions", "active"));
sessionMaxCount = registry.counter(MetricRegistry.name("nuxeo", "directories", getName(), "sessions", "max"));
}
protected boolean doSanityChecks() {
return true;
}
/** To be implemented with a more specific return type. */
public abstract BaseDirectoryDescriptor getDescriptor();
@Override
public String getName() {
return descriptor.name;
}
@Override
public String getSchema() {
return descriptor.schemaName;
}
@Override
public String getParentDirectory() {
return descriptor.parentDirectory;
}
@Override
public String getIdField() {
return descriptor.idField;
}
@Override
public String getPasswordField() {
return descriptor.passwordField;
}
@Override
public boolean isReadOnly() {
return descriptor.isReadOnly();
}
public void setReadOnly(boolean readOnly) {
descriptor.setReadOnly(readOnly);
}
/**
* Invalidate my cache and the caches of linked directories by references.
*/
public void invalidateCaches() throws DirectoryException {
cache.invalidateAll();
for (Reference ref : getReferences()) {
Directory targetDir = ref.getTargetDirectory();
if (targetDir != null) {
targetDir.invalidateDirectoryCache();
}
}
}
public DirectoryFieldMapper getFieldMapper() {
if (fieldMapper == null) {
fieldMapper = new DirectoryFieldMapper();
}
return fieldMapper;
}
@Deprecated
@Override
public Reference getReference(String referenceFieldName) {
List<Reference> refs = getReferences(referenceFieldName);
if (refs == null || refs.isEmpty()) {
return null;
} else if (refs.size() == 1) {
return refs.get(0);
} else {
throw new DirectoryException("Unexpected multiple references for " + referenceFieldName + " in directory "
+ getName());
}
}
@Override
public List<Reference> getReferences(String referenceFieldName) {
return references.get(referenceFieldName);
}
public boolean isReference(String referenceFieldName) {
return references.containsKey(referenceFieldName);
}
public void addReference(Reference reference) {
reference.setSourceDirectoryName(getName());
String fieldName = reference.getFieldName();
List<Reference> fieldRefs;
if (references.containsKey(fieldName)) {
fieldRefs = references.get(fieldName);
} else {
references.put(fieldName, fieldRefs = new ArrayList<>(1));
}
fieldRefs.add(reference);
}
public void addReferences(Reference[] refs) {
for (Reference reference : refs) {
addReference(reference);
}
}
@Override
public Collection<Reference> getReferences() {
List<Reference> allRefs = new ArrayList<>(2);
for (List<Reference> refs : references.values()) {
allRefs.addAll(refs);
}
return allRefs;
}
/**
* Helper method to order entries.
*
* @param entries the list of entries.
* @param orderBy an ordered map of field name -> "asc" or "desc".
*/
public void orderEntries(List<DocumentModel> entries, Map<String, String> orderBy) throws DirectoryException {
Collections.sort(entries, new DocumentModelComparator(getSchema(), orderBy));
}
@Override
public DirectoryCache getCache() {
return cache;
}
public void removeSession(Session session) {
sessionCount.dec();
}
public void addSession(Session session) {
sessionCount.inc();
if (sessionCount.getCount() > sessionMaxCount.getCount()) {
sessionMaxCount.inc();
}
}
@Override
public void invalidateDirectoryCache() throws DirectoryException {
getCache().invalidateAll();
}
@Override
public boolean isMultiTenant() {
return false;
}
@Override
public void shutdown() {
sessionCount.dec(sessionCount.getCount());
sessionMaxCount.dec(sessionMaxCount.getCount());
}
/**
* since @8.4
*/
@Override
public List<String> getTypes() {
return types;
}
/**
* @since 8.4
*/
@Override
public List<DirectoryDeleteConstraint> getDirectoryDeleteConstraints() {
return descriptor.getDeleteConstraints();
}
}