/* * Copyright 2013-2017 Erudika. https://erudika.com * * 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. * * For issues and patches go to: https://github.com/erudika */ package com.erudika.para.persistence; import com.erudika.para.annotations.Locked; import com.erudika.para.core.ParaObject; import com.erudika.para.core.utils.ParaObjectUtils; import com.erudika.para.search.Search; import com.erudika.para.utils.Config; import com.erudika.para.utils.Pager; import com.erudika.para.utils.Utils; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.inject.Inject; import javax.inject.Singleton; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An implementation of the {@link DAO} interface used <b>for local development only</b>. * It uses is based on the {@link com.erudika.para.search.Search} implementation. * Objects are stored in the index rather than in a data store. * * <b>Note</b>: This implementation doesn't work well with apps sharing one index (app.isSharingIndex() must be false). * @author Alex Bogdanovski [alex@erudika.com] */ @Singleton public class IndexBasedDAO implements DAO { private static final Logger logger = LoggerFactory.getLogger(IndexBasedDAO.class); private Search search; /** * No-args constructor. */ public IndexBasedDAO() { } /** * Default constructor. * @param search the search object */ @Inject public IndexBasedDAO(Search search) { this.search = search; } /** * Sets the search instance. * @param search a serch instance */ public void setSearch(Search search) { this.search = search; } @Override public <P extends ParaObject> String create(String appid, P so) { if (so == null) { return null; } if (StringUtils.isBlank(so.getId())) { so.setId(Utils.getNewId()); } if (so.getTimestamp() == null) { so.setTimestamp(Utils.timestamp()); } so.setAppid(appid); so.setIndexed(false); // skip indexing - already indexed here search.index(appid, ParaObjectUtils.setAnnotatedFields(ParaObjectUtils.toObject(so.getType()), ParaObjectUtils.getAnnotatedFields(so), null)); logger.debug("DAO.create() {}", so.getId()); return so.getId(); } @Override @SuppressWarnings("unchecked") public <P extends ParaObject> P read(String appid, String key) { if (key == null || StringUtils.isBlank(appid) || search == null) { return null; } P so = search.findById(getAppidWithRouting(appid), key); logger.debug("DAO.read() {} -> {}", key, so == null ? null : so.getType()); return so; } @Override public <P extends ParaObject> void update(String appid, P so) { if (so != null && !StringUtils.isBlank(appid)) { so.setUpdated(Utils.timestamp()); so.setIndexed(false); // skip indexing - already indexed here ParaObject soUpdated = read(appid, so.getId()); search.index(appid, ParaObjectUtils.setAnnotatedFields(soUpdated, ParaObjectUtils.getAnnotatedFields(so), Locked.class)); logger.debug("DAO.update() {}", so.getId()); } } @Override public <P extends ParaObject> void delete(String appid, P so) { if (so != null && !StringUtils.isBlank(appid)) { search.unindex(appid, so); logger.debug("DAO.delete() {}", so.getId()); } } @Override public <P extends ParaObject> void createAll(String appid, List<P> objects) { if (StringUtils.isBlank(appid) || objects == null) { return; } Iterator<P> iter = objects.iterator(); while (iter.hasNext()) { P p = iter.next(); if (p == null) { iter.remove(); continue; } p.setAppid(appid); p.setIndexed(false); if (StringUtils.isBlank(p.getId())) { p.setId(Utils.getNewId()); } if (p.getTimestamp() == null) { p.setTimestamp(Utils.timestamp()); } } search.indexAll(appid, objects); logger.debug("DAO.createAll() {}", objects.size()); } @Override public <P extends ParaObject> Map<String, P> readAll(String appid, List<String> keys, boolean getAllColumns) { if (keys == null || StringUtils.isBlank(appid)) { return Collections.emptyMap(); } Map<String, P> results = new LinkedHashMap<String, P>(keys.size()); List<P> list = search.findByIds(getAppidWithRouting(appid), keys); for (P p : list) { if (p != null) { results.put(p.getId(), p); } } logger.debug("DAO.readAll() {}", results.size()); return results; } @Override public <P extends ParaObject> List<P> readPage(String appid, Pager pager) { List<P> results = new LinkedList<P>(); if (StringUtils.isBlank(appid)) { return results; } if (pager == null) { pager = new Pager(); } List<P> res = search.findQuery(appid, null, "*", pager); for (P obj : res) { if (obj != null) { results.add(obj); } } if (!results.isEmpty()) { pager.setPage(pager.getPage() + 1); } return results; } @Override public <P extends ParaObject> void updateAll(String appid, List<P> objects) { if (!StringUtils.isBlank(appid) && objects != null) { for (P obj : objects) { if (obj != null) { update(appid, obj); } } logger.debug("DAO.updateAll() {}", objects.size()); } } @Override public <P extends ParaObject> void deleteAll(String appid, List<P> objects) { if (!StringUtils.isBlank(appid) && objects != null) { search.unindexAll(appid, objects); logger.debug("DAO.deleteAll() {}", objects.size()); } } private String getAppidWithRouting(String appid) { return appid; } //////////////////////////////////////////////////////////////////// @Override public <P extends ParaObject> String create(P so) { return create(Config.APP_NAME_NS, so); } @Override public <P extends ParaObject> P read(String key) { return read(Config.APP_NAME_NS, key); } @Override public <P extends ParaObject> void update(P so) { update(Config.APP_NAME_NS, so); } @Override public <P extends ParaObject> void delete(P so) { delete(Config.APP_NAME_NS, so); } @Override public <P extends ParaObject> void createAll(List<P> objects) { createAll(Config.APP_NAME_NS, objects); } @Override public <P extends ParaObject> Map<String, P> readAll(List<String> keys, boolean getAllColumns) { return readAll(Config.APP_NAME_NS, keys, getAllColumns); } @Override public <P extends ParaObject> List<P> readPage(Pager pager) { return readPage(Config.APP_NAME_NS, pager); } @Override public <P extends ParaObject> void updateAll(List<P> objects) { updateAll(Config.APP_NAME_NS, objects); } @Override public <P extends ParaObject> void deleteAll(List<P> objects) { deleteAll(Config.APP_NAME_NS, objects); } }