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