001/* 002 * (C) Copyright 2006-2007 Nuxeo SAS (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.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 * Florent Guillaume 016 * 017 * $Id: MemoryDirectorySession.java 30374 2008-02-20 16:31:28Z gracinet $ 018 */ 019 020package org.nuxeo.ecm.directory.memory; 021 022import java.io.Serializable; 023import java.util.ArrayList; 024import java.util.Collections; 025import java.util.HashMap; 026import java.util.LinkedHashMap; 027import java.util.List; 028import java.util.Map; 029import java.util.Set; 030import java.util.Map.Entry; 031 032import org.nuxeo.ecm.core.api.DataModel; 033import org.nuxeo.ecm.core.api.DocumentModel; 034import org.nuxeo.ecm.core.api.DocumentModelList; 035import org.nuxeo.ecm.core.api.PropertyException; 036import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl; 037import org.nuxeo.ecm.core.api.model.PropertyNotFoundException; 038import org.nuxeo.ecm.directory.BaseSession; 039import org.nuxeo.ecm.directory.DirectoryException; 040 041/** 042 * Trivial in-memory implementation of a Directory to use in unit tests. 043 * 044 * @author Florent Guillaume 045 */ 046public class MemoryDirectorySession extends BaseSession { 047 048 protected final MemoryDirectory directory; 049 050 protected final Map<String, Map<String, Object>> data; 051 052 public MemoryDirectorySession(MemoryDirectory directory) { 053 this.directory = directory; 054 data = Collections.synchronizedMap(new LinkedHashMap<String, Map<String, Object>>()); 055 } 056 057 public boolean authenticate(String username, String password) throws DirectoryException { 058 Map<String, Object> map = data.get(username); 059 if (map == null) { 060 return false; 061 } 062 String expected = (String) map.get(directory.passwordField); 063 if (expected == null) { 064 return false; 065 } 066 return expected.equals(password); 067 } 068 069 public void close() { 070 } 071 072 public void commit() { 073 } 074 075 public void rollback() throws DirectoryException { 076 // TODO Auto-generated method stub 077 throw new RuntimeException("Not implemented"); 078 } 079 080 public DocumentModel createEntry(Map<String, Object> fieldMap) throws DirectoryException { 081 if (isReadOnly()) { 082 return null; 083 } 084 // find id 085 Object rawId = fieldMap.get(directory.idField); 086 if (rawId == null) { 087 throw new DirectoryException("Missing id"); 088 } 089 String id = String.valueOf(rawId); 090 Map<String, Object> map = data.get(id); 091 if (map != null) { 092 throw new DirectoryException(String.format("Entry with id %s already exists", id)); 093 } 094 map = new HashMap<String, Object>(); 095 data.put(id, map); 096 // put fields in map 097 for (Entry<String, Object> e : fieldMap.entrySet()) { 098 String fieldName = e.getKey(); 099 if (!directory.schemaSet.contains(fieldName)) { 100 continue; 101 } 102 map.put(fieldName, e.getValue()); 103 } 104 return getEntry(id); 105 } 106 107 public DocumentModel getEntry(String id) throws DirectoryException { 108 return getEntry(id, true); 109 } 110 111 public DocumentModel getEntry(String id, boolean fetchReferences) throws DirectoryException { 112 // XXX no references here 113 Map<String, Object> map = data.get(id); 114 if (map == null) { 115 return null; 116 } 117 try { 118 DocumentModel entry = BaseSession.createEntryModel(null, directory.schemaName, id, map, isReadOnly()); 119 return entry; 120 } catch (PropertyException e) { 121 throw new DirectoryException(e); 122 } 123 } 124 125 public void updateEntry(DocumentModel docModel) throws DirectoryException { 126 String id = docModel.getId(); 127 DataModel dataModel = docModel.getDataModel(directory.schemaName); 128 129 Map<String, Object> map = data.get(id); 130 if (map == null) { 131 throw new DirectoryException("UpdateEntry failed: entry '" + id + "' not found"); 132 } 133 134 for (String fieldName : directory.schemaSet) { 135 try { 136 if (!dataModel.isDirty(fieldName) || fieldName.equals(directory.idField)) { 137 continue; 138 } 139 } catch (PropertyNotFoundException e) { 140 continue; 141 } 142 // TODO references 143 map.put(fieldName, dataModel.getData(fieldName)); 144 } 145 dataModel.getDirtyFields().clear(); 146 } 147 148 public DocumentModelList getEntries() throws DirectoryException { 149 DocumentModelList list = new DocumentModelListImpl(); 150 for (String id : data.keySet()) { 151 list.add(getEntry(id)); 152 } 153 return list; 154 } 155 156 public void deleteEntry(String id) throws DirectoryException { 157 data.remove(id); 158 } 159 160 // given our storage model this doesn't even make sense, as id field is 161 // unique 162 public void deleteEntry(String id, Map<String, String> map) throws DirectoryException { 163 throw new DirectoryException("Not implemented"); 164 } 165 166 public void deleteEntry(DocumentModel docModel) throws DirectoryException { 167 deleteEntry(docModel.getId()); 168 } 169 170 public String getIdField() { 171 return directory.idField; 172 } 173 174 public String getPasswordField() { 175 return directory.passwordField; 176 } 177 178 public boolean isAuthenticating() { 179 return directory.passwordField != null; 180 } 181 182 public boolean isReadOnly() { 183 return directory.isReadOnly(); 184 } 185 186 public DocumentModelList query(Map<String, Serializable> filter) throws DirectoryException { 187 return query(filter, Collections.<String> emptySet()); 188 } 189 190 public DocumentModelList query(Map<String, Serializable> filter, Set<String> fulltext) throws DirectoryException { 191 return query(filter, fulltext, Collections.<String, String> emptyMap()); 192 } 193 194 public DocumentModelList query(Map<String, Serializable> filter, Set<String> fulltext, Map<String, String> orderBy) 195 throws DirectoryException { 196 return query(filter, fulltext, orderBy, true); 197 } 198 199 public DocumentModelList query(Map<String, Serializable> filter, Set<String> fulltext, Map<String, String> orderBy, 200 boolean fetchReferences) throws DirectoryException { 201 DocumentModelList results = new DocumentModelListImpl(); 202 // canonicalize filter 203 Map<String, Object> filt = new HashMap<String, Object>(); 204 for (Entry<String, Serializable> e : filter.entrySet()) { 205 String fieldName = e.getKey(); 206 if (!directory.schemaSet.contains(fieldName)) { 207 continue; 208 } 209 filt.put(fieldName, e.getValue()); 210 } 211 // do the search 212 data_loop: for (Entry<String, Map<String, Object>> datae : data.entrySet()) { 213 String id = datae.getKey(); 214 Map<String, Object> map = datae.getValue(); 215 for (Entry<String, Object> e : filt.entrySet()) { 216 String fieldName = e.getKey(); 217 Object expected = e.getValue(); 218 Object value = map.get(fieldName); 219 if (value == null) { 220 if (expected != null) { 221 continue data_loop; 222 } 223 } else { 224 if (fulltext != null && fulltext.contains(fieldName)) { 225 if (!value.toString().toLowerCase().startsWith(expected.toString().toLowerCase())) { 226 continue data_loop; 227 } 228 } else { 229 if (!value.equals(expected)) { 230 continue data_loop; 231 } 232 } 233 } 234 } 235 // this entry matches 236 results.add(getEntry(id)); 237 } 238 // order entries 239 if (orderBy != null && !orderBy.isEmpty()) { 240 directory.orderEntries(results, orderBy); 241 } 242 return results; 243 } 244 245 public List<String> getProjection(Map<String, Serializable> filter, String columnName) throws DirectoryException { 246 return getProjection(filter, Collections.<String> emptySet(), columnName); 247 } 248 249 public List<String> getProjection(Map<String, Serializable> filter, Set<String> fulltext, String columnName) 250 throws DirectoryException { 251 DocumentModelList l = query(filter, fulltext); 252 List<String> results = new ArrayList<String>(l.size()); 253 for (DocumentModel doc : l) { 254 Object value; 255 try { 256 value = doc.getProperty(directory.schemaName, columnName); 257 } catch (PropertyException e) { 258 throw new DirectoryException(e); 259 } 260 if (value != null) { 261 results.add(value.toString()); 262 } else { 263 results.add(null); 264 } 265 } 266 return results; 267 } 268 269 public DocumentModel createEntry(DocumentModel entry) { 270 Map<String, Object> fieldMap = entry.getProperties(directory.schemaName); 271 return createEntry(fieldMap); 272 } 273 274 public boolean hasEntry(String id) { 275 return data.containsKey(id); 276 } 277 278}