/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.capedwarf.datastore;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.google.appengine.api.datastore.DatastoreAttributes;
import com.google.appengine.api.datastore.DatastoreServiceConfig;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Index;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyRange;
import com.google.appengine.api.datastore.Transaction;
import com.google.appengine.api.datastore.TransactionOptions;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import org.jboss.capedwarf.common.threads.DirectFuture;
/**
* JBoss DatastoreService impl.
*
* @author <a href="mailto:ales.justin@jboss.org">Ales Justin</a>
* @author <a href="mailto:marko.luksa@gmail.com">Marko Luksa</a>
*/
public class CapedwarfDatastoreService extends AbstractDatastoreService implements ExposedDatastoreService {
public CapedwarfDatastoreService() {
this(null);
}
public CapedwarfDatastoreService(DatastoreServiceConfig config) {
super(new DatastoreServiceImpl(config));
}
protected CurrentTransactionProvider postTxProvider(Transaction tx) {
return this;
}
protected <T> Future<T> wrap(final Transaction transaction, final Callable<T> callable, final Runnable pre, final Function<T, Void> post) {
return DirectFuture.create(new Callable<T>() {
public T call() throws Exception {
if (pre != null) {
pre.run();
}
final T result = callable.call();
if (post != null) {
post.apply(result);
}
return result;
}
});
}
protected <T> T unwrap(Future<T> future) {
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
@AutoTx
@Deadline
public Entity get(Key key) throws EntityNotFoundException {
return get(getCurrentTransaction(null), key);
}
@AutoTx
@Deadline
public Entity get(Transaction transaction, Key key) throws EntityNotFoundException {
final Entity result = unwrap(doGet(transaction, key));
if (result == null) {
throw new EntityNotFoundException(key);
}
return result;
}
@AutoTx
@Deadline
public Map<Key, Entity> get(Iterable<Key> keys) {
return get(getCurrentTransaction(null), keys);
}
@AutoTx
@Deadline
public Map<Key, Entity> get(final Transaction transaction, final Iterable<Key> keys) {
final Map<Key, Entity> map = new LinkedHashMap<Key, Entity>();
getDatastoreCallbacks().executePreGetCallbacks(this, Lists.newArrayList(keys), map);
final List<Key> requiredKeys = Lists.newArrayList(keys);
if (map.isEmpty() == false) {
requiredKeys.removeAll(map.keySet()); // remove manually added keys
}
for (Key key : requiredKeys) {
final Entity entity = getDelegate().get(transaction, key);
if (entity != null) {
map.put(key, entity);
}
}
getDatastoreCallbacks().executePostLoadCallbacks(this, Lists.newArrayList(map.values()));
return map;
}
@AutoTx
@Deadline
public Key put(Entity entity) {
return put(getCurrentTransaction(null), entity);
}
@AutoTx
@Deadline
public Key put(Transaction transaction, Entity entity) {
return unwrap(doPut(transaction, entity, true));
}
@AutoTx
@Deadline
public List<Key> put(Iterable<Entity> entities) {
return put(getCurrentTransaction(null), entities);
}
@AutoTx
@Deadline
public List<Key> put(Transaction transaction, final Iterable<Entity> entities) {
final boolean isSpecialKind = KindUtils.inProgress(KindUtils.Type.METADATA);
if (isSpecialKind == false) {
getDatastoreCallbacks().executePrePutCallbacks(this, Lists.newArrayList(entities));
}
final Runnable post = new Runnable() {
public void run() {
if (isSpecialKind == false) {
getDatastoreCallbacks().executePostPutCallbacks(CapedwarfDatastoreService.this, Lists.newArrayList(entities));
}
}
};
return getDelegate().put(transaction, entities, post);
}
@AutoTx
@Deadline
public void delete(Key... keys) {
delete(getCurrentTransaction(null), keys);
}
@AutoTx
@Deadline
public void delete(Transaction transaction, Key... keys) {
delete(transaction, Arrays.asList(keys));
}
@AutoTx
@Deadline
public void delete(Iterable<Key> keys) {
delete(getCurrentTransaction(null), keys);
}
@AutoTx
@Deadline
public void delete(final Transaction transaction, final Iterable<Key> keys) {
final boolean isSpecialKind = KindUtils.inProgress(KindUtils.Type.METADATA);
if (isSpecialKind == false) {
getDatastoreCallbacks().executePreDeleteCallbacks(this, Lists.newArrayList(keys));
}
final Runnable post = new Runnable() {
public void run() {
if (isSpecialKind == false) {
getDatastoreCallbacks().executePostDeleteCallbacks(CapedwarfDatastoreService.this, Lists.newArrayList(keys));
}
}
};
getDelegate().delete(transaction, keys, post);
}
@Deadline
public Transaction beginTransaction() {
return beginTransaction(TransactionOptions.Builder.withDefaults());
}
@Deadline
public Transaction beginTransaction(final TransactionOptions transactionOptions) {
return getDelegate().beginTransaction(transactionOptions);
}
@Deadline
public KeyRange allocateIds(String kind, long num) {
return allocateIds(null, kind, num);
}
@Deadline
public KeyRange allocateIds(Key key, String s, long l) {
return getDelegate().allocateIds(key, s, l);
}
@Deadline
public KeyRangeState allocateIdRange(KeyRange keys) {
return getDelegate().allocateIdRange(keys);
}
@Deadline
public DatastoreAttributes getDatastoreAttributes() {
return getDelegate().getDatastoreAttributes();
}
@Deadline
public Map<Index, Index.IndexState> getIndexes() {
return getDelegate().getIndexes();
}
}