/*
* Copyright (c) 2010-2012 Grid Dynamics Consulting Services, Inc, All Rights Reserved
* http://www.griddynamics.com
*
* This library is free software; you can redistribute it and/or modify it under the terms of
* the Apache License; either
* version 2.0 of the License, or any later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.griddynamics.jagger.storage.rdb;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.griddynamics.jagger.storage.KeyValueStorage;
import com.griddynamics.jagger.storage.Namespace;
import com.griddynamics.jagger.util.SerializationUtils;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import java.sql.SQLException;
import java.util.*;
public class HibernateKeyValueStorage extends HibernateDaoSupport implements KeyValueStorage {
private static final Logger log = LoggerFactory.getLogger(HibernateKeyValueStorage.class);
private int hibernateBatchSize;
private int sessionTempDataCount=50;
private String sessionId;
public int getHibernateBatchSize() {
return hibernateBatchSize;
}
public int getSessionTempDataCount() {
return sessionTempDataCount;
}
@Required
public void setSessionTempDataCount(int sessionTempDataCount) {
if (sessionTempDataCount < 0) {
log.warn("Session count can't be < 0; chassis.storage.temporary.data.session.count is equal {}.", sessionTempDataCount);
return;
}
this.sessionTempDataCount = sessionTempDataCount;
}
@Required
public void setHibernateBatchSize(int hibernateBatchSize) {
this.hibernateBatchSize = hibernateBatchSize;
}
@Override
public boolean isAvailable() {
return false;
}
@Override
public void initialize() {
}
@Override
public void setSessionId(String sessionId) {
this.sessionId=sessionId;
}
@Override
public void put(Namespace namespace, String key, Object value) {
getHibernateTemplate().persist(createKeyValue(namespace, key, value));
}
@Override
public void putAll(Namespace namespace, Multimap<String, Object> valuesMap) {
Session session = null;
int count = 0;
try {
session = getHibernateTemplate().getSessionFactory().openSession();
session.beginTransaction();
for (String key : valuesMap.keySet()) {
Collection<Object> values = valuesMap.get(key);
for (Object val : values) {
session.save(createKeyValue(namespace, key, val));
count++;
if (count % getHibernateBatchSize() == 0) {
session.flush();
session.clear();
}
}
}
session.getTransaction().commit();
} finally {
if (session != null) {
session.close();
}
}
}
@Override
public void deleteAll() {
ArrayList<String> sessions = (ArrayList) getHibernateTemplate().find(
"Select distinct k.sessionId from KeyValue k ORDER by k.sessionId");
if (sessions.size() == 0)
return;
if (sessionTempDataCount == 0) {
log.warn("Session count limit is equal '0', all temporary data about sessions in KeyValue will be delete");
getHibernateTemplate().bulkUpdate("delete from KeyValue");
return;
}
final List<String> sessionsToDelete = Lists.newArrayList();
sessionsToDelete.add(sessionId);
if (sessions.size() > sessionTempDataCount) {
sessionsToDelete.addAll(sessions.subList(0, (sessions.size() - 1) - sessionTempDataCount));
}
getHibernateTemplate().execute(new HibernateCallback<Void>() {
@Override
public Void doInHibernate(Session session) throws HibernateException, SQLException {
Query query = session.createQuery("delete from KeyValue where sessionId in (:sessionIds)");
query.setParameterList("sessionIds", sessionsToDelete);
query.executeUpdate();
session.flush();
return null;
}
});
}
@SuppressWarnings("unchecked")
@Override
public Object fetch(Namespace namespace, String key) {
List<KeyValue> values = (List<KeyValue>) getHibernateTemplate()
.find("from KeyValue kv where kv.namespace = ? and kv.key = ?", namespace.toString(), key);
if (values.isEmpty()) {
return null;
}
if (values.size() > 1) {
throw new IllegalStateException("Use fetchAll");
}
return SerializationUtils.deserialize(values.get(0).getData());
}
@SuppressWarnings("unchecked")
@Override
public Collection<Object> fetchAll(Namespace namespace, String key) {
List<KeyValue> entities = (List<KeyValue>) getHibernateTemplate().find(
"from KeyValue kv where kv.namespace = ? and kv.key = ?", namespace.toString(), key);
Collection<Object> result = Lists.newLinkedList();
for (KeyValue entity : entities) {
result.add(SerializationUtils.deserialize(entity.getData()));
}
return result;
}
@SuppressWarnings("unchecked")
@Override
public Multimap<String, Object> fetchAll(Namespace namespace) {
List<KeyValue> entities = (List<KeyValue>) getHibernateTemplate().find(
"from KeyValue kv where kv.namespace = ?", namespace.toString());
Multimap<String, Object> result = ArrayListMultimap.create();
for (KeyValue entity : entities) {
result.put(entity.getKey(), SerializationUtils.deserialize(entity.getData()));
}
return result;
}
@Override
public Object fetchNotNull(Namespace namespace, String key) {
Object result = fetch(namespace, key);
if (result == null) {
throw new IllegalStateException("Cannot find value for namespace " + namespace + " and key " + key);
}
return result;
}
private KeyValue createKeyValue(Namespace namespace, String key, Object value) {
KeyValue keyvalue = new KeyValue();
keyvalue.setNamespace(namespace.toString());
keyvalue.setKey(key);
keyvalue.setData(SerializationUtils.serialize(value));
keyvalue.setSessionId(sessionId);
return keyvalue;
}
}