@@ -19,9 +19,10 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.ee.infinispan;
package org.wildfly.clustering.ee.cache.tx;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;

import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
@@ -30,21 +31,21 @@
import javax.transaction.SystemException;
import javax.transaction.Transaction;

import org.infinispan.commons.CacheException;

/**
* Abstract {@link TransactionBatch} that associates and exposes the underlying transaction.
* @author Paul Ferraro
*/
public class InfinispanBatch implements TransactionBatch {
public class TransactionalBatch<E extends RuntimeException> implements TransactionBatch {

private final Function<Throwable, E> exceptionTransformer;
private final Transaction tx;
private final AtomicInteger count = new AtomicInteger(0);

private volatile boolean active = true;

public InfinispanBatch(Transaction tx) {
public TransactionalBatch(Transaction tx, Function<Throwable, E> exceptionTransformer) {
this.tx = tx;
this.exceptionTransformer = exceptionTransformer;
}

@Override
@@ -82,7 +83,7 @@ public State getState() {
}
}
} catch (SystemException e) {
throw new CacheException(e);
throw this.exceptionTransformer.apply(e);
}
}

@@ -99,7 +100,7 @@ public void close() {
} catch (RollbackException e) {
throw new IllegalStateException(e);
} catch (HeuristicMixedException | HeuristicRollbackException e) {
throw new CacheException(e);
throw this.exceptionTransformer.apply(e);
}
}
// Otherwise fall through
@@ -110,7 +111,7 @@ public void close() {
}
}
} catch (SystemException e) {
throw new CacheException(e);
throw this.exceptionTransformer.apply(e);
}
}
}
@@ -122,8 +123,8 @@ public int hashCode() {

@Override
public boolean equals(Object object) {
if (!(object instanceof InfinispanBatch)) return false;
InfinispanBatch batch = (InfinispanBatch) object;
if (!(object instanceof TransactionalBatch)) return false;
TransactionalBatch<?> batch = (TransactionalBatch<?>) object;
return this.tx.equals(batch.tx);
}

@@ -19,7 +19,9 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.ee.infinispan;
package org.wildfly.clustering.ee.cache.tx;

import java.util.function.Function;

import javax.transaction.InvalidTransactionException;
import javax.transaction.NotSupportedException;
@@ -29,8 +31,6 @@
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;

import org.infinispan.Cache;
import org.infinispan.commons.CacheException;
import org.wildfly.clustering.ee.Batch;
import org.wildfly.clustering.ee.BatchContext;
import org.wildfly.clustering.ee.Batcher;
@@ -42,7 +42,7 @@
* via {@link #resumeBatch(TransactionBatch)}.
* @author Paul Ferraro
*/
public class InfinispanBatcher implements Batcher<TransactionBatch> {
public class TransactionalBatcher<E extends RuntimeException> implements Batcher<TransactionBatch> {

private static final BatchContext PASSIVE_BATCH_CONTEXT = () -> {
// Do nothing
@@ -103,13 +103,11 @@ public void afterCompletion(int status) {
};

private final TransactionManager tm;
private final Function<Throwable, E> exceptionTransformer;

public InfinispanBatcher(Cache<?, ?> cache) {
this(cache.getAdvancedCache().getTransactionManager());
}

public InfinispanBatcher(TransactionManager tm) {
public TransactionalBatcher(TransactionManager tm, Function<Throwable, E> exceptionTransformer) {
this.tm = tm;
this.exceptionTransformer = exceptionTransformer;
}

@Override
@@ -124,11 +122,11 @@ public TransactionBatch createBatch() {
this.tm.begin();
Transaction tx = this.tm.getTransaction();
tx.registerSynchronization(CURRENT_BATCH_SYNCHRONIZATION);
batch = new InfinispanBatch(tx);
batch = new TransactionalBatch<>(tx, this.exceptionTransformer);
setCurrentBatch(batch);
return batch;
} catch (RollbackException | SystemException | NotSupportedException e) {
throw new CacheException(e);
throw this.exceptionTransformer.apply(e);
}
}

@@ -159,17 +157,17 @@ public BatchContext resumeBatch(TransactionBatch batch) {
try {
this.tm.resume(existingBatch.getTransaction());
} catch (InvalidTransactionException e) {
throw new CacheException(e);
throw this.exceptionTransformer.apply(e);
}
}
} catch (SystemException e) {
throw new CacheException(e);
throw this.exceptionTransformer.apply(e);
} finally {
setCurrentBatch(existingBatch);
}
};
} catch (SystemException | InvalidTransactionException e) {
throw new CacheException(e);
throw this.exceptionTransformer.apply(e);
}
}

@@ -184,7 +182,7 @@ public TransactionBatch suspendBatch() {
throw new IllegalStateException();
}
} catch (SystemException e) {
throw new CacheException(e);
throw this.exceptionTransformer.apply(e);
} finally {
setCurrentBatch(null);
}
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.infinispan.spi.function;
package org.wildfly.clustering.ee.cache.function;

import java.util.Map;
import java.util.Set;
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee.retry;
package org.wildfly.clustering.ee.cache.retry;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
@@ -19,7 +19,7 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.ee.infinispan;
package org.wildfly.clustering.ee.cache.tx;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
@@ -40,20 +40,20 @@
* Unit test for {@link InfinispanBatcher}.
* @author Paul Ferraro
*/
public class InfinispanBatcherTestCase {
public class TransactionalBatcherTestCase {
private final TransactionManager tm = mock(TransactionManager.class);
private final Batcher<TransactionBatch> batcher = new InfinispanBatcher(this.tm);
private final Batcher<TransactionBatch> batcher = new TransactionalBatcher<>(this.tm, RuntimeException::new);

@After
public void destroy() {
InfinispanBatcher.setCurrentBatch(null);
TransactionalBatcher.setCurrentBatch(null);
}

@Test
public void createExistingActiveBatch() throws Exception {
TransactionBatch existingBatch = mock(TransactionBatch.class);

InfinispanBatcher.setCurrentBatch(existingBatch);
TransactionalBatcher.setCurrentBatch(existingBatch);
when(existingBatch.getState()).thenReturn(Batch.State.ACTIVE);
when(existingBatch.interpose()).thenReturn(existingBatch);

@@ -71,7 +71,7 @@ public void createExistingClosedBatch() throws Exception {
Transaction tx = mock(Transaction.class);
ArgumentCaptor<Synchronization> capturedSync = ArgumentCaptor.forClass(Synchronization.class);

InfinispanBatcher.setCurrentBatch(existingBatch);
TransactionalBatcher.setCurrentBatch(existingBatch);
when(existingBatch.getState()).thenReturn(Batch.State.CLOSED);

when(this.tm.getTransaction()).thenReturn(tx);
@@ -81,14 +81,14 @@ public void createExistingClosedBatch() throws Exception {
verify(tx).registerSynchronization(capturedSync.capture());

assertSame(tx, batch.getTransaction());
assertSame(batch, InfinispanBatcher.getCurrentBatch());
assertSame(batch, TransactionalBatcher.getCurrentBatch());
} finally {
capturedSync.getValue().afterCompletion(Status.STATUS_COMMITTED);
}

verify(tx).commit();

assertNull(InfinispanBatcher.getCurrentBatch());
assertNull(TransactionalBatcher.getCurrentBatch());
}


@@ -110,7 +110,7 @@ public void createBatchClose() throws Exception {

verify(tx).commit();

assertNull(InfinispanBatcher.getCurrentBatch());
assertNull(TransactionalBatcher.getCurrentBatch());
}

@Test
@@ -134,7 +134,7 @@ public void createBatchDiscard() throws Exception {
verify(tx, never()).commit();
verify(tx).rollback();

assertNull(InfinispanBatcher.getCurrentBatch());
assertNull(TransactionalBatcher.getCurrentBatch());
}

@Test
@@ -167,7 +167,7 @@ public void createNestedBatchClose() throws Exception {
verify(tx, never()).rollback();
verify(tx).commit();

assertNull(InfinispanBatcher.getCurrentBatch());
assertNull(TransactionalBatcher.getCurrentBatch());
}

@Test
@@ -202,7 +202,7 @@ public void createNestedBatchDiscard() throws Exception {
verify(tx).rollback();
verify(tx, never()).commit();

assertNull(InfinispanBatcher.getCurrentBatch());
assertNull(TransactionalBatcher.getCurrentBatch());
}

@SuppressWarnings("resource")
@@ -240,7 +240,7 @@ public void createOverlappingBatchClose() throws Exception {
verify(tx, never()).rollback();
verify(tx).commit();

assertNull(InfinispanBatcher.getCurrentBatch());
assertNull(TransactionalBatcher.getCurrentBatch());
}

@SuppressWarnings("resource")
@@ -280,34 +280,34 @@ public void createOverlappingBatchDiscard() throws Exception {
verify(tx).rollback();
verify(tx, never()).commit();

assertNull(InfinispanBatcher.getCurrentBatch());
assertNull(TransactionalBatcher.getCurrentBatch());
}

@Test
public void resumeNullBatch() throws Exception {
TransactionBatch batch = mock(TransactionBatch.class);
InfinispanBatcher.setCurrentBatch(batch);
TransactionalBatcher.setCurrentBatch(batch);

try (BatchContext context = this.batcher.resumeBatch(null)) {
verifyZeroInteractions(this.tm);
assertNull(InfinispanBatcher.getCurrentBatch());
assertNull(TransactionalBatcher.getCurrentBatch());
}
verifyZeroInteractions(this.tm);
assertSame(batch, InfinispanBatcher.getCurrentBatch());
assertSame(batch, TransactionalBatcher.getCurrentBatch());
}

@Test
public void resumeNonTxBatch() throws Exception {
TransactionBatch existingBatch = mock(TransactionBatch.class);
InfinispanBatcher.setCurrentBatch(existingBatch);
TransactionalBatcher.setCurrentBatch(existingBatch);
TransactionBatch batch = mock(TransactionBatch.class);

try (BatchContext context = this.batcher.resumeBatch(batch)) {
verifyZeroInteractions(this.tm);
assertSame(batch, InfinispanBatcher.getCurrentBatch());
assertSame(batch, TransactionalBatcher.getCurrentBatch());
}
verifyZeroInteractions(this.tm);
assertSame(existingBatch, InfinispanBatcher.getCurrentBatch());
assertSame(existingBatch, TransactionalBatcher.getCurrentBatch());
}

@Test
@@ -322,20 +322,20 @@ public void resumeBatch() throws Exception {
verify(this.tm).resume(tx);
reset(this.tm);

assertSame(batch, InfinispanBatcher.getCurrentBatch());
assertSame(batch, TransactionalBatcher.getCurrentBatch());
}

verify(this.tm).suspend();
verify(this.tm, never()).resume(any());

assertNull(InfinispanBatcher.getCurrentBatch());
assertNull(TransactionalBatcher.getCurrentBatch());
}

@Test
public void resumeBatchExisting() throws Exception {
TransactionBatch existingBatch = mock(TransactionBatch.class);
Transaction existingTx = mock(Transaction.class);
InfinispanBatcher.setCurrentBatch(existingBatch);
TransactionalBatcher.setCurrentBatch(existingBatch);
TransactionBatch batch = mock(TransactionBatch.class);
Transaction tx = mock(Transaction.class);

@@ -347,27 +347,27 @@ public void resumeBatchExisting() throws Exception {
verify(this.tm).resume(tx);
reset(this.tm);

assertSame(batch, InfinispanBatcher.getCurrentBatch());
assertSame(batch, TransactionalBatcher.getCurrentBatch());

when(this.tm.suspend()).thenReturn(tx);
}

verify(this.tm).resume(existingTx);

assertSame(existingBatch, InfinispanBatcher.getCurrentBatch());
assertSame(existingBatch, TransactionalBatcher.getCurrentBatch());
}

@Test
public void suspendBatch() throws Exception {
TransactionBatch batch = mock(TransactionBatch.class);
InfinispanBatcher.setCurrentBatch(batch);
TransactionalBatcher.setCurrentBatch(batch);

TransactionBatch result = this.batcher.suspendBatch();

verify(this.tm).suspend();

assertSame(batch, result);
assertNull(InfinispanBatcher.getCurrentBatch());
assertNull(TransactionalBatcher.getCurrentBatch());
}

@Test
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2018, Red Hat, Inc., and individual contributors
~ as indicated by the @author tags. See the copyright.txt file in the
~ distribution for a full listing of individual contributors.
~
~ This is free software; you can redistribute it and/or modify it
~ under the terms of the GNU Lesser General Public License as
~ published by the Free Software Foundation; either version 2.1 of
~ the License, or (at your option) any later version.
~
~ This software is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
~ Lesser General Public License for more details.
~
~ You should have received a copy of the GNU Lesser General Public
~ License along with this software; if not, write to the Free
~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-clustering-ee</artifactId>
<!--
Maintain separation between the artifact id and the version to help prevent
merge conflicts between commits changing the GA and those changing the V.
-->
<version>17.0.0.Beta1-SNAPSHOT</version>
</parent>

<artifactId>wildfly-clustering-ee-hotrod</artifactId>
<packaging>jar</packaging>

<name>WildFly: EE clustering - HotRod service provider</name>

<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wildfly-clustering-ee-cache</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,54 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2014, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee.hotrod;

import java.util.Map;

import org.infinispan.client.hotrod.RemoteCache;
import org.wildfly.clustering.ee.Mutator;

/**
* Mutates a given cache entry.
* @author Paul Ferraro
*/
public class RemoteCacheEntryMutator<K, V> implements Mutator {

private final RemoteCache<K, V> cache;
private final K id;
private final V value;

public RemoteCacheEntryMutator(RemoteCache<K, V> cache, Map.Entry<K, V> entry) {
this(cache, entry.getKey(), entry.getValue());
}

public RemoteCacheEntryMutator(RemoteCache<K, V> cache, K id, V value) {
this.cache = cache;
this.id = id;
this.value = value;
}

@Override
public void mutate() {
this.cache.put(this.id, this.value);
}
}
@@ -0,0 +1,64 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2018, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee.hotrod;

import org.infinispan.client.hotrod.configuration.Configuration;
import org.infinispan.client.hotrod.configuration.TransactionMode;
import org.wildfly.clustering.ee.cache.CacheProperties;

/**
* @author Paul Ferraro
*/
public class RemoteCacheManagerProperties implements CacheProperties {

private final boolean transactional;

public RemoteCacheManagerProperties(Configuration configuration) {
this.transactional = configuration.transaction().transactionMode() != TransactionMode.NONE;
}

@Override
public boolean isLockOnRead() {
return false;
}

@Override
public boolean isLockOnWrite() {
return true;
}

@Override
public boolean isMarshalling() {
return true;
}

@Override
public boolean isPersistent() {
return true;
}

@Override
public boolean isTransactional() {
return this.transactional;
}
}
@@ -0,0 +1,37 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2018, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee.hotrod.tx;

import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.wildfly.clustering.ee.cache.tx.TransactionalBatcher;

/**
* @author Paul Ferraro
*/
public class HotRodBatcher extends TransactionalBatcher<HotRodClientException> {

public HotRodBatcher(RemoteCache<?, ?> cache) {
super(cache.getTransactionManager(), HotRodClientException::new);
}
}
@@ -44,7 +44,7 @@
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wildfly-clustering-ee-spi</artifactId>
<artifactId>wildfly-clustering-ee-cache</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
@@ -25,6 +25,7 @@
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.transaction.LockingMode;
import org.infinispan.util.concurrent.IsolationLevel;
import org.wildfly.clustering.ee.cache.CacheProperties;

/**
* Eagerly calculates the properties of a cache configuration.
@@ -33,7 +33,7 @@
* Retrying invoker whose retry intervals are auto-generated based an Infinispan cache configuration.
* @author Paul Ferraro
*/
public class RetryingInvoker extends org.wildfly.clustering.ee.retry.RetryingInvoker {
public class RetryingInvoker extends org.wildfly.clustering.ee.cache.retry.RetryingInvoker {

public RetryingInvoker(Cache<?, ?> cache) {
super(calculateRetryIntervals(cache.getCacheConfiguration()));
@@ -0,0 +1,37 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2018, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee.infinispan.tx;

import org.infinispan.Cache;
import org.infinispan.commons.CacheException;
import org.wildfly.clustering.ee.cache.tx.TransactionalBatcher;

/**
* @author Paul Ferraro
*/
public class InfinispanBatcher extends TransactionalBatcher<CacheException> {

public InfinispanBatcher(Cache<?, ?> cache) {
super(cache.getAdvancedCache().getTransactionManager(), CacheException::new);
}
}
@@ -32,6 +32,7 @@
import org.infinispan.util.concurrent.IsolationLevel;
import org.junit.Assert;
import org.junit.Test;
import org.wildfly.clustering.ee.cache.CacheProperties;

/**
* @author Paul Ferraro
@@ -43,6 +43,8 @@

<modules>
<module>spi</module>
<module>cache</module>
<module>hotrod</module>
<module>infinispan</module>
</modules>

@@ -46,10 +46,6 @@
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.common</groupId>
<artifactId>wildfly-common</artifactId>
@@ -76,7 +76,7 @@
*
* @author Paul Ferraro
*/
public class ImmutabilityTestCase {
public class DefaultImmutabilityTestCase {

@Test
public void test() throws Exception {
@@ -30,7 +30,7 @@

import org.wildfly.clustering.ee.Batch;
import org.wildfly.clustering.ee.Batcher;
import org.wildfly.clustering.ee.infinispan.TransactionBatch;
import org.wildfly.clustering.ee.cache.tx.TransactionBatch;
import org.wildfly.clustering.ejb.infinispan.logging.InfinispanEjbLogger;
import org.wildfly.clustering.infinispan.spi.distribution.Locality;

@@ -58,10 +58,10 @@
import org.wildfly.clustering.dispatcher.CommandDispatcherFactory;
import org.wildfly.clustering.ee.Batcher;
import org.wildfly.clustering.ee.Invoker;
import org.wildfly.clustering.ee.infinispan.CacheProperties;
import org.wildfly.clustering.ee.infinispan.InfinispanBatcher;
import org.wildfly.clustering.ee.infinispan.TransactionBatch;
import org.wildfly.clustering.ee.retry.RetryingInvoker;
import org.wildfly.clustering.ee.cache.CacheProperties;
import org.wildfly.clustering.ee.cache.retry.RetryingInvoker;
import org.wildfly.clustering.ee.cache.tx.TransactionBatch;
import org.wildfly.clustering.ee.infinispan.tx.InfinispanBatcher;
import org.wildfly.clustering.ejb.Bean;
import org.wildfly.clustering.ejb.BeanManager;
import org.wildfly.clustering.ejb.IdentifierFactory;
@@ -26,7 +26,7 @@

import org.infinispan.remoting.transport.Address;
import org.wildfly.clustering.dispatcher.CommandDispatcherFactory;
import org.wildfly.clustering.ee.infinispan.CacheProperties;
import org.wildfly.clustering.ee.cache.CacheProperties;
import org.wildfly.clustering.infinispan.spi.affinity.KeyAffinityServiceFactory;
import org.wildfly.clustering.registry.Registry;
import org.wildfly.clustering.spi.NodeFactory;
@@ -29,14 +29,14 @@
import org.infinispan.Cache;
import org.infinispan.remoting.transport.Address;
import org.wildfly.clustering.dispatcher.CommandDispatcherFactory;
import org.wildfly.clustering.ee.infinispan.CacheProperties;
import org.wildfly.clustering.ee.cache.CacheProperties;
import org.wildfly.clustering.ee.cache.tx.TransactionBatch;
import org.wildfly.clustering.ee.infinispan.InfinispanCacheProperties;
import org.wildfly.clustering.ee.infinispan.TransactionBatch;
import org.wildfly.clustering.ejb.BeanManager;
import org.wildfly.clustering.ejb.BeanManagerFactory;
import org.wildfly.clustering.ejb.BeanPassivationConfiguration;
import org.wildfly.clustering.ejb.PassivationListener;
import org.wildfly.clustering.ejb.IdentifierFactory;
import org.wildfly.clustering.ejb.PassivationListener;
import org.wildfly.clustering.ejb.RemoveListener;
import org.wildfly.clustering.ejb.infinispan.bean.InfinispanBeanFactory;
import org.wildfly.clustering.ejb.infinispan.group.InfinispanBeanGroupFactory;
@@ -35,7 +35,7 @@
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.ServiceTarget;
import org.wildfly.clustering.dispatcher.CommandDispatcherFactory;
import org.wildfly.clustering.ee.infinispan.TransactionBatch;
import org.wildfly.clustering.ee.cache.tx.TransactionBatch;
import org.wildfly.clustering.ejb.BeanContext;
import org.wildfly.clustering.ejb.BeanManagerFactory;
import org.wildfly.clustering.ejb.BeanManagerFactoryServiceConfiguratorConfiguration;
@@ -26,8 +26,8 @@
import org.infinispan.Cache;
import org.infinispan.context.Flag;
import org.wildfly.clustering.ee.Mutator;
import org.wildfly.clustering.ee.cache.CacheProperties;
import org.wildfly.clustering.ee.infinispan.CacheEntryMutator;
import org.wildfly.clustering.ee.infinispan.CacheProperties;
import org.wildfly.clustering.ejb.Bean;
import org.wildfly.clustering.ejb.PassivationListener;
import org.wildfly.clustering.ejb.RemoveListener;
@@ -38,8 +38,8 @@
import org.infinispan.notifications.cachelistener.event.CacheEntryActivatedEvent;
import org.infinispan.notifications.cachelistener.event.CacheEntryPassivatedEvent;
import org.wildfly.clustering.ee.Mutator;
import org.wildfly.clustering.ee.cache.CacheProperties;
import org.wildfly.clustering.ee.infinispan.CacheEntryMutator;
import org.wildfly.clustering.ee.infinispan.CacheProperties;
import org.wildfly.clustering.ejb.PassivationListener;
import org.wildfly.clustering.ejb.infinispan.BeanEntry;
import org.wildfly.clustering.ejb.infinispan.BeanGroup;
@@ -31,7 +31,7 @@

import org.junit.Test;
import org.wildfly.clustering.ee.Batcher;
import org.wildfly.clustering.ee.infinispan.TransactionBatch;
import org.wildfly.clustering.ee.cache.tx.TransactionBatch;
import org.wildfly.clustering.ejb.RemoveListener;

public class BeanExpirationSchedulerTestCase {
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2018, Red Hat, Inc., and individual contributors
~ as indicated by the @author tags. See the copyright.txt file in the
~ distribution for a full listing of individual contributors.
~
~ This is free software; you can redistribute it and/or modify it
~ under the terms of the GNU Lesser General Public License as
~ published by the Free Software Foundation; either version 2.1 of
~ the License, or (at your option) any later version.
~
~ This software is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
~ Lesser General Public License for more details.
~
~ You should have received a copy of the GNU Lesser General Public
~ License along with this software; if not, write to the Free
~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-clustering-infinispan</artifactId>
<!--
Maintain separation between the artifact id and the version to help prevent
merge conflicts between commits changing the GA and those changing the V.
-->
<version>17.0.0.Beta1-SNAPSHOT</version>
</parent>

<artifactId>wildfly-clustering-infinispan-client</artifactId>
<packaging>jar</packaging>

<name>WildFly: Infinispan Client SPI</name>

<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wildfly-clustering-common</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,62 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2018, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.infinispan.client;

import org.infinispan.client.hotrod.configuration.Configuration;
import org.jboss.as.clustering.controller.UnaryRequirementServiceNameFactory;
import org.jboss.as.clustering.controller.UnaryServiceNameFactory;
import org.jboss.as.clustering.controller.UnaryServiceNameFactoryProvider;
import org.wildfly.clustering.service.UnaryRequirement;

/**
* @author Paul Ferraro
*/
public enum InfinispanClientRequirement implements UnaryRequirement, UnaryServiceNameFactoryProvider {

REMOTE_CONTAINER("org.wildfly.clustering.infinispan.remote-cache-container", RemoteCacheContainer.class),
REMOTE_CONTAINER_CONFIGURATION("org.wildfly.clustering.infinispan.remote-cache-container-configuration", Configuration.class),
;
private final String name;
private final Class<?> type;
private final UnaryServiceNameFactory factory = new UnaryRequirementServiceNameFactory(this);

InfinispanClientRequirement(String name, Class<?> type) {
this.name = name;
this.type = type;
}

@Override
public String getName() {
return this.name;
}

@Override
public Class<?> getType() {
return this.type;
}

@Override
public UnaryServiceNameFactory getServiceNameFactory() {
return this.factory;
}
}
@@ -0,0 +1,57 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.infinispan.client;

import java.util.Objects;

/**
* Base type for cache keys.
* @author Paul Ferraro
*/
public class Key<I> {

private I id;

public Key(I id) {
this.id = id;
}

public I getId() {
return this.id;
}

@Override
public int hashCode() {
return Objects.hash(this.getClass(), this.id);
}

@Override
public boolean equals(Object object) {
return this.getClass().equals(object.getClass()) && this.id.equals(((Key<?>) object).id);
}

@Override
public String toString() {
return String.format("%s(%s)", this.getClass().getSimpleName(), this.id);
}
}
@@ -20,12 +20,12 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.infinispan.spi;
package org.wildfly.clustering.infinispan.client;

import org.infinispan.client.hotrod.RemoteCacheManagerAdmin;

/**
* Exposes Infinispan's {@link org.infinispan.client.hotrod.RemoteCacheContainer} additionally exposing the name of the
* Exposes Infinispan's {@link org.wildfly.clustering.infinispan.client.client.hotrod.RemoteCacheContainer} additionally exposing the name of the
* remote cache container and an administration utility.
*
* @author Radoslav Husar
@@ -50,6 +50,10 @@
<groupId>${project.groupId}</groupId>
<artifactId>wildfly-clustering-jgroups-extension</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wildfly-clustering-infinispan-client</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wildfly-clustering-infinispan-spi</artifactId>
@@ -51,7 +51,7 @@
import org.infinispan.persistence.spi.SegmentedAdvancedLoadWriteStore;
import org.jboss.as.clustering.infinispan.InfinispanLogger;
import org.reactivestreams.Publisher;
import org.wildfly.clustering.infinispan.spi.RemoteCacheContainer;
import org.wildfly.clustering.infinispan.client.RemoteCacheContainer;

import io.reactivex.Flowable;
import io.reactivex.functions.Consumer;
@@ -29,7 +29,7 @@
import org.infinispan.configuration.cache.AbstractStoreConfiguration;
import org.infinispan.configuration.cache.AsyncStoreConfiguration;
import org.infinispan.configuration.cache.SingletonStoreConfiguration;
import org.wildfly.clustering.infinispan.spi.RemoteCacheContainer;
import org.wildfly.clustering.infinispan.client.RemoteCacheContainer;

/**
* @author Radoslav Husar
@@ -30,7 +30,7 @@
import org.infinispan.configuration.cache.AbstractStoreConfiguration;
import org.infinispan.configuration.cache.AbstractStoreConfigurationBuilder;
import org.infinispan.configuration.cache.PersistenceConfigurationBuilder;
import org.wildfly.clustering.infinispan.spi.RemoteCacheContainer;
import org.wildfly.clustering.infinispan.client.RemoteCacheContainer;

/**
* @author Radoslav Husar
@@ -34,7 +34,7 @@
import org.jboss.as.controller.registry.AttributeAccess;
import org.jboss.as.controller.transform.description.ResourceTransformationDescriptionBuilder;
import org.jboss.dmr.ModelType;
import org.wildfly.clustering.infinispan.spi.InfinispanRequirement;
import org.wildfly.clustering.infinispan.client.InfinispanClientRequirement;

/**
* Resource description for the addressable resource:
@@ -49,7 +49,7 @@

public enum Attribute implements org.jboss.as.clustering.controller.Attribute {
CACHE_CONFIGURATION("cache-configuration", ModelType.STRING, null),
REMOTE_CACHE_CONTAINER("remote-cache-container", ModelType.STRING, new CapabilityReference(Capability.PERSISTENCE, InfinispanRequirement.REMOTE_CONTAINER)),
REMOTE_CACHE_CONTAINER("remote-cache-container", ModelType.STRING, new CapabilityReference(Capability.PERSISTENCE, InfinispanClientRequirement.REMOTE_CONTAINER)),
;

private final AttributeDefinition definition;
@@ -32,8 +32,8 @@
import org.jboss.as.controller.PathAddress;
import org.jboss.dmr.ModelNode;
import org.jboss.msc.service.ServiceBuilder;
import org.wildfly.clustering.infinispan.spi.InfinispanRequirement;
import org.wildfly.clustering.infinispan.spi.RemoteCacheContainer;
import org.wildfly.clustering.infinispan.client.InfinispanClientRequirement;
import org.wildfly.clustering.infinispan.client.RemoteCacheContainer;
import org.wildfly.clustering.service.ServiceConfigurator;
import org.wildfly.clustering.service.ServiceSupplierDependency;
import org.wildfly.clustering.service.SupplierDependency;
@@ -54,7 +54,7 @@
public ServiceConfigurator configure(OperationContext context, ModelNode model) throws OperationFailedException {
this.cacheConfiguration = CACHE_CONFIGURATION.resolveModelAttribute(context, model).asStringOrNull();
String remoteCacheContainerName = REMOTE_CACHE_CONTAINER.resolveModelAttribute(context, model).asString();
this.remoteCacheContainer = new ServiceSupplierDependency<>(InfinispanRequirement.REMOTE_CONTAINER.getServiceName(context, remoteCacheContainerName));
this.remoteCacheContainer = new ServiceSupplierDependency<>(InfinispanClientRequirement.REMOTE_CONTAINER.getServiceName(context, remoteCacheContainerName));
return super.configure(context, model);
}

@@ -29,7 +29,7 @@
import org.infinispan.client.hotrod.configuration.TransactionMode;
import org.infinispan.commons.api.BasicCache;
import org.infinispan.commons.marshall.Marshaller;
import org.wildfly.clustering.infinispan.spi.RemoteCacheContainer;
import org.wildfly.clustering.infinispan.client.RemoteCacheContainer;

import java.util.Set;

@@ -48,7 +48,7 @@
import org.jboss.as.controller.transform.description.ResourceTransformationDescriptionBuilder;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
import org.wildfly.clustering.infinispan.spi.InfinispanRequirement;
import org.wildfly.clustering.infinispan.client.InfinispanClientRequirement;
import org.wildfly.clustering.service.UnaryRequirement;

/**
@@ -65,8 +65,8 @@ public static PathElement pathElement(String containerName) {
}

public enum Capability implements CapabilityProvider {
CONTAINER(InfinispanRequirement.REMOTE_CONTAINER),
CONFIGURATION(InfinispanRequirement.REMOTE_CONTAINER_CONFIGURATION),
CONTAINER(InfinispanClientRequirement.REMOTE_CONTAINER),
CONFIGURATION(InfinispanClientRequirement.REMOTE_CONTAINER_CONFIGURATION),
;

private final org.jboss.as.clustering.controller.Capability capability;
@@ -39,8 +39,8 @@
import org.jboss.msc.service.ServiceBuilder;
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceTarget;
import org.wildfly.clustering.infinispan.spi.InfinispanRequirement;
import org.wildfly.clustering.infinispan.spi.RemoteCacheContainer;
import org.wildfly.clustering.infinispan.client.InfinispanClientRequirement;
import org.wildfly.clustering.infinispan.client.RemoteCacheContainer;
import org.wildfly.clustering.service.AsyncServiceConfigurator;
import org.wildfly.clustering.service.FunctionalService;
import org.wildfly.clustering.service.ServiceConfigurator;
@@ -63,7 +63,7 @@ public RemoteCacheContainerServiceConfigurator(PathAddress address) {

@Override
public ServiceConfigurator configure(OperationContext context, ModelNode model) throws OperationFailedException {
this.configuration = new ServiceSupplierDependency<>(InfinispanRequirement.REMOTE_CONTAINER_CONFIGURATION.getServiceName(context, this.name));
this.configuration = new ServiceSupplierDependency<>(InfinispanClientRequirement.REMOTE_CONTAINER_CONFIGURATION.getServiceName(context, this.name));
return this;
}

@@ -50,7 +50,7 @@
import org.jboss.as.controller.transform.description.ResourceTransformationDescriptionBuilder;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
import org.wildfly.clustering.infinispan.spi.InfinispanRequirement;
import org.wildfly.clustering.infinispan.client.InfinispanClientRequirement;

/**
* Resource definition for the transaction component of a remote cache container.
@@ -104,7 +104,7 @@ public RemoteTransactionResourceDefinition() {
@Override
public ManagementResourceRegistration register(ManagementResourceRegistration parent) {
ManagementResourceRegistration registration = parent.registerSubModel(new RemoteTransactionResourceDefinition());
Capability dependentCapability = new UnaryRequirementCapability(InfinispanRequirement.REMOTE_CONTAINER_CONFIGURATION, UnaryCapabilityNameResolver.PARENT);
Capability dependentCapability = new UnaryRequirementCapability(InfinispanClientRequirement.REMOTE_CONTAINER_CONFIGURATION, UnaryCapabilityNameResolver.PARENT);
ResourceDescriptor descriptor = new ResourceDescriptor(this.getResourceDescriptionResolver())
.addAttributes(Attribute.class)
// Add a requirement on the tm capability to the parent cache capability
@@ -42,7 +42,8 @@
<name>WildFly: Infinispan modules</name>

<modules>
<module>extension</module>
<module>client</module>
<module>spi</module>
<module>extension</module>
</modules>
</project>
@@ -42,10 +42,6 @@
<name>WildFly: Infinispan SPI</name>

<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wildfly-clustering-api</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wildfly-clustering-common</artifactId>
@@ -58,19 +54,10 @@
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<groupId>org.kohsuke.metainf-services</groupId>
<artifactId>metainf-services</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
@@ -22,7 +22,6 @@

package org.wildfly.clustering.infinispan.spi;

import org.infinispan.client.hotrod.configuration.Configuration;
import org.infinispan.configuration.global.GlobalConfiguration;
import org.jboss.as.clustering.controller.UnaryRequirementServiceNameFactory;
import org.jboss.as.clustering.controller.UnaryServiceNameFactory;
@@ -38,8 +37,6 @@
CONTAINER("org.wildfly.clustering.infinispan.cache-container", CacheContainer.class),
CONFIGURATION("org.wildfly.clustering.infinispan.cache-container-configuration", GlobalConfiguration.class),
KEY_AFFINITY_FACTORY("org.wildfly.clustering.infinispan.key-affinity-factory", KeyAffinityServiceFactory.class),
REMOTE_CONTAINER("org.wildfly.clustering.infinispan.remote-cache-container", RemoteCacheContainer.class),
REMOTE_CONTAINER_CONFIGURATION("org.wildfly.clustering.infinispan.remote-cache-container-configuration", Configuration.class),
;
private final String name;
private final Class<?> type;
@@ -56,16 +56,16 @@
import org.wildfly.clustering.ee.Batch;
import org.wildfly.clustering.ee.Batcher;
import org.wildfly.clustering.ee.Invoker;
import org.wildfly.clustering.ee.infinispan.CacheProperties;
import org.wildfly.clustering.ee.cache.CacheProperties;
import org.wildfly.clustering.ee.cache.function.ConcurrentSetAddFunction;
import org.wildfly.clustering.ee.cache.function.ConcurrentSetRemoveFunction;
import org.wildfly.clustering.ee.cache.function.CopyOnWriteSetAddFunction;
import org.wildfly.clustering.ee.cache.function.CopyOnWriteSetRemoveFunction;
import org.wildfly.clustering.ee.infinispan.InfinispanCacheProperties;
import org.wildfly.clustering.ee.infinispan.retry.RetryingInvoker;
import org.wildfly.clustering.group.GroupListener;
import org.wildfly.clustering.group.Membership;
import org.wildfly.clustering.group.Node;
import org.wildfly.clustering.infinispan.spi.function.ConcurrentSetAddFunction;
import org.wildfly.clustering.infinispan.spi.function.ConcurrentSetRemoveFunction;
import org.wildfly.clustering.infinispan.spi.function.CopyOnWriteSetAddFunction;
import org.wildfly.clustering.infinispan.spi.function.CopyOnWriteSetRemoveFunction;
import org.wildfly.clustering.provider.ServiceProviderRegistration;
import org.wildfly.clustering.provider.ServiceProviderRegistration.Listener;
import org.wildfly.clustering.provider.ServiceProviderRegistry;
@@ -39,7 +39,7 @@
import org.wildfly.clustering.dispatcher.CommandDispatcherFactory;
import org.wildfly.clustering.ee.Batch;
import org.wildfly.clustering.ee.Batcher;
import org.wildfly.clustering.ee.infinispan.InfinispanBatcher;
import org.wildfly.clustering.ee.infinispan.tx.InfinispanBatcher;
import org.wildfly.clustering.infinispan.spi.InfinispanCacheRequirement;
import org.wildfly.clustering.provider.ServiceProviderRegistry;
import org.wildfly.clustering.server.group.Group;
@@ -30,7 +30,7 @@
import org.jboss.msc.service.ServiceName;
import org.wildfly.clustering.ee.Batch;
import org.wildfly.clustering.ee.Batcher;
import org.wildfly.clustering.ee.infinispan.InfinispanBatcher;
import org.wildfly.clustering.ee.infinispan.tx.InfinispanBatcher;
import org.wildfly.clustering.infinispan.spi.InfinispanCacheRequirement;
import org.wildfly.clustering.registry.Registry;
import org.wildfly.clustering.registry.RegistryFactory;
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2010, Red Hat, Inc., and individual contributors
~ as indicated by the @author tags. See the copyright.txt file in the
~ distribution for a full listing of individual contributors.
~
~ This is free software; you can redistribute it and/or modify it
~ under the terms of the GNU Lesser General Public License as
~ published by the Free Software Foundation; either version 2.1 of
~ the License, or (at your option) any later version.
~
~ This software is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
~ Lesser General Public License for more details.
~
~ You should have received a copy of the GNU Lesser General Public
~ License along with this software; if not, write to the Free
~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-clustering-web</artifactId>
<!--
Maintain separation between the artifact id and the version to help prevent
merge conflicts between commits changing the GA and those changing the V.
-->
<version>17.0.0.Beta1-SNAPSHOT</version>
</parent>

<artifactId>wildfly-clustering-web-cache</artifactId>
<packaging>jar</packaging>

<name>WildFly: Common abstractions for cache-based session manager implementations.</name>

<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wildfly-clustering-ee-cache</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wildfly-clustering-web-spi</artifactId>
</dependency>
<dependency>
<groupId>org.kohsuke.metainf-services</groupId>
<artifactId>metainf-services</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wildfly-clustering-marshalling-api</artifactId>
<version>${project.version}</version>
<scope>test</scope>
<classifier>tests</classifier>
</dependency>
</dependencies>

</project>
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan;
package org.wildfly.clustering.web.cache;

import java.io.DataInput;
import java.io.DataOutput;
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.routing;
package org.wildfly.clustering.web.cache.routing;

import org.wildfly.clustering.web.routing.RouteLocator;

@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.routing;
package org.wildfly.clustering.web.cache.routing;

import java.util.function.Consumer;
import java.util.function.Function;
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.routing;
package org.wildfly.clustering.web.cache.routing;

import org.jboss.as.clustering.controller.CapabilityServiceConfigurator;
import org.wildfly.clustering.web.WebDeploymentConfiguration;
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.routing;
package org.wildfly.clustering.web.cache.routing;

import java.util.function.Consumer;
import java.util.function.Function;
@@ -0,0 +1,41 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2018, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.cache.routing;

import java.util.Collection;
import java.util.Collections;

import org.jboss.as.clustering.controller.CapabilityServiceConfigurator;
import org.wildfly.clustering.service.SupplierDependency;
import org.wildfly.clustering.web.routing.RoutingProvider;

/**
* @author Paul Ferraro
*/
public class LocalRoutingProvider implements RoutingProvider {

@Override
public Collection<CapabilityServiceConfigurator> getServiceConfigurators(String serverName, SupplierDependency<String> route) {
return Collections.singleton(new LocalRouteServiceConfigurator(serverName, route));
}
}
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.routing;
package org.wildfly.clustering.web.cache.routing;

import org.wildfly.clustering.web.routing.RouteLocator;

@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.routing;
package org.wildfly.clustering.web.cache.routing;

import java.util.function.Consumer;

@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.routing;
package org.wildfly.clustering.web.cache.routing;

import org.jboss.as.clustering.controller.CapabilityServiceConfigurator;
import org.wildfly.clustering.web.WebDeploymentConfiguration;
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.routing;
package org.wildfly.clustering.web.cache.routing;

import org.jboss.as.controller.ServiceNameFactory;
import org.wildfly.clustering.service.SimpleServiceNameProvider;
@@ -19,7 +19,7 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import org.wildfly.clustering.web.session.ImmutableSession;
import org.wildfly.clustering.web.session.ImmutableSessionAttributes;
@@ -29,13 +29,13 @@
* Generic immutable session implementation - independent of cache mapping strategy.
* @author Paul Ferraro
*/
public class InfinispanImmutableSession implements ImmutableSession {
public class CompositeImmutableSession implements ImmutableSession {

private final String id;
private final ImmutableSessionMetaData metaData;
private final ImmutableSessionAttributes attributes;

public InfinispanImmutableSession(String id, ImmutableSessionMetaData metaData, ImmutableSessionAttributes attributes) {
public CompositeImmutableSession(String id, ImmutableSessionMetaData metaData, ImmutableSessionAttributes attributes) {
this.id = id;
this.metaData = metaData;
this.attributes = attributes;
@@ -19,7 +19,7 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.time.Instant;
import java.util.concurrent.atomic.AtomicReference;
@@ -33,15 +33,15 @@
* Generic session implementation - independent of cache mapping strategy.
* @author Paul Ferraro
*/
public class InfinispanSession<L> extends InfinispanImmutableSession implements Session<L> {
public class CompositeSession<L> extends CompositeImmutableSession implements Session<L> {

private final InvalidatableSessionMetaData metaData;
private final SessionAttributes attributes;
private final AtomicReference<L> localContext;
private final LocalContextFactory<L> localContextFactory;
private final Remover<String> remover;

public InfinispanSession(String id, InvalidatableSessionMetaData metaData, SessionAttributes attributes, AtomicReference<L> localContext, LocalContextFactory<L> localContextFactory, Remover<String> remover) {
public CompositeSession(String id, InvalidatableSessionMetaData metaData, SessionAttributes attributes, AtomicReference<L> localContext, LocalContextFactory<L> localContextFactory, Remover<String> remover) {
super(id, metaData, attributes);
this.metaData = metaData;
this.attributes = attributes;
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Map;
@@ -34,29 +34,29 @@
/**
* @author Paul Ferraro
*/
public class InfinispanSessionFactory<V, L> implements SessionFactory<InfinispanSessionMetaData<L>, V, L> {
public class CompositeSessionFactory<V, L> implements SessionFactory<CompositeSessionMetaDataEntry<L>, V, L> {

private final SessionMetaDataFactory<InfinispanSessionMetaData<L>, L> metaDataFactory;
private final SessionMetaDataFactory<CompositeSessionMetaDataEntry<L>, L> metaDataFactory;
private final SessionAttributesFactory<V> attributesFactory;
private final LocalContextFactory<L> localContextFactory;

public InfinispanSessionFactory(SessionMetaDataFactory<InfinispanSessionMetaData<L>, L> metaDataFactory, SessionAttributesFactory<V> attributesFactory, LocalContextFactory<L> localContextFactory) {
public CompositeSessionFactory(SessionMetaDataFactory<CompositeSessionMetaDataEntry<L>, L> metaDataFactory, SessionAttributesFactory<V> attributesFactory, LocalContextFactory<L> localContextFactory) {
this.metaDataFactory = metaDataFactory;
this.attributesFactory = attributesFactory;
this.localContextFactory = localContextFactory;
}

@Override
public Map.Entry<InfinispanSessionMetaData<L>, V> createValue(String id, Void context) {
InfinispanSessionMetaData<L> metaDataValue = this.metaDataFactory.createValue(id, context);
public Map.Entry<CompositeSessionMetaDataEntry<L>, V> createValue(String id, Void context) {
CompositeSessionMetaDataEntry<L> metaDataValue = this.metaDataFactory.createValue(id, context);
if (metaDataValue == null) return null;
V attributesValue = this.attributesFactory.createValue(id, context);
return new SimpleImmutableEntry<>(metaDataValue, attributesValue);
}

@Override
public Map.Entry<InfinispanSessionMetaData<L>, V> findValue(String id) {
InfinispanSessionMetaData<L> metaDataValue = this.metaDataFactory.findValue(id);
public Map.Entry<CompositeSessionMetaDataEntry<L>, V> findValue(String id) {
CompositeSessionMetaDataEntry<L> metaDataValue = this.metaDataFactory.findValue(id);
if (metaDataValue != null) {
V attributesValue = this.attributesFactory.findValue(id);
if (attributesValue != null) {
@@ -69,8 +69,8 @@ public InfinispanSessionFactory(SessionMetaDataFactory<InfinispanSessionMetaData
}

@Override
public Map.Entry<InfinispanSessionMetaData<L>, V> tryValue(String id) {
InfinispanSessionMetaData<L> metaDataValue = this.metaDataFactory.tryValue(id);
public Map.Entry<CompositeSessionMetaDataEntry<L>, V> tryValue(String id) {
CompositeSessionMetaDataEntry<L> metaDataValue = this.metaDataFactory.tryValue(id);
if (metaDataValue != null) {
V attributesValue = this.attributesFactory.tryValue(id);
if (attributesValue != null) {
@@ -92,7 +92,7 @@ public boolean remove(String id) {
}

@Override
public SessionMetaDataFactory<InfinispanSessionMetaData<L>, L> getMetaDataFactory() {
public SessionMetaDataFactory<CompositeSessionMetaDataEntry<L>, L> getMetaDataFactory() {
return this.metaDataFactory;
}

@@ -102,15 +102,15 @@ public boolean remove(String id) {
}

@Override
public Session<L> createSession(String id, Map.Entry<InfinispanSessionMetaData<L>, V> entry) {
InfinispanSessionMetaData<L> key = entry.getKey();
public Session<L> createSession(String id, Map.Entry<CompositeSessionMetaDataEntry<L>, V> entry) {
CompositeSessionMetaDataEntry<L> key = entry.getKey();
InvalidatableSessionMetaData metaData = this.metaDataFactory.createSessionMetaData(id, key);
SessionAttributes attributes = this.attributesFactory.createSessionAttributes(id, entry.getValue());
return new InfinispanSession<>(id, metaData, attributes, key.getLocalContext(), this.localContextFactory, this);
return new CompositeSession<>(id, metaData, attributes, key.getLocalContext(), this.localContextFactory, this);
}

@Override
public ImmutableSession createImmutableSession(String id, ImmutableSessionMetaData metaData, ImmutableSessionAttributes attributes) {
return new InfinispanImmutableSession(id, metaData, attributes);
return new CompositeImmutableSession(id, metaData, attributes);
}
}
@@ -19,7 +19,7 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.time.Duration;
import java.time.Instant;
@@ -28,19 +28,19 @@
* Composite view of the meta data of a session, combining volatile and static aspects.
* @author Paul Ferraro
*/
public class SimpleSessionMetaData extends AbstractImmutableSessionMetaData implements InvalidatableSessionMetaData {
public class CompositeSessionMetaData implements InvalidatableSessionMetaData {

private final SessionCreationMetaData creationMetaData;
private final SessionAccessMetaData accessMetaData;

public SimpleSessionMetaData(SessionCreationMetaData creationMetaData, SessionAccessMetaData accessMetaData) {
public CompositeSessionMetaData(SessionCreationMetaData creationMetaData, SessionAccessMetaData accessMetaData) {
this.creationMetaData = creationMetaData;
this.accessMetaData = accessMetaData;
}

@Override
public boolean isNew() {
// We can implement this more efficiently than the super implementation
// We can implement this more efficiently than the default implementation
return this.accessMetaData.getLastAccessedDuration().isZero();
}

@@ -20,20 +20,20 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.util.concurrent.atomic.AtomicReference;

/**
* Wrapper for the components of a sessions's meta-data,
* @author Paul Ferraro
*/
public class InfinispanSessionMetaData<L> {
public class CompositeSessionMetaDataEntry<L> {
private final SessionCreationMetaData creationMetaData;
private final SessionAccessMetaData accessMetaData;
private final AtomicReference<L> localContext;

public InfinispanSessionMetaData(SessionCreationMetaData creationMetaData, SessionAccessMetaData accessMetaData, AtomicReference<L> localContext) {
public CompositeSessionMetaDataEntry(SessionCreationMetaData creationMetaData, SessionAccessMetaData accessMetaData, AtomicReference<L> localContext) {
this.creationMetaData = creationMetaData;
this.accessMetaData = accessMetaData;
this.localContext = localContext;
@@ -0,0 +1,39 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.cache.session;

import java.util.Map;

import javax.servlet.http.HttpSession;

/**
* An {@link HttpSession} whose attributes can be filtered.
* @author Paul Ferraro
*/
public interface FilteringHttpSession extends HttpSession {
/**
* Returns the session attributes that are instances of the specified class.
* @return an map of session attribute names and values
*/
<T> Map<String, T> getAttributes(Class<T> targetClass);
}
@@ -19,29 +19,50 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.session;
package org.wildfly.clustering.web.cache.session;

import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;

import org.wildfly.clustering.web.session.ImmutableSession;
import org.wildfly.clustering.web.session.ImmutableSessionAttributes;

/**
* Adapts an {@link ImmutableSession} to the {@link HttpSession} interface.
* @author Paul Ferraro
*/
public class ImmutableHttpSessionAdapter implements HttpSession {
public class ImmutableFilteringHttpSession implements FilteringHttpSession {

private final ImmutableSession session;
private final ServletContext context;

public ImmutableHttpSessionAdapter(ImmutableSession session, ServletContext context) {
public ImmutableFilteringHttpSession(ImmutableSession session, ServletContext context) {
this.session = session;
this.context = context;
}

@Override
public <T> Map<String, T> getAttributes(Class<T> targetClass) {
ImmutableSessionAttributes attributes = this.session.getAttributes();
Set<String> names = attributes.getAttributeNames();
if (names.isEmpty()) return Collections.emptyMap();
Map<String, T> result = new HashMap<>(names.size());
for (String name : names) {
Object attribute = attributes.getAttribute(name);
if (targetClass.isInstance(attribute)) {
result.put(name, targetClass.cast(attribute));
}
}
return Collections.unmodifiableMap(result);
}

@Override
public long getCreationTime() {
return this.session.getMetaData().getCreationTime().toEpochMilli();
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.time.Duration;

@@ -0,0 +1,66 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.cache.session;

import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;

import org.wildfly.clustering.web.session.ImmutableSession;

/**
* Triggers activation events for all attributes of a session.
* @author Paul Ferraro
*/
public class ImmutableSessionActivationNotifier implements SessionActivationNotifier {

private final FilteringHttpSession session;

public ImmutableSessionActivationNotifier(ImmutableSession session, ServletContext context) {
this.session = new ImmutableFilteringHttpSession(session, context);
}

@Override
public void prePassivate() {
Map<String, HttpSessionActivationListener> listeners = this.session.getAttributes(HttpSessionActivationListener.class);
if (!listeners.isEmpty()) {
HttpSessionEvent event = new HttpSessionEvent(this.session);
for (HttpSessionActivationListener listener : listeners.values()) {
listener.sessionWillPassivate(event);
}
}
}

@Override
public void postActivate() {
Map<String, HttpSessionActivationListener> listeners = this.session.getAttributes(HttpSessionActivationListener.class);
if (!listeners.isEmpty()) {
HttpSessionEvent event = new HttpSessionEvent(this.session);
for (HttpSessionActivationListener listener : listeners.values()) {
listener.sessionDidActivate(event);
}
}
}
}
@@ -0,0 +1,54 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.cache.session;

import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

import org.wildfly.clustering.web.session.ImmutableSession;

/**
* @author Paul Ferraro
*/
public class ImmutableSessionBindingNotifier implements SessionBindingNotifier {

private final FilteringHttpSession session;

public ImmutableSessionBindingNotifier(ImmutableSession session, ServletContext context) {
this.session = new ImmutableFilteringHttpSession(session, context);
}

@Override
public void unbound() {
Map<String, HttpSessionBindingListener> listeners = this.session.getAttributes(HttpSessionBindingListener.class);
if (!listeners.isEmpty()) {
for (Map.Entry<String, HttpSessionBindingListener> entry : listeners.entrySet()) {
HttpSessionBindingListener listener = entry.getValue();
listener.valueUnbound(new HttpSessionBindingEvent(this.session, entry.getKey(), listener));
}
}
}
}
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.time.Duration;
import java.time.Instant;
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import org.wildfly.clustering.web.session.SessionMetaData;

@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.time.Duration;

@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.time.Duration;
import java.time.Instant;
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.time.Duration;

@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.io.IOException;
import java.io.ObjectInput;
@@ -0,0 +1,40 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.cache.session;

/**
* Notifies attributes of a session implementing {@link javax.servlet.http.HttpSessionActivationListener}.
* @author Paul Ferraro
*/
public interface SessionActivationNotifier {

/**
* Notifies interested attributes that they will be passivated.
*/
void prePassivate();

/**
* Notifies interested attributes that they are were activated.
*/
void postActivate();
}
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

/**
* @author Paul Ferraro
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import org.wildfly.clustering.ee.Creator;
import org.wildfly.clustering.ee.Locator;
@@ -0,0 +1,35 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.cache.session;

/**
* Notifies attributes of a session implementing {@link javax.servlet.http.HttpSessionBindingListener}.
* @author Paul Ferraro
*/
public interface SessionBindingNotifier {

/**
* Notifies all attributes that they are being unbound from a given session.
*/
void unbound();
}
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.time.Duration;

@@ -19,7 +19,7 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.util.concurrent.atomic.AtomicReference;

@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.io.IOException;
import java.io.ObjectInput;
@@ -19,7 +19,7 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.util.Map;

@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import org.wildfly.clustering.ee.Creator;
import org.wildfly.clustering.ee.Locator;
@@ -19,7 +19,7 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import org.wildfly.clustering.web.session.ImmutableSession;
import org.wildfly.clustering.web.session.ImmutableSessionAttributes;
@@ -19,7 +19,7 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.util.Collections;
import java.util.HashMap;
@@ -19,7 +19,7 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.time.Duration;
import java.time.Instant;
@@ -30,7 +30,7 @@
* An immutable "snapshot" of a session's meta-data which can be accessed outside the scope of a transaction.
* @author Paul Ferraro
*/
public class SimpleImmutableSessionMetaData extends AbstractImmutableSessionMetaData {
public class SimpleImmutableSessionMetaData implements ImmutableSessionMetaData {

private final Instant creationTime;
private final Instant lastAccessedTime;
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.time.Duration;

@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.session;
package org.wildfly.clustering.web.cache.session;

import java.time.Duration;
import java.time.Instant;
@@ -19,7 +19,7 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.session.coarse;
package org.wildfly.clustering.web.cache.session.coarse;

import java.util.Map;
import java.util.Set;
@@ -19,18 +19,18 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.session.coarse;
package org.wildfly.clustering.web.cache.session.coarse;

import java.io.NotSerializableException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.infinispan.commons.marshall.NotSerializableException;
import org.wildfly.clustering.ee.Immutability;
import org.wildfly.clustering.ee.Mutator;
import org.wildfly.clustering.ee.infinispan.CacheProperties;
import org.wildfly.clustering.ee.cache.CacheProperties;
import org.wildfly.clustering.marshalling.spi.Marshallability;
import org.wildfly.clustering.web.infinispan.session.SessionAttributes;
import org.wildfly.clustering.web.cache.session.SessionAttributes;

/**
* Exposes session attributes for a coarse granularity session.
@@ -19,31 +19,31 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.session.fine;
package org.wildfly.clustering.web.cache.session.fine;

import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;

import org.wildfly.clustering.marshalling.spi.InvalidSerializedFormException;
import org.wildfly.clustering.marshalling.spi.Marshaller;
import org.wildfly.clustering.web.infinispan.logging.InfinispanWebLogger;
import org.wildfly.clustering.web.session.ImmutableSessionAttributes;

/**
* Exposes session attributes for fine granularity sessions.
* @author Paul Ferraro
*/
public class FineImmutableSessionAttributes<V> implements ImmutableSessionAttributes {
private final String id;
public class FineImmutableSessionAttributes<K, V> implements ImmutableSessionAttributes {
private final Map<String, UUID> names;
private final Map<SessionAttributeKey, V> attributeCache;
private final Function<UUID, K> keyFactory;
private final Map<K, V> attributeCache;
private final Marshaller<Object, V> marshaller;

public FineImmutableSessionAttributes(String id, Map<String, UUID> names, Map<SessionAttributeKey, V> attributeCache, Marshaller<Object, V> marshaller) {
this.id = id;
public FineImmutableSessionAttributes(Map<String, UUID> names, Function<UUID, K> keyFactory, Map<K, V> attributeCache, Marshaller<Object, V> marshaller) {
this.names = Collections.unmodifiableMap(names);
this.keyFactory = keyFactory;
this.attributeCache = attributeCache;
this.marshaller = marshaller;
}
@@ -56,15 +56,17 @@ public FineImmutableSessionAttributes(String id, Map<String, UUID> names, Map<Se
@Override
public Object getAttribute(String name) {
UUID attributeId = this.names.get(name);
return (attributeId != null) ? this.read(name, this.attributeCache.get(new SessionAttributeKey(this.id, attributeId))) : null;
if (attributeId == null) return null;
K key = this.keyFactory.apply(attributeId);
return this.read(this.attributeCache.get(key));
}

private Object read(String name, V value) {
private Object read(V value) {
try {
return this.marshaller.read(value);
} catch (InvalidSerializedFormException e) {
// This should not happen here, since attributes were pre-activated during FineSessionFactory.findValue(...)
throw InfinispanWebLogger.ROOT_LOGGER.failedToReadSessionAttribute(e, this.id, name);
// This should not happen here, since attributes were pre-activated when session was constructed
throw new IllegalStateException(e);
}
}
}
@@ -19,51 +19,53 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.session.fine;
package org.wildfly.clustering.web.cache.session.fine;

import java.io.NotSerializableException;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.function.Function;

import org.infinispan.Cache;
import org.infinispan.commons.marshall.NotSerializableException;
import org.infinispan.context.Flag;
import org.wildfly.clustering.ee.Immutability;
import org.wildfly.clustering.ee.Mutator;
import org.wildfly.clustering.ee.infinispan.CacheEntryMutator;
import org.wildfly.clustering.ee.infinispan.CacheProperties;
import org.wildfly.clustering.infinispan.spi.function.ConcurrentMapPutFunction;
import org.wildfly.clustering.infinispan.spi.function.ConcurrentMapRemoveFunction;
import org.wildfly.clustering.infinispan.spi.function.CopyOnWriteMapPutFunction;
import org.wildfly.clustering.infinispan.spi.function.CopyOnWriteMapRemoveFunction;
import org.wildfly.clustering.ee.cache.CacheProperties;
import org.wildfly.clustering.ee.cache.function.ConcurrentMapPutFunction;
import org.wildfly.clustering.ee.cache.function.ConcurrentMapRemoveFunction;
import org.wildfly.clustering.ee.cache.function.CopyOnWriteMapPutFunction;
import org.wildfly.clustering.ee.cache.function.CopyOnWriteMapRemoveFunction;
import org.wildfly.clustering.marshalling.spi.InvalidSerializedFormException;
import org.wildfly.clustering.marshalling.spi.Marshaller;
import org.wildfly.clustering.web.infinispan.logging.InfinispanWebLogger;
import org.wildfly.clustering.web.infinispan.session.SessionAttributes;
import org.wildfly.clustering.web.cache.session.SessionAttributes;

/**
* Exposes session attributes for fine granularity sessions.
* @author Paul Ferraro
*/
public class FineSessionAttributes<V> implements SessionAttributes {
private final String id;
private final Cache<SessionAttributeNamesKey, Map<String, UUID>> namesCache;
private final Cache<SessionAttributeKey, V> attributeCache;
private final Map<String, Mutator> mutations = new ConcurrentHashMap<>();
public class FineSessionAttributes<NK, K, V> implements SessionAttributes {
private final NK key;
private final Map<NK, Map<String, UUID>> namesCache;
private final Function<UUID, K> keyFactory;
private final Map<K, V> attributeCache;
private final Map<UUID, Mutator> mutations = new ConcurrentHashMap<>();
private final Marshaller<Object, V> marshaller;
private final BiFunction<K, V, Mutator> mutatorFactory;
private final Immutability immutability;
private final CacheProperties properties;

private volatile Map<String, UUID> names;

public FineSessionAttributes(String id, Map<String, UUID> names, Cache<SessionAttributeNamesKey, Map<String, UUID>> namesCache, Cache<SessionAttributeKey, V> attributeCache, Marshaller<Object, V> marshaller, Immutability immutability, CacheProperties properties) {
this.id = id;
public FineSessionAttributes(NK key, Map<String, UUID> names, Map<NK, Map<String, UUID>> namesCache, Function<UUID, K> keyFactory, Map<K, V> attributeCache, Marshaller<Object, V> marshaller, BiFunction<K, V, Mutator> mutatorFactory, Immutability immutability, CacheProperties properties) {
this.key = key;
this.setNames(names);
this.namesCache = namesCache;
this.keyFactory = keyFactory;
this.attributeCache = attributeCache;
this.marshaller = marshaller;
this.mutatorFactory = mutatorFactory;
this.immutability = immutability;
this.properties = properties;
}
@@ -73,10 +75,10 @@ public Object removeAttribute(String name) {
UUID attributeId = this.names.get(name);
if (attributeId == null) return null;

this.setNames(this.namesCache.getAdvancedCache().withFlags(Flag.FORCE_SYNCHRONOUS).computeIfPresent(this.createKey(), this.properties.isTransactional() ? new CopyOnWriteMapRemoveFunction<>(name) : new ConcurrentMapRemoveFunction<>(name)));
this.setNames(this.namesCache.computeIfPresent(this.key, this.properties.isTransactional() ? new CopyOnWriteMapRemoveFunction<>(name) : new ConcurrentMapRemoveFunction<>(name)));

Object result = this.read(name, this.attributeCache.getAdvancedCache().withFlags(Flag.FORCE_SYNCHRONOUS).remove(this.createKey(attributeId)));
this.mutations.remove(name);
Object result = this.read(this.attributeCache.remove(this.keyFactory.apply(attributeId)));
this.mutations.remove(attributeId);
return result;
}

@@ -93,21 +95,21 @@ public Object setAttribute(String name, Object attribute) {
UUID attributeId = this.names.get(name);
if (attributeId == null) {
UUID newAttributeId = UUID.randomUUID();
this.setNames(this.namesCache.getAdvancedCache().withFlags(Flag.FORCE_SYNCHRONOUS).compute(this.createKey(), this.properties.isTransactional() ? new CopyOnWriteMapPutFunction<>(name, newAttributeId) : new ConcurrentMapPutFunction<>(name, newAttributeId)));
this.setNames(this.namesCache.compute(this.key, this.properties.isTransactional() ? new CopyOnWriteMapPutFunction<>(name, newAttributeId) : new ConcurrentMapPutFunction<>(name, newAttributeId)));
attributeId = this.names.get(name);
}

SessionAttributeKey key = this.createKey(attributeId);
Object result = this.read(name, this.attributeCache.getAdvancedCache().withFlags(Flag.FORCE_SYNCHRONOUS).put(key, value));
K key = this.keyFactory.apply(attributeId);
Object result = this.read(this.attributeCache.put(key, value));
if (this.properties.isTransactional()) {
// Add a passive mutation to prevent any subsequent mutable getAttribute(...) from triggering a redundant mutation on close.
this.mutations.put(name, Mutator.PASSIVE);
this.mutations.put(attributeId, Mutator.PASSIVE);
} else {
// If the object is mutable, we need to indicate trigger a mutation on close
if (this.immutability.test(attribute)) {
this.mutations.remove(name);
this.mutations.remove(attributeId);
} else {
this.mutations.put(name, new CacheEntryMutator<>(this.attributeCache, key, value));
this.mutations.put(attributeId, this.mutatorFactory.apply(key, value));
}
}
return result;
@@ -118,13 +120,13 @@ public Object getAttribute(String name) {
UUID attributeId = this.names.get(name);
if (attributeId == null) return null;

SessionAttributeKey key = this.createKey(attributeId);
K key = this.keyFactory.apply(attributeId);
V value = this.attributeCache.get(key);
Object attribute = this.read(name, value);
Object attribute = this.read(value);
if (attribute != null) {
// If the object is mutable, we need to trigger a mutation on close
if (!this.immutability.test(attribute)) {
this.mutations.putIfAbsent(name, new CacheEntryMutator<>(this.attributeCache, key, value));
this.mutations.putIfAbsent(attributeId, this.mutatorFactory.apply(key, value));
}
}
return attribute;
@@ -147,20 +149,12 @@ private void setNames(Map<String, UUID> names) {
this.names = (names != null) ? Collections.unmodifiableMap(names) : Collections.emptyMap();
}

private SessionAttributeNamesKey createKey() {
return new SessionAttributeNamesKey(this.id);
}

private SessionAttributeKey createKey(UUID attributeId) {
return new SessionAttributeKey(this.id, attributeId);
}

private Object read(String name, V value) {
private Object read(V value) {
try {
return this.marshaller.read(value);
} catch (InvalidSerializedFormException e) {
// This should not happen here, since attributes were pre-activated during FineSessionFactory.findValue(...)
throw InfinispanWebLogger.ROOT_LOGGER.failedToReadSessionAttribute(e, this.id, name);
// This should not happen here, since attributes were pre-activated during session construction
throw new IllegalStateException(e);
}
}
}
@@ -19,7 +19,7 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.sso;
package org.wildfly.clustering.web.cache.sso;

import java.util.concurrent.atomic.AtomicReference;

@@ -19,7 +19,7 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.sso;
package org.wildfly.clustering.web.cache.sso;

import java.io.IOException;
import java.io.ObjectInput;
@@ -19,7 +19,7 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.sso;
package org.wildfly.clustering.web.cache.sso;

import java.util.concurrent.atomic.AtomicReference;

@@ -28,15 +28,15 @@
import org.wildfly.clustering.web.sso.SSO;
import org.wildfly.clustering.web.sso.Sessions;

public class InfinispanSSO<A, D, S, L> implements SSO<A, D, S, L> {
public class CompositeSSO<A, D, S, L> implements SSO<A, D, S, L> {
private final String id;
private final A authentication;
private final Sessions<D, S> sessions;
private final AtomicReference<L> localContext;
private final LocalContextFactory<L> localContextFactory;
private final Remover<String> remover;

public InfinispanSSO(String id, A authentication, Sessions<D, S> sessions, AtomicReference<L> localContext, LocalContextFactory<L> localContextFactory, Remover<String> remover) {
public CompositeSSO(String id, A authentication, Sessions<D, S> sessions, AtomicReference<L> localContext, LocalContextFactory<L> localContextFactory, Remover<String> remover) {
this.id = id;
this.authentication = authentication;
this.sessions = sessions;
@@ -19,24 +19,24 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.sso;
package org.wildfly.clustering.web.cache.sso;

import java.util.Map;

import org.wildfly.clustering.ee.Batcher;
import org.wildfly.clustering.ee.infinispan.TransactionBatch;
import org.wildfly.clustering.ee.cache.tx.TransactionBatch;
import org.wildfly.clustering.web.IdentifierFactory;
import org.wildfly.clustering.web.sso.SSO;
import org.wildfly.clustering.web.sso.SSOManager;
import org.wildfly.clustering.web.sso.Sessions;

public class InfinispanSSOManager<AV, SV, A, D, S, L> implements SSOManager<A, D, S, L, TransactionBatch> {
public class CompositeSSOManager<AV, SV, A, D, S, L> implements SSOManager<A, D, S, L, TransactionBatch> {

private final SSOFactory<AV, SV, A, D, S, L> factory;
private final Batcher<TransactionBatch> batcher;
private final IdentifierFactory<String> identifierFactory;

public InfinispanSSOManager(SSOFactory<AV, SV, A, D, S, L> factory, IdentifierFactory<String> identifierFactory, Batcher<TransactionBatch> batcher) {
public CompositeSSOManager(SSOFactory<AV, SV, A, D, S, L> factory, IdentifierFactory<String> identifierFactory, Batcher<TransactionBatch> batcher) {
this.factory = factory;
this.batcher = batcher;
this.identifierFactory = identifierFactory;
@@ -19,7 +19,7 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.sso;
package org.wildfly.clustering.web.cache.sso;

import java.util.Map;

@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.sso;
package org.wildfly.clustering.web.cache.sso;

import java.util.Map;

@@ -19,7 +19,7 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.sso.coarse;
package org.wildfly.clustering.web.cache.sso.coarse;

import java.util.Collections;
import java.util.Map;
@@ -20,17 +20,19 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.web.infinispan.sso.coarse;
package org.wildfly.clustering.web.cache.sso.coarse;

import java.util.Map;
import java.util.function.Predicate;

/**
* Selects SSO sessions entries containing the specified session.
* @author Paul Ferraro
* @param <K> the cache key type
* @param <D> the deployment type
* @param <S> the session type
*/
public class SessionFilter<D, S> implements Predicate<Map.Entry<CoarseSessionsKey, Map<D, S>>> {
public class SessionFilter<K, D, S> implements Predicate<Map.Entry<K, Map<D, S>>> {

private final S session;

@@ -43,7 +45,7 @@ public S getSession() {
}

@Override
public boolean test(Map.Entry<CoarseSessionsKey, Map<D, S>> entry) {
public boolean test(Map.Entry<K, Map<D, S>> entry) {
return entry.getValue().values().contains(this.session);
}
}