001/* 002 * (C) Copyright 2006-2015 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 * Nuxeo - initial API and implementation 018 * 019 */ 020 021package org.nuxeo.ecm.directory; 022 023import java.util.ArrayList; 024import java.util.Collection; 025import java.util.Collections; 026import java.util.HashMap; 027import java.util.List; 028import java.util.Map; 029 030import org.apache.commons.lang.StringUtils; 031import org.nuxeo.ecm.core.api.DocumentModel; 032import org.nuxeo.ecm.core.api.DocumentModelComparator; 033import org.nuxeo.runtime.metrics.MetricsService; 034 035import com.codahale.metrics.Counter; 036import com.codahale.metrics.MetricRegistry; 037import com.codahale.metrics.SharedMetricRegistries; 038 039public abstract class AbstractDirectory implements Directory { 040 041 public final BaseDirectoryDescriptor descriptor; 042 043 protected DirectoryFieldMapper fieldMapper; 044 045 protected final Map<String, List<Reference>> references = new HashMap<>(); 046 047 // simple cache system for entry lookups, disabled by default 048 protected final DirectoryCache cache; 049 050 // @since 5.7 051 protected final MetricRegistry registry = SharedMetricRegistries.getOrCreate(MetricsService.class.getName()); 052 053 protected final Counter sessionCount; 054 055 protected final Counter sessionMaxCount; 056 057 protected AbstractDirectory(BaseDirectoryDescriptor descriptor) { 058 this.descriptor = descriptor; 059 if (!descriptor.template && doSanityChecks()) { 060 if (StringUtils.isEmpty(descriptor.idField)) { 061 throw new DirectoryException("idField configuration is missing for directory: " + getName()); 062 } 063 if (StringUtils.isEmpty(descriptor.schemaName)) { 064 throw new DirectoryException("schema configuration is missing for directory " + getName()); 065 } 066 } 067 cache = new DirectoryCache(getName()); 068 sessionCount = registry.counter(MetricRegistry.name("nuxeo", "directories", getName(), "sessions", "active")); 069 sessionMaxCount = registry.counter(MetricRegistry.name("nuxeo", "directories", getName(), "sessions", "max")); 070 } 071 072 protected boolean doSanityChecks() { 073 return true; 074 } 075 076 /** To be implemented with a more specific return type. */ 077 public abstract BaseDirectoryDescriptor getDescriptor(); 078 079 @Override 080 public String getName() { 081 return descriptor.name; 082 } 083 084 @Override 085 public String getSchema() { 086 return descriptor.schemaName; 087 } 088 089 @Override 090 public String getParentDirectory() { 091 return descriptor.parentDirectory; 092 } 093 094 @Override 095 public String getIdField() { 096 return descriptor.idField; 097 } 098 099 @Override 100 public String getPasswordField() { 101 return descriptor.passwordField; 102 } 103 104 @Override 105 public boolean isReadOnly() { 106 return descriptor.isReadOnly(); 107 } 108 109 public void setReadOnly(boolean readOnly) { 110 descriptor.setReadOnly(readOnly); 111 } 112 113 /** 114 * Invalidate my cache and the caches of linked directories by references. 115 */ 116 public void invalidateCaches() throws DirectoryException { 117 cache.invalidateAll(); 118 for (Reference ref : getReferences()) { 119 Directory targetDir = ref.getTargetDirectory(); 120 if (targetDir != null) { 121 targetDir.invalidateDirectoryCache(); 122 } 123 } 124 } 125 126 public DirectoryFieldMapper getFieldMapper() { 127 if (fieldMapper == null) { 128 fieldMapper = new DirectoryFieldMapper(); 129 } 130 return fieldMapper; 131 } 132 133 @Deprecated 134 @Override 135 public Reference getReference(String referenceFieldName) { 136 List<Reference> refs = getReferences(referenceFieldName); 137 if (refs == null || refs.isEmpty()) { 138 return null; 139 } else if (refs.size() == 1) { 140 return refs.get(0); 141 } else { 142 throw new DirectoryException("Unexpected multiple references for " + referenceFieldName + " in directory " 143 + getName()); 144 } 145 } 146 147 @Override 148 public List<Reference> getReferences(String referenceFieldName) { 149 return references.get(referenceFieldName); 150 } 151 152 public boolean isReference(String referenceFieldName) { 153 return references.containsKey(referenceFieldName); 154 } 155 156 public void addReference(Reference reference) { 157 reference.setSourceDirectoryName(getName()); 158 String fieldName = reference.getFieldName(); 159 List<Reference> fieldRefs; 160 if (references.containsKey(fieldName)) { 161 fieldRefs = references.get(fieldName); 162 } else { 163 references.put(fieldName, fieldRefs = new ArrayList<>(1)); 164 } 165 fieldRefs.add(reference); 166 } 167 168 public void addReferences(Reference[] refs) { 169 for (Reference reference : refs) { 170 addReference(reference); 171 } 172 } 173 174 @Override 175 public Collection<Reference> getReferences() { 176 List<Reference> allRefs = new ArrayList<>(2); 177 for (List<Reference> refs : references.values()) { 178 allRefs.addAll(refs); 179 } 180 return allRefs; 181 } 182 183 /** 184 * Helper method to order entries. 185 * 186 * @param entries the list of entries. 187 * @param orderBy an ordered map of field name -> "asc" or "desc". 188 */ 189 public void orderEntries(List<DocumentModel> entries, Map<String, String> orderBy) throws DirectoryException { 190 Collections.sort(entries, new DocumentModelComparator(getSchema(), orderBy)); 191 } 192 193 @Override 194 public DirectoryCache getCache() { 195 return cache; 196 } 197 198 public void removeSession(Session session) { 199 sessionCount.dec(); 200 } 201 202 public void addSession(Session session) { 203 sessionCount.inc(); 204 if (sessionCount.getCount() > sessionMaxCount.getCount()) { 205 sessionMaxCount.inc(); 206 } 207 } 208 209 @Override 210 public void invalidateDirectoryCache() throws DirectoryException { 211 getCache().invalidateAll(); 212 } 213 214 @Override 215 public boolean isMultiTenant() { 216 return false; 217 } 218 219 @Override 220 public void shutdown() { 221 sessionCount.dec(sessionCount.getCount()); 222 sessionMaxCount.dec(sessionMaxCount.getCount()); 223 } 224 225}