/*
* Copyright 2010-2016 Amazon.com, Inc. or its affiliates. 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.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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.amazonaws.mobileconnectors.pinpoint.analytics;
import com.amazonaws.mobileconnectors.pinpoint.internal.core.PinpointContext;
import com.amazonaws.mobileconnectors.pinpoint.targeting.TargetingClient;
import org.apache.commons.logging.LogFactory;
import static com.amazonaws.mobileconnectors.pinpoint.internal.core.util.Preconditions.checkNotNull;
public class SessionClient {
private static final org.apache.commons.logging.Log log =
LogFactory.getLog(SessionClient.class);
// ~ Event Type Constants ---------------------------=
public static final String SESSION_START_EVENT_TYPE = "_session.start";
public static final String SESSION_STOP_EVENT_TYPE = "_session.stop";
public static final String SESSION_PAUSE_EVENT_TYPE = "_session.pause";
public static final String SESSION_RESUME_EVENT_TYPE = "_session.resume";
// - Session Timer Constants ------------------------=
protected static final long DEFAULT_RESUME_DELAY = (long) 5e3;
protected static final long DEFAULT_RESTART_DELAY = (long) 30e3;
protected static final String RESUME_DELAY_CONFIG_KEY = "sessionResumeDelay";
protected static final String RESTART_DELAY_CONFIG_KEY = "sessionRestartDelay";
protected static final String NO_SESSION_ID = "00000000-00000000";
protected static final String SHARED_PREFS_SESSION_KEY = "AWSPinpoint.Session";
protected final PinpointContext pinpointContext;
protected Session session;
private final long resumeDelay;
private final long restartDelay;
/**
* CONSTRUCTOR
*
* @param pinpointContext
*/
public SessionClient(final PinpointContext pinpointContext) {
checkNotNull(pinpointContext, "A valid InsightsContext must be provided!");
checkNotNull(pinpointContext.getAnalyticsClient(), "A valid AnalyticsClient must be provided!");
this.pinpointContext = pinpointContext;
String sessionString = pinpointContext.getSystem().getPreferences().getString(SHARED_PREFS_SESSION_KEY, null);
if (sessionString != null) {
this.session = Session.getSessionFromSerializedSession(sessionString);
}
if (session != null) {
pinpointContext.getAnalyticsClient().setSessionId(session.getSessionID());
pinpointContext.getAnalyticsClient().setSessionStartTime(session.getStartTime());
} else {
if (pinpointContext.getPinpointConfiguration().getEnableTargeting()) {
pinpointContext.getAnalyticsClient().setSessionId(NO_SESSION_ID);
pinpointContext.getAnalyticsClient().setSessionStartTime(0);
}
}
this.restartDelay = pinpointContext.getConfiguration().optLong(RESTART_DELAY_CONFIG_KEY,
DEFAULT_RESTART_DELAY);
this.resumeDelay = pinpointContext.getConfiguration().optLong(RESUME_DELAY_CONFIG_KEY,
DEFAULT_RESUME_DELAY);
}
/**
* Starts an application session Used solely by Amazon Insights
*/
public synchronized void startSession() {
executeStop();
executeStart();
}
/**
* Stops an application session Used solely by Amazon Insights
*/
public synchronized void stopSession() {
executeStop();
}
/**
* Briefly pauses an application session. Should be called in an activity's
* onPause() method.
*/
public synchronized void pauseSession() {
if(getSessionState().equals(SessionState.ACTIVE)) {
executePause();
}
}
/**
* Resumes an application session if the session has been paused within a
* defined time interval. Otherwise, stops the old session and starts a new
* one. Should be called in an activity's onResume() method.
*/
public synchronized void resumeSession() {
if(getSessionState().equals(SessionState.PAUSED)) {
executeResume();
} else{
AnalyticsEvent e = this.pinpointContext.getAnalyticsClient()
.createEvent(SESSION_RESUME_EVENT_TYPE);
this.pinpointContext.getAnalyticsClient().recordEvent(e);
// log failure
log.info("Session Resume Failed: No session is paused.");
}
}
/**
* Overridden toString method for testing
*
* @return diagnostic string
*/
public String toString() {
return "[SessionClient]\n"
+ "- session: "
+ ((this.session == null) ? "<null>" : this.session.getSessionID())
+ ((this.session != null && this.session.isPaused()) ? ": paused" : "");
}
// - Implementations --------------------------------=
protected void executeStart() {
if (this.pinpointContext.getTargetingClient() != null) {
this.pinpointContext.getTargetingClient().updateEndpointProfile();
}
session = Session.newInstance(pinpointContext);
// Enable event tagging
this.pinpointContext.getAnalyticsClient().setSessionId(session.getSessionID());
this.pinpointContext.getAnalyticsClient().setSessionStartTime(session.getStartTime());
// Fire Session Start Event
log.info("Firing Session Event: " + SESSION_START_EVENT_TYPE);
AnalyticsEvent e = this.pinpointContext.getAnalyticsClient()
.createEvent(SESSION_START_EVENT_TYPE);
this.pinpointContext.getAnalyticsClient().recordEvent(e);
}
protected void executeStop() {
//No session to stop
if(session == null){
log.info("Session Stop Failed: No session exists.");
return;
}
// Fire Session Stop Event
// pause the session if it's not already
if (!session.isPaused()) {
session.pause();
}
log.info("Firing Session Event: " + SESSION_STOP_EVENT_TYPE);
Long stopTime = session.getStopTime() == null ? 0L : session.getStopTime();
AnalyticsEvent e = this.pinpointContext.getAnalyticsClient().createEvent(
SESSION_STOP_EVENT_TYPE, session.getStartTime(),
stopTime, session.getSessionDuration());
this.pinpointContext.getAnalyticsClient().recordEvent(e);
// clear the global campaign attributes.
this.pinpointContext.getAnalyticsClient().clearCampaignAttributes();
// Kill Session Object
session = null;
}
/**
* - Pause the current session object - Fire a Session Pause Event - Persist
* Session to the file system. (prepares for quiet death)
*/
protected void executePause() {
//No session to pause
if(session == null){
log.info("Session Stop Failed: No session exists.");
return;
}
// Set session paused
session.pause();
log.debug("Session Paused: " + session.getSessionID());
// - Fire Session Pause Event ----------------------------=
log.info("Firing Session Event: " + SESSION_PAUSE_EVENT_TYPE);
AnalyticsEvent e = this.pinpointContext.getAnalyticsClient().createEvent(
SESSION_PAUSE_EVENT_TYPE, session.getStartTime(), null,
session.getSessionDuration());
this.pinpointContext.getAnalyticsClient().recordEvent(e);
// Store session to file system
pinpointContext.getSystem().getPreferences().putString(SHARED_PREFS_SESSION_KEY, this.session.toString());
}
/**
* - Re-Activate the session - Fire Session Resume Event
*/
protected void executeResume() {
//No session to resume
if(session == null){
return;
}
// set session active
session.resume();
// Fire Session Resume Event
log.debug("Firing Session Event: " + SESSION_RESUME_EVENT_TYPE);
AnalyticsEvent e = this.pinpointContext.getAnalyticsClient()
.createEvent(SESSION_RESUME_EVENT_TYPE);
this.pinpointContext.getAnalyticsClient().recordEvent(e);
// log success
log.info("Session Resumed: " + session.getSessionID());
}
/**
* Getters
*/
protected Session getSession() {
return this.session;
}
public long getRestartDelay() {
return this.restartDelay;
}
public long getResumeDelay() {
return this.resumeDelay;
}
/**
* Internal Representation of Application Session's state
*/
protected static enum SessionState {
INACTIVE,
ACTIVE,
PAUSED
}
/**
* Returns the Application Session's state
*/
protected SessionState getSessionState() {
if (this.session != null) {
return (this.session.isPaused() ? SessionState.PAUSED : SessionState.ACTIVE);
}
return SessionState.INACTIVE;
}
}