package com.anjlab.ping.services.dao.impl.cache; import static com.anjlab.ping.services.dao.impl.cache.CacheHelper.getEntityCacheKey; import static com.anjlab.ping.services.dao.impl.cache.CacheHelper.getQueryCacheKey; import java.util.ArrayList; import java.util.List; import javax.cache.Cache; import org.apache.tapestry5.ioc.annotations.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.anjlab.ping.entities.Job; import com.anjlab.ping.services.Utils; import com.anjlab.ping.services.dao.impl.JobDAOImpl; import com.google.appengine.api.datastore.Key; // TODO Rewrite with AOP public class JobDAOImplCache extends JobDAOImpl { private static final Logger logger = LoggerFactory.getLogger(JobDAOImplCache.class); @Inject private Cache cache; public JobDAOImplCache() { } public JobDAOImplCache(Cache cache) { this.cache = cache; } @Override public Job delete(Long id) { Job job = super.delete(id); Object entityCacheKey = getEntityCacheKey(Job.class, getJobWideUniqueData(id)); cache.remove(entityCacheKey); if (job != null) { abandonJobCaches(job); } return job; } @SuppressWarnings("unchecked") @Override public Job find(Key jobKey) { Object entityCacheKey = getEntityCacheKey(Job.class, getJobWideUniqueData(jobKey)); Job result = (Job) cache.get(entityCacheKey); if (result != null) { return result; } result = super.find(jobKey); if (result != null) { cache.put(entityCacheKey, result); } return result; } private String getJobWideUniqueData(Key jobKey) { Long[] parts = Utils.createJobContext(jobKey); return getJobWideUniqueData(parts[0]); } private String getJobWideUniqueData(Long id) { return "" + id; } @SuppressWarnings("unchecked") @Override public Job find(Long id) { Object entityCacheKey = getEntityCacheKey(Job.class, getJobWideUniqueData(id)); Job result = (Job) cache.get(entityCacheKey); if (result != null) { return result; } result = super.find(id); if (result != null) { cache.put(entityCacheKey, result); } return result; } @SuppressWarnings("unchecked") @Override public void onAfterCommitNewJob(Job job) { logger.info("New job created: {} ({})", job.getPingURL(), job.getKey()); Object entityCacheKey = getEntityCacheKey(Job.class, getJobWideUniqueData(job.getKey())); cache.put(entityCacheKey, job); abandonJobsByCronStringQueryCache(job.getCronString()); abandonJobsByScheduleNameQueryCache(job.getScheduleName()); abandonJobsByPingUrlQueryCache(job.getPingURL()); } @SuppressWarnings("unchecked") @Override public void update(Job job, boolean commitAfter) { super.update(job, commitAfter); Object entityCacheKey = getEntityCacheKey(Job.class, getJobWideUniqueData(job.getKey())); Job cachedJob = (Job)cache.get(entityCacheKey); if (cachedJob != null) { if (!Utils.equals(cachedJob.getCronString(), job.getCronString())) { abandonJobsByCronStringQueryCache(cachedJob.getCronString()); abandonJobsByCronStringQueryCache(job.getCronString()); } if (!Utils.equals(cachedJob.getScheduleName(), job.getScheduleName())) { abandonJobsByScheduleNameQueryCache(cachedJob.getScheduleName()); abandonJobsByScheduleNameQueryCache(job.getScheduleName()); } if (!Utils.equals(cachedJob.getPingURL(), job.getPingURL())) { abandonJobsByPingUrlQueryCache(cachedJob.getPingURL()); abandonJobsByPingUrlQueryCache(job.getPingURL()); } updateJobInAllQueries(job); cache.put(entityCacheKey, job); } else { abandonJobCaches(job); } } private void updateJobInAllQueries(Job job) { // TODO Write update abandonJobCaches(job); } private void abandonJobCaches(Job job) { abandonJobsByCronStringQueryCache(job.getCronString()); abandonJobsByScheduleNameQueryCache(job.getScheduleName()); abandonJobsByPingUrlQueryCache(job.getPingURL()); } @SuppressWarnings("unchecked") @Override public List<Key> getJobsByCronString(String cronString) { Object entityCacheKey = getQueryCacheKey(Job.class, cronString); List<Key> result = (List<Key>) cache.get(entityCacheKey); if (result != null) { return result; } result = super.getJobsByCronString(cronString); if (result != null) { ArrayList<Key> serializableList = new ArrayList<Key>(result.subList(0, result.size())); cache.put(entityCacheKey, serializableList); } return result; } @SuppressWarnings("unchecked") @Override public List<Job> findByPingURL(String pingURL) { Object entityCacheKey = getQueryCacheKey(Job.class, pingURL); List<Job> result = (List<Job>) cache.get(entityCacheKey); if (result != null) { return result; } result = super.findByPingURL(pingURL); if (result != null) { ArrayList<Job> serializableList = new ArrayList<Job>(result.subList(0, result.size())); cache.put(entityCacheKey, serializableList); } return result; } private void abandonJobsByPingUrlQueryCache(String pingUrl) { Object entityCacheKey = getQueryCacheKey(Job.class, pingUrl); cache.remove(entityCacheKey); } private void abandonJobsByScheduleNameQueryCache(String scheduleName) { Object entityCacheKey = getQueryCacheKey(Job.class, scheduleName); cache.remove(entityCacheKey); } @SuppressWarnings("unchecked") @Override public List<Job> findByScheduleName(String scheduleName) { Object entityCacheKey = getQueryCacheKey(Job.class, scheduleName); List<Job> result = (List<Job>) cache.get(entityCacheKey); if (result != null) { return result; } result = super.findByScheduleName(scheduleName); if (result != null) { ArrayList<Job> serializableList = new ArrayList<Job>(result.subList(0, result.size())); cache.put(entityCacheKey, serializableList); } return result; } private void abandonJobsByCronStringQueryCache(String cronString) { Object entityCacheKey = getQueryCacheKey(Job.class, cronString); cache.remove(entityCacheKey); } }