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 checkDeleteConstraints(id); 172 data.remove(id); 173 } 174 175 // given our storage model this doesn't even make sense, as id field is 176 // unique 177 @Override 178 public void deleteEntry(String id, Map<String, String> map) throws DirectoryException { 179 throw new DirectoryException("Not implemented"); 180 } 181 182 @Override 183 public void deleteEntry(DocumentModel docModel) throws DirectoryException { 184 deleteEntry(docModel.getId()); 185 } 186 187 @Override 188 public DocumentModelList query(Map<String, Serializable> filter) throws DirectoryException { 189 return query(filter, Collections.<String> emptySet()); 190 } 191 192 @Override 193 public DocumentModelList query(Map<String, Serializable> filter, Set<String> fulltext) throws DirectoryException { 194 return query(filter, fulltext, Collections.<String, String> emptyMap()); 195 } 196 197 @Override 198 public DocumentModelList query(Map<String, Serializable> filter, Set<String> fulltext, Map<String, String> orderBy) 199 throws DirectoryException { 200 return query(filter, fulltext, orderBy, true); 201 } 202 203 @Override 204 public DocumentModelList query(Map<String, Serializable> filter, Set<String> fulltext, Map<String, String> orderBy, 205 boolean fetchReferences) throws DirectoryException { 206 DocumentModelList results = new DocumentModelListImpl(); 207 // canonicalize filter 208 Map<String, Object> filt = new HashMap<String, Object>(); 209 for (Entry<String, Serializable> e : filter.entrySet()) { 210 String fieldName = e.getKey(); 211 if (!getDirectory().schemaSet.contains(fieldName)) { 212 continue; 213 } 214 filt.put(fieldName, e.getValue()); 215 } 216 // do the search 217 data_loop: for (Entry<String, Map<String, Object>> datae : data.entrySet()) { 218 String id = datae.getKey(); 219 Map<String, Object> map = datae.getValue(); 220 for (Entry<String, Object> e : filt.entrySet()) { 221 String fieldName = e.getKey(); 222 Object expected = e.getValue(); 223 Object value = map.get(fieldName); 224 if (value == null) { 225 if (expected != null) { 226 continue data_loop; 227 } 228 } else { 229 if (fulltext != null && fulltext.contains(fieldName)) { 230 if (!value.toString().toLowerCase().startsWith(expected.toString().toLowerCase())) { 231 continue data_loop; 232 } 233 } else { 234 if (!value.equals(expected)) { 235 continue data_loop; 236 } 237 } 238 } 239 } 240 // this entry matches 241 results.add(getEntry(id)); 242 } 243 // order entries 244 if (orderBy != null && !orderBy.isEmpty()) { 245 getDirectory().orderEntries(results, orderBy); 246 } 247 return results; 248 } 249 250 @Override 251 public List<String> getProjection(Map<String, Serializable> filter, String columnName) throws DirectoryException { 252 return getProjection(filter, Collections.<String> emptySet(), columnName); 253 } 254 255 @Override 256 public List<String> getProjection(Map<String, Serializable> filter, Set<String> fulltext, String columnName) 257 throws DirectoryException { 258 DocumentModelList l = query(filter, fulltext); 259 List<String> results = new ArrayList<String>(l.size()); 260 for (DocumentModel doc : l) { 261 Object value; 262 try { 263 value = doc.getProperty(directory.getSchema(), columnName); 264 } catch (PropertyException e) { 265 throw new DirectoryException(e); 266 } 267 if (value != null) { 268 results.add(value.toString()); 269 } else { 270 results.add(null); 271 } 272 } 273 return results; 274 } 275 276 @Override 277 public DocumentModel createEntry(DocumentModel entry) { 278 Map<String, Object> fieldMap = entry.getProperties(directory.getSchema()); 279 return createEntry(fieldMap); 280 } 281 282 @Override 283 public boolean hasEntry(String id) { 284 return data.containsKey(id); 285 } 286 287}