001/*
002 * (C) Copyright 2006-2015 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo - initial API and implementation
016 *
017 */
018
019package org.nuxeo.ecm.directory;
020
021import java.util.ArrayList;
022import java.util.Collection;
023import java.util.Collections;
024import java.util.HashMap;
025import java.util.List;
026import java.util.Map;
027
028import org.nuxeo.ecm.core.api.DocumentModel;
029import org.nuxeo.ecm.core.api.DocumentModelComparator;
030import org.nuxeo.runtime.metrics.MetricsService;
031
032import com.codahale.metrics.Counter;
033import com.codahale.metrics.MetricRegistry;
034import com.codahale.metrics.SharedMetricRegistries;
035
036public abstract class AbstractDirectory implements Directory {
037
038    public final String name;
039
040    protected DirectoryFieldMapper fieldMapper;
041
042    protected final Map<String, List<Reference>> references = new HashMap<>();
043
044    // simple cache system for entry lookups, disabled by default
045    protected final DirectoryCache cache;
046
047    // @since 5.7
048    protected final MetricRegistry registry = SharedMetricRegistries.getOrCreate(MetricsService.class.getName());
049
050    protected final Counter sessionCount;
051
052    protected final Counter sessionMaxCount;
053
054    protected AbstractDirectory(String name) {
055        this.name = name;
056        cache = new DirectoryCache(name);
057        sessionCount = registry.counter(MetricRegistry.name("nuxeo", "directories", name, "sessions", "active"));
058
059        sessionMaxCount = registry.counter(MetricRegistry.name("nuxeo", "directories", name, "sessions", "max"));
060    }
061
062    /**
063     * Invalidate my cache and the caches of linked directories by references.
064     */
065    public void invalidateCaches() throws DirectoryException {
066        cache.invalidateAll();
067        for (Reference ref : getReferences()) {
068            Directory targetDir = ref.getTargetDirectory();
069            if (targetDir != null) {
070                targetDir.invalidateDirectoryCache();
071            }
072        }
073    }
074
075    public DirectoryFieldMapper getFieldMapper() {
076        if (fieldMapper == null) {
077            fieldMapper = new DirectoryFieldMapper();
078        }
079        return fieldMapper;
080    }
081
082    @Deprecated
083    @Override
084    public Reference getReference(String referenceFieldName) {
085        List<Reference> refs = getReferences(referenceFieldName);
086        if (refs == null || refs.isEmpty()) {
087            return null;
088        } else if (refs.size() == 1) {
089            return refs.get(0);
090        } else {
091            throw new DirectoryException("Unexpected multiple references for " + referenceFieldName + " in directory "
092                    + getName());
093        }
094    }
095
096    @Override
097    public List<Reference> getReferences(String referenceFieldName) {
098        return references.get(referenceFieldName);
099    }
100
101    public boolean isReference(String referenceFieldName) {
102        return references.containsKey(referenceFieldName);
103    }
104
105    public void addReference(Reference reference) {
106        reference.setSourceDirectoryName(getName());
107        String fieldName = reference.getFieldName();
108        List<Reference> fieldRefs;
109        if (references.containsKey(fieldName)) {
110            fieldRefs = references.get(fieldName);
111        } else {
112            references.put(fieldName, fieldRefs = new ArrayList<>(1));
113        }
114        fieldRefs.add(reference);
115    }
116
117    public void addReferences(Reference[] refs) {
118        for (Reference reference : refs) {
119            addReference(reference);
120        }
121    }
122
123    @Override
124    public Collection<Reference> getReferences() {
125        List<Reference> allRefs = new ArrayList<>(2);
126        for (List<Reference> refs : references.values()) {
127            allRefs.addAll(refs);
128        }
129        return allRefs;
130    }
131
132    /**
133     * Helper method to order entries.
134     *
135     * @param entries the list of entries.
136     * @param orderBy an ordered map of field name -> "asc" or "desc".
137     */
138    public void orderEntries(List<DocumentModel> entries, Map<String, String> orderBy) throws DirectoryException {
139        Collections.sort(entries, new DocumentModelComparator(getSchema(), orderBy));
140    }
141
142    @Override
143    public DirectoryCache getCache() {
144        return cache;
145    }
146
147    public void removeSession(Session session) {
148        sessionCount.dec();
149    }
150
151    public void addSession(Session session) {
152        sessionCount.inc();
153        if (sessionCount.getCount() > sessionMaxCount.getCount()) {
154            sessionMaxCount.inc();
155        }
156    }
157
158    @Override
159    public void invalidateDirectoryCache() throws DirectoryException {
160        getCache().invalidateAll();
161    }
162
163    @Override
164    public boolean isMultiTenant() {
165        return false;
166    }
167
168    @Override
169    public void shutdown() {
170        sessionCount.dec(sessionCount.getCount());
171        sessionMaxCount.dec(sessionMaxCount.getCount());
172    }
173
174}