package org.yaac.server.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.yaac.client.service.StatisticsService;
import org.yaac.server.util.DatastoreUtil;
import org.yaac.server.util.GWTUtil;
import org.yaac.shared.stat.StatConstants;
import org.yaac.shared.stat.StatDTO;
import org.yaac.shared.stat.StatDTO.KindWrapper;
import org.yaac.shared.stat.models.Kind;
import org.yaac.shared.stat.models.KindIsRootEntity;
import org.yaac.shared.stat.models.KindNonRootEntity;
import org.yaac.shared.stat.models.NSKind;
import org.yaac.shared.stat.models.NSKindIsRootEntity;
import org.yaac.shared.stat.models.NSKindNonRootEntity;
import org.yaac.shared.stat.models.NSPropertyTypePropertyNameKind;
import org.yaac.shared.stat.models.Total;
import com.google.appengine.api.NamespaceManager;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Query;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyService;
/**
* @author Max Zhu (thebbsky@gmail.com)
*
*/
public class StatisticsServiceImpl implements StatisticsService {
@Override
public StatDTO loadStat() {
// step 1 : kick off all async queries
// namespace query : we use low-level API rather than Objectify to manage namespace is because
Iterable<Entity> namespaceEntities =
DatastoreServiceFactory.getAsyncDatastoreService().prepare(new Query(StatConstants.STAT_NAMESPACE)).asIterable();
Objectify ofy = ObjectifyService.begin();
Iterable<Total> totals = ofy.query(Total.class).fetch(); // total stat query
// use HashMap here because Guava's map implementations don't support empty string
Map<String, Iterable<NSKind>> nsKindsMap = new HashMap<String, Iterable<NSKind>>();
Map<String, Iterable<NSKindIsRootEntity>> nsRootKindsMap = new HashMap<String, Iterable<NSKindIsRootEntity>>();
Map<String, Iterable<NSKindNonRootEntity>> nsNonRootKindsMap = new HashMap<String, Iterable<NSKindNonRootEntity>>();
Map<String, Iterable<NSPropertyTypePropertyNameKind>> nsPropertyTypeNameKindsMap =
new HashMap<String, Iterable<NSPropertyTypePropertyNameKind>>();
// kick off per namespace queries for kind / property
for (Entity entity : namespaceEntities) {
String namespace = entity.getKey().getName();
if (namespace == null) {
namespace = ""; // for empty namespace, the key will be 1, so namespace will be null here
}
NamespaceManager.set(namespace);
// __Stat_Ns_Kind__ query
nsKindsMap.put(namespace, ofy.query(NSKind.class).fetch());
// __Stat_Ns_Kind_IsRootEntity__ query
nsRootKindsMap.put(namespace, ofy.query(NSKindIsRootEntity.class).fetch());
// __Stat_Ns_Kind_NotRootEntity__ query
nsNonRootKindsMap.put(namespace, ofy.query(NSKindNonRootEntity.class).fetch());
// __Stat_Ns_PropertyType_PropertyName_Kind__ query
nsPropertyTypeNameKindsMap.put(namespace, ofy.query(NSPropertyTypePropertyNameKind.class).fetch());
}
NamespaceManager.set(null); // reset namespace
// ====================== step 2, assemble results=====================
Total total = DatastoreUtil.singleEntityFrom(totals);
Map<String, Iterable<KindWrapper>> nsKindsWrapperMap = new HashMap<String, Iterable<KindWrapper>>();
for (String namespace : nsKindsMap.keySet()) {
// kinds
Map<String, KindWrapper> kindWrapperMap = new HashMap<String, KindWrapper>();
for (Kind kind : nsKindsMap.get(namespace)) {
KindWrapper kindWrapper = new KindWrapper();
kindWrapper.setKind(kind);
kindWrapperMap.put(kind.getKind_name(), kindWrapper);
}
for (KindIsRootEntity kindRoot : nsRootKindsMap.get(namespace)) {
kindWrapperMap.get(kindRoot.getKind_name()).setRootKind(kindRoot);
}
for (KindNonRootEntity kindNonRoot : nsNonRootKindsMap.get(namespace)) {
kindWrapperMap.get(kindNonRoot.getKind_name()).setNonRootKind(kindNonRoot);
}
nsKindsWrapperMap.put(namespace, new ArrayList<KindWrapper>(kindWrapperMap.values()));
}
Map<String, Iterable<NSPropertyTypePropertyNameKind>> nsPropertyMap =
new HashMap<String, Iterable<NSPropertyTypePropertyNameKind>>();
for (String namespace : nsPropertyTypeNameKindsMap.keySet()) {
nsPropertyMap.put(namespace, GWTUtil.ensureGWTCompatible(nsPropertyTypeNameKindsMap.get(namespace)));
}
return new StatDTO(total, nsKindsWrapperMap, nsPropertyMap);
}
}