Skip to content

Commit

Permalink
Now we serialize all session's attributes as an array of bytes. All s…
Browse files Browse the repository at this point in the history
…ession's attributes have to be serializable in order to be saved to the database properly.
  • Loading branch information
maseev committed Dec 17, 2016
1 parent bb81a04 commit c1c79dc
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

import org.springframework.session.ExpiringSession;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -12,6 +17,7 @@
import java.util.concurrent.TimeUnit;

import javax.persistence.Id;
import javax.persistence.Transient;

public class OrientHttpSession implements ExpiringSession {

Expand All @@ -22,27 +28,33 @@ public class OrientHttpSession implements ExpiringSession {
public static final String MAX_INACTIVE_INTERVAL_IN_SECONDS_PROPERTY =
"maxInactiveIntervalInSeconds";

private static final byte[] ZERO_LENGTH_ARRAY = new byte[0];

@Id
private ORID orid;

private String sessionId;

private Map<String, Object> attributes;

private long creationTime;

private long lastAccessedTime;

private int maxInactiveIntervalInSeconds;

private byte[] serializedAttributes;

@Transient
private Map<String, Serializable> attributes;

public OrientHttpSession() {
serializedAttributes = ZERO_LENGTH_ARRAY;
attributes = new HashMap<>();
}

public OrientHttpSession(final int maxInactiveIntervalInSeconds) {
this();
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
sessionId = UUID.randomUUID().toString();
attributes = new HashMap<>();
creationTime = System.currentTimeMillis();
lastAccessedTime = creationTime;
}
Expand Down Expand Up @@ -104,7 +116,7 @@ public void setAttribute(final String attributeName, final Object attributeValue
removeAttribute(attributeName);
} else {
if (attributeValue instanceof Serializable) {
attributes.put(attributeName, attributeValue);
attributes.put(attributeName, (Serializable) attributeValue);
} else {
final String msg = "%s must implement %s in order to be saved to the database";
throw new IllegalArgumentException(
Expand All @@ -117,4 +129,31 @@ public void setAttribute(final String attributeName, final Object attributeValue
public void removeAttribute(final String attributeName) {
attributes.remove(attributeName);
}

void serializeAttributes() {
if (attributes.isEmpty()) {
return;
}

try (final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(attributes);
serializedAttributes = bos.toByteArray();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}

void deserializeAttributes() {
if (serializedAttributes.length == 0) {
return;
}

try (final ByteArrayInputStream bis = new ByteArrayInputStream(serializedAttributes);
final ObjectInputStream ois = new ObjectInputStream(bis)) {
attributes = (Map<String, Serializable>) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new IllegalArgumentException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,14 @@ public OrientHttpSession getSession(final String id) {
}

session.setLastAccessedTime(System.currentTimeMillis());
session.deserializeAttributes();

return session;
}

@Override
public void save(final OrientHttpSession session) {
session.serializeAttributes();
try (final OObjectDatabaseTx db = new OObjectDatabaseTx(pool.acquire())) {
db.save(session);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.util.concurrent.TimeUnit;

import io.github.maseev.spring.session.orientdb.entity.Person;
import io.github.maseev.spring.session.orientdb.integration.TestConfiguration;

@RunWith(SpringRunner.class)
Expand Down Expand Up @@ -81,4 +82,18 @@ public void flushExpiredSessionsMustDeleteAllExpiredSessions() {

assertThat(repository.getSession(session.getId()), is(equalTo(null)));
}

@Test
public void savingASerializableEntityShouldPass() {
final Person person = new Person("John Doe", 26);
final OrientHttpSession session = repository.createSession();

session.setAttribute("person", person);

repository.save(session);

final OrientHttpSession savedSession = repository.getSession(session.getId());

assertThat(savedSession.getAttribute("person"), is(equalTo(person)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,43 @@
import static org.junit.Assert.assertThat;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.session.SessionRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.concurrent.TimeUnit;

import io.github.maseev.spring.session.orientdb.integration.TestConfiguration;

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = TestConfiguration.class)
public class OrientHttpSessionTest {

@Autowired
private SessionRepository<OrientHttpSession> repository;

@Test
public void getIdMustReturnDifferentIdsForDifferentSessionObjects() {
final int maxInactiveIntervalInSeconds = 30;
final OrientHttpSession firstSession = new OrientHttpSession(maxInactiveIntervalInSeconds);
final OrientHttpSession secondSession = new OrientHttpSession(maxInactiveIntervalInSeconds);
final OrientHttpSession firstSession = repository.createSession();
final OrientHttpSession secondSession = repository.createSession();

assertThat(firstSession.getId(), is(not(equalTo(secondSession.getId()))));
}

@Test
public void isExpiredMustReturnFalseIfMaxInactiveIntervalIsNegative() {
final OrientHttpSession session = new OrientHttpSession(-1);
final OrientHttpSession session = repository.createSession();

assertThat(session.isExpired(), is(false));
}

@Test
public void isExpiredMustReturnTrueIfSessionHasNotBeeenAccessedLongEnough() {
final OrientHttpSession session = new OrientHttpSession(1);
final OrientHttpSession session = repository.createSession();

session.setLastAccessedTime(System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(1));
session.setLastAccessedTime(System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(1));

assertThat(session.isExpired(), is(true));
}
Expand All @@ -40,7 +51,7 @@ public void isExpiredMustReturnTrueIfSessionHasNotBeeenAccessedLongEnough() {
public void getAttributeMustReturnTheValueThatWasPutEarlier() {
final String key = "key";
final String value = "value";
final OrientHttpSession session = new OrientHttpSession(1);
final OrientHttpSession session = repository.createSession();

session.setAttribute(key, value);

Expand All @@ -51,7 +62,7 @@ public void getAttributeMustReturnTheValueThatWasPutEarlier() {
public void passingANullAttributeMustRemoveItCompletely() {
final String key = "key";
final String value = "value";
final OrientHttpSession session = new OrientHttpSession(1);
final OrientHttpSession session = repository.createSession();

session.setAttribute(key, value);
session.setAttribute(key, null);
Expand All @@ -61,7 +72,7 @@ public void passingANullAttributeMustRemoveItCompletely() {

@Test
public void afterSettingNegativeValueForMaxInactiveIntervalSessionMustBecomeValidAllTheTime() {
final OrientHttpSession session = new OrientHttpSession(1);
final OrientHttpSession session = repository.createSession();

session.setMaxInactiveIntervalInSeconds(-1);
session.setLastAccessedTime(System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(10));
Expand All @@ -70,12 +81,12 @@ public void afterSettingNegativeValueForMaxInactiveIntervalSessionMustBecomeVali
}

@Test(expected = IllegalArgumentException.class)
public void settingNonSerializableAttributeMustThrowAnException() {
public void nonSerializableClassesAreNotAllowed() {
class NonSerializable {
}

final OrientHttpSession session = new OrientHttpSession(1);
final OrientHttpSession session = repository.createSession();

session.setAttribute("nonSerializable", new NonSerializable());
session.setAttribute("nonserializable", new NonSerializable());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.github.maseev.spring.session.orientdb.entity;

import java.io.Serializable;

public class Person implements Serializable {

private String name;
private int age;

public Person() {
}

public Person(final String name, final int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}

if (!(o instanceof Person)) {
return false;
}

Person person = (Person) o;

if (age != person.age) {
return false;
}

return name.equals(person.name);
}

@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + age;
return result;
}
}

0 comments on commit c1c79dc

Please sign in to comment.