/*
* Copyright 2011 PA Consulting Ltd
*
* 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 com.prodeagle.java;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Transaction;
/**
* A helper class for storing information into the datastore
* @author Edward Hartwell Goose
*
*/
public class DatastoreManager {
private static final String COUNTER_NAMES_SHARD = "CounterNamesShard";
private static final Logger _logger = Logger.getLogger(DatastoreManager.class.getName());
public static enum ResultType { ADD_SUCCESS, ADD_FULL, ADD_FAIL };
/**
* Gets or creates an empty CounterNamesShard with the given key
* @param id - the id to turn into a key
* @return - the stored entity, or a newly stored entity
*/
public static Entity getOrInsertCounterNamesShard(long id) {
try {
Key key = KeyFactory.createKey(COUNTER_NAMES_SHARD, id);
return getOrInsertCounterNamesShard(key);
} catch (Exception e) {
_logger.severe("Unexpected failure: " + e);
return null;
}
}
/**
* Gets or creates an empty CounterNamesShard with the given key
* @param key
* @return - the stored entity, or a newly stored entity
*/
public static Entity getOrInsertCounterNamesShard(Key key) {
DatastoreService datastoreService = DatastoreServiceFactory.getDatastoreService();
try {
Entity entity = datastoreService.get(key);
_logger.info("Got entity: " + entity);
return entity;
} catch (EntityNotFoundException e) {
//if the entity doesn't exist, create it
_logger.info("Entity doesn't exist, creating and inserting");
Entity entity = new Entity(key);
entity.setUnindexedProperty("names", new ArrayList<String>());
entity.setProperty("timestamp", new Date());
datastoreService.put(entity);
return entity;
}
}
/**
* Stores an entity containing the names of all the counters we know about
* @param id - the id of the shard
* @param names - the list of names to store
* @return - a ResultType enum indicating the level of success/failure
*/
public static ResultType addNames(long id, Set<String> names) {
Key key = KeyFactory.createKey(COUNTER_NAMES_SHARD, id);
_logger.info("Key to add names for: " + key);
DatastoreService datastoreService = DatastoreServiceFactory.getDatastoreService();
Transaction txn = datastoreService.beginTransaction();
try {
Entity entity = datastoreService.get(txn, key);
@SuppressWarnings("unchecked")
List<String> localNames = (List<String>) entity.getProperty("names");
if (null == localNames) {
_logger.info("names property is null. Creating new names property list");
localNames = new ArrayList<String>();
}
Set<String> localNamesSet = new HashSet<String>(localNames);
for (String name : names) {
if (!localNamesSet.contains(name)) {
localNamesSet.add(name);
}
}
localNames = new ArrayList<String>(localNamesSet);
try {
entity.setProperty("names", localNames);
datastoreService.put(txn, entity);
txn.commit();
return ResultType.ADD_SUCCESS;
} catch (Exception e) {
_logger.warning("Failure to save entity with names: " + e);
if (localNames.size() >= 5000) { //python has an error about size, but we'll just artificially limit it to 1000 here
return ResultType.ADD_FULL;
} else {
return ResultType.ADD_FAIL;
}
}
} catch (Exception e) {
return ResultType.ADD_FAIL;
} finally {
if (txn.isActive()) {
_logger.info("Rolling back transaction");
txn.rollback();
}
}
}
}