Java tutorial
/* * Copyright 2011 Google Inc. All Rights Reserved. * * 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.google.sampling.experiential.model; import java.nio.charset.Charset; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; import javax.jdo.annotations.Extension; import javax.jdo.annotations.IdGeneratorStrategy; import javax.jdo.annotations.IdentityType; import javax.jdo.annotations.PersistenceCapable; import javax.jdo.annotations.Persistent; import javax.jdo.annotations.PrimaryKey; import org.apache.commons.codec.binary.Hex; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.sampling.experiential.server.EventServlet; import com.google.sampling.experiential.shared.TimeUtil; /** * Class that holds a response to an experiment. * * @author Bob Evans * */ @PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true") public class Event { private static final long serialVersionUID = -1407635488794262589l; public static final String SALT = "zyzzyfoo"; public static final List<String> eventProperties = Lists.newArrayList("who", "lat", "lon", "when", "appId", "experimentId", "experimentName", "responseTime", "scheduledTime", "experimentGroupName", "actionTriggerId", "actionTriggerSpecId", "actionId"); @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Long id; @Persistent private String who; @Persistent private String lat; @Persistent private String lon; @Persistent private Date when; @Persistent private String appId; @Persistent private String pacoVersion; @Persistent private String experimentName; @Persistent private String experimentId; @Persistent private Integer experimentVersion; @Persistent private Date scheduledTime; @Persistent private Date responseTime; @Persistent private String experimentGroupName; @Persistent private Long actionTriggerId; @Persistent private Long actionTriggerSpecId; @Persistent private Long actionId; @Persistent @Extension(vendorName = "datanucleus", key = "gae.unindexed", value = "true") private Set<What> what; @Persistent @Extension(vendorName = "datanucleus", key = "gae.unindexed", value = "true") private List<String> keysList; @Persistent @Extension(vendorName = "datanucleus", key = "gae.unindexed", value = "true") private List<String> valuesList; @Persistent private Boolean shared = false; @Persistent private List<PhotoBlob> blobs; @Persistent private String timeZone; public boolean isShared() { if (shared == null) { shared = true; } return shared; } public void setShared(boolean shared) { this.shared = shared; } public Event(String who, String lat, String lon, Date when, String appId, String pacoVersion, Set<What> what, boolean shared, String experimentId, String experimentName, Integer experimentVersion, Date responseTime, Date scheduledTime, List<PhotoBlob> blobs, String timezone, String groupName, Long actionTriggerId2, Long actionTriggerSpecId2, Long actionId2) { super(); if (/*what.size() == 0 || */who == null || when == null) { throw new IllegalArgumentException("There must be a who and a when"); } this.who = who; this.lat = lat; this.lon = lon; this.when = when; this.what = what; setWhatMap(what); this.appId = appId; this.pacoVersion = Strings.isNullOrEmpty(pacoVersion) ? "1" : pacoVersion; this.shared = shared; this.experimentId = experimentId; this.experimentName = experimentName; this.experimentVersion = experimentVersion; this.responseTime = responseTime; this.scheduledTime = scheduledTime; if (blobs != null) { this.blobs = blobs; } this.timeZone = timezone; this.experimentGroupName = groupName; this.actionTriggerId = actionTriggerId2; this.actionTriggerSpecId = actionTriggerSpecId2; this.actionId = actionId2; } private void setWhatMap(Set<What> whats) { this.keysList = Lists.newArrayList(); this.valuesList = Lists.newArrayList(); if (what == null) { return; } for (What what : whats) { keysList.add(what.getName()); valuesList.add(what.getValue()); } } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getWho() { return who; } public void setWho(String who) { this.who = who; } public String getLat() { return lat; } public void setLat(String lat) { this.lat = lat; } public String getLon() { return lon; } public void setLon(String lon) { this.lon = lon; } public Date getWhen() { return when; } public void setWhen(Date when) { this.when = when; } public Set<What> getWhat() { return what; } public void setWhat(Set<What> what) { this.what = what; setWhatMap(what); } public String getExperimentName() { return experimentName; } public void setExperimentName(String experimentName) { this.experimentName = experimentName; } public String getExperimentId() { return experimentId; } public void setExperimentId(String experimentId) { this.experimentId = experimentId; } public Date getScheduledTime() { return scheduledTime; } public void setScheduledTime(Date scheduledTime) { this.scheduledTime = scheduledTime; } public Date getResponseTime() { return responseTime; } public void setResponseTime(Date responseTime) { this.responseTime = responseTime; } private String getValueForKey(String key) { int index = keysList.indexOf(key); if (index == -1) { return null; } return valuesList.get(index); } public String getWhatByKey(String key) { return getValueForKey(key); } public String getAppId() { return appId; } public void setAppId(String appId) { this.appId = appId; } public String getPacoVersion() { return pacoVersion; } public void setPacoVersion(String pacoVersion) { this.pacoVersion = pacoVersion; } public List<String> getWhatKeys() { return keysList; } public List<PhotoBlob> getBlobs() { return blobs; } public void setBlobs(List<PhotoBlob> blobs) { this.blobs = blobs; } public Map<String, String> getWhatMap() { Map<String, String> map = Maps.newHashMap(); if (keysList == null) { keysList = Lists.newArrayList(); } for (int i = 0; i < keysList.size(); i++) { String keyName = keysList.get(i); if (keyName == null || keyName.length() == 0) { keyName = "unknown_" + i; } map.put(keyName, valuesList.get(i)); } return map; } public String[] toCSV(List<String> columnNames, boolean anon) { DateTimeFormatter jodaTimeFormatter = DateTimeFormat.forPattern(TimeUtil.DATETIME_FORMAT); int csvIndex = 0; String[] parts = new String[10 + columnNames.size()]; if (anon) { parts[csvIndex++] = Event.getAnonymousId(who + SALT); } else { parts[csvIndex++] = who; } parts[csvIndex++] = jodaTimeFormatter.print(new DateTime(when.getTime())); parts[csvIndex++] = appId; parts[csvIndex++] = pacoVersion; parts[csvIndex++] = experimentId; parts[csvIndex++] = experimentName; parts[csvIndex++] = experimentVersion != null ? Integer.toString(experimentVersion) : "0"; parts[csvIndex++] = responseTime != null ? jodaTimeFormatter.print(getResponseTimeWithTimeZone(null)) : null; parts[csvIndex++] = scheduledTime != null ? jodaTimeFormatter.print(getScheduledTimeWithTimeZone(null)) : null; parts[csvIndex++] = timeZone; Map<String, String> whatMap = getWhatMap(); for (String key : columnNames) { String value = whatMap.get(key); parts[csvIndex++] = value; } return parts; } public String toString() { java.text.SimpleDateFormat simpleDateFormat = new java.text.SimpleDateFormat(TimeUtil.DATETIME_FORMAT); java.text.SimpleDateFormat simpleDateFormatWithMs = new java.text.SimpleDateFormat( TimeUtil.DATETIME_FORMAT_WITH_MS); StringBuilder buf = new StringBuilder(); buf.append(who).append("\n"); //TODO better way to handle the formatting issue // Must make sure, when is holding a datetime with milliseconds and then just go with one consistent formatter try { buf.append(simpleDateFormat.format(when)).append("\n"); } catch (Exception e) { try { buf.append(simpleDateFormatWithMs.format(when)).append("\n"); } catch (Exception e1) { buf.append(when).append("\n"); } } buf.append(experimentId).append("\n"); buf.append(experimentName).append("\n"); buf.append(responseTime != null ? simpleDateFormat.format(getResponseTimeWithTimeZone(null)) : null) .append("\n"); buf.append(scheduledTime != null ? simpleDateFormat.format(getScheduledTimeWithTimeZone(null)) : null) .append("\n"); Map<String, String> whatMap = getWhatMap(); for (String key : whatMap.keySet()) { String value = whatMap.get(key); buf.append(key).append("=").append(value).append("\n"); } return buf.toString(); } public boolean isJoined() { return getWhatByKey("joined") != null; } public static String getAnonymousId(String who) { MessageDigest messageDigest = null; try { messageDigest = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { //Log.info("Could not get MD5 algorithm"); return null; } messageDigest.reset(); messageDigest.update(who.getBytes(Charset.forName("UTF8"))); byte[] resultByte = messageDigest.digest(); return new String(Hex.encodeHex(resultByte)); } public Integer getExperimentVersion() { return experimentVersion; } public void setExperimentVersion(Integer experimentVersion) { this.experimentVersion = experimentVersion; } public String getTimeZone() { return timeZone; } public void setTimeZone(String timeZone) { this.timeZone = timeZone; } public DateTime getScheduledTimeWithTimeZone(String defaultTimeZone) { DateTime timeZoneAdjustedDate = getTimeZoneAdjustedDate(getScheduledTime(), defaultTimeZone); return timeZoneAdjustedDate == null ? null : timeZoneAdjustedDate; } public DateTime getResponseTimeWithTimeZone(String defaultTimeZone) { DateTime timeZoneAdjustedDate = getTimeZoneAdjustedDate(getResponseTime(), defaultTimeZone); return timeZoneAdjustedDate == null ? null : timeZoneAdjustedDate; } public DateTime getTimeZoneAdjustedDate(Date time, String defaultTimeZone) { return getTimeZoneAdjustedDate(time, defaultTimeZone, getTimeZone()); } public static DateTime getTimeZoneAdjustedDate(Date time, String defaultTimeZone, String timeZone) { if (time == null) { return null; } if (Strings.isNullOrEmpty(timeZone)) { if (Strings.isNullOrEmpty(defaultTimeZone)) { return new DateTime(time); } else { DateTimeZone timezoneForOffsetHours = DateTimeZone.forID(defaultTimeZone); if (timezoneForOffsetHours == null) { return new DateTime(time); } return new DateTime(time).withZone(timezoneForOffsetHours); } } else { String hours = timeZone.substring(0, 3); if (hours.startsWith("+")) { hours = hours.substring(1); } int parseInt; try { parseInt = Integer.parseInt(hours); } catch (NumberFormatException e) { EventServlet.log.info("Timezone hours are not an integer this event: " + hours); return new DateTime(time); } DateTimeZone timezoneForOffsetHours = DateTimeZone.forOffsetHours(parseInt); if (timezoneForOffsetHours == null) { return new DateTime(time); } return new DateTime(time).withZone(timezoneForOffsetHours); } } public String getExperimentGroupName() { return experimentGroupName; } public void setExperimentGroupName(String experimentGroupName) { this.experimentGroupName = experimentGroupName; } public Long getActionTriggerId() { return actionTriggerId; } public void setActionTriggerId(Long actionTriggerId) { this.actionTriggerId = actionTriggerId; } public Long getActionTriggerSpecId() { return actionTriggerSpecId; } public void setActionTriggerSpecId(Long actionTriggerSpecId) { this.actionTriggerSpecId = actionTriggerSpecId; } public Long getActionId() { return actionId; } public void setActionId(Long actionId) { this.actionId = actionId; } }