package com.anjlab.ping.pages.report;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.tapestry5.annotations.BeforeRenderTemplate;
import org.apache.tapestry5.annotations.Component;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.beaneditor.BeanModel;
import org.apache.tapestry5.corelib.components.Grid;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.BeanModelSource;
import com.anjlab.ping.entities.Job;
import com.anjlab.ping.services.Application;
import com.anjlab.ping.services.Utils;
import com.anjlab.ping.services.dao.AccountDAO;
import com.anjlab.ping.services.dao.JobDAO;
import com.anjlab.tapestry5.AbstractReadonlyPropertyConduit;
public class JobsReport {
@SuppressWarnings("unused")
@Property
private Map.Entry<?, ?> entry;
@Property
private Job job;
@Inject
private AccountDAO accountDAO;
@Inject
private JobDAO jobDAO;
private List<Job> jobs;
public List<Job> getJobs() {
if (jobs == null) {
// java.lang.UnsupportedOperationException: This operation is not supported on Query Results
// at org.datanucleus.store.query.AbstractQueryResult.contains(AbstractQueryResult.java:250)
// at java.util.AbstractCollection.removeAll(AbstractCollection.java:353)
List<Job> dbJobs = jobDAO.getAll();
jobs = new ArrayList<Job>();
jobs.addAll(dbJobs);
}
return jobs;
}
private int counter = 0;
@Component(id="grid")
private Grid grid;
@BeforeRenderTemplate
void beforeRender() {
if (grid.getSortModel().getSortConstraints().isEmpty()) {
// ascending
grid.getSortModel().updateSort("createdAt");
// descending
grid.getSortModel().updateSort("createdAt");
}
}
@Inject private BeanModelSource beanModelSource;
@Inject private Messages messages;
public BeanModel<?> getModel() {
BeanModel<?> beanModel = beanModelSource.createDisplayModel(Job.class, messages);
beanModel.exclude("createdAt",
"lastBackupTimestamp",
"cronString",
"recentAvailabilityPercent",
"totalAvailabilityPercent");
beanModel.add("recentAvailabilityPercent", new AbstractReadonlyPropertyConduit()
{
@Override
public Object get(Object instance) {
return ((Job) instance).getRecentAvailabilityPercentFriendly().replace("%", "");
}
});
beanModel.add("totalAvailabilityPercent", new AbstractReadonlyPropertyConduit()
{
@Override
public Object get(Object instance) {
return ((Job) instance).getTotalAvailabilityPercentFriendly().replace("%", "");
}
});
beanModel.add("cronString", new AbstractReadonlyPropertyConduit()
{
@Override
public Object get(Object instance) {
Job job = (Job) instance;
return job.isSuspended()
? "suspended"
: job.getCronString().replace("every ", "")
.replace(" hours", "h")
.replace(" minutes", "m");
}
});
beanModel.add("lastBackupTimestamp", new AbstractReadonlyPropertyConduit()
{
@Override
public Object get(Object instance) {
Date date = ((Job) instance).getLastBackupTimestamp();
return date == null ? null : Application.DATETIME_FORMAT.format(date);
}
});
beanModel.add("createdAt", new AbstractReadonlyPropertyConduit()
{
@Override
public Object get(Object instance) {
Date date = ((Job) instance).getCreatedAt();
return date == null ? null : Application.DATETIME_FORMAT.format(date);
}
});
beanModel.add("userLastVisit", new AbstractReadonlyPropertyConduit()
{
@Override
public Object get(Object instance) {
Date date = accountDAO.getAccount(((Job) instance).getScheduleName()).getLastVisitDate();
return date == null ? null : Application.DATETIME_FORMAT.format(date);
}
});
beanModel.add("SN", new AbstractReadonlyPropertyConduit()
{
@Override
public Object get(Object instance) {
return ++counter;
}
}).sortable(false);
beanModel.add("analytics", null);
beanModel.add("details", null);
beanModel.exclude(
"lastPingDetails",
"lastPingFailed",
"lastPingResult",
"usesValidatingRegexp",
"usesValidatingHttpCode",
"validatingRegexp",
"validatingHttpCode",
"responseEncoding",
"shortenUrl",
"title",
"pingURL",
"statusCounter",
"statusCounterFriendlyShort",
"upDownTimeInMinutes",
"previousStatusCounter",
"totalStatusCounter",
"totalSuccessStatusCounter",
"totalAvailabilityPercentFriendly",
"recentAvailabilityPercentFriendly",
"lastPingTimestamp",
"validationSummary",
"reportEmail",
"statusCounterFriendly",
"previousStatusCounterFriendly",
"googleIOException",
"totalStatusCounterFriendly",
"totalSuccessStatusCounterFriendly",
"healthStatus",
"lastPingWasTooLongAgo",
"suspended",
"suspendReason",
"suspendedBy",
"suspendedAt",
"modifiedAt",
"modifiedBy",
"scheduleName",
"estimatedSerializedSize");
beanModel.reorder(
"SN",
"cronString",
"titleFriendly",
"lastPingSummary",
"recentAvailabilityPercent",
"totalAvailabilityPercent",
"scheduledBy",
"userLastVisit",
"createdAt",
"resultsCount");
return beanModel;
}
public Long[] getJobContext() {
return Utils.createJobContext(job);
}
public String getSummaryStatusCssClass() {
if (job.isGoogleIOException()) {
return "status-warning";
}
if (job.isLastPingFailed()) {
return "status-error";
}
if (job.getTotalStatusCounter() == 0) {
return "status-na";
}
return "status-okay";
}
public String getLastPingTimestamp() {
return Utils.formatTime(job.getLastPingTimestamp());
}
public String getLastBackupTimestampFriendly() {
return Utils.getTimeAgoUpToDays(job.getLastBackupTimestamp());
}
public String getCreatedAtFriendly() {
return Utils.getTimeAgoUpToDays(job.getCreatedAt());
}
public String getUserLastVisitFriendly() {
return Utils.getTimeAgoUpToDays(accountDAO.getAccount(job.getScheduleName()).getLastVisitDate());
}
public String getLastBackupTimestamp() {
return Utils.formatTime(job.getLastBackupTimestamp());
}
public String getCreatedAt() {
return Utils.formatTime(job.getCreatedAt());
}
public String getUserLastVisit() {
return Utils.formatTime(accountDAO.getAccount(job.getScheduleName()).getLastVisitDate());
}
private Map<String, Integer> countersByAccount;
public Map<String, Integer> getCountersByAccount() {
if (countersByAccount == null) {
countersByAccount = new HashMap<String, Integer>();
for (Job job : getJobs()) {
String account = job.getScheduledBy();
Integer count = countersByAccount.get(account);
if (count == null) {
count = 0;
}
count++;
countersByAccount.put(account, count);
}
}
return countersByAccount;
}
private Map<String, Integer> countersByCronString;
public Map<String, Integer> getCountersByCronString() {
if (countersByCronString == null) {
countersByCronString = new HashMap<String, Integer>();
for (Job job : getJobs()) {
String cronString = job.getCronString();
Integer count = countersByCronString.get(cronString);
if (count == null) {
count = 0;
}
count++;
countersByCronString.put(cronString, count);
}
}
return countersByCronString;
}
private Map<String, Integer> countersByNumberOfJobs;
public Map<String, Integer> getCountersByNumberOfJobs() {
if (countersByNumberOfJobs == null) {
countersByNumberOfJobs = new HashMap<String, Integer>();
for (Entry<?, ?> entry : getCountersByAccount().entrySet()) {
String key = entry.getValue().toString();
Integer count = countersByNumberOfJobs.get(key);
if (count == null) {
count = 0;
}
count++;
countersByNumberOfJobs.put(key, count);
}
}
return countersByNumberOfJobs;
}
private MessageDigest digest;
public MessageDigest getDigest() {
if (digest == null) {
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
return digest;
}
public String md5(String s) {
MessageDigest digest = getDigest();
digest.reset();
digest.update((s.trim().toLowerCase()).getBytes());
return new BigInteger(1, digest.digest()).toString(16);
}
}