/* * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * Florent Guillaume * * $Id: MemoryDirectorySession.java 30374 2008-02-20 16:31:28Z gracinet $ */ package org.nuxeo.ecm.directory.memory; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import org.nuxeo.ecm.core.api.DataModel; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.DocumentModelList; import org.nuxeo.ecm.core.api.PropertyException; import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl; import org.nuxeo.ecm.core.api.model.PropertyNotFoundException; import org.nuxeo.ecm.directory.BaseSession; import org.nuxeo.ecm.directory.DirectoryException; /** * Trivial in-memory implementation of a Directory to use in unit tests. * * @author Florent Guillaume */ public class MemoryDirectorySession extends BaseSession { protected final Map<String, Map<String, Object>> data; public MemoryDirectorySession(MemoryDirectory directory) { super(directory); data = Collections.synchronizedMap(new LinkedHashMap<String, Map<String, Object>>()); } /** To be implemented with a more specific type. */ @Override public MemoryDirectory getDirectory() { return (MemoryDirectory) directory; } @Override public boolean authenticate(String username, String password) throws DirectoryException { Map<String, Object> map = data.get(username); if (map == null) { return false; } String expected = (String) map.get(getPasswordField()); if (expected == null) { return false; } return expected.equals(password); } @Override public void close() { } public void commit() { } public void rollback() throws DirectoryException { // TODO Auto-generated method stub throw new RuntimeException("Not implemented"); } @Override public DocumentModel createEntry(Map<String, Object> fieldMap) throws DirectoryException { if (isReadOnly()) { return null; } // find id Object rawId = fieldMap.get(getIdField()); if (rawId == null) { throw new DirectoryException("Missing id"); } String id = String.valueOf(rawId); Map<String, Object> map = data.get(id); if (map != null) { throw new DirectoryException(String.format("Entry with id %s already exists", id)); } map = new HashMap<String, Object>(); data.put(id, map); // put fields in map for (Entry<String, Object> e : fieldMap.entrySet()) { String fieldName = e.getKey(); if (!getDirectory().schemaSet.contains(fieldName)) { continue; } map.put(fieldName, e.getValue()); } return getEntry(id); } @Override public DocumentModel getEntry(String id) throws DirectoryException { return getEntry(id, true); } @Override public DocumentModel getEntry(String id, boolean fetchReferences) throws DirectoryException { // XXX no references here Map<String, Object> map = data.get(id); if (map == null) { return null; } try { DocumentModel entry = BaseSession.createEntryModel(null, directory.getSchema(), id, map, isReadOnly()); return entry; } catch (PropertyException e) { throw new DirectoryException(e); } } @Override public void updateEntry(DocumentModel docModel) throws DirectoryException { String id = docModel.getId(); DataModel dataModel = docModel.getDataModel(directory.getSchema()); Map<String, Object> map = data.get(id); if (map == null) { throw new DirectoryException("UpdateEntry failed: entry '" + id + "' not found"); } for (String fieldName : getDirectory().schemaSet) { try { if (!dataModel.isDirty(fieldName) || fieldName.equals(getIdField())) { continue; } } catch (PropertyNotFoundException e) { continue; } // TODO references map.put(fieldName, dataModel.getData(fieldName)); } dataModel.getDirtyFields().clear(); } @Override public DocumentModelList getEntries() throws DirectoryException { DocumentModelList list = new DocumentModelListImpl(); for (String id : data.keySet()) { list.add(getEntry(id)); } return list; } @Override public void deleteEntry(String id) throws DirectoryException { checkDeleteConstraints(id); data.remove(id); } // given our storage model this doesn't even make sense, as id field is // unique @Override public void deleteEntry(String id, Map<String, String> map) throws DirectoryException { throw new DirectoryException("Not implemented"); } @Override public void deleteEntry(DocumentModel docModel) throws DirectoryException { deleteEntry(docModel.getId()); } @Override public DocumentModelList query(Map<String, Serializable> filter) throws DirectoryException { return query(filter, Collections.<String> emptySet()); } @Override public DocumentModelList query(Map<String, Serializable> filter, Set<String> fulltext) throws DirectoryException { return query(filter, fulltext, Collections.<String, String> emptyMap()); } @Override public DocumentModelList query(Map<String, Serializable> filter, Set<String> fulltext, Map<String, String> orderBy) throws DirectoryException { return query(filter, fulltext, orderBy, true); } @Override public DocumentModelList query(Map<String, Serializable> filter, Set<String> fulltext, Map<String, String> orderBy, boolean fetchReferences) throws DirectoryException { DocumentModelList results = new DocumentModelListImpl(); // canonicalize filter Map<String, Object> filt = new HashMap<String, Object>(); for (Entry<String, Serializable> e : filter.entrySet()) { String fieldName = e.getKey(); if (!getDirectory().schemaSet.contains(fieldName)) { continue; } filt.put(fieldName, e.getValue()); } // do the search data_loop: for (Entry<String, Map<String, Object>> datae : data.entrySet()) { String id = datae.getKey(); Map<String, Object> map = datae.getValue(); for (Entry<String, Object> e : filt.entrySet()) { String fieldName = e.getKey(); Object expected = e.getValue(); Object value = map.get(fieldName); if (value == null) { if (expected != null) { continue data_loop; } } else { if (fulltext != null && fulltext.contains(fieldName)) { if (!value.toString().toLowerCase().startsWith(expected.toString().toLowerCase())) { continue data_loop; } } else { if (!value.equals(expected)) { continue data_loop; } } } } // this entry matches results.add(getEntry(id)); } // order entries if (orderBy != null && !orderBy.isEmpty()) { getDirectory().orderEntries(results, orderBy); } return results; } @Override public List<String> getProjection(Map<String, Serializable> filter, String columnName) throws DirectoryException { return getProjection(filter, Collections.<String> emptySet(), columnName); } @Override public List<String> getProjection(Map<String, Serializable> filter, Set<String> fulltext, String columnName) throws DirectoryException { DocumentModelList l = query(filter, fulltext); List<String> results = new ArrayList<String>(l.size()); for (DocumentModel doc : l) { Object value; try { value = doc.getProperty(directory.getSchema(), columnName); } catch (PropertyException e) { throw new DirectoryException(e); } if (value != null) { results.add(value.toString()); } else { results.add(null); } } return results; } @Override public DocumentModel createEntry(DocumentModel entry) { Map<String, Object> fieldMap = entry.getProperties(directory.getSchema()); return createEntry(fieldMap); } @Override public boolean hasEntry(String id) { return data.containsKey(id); } }