Skip to content

Commit

Permalink
TP-1259: Add Partitioned Space (#54)
Browse files Browse the repository at this point in the history
* TP-1259: Add Partitioned Space

* Converted from legacy code
* Re-implemented using `PartitionedPu` under the hood instead of a separate implementation
* Test class cannot be run without using a gs license (will work in later versions)
* Backport possibility to configure `PartitionedPuConfigurer` and `MirrorPuConfigurer` with `Resource` from `main` branch
  • Loading branch information
pativa authored Oct 31, 2022
1 parent 8ac0ddb commit e8f7231
Show file tree
Hide file tree
Showing 9 changed files with 461 additions and 3 deletions.
4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
</dependencies>
<properties>
<!-- -Xdoclint:NONE ignores validation errors in javadoc -->
Expand Down
10 changes: 9 additions & 1 deletion src/main/java/com/avanza/gs/test/MirrorPu.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.openspaces.pu.container.integrated.IntegratedProcessingUnitContainer;
import org.openspaces.pu.container.integrated.IntegratedProcessingUnitContainerProvider;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.util.Properties;
Expand All @@ -29,13 +30,15 @@ public class MirrorPu implements PuRunner {
private IntegratedProcessingUnitContainer container;
private final String gigaSpaceBeanName = "gigaSpace";
private final String puXmlPath;
private final Resource puConfigResource;
private Properties contextProperties = new Properties();
private final String lookupGroupName;
private final boolean autostart;
private final ApplicationContext parentContext;

public MirrorPu(MirrorPuConfigurer config) {
this.puXmlPath = config.puXmlPath;
this.puConfigResource = config.puConfigResource;
this.contextProperties = config.properties;
this.lookupGroupName = config.lookupGroupName;
this.autostart = true;
Expand All @@ -56,7 +59,12 @@ public void run() throws IOException {
private void startContainers() throws IOException {
IntegratedProcessingUnitContainerProvider provider = new IntegratedProcessingUnitContainerProvider();
provider.setBeanLevelProperties(createBeanLevelProperties());
provider.addConfigLocation(puXmlPath);
if (puXmlPath != null) {
provider.addConfigLocation(puXmlPath);
}
if (puConfigResource != null) {
provider.addConfigLocation(puConfigResource);
}
if (parentContext != null) {
provider.setParentContext(parentContext);
}
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/com/avanza/gs/test/MirrorPuConfigurer.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,24 @@
import java.util.Properties;

import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;

public class MirrorPuConfigurer {

final String puXmlPath;
final Resource puConfigResource;
Properties properties = new Properties();
ApplicationContext parentContext;
String lookupGroupName = JVMGlobalLus.getLookupGroupName();

public MirrorPuConfigurer(String puXmlPath) {
this.puXmlPath = puXmlPath;
this.puConfigResource = null;
}

public MirrorPuConfigurer(Resource puConfigResource) {
this.puXmlPath = null;
this.puConfigResource = puConfigResource;
}

/**
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/com/avanza/gs/test/PartitionedPu.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import org.openspaces.pu.container.integrated.IntegratedProcessingUnitContainerProvider;
import org.openspaces.pu.container.support.CompoundProcessingUnitContainer;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;

import com.gigaspaces.security.directory.DefaultCredentialsProvider;

/**
Expand All @@ -39,6 +41,7 @@ public final class PartitionedPu implements PuRunner {
private CompoundProcessingUnitContainer container;
private final String gigaSpaceBeanName = "gigaSpace";
private final String puXmlPath;
private final Resource puConfigResource;
private final Integer numberOfPrimaries;
private final Integer numberOfBackups;
private final Properties contextProperties = new Properties();
Expand All @@ -50,6 +53,7 @@ public final class PartitionedPu implements PuRunner {

public PartitionedPu(PartitionedPuConfigurer configurer) {
this.puXmlPath = configurer.puXmlPath;
this.puConfigResource = configurer.puConfigResource;
this.numberOfBackups = configurer.numberOfBackups;
this.numberOfPrimaries = configurer.numberOfPrimaries;
this.contextProperties.putAll(configurer.contextProperties);
Expand All @@ -76,7 +80,12 @@ private void startContainers() throws IOException {
IntegratedProcessingUnitContainerProvider provider = new IntegratedProcessingUnitContainerProvider();
provider.setBeanLevelProperties(createBeanLevelProperties());
provider.setClusterInfo(createClusterInfo());
provider.addConfigLocation(puXmlPath);
if (puXmlPath != null) {
provider.addConfigLocation(puXmlPath);
}
if (puConfigResource != null) {
provider.addConfigLocation(puConfigResource);
}
if (parentContext != null) {
provider.setParentContext(parentContext);
}
Expand Down
10 changes: 9 additions & 1 deletion src/main/java/com/avanza/gs/test/PartitionedPuConfigurer.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
import java.util.Properties;

import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;

public final class PartitionedPuConfigurer {

String puXmlPath;
final String puXmlPath;
final Resource puConfigResource;
int numberOfPrimaries = 1;
int numberOfBackups = 0;
boolean startAsync = false;
Expand All @@ -37,6 +39,12 @@ public final class PartitionedPuConfigurer {

public PartitionedPuConfigurer(String puXmlPath) {
this.puXmlPath = puXmlPath;
this.puConfigResource = null;
}

public PartitionedPuConfigurer(Resource puConfigResource) {
this.puXmlPath = null;
this.puConfigResource = puConfigResource;
}

public PartitionedPuConfigurer parentContext(ApplicationContext parentContext) {
Expand Down
215 changes: 215 additions & 0 deletions src/main/java/com/avanza/gs/test/PartitionedSpace.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
/*
* Copyright 2017 Avanza Bank AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.avanza.gs.test;

import static java.nio.charset.StandardCharsets.UTF_8;

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.openspaces.core.GigaSpace;
import org.openspaces.core.space.UrlSpaceConfigurer;
import org.springframework.core.io.FileSystemResource;
import org.springframework.util.StreamUtils;

/**
* Utility class to create a partitioned space without backups.
* <p>
* Individual primary instances can be retrieved by using the {@code partition(ID)} method. An url to the
* cluster can be retrieved through the {@code getUrl()} method.
*
* @deprecated This class is provided for backwards compatibility.
* For a simple test with no need for partitions, {@link EmbeddedSpace} can be used instead.
* For more complex tests, use {@link PuConfigurers} to set up a {@code partitionedPu}.
*/
@Deprecated
public class PartitionedSpace implements TestRule {

private final GigaSpace[] instances;
private final RunningPu partitionedPu;
private final Path puXml;
private final String spaceName;
private final String groupName;
private final int numberOfPartitions;

private boolean started = false;

/**
* Creates a partitioned space with a given number of partitions.
*
* @param numberOfPartitions (must be at least 2).
* @throws IllegalArgumentException if numberOfPartitions is less than 2.
*/
public PartitionedSpace(int numberOfPartitions) {
this(numberOfPartitions, "testSpace");
}

/**
* Creates a partitioned space with a given number of partitions.
*
* @param numberOfPartitions (must be at least 2).
* @param spaceName name of the space to create.
*
* @throws IllegalArgumentException if numberOfPartitions is less than 2.
* @throws IllegalArgumentException if spaceName is empty string.
* @throws NullPointerException if spaceName is null.
*/
public PartitionedSpace(int numberOfPartitions, String spaceName) {
this(numberOfPartitions, spaceName, JVMGlobalLus.getLookupGroupName());
}

public PartitionedSpace(int numberOfPartitions, String spaceName, String lookupGroupName) {
if (numberOfPartitions < 2) {
throw new IllegalArgumentException("Number of partitions must be at least 2, was " + numberOfPartitions);
}
if (spaceName.isEmpty()) {
throw new IllegalArgumentException("Space name must not be empty");
}
this.numberOfPartitions = numberOfPartitions;
this.groupName = lookupGroupName;
this.spaceName = spaceName;
this.instances = new GigaSpace[numberOfPartitions];
this.puXml = writePuXml(spaceName);
this.partitionedPu = PuConfigurers.partitionedPu(new FileSystemResource(puXml.toFile()))
.lookupGroup(lookupGroupName)
.spaceName(spaceName)
.numberOfPrimaries(numberOfPartitions)
.numberOfBackups(0)
.configure();

start();
}

private static Path writePuXml(String spaceName) {
try (InputStream in = PartitionedSpace.class.getResourceAsStream("/partitioned_space/simple-pu.xml.template")) {
Path tempFile = Files.createTempFile("partitioned-space-", ".xml");
String content = StreamUtils.copyToString(in, UTF_8)
.replace("##SPACE_NAME##", spaceName);
return Files.write(tempFile, content.getBytes(UTF_8));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}

public void start() {
if (started) {
return;
}
try {
partitionedPu.start();
} catch (Exception e) {
throw new RuntimeException("Could not start partitionedPu", e);
}
for (int instanceId = 1; instanceId <= numberOfPartitions; instanceId ++) {
instances[instanceId - 1] = partitionedPu.getPrimaryInstanceApplicationContext(instanceId - 1)
.getBean(GigaSpace.class);
}
started = true;
}

@Deprecated
protected void configure(UrlSpaceConfigurer spaceConfigurer) {
throw new UnsupportedOperationException("This method is not supported");
}

/**
* Returns the primary with the given instanceId.
*
* NOTE: Primaries are numbered from 1!
*/
public GigaSpace primary(int instanceId) {
if (instanceId < 1) {
throw new IllegalArgumentException("Primaries are numbered from 1! Requested instance was " + instanceId);
}
if (instanceId > instances.length) {
throw new IllegalArgumentException("No such primary: " + instanceId + ". Space contains " + this.instances.length + " partitions.");
}
return instances[instanceId - 1];
}

private static final Object ALL_OBJECTS = null; /* Intentional NULL */

/**
* Cleans all space's in this cluster.
*/
public void clean() {
for (GigaSpace instance : instances) {
instance.clear(ALL_OBJECTS);
}
}

/**
* Returns an url to this space.
*/
public String getUrl() {
return "jini://*/*/" + this.spaceName + "?groups=" + this.groupName;
}

/**
* Creates a clustered proxy against this space.
*/
public GigaSpace createClusteredProxy() {
return partitionedPu.getClusteredGigaSpace();
}

/**
* Destroys this space.
*/
public void destroy() {
try {
partitionedPu.stop();
Files.deleteIfExists(puXml);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

/**
* Returns the name of this space.
*/
public String getName() {
return this.spaceName;
}

/**
* Returns the lookup group name
*/
public String getLookupGroupName() {
return this.groupName;
}

@Override
public Statement apply(final Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
start();
base.evaluate();
} finally {
destroy();
}
}
};
}

}
10 changes: 10 additions & 0 deletions src/main/java/com/avanza/gs/test/PuConfigurers.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,24 @@
*/
package com.avanza.gs.test;

import org.springframework.core.io.Resource;

public class PuConfigurers {

public static PartitionedPuConfigurer partitionedPu(String puXmlPath) {
return new PartitionedPuConfigurer(puXmlPath);
}

public static PartitionedPuConfigurer partitionedPu(Resource puConfigResource) {
return new PartitionedPuConfigurer(puConfigResource);
}

public static MirrorPuConfigurer mirrorPu(String puXmlPath) {
return new MirrorPuConfigurer(puXmlPath);
}

public static MirrorPuConfigurer mirrorPu(Resource puConfigResource) {
return new MirrorPuConfigurer(puConfigResource);
}

}
Loading

0 comments on commit e8f7231

Please sign in to comment.