/*
* Copyright 2013 the original author or authors.
*
* 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.
*/
package org.springframework.xd.store;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.util.Assert;
/**
* Base implementation for an in-memory store, using a {@link Map} internally.
*
* Default behaviour is to retain sort order on the keys. Hence, this is by default the only sort supported when
* querying with a {@link Pageable}.
*
* @param <T> the type of things to store
* @param <ID> a "primary key" to the things
* @author Eric Bottard
*/
public abstract class AbstractInMemoryRepository<T, ID extends Serializable & Comparable<ID>> extends
AbstractRepository<T, ID>
implements PagingAndSortingRepository<T, ID>, RangeCapableRepository<T, ID> {
private final NavigableMap<ID, T> map;
protected AbstractInMemoryRepository() {
map = buildMap();
}
protected NavigableMap<ID, T> buildMap() {
return new ConcurrentSkipListMap<ID, T>();
}
@Override
public <S extends T> S save(S entity) {
Assert.notNull(entity);
map.put(safeKeyFor(entity), entity);
return entity;
}
private final ID safeKeyFor(T entity) {
ID k = keyFor(entity);
Assert.notNull(k);
return k;
}
protected abstract ID keyFor(T entity);
@Override
public T findOne(ID id) {
Assert.notNull(id);
return map.get(id);
}
@Override
public Iterable<T> findAll() {
return new ArrayList<T>(map.values());
}
@Override
public long count() {
return map.size();
}
@Override
public void delete(ID id) {
Assert.notNull(id);
map.remove(id);
}
@Override
public void delete(T entity) {
Assert.notNull(entity);
map.remove(safeKeyFor(entity));
}
@Override
public void deleteAll() {
map.clear();
}
@Override
public Page<T> findAll(Pageable pageable) {
Assert.isNull(pageable.getSort(), "Arbitrary sorting is not implemented");
return slice((List<T>) findAll(), pageable);
}
/**
* Post-process the list to only return elements matching the page request.
*/
protected Page<T> slice(List<T> list, Pageable pageable) {
int to = Math.min(list.size(), pageable.getOffset() + pageable.getPageSize());
List<T> data = list.subList(pageable.getOffset(), to);
return new PageImpl<T>(data, pageable, list.size());
}
@Override
public Iterable<T> findAll(Sort sort) {
throw new UnsupportedOperationException("Arbitrary sorting is not implemented");
}
@Override
public Iterable<T> findAllInRange(ID from, boolean fromInclusive, ID to, boolean toInclusive) {
return map.subMap(from, fromInclusive, to, toInclusive).values();
}
}