All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.infinispan.spring.common.session.MapSessionProtoAdapter Maven / Gradle / Ivy

package org.infinispan.spring.common.session;

import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.Objects;
import java.util.stream.Collectors;

import org.infinispan.commons.CacheException;
import org.infinispan.commons.marshall.JavaSerializationMarshaller;
import org.infinispan.commons.marshall.ProtoStreamTypeIds;
import org.infinispan.protostream.ProtobufTagMarshaller;
import org.infinispan.protostream.TagReader;
import org.infinispan.protostream.WrappedMessage;
import org.infinispan.protostream.annotations.ProtoAdapter;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.infinispan.protostream.annotations.impl.GeneratedMarshallerBase;
import org.infinispan.protostream.impl.SerializationContextImpl;
import org.springframework.session.MapSession;

/**
 * Protostream adapter for Spring's {@link MapSession}.
 *
 * 

Attribute values set by the application should be marshalled with Protostream, but Java Serialization * is also supported.

*

Attribute values set by spring-session internally have not been converted to use Protostream, * so they are always marshalled using Java Serialization.

*

Note: Each attribute value uses either Protostream or Java Serialization for marshalling. * Mixing Protostream and Java Serialization in the same attribute is not supported.

* * @author Dan Berindei * @since 12.1 */ @ProtoAdapter(MapSession.class) @ProtoTypeId(ProtoStreamTypeIds.SPRING_SESSION) public class MapSessionProtoAdapter { @ProtoFactory static MapSession createSession(String id, String originalId, Collection attributes, Instant creationTime, Instant lastAccessedTime, long maxInactiveSeconds) { MapSession session = new MapSession(originalId); session.setId(id); session.setCreationTime(creationTime); session.setLastAccessedTime(lastAccessedTime); session.setMaxInactiveInterval(Duration.ofSeconds(maxInactiveSeconds)); for (SessionAttribute attribute : attributes) { session.setAttribute(attribute.getName(), attribute.getValue()); } return session; } @ProtoField(number = 1) String getId(MapSession session) { return session.getId(); } @ProtoField(number = 2) String getOriginalId(MapSession session) { if (Objects.equals(session.getOriginalId(), session.getId())) return null; return session.getOriginalId(); } @ProtoField(number = 3, defaultValue = "0") Instant getCreationTime(MapSession session) { return session.getCreationTime(); } @ProtoField(number = 4, defaultValue = "0") Instant getLastAccessedTime(MapSession session) { return session.getLastAccessedTime(); } @ProtoField(number = 5, defaultValue = "-1") long getMaxInactiveSeconds(MapSession session) { return session.getMaxInactiveInterval().getSeconds(); } @ProtoField(number = 6) Collection getAttributes(MapSession session) { return session.getAttributeNames().stream() .map(name -> new SessionAttribute(name, session.getAttribute(name))) .collect(Collectors.toList()); } @ProtoTypeId(ProtoStreamTypeIds.SPRING_SESSION_ATTRIBUTE) public static class SessionAttribute { private final String name; private final Object value; @ProtoFactory SessionAttribute(String name, WrappedMessage wrappedMessage, byte[] serializedBytes) { throw new IllegalStateException("Custom marshaller not registered!"); } public SessionAttribute(String name, Object value) { this.name = name; this.value = value; } @ProtoField(number = 1) public String getName() { return name; } public Object getValue() { return value; } @ProtoField(number = 2) public WrappedMessage getWrappedMessage() { return new WrappedMessage(value); } @ProtoField(number = 3) public byte[] getSerializedBytes() { throw new IllegalStateException("Custom marshaller not registered!"); } } /** * Generated with protostream-processor and then adapted to use {@code JavaSerializationMarshaller}. * *

A raw marshaller is necessary because we need a {@code JavaSerializationMarshaller} instance, * and {@link MapSessionProtoAdapter} must be stateless.

*/ public static final class SessionAttributeRawMarshaller extends GeneratedMarshallerBase implements ProtobufTagMarshaller { private final JavaSerializationMarshaller javaSerializationMarshaller; private org.infinispan.protostream.impl.BaseMarshallerDelegate wrappedMessageDelegate; public SessionAttributeRawMarshaller(JavaSerializationMarshaller javaSerializationMarshaller) { this.javaSerializationMarshaller = javaSerializationMarshaller; } @Override public Class getJavaClass() { return MapSessionProtoAdapter.SessionAttribute.class; } @Override public String getTypeName() { return "org.infinispan.persistence.spring.SessionAttribute"; } @Override public MapSessionProtoAdapter.SessionAttribute read(ReadContext ctx) throws IOException { TagReader in = ctx.getReader(); String name = null; boolean done = false; Object value = null; while (!done) { final int tag = in.readTag(); switch (tag) { case 0: done = true; break; case 10: { name = in.readString(); break; } case 18: { if (wrappedMessageDelegate == null) { wrappedMessageDelegate = ((SerializationContextImpl) ctx.getSerializationContext()).getMarshallerDelegate(WrappedMessage.class); } int length = in.readRawVarint32(); int oldLimit = in.pushLimit(length); WrappedMessage wrappedMessage = readMessage(wrappedMessageDelegate, ctx); value = wrappedMessage.getValue(); in.checkLastTagWas(0); in.popLimit(oldLimit); break; } case 26: { byte[] serializedBytes = in.readByteArray(); value = deserializeValue(serializedBytes); break; } default: { if (!in.skipField(tag)) done = true; } } } return new MapSessionProtoAdapter.SessionAttribute(name, value); } @Override public void write(WriteContext ctx, MapSessionProtoAdapter.SessionAttribute attribute) throws IOException { final String name = attribute.getName(); if (name != null) ctx.getWriter().writeString(1, name); Object value = attribute.getValue(); if (value != null) { if (ctx.getSerializationContext().canMarshall(value.getClass())) { // The attribute value is an application class that can be marshalled with Protostream final WrappedMessage wrappedMessage = new WrappedMessage(value); if (wrappedMessageDelegate == null) { wrappedMessageDelegate = ((SerializationContextImpl) ctx.getSerializationContext()).getMarshallerDelegate(WrappedMessage.class); } writeNestedMessage(wrappedMessageDelegate, ctx, 2, wrappedMessage); } else { // The attribute value cannot be marshalled with Protostream, but Java Serialization should work // E.g. all sessions have a org.springframework.security.core.context.SecurityContext attribute byte[] serializedBytes = serializeValue(value); ctx.getWriter().writeBytes(3, serializedBytes); } } } private byte[] serializeValue(Object value) throws IOException { final byte[] serializedBytes; try { serializedBytes = javaSerializationMarshaller.objectToByteBuffer(value); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new CacheException(e); } return serializedBytes; } private Object deserializeValue(byte[] serializedBytes) { try { return javaSerializationMarshaller.objectFromByteBuffer(serializedBytes); } catch (IOException | ClassNotFoundException e) { throw new CacheException(e); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy