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 Map<String, Map<String, Object>> data; 051 052 public MemoryDirectorySession(MemoryDirectory directory) { 053 super(directory); 054 data = Collections.synchronizedMap(new LinkedHashMap<String, Map<String, Object>>()); 055 } 056 057 /** To be implemented with a more specific type. */ 058 @Override 059 public MemoryDirectory getDirectory() { 060 return (MemoryDirectory) directory; 061 } 062 063 @Override 064 public boolean authenticate(String username, String password) throws DirectoryException { 065 Map<String, Object> map = data.get(username); 066 if (map == null) { 067 return false; 068 } 069 String expected = (String) map.get(getPasswordField()); 070 if (expected == null) { 071 return false; 072 } 073 return expected.equals(password); 074 } 075 076 @Override 077 public void close() { 078 } 079 080 public void commit() { 081 } 082 083 public void rollback() throws DirectoryException { 084 // TODO Auto-generated method stub 085 throw new RuntimeException("Not implemented"); 086 } 087 088 @Override 089 public DocumentModel createEntry(Map<String, Object> fieldMap) throws DirectoryException { 090 if (isReadOnly()) { 091 return null; 092 } 093 // find id 094 Object rawId = fieldMap.get(getIdField()); 095 if (rawId == null) { 096 throw new DirectoryException("Missing id"); 097 } 098 String id = String.valueOf(rawId); 099 Map<String, Object> map = data.get(id); 100 if (map != null) { 101 throw new DirectoryException(String.format("Entry with id %s already exists", id)); 102 } 103 map = new HashMap<String, Object>(); 104 data.put(id, map); 105 // put fields in map 106 for (Entry<String, Object> e : fieldMap.entrySet()) { 107 String fieldName = e.getKey(); 108 if (!getDirectory().schemaSet.contains(fieldName)) { 109 continue; 110 } 111 map.put(fieldName, e.getValue()); 112 } 113 return getEntry(id); 114 } 115 116 @Override 117 public DocumentModel getEntry(String id) throws DirectoryException { 118 return getEntry(id, true); 119 } 120 121 @Override 122 public DocumentModel getEntry(String id, boolean fetchReferences) throws DirectoryException { 123 // XXX no references here 124 Map<String, Object> map = data.get(id); 125 if (map == null) { 126 return null; 127 } 128 try { 129 DocumentModel entry = BaseSession.createEntryModel(null, directory.getSchema(), id, map, isReadOnly()); 130 return entry; 131 } catch (PropertyException e) { 132 throw new DirectoryException(e); 133 } 134 } 135 136 @Override 137 public void updateEntry(DocumentModel docModel) throws DirectoryException { 138 String id = docModel.getId(); 139 DataModel dataModel = docModel.getDataModel(directory.getSchema()); 140 141 Map<String, Object> map = data.get(id); 142 if (map == null) { 143 throw new DirectoryException("UpdateEntry failed: entry '" + id + "' not found"); 144 } 145 146 for (String fieldName : getDirectory().schemaSet) { 147 try { 148 if (!dataModel.isDirty(fieldName) || fieldName.equals(getIdField())) { 149 continue; 150 } 151 } catch (PropertyNotFoundException e) { 152 continue; 153 } 154 // TODO references 155 map.put(fieldName, dataModel.getData(fieldName)); 156 } 157 dataModel.getDirtyFields().clear(); 158 } 159 160 @Override 161 public DocumentModelList getEntries() throws DirectoryException { 162 DocumentModelList list = new DocumentModelListImpl(); 163 for (String id : data.keySet()) { 164 list.add(getEntry(id)); 165 } 166 return list; 167 } 168 169 @Override 170 public void deleteEntry(String id) throws DirectoryException { 171 data.remove(id); 172 } 173 174 // given our storage model this doesn't even make sense, as id field is 175 // unique 176 @Override 177 public void deleteEntry(String id, Map<String, String> map) throws DirectoryException { 178 throw new DirectoryException("Not implemented"); 179 } 180 181 @Override 182 public void deleteEntry(DocumentModel docModel) throws DirectoryException { 183 deleteEntry(docModel.getId()); 184 } 185 186 @Override 187 public DocumentModelList query(Map<String, Serializable> filter) throws DirectoryException { 188 return query(filter, Collections.<String> emptySet()); 189 } 190 191 @Override 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 @Override 197 public DocumentModelList query(Map<String, Serializable> filter, Set<String> fulltext, Map<String, String> orderBy) 198 throws DirectoryException { 199 return query(filter, fulltext, orderBy, true); 200 } 201 202 @Override 203 public DocumentModelList query(Map<String, Serializable> filter, Set<String> fulltext, Map<String, String> orderBy, 204 boolean fetchReferences) throws DirectoryException { 205 DocumentModelList results = new DocumentModelListImpl(); 206 // canonicalize filter 207 Map<String, Object> filt = new HashMap<String, Object>(); 208 for (Entry<String, Serializable> e : filter.entrySet()) { 209 String fieldName = e.getKey(); 210 if (!getDirectory().schemaSet.contains(fieldName)) { 211 continue; 212 } 213 filt.put(fieldName, e.getValue()); 214 } 215 // do the search 216 data_loop: for (Entry<String, Map<String, Object>> datae : data.entrySet()) { 217 String id = datae.getKey(); 218 Map<String, Object> map = datae.getValue(); 219 for (Entry<String, Object> e : filt.entrySet()) { 220 String fieldName = e.getKey(); 221 Object expected = e.getValue(); 222 Object value = map.get(fieldName); 223 if (value == null) { 224 if (expected != null) { 225 continue data_loop; 226 } 227 } else { 228 if (fulltext != null && fulltext.contains(fieldName)) { 229 if (!value.toString().toLowerCase().startsWith(expected.toString().toLowerCase())) { 230 continue data_loop; 231 } 232 } else { 233 if (!value.equals(expected)) { 234 continue data_loop; 235 } 236 } 237 } 238 } 239 // this entry matches 240 results.add(getEntry(id)); 241 } 242 // order entries 243 if (orderBy != null && !orderBy.isEmpty()) { 244 getDirectory().orderEntries(results, orderBy); 245 } 246 return results; 247 } 248 249 @Override 250 public List<String> getProjection(Map<String, Serializable> filter, String columnName) throws DirectoryException { 251 return getProjection(filter, Collections.<String> emptySet(), columnName); 252 } 253 254 @Override 255 public List<String> getProjection(Map<String, Serializable> filter, Set<String> fulltext, String columnName) 256 throws DirectoryException { 257 DocumentModelList l = query(filter, fulltext); 258 List<String> results = new ArrayList<String>(l.size()); 259 for (DocumentModel doc : l) { 260 Object value; 261 try { 262 value = doc.getProperty(directory.getSchema(), columnName); 263 } catch (PropertyException e) { 264 throw new DirectoryException(e); 265 } 266 if (value != null) { 267 results.add(value.toString()); 268 } else { 269 results.add(null); 270 } 271 } 272 return results; 273 } 274 275 @Override 276 public DocumentModel createEntry(DocumentModel entry) { 277 Map<String, Object> fieldMap = entry.getProperties(directory.getSchema()); 278 return createEntry(fieldMap); 279 } 280 281 @Override 282 public boolean hasEntry(String id) { 283 return data.containsKey(id); 284 } 285 286}