Skip to content
This repository has been archived by the owner on Dec 16, 2021. It is now read-only.

Refactored datastore session classes #112

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,18 @@

package com.google.cloud.runtimes.tomcat.session;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.Session;
import org.apache.catalina.Store;
import org.apache.catalina.StoreManager;
import org.apache.catalina.session.ManagerBase;
import org.apache.catalina.session.StandardSession;
import org.apache.catalina.session.StoreBase;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;


/**
* Implementation of the {@code org.apache.catalina.Manager} interface which uses
* Google Datastore to share sessions across nodes.
*
* <p>This manager should be used in conjunction with {@link DatastoreValve} and can be used
* with {@link DatastoreStore}.<br/>
* <p>This manager should be used in conjunction with {@link KeyValuePersistentValve} and can be
* used with {@link DatastoreStore}.<br/>
* Example configuration:</p>
*
* <pre>
* {@code
* <Valve className="com.google.cloud.runtimes.tomcat.session.DatastoreValve" />
* <Valve className="com.google.cloud.runtimes.tomcat.session.KeyValuePersistentValve" />
* <Manager className="com.google.cloud.runtimes.tomcat.session.DatastoreManager" >
* <Store className="com.google.cloud.runtimes.tomcat.session.DatastoreStore" />
* </Manager>
Expand All @@ -53,179 +36,10 @@
*
* <p>The sessions is never stored locally and is always fetched from the Datastore.</p>
*/
public class DatastoreManager extends ManagerBase implements StoreManager {

private static final Log log = LogFactory.getLog(DatastoreManager.class);

/**
* The store will be in charge of all the interactions with the Datastore.
*/
protected Store store = null;

/**
* {@inheritDoc}
*
* <p>Ensure that a store is present and initialized.</p>
*
* @throws LifecycleException If an error occurs during the store initialization
*/
@Override
protected synchronized void startInternal() throws LifecycleException {
super.startInternal();
public class DatastoreManager extends KeyValuePersistentManager<DatastoreSession> {

if (store == null) {
throw new LifecycleException("No Store configured, persistence disabled");
} else if (store instanceof Lifecycle) {
((Lifecycle) store).start();
}

setState(LifecycleState.STARTING);
}

/**
* Search in the store for an existing session with the specified id.
*
* @param id The session id for the session to be returned
* @return The request session or null if a session with the requested ID could not be found
* @throws IOException If an input/output error occurs while processing this request
*/
@Override
public Session findSession(String id) throws IOException {
log.debug("Datastore manager is loading session: " + id);
Session session = null;

try {
session = this.getStore().load(id);
} catch (ClassNotFoundException ex) {
log.warn("An error occurred during session deserialization", ex);
}

return session;
}

/**
* {@inheritDoc}
*
* <p>Note: Sessions are loaded at each request therefore no session is loaded at
* initialization.</p>
*
* @throws ClassNotFoundException Cannot occurs
* @throws IOException Cannot occurs
*/
@Override
public void load() throws ClassNotFoundException, IOException {}

/**
* {@inheritDoc}
*
* <p>Note: Sessions are persisted after each requests but never saved into the local manager,
* therefore no operation is needed during unload.</p>
*
* @throws IOException Cannot occurs
*/
@Override
public void unload() throws IOException {}

/**
* Remove the Session from the manager but not from the Datastore.
*
* @param session The session to remove.
*/
@Override
public void removeSuper(Session session) {
super.remove(session);
}

/**
* Remove this Session from the active Sessions and the Datastore.
*
* @param session The session to remove.
*/
@Override
public void remove(Session session) {
this.removeSuper(session);

try {
store.remove(session.getId());
} catch (IOException e) {
log.error("An error occurred while removing session with id: " + session.getId(), e);
}
}

/**
* Returns the number of sessions present in the Store.
*
* <p>Note: Aggregation can be slow on the Datastore, cache the result if possible</p>
*
* @return the session count.
*/
@Override
public int getActiveSessionsFull() {
int sessionCount = 0;
try {
sessionCount = store.getSize();
} catch (IOException e) {
log.error("An error occurred while counting sessions: ", e);
}

return sessionCount;
}

/**
* Returns a set of all sessions IDs or null if an error occurs.
*
* <p>Note: Listing all the keys can be slow on the Datastore.</p>
*
* @return The complete set of sessions IDs across the cluster.
*/
@Override
public Set<String> getSessionIdsFull() {
Set<String> sessionsId = null;
try {
String[] keys = this.store.keys();
sessionsId = new HashSet<>(Arrays.asList(keys));
} catch (IOException e) {
log.error("An error occurred while listing active sessions: ", e);
}

return sessionsId;
}

@Override
protected void stopInternal() throws LifecycleException {
super.stopInternal();

if (store instanceof Lifecycle) {
((Lifecycle) store).stop();
}

setState(LifecycleState.STOPPING);
}

@Override
public void processExpires() {
log.debug("Processing expired sessions");
if (store instanceof StoreBase) {
((StoreBase) store).processExpires();
}
}

@Override
protected StandardSession getNewSession() {
protected DatastoreSession getNewSession() {
return new DatastoreSession(this);
}

public Store getStore() {
return this.store;
}

/**
* The store will be injected by Tomcat on startup.
*
* <p>See distributed-sessions.xml for the configuration.</p>
*/
public void setStore(Store store) {
this.store = store;
store.setManager(this);
}
}
Loading