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