Restructure the Spring Boot for Apache Geode project to mirror Spring Boot's project structure.
Resolves gh-60.
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
description = "Apache Geode Extensions"
|
||||
|
||||
dependencies {
|
||||
|
||||
api "org.apache.geode:geode-core:$apacheGeodeVersion"
|
||||
api "org.apache.geode:geode-cq:$apacheGeodeVersion"
|
||||
api "org.apache.geode:geode-lucene:$apacheGeodeVersion"
|
||||
api "org.apache.geode:geode-wan:$apacheGeodeVersion"
|
||||
|
||||
implementation "com.fasterxml.jackson.core:jackson-databind"
|
||||
|
||||
// See additional testImplementation dependencies declared in the testDependencies project extension
|
||||
// defined in the DependencySetPlugin.
|
||||
testImplementation "org.apache.geode:geode-membership:$apacheGeodeVersion"
|
||||
testImplementation "org.apache.geode:geode-serialization:$apacheGeodeVersion"
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.cache;
|
||||
|
||||
import org.apache.geode.cache.CacheListener;
|
||||
import org.apache.geode.cache.EntryEvent;
|
||||
import org.apache.geode.cache.RegionEvent;
|
||||
import org.apache.geode.cache.util.CacheListenerAdapter;
|
||||
|
||||
/**
|
||||
* An {@link Class abstract base class} implementing the Apache Geode {@link CacheListener} interface
|
||||
* by extending the {@link CacheListenerAdapter} base class, which processes all {@link EntryEvent EntryEvents}
|
||||
* and {@link RegionEvent RegionEvents} using the same logic.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.CacheListener
|
||||
* @see org.apache.geode.cache.EntryEvent
|
||||
* @see org.apache.geode.cache.RegionEvent
|
||||
* @see org.apache.geode.cache.util.CacheListenerAdapter
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public abstract class AbstractCommonEventProcessingCacheListener<K, V> extends CacheListenerAdapter<K, V> {
|
||||
|
||||
@Override
|
||||
public void afterCreate(EntryEvent<K, V> event) {
|
||||
processEntryEvent(event, EntryEventType.CREATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterDestroy(EntryEvent<K, V> event) {
|
||||
processEntryEvent(event, EntryEventType.DESTROY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterInvalidate(EntryEvent<K, V> event) {
|
||||
processEntryEvent(event, EntryEventType.INVALIDATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterUpdate(EntryEvent<K, V> event) {
|
||||
processEntryEvent(event, EntryEventType.UPDATE);
|
||||
}
|
||||
|
||||
protected void processEntryEvent(EntryEvent<K, V> event, EntryEventType eventType) { }
|
||||
|
||||
@Override
|
||||
public void afterRegionClear(RegionEvent<K, V> event) {
|
||||
processRegionEvent(event, RegionEventType.CLEAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterRegionCreate(RegionEvent<K, V> event) {
|
||||
processRegionEvent(event, RegionEventType.CREATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterRegionDestroy(RegionEvent<K, V> event) {
|
||||
processRegionEvent(event, RegionEventType.DESTROY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterRegionInvalidate(RegionEvent<K, V> event) {
|
||||
processRegionEvent(event, RegionEventType.INVALIDATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterRegionLive(RegionEvent<K, V> event) {
|
||||
processRegionEvent(event, RegionEventType.LIVE);
|
||||
}
|
||||
|
||||
protected void processRegionEvent(RegionEvent<K, V> event, RegionEventType eventType) { }
|
||||
|
||||
public enum EntryEventType {
|
||||
|
||||
CREATE,
|
||||
DESTROY,
|
||||
INVALIDATE,
|
||||
UPDATE;
|
||||
|
||||
}
|
||||
|
||||
public enum RegionEventType {
|
||||
|
||||
CLEAR,
|
||||
CREATE,
|
||||
DESTROY,
|
||||
INVALIDATE,
|
||||
LIVE;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.cache;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.CacheFactory;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.RegionService;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.client.ClientCacheFactory;
|
||||
|
||||
import org.springframework.geode.util.CacheUtils;
|
||||
|
||||
/**
|
||||
* The {@link SimpleCacheResolver} abstract class contains utility functions for resolving Apache Geode
|
||||
* {@link GemFireCache} instances, such as a {@link ClientCache} or a {@literal peer} {@link Cache}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.CacheFactory
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.RegionService
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.client.ClientCacheFactory
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class SimpleCacheResolver {
|
||||
|
||||
private static final AtomicReference<SimpleCacheResolver> instance = new AtomicReference<>(null);
|
||||
|
||||
/**
|
||||
* Lazily constructs and gets an instance to the {@link SimpleCacheResolver}, as needed.
|
||||
*
|
||||
* @return an instance of the {@link SimpleCacheResolver}.
|
||||
* @see #newSimpleCacheResolver()
|
||||
*/
|
||||
public static SimpleCacheResolver getInstance() {
|
||||
|
||||
return instance.updateAndGet(cacheResolver -> cacheResolver != null
|
||||
? cacheResolver
|
||||
: newSimpleCacheResolver());
|
||||
}
|
||||
|
||||
// TODO Consider resolving the SimpleCacheResolver instance using Java's ServiceProvider API.
|
||||
private static SimpleCacheResolver newSimpleCacheResolver() {
|
||||
return new SimpleCacheResolver() { };
|
||||
}
|
||||
|
||||
/**
|
||||
* The 1st {@code resolve():Optional<? extends GemFireCache>} method signature avoids the cast
|
||||
* and the @SuppressWarnings("unchecked") annotation, but puts the burden on the caller.
|
||||
* The 2nd {@code resolve():Optional<T extends GemFireCache>} method signature requires a cast
|
||||
* and the @SuppressWarnings("unchecked") annotation, but avoids putting the burden on the caller.
|
||||
*/
|
||||
private static void testCallResolve() {
|
||||
Optional<ClientCache> clientCache = getInstance().resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* The resolution algorithm first tries to resolve an {@link Optional} {@link ClientCache} instance
|
||||
* then a {@literal peer} {@link Cache} instance if a {@link ClientCache} is not present.
|
||||
*
|
||||
* If neither a {@link ClientCache} or {@literal peer} {@link Cache} is available, then {@link Optional#empty()}
|
||||
* is returned. No {@link Throwable Exception} is thrown.
|
||||
*
|
||||
* @param <T> {@link Class subclass} of {@link GemFireCache}.
|
||||
* @return a {@link ClientCache} or then a {@literal peer} {@link Cache} instance if present.
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see java.util.Optional
|
||||
* @see #resolveClientCache()
|
||||
* @see #resolvePeerCache()
|
||||
*/
|
||||
//public static Optional<? extends GemFireCache> resolve() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends GemFireCache> Optional<T> resolve() {
|
||||
|
||||
Optional<ClientCache> clientCache = resolveClientCache();
|
||||
|
||||
return (Optional<T>) (clientCache.isPresent() ? clientCache : resolvePeerCache());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to resolve an {@link Optional} {@link ClientCache} instance.
|
||||
*
|
||||
* @return an {@link Optional} {@link ClientCache} instance.
|
||||
* @see org.springframework.geode.util.CacheUtils#isClientCache(RegionService)
|
||||
* @see org.apache.geode.cache.client.ClientCacheFactory#getAnyInstance()
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see java.util.Optional
|
||||
*/
|
||||
public Optional<ClientCache> resolveClientCache() {
|
||||
|
||||
try {
|
||||
return Optional.ofNullable(ClientCacheFactory.getAnyInstance())
|
||||
.filter(CacheUtils::isClientCache);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to resolve an {@link Optional} {@link Cache} instance.
|
||||
*
|
||||
* @return an {@link Optional} {@link Cache} instance.
|
||||
* @see org.springframework.geode.util.CacheUtils#isPeerCache(RegionService)
|
||||
* @see org.apache.geode.cache.CacheFactory#getAnyInstance()
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see java.util.Optional
|
||||
*/
|
||||
public Optional<Cache> resolvePeerCache() {
|
||||
|
||||
try {
|
||||
return Optional.ofNullable(CacheFactory.getAnyInstance())
|
||||
.filter(CacheUtils::isPeerCache);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires an instance of either a {@link ClientCache} or a {@literal peer} {@link Cache}.
|
||||
*
|
||||
* @param <T> {@link Class subclass} of {@link GemFireCache} to resolve.
|
||||
* @return an instance of either a {@link ClientCache} or a {@literal peer} {@link Cache}.
|
||||
* @throws IllegalStateException if a cache instance cannot be resolved.
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see #resolve()
|
||||
*/
|
||||
public <T extends GemFireCache> T require() {
|
||||
return this.<T>resolve()
|
||||
.orElseThrow(() -> new IllegalStateException("GemFireCache not found"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.distributed.event;
|
||||
|
||||
import java.util.EventObject;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.distributed.DistributedMember;
|
||||
import org.apache.geode.distributed.DistributedSystem;
|
||||
import org.apache.geode.distributed.internal.DistributionManager;
|
||||
|
||||
/**
|
||||
* {@link EventObject} implementation indicating a membership event in the {@link DistributedSystem}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @param <T> specific {@link Class type} of {@link MembershipEvent}.
|
||||
* @see java.util.EventObject
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see org.apache.geode.distributed.DistributedSystem
|
||||
* @see org.apache.geode.distributed.internal.DistributionManager
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class MembershipEvent<T extends MembershipEvent<T>> extends EventObject {
|
||||
|
||||
private DistributedMember distributedMember;
|
||||
|
||||
/**
|
||||
* Asserts that the given {@link Object target} is not {@literal null}.
|
||||
*
|
||||
* @param <T> {@link Class type} of the {@link Object target}.
|
||||
* @param target {@link Object} to evaluate.
|
||||
* @param message {@link String} containing the message for the {@link IllegalArgumentException}.
|
||||
* @param arguments array of {@link Object arguments} to populate the placeholders in the {@link String message}.
|
||||
* @return the {@link Object target}.
|
||||
* @throws IllegalArgumentException if {@link Object target} is {@literal null}.
|
||||
*/
|
||||
protected static <T> T assertNotNull(T target, String message, Object... arguments) {
|
||||
|
||||
if (target == null) {
|
||||
throw new IllegalArgumentException(String.format(message, arguments));
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link MembershipEvent} initialized with the given {@link DistributionManager}.
|
||||
*
|
||||
* @param distributionManager {@link DistributionManager} used to acquire the {@link Cache}, which is used
|
||||
* as the {@literal source} of this event.
|
||||
* @throws IllegalArgumentException if {@link DistributionManager} is {@literal null}.
|
||||
* @see org.apache.geode.distributed.internal.DistributionManager
|
||||
*/
|
||||
public MembershipEvent(DistributionManager distributionManager) {
|
||||
super(assertNotNull(distributionManager, "DistributionManager must not be null"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} reference to the {@literal peer} {@link Cache}.
|
||||
*
|
||||
* @return an {@link Optional} reference to the {@literal peer} {@link Cache}.
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see #getDistributionManager()
|
||||
* @see java.util.Optional
|
||||
*/
|
||||
public Optional<Cache> getCache() {
|
||||
return Optional.ofNullable(getDistributionManager().getCache());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} reference to the {@link DistributedMember} that is the subject
|
||||
* of this {@link MembershipEvent}.
|
||||
*
|
||||
* @return an {@link Optional} reference to the {@link DistributedMember} that is the subject of this event.
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see #getDistributionManager()
|
||||
* @see java.util.Optional
|
||||
*/
|
||||
public Optional<DistributedMember> getDistributedMember() {
|
||||
return Optional.ofNullable(this.distributedMember);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} reference to the {@link DistributedSystem} (cluster) to which the {@literal peer}
|
||||
* {@link Cache} is connected.
|
||||
*
|
||||
* @return an {@link Optional} reference to the {@link DistributedSystem}.
|
||||
* @see org.apache.geode.distributed.DistributedSystem
|
||||
* @see #getDistributionManager()
|
||||
* @see java.util.Optional
|
||||
*/
|
||||
public Optional<DistributedSystem> getDistributedSystem() {
|
||||
return Optional.ofNullable(getDistributionManager().getSystem());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the configured {@link DistributionManager} which is use as the {@link #getSource() source}
|
||||
* of this event.
|
||||
*
|
||||
* @return a reference to the {@link DistributionManager}.
|
||||
* @see org.apache.geode.distributed.internal.DistributionManager
|
||||
*/
|
||||
public DistributionManager getDistributionManager() {
|
||||
return (DistributionManager) getSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Type} of this {@link MembershipEvent}, such as {@link Type#MEMBER_JOINED}.
|
||||
*
|
||||
* @return the {@link MembershipEvent.Type}.
|
||||
*/
|
||||
public Type getType() {
|
||||
return Type.UNQUALIFIED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe builder method used to configure the {@link DistributedMember member} that is the subject
|
||||
* of this event.
|
||||
*
|
||||
* @param distributedMember {@link DistributedMember} that is the subject of this event.
|
||||
* @return this {@link MembershipEvent}.
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see #getDistributedMember()
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T withMember(DistributedMember distributedMember) {
|
||||
|
||||
this.distributedMember = distributedMember;
|
||||
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link Enum enumeration} of different type of {@link MembershipEvent MembershipEvents}.
|
||||
*/
|
||||
public enum Type {
|
||||
|
||||
MEMBER_DEPARTED,
|
||||
MEMBER_JOINED,
|
||||
MEMBER_SUSPECT,
|
||||
QUORUM_LOST,
|
||||
UNQUALIFIED;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.distributed.event;
|
||||
|
||||
import java.util.EventListener;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.distributed.internal.DistributionManager;
|
||||
import org.apache.geode.distributed.internal.InternalDistributedSystem;
|
||||
import org.apache.geode.distributed.internal.MembershipListener;
|
||||
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
|
||||
|
||||
import org.springframework.geode.distributed.event.support.MemberDepartedEvent;
|
||||
import org.springframework.geode.distributed.event.support.MemberJoinedEvent;
|
||||
import org.springframework.geode.distributed.event.support.MemberSuspectEvent;
|
||||
import org.springframework.geode.distributed.event.support.QuorumLostEvent;
|
||||
|
||||
/**
|
||||
* An abstract {@link MembershipListener} implementation using the
|
||||
* <a href="https://en.wikipedia.org/wiki/Adapter_pattern">Adapter Software Design Pattern</a>
|
||||
* to delegate membership event callbacks to event handlers for those membership events.
|
||||
*
|
||||
* @author John Blum
|
||||
* @param <T> specific {@link Class sub-type} of this {@link MembershipListenerAdapter}.
|
||||
* @see java.util.EventListener
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.distributed.internal.DistributionManager
|
||||
* @see org.apache.geode.distributed.internal.InternalDistributedSystem
|
||||
* @see org.apache.geode.distributed.internal.MembershipListener
|
||||
* @see org.apache.geode.distributed.internal.membership.InternalDistributedMember
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class MembershipListenerAdapter<T extends MembershipListenerAdapter<T>>
|
||||
implements EventListener, MembershipListener {
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public final void memberDeparted(DistributionManager manager, InternalDistributedMember member, boolean crashed) {
|
||||
|
||||
MemberDepartedEvent event = new MemberDepartedEvent(manager)
|
||||
.withMember(member)
|
||||
.crashed(crashed);
|
||||
|
||||
handleMemberDeparted(event);
|
||||
}
|
||||
|
||||
public void handleMemberDeparted(MemberDepartedEvent event) { }
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public final void memberJoined(DistributionManager manager, InternalDistributedMember member) {
|
||||
|
||||
MemberJoinedEvent event = new MemberJoinedEvent(manager)
|
||||
.withMember(member);
|
||||
|
||||
handleMemberJoined(event);
|
||||
}
|
||||
|
||||
public void handleMemberJoined(MemberJoinedEvent event) { }
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public final void memberSuspect(DistributionManager manager, InternalDistributedMember member,
|
||||
InternalDistributedMember suspectMember, String reason) {
|
||||
|
||||
MemberSuspectEvent event = new MemberSuspectEvent(manager)
|
||||
.withMember(member)
|
||||
.withReason(reason)
|
||||
.withSuspect(suspectMember);
|
||||
|
||||
handleMemberSuspect(event);
|
||||
}
|
||||
|
||||
public void handleMemberSuspect(MemberSuspectEvent event) { }
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public final void quorumLost(DistributionManager manager, Set<InternalDistributedMember> failedMembers,
|
||||
List<InternalDistributedMember> remainingMembers) {
|
||||
|
||||
QuorumLostEvent event = new QuorumLostEvent(manager)
|
||||
.withFailedMembers(failedMembers)
|
||||
.withRemainingMembers(remainingMembers);
|
||||
|
||||
handleQuorumLost(event);
|
||||
}
|
||||
|
||||
public void handleQuorumLost(QuorumLostEvent event) { }
|
||||
|
||||
/**
|
||||
* Registers this {@link MembershipListener} with the given {@literal peer} {@link Cache}.
|
||||
*
|
||||
* @param peerCache {@literal peer} {@link Cache} on which to register this {@link MembershipListener}.
|
||||
* @return this {@link MembershipListenerAdapter}.
|
||||
* @see org.apache.geode.cache.Cache
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T register(Cache peerCache) {
|
||||
|
||||
Optional.ofNullable(peerCache)
|
||||
.map(Cache::getDistributedSystem)
|
||||
.filter(InternalDistributedSystem.class::isInstance)
|
||||
.map(InternalDistributedSystem.class::cast)
|
||||
.map(InternalDistributedSystem::getDistributionManager)
|
||||
.ifPresent(distributionManager -> distributionManager
|
||||
.addMembershipListener(this));
|
||||
|
||||
return (T) this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.distributed.event.support;
|
||||
|
||||
import org.apache.geode.distributed.DistributedMember;
|
||||
import org.apache.geode.distributed.DistributedSystem;
|
||||
import org.apache.geode.distributed.internal.DistributionManager;
|
||||
|
||||
import org.springframework.geode.distributed.event.MembershipEvent;
|
||||
|
||||
/**
|
||||
* {@link MembershipEvent} fired when a {@link DistributedMember} departs from the {@link DistributedSystem}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see org.apache.geode.distributed.DistributedSystem
|
||||
* @see org.springframework.geode.distributed.event.MembershipEvent
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class MemberDepartedEvent extends MembershipEvent<MemberDepartedEvent> {
|
||||
|
||||
private boolean crashed = false;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link MemberDepartedEvent} initialized with the given {@link DistributionManager}.
|
||||
*
|
||||
* @param distributionManager {@link DistributionManager} used as the {@link #getSource() source} of this event;
|
||||
* must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if {@link DistributionManager} is {@literal null}.
|
||||
* @see org.apache.geode.distributed.internal.DistributionManager
|
||||
*/
|
||||
public MemberDepartedEvent(DistributionManager distributionManager) {
|
||||
super(distributionManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the peer member crashed when it departed from the {@link DistributedSystem} (cluster).
|
||||
*
|
||||
* @return a boolean value indicating whether the peer member crashed when it departed
|
||||
* from the {@link DistributedSystem} (cluster).
|
||||
*/
|
||||
public boolean isCrashed() {
|
||||
return this.crashed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder method used to configure the {@link #isCrashed()} property indicating whether the peer member crashed
|
||||
* when it departed from the {@link DistributedSystem}.
|
||||
*
|
||||
* @param crashed boolean value indicating whether the peer member crashed.
|
||||
* @return this {@link MemberDepartedEvent}.
|
||||
* @see #isCrashed()
|
||||
*/
|
||||
public MemberDepartedEvent crashed(boolean crashed) {
|
||||
|
||||
this.crashed = crashed;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public final Type getType() {
|
||||
return Type.MEMBER_DEPARTED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.distributed.event.support;
|
||||
|
||||
import org.apache.geode.distributed.DistributedMember;
|
||||
import org.apache.geode.distributed.DistributedSystem;
|
||||
import org.apache.geode.distributed.internal.DistributionManager;
|
||||
|
||||
import org.springframework.geode.distributed.event.MembershipEvent;
|
||||
|
||||
/**
|
||||
* {@link MembershipEvent} fired when a {@link DistributedMember} joins the {@link DistributedSystem}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see org.apache.geode.distributed.DistributedSystem
|
||||
* @see org.springframework.geode.distributed.event.MembershipEvent
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class MemberJoinedEvent extends MembershipEvent<MemberJoinedEvent> {
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link MemberJoinedEvent} initialized with the given {@link DistributionManager}.
|
||||
*
|
||||
* @param distributionManager {@link DistributionManager} used as the {@link #getSource() source} of this event;
|
||||
* must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if {@link DistributionManager} is {@literal null}.
|
||||
* @see org.apache.geode.distributed.internal.DistributionManager
|
||||
*/
|
||||
public MemberJoinedEvent(DistributionManager distributionManager) {
|
||||
super(distributionManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.MEMBER_JOINED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.distributed.event.support;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.distributed.DistributedMember;
|
||||
import org.apache.geode.distributed.DistributedSystem;
|
||||
import org.apache.geode.distributed.internal.DistributionManager;
|
||||
|
||||
import org.springframework.geode.distributed.event.MembershipEvent;
|
||||
|
||||
/**
|
||||
* {@link MembershipEvent} fired when a {@link DistributedMember} of the {@link DistributedSystem} is suspected
|
||||
* of being unresponsive to other {@link DistributedMember peer members} in the cluster.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see org.apache.geode.distributed.DistributedSystem
|
||||
* @see org.springframework.geode.distributed.event.MembershipEvent
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class MemberSuspectEvent extends MembershipEvent<MemberSuspectEvent> {
|
||||
|
||||
private DistributedMember suspectMember;
|
||||
|
||||
private String reason;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link MemberSuspectEvent} initialized with the given {@link DistributionManager}.
|
||||
*
|
||||
* @param distributionManager {@link DistributionManager} used as the {@link #getSource() source} of this event;
|
||||
* must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if {@link DistributionManager} is {@literal null}.
|
||||
* @see org.apache.geode.distributed.internal.DistributionManager
|
||||
*/
|
||||
public MemberSuspectEvent(DistributionManager distributionManager) {
|
||||
super(distributionManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} {@link String reason} describing the suspicion of the peer member.
|
||||
*
|
||||
* @return an {@link Optional} {@link String reason} describing the suspicion of the peer member.
|
||||
* @see java.util.Optional
|
||||
*/
|
||||
public Optional<String> getReason() {
|
||||
return Optional.ofNullable(this.reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} {@link DistributedMember} identified as the suspect in the {@link MembershipEvent}.
|
||||
*
|
||||
* @return an {@link Optional} {@link DistributedMember} identified as the suspect in the {@link MembershipEvent}.
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see java.util.Optional
|
||||
*/
|
||||
public Optional<DistributedMember> getSuspectMember() {
|
||||
return Optional.ofNullable(this.suspectMember);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder method used to configure the {@link String reason} describing the suspicion of
|
||||
* the {@link DistributedMember suspect member}.
|
||||
*
|
||||
* @param reason {@link String} describing the suspicion of the {@link DistributedMember peer member};
|
||||
* may be {@literal null}.
|
||||
* @return this {@link MemberSuspectEvent}.
|
||||
* @see #getReason()
|
||||
*/
|
||||
public MemberSuspectEvent withReason(String reason) {
|
||||
|
||||
this.reason = reason;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder method used to configure the {@link DistributedMember peer member} that is the subject of the suspicion
|
||||
* {@link MembershipEvent}.
|
||||
*
|
||||
* @param suspectMember {@link DistributedMember peer member} that is being suspected; may be {@literal null}.
|
||||
* @return this {@link MemberSuspectEvent}.
|
||||
* @see #getSuspectMember()
|
||||
*/
|
||||
public MemberSuspectEvent withSuspect(DistributedMember suspectMember) {
|
||||
|
||||
this.suspectMember = suspectMember;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public final Type getType() {
|
||||
return Type.MEMBER_SUSPECT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.distributed.event.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.geode.distributed.DistributedMember;
|
||||
import org.apache.geode.distributed.DistributedSystem;
|
||||
import org.apache.geode.distributed.internal.DistributionManager;
|
||||
|
||||
import org.springframework.geode.distributed.event.MembershipEvent;
|
||||
|
||||
/**
|
||||
* {@link QuorumLostEvent} is fired for the losing side of the {@link DistributedSystem} when
|
||||
* a network partition occurs.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see org.apache.geode.distributed.DistributedSystem
|
||||
* @see org.springframework.geode.distributed.event.MembershipEvent
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class QuorumLostEvent extends MembershipEvent<QuorumLostEvent> {
|
||||
|
||||
private Iterable<? extends DistributedMember> remainingMembers = Collections.emptyList();
|
||||
|
||||
private Iterable<? extends DistributedMember> failedMembers = Collections.emptySet();
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link QuorumLostEvent} initialized with the given {@link DistributionManager}.
|
||||
*
|
||||
* @param distributionManager {@link DistributionManager} used as the {@link #getSource() source} of this event;
|
||||
* must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if {@link DistributionManager} is {@literal null}.
|
||||
* @see org.apache.geode.distributed.internal.DistributionManager
|
||||
*/
|
||||
public QuorumLostEvent(DistributionManager distributionManager) {
|
||||
super(distributionManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configured {@link Iterable} of failed {@link DistributedMember peer members}
|
||||
* in the {@link DistributedSystem} that are on the losing side of a network partition.
|
||||
*
|
||||
* @return an {@link Iterable} of failed {@link DistributedMember peer members}; never {@literal null}.
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see #getRemainingMembers()
|
||||
* @see java.lang.Iterable
|
||||
*/
|
||||
public Iterable<? extends DistributedMember> getFailedMembers() {
|
||||
return this.failedMembers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configured {@link Iterable} of remaining {@link DistributedMember peer members}
|
||||
* in the {@link DistributedSystem} that are on the winning side of a network partition.
|
||||
*
|
||||
* @return an {@link Iterable} of remaining {@link DistributedMember peer members}; never {@literal null}.
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see #getFailedMembers()
|
||||
* @see java.lang.Iterable
|
||||
*/
|
||||
public Iterable<? extends DistributedMember> getRemainingMembers() {
|
||||
return this.remainingMembers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe builder method used to configure an array of failing {@link DistributedMember peer members}
|
||||
* in the {@link DistributedSystem} on the losing side of a network partition.
|
||||
*
|
||||
* @param failedMembers array of failed {@link DistributedMember peer members}; may be {@literal null}.
|
||||
* @return this {@link QuorumLostEvent}.
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see #withFailedMembers(Iterable)
|
||||
* @see #getFailedMembers()
|
||||
*/
|
||||
public QuorumLostEvent withFailedMembers(DistributedMember... failedMembers) {
|
||||
|
||||
return withFailedMembers(failedMembers != null
|
||||
? Arrays.asList(failedMembers)
|
||||
: Collections.emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe builder method used to configure an {@link Iterable} of failing {@link DistributedMember peer members}
|
||||
* in the {@link DistributedSystem} on the losing side of a network partition.
|
||||
*
|
||||
* @param failedMembers {@link Iterable} of failed {@link DistributedMember peer members}; may be {@literal null}.
|
||||
* @return this {@link QuorumLostEvent}.
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see #getFailedMembers()
|
||||
* @see java.lang.Iterable
|
||||
*/
|
||||
public QuorumLostEvent withFailedMembers(Iterable<? extends DistributedMember> failedMembers) {
|
||||
|
||||
this.failedMembers = failedMembers != null
|
||||
? failedMembers
|
||||
: Collections.emptySet();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe builder method used to configure an array of remaining {@link DistributedMember peer members}
|
||||
* in the {@link DistributedSystem} on the winning side of a network partition.
|
||||
*
|
||||
* @param remainingMembers array of remaining {@link DistributedMember peer members}; may be {@literal null}.
|
||||
* @return this {@link QuorumLostEvent}.
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see #withRemainingMembers(Iterable)
|
||||
* @see #getRemainingMembers()
|
||||
*/
|
||||
public QuorumLostEvent withRemainingMembers(DistributedMember... remainingMembers) {
|
||||
|
||||
return withRemainingMembers(remainingMembers != null
|
||||
? Arrays.asList(remainingMembers)
|
||||
: Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe builder method used to configure an {@link Iterable} of remaining {@link DistributedMember peer members}
|
||||
* in the {@link DistributedSystem} on the winning side of a network partition.
|
||||
*
|
||||
* @param remainingMembers {@link Iterable} of remaining {@link DistributedMember peer members};
|
||||
* may be {@literal null}.
|
||||
* @return this {@link QuorumLostEvent}.
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see #getRemainingMembers()
|
||||
* @see java.lang.Iterable
|
||||
*/
|
||||
public QuorumLostEvent withRemainingMembers(Iterable<? extends DistributedMember> remainingMembers) {
|
||||
|
||||
this.remainingMembers = remainingMembers != null
|
||||
? remainingMembers
|
||||
: Collections.emptyList();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public final Type getType() {
|
||||
return Type.QUORUM_LOST;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.pdx;
|
||||
|
||||
import org.apache.geode.pdx.PdxInstance;
|
||||
|
||||
/**
|
||||
* A {@link RuntimeException} thrown to indicate that a PDX field of a {@link PdxInstance} is not writable.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.lang.RuntimeException
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class PdxFieldNotWritableException extends RuntimeException {
|
||||
|
||||
public PdxFieldNotWritableException() { }
|
||||
|
||||
public PdxFieldNotWritableException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public PdxFieldNotWritableException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public PdxFieldNotWritableException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.pdx;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.RegionService;
|
||||
import org.apache.geode.pdx.PdxInstance;
|
||||
import org.apache.geode.pdx.PdxInstanceFactory;
|
||||
|
||||
import org.springframework.geode.cache.SimpleCacheResolver;
|
||||
|
||||
/**
|
||||
* The {@link PdxInstanceBuilder} class is a <a href="https://en.wikipedia.org/wiki/Builder_pattern">Builder</a>
|
||||
* used to construct and initialize a {@link PdxInstance} from different sources.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.RegionService
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
* @see org.apache.geode.pdx.PdxInstanceFactory
|
||||
* @see <a href="https://en.wikipedia.org/wiki/Builder_pattern">Builder Software Design Pattern</a>
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class PdxInstanceBuilder {
|
||||
|
||||
/**
|
||||
* Factory method used to construct a new instance of the {@link PdxInstanceBuilder} class.
|
||||
*
|
||||
* This factory method tries to resolve the {@link GemFireCache} instance for the caller
|
||||
* by using {@link SimpleCacheResolver}.
|
||||
*
|
||||
* Alternatively, callers may provider their own {@link GemFireCache} instance by calling
|
||||
* {@link #create(RegionService)}.
|
||||
*
|
||||
* @return a new instance of the {@link PdxInstanceBuilder}.
|
||||
* @throws IllegalArgumentException if a {@link GemFireCache} instance is not present.
|
||||
* @see #create(RegionService)
|
||||
*/
|
||||
public static PdxInstanceBuilder create() {
|
||||
return create(SimpleCacheResolver.getInstance().require());
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method use to construct a new instance of the {@link PdxInstanceBuilder} class initialized with
|
||||
* the given, required {@link RegionService} used by the Builder to performs its functions.
|
||||
*
|
||||
* @param regionService {@link RegionService} instance used by the {@link PdxInstanceBuilder} to perform
|
||||
* its functions;
|
||||
* must not be {@literal null}.
|
||||
* @return an new instance of the {@link PdxInstanceBuilder}.
|
||||
* @throws IllegalArgumentException if {@link GemFireCache} is {@literal null}.
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see #PdxInstanceBuilder(RegionService)
|
||||
*/
|
||||
public static PdxInstanceBuilder create(RegionService regionService) {
|
||||
return new PdxInstanceBuilder(regionService);
|
||||
}
|
||||
|
||||
private static void assertNotNull(Object target, String message, Object... arguments) {
|
||||
|
||||
if (target == null) {
|
||||
throw new IllegalArgumentException(String.format(message, arguments));
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> List<T> nullSafeList(List<T> list) {
|
||||
return list != null ? list : Collections.emptyList();
|
||||
}
|
||||
|
||||
private final RegionService regionService;
|
||||
|
||||
private PdxInstanceFactory pdxFactory;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link PdxInstanceBuilder} initialized with the required {@link RegionService}.
|
||||
*
|
||||
* @param regionService {@link RegionService} instance used to perform the functions of the PDX Builder.
|
||||
* @throws IllegalArgumentException if {@link RegionService} is {@literal null}.
|
||||
* @see org.apache.geode.cache.RegionService
|
||||
*/
|
||||
protected PdxInstanceBuilder(RegionService regionService) {
|
||||
|
||||
assertNotNull(regionService, "RegionService must not be null");
|
||||
|
||||
this.regionService = regionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the configured {@link RegionService} used to perform the operations of this PDX Builder.
|
||||
*
|
||||
* @return a reference to the configured {@link RegionService}; never {@literal null}.
|
||||
*/
|
||||
protected RegionService getRegionService() {
|
||||
return this.regionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the contents of the existing {@link PdxInstance} to a new {@link PdxInstance} built with this Builder.
|
||||
*
|
||||
* @param pdxInstance {@link PdxInstance} to copy.
|
||||
* @return an instance of the {@link PdxInstanceFactory} used to {@link PdxInstanceFactory#create() create}
|
||||
* the {@link PdxInstance}.
|
||||
* @throws IllegalArgumentException if {@link PdxInstance} is {@literal null}.
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
* @see org.apache.geode.pdx.PdxInstanceFactory
|
||||
*/
|
||||
public PdxInstanceFactory copy(PdxInstance pdxInstance) {
|
||||
|
||||
assertNotNull(pdxInstance, "PdxInstance must not be null");
|
||||
|
||||
PdxInstanceFactory factory = getRegionService().createPdxInstanceFactory(pdxInstance.getClassName());
|
||||
|
||||
nullSafeList(pdxInstance.getFieldNames()).forEach(fieldName -> {
|
||||
|
||||
factory.writeObject(fieldName, pdxInstance.getField(fieldName));
|
||||
|
||||
if (pdxInstance.isIdentityField(fieldName)) {
|
||||
factory.markIdentityField(fieldName);
|
||||
}
|
||||
});
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link PdxInstance} from the given, required source {@link Object}.
|
||||
*
|
||||
* @param source {@link Object} being serialized to PDX; must not be {@literal null}.
|
||||
* @return a {@link Factory} used to create the {@link PdxInstance} from the given,
|
||||
* required source {@link Object}, which was serialized to PDX.
|
||||
* @throws IllegalArgumentException if {@link Object source} is {@literal null}.
|
||||
* @see Factory
|
||||
*/
|
||||
public Factory from(Object source) {
|
||||
|
||||
assertNotNull(source, "Source object to serialize to PDX must not be null");
|
||||
|
||||
RegionService regionService = getRegionService();
|
||||
|
||||
Optional.of(regionService)
|
||||
.filter(GemFireCache.class::isInstance)
|
||||
.map(GemFireCache.class::cast)
|
||||
.map(GemFireCache::getPdxReadSerialized)
|
||||
.filter(Boolean.TRUE::equals)
|
||||
.orElseThrow(() -> new IllegalStateException("PDX read-serialized must be set to true"));
|
||||
|
||||
PdxInstanceFactory factory = regionService.createPdxInstanceFactory(source.getClass().getName());
|
||||
|
||||
factory.writeObject("source", source);
|
||||
|
||||
AtomicReference<Object> resolvedSource = new AtomicReference<>(null);
|
||||
|
||||
return () -> Optional.of(factory)
|
||||
.map(PdxInstanceFactory::create)
|
||||
.map(pdxInstance -> resolvedSource.updateAndGet(it -> pdxInstance.getField("source")))
|
||||
.filter(PdxInstance.class::isInstance)
|
||||
.map(PdxInstance.class::cast)
|
||||
.orElseThrow(() -> {
|
||||
|
||||
String message = String.format("Expected an instance of PDX but was an instance of type [%s];"
|
||||
+ " Was PDX read-serialized set to true", nullSafeClassName(resolvedSource.get()));
|
||||
|
||||
return new IllegalArgumentException(message);
|
||||
});
|
||||
}
|
||||
|
||||
private String nullSafeClassName(Object target) {
|
||||
return target != null ? target.getClass().getName() : null;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Factory {
|
||||
|
||||
/**
|
||||
* Creates a {@link PdxInstance}.
|
||||
*
|
||||
* @return the created {@link PdxInstance}.
|
||||
* @throws IllegalArgumentException Depending on the implementation, an {@link IllegalArgumentException}
|
||||
* may be thrown if the {@link Object created object} is not of type {@link PdxInstance}.
|
||||
* @throws ClassCastException Depending on the implementation, a {@link ClassCastException} may be thrown
|
||||
* if the {@link Object created object} is not of type {@link PdxInstance}.
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
*/
|
||||
PdxInstance create();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,500 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.pdx;
|
||||
|
||||
import static org.springframework.geode.util.GeodeAssertions.assertThat;
|
||||
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
|
||||
import org.apache.geode.internal.Sendable;
|
||||
import org.apache.geode.pdx.JSONFormatter;
|
||||
import org.apache.geode.pdx.PdxInstance;
|
||||
import org.apache.geode.pdx.WritablePdxInstance;
|
||||
|
||||
/**
|
||||
* The {@link PdxInstanceWrapper} class is an implementation of the {@link PdxInstance} interface
|
||||
* wrapping an existing {@link PdxInstance} object and decorating the functionality.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.function.Function
|
||||
* @see com.fasterxml.jackson.databind.ObjectMapper
|
||||
* @see org.apache.geode.pdx.JSONFormatter
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
* @see org.apache.geode.pdx.WritablePdxInstance
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class PdxInstanceWrapper implements PdxInstance, Sendable {
|
||||
|
||||
public static final String AT_IDENTIFIER_FIELD_NAME = "@identifier";
|
||||
public static final String AT_TYPE_FIELD_NAME = "@type";
|
||||
public static final String CLASS_NAME_PROPERTY = "className";
|
||||
public static final String ID_FIELD_NAME = "id";
|
||||
protected static final String NO_FIELD_NAME = "";
|
||||
|
||||
protected static final String ARRAY_BEGIN = "[";
|
||||
protected static final String ARRAY_END = "]";
|
||||
protected static final String COMMA = ",";
|
||||
protected static final String EMPTY_STRING = "";
|
||||
protected static final String FIELD_TYPE_VALUE = "\"%1$s\"(%2$s): \"%3$s\"";
|
||||
protected static final String INDENT_STRING = "\t";
|
||||
protected static final String NEW_LINE = "\n";
|
||||
protected static final String COMMA_NEW_LINE = "," + NEW_LINE;
|
||||
protected static final String COMMA_SPACE = COMMA + " ";
|
||||
protected static final String OBJECT_BEGIN = "{";
|
||||
protected static final String OBJECT_END = "}";
|
||||
|
||||
/**
|
||||
* Smart, {@literal null-safe} factory method used to evaluate the given {@link Object} and wrap the {@link Object}
|
||||
* in a new instance of {@link PdxInstanceWrapper} if the {@link Object} is an instance of {@link PdxInstance}
|
||||
* or return the given {@link Object} as is.
|
||||
*
|
||||
* @param target {@link Object} to evaluate
|
||||
* @return the {@link Object} wrapped in a new instance of {@link PdxInstanceWrapper} if {@link Object}
|
||||
* is an instance of {@link PdxInstance}, otherwise returns the given {@link Object}.
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
* @see java.lang.Object
|
||||
* @see #from(PdxInstance)
|
||||
*/
|
||||
public static Object from(Object target) {
|
||||
|
||||
return target instanceof PdxInstance
|
||||
? from((PdxInstance) target)
|
||||
: target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method used to construct a new instance of {@link PdxInstanceWrapper} initialized with the given,
|
||||
* required {@link PdxInstance} used to back the wrapper.
|
||||
*
|
||||
* @param pdxInstance {@link PdxInstance} object used to back this wrapper; must not be {@literal null}.
|
||||
* @return a new instance of {@link PdxInstanceWrapper} initialized with the given {@link PdxInstance}.
|
||||
* @throws IllegalArgumentException if {@link PdxInstance} is {@literal null}.
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
* @see #PdxInstanceWrapper(PdxInstance)
|
||||
*/
|
||||
public static PdxInstanceWrapper from(PdxInstance pdxInstance) {
|
||||
|
||||
return pdxInstance instanceof PdxInstanceWrapper
|
||||
? (PdxInstanceWrapper) pdxInstance
|
||||
: new PdxInstanceWrapper(pdxInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe factory method used to unwrap the given {@link PdxInstance}.
|
||||
*
|
||||
* If the given {@link PdxInstance} is an instance of {@link PdxInstanceWrapper} then this factory method will
|
||||
* unwrap the {@link PdxInstanceWrapper} returning the underlying, {@link PdxInstanceWrapper#getDelegate() delegate}
|
||||
* {@link PdxInstance}. Otherwise, the given {@link PdxInstance} is returned.
|
||||
*
|
||||
* @param pdxInstance {@link PdxInstance} to unwrap; may be {@literal null}.
|
||||
* @return the unwrapped {@link PdxInstance}.
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
* @see #getDelegate()
|
||||
*/
|
||||
public static PdxInstance unwrap(PdxInstance pdxInstance) {
|
||||
|
||||
return pdxInstance instanceof PdxInstanceWrapper
|
||||
? ((PdxInstanceWrapper) pdxInstance).getDelegate()
|
||||
: pdxInstance;
|
||||
}
|
||||
|
||||
private final PdxInstance delegate;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link PdxInstanceWrapper} initialized with the given, required {@link PdxInstance}
|
||||
* object used to back this wrapper.
|
||||
*
|
||||
* @param pdxInstance {@link PdxInstance} object used to back this wrapper; must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if {@link PdxInstance} is {@literal null}.
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
*/
|
||||
public PdxInstanceWrapper(PdxInstance pdxInstance) {
|
||||
|
||||
assertThat(pdxInstance).isNotNull();
|
||||
|
||||
this.delegate = pdxInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the configured, underlying {@link PdxInstance} backing this wrapper.
|
||||
*
|
||||
* @return a reference to the configured, underlying {@link PdxInstance} backing this wrapper;
|
||||
* never {@literal null}.
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
*/
|
||||
public PdxInstance getDelegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} reference to a configured Jackson {@link ObjectMapper} used to
|
||||
* deserialize the {@link String JSON} generated from {@link PdxInstance PDX} back into an {@link Object}.
|
||||
*
|
||||
* This method is meant ot be overridden by {@link Class subclasses}.
|
||||
*
|
||||
* @return an {@link Optional} {@link ObjectMapper}.
|
||||
* @see com.fasterxml.jackson.databind.ObjectMapper
|
||||
* @see java.util.Optional
|
||||
*/
|
||||
protected Optional<ObjectMapper> getObjectMapper() {
|
||||
|
||||
ObjectMapper objectMapper = newJsonMapperBuilder()
|
||||
.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false)
|
||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
|
||||
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS, true)
|
||||
.build()
|
||||
.findAndRegisterModules();
|
||||
|
||||
return Optional.of(objectMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of Jackson's {@link JsonMapper}.
|
||||
*
|
||||
* @return a new instance of Jackson's {@link JsonMapper}; never {@literal null}.
|
||||
* @see com.fasterxml.jackson.databind.json.JsonMapper
|
||||
*/
|
||||
JsonMapper.Builder newJsonMapperBuilder() {
|
||||
return JsonMapper.builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return getDelegate().getClassName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public boolean isDeserializable() {
|
||||
return getDelegate().isDeserializable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public boolean isEnum() {
|
||||
return getDelegate().isEnum();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public Object getField(String fieldName) {
|
||||
return getDelegate().getField(fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public List<String> getFieldNames() {
|
||||
return getDelegate().getFieldNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the {@link Object identifier} for, or {@link PdxInstance#isIdentityField(String) identity} of,
|
||||
* this {@link PdxInstance}.
|
||||
*
|
||||
* @return the {@link Object identifier} for this {@link PdxInstance}; never {@literal null}.
|
||||
* @throws IllegalStateException if the {@link PdxInstance} does not have an id.
|
||||
* @see #isIdentityField(String)
|
||||
* @see #getField(String)
|
||||
* @see #getFieldNames()
|
||||
* @see #getId()
|
||||
*/
|
||||
public Object getIdentifier() {
|
||||
|
||||
Optional<String> identityFieldName = nullSafeList(getFieldNames()).stream()
|
||||
.filter(this::hasText)
|
||||
.filter(this::isIdentityField)
|
||||
.findFirst();
|
||||
|
||||
return identityFieldName
|
||||
.map(this::getField)
|
||||
.orElseGet(this::getId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a PDX {@link String field name} called {@literal id} on this {@link PdxInstance}
|
||||
* and returns its {@link Object value} as the {@link Object identifier} for,
|
||||
* or {@link PdxInstance#isIdentityField(String) identity} of, this {@link PdxInstance}.
|
||||
*
|
||||
* @return the {@link Object value} of the {@literal id} {@link String field} on this {@link PdxInstance}.
|
||||
* @throws IllegalStateException if this {@link PdxInstance} does not have an id.
|
||||
* @see #getAtIdentifier()
|
||||
* @see #getField(String)
|
||||
* @see #hasField(String)
|
||||
*/
|
||||
protected Object getId() {
|
||||
|
||||
return hasField(ID_FIELD_NAME)
|
||||
? getField(ID_FIELD_NAME)
|
||||
: getAtIdentifier();
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a PDX {@link String field} declared by the {@literal @identifier} metadata {@link String field}
|
||||
* on this {@link PdxInstance} and returns the {@link Object value} of this {@link String field}
|
||||
* as the {@link Object identifier} for, or {@link PdxInstance#isIdentityField(String) identity} of,
|
||||
* this {@link PdxInstance}.
|
||||
*
|
||||
* @return the {@link Object value} of the {@link String field} declared in the {@literal @identifier} metadata
|
||||
* {@link String field} on this {@link PdxInstance}.
|
||||
* @throws IllegalStateException if the {@link PdxInstance} does not have an id.
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
*/
|
||||
protected Object getAtIdentifier() {
|
||||
|
||||
return Optional.of(AT_IDENTIFIER_FIELD_NAME)
|
||||
.filter(this::hasField)
|
||||
.map(this::getField)
|
||||
.map(String::valueOf)
|
||||
.filter(this::hasField)
|
||||
.map(this::getField)
|
||||
.orElseThrow(() -> new IllegalStateException(String.format("PdxInstance for type [%1$s] has no %2$s",
|
||||
getClassName(), resolveMessageForIdentifierError(this))));
|
||||
}
|
||||
|
||||
private String resolveMessageForIdentifierError(PdxInstance pdxInstance) {
|
||||
|
||||
String message = "declared identifier";
|
||||
|
||||
if (pdxInstance.hasField(ID_FIELD_NAME)) {
|
||||
message = "id";
|
||||
}
|
||||
else if (pdxInstance.hasField(AT_IDENTIFIER_FIELD_NAME)) {
|
||||
|
||||
Object atIdentifierFieldValue = pdxInstance.getField(AT_IDENTIFIER_FIELD_NAME);
|
||||
|
||||
String resolvedIdentifierFieldName = Objects.nonNull(atIdentifierFieldValue)
|
||||
? atIdentifierFieldValue.toString().trim()
|
||||
: NO_FIELD_NAME;
|
||||
|
||||
boolean identifierFieldNameWasDeclaredAndIsValid = pdxInstance.hasField(resolvedIdentifierFieldName);
|
||||
|
||||
Object identifier = identifierFieldNameWasDeclaredAndIsValid
|
||||
? pdxInstance.getField(resolvedIdentifierFieldName)
|
||||
: null;
|
||||
|
||||
String ifMessage = "value [%s] for field [%s] declared in [%s]";
|
||||
String elseMessage = "field [%s] declared in [%s]";
|
||||
|
||||
message = identifierFieldNameWasDeclaredAndIsValid
|
||||
? String.format(ifMessage, identifier, resolvedIdentifierFieldName, AT_IDENTIFIER_FIELD_NAME)
|
||||
: String.format(elseMessage, resolvedIdentifierFieldName, AT_IDENTIFIER_FIELD_NAME);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public boolean isIdentityField(String fieldName) {
|
||||
return getDelegate().isIdentityField(fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Materializes an {@link Object} from the PDX bytes described by this {@link PdxInstance}.
|
||||
*
|
||||
* If these PDX bytes describe an {@link Object} parsed from JSON, then the JSON is reconstructed from
|
||||
* this {@link PdxInstance} and mapped to an instance of the {@link Class type} identified by
|
||||
* the {@literal @type} metadata PDX {@link String field} using Jackson's {@link ObjectMapper}.
|
||||
*
|
||||
* @return an {@link Object} constructed from the PDX bytes described by this {@link PdxInstance}.
|
||||
* @see com.fasterxml.jackson.databind.ObjectMapper
|
||||
* @see java.lang.Object
|
||||
* @see #getObjectMapper()
|
||||
*/
|
||||
@Override
|
||||
public Object getObject() {
|
||||
|
||||
return getObjectMapper()
|
||||
.filter(objectMapper -> JSONFormatter.JSON_CLASSNAME.equals(getClassName()))
|
||||
.filter(objectMapper -> hasField(AT_TYPE_FIELD_NAME))
|
||||
.<Object>map(objectMapper -> {
|
||||
try {
|
||||
|
||||
String typeName = String.valueOf(getField(AT_TYPE_FIELD_NAME));
|
||||
|
||||
Class<?> type = Class.forName(typeName);
|
||||
|
||||
String json = jsonFormatterToJson(getDelegate());
|
||||
|
||||
return objectMapper.readValue(json, type);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
// TODO Log Throwable?
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.orElseGet(() -> getDelegate().getObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link JSONFormatter#toJSON(PdxInstance)} to convert the {@link PdxInstance} into {@link String JSON}.
|
||||
*
|
||||
* @param pdxInstance {@link PdxInstance} to convert to {@link String JSON}.
|
||||
* @return {@link String JSON} generated from the given {@link PdxInstance}.
|
||||
* @see org.apache.geode.pdx.JSONFormatter#toJSON(PdxInstance)
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
*/
|
||||
String jsonFormatterToJson(PdxInstance pdxInstance) {
|
||||
return JSONFormatter.toJSON(pdxInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public WritablePdxInstance createWriter() {
|
||||
return getDelegate().createWriter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public boolean hasField(String fieldName) {
|
||||
return getDelegate().hasField(fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void sendTo(DataOutput out) throws IOException {
|
||||
|
||||
PdxInstance delegate = getDelegate();
|
||||
|
||||
if (delegate instanceof Sendable) {
|
||||
((Sendable) delegate).sendTo(out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link String} representation of this {@link PdxInstance}.
|
||||
*
|
||||
* @return a {@link String} representation of this {@link PdxInstance}.
|
||||
* @see java.lang.String
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
//return getDelegate().toString();
|
||||
return toString(this);
|
||||
}
|
||||
|
||||
private String toString(PdxInstance pdx) {
|
||||
return toString(pdx, "");
|
||||
}
|
||||
|
||||
private String toString(PdxInstance pdx, String indent) {
|
||||
|
||||
if (Objects.nonNull(pdx)) {
|
||||
|
||||
StringBuilder buffer = new StringBuilder(OBJECT_BEGIN).append(NEW_LINE);
|
||||
|
||||
String fieldIndent = indent + INDENT_STRING;
|
||||
|
||||
buffer.append(fieldIndent).append(formatFieldValue(CLASS_NAME_PROPERTY, pdx.getClassName()));
|
||||
|
||||
for (String fieldName : nullSafeList(pdx.getFieldNames())) {
|
||||
|
||||
Object fieldValue = pdx.getField(fieldName);
|
||||
|
||||
String valueString = toStringObject(fieldValue, fieldIndent);
|
||||
|
||||
buffer.append(COMMA_NEW_LINE);
|
||||
buffer.append(fieldIndent).append(formatFieldValue(fieldName, valueString));
|
||||
}
|
||||
|
||||
buffer.append(NEW_LINE).append(indent).append(OBJECT_END);
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String toStringArray(Object value, String indent) {
|
||||
|
||||
Object[] array = (Object[]) value;
|
||||
|
||||
StringBuilder buffer = new StringBuilder(ARRAY_BEGIN);
|
||||
|
||||
boolean addComma = false;
|
||||
|
||||
for (Object element : array) {
|
||||
buffer.append(addComma ? COMMA_SPACE : EMPTY_STRING);
|
||||
buffer.append(toStringObject(element, indent));
|
||||
addComma = true;
|
||||
}
|
||||
|
||||
buffer.append(ARRAY_END);
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private String toStringObject(Object value, String indent) {
|
||||
|
||||
return isPdxInstance(value) ? toString((PdxInstance) value, indent)
|
||||
: isArray(value) ? toStringArray(value, indent)
|
||||
: String.valueOf(value);
|
||||
}
|
||||
|
||||
private String formatFieldValue(String fieldName, Object fieldValue) {
|
||||
return String.format(FIELD_TYPE_VALUE, fieldName, nullSafeType(fieldValue), fieldValue);
|
||||
}
|
||||
|
||||
private boolean hasText(String value) {
|
||||
return value != null && !value.trim().isEmpty();
|
||||
}
|
||||
|
||||
private boolean isArray(Object value) {
|
||||
return Objects.nonNull(value) && value.getClass().isArray();
|
||||
}
|
||||
|
||||
private boolean isPdxInstance(Object value) {
|
||||
return value instanceof PdxInstance;
|
||||
}
|
||||
|
||||
private <T> List<T> nullSafeList(List<T> list) {
|
||||
return list != null ? list : Collections.emptyList();
|
||||
}
|
||||
|
||||
private Class<?> nullSafeType(Object value) {
|
||||
return value != null ? value.getClass() : Object.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.security;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.geode.distributed.DistributedMember;
|
||||
import org.apache.geode.security.AuthInitialize;
|
||||
import org.apache.geode.security.AuthenticationFailedException;
|
||||
|
||||
import org.springframework.geode.util.GeodeConstants;
|
||||
|
||||
/**
|
||||
* Simple, test {@link AuthInitialize} implementation.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.security.AuthInitialize
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class TestAuthInitialize implements AuthInitialize {
|
||||
|
||||
private static final String DEFAULT_USERNAME = "test";
|
||||
private static final String DEFAULT_PASSWORD = DEFAULT_USERNAME;
|
||||
|
||||
public static TestAuthInitialize create() {
|
||||
return new TestAuthInitialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getCredentials(Properties securityProperties, DistributedMember server, boolean isPeer)
|
||||
throws AuthenticationFailedException {
|
||||
|
||||
Properties credentials = new Properties();
|
||||
|
||||
credentials.setProperty(GeodeConstants.USERNAME,
|
||||
securityProperties.getProperty(GeodeConstants.USERNAME, DEFAULT_USERNAME));
|
||||
|
||||
credentials.setProperty(GeodeConstants.PASSWORD,
|
||||
securityProperties.getProperty(GeodeConstants.PASSWORD, DEFAULT_PASSWORD));
|
||||
|
||||
return credentials;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() { }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.security;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.security.Principal;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.geode.security.AuthenticationFailedException;
|
||||
|
||||
import org.springframework.geode.util.GeodeConstants;
|
||||
|
||||
/**
|
||||
* Simple, test {@link org.apache.geode.security.SecurityManager}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.security.Principal
|
||||
* @see java.util.Properties
|
||||
* @see org.apache.geode.security.SecurityManager
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class TestSecurityManager implements org.apache.geode.security.SecurityManager {
|
||||
|
||||
@Override
|
||||
public Object authenticate(Properties credentials) throws AuthenticationFailedException {
|
||||
|
||||
String username = credentials.getProperty(GeodeConstants.USERNAME);
|
||||
String password = credentials.getProperty(GeodeConstants.PASSWORD);
|
||||
|
||||
if (!String.valueOf(username).equals(password)) {
|
||||
throw new AuthenticationFailedException(String.format("User [%s] could not be authenticated", username));
|
||||
}
|
||||
|
||||
return User.create(username);
|
||||
}
|
||||
|
||||
public static class User implements Comparable<User>, Principal, Serializable {
|
||||
|
||||
public static User create(String name) {
|
||||
return new User(name);
|
||||
}
|
||||
|
||||
private final String name;
|
||||
|
||||
public User(String name) {
|
||||
|
||||
if (name == null || name.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("Username is required");
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(User user) {
|
||||
return this.getName().compareTo(user.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof User)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
User that = (User) obj;
|
||||
|
||||
return this.getName().equals(that.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int hashValue = 17;
|
||||
|
||||
hashValue = 37 * hashValue + getName().hashCode();
|
||||
|
||||
return hashValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.util;
|
||||
|
||||
import static org.springframework.geode.util.GeodeAssertions.assertThat;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.DataPolicy;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionAttributes;
|
||||
import org.apache.geode.cache.RegionService;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.client.Pool;
|
||||
import org.apache.geode.internal.cache.GemFireCacheImpl;
|
||||
|
||||
/**
|
||||
* Abstract utility class for working with Apache Geode cache instances, such as {@link ClientCache}
|
||||
* and {@literal peer} {@link Cache} instances.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.DataPolicy
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.RegionAttributes
|
||||
* @see org.apache.geode.cache.RegionService
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public abstract class CacheUtils {
|
||||
|
||||
/**
|
||||
* Collects all {@link Object values} from the given {@link Region}.
|
||||
*
|
||||
* This method is capable of pulling {@link Object values} from either {@literal client}
|
||||
* or {@literal peer} {@link Region Regions}.
|
||||
*
|
||||
* @param <T> {@link Class type} of the {@link Region} {@link Object values}.
|
||||
* @param region {@link Region} from which to collect the {@link Object values}.
|
||||
* @return a {@link Collection} of all {@link Object values} from the given {@link Region}.
|
||||
* @throws IllegalArgumentException if {@link Region} is {@literal null}.
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see java.util.Collection
|
||||
*/
|
||||
// TODO Add Predicate-based Filtering
|
||||
public static <T> Collection<T> collectValues(Region<?, T> region) {
|
||||
|
||||
assertThat(region).isNotNull();
|
||||
|
||||
return isClientRegion(region)
|
||||
? clientRegionValues(region)
|
||||
: localRegionValues(region);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects values from the given {@literal client} {@link Region}.
|
||||
*
|
||||
* @param <T> {@link Class type} of the {@link Region Region's} values.
|
||||
* @param region {@link Region} from which to collect values.
|
||||
* @return a {@link Collection} of the {@literal client} {@link Region Region's} values.
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see #clientRegionValuesFromServer(Region)
|
||||
* @see #localRegionValues(Region)
|
||||
* @see #isProxyRegion(Region)
|
||||
*/
|
||||
private static <T> Collection<T> clientRegionValues(Region<?, T> region) {
|
||||
|
||||
return isProxyRegion(region)
|
||||
? clientRegionValuesFromServer(region)
|
||||
: localRegionValues(region);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collections all values from the {@literal client} {@link Region} by pulling the values down from the server.
|
||||
*
|
||||
* @param <T> {@link Class type} of the {@link Region Region's} values.
|
||||
* @param region {@link Region} from which to collect values.
|
||||
* @return a {@link Collection} containing the values from the {@literal client} {@link Region} on the server.
|
||||
* @see org.apache.geode.cache.Region#keySetOnServer()
|
||||
* @see #getAll(Region, Set)
|
||||
*/
|
||||
private static <T> Collection<T> clientRegionValuesFromServer(Region<?, T> region) {
|
||||
|
||||
Set<?> keys = nullSafeSet(region.keySetOnServer());
|
||||
|
||||
return !keys.isEmpty() ? getAll(region, keys) : Collections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all values from the given {@link Region} mapped to the specified {@link Set keys}.
|
||||
*
|
||||
* @param <T> {@link Class type} of the {@link Region Region's} values.
|
||||
* @param region {@link Region} from which to get all values.
|
||||
* @param keys {@link Set} of keys targeting the values to retrieve.
|
||||
* @return a {@link Collection} of the {@link Region Region's} values.
|
||||
* @see org.apache.geode.cache.Region#getAll(Collection)
|
||||
*/
|
||||
private static <T> Collection<T> getAll(Region<?, T> region, Set<?> keys) {
|
||||
return nullSafeMap(region.getAll(keys)).values();
|
||||
// Fallback procedure if region.getAll(keys) is buggered
|
||||
//return keys.stream().map(region::get).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects values from the given {@link Region}, locally.
|
||||
*
|
||||
* @param <T> {@link Class type} of the {@link Region Region's} values.
|
||||
* @param region {@link Region} from which to collect values.
|
||||
* @return a {@link Collection} of the {@link Region Region's} values.
|
||||
* @see org.apache.geode.cache.Region#values()
|
||||
*/
|
||||
private static <T> Collection<T> localRegionValues(Region<?, T> region) {
|
||||
return region.values();
|
||||
}
|
||||
|
||||
private static boolean hasText(String value) {
|
||||
return value != null && !value.trim().isEmpty();
|
||||
}
|
||||
|
||||
private static <K, V> Map<K, V> nullSafeMap(Map<K, V> map) {
|
||||
return map != null ? map :Collections.emptyMap();
|
||||
}
|
||||
|
||||
private static <T> Set<T> nullSafeSet(Set<T> set) {
|
||||
return set != null ? set : Collections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe method to determine whether the given {@link RegionService} is an instance of {@link ClientCache}.
|
||||
*
|
||||
* The problem is, {@link GemFireCacheImpl} implements both the (peer) {@link Cache}
|
||||
* and {@link ClientCache} interfaces. #sigh
|
||||
*
|
||||
* @param regionService {@link RegionService} to evaluate.
|
||||
* @return a boolean value indicating whether the {@link RegionService} an instance of {@link ClientCache}.
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.RegionService
|
||||
*/
|
||||
public static boolean isClientCache(RegionService regionService) {
|
||||
|
||||
boolean result = regionService instanceof ClientCache;
|
||||
|
||||
if (regionService instanceof GemFireCacheImpl) {
|
||||
result &= ((GemFireCacheImpl) regionService).isClient();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe method to determine whether the given {@link Region} is a {@literal client} {@link Region}
|
||||
* in a {@link ClientCache}.
|
||||
*
|
||||
* @param region {@link Region} to evaluate.
|
||||
* @return a boolean value indicating whether the given {@link Region} is a {@literal client} {@link Region}.
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see #isClientCache(RegionService)
|
||||
*/
|
||||
public static boolean isClientRegion(Region<?, ?> region) {
|
||||
|
||||
return region != null
|
||||
&& (isClientCache(region.getRegionService()) || isRegionWithPool(region));
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe method to determine whether the given {@link RegionService} is an instance of
|
||||
* a {@literal peer} {@link Cache}.
|
||||
*
|
||||
* The problem is, {@link GemFireCacheImpl} implements both the (peer) {@link Cache}
|
||||
* and {@link ClientCache} interfaces. #sigh
|
||||
*
|
||||
* @param regionService {@link RegionService} to evaluate.
|
||||
* @return a boolean value indicating whether the {@link RegionService} is an instance of
|
||||
* a {@literal peer} {@link Cache}.
|
||||
* @see org.apache.geode.cache.RegionService
|
||||
* @see org.apache.geode.cache.Cache
|
||||
*/
|
||||
public static boolean isPeerCache(RegionService regionService) {
|
||||
|
||||
boolean result = regionService instanceof Cache;
|
||||
|
||||
if (regionService instanceof GemFireCacheImpl) {
|
||||
result &= !((GemFireCacheImpl) regionService).isClient();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe method to determine whether the given {@link Region} is a {@literal peer} {@link Region}
|
||||
* in a {@literal peer} {@link Cache}.
|
||||
*
|
||||
* @param region {@link Region} to evaluate.
|
||||
* @return a boolean value indicating whether the given {@link Region} is a {@literal peer} {@link Region}.
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see #isPeerCache(RegionService)
|
||||
*/
|
||||
public static boolean isPeerRegion(Region<?, ?> region) {
|
||||
return region != null && !isClientRegion(region);
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe method to determine whether the given {@link Region} is a [client] {@literal PROXY} {@link Region}.
|
||||
*
|
||||
* The {@link Region} is a {@literal PROXY} if the {@link DataPolicy} is {@link DataPolicy#EMPTY}
|
||||
* or the {@link Region} has a configured {@link Pool}.
|
||||
*
|
||||
* @param region {@link Region} to evaluate.
|
||||
* @return a boolean value to determine whether the {@link Region} is a [client] {@literal PROXY} {@link Region}.
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see #isRegionWithPool(Region)
|
||||
*/
|
||||
public static boolean isProxyRegion(Region<?, ?> region) {
|
||||
|
||||
return region != null
|
||||
&& region.getAttributes() != null
|
||||
&& (DataPolicy.EMPTY.equals(region.getAttributes().getDataPolicy())
|
||||
|| isRegionWithPool(region));
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe method to determine whether the given {@link Region} was configured with a {@link Pool}.
|
||||
*
|
||||
* A {@link Region} configured with a {@link Pool} (by {@link String name} specified in the {@link RegionAttributes})
|
||||
* is a strong indicator that the {@link Region} is a {@literal client} {@link Region}.
|
||||
*
|
||||
* @param region {@link Region} to evaluate.
|
||||
* @return a boolean to determine whether the given {@link Region} was configured with a {@link Pool}.
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
* @see org.apache.geode.cache.Region
|
||||
*/
|
||||
public static boolean isRegionWithPool(Region<?, ?> region) {
|
||||
|
||||
return Optional.ofNullable(region)
|
||||
.map(Region::getAttributes)
|
||||
.map(RegionAttributes::getPoolName)
|
||||
.filter(CacheUtils::hasText)
|
||||
.isPresent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.util;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.distributed.internal.InternalDistributedSystem;
|
||||
import org.apache.geode.internal.cache.AbstractRegion;
|
||||
import org.apache.geode.internal.cache.GemFireCacheImpl;
|
||||
|
||||
/**
|
||||
* Abstract utility class containing different assertions for Apache Geode objects, such as a {@link GemFireCache}
|
||||
* or {@link Region}, and so on.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class GeodeAssertions {
|
||||
|
||||
/**
|
||||
* Asserts that given {@link Object} upholds certain contractual obligations.
|
||||
*
|
||||
* @param <T> {@link Class type} of the given {@link Object}.
|
||||
* @param obj {@link Object} being evaluated in the assertion.
|
||||
* @return a new instance of {@link AssertThat} using the given {@link Object}
|
||||
* as the {@link AssertThat#getSubject() subject} of the assertion.
|
||||
* @see java.lang.Object
|
||||
* @see AssertThat
|
||||
*/
|
||||
public static <T> AssertThat<T> assertThat(T obj) {
|
||||
return () -> obj;
|
||||
}
|
||||
|
||||
private static void assertIsInstanceOf(Object target, Class<?> type) {
|
||||
|
||||
if (!type.isInstance(target)) {
|
||||
throw new AssertionError(String.format("[%1$s] is not an instance of [%2$s]",
|
||||
nullSafeTypeName(target), nullSafeTypeName(type)));
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertIsNotInstanceOf(Object target, Class<?> type) {
|
||||
|
||||
if (type.isInstance(target)) {
|
||||
throw new AssertionError(String.format("[%1%s] is an instance of [%2$s]",
|
||||
nullSafeTypeName(target), nullSafeTypeName(type)));
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertIsNotNull(Object target) {
|
||||
|
||||
if (Objects.isNull(target)) {
|
||||
throw new IllegalArgumentException("Argument must not be null");
|
||||
}
|
||||
}
|
||||
|
||||
private static Class<?> nullSafeType(Object obj) {
|
||||
return obj != null ? obj.getClass() : null;
|
||||
}
|
||||
|
||||
private static String nullSafeTypeName(Class<?> type) {
|
||||
return type != null ? type.getName() : null;
|
||||
}
|
||||
|
||||
public static String nullSafeTypeName(Object obj) {
|
||||
return nullSafeTypeName(nullSafeType(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link AssertThat} {@link FunctionalInterface interface} defines a contract for making assertion about
|
||||
* a given {@link Object} used as the {@link #getSubject() subject} of the assert statement.
|
||||
*
|
||||
* @param <T> {@link Class type} of the {@link Object} that is the {@link #getSubject() subject} of the assertion.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface AssertThat<T> {
|
||||
|
||||
/**
|
||||
* Returns the {@link Object} used as the subject of this assertion.
|
||||
*
|
||||
* @return the {@link Object} used as the subject of this assertion.
|
||||
* @see java.lang.Object
|
||||
*/
|
||||
T getSubject();
|
||||
|
||||
/**
|
||||
* Asserts the {@link #getSubject() subject} is not {@literal null}.
|
||||
*/
|
||||
default void isNotNull() {
|
||||
assertIsNotNull(getSubject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the {@link #getSubject()} is an instance of {@link GemFireCacheImpl}.
|
||||
*/
|
||||
default void isInstanceOfGemFireCacheImpl() {
|
||||
assertIsInstanceOf(getSubject(), GemFireCacheImpl.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the {@link #getSubject()} is an instance of {@link InternalDistributedSystem}.
|
||||
*/
|
||||
default void isInstanceOfInternalDistributedSystem() {
|
||||
assertIsInstanceOf(getSubject(), InternalDistributedSystem.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the {@link #getSubject()} is not an instance of {@link AbstractRegion}.
|
||||
*/
|
||||
default void isNotInstanceOfAbstractRegion() {
|
||||
assertIsNotInstanceOf(getSubject(), AbstractRegion.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the {@link #getSubject()} is not an instance of {@link GemFireCacheImpl}.
|
||||
*/
|
||||
default void isNotInstanceOfGemFireCacheImpl() {
|
||||
assertIsNotInstanceOf(getSubject(), GemFireCacheImpl.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the {@link #getSubject()} is not an instance of {@link InternalDistributedSystem}.
|
||||
*/
|
||||
default void isNotInstanceOfInternalDistributedSystem() {
|
||||
assertIsNotInstanceOf(getSubject(), InternalDistributedSystem.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.util;
|
||||
|
||||
import org.apache.geode.distributed.ConfigurationProperties;
|
||||
import org.apache.geode.management.internal.security.ResourceConstants;
|
||||
|
||||
/**
|
||||
* Interface encapsulating common Apache Geode constants used by SBDG.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.distributed.ConfigurationProperties
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public interface GeodeConstants {
|
||||
|
||||
String GEMFIRE_PROPERTY_PREFIX = "gemfire.";
|
||||
|
||||
// Logging Constants (referring to Properties)
|
||||
String LOG_DISK_SPACE_LIMIT = ConfigurationProperties.LOG_DISK_SPACE_LIMIT;
|
||||
String LOG_FILE = ConfigurationProperties.LOG_FILE;
|
||||
String LOG_FILE_SIZE_LIMIT = ConfigurationProperties.LOG_FILE_SIZE_LIMIT;
|
||||
String LOG_LEVEL = ConfigurationProperties.LOG_LEVEL;
|
||||
|
||||
// Security Constants (referring to Properties)
|
||||
String PASSWORD = ResourceConstants.PASSWORD;
|
||||
String USERNAME = ResourceConstants.USER_NAME;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.util.function;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* {@link Iterable} of {@link Method} invocation {@link Object arguments}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.lang.Iterable
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class InvocationArguments implements Iterable<Object> {
|
||||
|
||||
public static InvocationArguments from(Object... arguments) {
|
||||
return new InvocationArguments(arguments);
|
||||
}
|
||||
|
||||
private final Object[] arguments;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link InvocationArguments} initialized with the given array of
|
||||
* {@link Object arguments}.
|
||||
*
|
||||
* @param arguments array of {@link Object arguments} indicating the values passed to the {@link Method} invocation
|
||||
* parameters; may be {@literal null}.
|
||||
*/
|
||||
public InvocationArguments(Object[] arguments) {
|
||||
this.arguments = arguments != null ? arguments : new Object[0];
|
||||
}
|
||||
|
||||
protected Object[] getArguments() {
|
||||
return this.arguments;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T getArgumentAt(int index) {
|
||||
return (T) getArguments()[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Object> iterator() {
|
||||
|
||||
return new Iterator<Object>() {
|
||||
|
||||
int index = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.index < InvocationArguments.this.getArguments().length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object next() {
|
||||
return InvocationArguments.this.getArguments()[this.index++];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.arguments.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Arrays.toString(getArguments());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.util.function;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* {@link Consumer} like interface accepting 3 arguments.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.function.Consumer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface TriConsumer<T, U, V> {
|
||||
|
||||
/**
|
||||
* Performs a given operation on the 3 arguments.
|
||||
*
|
||||
* @param t first {@link Object argument}.
|
||||
* @param u second {@link Object argument}.
|
||||
* @param v third {@link Object argument}.
|
||||
*/
|
||||
void accept(T t, U u, V v);
|
||||
|
||||
/**
|
||||
* Composes this {@link TriConsumer} with the given {@link TriConsumer} after this {@link TriConsumer}.
|
||||
*
|
||||
* @param after {@link TriConsumer} to composed with this {@link TriConsumer}; must not be {@literal null}.
|
||||
* @return a new {@link TriConsumer} with the given {@link TriConsumer} composed after this {@link TriConsumer}.
|
||||
* @throws NullPointerException if {@link TriConsumer} is {@literal null}.
|
||||
*/
|
||||
default TriConsumer<T, U, V> andThen(TriConsumer<T, U, V> after) {
|
||||
|
||||
Objects.requireNonNull(after);
|
||||
|
||||
return (t, u, v) -> {
|
||||
accept(t, u, v);
|
||||
after.accept(t, u, v);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.util.function;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* {@link Consumer} implementation accepting a tuple of {@link InvocationArguments arguments}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.function.Consumer
|
||||
* @see org.springframework.geode.util.function.InvocationArguments
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public interface TupleConsumer extends Consumer<InvocationArguments> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.app;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.client.ClientCacheFactory;
|
||||
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||
|
||||
/**
|
||||
* An example Apache Geode {@link ClientCache} application.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.Properties
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.client.ClientCacheFactory
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ApacheGeodeClientApplication implements Runnable {
|
||||
|
||||
private static final ClientRegionShortcut CLIENT_REGION_SHORTCUT = ClientRegionShortcut.LOCAL;
|
||||
|
||||
private static final String APPLICATION_NAME = ApacheGeodeClientApplication.class.getSimpleName();
|
||||
private static final String GEMFIRE_LOG_LEVEL = "info";
|
||||
|
||||
private static final String[] EMPTY_ARGUMENTS = {};
|
||||
|
||||
public static void main(String[] args) {
|
||||
new ApacheGeodeClientApplication(args).run();
|
||||
}
|
||||
|
||||
private final String[] arguments;
|
||||
|
||||
public ApacheGeodeClientApplication(String[] arguments) {
|
||||
this.arguments = arguments != null ? arguments : EMPTY_ARGUMENTS;
|
||||
}
|
||||
|
||||
protected String[] getArguments() {
|
||||
return this.arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
run(getArguments());
|
||||
}
|
||||
|
||||
public void run(String[] arguments) {
|
||||
|
||||
ClientCache clientCache = registerShutdownHook(newClientCache(gemfireProperties()));
|
||||
|
||||
Region<Object, Object> example = newClientRegion(clientCache, "Example");
|
||||
|
||||
doDataAccessOperationsTest(example);
|
||||
}
|
||||
|
||||
protected Properties gemfireProperties() {
|
||||
|
||||
Properties gemfireProperties = new Properties();
|
||||
|
||||
gemfireProperties.setProperty("name", APPLICATION_NAME);
|
||||
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
|
||||
// See: https://issues.apache.org/jira/browse/GEODE-7891
|
||||
//gemfireProperties.setProperty("geode.disallow-internal-messages-without-credentials", Boolean.TRUE.toString());
|
||||
//gemfireProperties.setProperty("tombstone-gc-threshold", "100");
|
||||
|
||||
return gemfireProperties;
|
||||
}
|
||||
|
||||
protected ClientCache newClientCache(Properties gemfireProperties) {
|
||||
return new ClientCacheFactory(gemfireProperties).create();
|
||||
}
|
||||
|
||||
protected <K, V> Region<K, V> newClientRegion(ClientCache clientCache, String regionName) {
|
||||
return clientCache.<K, V>createClientRegionFactory(CLIENT_REGION_SHORTCUT).create(regionName);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <K, V> Region<K, V> doDataAccessOperationsTest(Region<Object, Object> region) {
|
||||
|
||||
assertThat(region.put(1, "TEST")).isNull();
|
||||
assertThat(region.get(1)).isEqualTo("TEST");
|
||||
|
||||
return (Region<K, V>) region;
|
||||
}
|
||||
|
||||
protected ClientCache registerShutdownHook(ClientCache clientCache) {
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() ->
|
||||
Optional.ofNullable(clientCache).ifPresent(ClientCache::close),
|
||||
"ClientCache Shutdown Hook"));
|
||||
|
||||
return clientCache;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.cache;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import org.apache.geode.cache.EntryEvent;
|
||||
import org.apache.geode.cache.RegionEvent;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link AbstractCommonEventProcessingCacheListener}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.apache.geode.cache.CacheListener
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AbstractCommonEventProcessingCacheListenerUnitTests {
|
||||
|
||||
@Mock
|
||||
private EntryEvent<Object, Object> mockEntryEvent;
|
||||
|
||||
@Mock
|
||||
private RegionEvent<Object, Object> mockRegionEvent;
|
||||
|
||||
@Spy
|
||||
private AbstractCommonEventProcessingCacheListener<Object, Object> cacheListener;
|
||||
|
||||
@Test
|
||||
public void afterCreateCallsProcessEntryEventWithCreate() {
|
||||
|
||||
this.cacheListener.afterCreate(this.mockEntryEvent);
|
||||
|
||||
verify(this.cacheListener, times(1)).afterCreate(eq(this.mockEntryEvent));
|
||||
|
||||
verify(this.cacheListener, times(1)).processEntryEvent(eq(this.mockEntryEvent),
|
||||
eq(AbstractCommonEventProcessingCacheListener.EntryEventType.CREATE));
|
||||
|
||||
verifyNoMoreInteractions(this.cacheListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterDestroyCallsProcessEntryEventWithDestroy() {
|
||||
|
||||
this.cacheListener.afterDestroy(this.mockEntryEvent);
|
||||
|
||||
verify(this.cacheListener, times(1)).afterDestroy(eq(this.mockEntryEvent));
|
||||
|
||||
verify(this.cacheListener, times(1)).processEntryEvent(eq(this.mockEntryEvent),
|
||||
eq(AbstractCommonEventProcessingCacheListener.EntryEventType.DESTROY));
|
||||
|
||||
verifyNoMoreInteractions(this.cacheListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterInvalidateCallsProcessEntryEventWithInvalidate() {
|
||||
|
||||
this.cacheListener.afterInvalidate(this.mockEntryEvent);
|
||||
|
||||
verify(this.cacheListener, times(1)).afterInvalidate(eq(this.mockEntryEvent));
|
||||
|
||||
verify(this.cacheListener, times(1)).processEntryEvent(eq(this.mockEntryEvent),
|
||||
eq(AbstractCommonEventProcessingCacheListener.EntryEventType.INVALIDATE));
|
||||
|
||||
verifyNoMoreInteractions(this.cacheListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterUpdateCallsProcessEntryEventWithUpdate() {
|
||||
|
||||
this.cacheListener.afterUpdate(this.mockEntryEvent);
|
||||
|
||||
verify(this.cacheListener, times(1)).afterUpdate(eq(this.mockEntryEvent));
|
||||
|
||||
verify(this.cacheListener, times(1)).processEntryEvent(eq(this.mockEntryEvent),
|
||||
eq(AbstractCommonEventProcessingCacheListener.EntryEventType.UPDATE));
|
||||
|
||||
verifyNoMoreInteractions(this.cacheListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterRegionClearCallsProcessRegionEventWithClear() {
|
||||
|
||||
this.cacheListener.afterRegionClear(this.mockRegionEvent);
|
||||
|
||||
verify(this.cacheListener, times(1)).afterRegionClear(eq(this.mockRegionEvent));
|
||||
|
||||
verify(this.cacheListener, times(1)).processRegionEvent(eq(this.mockRegionEvent),
|
||||
eq(AbstractCommonEventProcessingCacheListener.RegionEventType.CLEAR));
|
||||
|
||||
verifyNoMoreInteractions(this.cacheListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterRegionCreateCallsProcessRegionEventWithCreate() {
|
||||
|
||||
this.cacheListener.afterRegionCreate(this.mockRegionEvent);
|
||||
|
||||
verify(this.cacheListener, times(1)).afterRegionCreate(eq(this.mockRegionEvent));
|
||||
|
||||
verify(this.cacheListener, times(1)).processRegionEvent(eq(this.mockRegionEvent),
|
||||
eq(AbstractCommonEventProcessingCacheListener.RegionEventType.CREATE));
|
||||
|
||||
verifyNoMoreInteractions(this.cacheListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterRegionDestroyCallsProcessRegionEventWithCreate() {
|
||||
|
||||
this.cacheListener.afterRegionDestroy(this.mockRegionEvent);
|
||||
|
||||
verify(this.cacheListener, times(1)).afterRegionDestroy(eq(this.mockRegionEvent));
|
||||
|
||||
verify(this.cacheListener, times(1)).processRegionEvent(eq(this.mockRegionEvent),
|
||||
eq(AbstractCommonEventProcessingCacheListener.RegionEventType.DESTROY));
|
||||
|
||||
verifyNoMoreInteractions(this.cacheListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterRegionInvalidateCallsProcessRegionEventWithInvalidate() {
|
||||
|
||||
this.cacheListener.afterRegionInvalidate(this.mockRegionEvent);
|
||||
|
||||
verify(this.cacheListener, times(1)).afterRegionInvalidate(eq(this.mockRegionEvent));
|
||||
|
||||
verify(this.cacheListener, times(1)).processRegionEvent(eq(this.mockRegionEvent),
|
||||
eq(AbstractCommonEventProcessingCacheListener.RegionEventType.INVALIDATE));
|
||||
|
||||
verifyNoMoreInteractions(this.cacheListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterRegionLiveCallsProcessRegionEventWithLive() {
|
||||
|
||||
this.cacheListener.afterRegionLive(this.mockRegionEvent);
|
||||
|
||||
verify(this.cacheListener, times(1)).afterRegionLive(eq(this.mockRegionEvent));
|
||||
|
||||
verify(this.cacheListener, times(1)).processRegionEvent(eq(this.mockRegionEvent),
|
||||
eq(AbstractCommonEventProcessingCacheListener.RegionEventType.LIVE));
|
||||
|
||||
verifyNoMoreInteractions(this.cacheListener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.cache;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link SimpleCacheResolver}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.springframework.geode.cache.SimpleCacheResolver
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class SimpleCacheResolverUnitTests {
|
||||
|
||||
@Test
|
||||
public void getInstanceReturnsASingleInstance() {
|
||||
|
||||
SimpleCacheResolver cacheResolver = SimpleCacheResolver.getInstance();
|
||||
|
||||
assertThat(cacheResolver).isNotNull();
|
||||
assertThat(cacheResolver).isSameAs(SimpleCacheResolver.getInstance());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveWhenNoCacheIsPresentReturnsEmptyOptional() {
|
||||
assertThat(SimpleCacheResolver.getInstance().resolve().orElse(null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveClientCacheWhenNoClientCacheIsPresentReturnsEmptyOptional() {
|
||||
assertThat(SimpleCacheResolver.getInstance().resolveClientCache().orElse(null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePeerCacheWhenNoPeerCacheIsPresentReturnsEmptyOptional() {
|
||||
assertThat(SimpleCacheResolver.getInstance().resolvePeerCache().orElse(null)).isNull();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void requireCacheWhenNoCacheIsPresentThrowsIllegalStateException() {
|
||||
|
||||
try {
|
||||
SimpleCacheResolver.getInstance().require();
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("GemFireCache not found");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.cache;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.client.ClientCacheFactory;
|
||||
|
||||
/**
|
||||
* Integration Tests for {@link SimpleCacheResolver} using an Apache Geode {@link ClientCache}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.client.ClientCacheFactory
|
||||
* @see org.springframework.geode.cache.SimpleCacheResolver
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class SimpleClientCacheResolverIntegrationTests {
|
||||
|
||||
private static ClientCache clientCache;
|
||||
|
||||
@BeforeClass
|
||||
public static void createClientCache() {
|
||||
clientCache = new ClientCacheFactory().create();
|
||||
assertThat(clientCache).isNotNull();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void destroyClientCache() {
|
||||
Optional.ofNullable(clientCache).ifPresent(ClientCache::close);
|
||||
clientCache = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveReturnsClientCache() {
|
||||
assertThat(SimpleCacheResolver.getInstance().resolve().orElse(null)).isSameAs(clientCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveClientCacheReturnsClientCache() {
|
||||
assertThat(SimpleCacheResolver.getInstance().resolveClientCache().orElse(null)).isSameAs(clientCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePeerCacheReturnsEmptyOptional() {
|
||||
assertThat(SimpleCacheResolver.getInstance().resolvePeerCache().orElse(null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requireReturnsClientCache() {
|
||||
assertThat(SimpleCacheResolver.getInstance().<ClientCache>require()).isSameAs(clientCache);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.cache;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.CacheFactory;
|
||||
|
||||
/**
|
||||
* Integration Tests for {@link SimpleCacheResolver} using an Apache Geode {@literal peer} {@link Cache}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.CacheFactory
|
||||
* @see org.springframework.geode.cache.SimpleCacheResolver
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class SimplePeerCacheResolverIntegrationTests {
|
||||
|
||||
private static Cache peerCache;
|
||||
|
||||
@BeforeClass
|
||||
public static void createPeerCache() {
|
||||
peerCache = new CacheFactory().create();
|
||||
assertThat(peerCache).isNotNull();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void destroyPeerCache() {
|
||||
Optional.ofNullable(peerCache).ifPresent(Cache::close);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveReturnsPeerCache() {
|
||||
assertThat(SimpleCacheResolver.getInstance().resolve().orElse(null)).isSameAs(peerCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveClientCacheReturnsEmptyOptional() {
|
||||
assertThat(SimpleCacheResolver.getInstance().resolveClientCache().orElse(null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePeerCacheReturnsPeerCache() {
|
||||
assertThat(SimpleCacheResolver.getInstance().resolvePeerCache().orElse(null)).isSameAs(peerCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requireReturnsPeerCache() {
|
||||
assertThat(SimpleCacheResolver.getInstance().<Cache>require()).isSameAs(peerCache);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.distributed.event;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.geode.distributed.DistributedMember;
|
||||
import org.apache.geode.distributed.internal.DistributionManager;
|
||||
import org.apache.geode.distributed.internal.InternalDistributedSystem;
|
||||
import org.apache.geode.internal.cache.InternalCache;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link MembershipEvent}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see org.apache.geode.distributed.DistributedSystem
|
||||
* @see org.apache.geode.distributed.internal.DistributionManager
|
||||
* @see org.springframework.geode.distributed.event.MembershipEvent
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class MembershipEventUnitTests {
|
||||
|
||||
@Test
|
||||
public void assertNotNullWithNonNullValue() {
|
||||
assertThat(MembershipEvent.assertNotNull("test", "message")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void assertNotNullWithNullValue() {
|
||||
|
||||
try {
|
||||
MembershipEvent.assertNotNull(null, "Message with argument [%s]", "test");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Message with argument [test]");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructsNewMembershipEventWithDistributionManager() {
|
||||
|
||||
DistributionManager mockDistributionManager = mock(DistributionManager.class);
|
||||
|
||||
InternalCache mockCache = mock(InternalCache.class);
|
||||
|
||||
InternalDistributedSystem mockDistributedSystem = mock(InternalDistributedSystem.class);
|
||||
|
||||
doReturn(mockCache).when(mockDistributionManager).getCache();
|
||||
doReturn(mockDistributedSystem).when(mockDistributionManager).getSystem();
|
||||
|
||||
MembershipEvent<TestMembershipEvent> event = new TestMembershipEvent(mockDistributionManager);
|
||||
|
||||
assertThat(event).isNotNull();
|
||||
assertThat(event.getCache().orElse(null)).isEqualTo(mockCache);
|
||||
assertThat(event.getDistributedMember().orElse(null)).isNull();
|
||||
assertThat(event.getDistributedSystem().orElse(null)).isEqualTo(mockDistributedSystem);
|
||||
assertThat(event.getDistributionManager()).isEqualTo(mockDistributionManager);
|
||||
assertThat(event.getType()).isEqualTo(MembershipEvent.Type.UNQUALIFIED);
|
||||
|
||||
verify(mockDistributionManager, times(1)).getCache();
|
||||
verify(mockDistributionManager, times(1)).getSystem();
|
||||
verifyNoMoreInteractions(mockDistributionManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withMemberReturnsMember() {
|
||||
|
||||
DistributedMember mockDistributedMember = mock(DistributedMember.class);
|
||||
|
||||
DistributionManager mockDistributionManager = mock(DistributionManager.class);
|
||||
|
||||
MembershipEvent<TestMembershipEvent> event = new TestMembershipEvent(mockDistributionManager);
|
||||
|
||||
assertThat(event).isNotNull();
|
||||
assertThat(event.getDistributedMember().orElse(null)).isNull();
|
||||
assertThat(event.withMember(mockDistributedMember)).isSameAs(event);
|
||||
assertThat(event.getDistributedMember().orElse(null)).isEqualTo(mockDistributedMember);
|
||||
assertThat(event.withMember(null)).isSameAs(event);
|
||||
assertThat(event.getDistributedMember().orElse(null)).isNull();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructWithNullDistributionManagerThrowsIllegalArgumentException() {
|
||||
|
||||
try {
|
||||
new TestMembershipEvent(null);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("DistributionManager must not be null");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
static class TestMembershipEvent extends MembershipEvent<TestMembershipEvent> {
|
||||
|
||||
TestMembershipEvent(DistributionManager distributionManager) {
|
||||
super(distributionManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.distributed.event;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isA;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.distributed.DistributedSystem;
|
||||
import org.apache.geode.distributed.internal.DistributionManager;
|
||||
import org.apache.geode.distributed.internal.InternalDistributedSystem;
|
||||
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
|
||||
|
||||
import org.springframework.geode.distributed.event.support.MemberDepartedEvent;
|
||||
import org.springframework.geode.distributed.event.support.MemberJoinedEvent;
|
||||
import org.springframework.geode.distributed.event.support.MemberSuspectEvent;
|
||||
import org.springframework.geode.distributed.event.support.QuorumLostEvent;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link MembershipListenerAdapter}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see org.apache.geode.distributed.DistributedSystem
|
||||
* @see org.apache.geode.distributed.internal.DistributionManager
|
||||
* @see org.apache.geode.distributed.internal.membership.InternalDistributedMember
|
||||
* @see MembershipListenerAdapter
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class MembershipListenerAdapterUnitTests {
|
||||
|
||||
@Mock
|
||||
private DistributionManager mockDistributionManager;
|
||||
|
||||
@Mock
|
||||
private InternalDistributedMember mockDistributedMember;
|
||||
|
||||
@Mock
|
||||
private InternalDistributedSystem mockDistributedSystem;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> Set<T> asSet(T... elements) {
|
||||
return new HashSet<>(Arrays.asList(elements));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void memberDepartedCallsHandleMemberDeparted() {
|
||||
|
||||
MembershipListenerAdapter<?> listener = spy(new TestMembershipListener());
|
||||
|
||||
doAnswer(invocation -> {
|
||||
|
||||
MemberDepartedEvent event = invocation.getArgument(0);
|
||||
|
||||
assertThat(event).isNotNull();
|
||||
assertThat(event.isCrashed()).isTrue();
|
||||
assertThat(event.getDistributedMember().orElse(null)).isEqualTo(this.mockDistributedMember);
|
||||
assertThat(event.getDistributionManager()).isEqualTo(this.mockDistributionManager);
|
||||
assertThat(event.getType()).isEqualTo(MembershipEvent.Type.MEMBER_DEPARTED);
|
||||
|
||||
return null;
|
||||
|
||||
}).when(listener).handleMemberDeparted(any(MemberDepartedEvent.class));
|
||||
|
||||
listener.memberDeparted(this.mockDistributionManager, this.mockDistributedMember, true);
|
||||
|
||||
verify(listener, times(1)).handleMemberDeparted(isA(MemberDepartedEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void memberJoinedCallsHandleMemberJoined() {
|
||||
|
||||
MembershipListenerAdapter<?> listener = spy(new TestMembershipListener());
|
||||
|
||||
doAnswer(invocation -> {
|
||||
|
||||
MemberJoinedEvent event = invocation.getArgument(0);
|
||||
|
||||
assertThat(event).isNotNull();
|
||||
assertThat(event.getDistributedMember().orElse(null)).isEqualTo(this.mockDistributedMember);
|
||||
assertThat(event.getDistributionManager()).isEqualTo(this.mockDistributionManager);
|
||||
assertThat(event.getType()).isEqualTo(MembershipEvent.Type.MEMBER_JOINED);
|
||||
|
||||
return null;
|
||||
|
||||
}).when(listener).handleMemberJoined(any(MemberJoinedEvent.class));
|
||||
|
||||
listener.memberJoined(this.mockDistributionManager, this.mockDistributedMember);
|
||||
|
||||
verify(listener, times(1)).handleMemberJoined(isA(MemberJoinedEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void memberSuspectCallsHandleMemberSuspect() {
|
||||
|
||||
InternalDistributedMember suspectMember = mock(InternalDistributedMember.class);
|
||||
|
||||
MembershipListenerAdapter<?> listener = spy(new TestMembershipListener());
|
||||
|
||||
doAnswer(invocation -> {
|
||||
|
||||
MemberSuspectEvent event = invocation.getArgument(0);
|
||||
|
||||
assertThat(event).isNotNull();
|
||||
assertThat(event.getDistributedMember().orElse(null)).isEqualTo(this.mockDistributedMember);
|
||||
assertThat(event.getDistributionManager()).isEqualTo(this.mockDistributionManager);
|
||||
assertThat(event.getReason().orElse(null)).isEqualTo("The system sucks!");
|
||||
assertThat(event.getSuspectMember().orElse(null)).isEqualTo(suspectMember);
|
||||
assertThat(event.getType()).isEqualTo(MembershipEvent.Type.MEMBER_SUSPECT);
|
||||
|
||||
return null;
|
||||
|
||||
}).when(listener).handleMemberSuspect(any(MemberSuspectEvent.class));
|
||||
|
||||
listener.memberSuspect(this.mockDistributionManager, this.mockDistributedMember, suspectMember,
|
||||
"The system sucks!");
|
||||
|
||||
verify(listener, times(1)).handleMemberSuspect(isA(MemberSuspectEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quorumLostCallsHandleQuorumLost() {
|
||||
|
||||
InternalDistributedMember mockMemberOne = mock(InternalDistributedMember.class);
|
||||
InternalDistributedMember mockMemberTwo = mock(InternalDistributedMember.class);
|
||||
|
||||
MembershipListenerAdapter<?> listener = spy(new TestMembershipListener());
|
||||
|
||||
doAnswer(invocation -> {
|
||||
|
||||
QuorumLostEvent event = invocation.getArgument(0);
|
||||
|
||||
assertThat(event).isNotNull();
|
||||
assertThat(event.getDistributedMember().orElse(null)).isNull();
|
||||
assertThat(event.getDistributionManager()).isEqualTo(this.mockDistributionManager);
|
||||
assertThat(event.getFailedMembers()).isEqualTo(asSet(mockMemberOne, mockMemberTwo));
|
||||
assertThat(event.getRemainingMembers()).isEqualTo(Collections.singletonList(this.mockDistributedMember));
|
||||
assertThat(event.getType()).isEqualTo(MembershipEvent.Type.QUORUM_LOST);
|
||||
|
||||
return null;
|
||||
|
||||
}).when(listener).handleQuorumLost(any(QuorumLostEvent.class));
|
||||
|
||||
listener.quorumLost(this.mockDistributionManager, asSet(mockMemberOne, mockMemberTwo),
|
||||
Collections.singletonList(this.mockDistributedMember));
|
||||
|
||||
verify(listener, times(1)).handleQuorumLost(isA(QuorumLostEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registersListenerWithPeerCache() {
|
||||
|
||||
Cache mockCache = mock(Cache.class);
|
||||
|
||||
doReturn(this.mockDistributedSystem).when(mockCache).getDistributedSystem();
|
||||
doReturn(this.mockDistributionManager).when(this.mockDistributedSystem).getDistributionManager();
|
||||
|
||||
MembershipListenerAdapter<?> listener = new TestMembershipListener();
|
||||
|
||||
assertThat(listener.register(mockCache)).isSameAs(listener);
|
||||
|
||||
verify(mockCache, times(1)).getDistributedSystem();
|
||||
verify(this.mockDistributedSystem, times(1)).getDistributionManager();
|
||||
verify(this.mockDistributionManager, times(1))
|
||||
.addMembershipListener(eq(listener));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerListenerWithNullCacheIsNullSafe() {
|
||||
|
||||
MembershipListenerAdapter<?> listener = new TestMembershipListener();
|
||||
|
||||
assertThat(listener.register(null)).isSameAs(listener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerListenerWithNullDistributedSystemIsNullSafe() {
|
||||
|
||||
Cache mockCache = mock(Cache.class);
|
||||
|
||||
MembershipListenerAdapter<?> listener = new TestMembershipListener();
|
||||
|
||||
assertThat(listener.register(mockCache)).isSameAs(listener);
|
||||
|
||||
verify(mockCache, times(1)).getDistributedSystem();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerListenerWithNonInternalDistributedSystemIsSafe() {
|
||||
|
||||
Cache mockCache = mock(Cache.class);
|
||||
|
||||
DistributedSystem mockDistributedSystem = mock(DistributedSystem.class);
|
||||
|
||||
doReturn(mockDistributedSystem).when(mockCache).getDistributedSystem();
|
||||
|
||||
MembershipListenerAdapter<?> listener = new TestMembershipListener();
|
||||
|
||||
assertThat(listener.register(mockCache)).isSameAs(listener);
|
||||
|
||||
verify(mockCache, times(1)).getDistributedSystem();
|
||||
verifyNoInteractions(mockDistributedSystem);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerListenerWithNullDistributionManagerIsNullSafe() {
|
||||
|
||||
Cache mockCache = mock(Cache.class);
|
||||
|
||||
doReturn(this.mockDistributedSystem).when(mockCache).getDistributedSystem();
|
||||
|
||||
MembershipListenerAdapter<?> listener = new TestMembershipListener();
|
||||
|
||||
assertThat(listener.register(mockCache)).isSameAs(listener);
|
||||
|
||||
verify(mockCache, times(1)).getDistributedSystem();
|
||||
verify(this.mockDistributedSystem, times(1)).getDistributionManager();
|
||||
}
|
||||
|
||||
static class TestMembershipListener extends MembershipListenerAdapter<TestMembershipListener> { }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.distributed.event.support;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.geode.distributed.internal.DistributionManager;
|
||||
|
||||
import org.springframework.geode.distributed.event.MembershipEvent;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link MemberDepartedEvent}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.geode.distributed.event.MembershipEvent
|
||||
* @see org.springframework.geode.distributed.event.support.MemberDepartedEvent
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class MemberDepartedEventUnitTests {
|
||||
|
||||
@Test
|
||||
public void constructMemberDepartedEvent() {
|
||||
|
||||
DistributionManager mockDistributionManager = mock(DistributionManager.class);
|
||||
|
||||
MemberDepartedEvent event = new MemberDepartedEvent(mockDistributionManager);
|
||||
|
||||
assertThat(event).isNotNull();
|
||||
assertThat(event.getDistributionManager()).isEqualTo(mockDistributionManager);
|
||||
assertThat(event.isCrashed()).isFalse();
|
||||
assertThat(event.getType()).isEqualTo(MembershipEvent.Type.MEMBER_DEPARTED);
|
||||
|
||||
verifyNoInteractions(mockDistributionManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetCrashed() {
|
||||
|
||||
DistributionManager mockDistributionManager = mock(DistributionManager.class);
|
||||
|
||||
MemberDepartedEvent event = new MemberDepartedEvent(mockDistributionManager);
|
||||
|
||||
assertThat(event).isNotNull();
|
||||
assertThat(event.isCrashed()).isFalse();
|
||||
assertThat(event.crashed(true)).isEqualTo(event);
|
||||
assertThat(event.isCrashed()).isTrue();
|
||||
assertThat(event.crashed(false)).isEqualTo(event);
|
||||
assertThat(event.isCrashed()).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.distributed.event.support;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.geode.distributed.internal.DistributionManager;
|
||||
|
||||
import org.springframework.geode.distributed.event.MembershipEvent;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link MemberJoinedEvent}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.geode.distributed.event.MembershipEvent
|
||||
* @see org.springframework.geode.distributed.event.support.MemberJoinedEvent
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class MemberJoinedEventUnitTests {
|
||||
|
||||
@Test
|
||||
public void constructsMemberJoinedEvent() {
|
||||
|
||||
DistributionManager mockDistributionManager = mock(DistributionManager.class);
|
||||
|
||||
MemberJoinedEvent event = new MemberJoinedEvent(mockDistributionManager);
|
||||
|
||||
assertThat(event).isNotNull();
|
||||
assertThat(event.getDistributionManager()).isEqualTo(mockDistributionManager);
|
||||
assertThat(event.getType()).isEqualTo(MembershipEvent.Type.MEMBER_JOINED);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.distributed.event.support;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.geode.distributed.DistributedMember;
|
||||
import org.apache.geode.distributed.internal.DistributionManager;
|
||||
|
||||
import org.springframework.geode.distributed.event.MembershipEvent;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link MemberSuspectEvent}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see org.springframework.geode.distributed.event.MembershipEvent
|
||||
* @see org.springframework.geode.distributed.event.support.MemberSuspectEvent
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class MemberSuspectEventUnitTests {
|
||||
|
||||
@Test
|
||||
public void constructsMemberSuspectEvent() {
|
||||
|
||||
DistributionManager mockDistributionManager = mock(DistributionManager.class);
|
||||
|
||||
MemberSuspectEvent event = new MemberSuspectEvent(mockDistributionManager);
|
||||
|
||||
assertThat(event).isNotNull();
|
||||
assertThat(event.getDistributionManager()).isEqualTo(mockDistributionManager);
|
||||
assertThat(event.getReason().orElse(null)).isNull();
|
||||
assertThat(event.getSuspectMember().orElse(null)).isNull();
|
||||
assertThat(event.getType()).isEqualTo(MembershipEvent.Type.MEMBER_SUSPECT);
|
||||
|
||||
verifyNoInteractions(mockDistributionManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetReason() {
|
||||
|
||||
DistributionManager mockDistributionManager = mock(DistributionManager.class);
|
||||
|
||||
MemberSuspectEvent event = new MemberSuspectEvent(mockDistributionManager);
|
||||
|
||||
assertThat(event).isNotNull();
|
||||
assertThat(event.getReason().orElse(null)).isNull();
|
||||
assertThat(event.withReason("TEST")).isSameAs(event);
|
||||
assertThat(event.getReason().orElse(null)).isEqualTo("TEST");
|
||||
assertThat(event.withReason(null)).isSameAs(event);
|
||||
assertThat(event.getReason().orElse(null)).isNull();
|
||||
assertThat(event.withReason(" ")).isSameAs(event);
|
||||
assertThat(event.getReason().orElse(null)).isEqualTo(" ");
|
||||
assertThat(event.withReason(null)).isSameAs(event);
|
||||
assertThat(event.getReason().orElse(null)).isNull();
|
||||
assertThat(event.withReason("")).isSameAs(event);
|
||||
assertThat(event.getReason().orElse(null)).isEqualTo("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetSuspectMember() {
|
||||
|
||||
DistributedMember mockDistributedMember = mock(DistributedMember.class);
|
||||
|
||||
DistributionManager mockDistributionManager = mock(DistributionManager.class);
|
||||
|
||||
MemberSuspectEvent event = new MemberSuspectEvent(mockDistributionManager);
|
||||
|
||||
assertThat(event).isNotNull();
|
||||
assertThat(event.getSuspectMember().orElse(null)).isNull();
|
||||
assertThat(event.withSuspect(mockDistributedMember)).isSameAs(event);
|
||||
assertThat(event.getSuspectMember().orElse(null)).isEqualTo(mockDistributedMember);
|
||||
assertThat(event.withSuspect(null)).isSameAs(event);
|
||||
assertThat(event.getSuspectMember().orElse(null)).isNull();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.distributed.event.support;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.geode.distributed.DistributedMember;
|
||||
import org.apache.geode.distributed.internal.DistributionManager;
|
||||
|
||||
import org.springframework.geode.distributed.event.MembershipEvent;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link QuorumLostEvent}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see org.springframework.geode.distributed.event.MembershipEvent
|
||||
* @see org.springframework.geode.distributed.event.support.QuorumLostEvent
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class QuorumLostEventUnitTests {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> Iterable<T> normalize(Iterable<? extends T> iterable) {
|
||||
return (Iterable<T>) iterable;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructsQuorumLostEvent() {
|
||||
|
||||
DistributionManager mockDistributionManager = mock(DistributionManager.class);
|
||||
|
||||
QuorumLostEvent event = new QuorumLostEvent(mockDistributionManager);
|
||||
|
||||
assertThat(event).isNotNull();
|
||||
assertThat(event.getDistributionManager()).isEqualTo(mockDistributionManager);
|
||||
assertThat(event.getFailedMembers()).isEmpty();
|
||||
assertThat(event.getRemainingMembers()).isEmpty();
|
||||
assertThat(event.getType()).isEqualTo(MembershipEvent.Type.QUORUM_LOST);
|
||||
|
||||
verifyNoInteractions(mockDistributionManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetFailedMembers() {
|
||||
|
||||
DistributedMember mockMemberOne = mock(DistributedMember.class);
|
||||
DistributedMember mockMemberTwo = mock(DistributedMember.class);
|
||||
|
||||
DistributionManager mockDistributionManager = mock(DistributionManager.class);
|
||||
|
||||
QuorumLostEvent event = new QuorumLostEvent(mockDistributionManager);
|
||||
|
||||
assertThat(event).isNotNull();
|
||||
assertThat(event.getFailedMembers()).isNotNull();
|
||||
assertThat(event.getFailedMembers()).isEmpty();
|
||||
|
||||
assertThat(event.withFailedMembers(mockMemberOne, mockMemberTwo)).isSameAs(event);
|
||||
assertThat(this.<DistributedMember>normalize(event.getFailedMembers()))
|
||||
.containsExactlyInAnyOrder(mockMemberOne, mockMemberTwo);
|
||||
|
||||
assertThat(event.withFailedMembers((DistributedMember[]) null)).isSameAs(event);
|
||||
assertThat(event.getFailedMembers()).isNotNull();
|
||||
assertThat(event.getFailedMembers()).isEmpty();
|
||||
|
||||
assertThat(event.withFailedMembers(mockMemberOne)).isSameAs(event);
|
||||
assertThat(this.<DistributedMember>normalize(event.getFailedMembers())).containsExactly(mockMemberOne);
|
||||
|
||||
assertThat(event.withFailedMembers((Iterable<? extends DistributedMember>) null)).isSameAs(event);
|
||||
assertThat(event.getFailedMembers()).isNotNull();
|
||||
assertThat(event.getFailedMembers()).isEmpty();
|
||||
|
||||
assertThat(event.withFailedMembers(Collections.singleton(mockMemberTwo))).isSameAs(event);
|
||||
assertThat(this.<DistributedMember>normalize(event.getFailedMembers())).containsExactly(mockMemberTwo);
|
||||
|
||||
assertThat(event.withFailedMembers()).isSameAs(event);
|
||||
assertThat(event.getFailedMembers()).isNotNull();
|
||||
assertThat(event.getFailedMembers()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetRemainingMembers() {
|
||||
|
||||
DistributedMember mockMemberOne = mock(DistributedMember.class);
|
||||
DistributedMember mockMemberTwo = mock(DistributedMember.class);
|
||||
|
||||
DistributionManager mockDistributionManager = mock(DistributionManager.class);
|
||||
|
||||
QuorumLostEvent event = new QuorumLostEvent(mockDistributionManager);
|
||||
|
||||
assertThat(event).isNotNull();
|
||||
assertThat(event.getRemainingMembers()).isNotNull();
|
||||
assertThat(event.getRemainingMembers()).isEmpty();
|
||||
|
||||
assertThat(event.withRemainingMembers(mockMemberOne, mockMemberTwo)).isSameAs(event);
|
||||
assertThat(this.<DistributedMember>normalize(event.getRemainingMembers()))
|
||||
.containsExactlyInAnyOrder(mockMemberOne, mockMemberTwo);
|
||||
|
||||
assertThat(event.withRemainingMembers((DistributedMember[]) null)).isSameAs(event);
|
||||
assertThat(event.getRemainingMembers()).isNotNull();
|
||||
assertThat(event.getRemainingMembers()).isEmpty();
|
||||
|
||||
assertThat(event.withRemainingMembers(mockMemberOne)).isSameAs(event);
|
||||
assertThat(this.<DistributedMember>normalize(event.getRemainingMembers()))
|
||||
.containsExactlyInAnyOrder(mockMemberOne);
|
||||
|
||||
assertThat(event.withRemainingMembers((Iterable<? extends DistributedMember>) null)).isSameAs(event);
|
||||
assertThat(event.getRemainingMembers()).isNotNull();
|
||||
assertThat(event.getRemainingMembers()).isEmpty();
|
||||
|
||||
assertThat(event.withRemainingMembers(Collections.singletonList(mockMemberTwo))).isSameAs(event);
|
||||
assertThat(this.<DistributedMember>normalize(event.getRemainingMembers()))
|
||||
.containsExactlyInAnyOrder(mockMemberTwo);
|
||||
|
||||
assertThat(event.withRemainingMembers()).isSameAs(event);
|
||||
assertThat(event.getRemainingMembers()).isNotNull();
|
||||
assertThat(event.getRemainingMembers()).isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.pdx;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.RegionService;
|
||||
import org.apache.geode.pdx.PdxInstance;
|
||||
import org.apache.geode.pdx.PdxInstanceFactory;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link PdxInstanceBuilder}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.RegionService
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
* @see org.apache.geode.pdx.PdxInstanceFactory
|
||||
* @see org.springframework.geode.pdx.PdxInstanceBuilder
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class PdxInstanceBuilderUnitTests {
|
||||
|
||||
@Test
|
||||
public void constructPdxInstanceBuilderInitializedWithRegionService() {
|
||||
|
||||
RegionService mockRegionService = mock(RegionService.class);
|
||||
|
||||
PdxInstanceBuilder builder = new PdxInstanceBuilder(mockRegionService);
|
||||
|
||||
assertThat(builder).isNotNull();
|
||||
assertThat(builder.getRegionService()).isEqualTo(mockRegionService);
|
||||
|
||||
verifyNoInteractions(mockRegionService);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructPdxInstanceBuilderWithNullRegionService() {
|
||||
|
||||
try {
|
||||
new PdxInstanceBuilder(null);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("RegionService must not be null");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPdxInstanceBuilderWithRegionService() {
|
||||
|
||||
RegionService mockRegionService = mock(RegionService.class);
|
||||
|
||||
PdxInstanceBuilder builder = PdxInstanceBuilder.create(mockRegionService);
|
||||
|
||||
assertThat(builder).isNotNull();
|
||||
assertThat(builder.getRegionService()).isEqualTo(mockRegionService);
|
||||
|
||||
verifyNoMoreInteractions(mockRegionService);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void createPdxInstanceBuilderWithUnresolvableRegionService() {
|
||||
|
||||
try {
|
||||
PdxInstanceBuilder.create();
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("GemFireCache not found");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyPdxInstance() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
doReturn("example.app.test.model.Type").when(mockPdxInstance).getClassName();
|
||||
doReturn("testOne").when(mockPdxInstance).getField(eq("fieldOne"));
|
||||
doReturn("testTwo").when(mockPdxInstance).getField(eq("fieldTwo"));
|
||||
doReturn(1).when(mockPdxInstance).getField(eq("id"));
|
||||
doReturn(Arrays.asList("fieldOne", "id", "fieldTwo")).when(mockPdxInstance).getFieldNames();
|
||||
doReturn(true).when(mockPdxInstance).isIdentityField(eq("id"));
|
||||
|
||||
PdxInstanceFactory mockPdxInstanceFactory = mock(PdxInstanceFactory.class);
|
||||
|
||||
RegionService mockRegionService = mock(RegionService.class);
|
||||
|
||||
doReturn(mockPdxInstanceFactory).when(mockRegionService)
|
||||
.createPdxInstanceFactory(eq("example.app.test.model.Type"));
|
||||
|
||||
PdxInstanceBuilder builder = PdxInstanceBuilder.create(mockRegionService);
|
||||
|
||||
assertThat(builder).isNotNull();
|
||||
assertThat(builder.getRegionService()).isEqualTo(mockRegionService);
|
||||
assertThat(builder.copy(mockPdxInstance)).isEqualTo(mockPdxInstanceFactory);
|
||||
|
||||
InOrder inOrder = Mockito.inOrder(mockPdxInstance, mockPdxInstanceFactory, mockRegionService);
|
||||
|
||||
inOrder.verify(mockPdxInstance, times(1)).getClassName();
|
||||
inOrder.verify(mockRegionService, times(1))
|
||||
.createPdxInstanceFactory(eq("example.app.test.model.Type"));
|
||||
inOrder.verify(mockPdxInstance, times(1)).getFieldNames();
|
||||
inOrder.verify(mockPdxInstance, times(1)).getField(eq("fieldOne"));
|
||||
inOrder.verify(mockPdxInstanceFactory, times(1))
|
||||
.writeObject(eq("fieldOne"), eq("testOne"));
|
||||
inOrder.verify(mockPdxInstance, times(1)).isIdentityField(eq("fieldOne"));
|
||||
inOrder.verify(mockPdxInstance, times(1)).getField(eq("id"));
|
||||
inOrder.verify(mockPdxInstanceFactory, times(1))
|
||||
.writeObject(eq("id"), eq(1));
|
||||
inOrder.verify(mockPdxInstance, times(1)).isIdentityField(eq("id"));
|
||||
inOrder.verify(mockPdxInstanceFactory, times(1)).markIdentityField(eq("id"));
|
||||
inOrder.verify(mockPdxInstance, times(1)).getField(eq("fieldTwo"));
|
||||
inOrder.verify(mockPdxInstanceFactory, times(1))
|
||||
.writeObject(eq("fieldTwo"), eq("testTwo"));
|
||||
inOrder.verify(mockPdxInstance, times(1)).isIdentityField(eq("fieldTwo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyPdxInstanceWhenGetFieldsNamesReturnsNullIsNullSafe() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceFactory mockPdxInstanceFactory = mock(PdxInstanceFactory.class);
|
||||
|
||||
RegionService mockRegionService = mock(RegionService.class);
|
||||
|
||||
doReturn("example.app.test.model.Type").when(mockPdxInstance).getClassName();
|
||||
doReturn(null).when(mockPdxInstance).getFieldNames();
|
||||
doReturn(mockPdxInstanceFactory).when(mockRegionService)
|
||||
.createPdxInstanceFactory(eq("example.app.test.model.Type"));
|
||||
|
||||
PdxInstanceBuilder builder = PdxInstanceBuilder.create(mockRegionService);
|
||||
|
||||
assertThat(builder).isNotNull();
|
||||
assertThat(builder.getRegionService()).isEqualTo(mockRegionService);
|
||||
assertThat(builder.copy(mockPdxInstance)).isEqualTo(mockPdxInstanceFactory);
|
||||
|
||||
verify(mockPdxInstance, times(1)).getFieldNames();
|
||||
verifyNoInteractions(mockPdxInstanceFactory);
|
||||
verify(mockRegionService, times(1))
|
||||
.createPdxInstanceFactory(eq("example.app.test.model.Type"));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void copyNullPdxInstanceThrowsIllegalArgumentException() {
|
||||
|
||||
RegionService mockRegionService = mock(RegionService.class);
|
||||
|
||||
try {
|
||||
PdxInstanceBuilder.create(mockRegionService).copy(null);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("PdxInstance must not be null");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
finally {
|
||||
verifyNoInteractions(mockRegionService);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromSourceObject() {
|
||||
|
||||
Object source = new Object();
|
||||
|
||||
GemFireCache mockCache = mock(GemFireCache.class);
|
||||
|
||||
PdxInstance mockPdxInstanceHolder = mock(PdxInstance.class);
|
||||
PdxInstance mockPdxInstanceSource = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceFactory mockPdxInstanceFactory = mock(PdxInstanceFactory.class);
|
||||
|
||||
doReturn(true).when(mockCache).getPdxReadSerialized();
|
||||
doReturn(mockPdxInstanceFactory).when(mockCache).createPdxInstanceFactory(eq(source.getClass().getName()));
|
||||
doReturn(mockPdxInstanceHolder).when(mockPdxInstanceFactory).create();
|
||||
doReturn(mockPdxInstanceSource).when(mockPdxInstanceHolder).getField(eq("source"));
|
||||
|
||||
PdxInstanceBuilder builder = PdxInstanceBuilder.create(mockCache);
|
||||
|
||||
assertThat(builder).isNotNull();
|
||||
assertThat(builder.getRegionService()).isEqualTo(mockCache);
|
||||
|
||||
PdxInstanceBuilder.Factory factory = builder.from(source);
|
||||
|
||||
assertThat(factory).isNotNull();
|
||||
assertThat(factory.create()).isEqualTo(mockPdxInstanceSource);
|
||||
|
||||
verify(mockCache, times(1)).getPdxReadSerialized();
|
||||
verify(mockCache, times(1)).createPdxInstanceFactory(eq(source.getClass().getName()));
|
||||
verify(mockPdxInstanceFactory, times(1)).writeObject(eq("source"), eq(source));
|
||||
verify(mockPdxInstanceFactory, times(1)).create();
|
||||
verify(mockPdxInstanceHolder, times(1)).getField(eq("source"));
|
||||
verifyNoInteractions(mockPdxInstanceSource);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void fromNullSourceObjectThrowsIllegalArgumentException() {
|
||||
|
||||
RegionService mockRegionService = mock(RegionService.class);
|
||||
|
||||
try {
|
||||
PdxInstanceBuilder.create(mockRegionService).from(null);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Source object to serialize to PDX must not be null");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
finally {
|
||||
verifyNoInteractions(mockRegionService);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void fromNonNullSourceObjectWhenCacheIsNotPresent() {
|
||||
|
||||
RegionService mockRegionService = mock(RegionService.class);
|
||||
|
||||
try {
|
||||
PdxInstanceBuilder.create(mockRegionService).from("TEST");
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("PDX read-serialized must be set to true");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
finally {
|
||||
verifyNoInteractions(mockRegionService);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void fromNonNullSourceObjectWhenCachePdxReadSerializedIsFalse() {
|
||||
|
||||
GemFireCache mockCache = mock(GemFireCache.class);
|
||||
|
||||
doReturn(false).when(mockCache).getPdxReadSerialized();
|
||||
|
||||
try {
|
||||
PdxInstanceBuilder.create(mockCache).from("TEST");
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("PDX read-serialized must be set to true");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
finally {
|
||||
verify(mockCache, times(1)).getPdxReadSerialized();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void fromNonNullSourceObjectReturningNonPdxInstanceThrowsIllegalArgumentException() {
|
||||
|
||||
Object source = new Object();
|
||||
|
||||
GemFireCache mockCache = mock(GemFireCache.class);
|
||||
|
||||
PdxInstance mockPdxInstanceHolder = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceFactory mockPdxInstanceFactory = mock(PdxInstanceFactory.class);
|
||||
|
||||
doReturn(true).when(mockCache).getPdxReadSerialized();
|
||||
doReturn(mockPdxInstanceFactory).when(mockCache).createPdxInstanceFactory(eq(source.getClass().getName()));
|
||||
doReturn(mockPdxInstanceHolder).when(mockPdxInstanceFactory).create();
|
||||
doReturn(source).when(mockPdxInstanceHolder).getField(eq("source"));
|
||||
|
||||
PdxInstanceBuilder builder = PdxInstanceBuilder.create(mockCache);
|
||||
|
||||
assertThat(builder).isNotNull();
|
||||
assertThat(builder.getRegionService()).isEqualTo(mockCache);
|
||||
|
||||
PdxInstanceBuilder.Factory factory = builder.from(source);
|
||||
|
||||
assertThat(factory).isNotNull();
|
||||
|
||||
try {
|
||||
factory.create();
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Expected an instance of PDX but was an instance of type [%s];"
|
||||
+ " Was PDX read-serialized set to true", source.getClass().getName());
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
finally {
|
||||
verify(mockCache, times(1)).getPdxReadSerialized();
|
||||
verify(mockCache, times(1)).createPdxInstanceFactory(eq(source.getClass().getName()));
|
||||
verify(mockPdxInstanceFactory, times(1)).writeObject(eq("source"), eq(source));
|
||||
verify(mockPdxInstanceHolder, times(1)).getField(eq("source"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void fromNonNullSourceObjectReturningNullOnPdxInstanceFactoryCreateIsNullSafe() {
|
||||
|
||||
Object source = mock(Object.class);
|
||||
|
||||
GemFireCache mockCache = mock(GemFireCache.class);
|
||||
|
||||
PdxInstanceFactory mockPdxInstanceFactory = mock(PdxInstanceFactory.class);
|
||||
|
||||
doReturn(true).when(mockCache).getPdxReadSerialized();
|
||||
doReturn(mockPdxInstanceFactory).when(mockCache).createPdxInstanceFactory(eq(source.getClass().getName()));
|
||||
doReturn(null).when(mockPdxInstanceFactory).create();
|
||||
|
||||
PdxInstanceBuilder builder = PdxInstanceBuilder.create(mockCache);
|
||||
|
||||
assertThat(builder).isNotNull();
|
||||
assertThat(builder.getRegionService()).isEqualTo(mockCache);
|
||||
|
||||
PdxInstanceBuilder.Factory factory = builder.from(source);
|
||||
|
||||
assertThat(factory).isNotNull();
|
||||
|
||||
try {
|
||||
factory.create();
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Expected an instance of PDX but was an instance of type [null];"
|
||||
+ " Was PDX read-serialized set to true");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
finally {
|
||||
verify(mockCache, times(1)).getPdxReadSerialized();
|
||||
verify(mockCache, times(1)).createPdxInstanceFactory(eq(source.getClass().getName()));
|
||||
verify(mockPdxInstanceFactory, times(1)).writeObject(eq("source"), eq(source));
|
||||
verifyNoInteractions(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,813 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.pdx;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerationException;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.geode.internal.Sendable;
|
||||
import org.apache.geode.pdx.JSONFormatter;
|
||||
import org.apache.geode.pdx.PdxInstance;
|
||||
import org.apache.geode.pdx.WritablePdxInstance;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link PdxInstanceWrapper}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see com.fasterxml.jackson.core.JsonGenerator
|
||||
* @see com.fasterxml.jackson.databind.ObjectMapper
|
||||
* @see com.fasterxml.jackson.databind.json.JsonMapper
|
||||
* @see org.apache.geode.pdx.JSONFormatter
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
* @see org.apache.geode.pdx.WritablePdxInstance
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class PdxInstanceWrapperUnitTests {
|
||||
|
||||
@Test
|
||||
public void constructPdxInstanceWrapper() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = new PdxInstanceWrapper(mockPdxInstance);
|
||||
|
||||
assertThat(wrapper).isNotNull();
|
||||
assertThat(wrapper.getDelegate()).isEqualTo(mockPdxInstance);
|
||||
|
||||
verifyNoInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructPdxInstanceWrapperWithNull() {
|
||||
|
||||
try {
|
||||
new PdxInstanceWrapper(null);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Argument must not be null");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromObjectIsObject() {
|
||||
assertThat(PdxInstanceWrapper.from("TEST")).isEqualTo("TEST");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromNullIsNull() {
|
||||
assertThat(PdxInstanceWrapper.from((Object) null)).isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromPdxInstanceIsWrapper() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = PdxInstanceWrapper.from(mockPdxInstance);
|
||||
|
||||
assertThat(wrapper).isNotNull();
|
||||
assertThat(wrapper.getDelegate()).isEqualTo(mockPdxInstance);
|
||||
|
||||
verifyNoInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromPdxInstanceWrapperIsSameWrapper() {
|
||||
|
||||
PdxInstanceWrapper mockWrapper = mock(PdxInstanceWrapper.class);
|
||||
|
||||
assertThat(PdxInstanceWrapper.from(mockWrapper)).isSameAs(mockWrapper);
|
||||
|
||||
verifyNoInteractions(mockWrapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unwrapPdxInstanceWrapperReturnsPdxInstanceDelegate() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = PdxInstanceWrapper.from(mockPdxInstance);
|
||||
|
||||
assertThat(wrapper).isNotNull();
|
||||
assertThat(wrapper.getDelegate()).isEqualTo(mockPdxInstance);
|
||||
assertThat(PdxInstanceWrapper.unwrap(wrapper)).isEqualTo(mockPdxInstance);
|
||||
|
||||
verifyNoInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unwrapPdxInstanceReturnsPdxInstance() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
assertThat(PdxInstanceWrapper.unwrap(mockPdxInstance)).isEqualTo(mockPdxInstance);
|
||||
|
||||
verifyNoInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unwrapNullIsNullSafeAndReturnsNull() {
|
||||
assertThat(PdxInstanceWrapper.unwrap(null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void objectMapperConfigurationIsCorrect() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(PdxInstanceWrapper.from(mockPdxInstance));
|
||||
|
||||
ObjectMapper mockObjectMapper = mock(ObjectMapper.class);
|
||||
|
||||
JsonMapper.Builder mockJsonMapperBuilder = mock(JsonMapper.Builder.class);
|
||||
|
||||
JsonMapper mockJsonMapper = mock(JsonMapper.class);
|
||||
|
||||
doReturn(mockJsonMapperBuilder).when(wrapper).newJsonMapperBuilder();
|
||||
doReturn(mockJsonMapperBuilder).when(mockJsonMapperBuilder).configure(any(DeserializationFeature.class), anyBoolean());
|
||||
doReturn(mockJsonMapperBuilder).when(mockJsonMapperBuilder).configure(any(MapperFeature.class), anyBoolean());
|
||||
doReturn(mockJsonMapper).when(mockJsonMapperBuilder).build();
|
||||
doReturn(mockObjectMapper).when(mockJsonMapper).findAndRegisterModules();
|
||||
|
||||
assertThat(wrapper.getDelegate()).isEqualTo(mockPdxInstance);
|
||||
|
||||
ObjectMapper objectMapper = wrapper.getObjectMapper().orElse(null);
|
||||
|
||||
assertThat(objectMapper).isNotNull();
|
||||
|
||||
verify(mockJsonMapperBuilder, times(1)).configure(eq(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES), eq(false));
|
||||
verify(mockJsonMapperBuilder, times(1)).configure(eq(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES), eq(false));
|
||||
verify(mockJsonMapperBuilder, times(1)).configure(eq(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS), eq(true));
|
||||
verify(mockJsonMapperBuilder, times(1)).build();
|
||||
verify(mockJsonMapper, times(1)).findAndRegisterModules();
|
||||
verifyNoMoreInteractions(mockJsonMapperBuilder, mockJsonMapper);
|
||||
verifyNoInteractions(mockPdxInstance, mockObjectMapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getClassNameCallsPdxInstanceGetClassName() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
doReturn("example.app.test.model.Type").when(mockPdxInstance).getClassName();
|
||||
|
||||
assertThat(PdxInstanceWrapper.from(mockPdxInstance).getClassName()).isEqualTo("example.app.test.model.Type");
|
||||
|
||||
verify(mockPdxInstance, times(1)).getClassName();
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isDeserializaleCallsPdxInstanceIsDeserializable() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
doReturn(true).when(mockPdxInstance).isDeserializable();
|
||||
|
||||
assertThat(PdxInstanceWrapper.from(mockPdxInstance).isDeserializable()).isTrue();
|
||||
|
||||
verify(mockPdxInstance, times(1)).isDeserializable();
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEnumCallsPdxInstanceIsEnum() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
doReturn(false).when(mockPdxInstance).isEnum();
|
||||
|
||||
assertThat(PdxInstanceWrapper.from(mockPdxInstance).isEnum()).isFalse();
|
||||
|
||||
verify(mockPdxInstance, times(1)).isEnum();
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isIdentityFieldCallsPdxInstanceIsIdentityField() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
doReturn(false).when(mockPdxInstance).isIdentityField(anyString());
|
||||
doReturn(true).when(mockPdxInstance).isIdentityField("id");
|
||||
|
||||
PdxInstanceWrapper wrapper = PdxInstanceWrapper.from(mockPdxInstance);
|
||||
|
||||
assertThat(wrapper.isIdentityField("id")).isTrue();
|
||||
assertThat(wrapper.isIdentityField("randomField")).isFalse();
|
||||
|
||||
verify(mockPdxInstance, times(1)).isIdentityField(eq("id"));
|
||||
verify(mockPdxInstance, times(1)).isIdentityField(eq("randomField"));
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFieldCallPdxInstanceGetField() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
doReturn("TestValue").when(mockPdxInstance).getField(eq("TestField"));
|
||||
|
||||
assertThat(PdxInstanceWrapper.from(mockPdxInstance).getField("TestField")).isEqualTo("TestValue");
|
||||
|
||||
verify(mockPdxInstance, times(1)).getField(eq("TestField"));
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFieldNameCallsPdxInstanceGetFieldNames() {
|
||||
|
||||
List<String> fieldNames = Arrays.asList("FieldOne", "FieldTwo");
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
doReturn(fieldNames).when(mockPdxInstance).getFieldNames();
|
||||
|
||||
assertThat(PdxInstanceWrapper.from(mockPdxInstance).getFieldNames()).isEqualTo(fieldNames);
|
||||
|
||||
verify(mockPdxInstance, times(1)).getFieldNames();
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIdentifierFromPdxInstanceHavingAnIdentity() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
doReturn(Arrays.asList("age", "id", "name")).when(mockPdxInstance).getFieldNames();
|
||||
doReturn(true).when(mockPdxInstance).isIdentityField(eq("id"));
|
||||
doReturn(42).when(mockPdxInstance).getField(eq("id"));
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(new PdxInstanceWrapper(mockPdxInstance));
|
||||
|
||||
assertThat(wrapper.getIdentifier()).isEqualTo(42);
|
||||
|
||||
verify(wrapper, never()).getId();
|
||||
verify(mockPdxInstance, times(1)).getFieldNames();
|
||||
verify(mockPdxInstance, times(1)).isIdentityField(eq("age"));
|
||||
verify(mockPdxInstance, times(1)).isIdentityField(eq("id"));
|
||||
verify(mockPdxInstance, never()).isIdentityField(eq("name"));
|
||||
verify(mockPdxInstance, times(1)).getField(eq("id"));
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIdentifierFromPdxInstanceHavingNoFields() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(new PdxInstanceWrapper(mockPdxInstance));
|
||||
|
||||
doReturn(null).when(mockPdxInstance).getFieldNames();
|
||||
doReturn(69).when(wrapper).getId();
|
||||
|
||||
assertThat(wrapper.getIdentifier()).isEqualTo(69);
|
||||
|
||||
verify(wrapper, times(1)).getId();
|
||||
verify(mockPdxInstance, times(1)).getFieldNames();
|
||||
verify(mockPdxInstance, never()).isIdentityField(anyString());
|
||||
verify(mockPdxInstance, never()).getField(anyString());
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIdentifierFromPdxInstanceHavingNoIdentityFields() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(new PdxInstanceWrapper(mockPdxInstance));
|
||||
|
||||
doReturn(Arrays.asList("", "age", null, "name", " ")).when(mockPdxInstance).getFieldNames();
|
||||
doReturn(false).when(mockPdxInstance).isIdentityField(any());
|
||||
doReturn(99).when(wrapper).getId();
|
||||
|
||||
assertThat(wrapper.getIdentifier()).isEqualTo(99);
|
||||
|
||||
verify(wrapper, times(1)).getId();
|
||||
verify(mockPdxInstance, times(1)).getFieldNames();
|
||||
verify(mockPdxInstance, times(1)).isIdentityField(eq("age"));
|
||||
verify(mockPdxInstance, times(1)).isIdentityField(eq("name"));
|
||||
verify(mockPdxInstance, never()).isIdentityField(isNull());
|
||||
verify(mockPdxInstance, never()).isIdentityField(eq(""));
|
||||
verify(mockPdxInstance, never()).isIdentityField(eq(" "));
|
||||
verify(mockPdxInstance, never()).getField(anyString());
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void getIdentifierFromPdxInstanceWithNoIdentifier() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(new PdxInstanceWrapper(mockPdxInstance));
|
||||
|
||||
doReturn(Collections.singletonList("name")).when(mockPdxInstance).getFieldNames();
|
||||
doReturn(false).when(mockPdxInstance).isIdentityField(anyString());
|
||||
doThrow(new IllegalStateException("NO ID")).when(wrapper).getId();
|
||||
|
||||
try {
|
||||
wrapper.getIdentifier();
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("NO ID");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
finally {
|
||||
verify(mockPdxInstance, times(1)).getFieldNames();
|
||||
verify(mockPdxInstance, times(1)).isIdentityField(eq("name"));
|
||||
verify(mockPdxInstance, never()).getField(anyString());
|
||||
verify(wrapper, times(1)).getId();
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIdFromPdxInstanceHavingIdField() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(new PdxInstanceWrapper(mockPdxInstance));
|
||||
|
||||
doReturn(true).when(mockPdxInstance).hasField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
doReturn(42).when(mockPdxInstance).getField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
|
||||
assertThat(wrapper.getId()).isEqualTo(42);
|
||||
|
||||
verify(mockPdxInstance, times(1)).hasField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
verify(mockPdxInstance, times(1)).getField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
verify(wrapper, never()).getAtIdentifier();
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIdFromPdxInstanceHavingIdFieldWithNoValueReturnsNull() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(new PdxInstanceWrapper(mockPdxInstance));
|
||||
|
||||
doReturn(true).when(mockPdxInstance).hasField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
doReturn(null).when(mockPdxInstance).getField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
|
||||
assertThat(wrapper.getId()).isNull();
|
||||
|
||||
verify(mockPdxInstance, times(1)).hasField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
verify(mockPdxInstance, times(1)).getField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
verify(wrapper, never()).getAtIdentifier();
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIdFromPdxInstanceWithNoIdFieldCallsGetAtIdentifier() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(new PdxInstanceWrapper(mockPdxInstance));
|
||||
|
||||
doReturn(false).when(mockPdxInstance).hasField(any());
|
||||
doReturn(99).when(wrapper).getAtIdentifier();
|
||||
|
||||
assertThat(wrapper.getId()).isEqualTo(99);
|
||||
|
||||
verify(mockPdxInstance, times(1)).hasField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
verify(mockPdxInstance, never()).getField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
verify(wrapper, times(1)).getAtIdentifier();
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAtIdentifierFromPdxInstance() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(new PdxInstanceWrapper(mockPdxInstance));
|
||||
|
||||
doReturn(true).when(mockPdxInstance).hasField(eq(PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME));
|
||||
doReturn(true).when(mockPdxInstance).hasField(eq("isbn"));
|
||||
doReturn("isbn").when(mockPdxInstance).getField(eq(PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME));
|
||||
doReturn("123456789").when(mockPdxInstance).getField(eq("isbn"));
|
||||
|
||||
assertThat(wrapper.getAtIdentifier()).isEqualTo("123456789");
|
||||
|
||||
verify(mockPdxInstance, times(1))
|
||||
.hasField(eq(PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME));
|
||||
verify(mockPdxInstance, times(1))
|
||||
.getField(eq(PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME));
|
||||
verify(mockPdxInstance, times(1)).hasField(eq("isbn"));
|
||||
verify(mockPdxInstance, times(1)).getField(eq("isbn"));
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void getAtIdentifierFromPdxInstanceWithNoDeclaredIdentity() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(new PdxInstanceWrapper(mockPdxInstance));
|
||||
|
||||
doReturn(Account.class.getName()).when(mockPdxInstance).getClassName();
|
||||
doReturn(false).when(mockPdxInstance).hasField(any());
|
||||
|
||||
try {
|
||||
wrapper.getAtIdentifier();
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("PdxInstance for type [%s] has no declared identifier",
|
||||
Account.class.getName());
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
finally {
|
||||
verify(mockPdxInstance, times(1)).getClassName();
|
||||
verify(mockPdxInstance, times(2))
|
||||
.hasField(eq(PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME));
|
||||
verify(mockPdxInstance, times(1))
|
||||
.hasField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
verify(mockPdxInstance, never()).getField(anyString());
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void getAtIdentifierFromPdxInstanceWithNoId() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(new PdxInstanceWrapper(mockPdxInstance));
|
||||
|
||||
doReturn(Account.class.getName()).when(mockPdxInstance).getClassName();
|
||||
doReturn(true).when(mockPdxInstance).hasField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
|
||||
try {
|
||||
wrapper.getAtIdentifier();
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("PdxInstance for type [%s] has no id",
|
||||
Account.class.getName());
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
finally {
|
||||
verify(mockPdxInstance, times(1)).getClassName();
|
||||
verify(mockPdxInstance, times(1))
|
||||
.hasField(eq(PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME));
|
||||
verify(mockPdxInstance, times(1))
|
||||
.hasField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
verify(mockPdxInstance, never()).getField(any());
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void getAtIdentifierFromPdxInstanceWithValidAtIdentifierAndIdentifierFieldButNoId() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(new PdxInstanceWrapper(mockPdxInstance));
|
||||
|
||||
doReturn(Person.class.getName()).when(mockPdxInstance).getClassName();
|
||||
doReturn(true).when(mockPdxInstance).hasField(eq(PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME));
|
||||
doReturn(false).when(mockPdxInstance).hasField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
doReturn(true).when(mockPdxInstance).hasField(eq("ssn"));
|
||||
doReturn("ssn").when(mockPdxInstance).getField(eq(PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME));
|
||||
doReturn(null).when(mockPdxInstance).getField(eq("ssn"));
|
||||
|
||||
try {
|
||||
wrapper.getAtIdentifier();
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
|
||||
String expectedMessage = "PdxInstance for type [%s] has no value [null] for field [ssn] declared in [%s]";
|
||||
|
||||
assertThat(expected).hasMessage(expectedMessage, Person.class.getName(),
|
||||
PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME);
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
finally {
|
||||
verify(mockPdxInstance, times(1)).getClassName();
|
||||
verify(mockPdxInstance, times(2)).hasField(eq(PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME));
|
||||
verify(mockPdxInstance, times(1)).hasField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
verify(mockPdxInstance, times(2)).hasField(eq("ssn"));
|
||||
verify(mockPdxInstance, times(2)).getField(eq(PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME));
|
||||
verify(mockPdxInstance, times(2)).getField(eq("ssn"));
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void getAtIdentifierFromPdxInstanceWithAtIdentifierReferringToInvalidIdentifierField() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(new PdxInstanceWrapper(mockPdxInstance));
|
||||
|
||||
doReturn(Person.class.getName()).when(mockPdxInstance).getClassName();
|
||||
doReturn(true).when(mockPdxInstance).hasField(eq(PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME));
|
||||
doReturn(false).when(mockPdxInstance).hasField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
doReturn(false).when(mockPdxInstance).hasField(eq("ssn"));
|
||||
doReturn("ssn").when(mockPdxInstance).getField(eq(PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME));
|
||||
|
||||
try {
|
||||
wrapper.getAtIdentifier();
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("PdxInstance for type [%s] has no field [ssn] declared in [%s]",
|
||||
Person.class.getName(), PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME);
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
finally {
|
||||
verify(mockPdxInstance, times(1)).getClassName();
|
||||
verify(mockPdxInstance, times(2)).hasField(eq(PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME));
|
||||
verify(mockPdxInstance, times(1)).hasField(eq(PdxInstanceWrapper.ID_FIELD_NAME));
|
||||
verify(mockPdxInstance, times(2)).hasField(eq("ssn"));
|
||||
verify(mockPdxInstance, times(2)).getField(eq(PdxInstanceWrapper.AT_IDENTIFIER_FIELD_NAME));
|
||||
verify(mockPdxInstance, never()).getField(eq("ssn"));
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getObjectReturnsObject() throws JsonProcessingException {
|
||||
|
||||
Account mockAccount = mock(Account.class);
|
||||
|
||||
ObjectMapper mockObjectMapper = mock(ObjectMapper.class);
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
String json = String.format("{ \"@type\": \"%s\", \"name\": \"Savings\"}", Account.class.getName());
|
||||
|
||||
doReturn(JSONFormatter.JSON_CLASSNAME).when(mockPdxInstance).getClassName();
|
||||
doReturn(true).when(mockPdxInstance).hasField(eq(PdxInstanceWrapper.AT_TYPE_FIELD_NAME));
|
||||
doReturn(Account.class.getName()).when(mockPdxInstance).getField(eq(PdxInstanceWrapper.AT_TYPE_FIELD_NAME));
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(PdxInstanceWrapper.from(mockPdxInstance));
|
||||
|
||||
assertThat(wrapper).isNotNull();
|
||||
assertThat(wrapper.getDelegate()).isEqualTo(mockPdxInstance);
|
||||
|
||||
doReturn(Optional.of(mockObjectMapper)).when(wrapper).getObjectMapper();
|
||||
doReturn(json).when(wrapper).jsonFormatterToJson(eq(mockPdxInstance));
|
||||
doReturn(mockAccount).when(mockObjectMapper).readValue(eq(json), eq(Account.class));
|
||||
|
||||
assertThat(wrapper.getObject()).isEqualTo(mockAccount);
|
||||
|
||||
verify(wrapper, atLeastOnce()).getDelegate();
|
||||
verify(wrapper, times(1)).getObjectMapper();
|
||||
verify(mockPdxInstance, times(1)).getClassName();
|
||||
verify(mockPdxInstance, times(1)).hasField(eq(PdxInstanceWrapper.AT_TYPE_FIELD_NAME));
|
||||
verify(mockPdxInstance, times(1)).getField(eq(PdxInstanceWrapper.AT_TYPE_FIELD_NAME));
|
||||
verify(wrapper, times(1)).jsonFormatterToJson(eq(mockPdxInstance));
|
||||
verify(mockObjectMapper, times(1)).readValue(eq(json), eq(Account.class));
|
||||
verify(mockPdxInstance, never()).getObject();
|
||||
verifyNoMoreInteractions(mockObjectMapper, mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getObjectCallsPdxInstanceGetObjectWhenAtTypeFieldIsNotPresent() throws JsonProcessingException {
|
||||
|
||||
Object value = new Object();
|
||||
|
||||
ObjectMapper mockObjectMapper = mock(ObjectMapper.class);
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
doReturn(JSONFormatter.JSON_CLASSNAME).when(mockPdxInstance).getClassName();
|
||||
doReturn(false).when(mockPdxInstance).hasField(eq(PdxInstanceWrapper.AT_TYPE_FIELD_NAME));
|
||||
doReturn(value).when(mockPdxInstance).getObject();
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(PdxInstanceWrapper.from(mockPdxInstance));
|
||||
|
||||
assertThat(wrapper).isNotNull();
|
||||
assertThat(wrapper.getDelegate()).isEqualTo(mockPdxInstance);
|
||||
|
||||
doReturn(Optional.of(mockObjectMapper)).when(wrapper).getObjectMapper();
|
||||
|
||||
assertThat(wrapper.getObject()).isEqualTo(value);
|
||||
|
||||
verify(wrapper, atLeastOnce()).getDelegate();
|
||||
verify(wrapper, times(1)).getObjectMapper();
|
||||
verify(mockPdxInstance, times(1)).getClassName();
|
||||
verify(mockPdxInstance, times(1)).hasField(eq(PdxInstanceWrapper.AT_TYPE_FIELD_NAME));
|
||||
verify(mockPdxInstance, never()).getField(anyString());
|
||||
verify(wrapper, never()).jsonFormatterToJson(any());
|
||||
verify(mockObjectMapper, never()).readValue(anyString(), any(Class.class));
|
||||
verify(mockPdxInstance, times(1)).getObject();
|
||||
verifyNoMoreInteractions(mockObjectMapper, mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getObjectCallsPdxInstanceGetObjectWhenClassNameIsNotGemFireJson() throws JsonProcessingException {
|
||||
|
||||
ObjectMapper mockObjectMapper = mock(ObjectMapper.class);
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
doReturn("non.existing.class.Name").when(mockPdxInstance).getClassName();
|
||||
doReturn("TEST").when(mockPdxInstance).getObject();
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(PdxInstanceWrapper.from(mockPdxInstance));
|
||||
|
||||
assertThat(wrapper).isNotNull();
|
||||
assertThat(wrapper.getDelegate()).isEqualTo(mockPdxInstance);
|
||||
|
||||
doReturn(Optional.of(mockObjectMapper)).when(wrapper).getObjectMapper();
|
||||
|
||||
assertThat(wrapper.getObject()).isEqualTo("TEST");
|
||||
|
||||
verify(wrapper, atLeastOnce()).getDelegate();
|
||||
verify(wrapper, times(1)).getObjectMapper();
|
||||
verify(mockPdxInstance, times(1)).getClassName();
|
||||
verify(mockPdxInstance, never()).hasField(anyString());
|
||||
verify(mockPdxInstance, never()).getField(anyString());
|
||||
verify(wrapper, never()).jsonFormatterToJson(any());
|
||||
verify(mockObjectMapper, never()).readValue(anyString(), any(Class.class));
|
||||
verify(mockPdxInstance, times(1)).getObject();
|
||||
verifyNoMoreInteractions(mockObjectMapper, mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getObjectCallsPdxInstanceGetObjectWhenExceptionIsThrown() throws JsonProcessingException {
|
||||
|
||||
Object value = new Object();
|
||||
|
||||
ObjectMapper mockObjectMapper = mock(ObjectMapper.class);
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
String json = String.format("{ \"@type\": \"%s\", \"name\": \"Checking\"}", Account.class.getName());
|
||||
|
||||
doReturn(JSONFormatter.JSON_CLASSNAME).when(mockPdxInstance).getClassName();
|
||||
doReturn(true).when(mockPdxInstance).hasField(eq(PdxInstanceWrapper.AT_TYPE_FIELD_NAME));
|
||||
doReturn(Account.class.getName()).when(mockPdxInstance).getField(eq(PdxInstanceWrapper.AT_TYPE_FIELD_NAME));
|
||||
doReturn(value).when(mockPdxInstance).getObject();
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(PdxInstanceWrapper.from(mockPdxInstance));
|
||||
|
||||
assertThat(wrapper).isNotNull();
|
||||
assertThat(wrapper.getDelegate()).isEqualTo(mockPdxInstance);
|
||||
|
||||
doReturn(Optional.of(mockObjectMapper)).when(wrapper).getObjectMapper();
|
||||
doReturn(json).when(wrapper).jsonFormatterToJson(eq(mockPdxInstance));
|
||||
doThrow(new JsonGenerationException("TEST", mock(JsonGenerator.class)))
|
||||
.when(mockObjectMapper).readValue(anyString(), any(Class.class));
|
||||
|
||||
assertThat(wrapper.getObject()).isEqualTo(value);
|
||||
|
||||
verify(wrapper, times(1)).getObjectMapper();
|
||||
verify(mockPdxInstance, times(1)).getClassName();
|
||||
verify(mockPdxInstance, times(1)).hasField(eq(PdxInstanceWrapper.AT_TYPE_FIELD_NAME));
|
||||
verify(mockPdxInstance, times(1)).getField(eq(PdxInstanceWrapper.AT_TYPE_FIELD_NAME));
|
||||
verify(wrapper, atLeastOnce()).getDelegate();
|
||||
verify(wrapper, times(1)).jsonFormatterToJson(eq(mockPdxInstance));
|
||||
verify(mockObjectMapper, times(1)).readValue(eq(json), eq(Account.class));
|
||||
verify(mockPdxInstance, times((1))).getObject();
|
||||
verifyNoMoreInteractions(mockObjectMapper, mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getObjectCallsPdxInstanceGetObjectWhenObjectMapperIsNotPresent() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
doReturn("non.existing.class.Name").when(mockPdxInstance).getClassName();
|
||||
doReturn("MOCK").when(mockPdxInstance).getObject();
|
||||
|
||||
PdxInstanceWrapper wrapper = spy(PdxInstanceWrapper.from(mockPdxInstance));
|
||||
|
||||
assertThat(wrapper).isNotNull();
|
||||
assertThat(wrapper.getDelegate()).isEqualTo(mockPdxInstance);
|
||||
|
||||
doReturn(Optional.empty()).when(wrapper).getObjectMapper();
|
||||
|
||||
assertThat(wrapper.getObject()).isEqualTo("MOCK");
|
||||
|
||||
verify(wrapper, atLeastOnce()).getDelegate();
|
||||
verify(wrapper, times(1)).getObjectMapper();
|
||||
verify(wrapper, never()).jsonFormatterToJson(any());
|
||||
verify(mockPdxInstance, times(1)).getObject();
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWriterCallsPdxInstanceCreateWriter() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
WritablePdxInstance mockWritablePdxInstance = mock(WritablePdxInstance.class);
|
||||
|
||||
doReturn(mockWritablePdxInstance).when(mockPdxInstance).createWriter();
|
||||
|
||||
assertThat(PdxInstanceWrapper.from(mockPdxInstance).createWriter()).isEqualTo(mockWritablePdxInstance);
|
||||
|
||||
verify(mockPdxInstance, times(1)).createWriter();
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasFieldCallsPdxInstanceHasField() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
doReturn(true).when(mockPdxInstance).hasField("name");
|
||||
|
||||
assertThat(PdxInstanceWrapper.from(mockPdxInstance).hasField("name")).isTrue();
|
||||
|
||||
verify(mockPdxInstance, times(1)).hasField(eq("name"));
|
||||
verifyNoMoreInteractions(mockPdxInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendToCallsPdxInstanceSendTo() throws IOException {
|
||||
|
||||
SendablePdxInstance mockSendablePdxInstance = mock(SendablePdxInstance.class);
|
||||
|
||||
PdxInstanceWrapper wrapper = PdxInstanceWrapper.from(mockSendablePdxInstance);
|
||||
|
||||
DataOutput mockOut = mock(DataOutput.class);
|
||||
|
||||
assertThat(wrapper).isNotNull();
|
||||
assertThat(wrapper.getDelegate()).isEqualTo(mockSendablePdxInstance);
|
||||
|
||||
wrapper.sendTo(mockOut);
|
||||
|
||||
verify(mockSendablePdxInstance, times(1)).sendTo(eq(mockOut));
|
||||
verifyNoMoreInteractions(mockSendablePdxInstance);
|
||||
verifyNoMoreInteractions(mockOut);
|
||||
}
|
||||
|
||||
interface Account {
|
||||
@SuppressWarnings("unused")
|
||||
String getName();
|
||||
}
|
||||
|
||||
interface Person { }
|
||||
|
||||
interface SendablePdxInstance extends PdxInstance, Sendable { }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.security;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.geode.util.GeodeConstants;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link TestAuthInitialize}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.Properties
|
||||
* @see org.junit.Test
|
||||
* @see org.springframework.geode.security.TestAuthInitialize
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class TestAuthInitializeUnitTests {
|
||||
|
||||
private final TestAuthInitialize authInitialize = TestAuthInitialize.create();
|
||||
|
||||
private boolean isSet(String value) {
|
||||
return !(value == null || value.trim().isEmpty());
|
||||
}
|
||||
|
||||
private Properties newSecurityProperties(String username, String password) {
|
||||
|
||||
Properties securityProperties = new Properties();
|
||||
|
||||
if (isSet(username)) {
|
||||
securityProperties.setProperty(GeodeConstants.USERNAME, username);
|
||||
}
|
||||
|
||||
if (isSet(password)) {
|
||||
securityProperties.setProperty(GeodeConstants.PASSWORD, password);
|
||||
}
|
||||
|
||||
return securityProperties;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCredentialsUsesProperties() {
|
||||
|
||||
Properties securityProperties = newSecurityProperties("testUser", "s3cr3t");
|
||||
Properties credentials = this.authInitialize.getCredentials(securityProperties, null, false);
|
||||
|
||||
assertThat(credentials).isNotNull();
|
||||
assertThat(credentials.getProperty(GeodeConstants.USERNAME)).isEqualTo("testUser");
|
||||
assertThat(credentials.getProperty(GeodeConstants.PASSWORD)).isEqualTo("s3cr3t");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCredentialsUsesProvidedUsernameAndDefaultPassword() {
|
||||
|
||||
Properties securityProperties = newSecurityProperties("testUser", null);
|
||||
Properties credentials = this.authInitialize.getCredentials(securityProperties, null, false);
|
||||
|
||||
assertThat(credentials).isNotNull();
|
||||
assertThat(credentials.getProperty(GeodeConstants.USERNAME)).isEqualTo("testUser");
|
||||
assertThat(credentials.getProperty(GeodeConstants.PASSWORD)).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCredentialsUsesProvidedPasswordAndDefaultUsername() {
|
||||
|
||||
Properties securityProperties = newSecurityProperties(null, "s3cr3t");
|
||||
Properties credentials = this.authInitialize.getCredentials(securityProperties, null, false);
|
||||
|
||||
assertThat(credentials).isNotNull();
|
||||
assertThat(credentials.getProperty(GeodeConstants.USERNAME)).isEqualTo("test");
|
||||
assertThat(credentials.getProperty(GeodeConstants.PASSWORD)).isEqualTo("s3cr3t");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCredentialsUsesDefaultUsernameAndPassword() {
|
||||
|
||||
Properties securityProperties = newSecurityProperties(null, null);
|
||||
Properties credentials = this.authInitialize.getCredentials(securityProperties, null, false);
|
||||
|
||||
assertThat(credentials).isNotNull();
|
||||
assertThat(credentials.getProperty(GeodeConstants.USERNAME)).isEqualTo("test");
|
||||
assertThat(credentials.getProperty(GeodeConstants.PASSWORD)).isEqualTo("test");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.security;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.geode.security.AuthenticationFailedException;
|
||||
import org.apache.geode.security.ResourcePermission;
|
||||
|
||||
import org.springframework.geode.util.GeodeConstants;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link org.springframework.geode.security.TestSecurityManager}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.geode.security.TestSecurityManager
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class TestSecurityManagerUnitTests {
|
||||
|
||||
private TestSecurityManager securityManager = new TestSecurityManager();
|
||||
|
||||
private Properties newSecurityProperties(String username, String password) {
|
||||
|
||||
Properties securityProperties = new Properties();
|
||||
|
||||
securityProperties.setProperty(GeodeConstants.USERNAME, username);
|
||||
securityProperties.setProperty(GeodeConstants.PASSWORD, password);
|
||||
|
||||
return securityProperties;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userAuthenticates() {
|
||||
|
||||
Object user = this.securityManager.authenticate(newSecurityProperties("test", "test"));
|
||||
|
||||
assertThat(user).isInstanceOf(TestSecurityManager.User.class);
|
||||
assertThat(((TestSecurityManager.User) user).getName()).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test(expected = AuthenticationFailedException.class)
|
||||
public void userDoesNotAuthenticateBecauseUsernamePasswordAreCaseSensitive() {
|
||||
|
||||
try {
|
||||
this.securityManager.authenticate(newSecurityProperties("TestUser", "testuser"));
|
||||
}
|
||||
catch (AuthenticationFailedException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("User [TestUser] could not be authenticated");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = AuthenticationFailedException.class)
|
||||
public void userDoesNotAuthenticateWhenUsernamePasswordDoNotMatch() {
|
||||
|
||||
try {
|
||||
this.securityManager.authenticate(newSecurityProperties("testUser", "testPassword"));
|
||||
}
|
||||
catch (AuthenticationFailedException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("User [testUser] could not be authenticated");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userIsAlwaysAuthorized() {
|
||||
|
||||
ResourcePermission clusterManage =
|
||||
new ResourcePermission(ResourcePermission.Resource.CLUSTER, ResourcePermission.Operation.MANAGE);
|
||||
|
||||
assertThat(this.securityManager.authorize(null, clusterManage)).isTrue();
|
||||
assertThat(this.securityManager.authorize(new TestSecurityManager.User("test"), clusterManage)).isTrue();
|
||||
assertThat(this.securityManager.authorize(mock(Principal.class), clusterManage)).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,564 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.util;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.DataPolicy;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionAttributes;
|
||||
import org.apache.geode.cache.RegionService;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.internal.cache.GemFireCacheImpl;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link CacheUtils}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.RegionAttributes
|
||||
* @see org.apache.geode.cache.RegionService
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class CacheUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void collectValuesFromClientRegion() {
|
||||
|
||||
Region<Object, Object> mockRegion = mock(Region.class);
|
||||
|
||||
RegionAttributes<Object, Object> mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
RegionService mockRegionService = mock(ClientCache.class);
|
||||
|
||||
Set<?> keySetOnServer = new TreeSet<>(Arrays.asList(1, 2, 3));
|
||||
|
||||
Map<Object, Object> keysValues = new HashMap<>();
|
||||
|
||||
keysValues.put(1, "one");
|
||||
keysValues.put(2, "two");
|
||||
keysValues.put(3, "three");
|
||||
|
||||
doReturn(mockRegionAttributes).when(mockRegion).getAttributes();
|
||||
doReturn(mockRegionService).when(mockRegion).getRegionService();
|
||||
doReturn(keySetOnServer).when(mockRegion).keySetOnServer();
|
||||
doReturn(keysValues).when(mockRegion).getAll(eq(keySetOnServer));
|
||||
doReturn(DataPolicy.EMPTY).when(mockRegionAttributes).getDataPolicy();
|
||||
|
||||
assertThat(CacheUtils.collectValues(mockRegion)).containsExactlyInAnyOrder(keysValues.values().toArray());
|
||||
|
||||
verify(mockRegion, times(2)).getAttributes();
|
||||
verify(mockRegion, times(1)).getRegionService();
|
||||
verify(mockRegion, times(1)).keySetOnServer();
|
||||
verify(mockRegion, times(1)).getAll(eq(keySetOnServer));
|
||||
verify(mockRegion, never()).values();
|
||||
verify(mockRegionAttributes, times(1)).getDataPolicy();
|
||||
verify(mockRegionAttributes, never()).getPoolName();
|
||||
verifyNoInteractions(mockRegionService);
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectValuesFromClientRegionWhenClientRegionGetAllKeysReturnsNullMapIsNullSafe() {
|
||||
|
||||
Region<Object, Object> mockRegion = mock(Region.class);
|
||||
|
||||
RegionAttributes<Object, Object> mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
RegionService mockRegionService = mock(ClientCache.class);
|
||||
|
||||
Set<Object> keySetOnServer = new TreeSet<>(Arrays.asList(1, 2));
|
||||
|
||||
doReturn(mockRegionAttributes).when(mockRegion).getAttributes();
|
||||
doReturn(mockRegionService).when(mockRegion).getRegionService();
|
||||
doReturn(keySetOnServer).when(mockRegion).keySetOnServer();
|
||||
doReturn(null).when(mockRegion).getAll(eq(keySetOnServer));
|
||||
doReturn(DataPolicy.NORMAL).when(mockRegionAttributes).getDataPolicy();
|
||||
doReturn("Car").when(mockRegionAttributes).getPoolName();
|
||||
|
||||
Collection<Object> values = CacheUtils.collectValues(mockRegion);
|
||||
|
||||
assertThat(values).isNotNull();
|
||||
assertThat(values).isEmpty();
|
||||
|
||||
verify(mockRegion, times(3)).getAttributes();
|
||||
verify(mockRegion, times(1)).getRegionService();
|
||||
verify(mockRegion, times(1)).keySetOnServer();
|
||||
verify(mockRegion, times(1)).getAll(eq(keySetOnServer));
|
||||
verify(mockRegion, never()).values();
|
||||
verify(mockRegionAttributes, times(1)).getDataPolicy();
|
||||
verify(mockRegionAttributes, times(1)).getPoolName();
|
||||
verifyNoInteractions(mockRegionService);
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectValuesFromClientRegionWhenClientRegionKeySetOnServerReturnsNullSetIsNullSafe() {
|
||||
|
||||
Region<Object, Object> mockRegion = mock(Region.class);
|
||||
|
||||
RegionAttributes<Object, Object> mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
RegionService mockRegionService = mock(ClientCache.class);
|
||||
|
||||
doReturn(mockRegionAttributes).when(mockRegion).getAttributes();
|
||||
doReturn(mockRegionService).when(mockRegion).getRegionService();
|
||||
doReturn(null).when(mockRegion).keySetOnServer();
|
||||
doReturn(DataPolicy.PARTITION).when(mockRegionAttributes).getDataPolicy();
|
||||
doReturn("Dead").when(mockRegionAttributes).getPoolName();
|
||||
|
||||
Collection<Object> values = CacheUtils.collectValues(mockRegion);
|
||||
|
||||
assertThat(values).isNotNull();
|
||||
assertThat(values).isEmpty();
|
||||
|
||||
verify(mockRegion, times(3)).getAttributes();
|
||||
verify(mockRegion, times(1)).getRegionService();
|
||||
verify(mockRegion, times(1)).keySetOnServer();
|
||||
verify(mockRegion, never()).getAll(any());
|
||||
verify(mockRegion, never()).values();
|
||||
verify(mockRegionAttributes, times(1)).getDataPolicy();
|
||||
verify(mockRegionAttributes, times(1)).getPoolName();
|
||||
verifyNoInteractions(mockRegionService);
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectValuesFromClientRegionWhenClientRegionGetRegionServiceReturnsNullIsNullSafe() {
|
||||
|
||||
Collection<Object> values = Arrays.asList("one", "two", "three");
|
||||
|
||||
Region<Object, Object> mockRegion = mock(Region.class);
|
||||
|
||||
doReturn(null).when(mockRegion).getRegionService();
|
||||
doReturn(values).when(mockRegion).values();
|
||||
|
||||
assertThat(CacheUtils.collectValues(mockRegion)).containsExactlyInAnyOrder(values.toArray());
|
||||
|
||||
verify(mockRegion, times(1)).getRegionService();
|
||||
verify(mockRegion, times(1)).values();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectValuesFromLocalClientRegion() {
|
||||
|
||||
Region<?, String> mockRegion = mock(Region.class);
|
||||
|
||||
RegionAttributes<?, String> mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
RegionService mockRegionService = mock(ClientCache.class);
|
||||
|
||||
doReturn(mockRegionAttributes).when(mockRegion).getAttributes();
|
||||
doReturn(mockRegionService).when(mockRegion).getRegionService();
|
||||
doReturn(DataPolicy.NORMAL).when(mockRegionAttributes).getDataPolicy();
|
||||
doReturn(" ").when(mockRegionAttributes).getPoolName();
|
||||
doReturn(Arrays.asList("one", "two")).when(mockRegion).values();
|
||||
|
||||
Collection<String> values = CacheUtils.collectValues(mockRegion);
|
||||
|
||||
assertThat(values).isNotNull();
|
||||
assertThat(values).containsExactly("one", "two");
|
||||
|
||||
verify(mockRegion, times(1)).getRegionService();
|
||||
verify(mockRegion, times(3)).getAttributes();
|
||||
verify(mockRegion, times(1)).values();
|
||||
verify(mockRegion, never()).keySetOnServer();
|
||||
verify(mockRegion, never()).getAll(any());
|
||||
verify(mockRegionAttributes, times(1)).getDataPolicy();
|
||||
verify(mockRegionAttributes, times(1)).getPoolName();
|
||||
verifyNoInteractions(mockRegionService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectValuesFromPeerRegion() {
|
||||
|
||||
Region<Object, Object> mockRegion = mock(Region.class);
|
||||
|
||||
RegionService mockRegionService = mock(Cache.class);
|
||||
|
||||
Collection<Object> values = Arrays.asList("one", "two", "three");
|
||||
|
||||
doReturn(mockRegionService).when(mockRegion).getRegionService();
|
||||
doReturn(values).when(mockRegion).values();
|
||||
|
||||
assertThat(CacheUtils.collectValues(mockRegion)).containsExactlyInAnyOrder(values.toArray());
|
||||
|
||||
verify(mockRegion, times(1)).getRegionService();
|
||||
verify(mockRegion, times(1)).values();
|
||||
verifyNoInteractions(mockRegionService);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void collectValuesWithNullRegionThrowsIllegalArgumentException() {
|
||||
|
||||
try {
|
||||
CacheUtils.collectValues(null);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessageStartingWith("Argument must not be null");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isClientCacheWithClientCache() {
|
||||
assertThat(CacheUtils.isClientCache(mock(ClientCache.class))).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isClientCacheWithGemFireCacheImplWhenIsClientReturnsTrue() {
|
||||
|
||||
GemFireCacheImpl mockCache = mock(GemFireCacheImpl.class);
|
||||
|
||||
doReturn(true).when(mockCache).isClient();
|
||||
|
||||
assertThat(CacheUtils.isClientCache(mockCache)).isTrue();
|
||||
|
||||
verify(mockCache, times(1)).isClient();
|
||||
verifyNoMoreInteractions(mockCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isClientCacheWithGemFireCacheImplWhenIsClientReturnsFalse() {
|
||||
|
||||
GemFireCacheImpl mockCache = mock(GemFireCacheImpl.class);
|
||||
|
||||
doReturn(false).when(mockCache).isClient();
|
||||
|
||||
assertThat(CacheUtils.isClientCache(mockCache)).isFalse();
|
||||
|
||||
verify(mockCache, times(1)).isClient();
|
||||
verifyNoMoreInteractions(mockCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isClientCacheWithNonClientCache() {
|
||||
assertThat(CacheUtils.isClientCache(mock(Cache.class))).isFalse();
|
||||
assertThat(CacheUtils.isClientCache(mock(GemFireCache.class))).isFalse();
|
||||
assertThat(CacheUtils.isClientCache(mock(RegionService.class))).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isClientCacheWithNull() {
|
||||
assertThat(CacheUtils.isClientCache(null)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isClientRegionWithClientRegionInClientCache() {
|
||||
|
||||
Region<?, ?> mockRegion = mock(Region.class);
|
||||
|
||||
RegionService mockRegionService = mock(ClientCache.class);
|
||||
|
||||
doReturn(mockRegionService).when(mockRegion).getRegionService();
|
||||
|
||||
assertThat(CacheUtils.isClientRegion(mockRegion)).isTrue();
|
||||
assertThat(CacheUtils.isPeerRegion(mockRegion)).isFalse();
|
||||
|
||||
verify(mockRegion, times(2)).getRegionService();
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
verifyNoInteractions(mockRegionService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isClientRegionWithClientRegionDeterminedByPoolName() {
|
||||
|
||||
Region<?, ?> mockRegion = mock(Region.class);
|
||||
|
||||
RegionAttributes<?, ?> mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
RegionService mockRegionService = mock(RegionService.class);
|
||||
|
||||
doReturn(mockRegionAttributes).when(mockRegion).getAttributes();
|
||||
doReturn(mockRegionService).when(mockRegion).getRegionService();
|
||||
doReturn("TestPool").when(mockRegionAttributes).getPoolName();
|
||||
|
||||
assertThat(CacheUtils.isClientRegion(mockRegion)).isTrue();
|
||||
assertThat(CacheUtils.isPeerRegion(mockRegion)).isFalse();
|
||||
|
||||
verify(mockRegion, times(2)).getRegionService();
|
||||
verify(mockRegion, times(2)).getAttributes();
|
||||
verify(mockRegionAttributes, times(2)).getPoolName();
|
||||
verifyNoMoreInteractions(mockRegion, mockRegionAttributes);
|
||||
verifyNoInteractions(mockRegionService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isClientRegionWithRegionHavingNoPoolName() {
|
||||
|
||||
Region<?, ?> mockRegion = mock(Region.class);
|
||||
|
||||
RegionAttributes<?, ?> mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
doReturn(mockRegionAttributes).when(mockRegion).getAttributes();
|
||||
doReturn(null).when(mockRegion).getRegionService();
|
||||
doReturn(" ").when(mockRegionAttributes).getPoolName();
|
||||
|
||||
assertThat(CacheUtils.isClientRegion(mockRegion)).isFalse();
|
||||
assertThat(CacheUtils.isPeerRegion(mockRegion)).isTrue();
|
||||
|
||||
verify(mockRegion, times(2)).getRegionService();
|
||||
verify(mockRegion, times(2)).getAttributes();
|
||||
verify(mockRegionAttributes, times(2)).getPoolName();
|
||||
verifyNoMoreInteractions(mockRegion, mockRegionAttributes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isClientRegionWithRegionHavingNoRegionAttributes() {
|
||||
|
||||
Region<?, ?> mockRegion = mock(Region.class);
|
||||
|
||||
doReturn(null).when(mockRegion).getAttributes();
|
||||
doReturn(null).when(mockRegion).getRegionService();
|
||||
|
||||
assertThat(CacheUtils.isClientRegion(mockRegion)).isFalse();
|
||||
assertThat(CacheUtils.isPeerRegion(mockRegion)).isTrue();
|
||||
|
||||
verify(mockRegion, times(2)).getRegionService();
|
||||
verify(mockRegion, times(2)).getAttributes();
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isClientRegionWithPeerRegionInPeerCache() {
|
||||
|
||||
Region<?, ?> mockRegion = mock(Region.class);
|
||||
|
||||
RegionService mockRegionService = mock(Cache.class);
|
||||
|
||||
doReturn(mockRegionService).when(mockRegion).getRegionService();
|
||||
|
||||
assertThat(CacheUtils.isClientRegion(mockRegion)).isFalse();
|
||||
assertThat(CacheUtils.isPeerRegion(mockRegion)).isTrue();
|
||||
|
||||
verify(mockRegion, times(2)).getRegionService();
|
||||
verify(mockRegion, times(2)).getAttributes();
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isClientRegionWithNull() {
|
||||
assertThat(CacheUtils.isClientRegion(null)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isPeerCacheWithPeerCache() {
|
||||
assertThat(CacheUtils.isPeerCache(mock(Cache.class))).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isPeerCacheWithGemFireCacheImplWhenIsClientReturnsTrue() {
|
||||
|
||||
GemFireCacheImpl mockCache = mock(GemFireCacheImpl.class);
|
||||
|
||||
doReturn(true).when(mockCache).isClient();
|
||||
|
||||
assertThat(CacheUtils.isPeerCache(mockCache)).isFalse();
|
||||
|
||||
verify(mockCache, times(1)).isClient();
|
||||
verifyNoMoreInteractions(mockCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isPeerCacheWithGemFireCacheImplWhenIsClientReturnsFalse() {
|
||||
|
||||
GemFireCacheImpl mockCache = mock(GemFireCacheImpl.class);
|
||||
|
||||
doReturn(false).when(mockCache).isClient();
|
||||
|
||||
assertThat(CacheUtils.isPeerCache(mockCache)).isTrue();
|
||||
|
||||
verify(mockCache, times(1)).isClient();
|
||||
verifyNoMoreInteractions(mockCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isPeerCacheWithNonPeerCache() {
|
||||
assertThat(CacheUtils.isPeerCache(mock(ClientCache.class))).isFalse();
|
||||
assertThat(CacheUtils.isPeerCache(mock(GemFireCache.class))).isFalse();
|
||||
assertThat(CacheUtils.isPeerCache(mock(RegionService.class))).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isPeerCacheWithNull() {
|
||||
assertThat(CacheUtils.isPeerCache(null)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isPeerRegionWithNull() {
|
||||
assertThat(CacheUtils.isPeerRegion(null)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isProxyRegionWithProxyRegionBasedOnDataPolicy() {
|
||||
|
||||
Region<?, ?> mockRegion = mock(Region.class);
|
||||
|
||||
RegionAttributes<?, ?> mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
doReturn(mockRegionAttributes).when(mockRegion).getAttributes();
|
||||
doReturn(DataPolicy.EMPTY).when(mockRegionAttributes).getDataPolicy();
|
||||
|
||||
assertThat(CacheUtils.isProxyRegion(mockRegion)).isTrue();
|
||||
|
||||
verify(mockRegion, times(2)).getAttributes();
|
||||
verify(mockRegionAttributes, times(1)).getDataPolicy();
|
||||
verify(mockRegionAttributes, never()).getPoolName();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isProxyRegionWithProxyRegionBasedOnPoolConfiguration() {
|
||||
|
||||
Region<?, ?> mockRegion = mock(Region.class);
|
||||
|
||||
RegionAttributes<?, ?> mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
doReturn(mockRegionAttributes).when(mockRegion).getAttributes();
|
||||
doReturn(DataPolicy.NORMAL).when(mockRegionAttributes).getDataPolicy();
|
||||
doReturn("TestPool").when(mockRegionAttributes).getPoolName();
|
||||
|
||||
assertThat(CacheUtils.isProxyRegion(mockRegion)).isTrue();
|
||||
|
||||
verify(mockRegion, times(3)).getAttributes();
|
||||
verify(mockRegionAttributes, times(1)).getDataPolicy();
|
||||
verify(mockRegionAttributes, times(1)).getPoolName();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isProxyRegionWithNonProxyRegion() {
|
||||
|
||||
Region<?, ?> mockRegion = mock(Region.class);
|
||||
|
||||
RegionAttributes<?, ?> mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
doReturn(mockRegionAttributes).when(mockRegion).getAttributes();
|
||||
doReturn(DataPolicy.NORMAL).when(mockRegionAttributes).getDataPolicy();
|
||||
doReturn(" ").when(mockRegionAttributes).getPoolName();
|
||||
|
||||
assertThat(CacheUtils.isProxyRegion(mockRegion)).isFalse();
|
||||
|
||||
verify(mockRegion, times(3)).getAttributes();
|
||||
verify(mockRegionAttributes, times(1)).getDataPolicy();
|
||||
verify(mockRegionAttributes, times(1)).getPoolName();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isProxyRegionWithRegionHavingNoAttributesIsNullSafe() {
|
||||
|
||||
Region<?, ?> mockRegion = mock(Region.class);
|
||||
|
||||
assertThat(CacheUtils.isProxyRegion(mockRegion)).isFalse();
|
||||
|
||||
verify(mockRegion, times(1)).getAttributes();
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isProxyRegionWithNullRegionIsNullSafe() {
|
||||
assertThat(CacheUtils.isProxyRegion(null)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isRegionWithPoolWithPooledRegion() {
|
||||
|
||||
Region<?, ?> mockRegion = mock(Region.class);
|
||||
|
||||
RegionAttributes<?, ?> mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
doReturn(mockRegionAttributes).when(mockRegion).getAttributes();
|
||||
doReturn("Swimming").when(mockRegionAttributes).getPoolName();
|
||||
|
||||
assertThat(CacheUtils.isRegionWithPool(mockRegion)).isTrue();
|
||||
|
||||
verify(mockRegion, times(1)).getAttributes();
|
||||
verify(mockRegionAttributes, times(1)).getPoolName();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isRegionWithPoolUsingRegionHavingNoAttributesIsNullSafe() {
|
||||
|
||||
Region<?, ?> mockRegion = mock(Region.class);
|
||||
|
||||
assertThat(CacheUtils.isRegionWithPool(mockRegion)).isFalse();
|
||||
|
||||
verify(mockRegion, times(1)).getAttributes();
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isRegionWithPoolUsingNullRegionIsNullSafe() {
|
||||
assertThat(CacheUtils.isRegionWithPool(null)).isFalse();
|
||||
}
|
||||
|
||||
private void testIsRegionWithPoolUsingRegionWithInvalidPoolNameReturnsFalse(String poolName) {
|
||||
|
||||
Region<?, ?> mockRegion = mock(Region.class);
|
||||
|
||||
RegionAttributes<?, ?> mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
doReturn(mockRegionAttributes).when(mockRegion).getAttributes();
|
||||
doReturn(poolName).when(mockRegionAttributes).getPoolName();
|
||||
|
||||
assertThat(CacheUtils.isRegionWithPool(mockRegion)).isFalse();
|
||||
|
||||
verify(mockRegion, times(1)).getAttributes();
|
||||
verify(mockRegionAttributes, times(1)).getPoolName();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isRegionWithPoolUsingRegionConfiguredWithBlankPoolName() {
|
||||
testIsRegionWithPoolUsingRegionWithInvalidPoolNameReturnsFalse(" ");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isRegionWithPoolUsingRegionConfiguredWithEmptyPoolName() {
|
||||
testIsRegionWithPoolUsingRegionWithInvalidPoolNameReturnsFalse("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isRegionWithPoolUsingRegionConfiguredWithNullPoolName() {
|
||||
testIsRegionWithPoolUsingRegionWithInvalidPoolNameReturnsFalse(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.util.function;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link InvocationArguments).
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.springframework.geode.util.function.InvocationArguments
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class InvocationArgumentsUnitTests {
|
||||
|
||||
@Test
|
||||
public void constructsInvocationArgumentsWithArguments() {
|
||||
|
||||
Object[] arguments = { true, 'c', 1, Math.PI, "test" };
|
||||
|
||||
InvocationArguments invocationArguments = new InvocationArguments(arguments);
|
||||
|
||||
assertThat(invocationArguments).isNotNull();
|
||||
assertThat(invocationArguments.size()).isEqualTo(arguments.length);
|
||||
assertThat(Arrays.equals(invocationArguments.getArguments(), arguments)).isTrue();
|
||||
assertThat(invocationArguments.<Boolean>getArgumentAt(0)).isEqualTo(true);
|
||||
assertThat(invocationArguments.<Character>getArgumentAt(1)).isEqualTo('c');
|
||||
assertThat(invocationArguments.<Integer>getArgumentAt(2)).isEqualTo(1);
|
||||
assertThat(invocationArguments.<Double>getArgumentAt(3)).isEqualTo(Math.PI);
|
||||
assertThat(invocationArguments.<String>getArgumentAt(4)).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromConstructsNewInvocationArguments() {
|
||||
|
||||
InvocationArguments arguments = InvocationArguments.from("test", 1, false);
|
||||
|
||||
assertThat(arguments).isNotNull();
|
||||
assertThat(arguments).hasSize(3);
|
||||
assertThat(arguments.size()).isEqualTo(3);
|
||||
assertThat(arguments).containsExactly("test", 1, false);
|
||||
assertThat(arguments.<String>getArgumentAt(0)).isEqualTo("test");
|
||||
assertThat(arguments.<Integer>getArgumentAt(1)).isEqualTo(1);
|
||||
assertThat(arguments.<Boolean>getArgumentAt(2)).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructInvocationArgumentsWithNull() {
|
||||
|
||||
InvocationArguments arguments = new InvocationArguments(null);
|
||||
|
||||
assertThat(arguments).isNotNull();
|
||||
assertThat(arguments).hasSize(0);
|
||||
assertThat(arguments.getArguments()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void iteratesArguments() {
|
||||
|
||||
Object[] arguments = { true, 1, "test" };
|
||||
|
||||
InvocationArguments invocationArguments = new InvocationArguments(arguments);
|
||||
|
||||
int index = 0;
|
||||
|
||||
for (Object argument : invocationArguments) {
|
||||
assertThat(argument).isEqualTo(arguments[index++]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toStringIsCorrect() {
|
||||
|
||||
InvocationArguments arguments = InvocationArguments.from("one", "two", "three");
|
||||
|
||||
assertThat(arguments).isNotNull();
|
||||
assertThat(arguments.toString()).isEqualTo("[one, two, three]");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.util.function;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doCallRealMethod;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link TriConsumer}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.geode.util.function.TriConsumer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class TriConsumerUnitTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void andThenComposesTriConsumers() {
|
||||
|
||||
TriConsumer consumerOne = mock(TriConsumer.class);
|
||||
TriConsumer consumerTwo = mock(TriConsumer.class);
|
||||
|
||||
doCallRealMethod().when(consumerOne).andThen(any(TriConsumer.class));
|
||||
|
||||
TriConsumer composedConsumer = consumerOne.andThen(consumerTwo);
|
||||
|
||||
assertThat(composedConsumer).isNotNull();
|
||||
assertThat(composedConsumer).isNotSameAs(consumerOne);
|
||||
assertThat(composedConsumer).isNotSameAs(consumerTwo);
|
||||
|
||||
composedConsumer.accept("one", "two", "three");
|
||||
|
||||
InOrder order = inOrder(consumerOne, consumerTwo);
|
||||
|
||||
order.verify(consumerOne, times(1))
|
||||
.accept(eq("one"), eq("two"), eq("three"));
|
||||
order.verify(consumerTwo, times(1))
|
||||
.accept(eq("one"), eq("two"), eq("three"));
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void andThenWithNull() {
|
||||
|
||||
TriConsumer consumer = mock(TriConsumer.class);
|
||||
|
||||
doCallRealMethod().when(consumer).andThen(any());
|
||||
|
||||
consumer.andThen(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.util.function;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doCallRealMethod;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link TupleConsumer}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.function.Consumer
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.geode.util.function.TupleConsumer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class TupleConsumerUnitTests {
|
||||
|
||||
@Test
|
||||
public void andThenComposesTupleConsumers() {
|
||||
|
||||
TupleConsumer consumerOne = mock(TupleConsumer.class);
|
||||
TupleConsumer consumerTwo = mock(TupleConsumer.class);
|
||||
|
||||
doCallRealMethod().when(consumerOne).andThen(any(TupleConsumer.class));
|
||||
|
||||
Consumer<InvocationArguments> composedConsumer = consumerOne.andThen(consumerTwo);
|
||||
|
||||
assertThat(composedConsumer).isNotNull();
|
||||
assertThat(composedConsumer).isNotSameAs(consumerOne);
|
||||
assertThat(composedConsumer).isNotSameAs(consumerTwo);
|
||||
|
||||
InvocationArguments arguments = InvocationArguments.from("test", 1, true);
|
||||
|
||||
composedConsumer.accept(arguments);
|
||||
|
||||
InOrder order = inOrder(consumerOne, consumerTwo);
|
||||
|
||||
order.verify(consumerOne, times(1)).accept(eq(arguments));
|
||||
order.verify(consumerTwo, times(1)).accept(eq(arguments));
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void andThenWithNull() {
|
||||
|
||||
TupleConsumer consumer = mock(TupleConsumer.class);
|
||||
|
||||
doCallRealMethod().when(consumer).andThen(any());
|
||||
|
||||
consumer.andThen(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
description = "Spring Boot Actuator Auto-Configuration for Apache Geode"
|
||||
|
||||
dependencies {
|
||||
|
||||
api project(":spring-geode-actuator")
|
||||
api project(":spring-geode-autoconfigure")
|
||||
|
||||
compileOnly "com.google.code.findbugs:jsr305:$findbugsVersion"
|
||||
|
||||
// See additional testImplementation dependencies declared in the testDependencies project extension
|
||||
// defined in the DependencySetPlugin.
|
||||
testImplementation "org.springframework.boot:spring-boot-starter-test"
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate.autoconfigure;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.gemfire.CacheFactoryBean;
|
||||
import org.springframework.geode.boot.actuate.autoconfigure.config.BaseGeodeHealthIndicatorConfiguration;
|
||||
import org.springframework.geode.boot.actuate.autoconfigure.config.ClientCacheHealthIndicatorConfiguration;
|
||||
import org.springframework.geode.boot.actuate.autoconfigure.config.PeerCacheHealthIndicatorConfiguration;
|
||||
import org.springframework.geode.boot.autoconfigure.ClientCacheAutoConfiguration;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} for Apache Geode
|
||||
* {@link HealthIndicator HealthIndicators}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator
|
||||
* @see org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.context.annotation.Import
|
||||
* @see org.springframework.data.gemfire.CacheFactoryBean
|
||||
* @see org.springframework.geode.boot.actuate.autoconfigure.config.BaseGeodeHealthIndicatorConfiguration
|
||||
* @see org.springframework.geode.boot.actuate.autoconfigure.config.ClientCacheHealthIndicatorConfiguration
|
||||
* @see org.springframework.geode.boot.actuate.autoconfigure.config.PeerCacheHealthIndicatorConfiguration
|
||||
* @see org.springframework.geode.boot.autoconfigure.ClientCacheAutoConfiguration
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter(ClientCacheAutoConfiguration.class)
|
||||
@ConditionalOnBean(GemFireCache.class)
|
||||
@ConditionalOnClass(CacheFactoryBean.class)
|
||||
@ConditionalOnEnabledHealthIndicator("geode")
|
||||
@Import({
|
||||
BaseGeodeHealthIndicatorConfiguration.class,
|
||||
ClientCacheHealthIndicatorConfiguration.class,
|
||||
PeerCacheHealthIndicatorConfiguration.class,
|
||||
})
|
||||
@SuppressWarnings("unused")
|
||||
public class GeodeHealthIndicatorAutoConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate.autoconfigure.config;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.geode.boot.actuate.GeodeCacheHealthIndicator;
|
||||
import org.springframework.geode.boot.actuate.GeodeDiskStoresHealthIndicator;
|
||||
import org.springframework.geode.boot.actuate.GeodeIndexesHealthIndicator;
|
||||
import org.springframework.geode.boot.actuate.GeodeRegionsHealthIndicator;
|
||||
|
||||
/**
|
||||
* Spring {@link Configuration} class declaring Spring beans for general Apache Geode peer {@link Cache}
|
||||
* and {@link ClientCache} {@link HealthIndicator HealthIndicators}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.geode.boot.actuate.GeodeCacheHealthIndicator
|
||||
* @see org.springframework.geode.boot.actuate.GeodeDiskStoresHealthIndicator
|
||||
* @see org.springframework.geode.boot.actuate.GeodeIndexesHealthIndicator
|
||||
* @see org.springframework.geode.boot.actuate.GeodeRegionsHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@SuppressWarnings("unused")
|
||||
public class BaseGeodeHealthIndicatorConfiguration {
|
||||
|
||||
@Bean("GeodeCacheHealthIndicator")
|
||||
GeodeCacheHealthIndicator cacheHealthIndicator(GemFireCache gemfireCache) {
|
||||
return new GeodeCacheHealthIndicator(gemfireCache);
|
||||
}
|
||||
|
||||
@Bean("GeodeDiskStoresHealthIndicator")
|
||||
GeodeDiskStoresHealthIndicator diskStoresHealthIndicator(ApplicationContext applicationContext) {
|
||||
return new GeodeDiskStoresHealthIndicator(applicationContext);
|
||||
}
|
||||
|
||||
@Bean("GeodeIndexesHealthIndicator")
|
||||
GeodeIndexesHealthIndicator indexesHealthIndicator(ApplicationContext applicationContext) {
|
||||
return new GeodeIndexesHealthIndicator(applicationContext);
|
||||
}
|
||||
|
||||
@Bean("GeodeRegionsHealthIndicator")
|
||||
GeodeRegionsHealthIndicator regionsHealthIndicator(GemFireCache gemfireCache) {
|
||||
return new GeodeRegionsHealthIndicator(gemfireCache);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate.autoconfigure.config;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.data.gemfire.listener.ContinuousQueryListenerContainer;
|
||||
import org.springframework.data.gemfire.util.CacheUtils;
|
||||
import org.springframework.geode.boot.actuate.GeodeContinuousQueriesHealthIndicator;
|
||||
import org.springframework.geode.boot.actuate.GeodePoolsHealthIndicator;
|
||||
|
||||
/**
|
||||
* Spring {@link Configuration} class declaring Spring beans for Apache Geode {@link ClientCache}
|
||||
* {@link HealthIndicator HealthIndicators}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.geode.boot.actuate.GeodeContinuousQueriesHealthIndicator
|
||||
* @see org.springframework.geode.boot.actuate.GeodePoolsHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@Conditional(ClientCacheHealthIndicatorConfiguration.ClientCacheCondition.class)
|
||||
@SuppressWarnings("unused")
|
||||
public class ClientCacheHealthIndicatorConfiguration {
|
||||
|
||||
@Bean("GeodeContinuousQueryHealthIndicator")
|
||||
GeodeContinuousQueriesHealthIndicator continuousQueriesHealthIndicator(
|
||||
@Autowired(required = false) ContinuousQueryListenerContainer continuousQueryListenerContainer) {
|
||||
|
||||
return new GeodeContinuousQueriesHealthIndicator(continuousQueryListenerContainer);
|
||||
}
|
||||
|
||||
@Bean("GeodePoolsHealthIndicator")
|
||||
GeodePoolsHealthIndicator poolsHealthIndicator(GemFireCache gemfireCache) {
|
||||
return new GeodePoolsHealthIndicator(gemfireCache);
|
||||
}
|
||||
|
||||
public static final class ClientCacheCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
|
||||
Cache peerCache = CacheUtils.getCache();
|
||||
|
||||
ClientCache clientCache = CacheUtils.getClientCache();
|
||||
|
||||
return clientCache != null || peerCache == null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate.autoconfigure.config;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.server.CacheServer;
|
||||
import org.apache.geode.cache.server.ServerLoadProbe;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.data.gemfire.server.CacheServerFactoryBean;
|
||||
import org.springframework.data.gemfire.util.CacheUtils;
|
||||
import org.springframework.geode.boot.actuate.GeodeAsyncEventQueuesHealthIndicator;
|
||||
import org.springframework.geode.boot.actuate.GeodeCacheServersHealthIndicator;
|
||||
import org.springframework.geode.boot.actuate.GeodeGatewayReceiversHealthIndicator;
|
||||
import org.springframework.geode.boot.actuate.GeodeGatewaySendersHealthIndicator;
|
||||
import org.springframework.geode.boot.actuate.health.support.ActuatorServerLoadProbeWrapper;
|
||||
import org.springframework.geode.core.util.ObjectUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Spring {@link Configuration} class declaring Spring beans for Apache Geode peer {@link Cache}
|
||||
* {@link HealthIndicator HealthIndicators}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.geode.boot.actuate.GeodeAsyncEventQueuesHealthIndicator
|
||||
* @see org.springframework.geode.boot.actuate.GeodeCacheServersHealthIndicator
|
||||
* @see org.springframework.geode.boot.actuate.GeodeGatewayReceiversHealthIndicator
|
||||
* @see org.springframework.geode.boot.actuate.GeodeGatewaySendersHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@Conditional(PeerCacheHealthIndicatorConfiguration.PeerCacheCondition.class)
|
||||
@SuppressWarnings("unused")
|
||||
public class PeerCacheHealthIndicatorConfiguration {
|
||||
|
||||
@Bean("GeodeAsyncEventQueuesHealthIndicator")
|
||||
GeodeAsyncEventQueuesHealthIndicator asyncEventQueuesHealthIndicator(GemFireCache gemfireCache) {
|
||||
return new GeodeAsyncEventQueuesHealthIndicator(gemfireCache);
|
||||
}
|
||||
|
||||
@Bean("GeodeCacheServersHealthIndicator")
|
||||
GeodeCacheServersHealthIndicator cacheServersHealthIndicator(GemFireCache gemfireCache) {
|
||||
return new GeodeCacheServersHealthIndicator(gemfireCache);
|
||||
}
|
||||
|
||||
@Bean("GeodeGatewayReceiversHealthIndicator")
|
||||
GeodeGatewayReceiversHealthIndicator gatewayReceiversHealthIndicator(GemFireCache gemfireCache) {
|
||||
return new GeodeGatewayReceiversHealthIndicator(gemfireCache);
|
||||
}
|
||||
|
||||
@Bean("GeodeGatewaySendersHealthIndicator")
|
||||
GeodeGatewaySendersHealthIndicator gatewaySendersHealthIndicator(GemFireCache gemfireCache) {
|
||||
return new GeodeGatewaySendersHealthIndicator(gemfireCache);
|
||||
}
|
||||
|
||||
@Bean
|
||||
BeanPostProcessor cacheServerLoadProbeWrappingBeanPostProcessor() {
|
||||
|
||||
return new BeanPostProcessor() {
|
||||
|
||||
@Nullable @Override @SuppressWarnings("all")
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
|
||||
if (bean instanceof CacheServerFactoryBean) {
|
||||
|
||||
CacheServerFactoryBean cacheServerFactoryBean = (CacheServerFactoryBean) bean;
|
||||
|
||||
ServerLoadProbe serverLoadProbe =
|
||||
ObjectUtils.<ServerLoadProbe>get(bean, "serverLoadProbe");
|
||||
|
||||
if (serverLoadProbe != null) {
|
||||
cacheServerFactoryBean.setServerLoadProbe(wrap(serverLoadProbe));
|
||||
}
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Nullable @Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
|
||||
if (bean instanceof CacheServer) {
|
||||
|
||||
CacheServer cacheServer = (CacheServer) bean;
|
||||
|
||||
Optional.ofNullable(cacheServer.getLoadProbe())
|
||||
.filter(it -> !(it instanceof ActuatorServerLoadProbeWrapper))
|
||||
.filter(it -> cacheServer.getLoadPollInterval() > 0)
|
||||
.filter(it -> !cacheServer.isRunning())
|
||||
.ifPresent(serverLoadProbe ->
|
||||
cacheServer.setLoadProbe(new ActuatorServerLoadProbeWrapper(serverLoadProbe)));
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
private ServerLoadProbe wrap(ServerLoadProbe serverLoadProbe) {
|
||||
return new ActuatorServerLoadProbeWrapper(serverLoadProbe);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static final class PeerCacheCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
|
||||
Cache peerCache = CacheUtils.getCache();
|
||||
|
||||
ClientCache clientCache = CacheUtils.getClientCache();
|
||||
|
||||
return peerCache != null || clientCache == null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.geode.boot.actuate.autoconfigure.GeodeHealthIndicatorAutoConfiguration
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate.autoconfigure;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.server.CacheServer;
|
||||
import org.apache.geode.cache.server.ServerLoad;
|
||||
import org.apache.geode.cache.server.ServerLoadProbe;
|
||||
import org.apache.geode.cache.server.ServerMetrics;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.gemfire.config.annotation.PeerCacheApplication;
|
||||
import org.springframework.data.gemfire.server.CacheServerFactoryBean;
|
||||
import org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport;
|
||||
import org.springframework.data.gemfire.tests.mock.CacheServerMockObjects;
|
||||
import org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects;
|
||||
import org.springframework.geode.boot.actuate.GeodeCacheServersHealthIndicator;
|
||||
import org.springframework.geode.boot.actuate.health.support.ActuatorServerLoadProbeWrapper;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* The GeodeCacheServerHealthIndicatorAutoConfigurationIntegrationTests class...
|
||||
*
|
||||
* @author John Blum
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
|
||||
@SuppressWarnings("unused")
|
||||
public class GeodeCacheServerHealthIndicatorAutoConfigurationIntegrationTests extends IntegrationTestsSupport {
|
||||
|
||||
private static final String GEODE_LOG_LEVEL = "error";
|
||||
|
||||
@Autowired
|
||||
private GeodeCacheServersHealthIndicator healthIndicator;
|
||||
|
||||
@Test
|
||||
public void mockCacheServerHealthCheckWithServerLoadDetails() {
|
||||
|
||||
Health health = this.healthIndicator.health();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
|
||||
Map<String, Object> healthDetails = health.getDetails();
|
||||
|
||||
assertThat(healthDetails).isNotNull();
|
||||
assertThat(healthDetails).isNotEmpty();
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.count", 1);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.port", 48484);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.load.connection-load", 0.65f);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.load.load-per-connection", 0.35f);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.load.load-per-subscription-connection", 0.75f);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.load.subscription-connection-load", 0.55f);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.metrics.client-count", 21);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.metrics.max-connection-count", 800);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.metrics.open-connection-count", 400);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.metrics.subscription-connection-count", 200);
|
||||
}
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableGemFireMockObjects
|
||||
@PeerCacheApplication(
|
||||
name = "GeodeCacheServerHealthIndicatorAutoConfigurationIntegrationTests",
|
||||
logLevel = GEODE_LOG_LEVEL
|
||||
)
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean("MockCacheServer")
|
||||
CacheServerFactoryBean mockCacheServer(Cache gemfireCache) {
|
||||
|
||||
CacheServerFactoryBean mockCacheServer = new CacheServerFactoryBean();
|
||||
|
||||
mockCacheServer.setCache(gemfireCache);
|
||||
mockCacheServer.setPort(48484);
|
||||
mockCacheServer.setServerLoadProbe(mockServerLoadProbe());
|
||||
|
||||
return mockCacheServer;
|
||||
}
|
||||
|
||||
@Bean("MockServerLoadProbe")
|
||||
ServerLoadProbe mockServerLoadProbe() {
|
||||
return CacheServerMockObjects.mockServerLoadProbe();
|
||||
}
|
||||
|
||||
@Bean
|
||||
ApplicationRunner runner(ServerLoadProbe mockServerLoadProbe,
|
||||
@Qualifier("MockCacheServer") CacheServer mockCacheServer) {
|
||||
|
||||
return args -> {
|
||||
|
||||
assertThat(mockCacheServer.getLoadProbe()).isInstanceOf(ActuatorServerLoadProbeWrapper.class);
|
||||
|
||||
ServerMetrics mockServerMetrics = CacheServerMockObjects.mockServerMetrics(21,
|
||||
400, 800, 200);
|
||||
|
||||
ServerLoad mockServerLoad = CacheServerMockObjects.mockServerLoad(0.65f,
|
||||
0.35f, 0.75f, 0.55f);
|
||||
|
||||
when(mockServerLoadProbe.getLoad(eq(mockServerMetrics))).thenReturn(mockServerLoad);
|
||||
|
||||
ServerLoadProbe serverLoadProbe = mockCacheServer.getLoadProbe();
|
||||
|
||||
if (serverLoadProbe != null) {
|
||||
serverLoadProbe.getLoad(mockServerMetrics);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
description = "Spring Boot Actuator for Apache Geode"
|
||||
|
||||
dependencies {
|
||||
|
||||
api project(":spring-geode")
|
||||
|
||||
api "org.springframework.boot:spring-boot-starter-actuator"
|
||||
|
||||
provided "org.apache.geode:geode-logging:$apacheGeodeVersion"
|
||||
provided "org.apache.geode:geode-serialization:$apacheGeodeVersion"
|
||||
|
||||
// See additional testImplementation dependencies declared in the testDependencies project extension
|
||||
// defined in the DependencySetPlugin.
|
||||
testImplementation "org.springframework.boot:spring-boot-starter-test"
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.asyncqueue.AsyncEventQueue;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.data.gemfire.util.CacheUtils;
|
||||
import org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator;
|
||||
|
||||
/**
|
||||
* The {@link GeodeAsyncEventQueuesHealthIndicator} class is a Spring Boot {@link HealthIndicator} providing details
|
||||
* about the health of Apache Geode {@link AsyncEventQueue AsyncEventQueues}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.asyncqueue.AsyncEventQueue
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class GeodeAsyncEventQueuesHealthIndicator extends AbstractGeodeHealthIndicator {
|
||||
|
||||
/**
|
||||
* Default constructor to construct an uninitialized instance of {@link GeodeAsyncEventQueuesHealthIndicator},
|
||||
* which will not provide any health information.
|
||||
*/
|
||||
public GeodeAsyncEventQueuesHealthIndicator() {
|
||||
super("Async Event Queues health check failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link GeodeAsyncEventQueuesHealthIndicator} initialized with a reference to
|
||||
* the {@link GemFireCache} instance.
|
||||
*
|
||||
* @param gemfireCache reference to the {@link GemFireCache} instance used to collect health information.
|
||||
* @throws IllegalArgumentException if {@link GemFireCache} is {@literal null}.
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
*/
|
||||
public GeodeAsyncEventQueuesHealthIndicator(GemFireCache gemfireCache) {
|
||||
super(gemfireCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
|
||||
if (getGemFireCache().filter(CacheUtils::isPeer).isPresent()) {
|
||||
|
||||
Set<AsyncEventQueue> asyncEventQueues = getGemFireCache()
|
||||
.map(Cache.class::cast)
|
||||
.map(Cache::getAsyncEventQueues)
|
||||
.orElseGet(Collections::emptySet);
|
||||
|
||||
builder.withDetail("geode.async-event-queue.count", asyncEventQueues.size());
|
||||
|
||||
asyncEventQueues.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(asyncEventQueue -> {
|
||||
|
||||
String asyncEventQueueId = asyncEventQueue.getId();
|
||||
|
||||
builder.withDetail(asyncEventQueueKey(asyncEventQueueId, "batch-conflation-enabled"), toYesNoString(asyncEventQueue.isBatchConflationEnabled()))
|
||||
.withDetail(asyncEventQueueKey(asyncEventQueueId, "batch-size"), asyncEventQueue.getBatchSize())
|
||||
.withDetail(asyncEventQueueKey(asyncEventQueueId, "batch-time-interval"), asyncEventQueue.getBatchTimeInterval())
|
||||
.withDetail(asyncEventQueueKey(asyncEventQueueId, "disk-store-name"), asyncEventQueue.getDiskStoreName())
|
||||
.withDetail(asyncEventQueueKey(asyncEventQueueId, "disk-synchronous"), toYesNoString(asyncEventQueue.isDiskSynchronous()))
|
||||
.withDetail(asyncEventQueueKey(asyncEventQueueId, "dispatcher-threads"), asyncEventQueue.getDispatcherThreads())
|
||||
.withDetail(asyncEventQueueKey(asyncEventQueueId, "forward-expiration-destroy"), toYesNoString(asyncEventQueue.isForwardExpirationDestroy()))
|
||||
.withDetail(asyncEventQueueKey(asyncEventQueueId, "max-queue-memory"), asyncEventQueue.getMaximumQueueMemory())
|
||||
.withDetail(asyncEventQueueKey(asyncEventQueueId, "order-policy"), asyncEventQueue.getOrderPolicy())
|
||||
.withDetail(asyncEventQueueKey(asyncEventQueueId, "parallel"), toYesNoString(asyncEventQueue.isParallel()))
|
||||
.withDetail(asyncEventQueueKey(asyncEventQueueId, "persistent"), toYesNoString(asyncEventQueue.isPersistent()))
|
||||
.withDetail(asyncEventQueueKey(asyncEventQueueId, "primary"), toYesNoString(asyncEventQueue.isPrimary()))
|
||||
.withDetail(asyncEventQueueKey(asyncEventQueueId, "size"), asyncEventQueue.size());
|
||||
});
|
||||
|
||||
builder.up();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
builder.unknown();
|
||||
}
|
||||
|
||||
private String asyncEventQueueKey(String id, String suffix) {
|
||||
return String.format("geode.async-event-queue.%1$s.%2$s", id, suffix);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.apache.geode.CancelCriterion;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.control.ResourceManager;
|
||||
import org.apache.geode.distributed.DistributedMember;
|
||||
import org.apache.geode.distributed.DistributedSystem;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.data.gemfire.util.CollectionUtils;
|
||||
import org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The {@link GeodeCacheHealthIndicator} class is a Spring Boot {@link HealthIndicator} providing details about
|
||||
* the health of the {@link GemFireCache}, the {@link DistributedSystem}, this {@link DistributedMember}
|
||||
* and the {@link ResourceManager}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.net.URL
|
||||
* @see java.util.Optional
|
||||
* @see java.util.function.Function
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.control.ResourceManager
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see org.apache.geode.distributed.DistributedSystem
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class GeodeCacheHealthIndicator extends AbstractGeodeHealthIndicator {
|
||||
|
||||
private final Function<Health.Builder, Health.Builder> gemfireHealthIndicatorFunctions = withCacheDetails()
|
||||
.andThen(withDistributedSystemDetails())
|
||||
.andThen(withDistributedMemberDetails())
|
||||
.andThen(withResourceManagerDetails());
|
||||
|
||||
/**
|
||||
* Default constructor to construct an uninitialized instance of {@link GeodeCacheHealthIndicator},
|
||||
* which will not provide any health information.
|
||||
*/
|
||||
public GeodeCacheHealthIndicator() {
|
||||
super("(Client) Cache health check failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link GeodeCacheHealthIndicator} initialized with a reference to
|
||||
* the {@link GemFireCache} instance.
|
||||
*
|
||||
* @param gemfireCache reference to the {@link GemFireCache} instance used to collect health information.
|
||||
* @throws IllegalArgumentException if {@link GemFireCache} is {@literal null}.
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
*/
|
||||
public GeodeCacheHealthIndicator(GemFireCache gemfireCache) {
|
||||
super(gemfireCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a collection of {@link Function Functions} that apply {@link HealthIndicator} information
|
||||
* about the {@link GemFireCache} to the {@link Health} aggregate object.
|
||||
*
|
||||
* @return a collection of {@link Function Functions} applying {@link HealthIndicator} information
|
||||
* about the {@link GemFireCache} to a {@link Health} object.
|
||||
* @see org.springframework.boot.actuate.health.Health.Builder
|
||||
* @see java.util.function.Function
|
||||
*/
|
||||
protected Function<Health.Builder, Health.Builder> getGemfireHealthIndicatorFunctions() {
|
||||
return this.gemfireHealthIndicatorFunctions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
|
||||
if (getGemFireCache().isPresent()) {
|
||||
|
||||
getGemfireHealthIndicatorFunctions().apply(builder);
|
||||
|
||||
builder.status(getGemFireCache().map(GemFireCache::isClosed).orElse(true)
|
||||
? Status.DOWN : Status.UP);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
builder.unknown();
|
||||
}
|
||||
|
||||
private Function<Health.Builder, Health.Builder> withCacheDetails() {
|
||||
|
||||
return healthBuilder -> healthBuilder.withDetail("geode.cache.name", getGemFireCache().map(GemFireCache::getName).orElse(""))
|
||||
.withDetail("geode.cache.closed", getGemFireCache().map(GemFireCache::isClosed).map(this::toYesNoString).orElse("Yes"))
|
||||
.withDetail("geode.cache.cancel-in-progress", getGemFireCache()
|
||||
.map(GemFireCache::getCancelCriterion)
|
||||
.filter(CancelCriterion::isCancelInProgress)
|
||||
.isPresent() ? "Yes" : "No");
|
||||
}
|
||||
|
||||
private Function<Health.Builder, Health.Builder> withDistributedMemberDetails() {
|
||||
|
||||
return healthBuilder -> getGemFireCache()
|
||||
.map(GemFireCache::getDistributedSystem)
|
||||
.map(DistributedSystem::getDistributedMember)
|
||||
.map(distributedMember -> healthBuilder
|
||||
.withDetail("geode.distributed-member.id", distributedMember.getId())
|
||||
.withDetail("geode.distributed-member.name", distributedMember.getName())
|
||||
.withDetail("geode.distributed-member.groups", distributedMember.getGroups())
|
||||
.withDetail("geode.distributed-member.host", distributedMember.getHost())
|
||||
.withDetail("geode.distributed-member.process-id", distributedMember.getProcessId())
|
||||
)
|
||||
.orElse(healthBuilder);
|
||||
}
|
||||
|
||||
private Function<Health.Builder, Health.Builder> withDistributedSystemDetails() {
|
||||
|
||||
return healthBuilder -> getGemFireCache()
|
||||
.map(GemFireCache::getDistributedSystem)
|
||||
.map(distributedSystem -> healthBuilder
|
||||
.withDetail("geode.distributed-system.member-count", toMemberCount(distributedSystem))
|
||||
.withDetail("geode.distributed-system.connection", toConnectedNoConnectedString(distributedSystem.isConnected()))
|
||||
.withDetail("geode.distributed-system.reconnecting", toYesNoString(distributedSystem.isReconnecting()))
|
||||
.withDetail("geode.distributed-system.properties-location", toString(DistributedSystem.getPropertiesFileURL()))
|
||||
.withDetail("geode.distributed-system.security-properties-location", toString(DistributedSystem.getSecurityPropertiesFileURL()))
|
||||
)
|
||||
.orElse(healthBuilder);
|
||||
}
|
||||
|
||||
private Function<Health.Builder, Health.Builder> withResourceManagerDetails() {
|
||||
|
||||
return healthBuilder -> getGemFireCache()
|
||||
.map(GemFireCache::getResourceManager)
|
||||
.map(resourceManager -> healthBuilder
|
||||
.withDetail("geode.resource-manager.critical-heap-percentage", resourceManager.getCriticalHeapPercentage())
|
||||
.withDetail("geode.resource-manager.critical-off-heap-percentage", resourceManager.getCriticalOffHeapPercentage())
|
||||
.withDetail("geode.resource-manager.eviction-heap-percentage", resourceManager.getEvictionHeapPercentage())
|
||||
.withDetail("geode.resource-manager.eviction-off-heap-percentage", resourceManager.getEvictionOffHeapPercentage())
|
||||
)
|
||||
.orElse(healthBuilder);
|
||||
}
|
||||
|
||||
private String emptyIfUnset(String value) {
|
||||
return StringUtils.hasText(value) ? value : "";
|
||||
}
|
||||
|
||||
private String toConnectedNoConnectedString(Boolean connected) {
|
||||
return Boolean.TRUE.equals(connected) ? "Connected" : "Not Connected";
|
||||
}
|
||||
|
||||
private int toMemberCount(DistributedSystem distributedSystem) {
|
||||
return CollectionUtils.nullSafeSize(distributedSystem.getAllOtherMembers()) + 1;
|
||||
}
|
||||
|
||||
private String toString(URL url) {
|
||||
|
||||
String urlString = url != null ? url.toExternalForm() : null;
|
||||
|
||||
return emptyIfUnset(urlString);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.server.CacheServer;
|
||||
import org.apache.geode.cache.server.ServerLoad;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.data.gemfire.util.CacheUtils;
|
||||
import org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator;
|
||||
import org.springframework.geode.boot.actuate.health.support.ActuatorServerLoadProbeWrapper;
|
||||
|
||||
/**
|
||||
* The {@link GeodeCacheServersHealthIndicator} class is a Spring Boot {@link HealthIndicator} providing details about
|
||||
* the health of Apache Geode {@link CacheServer CacheServers}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.server.CacheServer
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator
|
||||
* @see org.springframework.geode.boot.actuate.health.support.ActuatorServerLoadProbeWrapper
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class GeodeCacheServersHealthIndicator extends AbstractGeodeHealthIndicator {
|
||||
|
||||
/**
|
||||
* Default constructor to construct an uninitialized instance of {@link GeodeCacheServersHealthIndicator},
|
||||
* which will not provide any health information.
|
||||
*/
|
||||
public GeodeCacheServersHealthIndicator() {
|
||||
super("Cache Servers health check failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link GeodeCacheServersHealthIndicator} initialized with a reference to
|
||||
* the {@link GemFireCache} instance.
|
||||
*
|
||||
* @param gemfireCache reference to the {@link GemFireCache} instance used to collect health information.
|
||||
* @throws IllegalArgumentException if {@link GemFireCache} is {@literal null}.
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
*/
|
||||
public GeodeCacheServersHealthIndicator(GemFireCache gemfireCache) {
|
||||
super(gemfireCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
|
||||
if (getGemFireCache().filter(CacheUtils::isPeer).isPresent()) {
|
||||
|
||||
AtomicInteger globalIndex = new AtomicInteger(0);
|
||||
|
||||
List<CacheServer> cacheServers = getGemFireCache()
|
||||
.map(Cache.class::cast)
|
||||
.map(Cache::getCacheServers)
|
||||
.orElseGet(Collections::emptyList);
|
||||
|
||||
builder.withDetail("geode.cache.server.count", cacheServers.size());
|
||||
|
||||
cacheServers.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(cacheServer -> {
|
||||
|
||||
int cacheServerIndex = globalIndex.getAndIncrement();
|
||||
|
||||
builder.withDetail(cacheServerKey(cacheServerIndex, "bind-address"), cacheServer.getBindAddress())
|
||||
.withDetail(cacheServerKey(cacheServerIndex, "hostname-for-clients"), cacheServer.getHostnameForClients())
|
||||
.withDetail(cacheServerKey(cacheServerIndex, "load-poll-interval"), cacheServer.getLoadPollInterval())
|
||||
.withDetail(cacheServerKey(cacheServerIndex, "max-connections"), cacheServer.getMaxConnections())
|
||||
.withDetail(cacheServerKey(cacheServerIndex, "max-message-count"), cacheServer.getMaximumMessageCount())
|
||||
.withDetail(cacheServerKey(cacheServerIndex, "max-threads"), cacheServer.getMaxThreads())
|
||||
.withDetail(cacheServerKey(cacheServerIndex, "max-time-between-pings"), cacheServer.getMaximumTimeBetweenPings())
|
||||
.withDetail(cacheServerKey(cacheServerIndex, "message-time-to-live"), cacheServer.getMessageTimeToLive())
|
||||
.withDetail(cacheServerKey(cacheServerIndex, "port"), cacheServer.getPort())
|
||||
.withDetail(cacheServerKey(cacheServerIndex, "running"), toYesNoString(cacheServer.isRunning()))
|
||||
.withDetail(cacheServerKey(cacheServerIndex, "socket-buffer-size"), cacheServer.getSocketBufferSize())
|
||||
.withDetail(cacheServerKey(cacheServerIndex, "tcp-no-delay"), toYesNoString(cacheServer.getTcpNoDelay()));
|
||||
|
||||
Optional.ofNullable(cacheServer.getLoadProbe())
|
||||
.filter(ActuatorServerLoadProbeWrapper.class::isInstance)
|
||||
.map(ActuatorServerLoadProbeWrapper.class::cast)
|
||||
.flatMap(ActuatorServerLoadProbeWrapper::getCurrentServerMetrics)
|
||||
.ifPresent(serverMetrics -> {
|
||||
|
||||
builder.withDetail(cacheServerMetricsKey(cacheServerIndex, "client-count"), serverMetrics.getClientCount())
|
||||
.withDetail(cacheServerMetricsKey(cacheServerIndex, "max-connection-count"), serverMetrics.getMaxConnections())
|
||||
.withDetail(cacheServerMetricsKey(cacheServerIndex, "open-connection-count"), serverMetrics.getConnectionCount())
|
||||
.withDetail(cacheServerMetricsKey(cacheServerIndex, "subscription-connection-count"), serverMetrics.getSubscriptionConnectionCount());
|
||||
|
||||
ServerLoad serverLoad = cacheServer.getLoadProbe().getLoad(serverMetrics);
|
||||
|
||||
if (serverLoad != null) {
|
||||
|
||||
builder.withDetail(cacheServerLoadKey(cacheServerIndex, "connection-load"), serverLoad.getConnectionLoad())
|
||||
.withDetail(cacheServerLoadKey(cacheServerIndex, "load-per-connection"), serverLoad.getLoadPerConnection())
|
||||
.withDetail(cacheServerLoadKey(cacheServerIndex, "subscription-connection-load"), serverLoad.getSubscriptionConnectionLoad())
|
||||
.withDetail(cacheServerLoadKey(cacheServerIndex, "load-per-subscription-connection"), serverLoad.getLoadPerSubscriptionConnection());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
builder.up();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
builder.unknown();
|
||||
}
|
||||
|
||||
private String cacheServerKey(int index, String suffix) {
|
||||
return String.format("geode.cache.server.%d.%s", index, suffix);
|
||||
}
|
||||
|
||||
private String cacheServerLoadKey(int index, String suffix) {
|
||||
return String.format("geode.cache.server.%d.load.%s", index, suffix);
|
||||
}
|
||||
|
||||
private String cacheServerMetricsKey(int index, String suffix) {
|
||||
return String.format("geode.cache.server.%d.metrics.%s", index, suffix);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.query.CqQuery;
|
||||
import org.apache.geode.cache.query.CqState;
|
||||
import org.apache.geode.cache.query.CqStatistics;
|
||||
import org.apache.geode.cache.query.Query;
|
||||
import org.apache.geode.cache.query.QueryService;
|
||||
import org.apache.geode.cache.query.QueryStatistics;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.data.gemfire.listener.ContinuousQueryListenerContainer;
|
||||
import org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator;
|
||||
|
||||
/**
|
||||
* The {@link GeodeContinuousQueriesHealthIndicator} class is a Spring Boot {@link HealthIndicator} providing details
|
||||
* about the health of the registered Apache Geode {@link CqQuery Continuous Queries}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.query.CqQuery
|
||||
* @see org.apache.geode.cache.query.Query
|
||||
* @see org.apache.geode.cache.query.QueryService
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.data.gemfire.listener.ContinuousQueryListenerContainer
|
||||
* @see org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class GeodeContinuousQueriesHealthIndicator extends AbstractGeodeHealthIndicator {
|
||||
|
||||
private final ContinuousQueryListenerContainer continuousQueryListenerContainer;
|
||||
|
||||
/**
|
||||
* Default constructor to construct an uninitialized instance of {@link GeodeContinuousQueriesHealthIndicator},
|
||||
* which will not provide any health information.
|
||||
*/
|
||||
public GeodeContinuousQueriesHealthIndicator() {
|
||||
super("Continuous Queries health check failed");
|
||||
this.continuousQueryListenerContainer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link GeodeContinuousQueriesHealthIndicator} initialized with a reference to
|
||||
* the {@link ContinuousQueryListenerContainer}.
|
||||
*
|
||||
* @param continuousQueryListenerContainer reference to the SDG {@link ContinuousQueryListenerContainer}.
|
||||
* @see org.springframework.data.gemfire.listener.ContinuousQueryListenerContainer
|
||||
*/
|
||||
public GeodeContinuousQueriesHealthIndicator(ContinuousQueryListenerContainer continuousQueryListenerContainer) {
|
||||
|
||||
super("Continuous Queries health check enabled");
|
||||
|
||||
this.continuousQueryListenerContainer = continuousQueryListenerContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} reference to the configured {@link ContinuousQueryListenerContainer}.
|
||||
*
|
||||
* @return an {@link Optional} reference to the configured {@link ContinuousQueryListenerContainer}.
|
||||
* @see org.springframework.data.gemfire.listener.ContinuousQueryListenerContainer
|
||||
* @see java.util.Optional
|
||||
*/
|
||||
protected Optional<ContinuousQueryListenerContainer> getContinuousQueryListenerContainer() {
|
||||
return Optional.ofNullable(this.continuousQueryListenerContainer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
|
||||
if (getContinuousQueryListenerContainer().isPresent()) {
|
||||
|
||||
Optional<QueryService> queryService = getContinuousQueryListenerContainer()
|
||||
.map(ContinuousQueryListenerContainer::getQueryService);
|
||||
|
||||
List<CqQuery> continuousQueries = queryService
|
||||
.map(QueryService::getCqs)
|
||||
.map(Arrays::asList)
|
||||
.orElseGet(Collections::emptyList);
|
||||
|
||||
builder.withDetail("geode.continuous-query.count", continuousQueries.size());
|
||||
|
||||
queryService
|
||||
.map(QueryService::getCqStatistics)
|
||||
.ifPresent(cqServiceStatistics ->
|
||||
|
||||
builder.withDetail("geode.continuous-query.number-of-active", cqServiceStatistics.numCqsActive())
|
||||
.withDetail("geode.continuous-query.number-of-closed", cqServiceStatistics.numCqsClosed())
|
||||
.withDetail("geode.continuous-query.number-of-created", cqServiceStatistics.numCqsCreated())
|
||||
.withDetail("geode.continuous-query.number-of-stopped", cqServiceStatistics.numCqsStopped())
|
||||
.withDetail("geode.continuous-query.number-on-client", cqServiceStatistics.numCqsOnClient())
|
||||
);
|
||||
|
||||
continuousQueries.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(continuousQuery -> {
|
||||
|
||||
String continuousQueryName = continuousQuery.getName();
|
||||
|
||||
builder.withDetail(continuousQueryKey(continuousQueryName,"oql-query-string"), continuousQuery.getQueryString())
|
||||
.withDetail(continuousQueryKey(continuousQueryName, "closed"), toYesNoString(continuousQuery.isClosed()))
|
||||
.withDetail(continuousQueryKey(continuousQueryName, "closing"), toYesNoString(continuousQuery.getState()))
|
||||
.withDetail(continuousQueryKey(continuousQueryName, "durable"), toYesNoString(continuousQuery.isDurable()))
|
||||
.withDetail(continuousQueryKey(continuousQueryName, "running"), toYesNoString(continuousQuery.isRunning()))
|
||||
.withDetail(continuousQueryKey(continuousQueryName, "stopped"), toYesNoString(continuousQuery.isStopped()));
|
||||
|
||||
Query query = continuousQuery.getQuery();
|
||||
|
||||
if (query != null) {
|
||||
|
||||
QueryStatistics queryStatistics = query.getStatistics();
|
||||
|
||||
if (queryStatistics != null) {
|
||||
builder.withDetail(continuousQueryQueryKey(continuousQueryName, "number-of-executions"), queryStatistics.getNumExecutions())
|
||||
.withDetail(continuousQueryQueryKey(continuousQueryName, "total-execution-time"), queryStatistics.getTotalExecutionTime());
|
||||
}
|
||||
}
|
||||
|
||||
CqStatistics continuousQueryStatistics = continuousQuery.getStatistics();
|
||||
|
||||
if (continuousQueryStatistics != null) {
|
||||
|
||||
builder.withDetail(continuousQueryStatisticsKey(continuousQueryName, "number-of-deletes"), continuousQueryStatistics.numDeletes())
|
||||
.withDetail(continuousQueryStatisticsKey(continuousQueryName, "number-of-events"), continuousQueryStatistics.numEvents())
|
||||
.withDetail(continuousQueryStatisticsKey(continuousQueryName, "number-of-inserts"), continuousQueryStatistics.numInserts())
|
||||
.withDetail(continuousQueryStatisticsKey(continuousQueryName, "number-of-updates"), continuousQueryStatistics.numUpdates());
|
||||
}
|
||||
});
|
||||
|
||||
builder.up();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
builder.unknown();
|
||||
}
|
||||
|
||||
private String continuousQueryKey(String continuousQueryName, String suffix) {
|
||||
return String.format("geode.continuous-query.%1$s.%2$s", continuousQueryName, suffix);
|
||||
}
|
||||
|
||||
private String continuousQueryQueryKey(String continuousQueryName, String suffix) {
|
||||
return String.format("geode.continuous-query.%1$s.query.%2$s", continuousQueryName, suffix);
|
||||
}
|
||||
|
||||
private String continuousQueryStatisticsKey(String continuousQueryName, String suffix) {
|
||||
return String.format("geode.continuous-query.%1$s.statistics.%2$s", continuousQueryName, suffix);
|
||||
}
|
||||
|
||||
private String toYesNoString(CqState continuousQueryState) {
|
||||
return continuousQueryState != null ? toYesNoString(continuousQueryState.isClosing()) : UNKNOWN;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.DiskStore;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.gemfire.util.ArrayUtils;
|
||||
import org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The {@link GeodeDiskStoresHealthIndicator} class is a Spring Boot {@link HealthIndicator} providing details about
|
||||
* the health of Apache Geode {@link DiskStore DiskStores}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.DiskStore
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class GeodeDiskStoresHealthIndicator extends AbstractGeodeHealthIndicator {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
/**
|
||||
* Default constructor to construct an uninitialized instance of {@link GeodeDiskStoresHealthIndicator},
|
||||
* which will not provide any health information.
|
||||
*/
|
||||
public GeodeDiskStoresHealthIndicator() {
|
||||
super("Disk Stores health check failed");
|
||||
this.applicationContext = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link GeodeDiskStoresHealthIndicator} initialized with a reference to
|
||||
* the {@link ApplicationContext} instance.
|
||||
*
|
||||
* @param applicationContext reference to the Spring {@link ApplicationContext}.
|
||||
* @throws IllegalArgumentException if {@link ApplicationContext} is {@literal null}.
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
*/
|
||||
public GeodeDiskStoresHealthIndicator(ApplicationContext applicationContext) {
|
||||
|
||||
super("Disk Stores health check enabled");
|
||||
|
||||
Assert.notNull(applicationContext, "ApplicationContext is required");
|
||||
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} reference to the Spring {@link ApplicationContext}.
|
||||
*
|
||||
* @return an {@link Optional} reference to the Spring {@link ApplicationContext}.
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see java.util.Optional
|
||||
*/
|
||||
protected Optional<ApplicationContext> getApplicationContext() {
|
||||
return Optional.ofNullable(this.applicationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
|
||||
if (getApplicationContext().isPresent()) {
|
||||
|
||||
Map<String, DiskStore> diskStores = getApplicationContext()
|
||||
.map(it -> it.getBeansOfType(DiskStore.class))
|
||||
.orElseGet(Collections::emptyMap);
|
||||
|
||||
builder.withDetail("geode.disk-store.count", diskStores.size());
|
||||
|
||||
diskStores.values().forEach(diskStore -> {
|
||||
|
||||
String diskStoreName = diskStore.getName();
|
||||
|
||||
builder.withDetail(diskStoreKey(diskStoreName, "allow-force-compaction"), toYesNoString(diskStore.getAllowForceCompaction()))
|
||||
.withDetail(diskStoreKey(diskStoreName, "auto-compact"), toYesNoString(diskStore.getAutoCompact()))
|
||||
.withDetail(diskStoreKey(diskStoreName, "compaction-threshold"), diskStore.getCompactionThreshold())
|
||||
.withDetail(diskStoreKey(diskStoreName, "disk-directories"), toFileAbsolutePathStrings(diskStore.getDiskDirs()))
|
||||
.withDetail(diskStoreKey(diskStoreName, "disk-directory-sizes"), Arrays.toString(nullSafeArray(diskStore.getDiskDirSizes())))
|
||||
.withDetail(diskStoreKey(diskStoreName, "disk-usage-critical-percentage"), diskStore.getDiskUsageCriticalPercentage())
|
||||
.withDetail(diskStoreKey(diskStoreName, "disk-usage-warning-percentage"), diskStore.getDiskUsageWarningPercentage())
|
||||
.withDetail(diskStoreKey(diskStoreName, "max-oplog-size"), diskStore.getMaxOplogSize())
|
||||
.withDetail(diskStoreKey(diskStoreName, "queue-size"), diskStore.getQueueSize())
|
||||
.withDetail(diskStoreKey(diskStoreName, "time-interval"), diskStore.getTimeInterval())
|
||||
.withDetail(diskStoreKey(diskStoreName, "uuid"), diskStore.getDiskStoreUUID().toString())
|
||||
.withDetail(diskStoreKey(diskStoreName, "write-buffer-size"), diskStore.getWriteBufferSize());
|
||||
});
|
||||
|
||||
builder.up();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
builder.unknown();
|
||||
}
|
||||
|
||||
private String diskStoreKey(String diskStoreName, String suffix) {
|
||||
return String.format("geode.disk-store.%1$s.%2$s", diskStoreName, suffix);
|
||||
}
|
||||
|
||||
private int[] nullSafeArray(int[] array) {
|
||||
return array != null ? array : new int[0];
|
||||
}
|
||||
|
||||
private String toFileAbsolutePathStrings(File... files) {
|
||||
|
||||
return Arrays.toString(Arrays.stream(ArrayUtils.nullSafeArray(files, File.class))
|
||||
.filter(Objects::nonNull)
|
||||
.map(File::getAbsolutePath)
|
||||
.distinct()
|
||||
.toArray());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.wan.GatewayReceiver;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.data.gemfire.util.CacheUtils;
|
||||
import org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator;
|
||||
|
||||
/**
|
||||
* The {@link GeodeGatewayReceiversHealthIndicator} class is a Spring Boot {@link HealthIndicator} providing details
|
||||
* about the health of Apache Geode {@link GatewayReceiver GatewayReceivers}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.wan.GatewayReceiver
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class GeodeGatewayReceiversHealthIndicator extends AbstractGeodeHealthIndicator {
|
||||
|
||||
/**
|
||||
* Default constructor to construct an uninitialized instance of {@link GeodeGatewayReceiversHealthIndicator},
|
||||
* which will not provide any health information.
|
||||
*/
|
||||
public GeodeGatewayReceiversHealthIndicator() {
|
||||
super("Gateway Receivers health check failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link GeodeGatewayReceiversHealthIndicator} initialized with a reference to
|
||||
* the {@link GemFireCache} instance.
|
||||
*
|
||||
* @param gemfireCache reference to the {@link GemFireCache} instance used to collect health information.
|
||||
* @throws IllegalArgumentException if {@link GemFireCache} is {@literal null}.
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
*/
|
||||
public GeodeGatewayReceiversHealthIndicator(GemFireCache gemfireCache) {
|
||||
super(gemfireCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
|
||||
if (getGemFireCache().filter(CacheUtils::isPeer).isPresent()) {
|
||||
|
||||
AtomicInteger globalIndex = new AtomicInteger(0);
|
||||
|
||||
Set<GatewayReceiver> gatewayReceivers = getGemFireCache()
|
||||
.map(Cache.class::cast)
|
||||
.map(Cache::getGatewayReceivers)
|
||||
.orElseGet(Collections::emptySet);
|
||||
|
||||
builder.withDetail("geode.gateway-receiver.count", gatewayReceivers.size());
|
||||
|
||||
gatewayReceivers.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(gatewayReceiver -> {
|
||||
|
||||
int index = globalIndex.getAndIncrement();
|
||||
|
||||
builder.withDetail(gatewayReceiverKey(index, "bind-address"), gatewayReceiver.getBindAddress())
|
||||
.withDetail(gatewayReceiverKey(index, "end-port"), gatewayReceiver.getEndPort())
|
||||
.withDetail(gatewayReceiverKey(index, "host"), gatewayReceiver.getHost())
|
||||
.withDetail(gatewayReceiverKey(index, "max-time-between-pings"), gatewayReceiver.getMaximumTimeBetweenPings())
|
||||
.withDetail(gatewayReceiverKey(index, "port"), gatewayReceiver.getPort())
|
||||
.withDetail(gatewayReceiverKey(index, "running"), toYesNoString(gatewayReceiver.isRunning()))
|
||||
.withDetail(gatewayReceiverKey(index, "socket-buffer-size"), gatewayReceiver.getSocketBufferSize())
|
||||
.withDetail(gatewayReceiverKey(index, "start-port"), gatewayReceiver.getStartPort());
|
||||
});
|
||||
|
||||
builder.up();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
builder.unknown();
|
||||
}
|
||||
|
||||
private String gatewayReceiverKey(int index, String suffix) {
|
||||
return String.format("geode.gateway-receiver.%d.%s", index, suffix);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.wan.GatewaySender;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.data.gemfire.util.CacheUtils;
|
||||
import org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The {@link GeodeGatewaySendersHealthIndicator} class is a Spring Boot {@link HealthIndicator} providing details about
|
||||
* the health of Apache Geode {@link GatewaySender GatewaySenders}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.wan.GatewaySender
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class GeodeGatewaySendersHealthIndicator extends AbstractGeodeHealthIndicator {
|
||||
|
||||
/**
|
||||
* Default constructor to construct an uninitialized instance of {@link GeodeGatewaySendersHealthIndicator},
|
||||
* which will not provide any health information.
|
||||
*/
|
||||
public GeodeGatewaySendersHealthIndicator() {
|
||||
super("Gateway Senders health check failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link GeodeGatewaySendersHealthIndicator} initialized with a reference to
|
||||
* the {@link GemFireCache} instance.
|
||||
*
|
||||
* @param gemfireCache reference to the {@link GemFireCache} instance used to collect health information.
|
||||
* @throws IllegalArgumentException if {@link GemFireCache} is {@literal null}.
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
*/
|
||||
public GeodeGatewaySendersHealthIndicator(GemFireCache gemfireCache) {
|
||||
super(gemfireCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
|
||||
if (getGemFireCache().filter(CacheUtils::isPeer).isPresent()) {
|
||||
|
||||
Set<GatewaySender> gatewaySenders = getGemFireCache()
|
||||
.map(Cache.class::cast)
|
||||
.map(Cache::getGatewaySenders)
|
||||
.orElseGet(Collections::emptySet);
|
||||
|
||||
builder.withDetail("geode.gateway-sender.count", gatewaySenders.size());
|
||||
|
||||
gatewaySenders.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(gatewaySender -> {
|
||||
|
||||
String gatewaySenderId = gatewaySender.getId();
|
||||
|
||||
builder.withDetail(gatewaySendersKey(gatewaySenderId, "alert-threshold"), gatewaySender.getAlertThreshold())
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "batch-conflation-enabled"), toYesNoString(gatewaySender.isBatchConflationEnabled()))
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "batch-size"), gatewaySender.getBatchSize())
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "batch-time-interval"), gatewaySender.getBatchTimeInterval())
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "disk-store-name"), emptyIfUnset(gatewaySender.getDiskStoreName()))
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "disk-synchronous"), toYesNoString(gatewaySender.isDiskSynchronous()))
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "dispatcher-threads"), gatewaySender.getDispatcherThreads())
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "max-queue-memory"), gatewaySender.getMaximumQueueMemory())
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "max-parallelism-for-replicated-region"), gatewaySender.getMaxParallelismForReplicatedRegion())
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "order-policy"), gatewaySender.getOrderPolicy())
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "parallel"), toYesNoString(gatewaySender.isParallel()))
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "paused"), toYesNoString(gatewaySender.isPaused()))
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "persistent"), toYesNoString(gatewaySender.isPersistenceEnabled()))
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "remote-distributed-system-id"), gatewaySender.getRemoteDSId())
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "running"), toYesNoString(gatewaySender.isRunning()))
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "socket-buffer-size"), gatewaySender.getSocketBufferSize())
|
||||
.withDetail(gatewaySendersKey(gatewaySenderId, "socket-read-timeout"), gatewaySender.getSocketReadTimeout());
|
||||
});
|
||||
|
||||
builder.up();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
builder.unknown();
|
||||
}
|
||||
|
||||
private String emptyIfUnset(String value) {
|
||||
return StringUtils.hasText(value) ? value : "";
|
||||
}
|
||||
|
||||
private String gatewaySendersKey(String id, String suffix) {
|
||||
return String.format("geode.gateway-sender.%1$s.%2$s", id, suffix);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.apache.geode.cache.query.IndexStatistics;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The {@link GeodeIndexesHealthIndicator} class is a Spring Boot {@link HealthIndicator} providing details about
|
||||
* the health of Apache Geode {@link Region} OQL {@link Index Indexes}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class GeodeIndexesHealthIndicator extends AbstractGeodeHealthIndicator {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
/**
|
||||
* Default constructor to construct an uninitialized instance of {@link GeodeIndexesHealthIndicator},
|
||||
* which will not provide any health information.
|
||||
*/
|
||||
public GeodeIndexesHealthIndicator() {
|
||||
super("Indexes health check failed");
|
||||
this.applicationContext = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link GeodeIndexesHealthIndicator} initialized with a reference to
|
||||
* the {@link ApplicationContext} instance.
|
||||
*
|
||||
* @param applicationContext reference to the Spring {@link ApplicationContext}.
|
||||
* @throws IllegalArgumentException if {@link ApplicationContext} is {@literal null}.
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
*/
|
||||
public GeodeIndexesHealthIndicator(ApplicationContext applicationContext) {
|
||||
|
||||
super("Indexes health check enabled");
|
||||
|
||||
Assert.notNull(applicationContext, "ApplicationContext is required");
|
||||
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} reference to the Spring {@link ApplicationContext}.
|
||||
*
|
||||
* @return an {@link Optional} reference to the Spring {@link ApplicationContext}.
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see java.util.Optional
|
||||
*/
|
||||
protected Optional<ApplicationContext> getApplicationContext() {
|
||||
return Optional.ofNullable(this.applicationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
|
||||
if (getApplicationContext().isPresent()) {
|
||||
|
||||
Map<String, Index> indexes = getApplicationContext()
|
||||
.map(it -> it.getBeansOfType(Index.class))
|
||||
.orElseGet(Collections::emptyMap);
|
||||
|
||||
builder.withDetail("geode.index.count", indexes.size());
|
||||
|
||||
indexes.values().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(index -> {
|
||||
|
||||
String indexName = index.getName();
|
||||
|
||||
builder.withDetail(indexKey(indexName, "from-clause"), index.getFromClause())
|
||||
.withDetail(indexKey(indexName, "indexed-expression"), index.getIndexedExpression())
|
||||
.withDetail(indexKey(indexName, "projection-attributes"), index.getProjectionAttributes())
|
||||
.withDetail(indexKey(indexName, "region"), toRegionPath(index.getRegion()))
|
||||
.withDetail(indexKey(indexName, "type"), String.valueOf(index.getType()));
|
||||
|
||||
IndexStatistics indexStatistics = index.getStatistics();
|
||||
|
||||
if (indexStatistics != null) {
|
||||
|
||||
builder.withDetail(indexStatisticsKey(indexName, "number-of-bucket-indexes"), indexStatistics.getNumberOfBucketIndexes())
|
||||
.withDetail(indexStatisticsKey(indexName, "number-of-keys"), indexStatistics.getNumberOfKeys())
|
||||
.withDetail(indexStatisticsKey(indexName, "number-of-map-index-keys"), indexStatistics.getNumberOfMapIndexKeys())
|
||||
.withDetail(indexStatisticsKey(indexName, "number-of-values"), indexStatistics.getNumberOfValues())
|
||||
.withDetail(indexStatisticsKey(indexName, "number-of-updates"), indexStatistics.getNumUpdates())
|
||||
.withDetail(indexStatisticsKey(indexName, "read-lock-count"), indexStatistics.getReadLockCount())
|
||||
.withDetail(indexStatisticsKey(indexName, "total-update-time"), indexStatistics.getTotalUpdateTime())
|
||||
.withDetail(indexStatisticsKey(indexName, "total-uses"), indexStatistics.getTotalUses());
|
||||
}
|
||||
});
|
||||
|
||||
builder.up();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
builder.unknown();
|
||||
}
|
||||
|
||||
private String emptyIfUnset(String value) {
|
||||
return StringUtils.hasText(value) ? value : "";
|
||||
}
|
||||
|
||||
private String indexKey(String indexName, String suffix) {
|
||||
return String.format("geode.index.%1$s.%2$s", indexName, suffix);
|
||||
}
|
||||
|
||||
private String indexStatisticsKey(String indexName, String suffix) {
|
||||
return String.format("geode.index.%1$s.statistics.%2$s", indexName, suffix);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private String toRegionPath(Region region) {
|
||||
|
||||
String regionPath = region != null ? region.getFullPath() : null;
|
||||
|
||||
return emptyIfUnset(regionPath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeList;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeMap;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.client.Pool;
|
||||
import org.apache.geode.cache.client.PoolManager;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.data.gemfire.util.CacheUtils;
|
||||
import org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The {@link GeodePoolsHealthIndicator} class is a Spring Boot {@link HealthIndicator} providing details about
|
||||
* the health of the configured Apache Geode client {@link Pool Pools}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
* @see org.apache.geode.cache.client.PoolManager
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class GeodePoolsHealthIndicator extends AbstractGeodeHealthIndicator {
|
||||
|
||||
/**
|
||||
* Default constructor to construct an uninitialized instance of {@link GeodePoolsHealthIndicator},
|
||||
* which will not provide any health information.
|
||||
*/
|
||||
public GeodePoolsHealthIndicator() {
|
||||
super("Pools health check failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link GeodePoolsHealthIndicator} initialized with a reference to
|
||||
* the {@link GemFireCache} instance.
|
||||
*
|
||||
* @param gemfireCache reference to the {@link GemFireCache} instance used to collect health information.
|
||||
* @throws IllegalArgumentException if {@link GemFireCache} is {@literal null}.
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
*/
|
||||
public GeodePoolsHealthIndicator(GemFireCache gemfireCache) {
|
||||
super(gemfireCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
|
||||
if (getGemFireCache().filter(CacheUtils::isClient).isPresent()) {
|
||||
|
||||
Map<String, Pool> pools = nullSafeMap(findAllPools());
|
||||
|
||||
builder.withDetail("geode.pool.count", pools.size());
|
||||
|
||||
pools.values().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(pool -> {
|
||||
|
||||
String poolName = pool.getName();
|
||||
|
||||
builder.withDetail(poolKey(poolName, "destroyed"), toYesNoString(pool.isDestroyed()))
|
||||
.withDetail(poolKey(poolName, "free-connection-timeout"), pool.getFreeConnectionTimeout())
|
||||
.withDetail(poolKey(poolName, "idle-timeout"), pool.getIdleTimeout())
|
||||
.withDetail(poolKey(poolName, "load-conditioning-interval"), pool.getLoadConditioningInterval())
|
||||
.withDetail(poolKey(poolName, "locators"), toCommaDelimitedHostAndPortsString(pool.getLocators()))
|
||||
.withDetail(poolKey(poolName, "max-connections"), pool.getMaxConnections())
|
||||
.withDetail(poolKey(poolName, "min-connections"), pool.getMinConnections())
|
||||
.withDetail(poolKey(poolName, "multi-user-authentication"), toYesNoString(pool.getMultiuserAuthentication()))
|
||||
.withDetail(poolKey(poolName, "online-locators"), toCommaDelimitedHostAndPortsString(pool.getOnlineLocators()))
|
||||
.withDetail(poolKey(poolName, "ping-interval"), pool.getPingInterval())
|
||||
.withDetail(poolKey(poolName, "pr-single-hop-enabled"), toYesNoString(pool.getPRSingleHopEnabled()))
|
||||
.withDetail(poolKey(poolName, "read-timeout"), pool.getReadTimeout())
|
||||
.withDetail(poolKey(poolName, "retry-attempts"), pool.getRetryAttempts())
|
||||
.withDetail(poolKey(poolName, "server-group"), pool.getServerGroup())
|
||||
.withDetail(poolKey(poolName, "servers"), toCommaDelimitedHostAndPortsString(pool.getServers()))
|
||||
.withDetail(poolKey(poolName, "socket-buffer-size"), pool.getSocketBufferSize())
|
||||
.withDetail(poolKey(poolName, "statistic-interval"), pool.getStatisticInterval())
|
||||
.withDetail(poolKey(poolName, "subscription-ack-interval"), pool.getSubscriptionAckInterval())
|
||||
.withDetail(poolKey(poolName, "subscription-enabled"), toYesNoString(pool.getSubscriptionEnabled()))
|
||||
.withDetail(poolKey(poolName, "subscription-message-tracking-timeout"), pool.getSubscriptionMessageTrackingTimeout())
|
||||
.withDetail(poolKey(poolName, "subscription-redundancy"), pool.getSubscriptionRedundancy());
|
||||
//.withDetail(poolKey(poolName, "thread-local-connections"), toYesNoString(pool.getThreadLocalConnections()));
|
||||
|
||||
getGemFireCache()
|
||||
.map(ClientCache.class::cast)
|
||||
.filter(CacheUtils::isDurable)
|
||||
.ifPresent(it -> builder.withDetail(poolKey(poolName, "pending-event-count"), pool.getPendingEventCount()));
|
||||
});
|
||||
|
||||
builder.up();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
builder.unknown();
|
||||
}
|
||||
|
||||
Map<String, Pool> findAllPools() {
|
||||
return PoolManager.getAll();
|
||||
}
|
||||
|
||||
private String poolKey(String poolName, String suffix) {
|
||||
return String.format("geode.pool.%1$s.%2$s", poolName, suffix);
|
||||
}
|
||||
|
||||
private String toCommaDelimitedHostAndPortsString(List<InetSocketAddress> socketAddresses) {
|
||||
|
||||
return StringUtils.collectionToCommaDelimitedString(nullSafeList(socketAddresses).stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(socketAddress -> String.format("%1$s:%2$d", socketAddress.getHostName(), socketAddress.getPort()))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.EvictionAlgorithm;
|
||||
import org.apache.geode.cache.EvictionAttributes;
|
||||
import org.apache.geode.cache.ExpirationAttributes;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.PartitionAttributes;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionAttributes;
|
||||
import org.apache.geode.internal.cache.LocalDataSet;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator;
|
||||
import org.springframework.geode.boot.actuate.health.support.RegionStatisticsResolver;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The {@link GeodeRegionsHealthIndicator} class is a Spring Boot {@link HealthIndicator} providing details about
|
||||
* the health of the {@link GemFireCache} {@link Region Regions}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.geode.boot.actuate.health.AbstractGeodeHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class GeodeRegionsHealthIndicator extends AbstractGeodeHealthIndicator {
|
||||
|
||||
private final BiConsumer<Region<?, ?>, Health.Builder> gemfireRegionHealthIndicatorConsumers = withRegionDetails()
|
||||
.andThen(withPartitionRegionDetails())
|
||||
.andThen(withRegionEvictionPolicyDetails())
|
||||
.andThen(withRegionExpirationPolicyDetails())
|
||||
.andThen(withRegionStatisticsDetails());
|
||||
|
||||
/**
|
||||
* Default constructor to construct an uninitialized instance of {@link GeodeRegionsHealthIndicator},
|
||||
* which will not provide any health information.
|
||||
*/
|
||||
public GeodeRegionsHealthIndicator() {
|
||||
super("Regions health check failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link GeodeRegionsHealthIndicator} initialized with a reference to
|
||||
* the {@link GemFireCache} instance.
|
||||
*
|
||||
* @param gemfireCache reference to the {@link GemFireCache} instance used to collect health information.
|
||||
* @throws IllegalArgumentException if {@link GemFireCache} is {@literal null}.
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
*/
|
||||
public GeodeRegionsHealthIndicator(GemFireCache gemfireCache) {
|
||||
super(gemfireCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection of {@link BiConsumer} objects that applies health details about the {@link GemFireCache}
|
||||
* {@link Region Regions} to the {@link Health} object.
|
||||
*
|
||||
* @return the collection of {@link BiConsumer} objects that applies health details about the {@link GemFireCache}
|
||||
* {@link Region Regions} to the {@link Health} object.
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see java.util.function.BiConsumer
|
||||
*/
|
||||
protected BiConsumer<Region<?, ?>, Health.Builder> getGemfireRegionHealthIndicatorConsumers() {
|
||||
return this.gemfireRegionHealthIndicatorConsumers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
|
||||
if (getGemFireCache().isPresent()) {
|
||||
|
||||
Set<Region<?, ?>> rootRegions = getGemFireCache()
|
||||
.map(GemFireCache::rootRegions)
|
||||
.orElseGet(Collections::emptySet);
|
||||
|
||||
builder.withDetail("geode.cache.regions", rootRegions.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(Region::getFullPath)
|
||||
.sorted()
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
builder.withDetail("geode.cache.regions.count", rootRegions.stream().filter(Objects::nonNull).count());
|
||||
|
||||
rootRegions.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(region -> getGemfireRegionHealthIndicatorConsumers().accept(region, builder));
|
||||
|
||||
builder.up();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
builder.unknown();
|
||||
}
|
||||
|
||||
private BiConsumer<Region<?, ?>, Health.Builder> withRegionDetails() {
|
||||
|
||||
return (region, builder) -> {
|
||||
|
||||
String regionName = region.getName();
|
||||
|
||||
builder.withDetail(cacheRegionKey(regionName, "full-path"), region.getFullPath());
|
||||
|
||||
if (isRegionAttributesPresent(region)) {
|
||||
|
||||
RegionAttributes<?, ?> regionAttributes = region.getAttributes();
|
||||
|
||||
builder.withDetail(cacheRegionKey(regionName, "cloning-enabled"), toYesNoString(regionAttributes.getCloningEnabled()))
|
||||
.withDetail(cacheRegionKey(regionName, "data-policy"), String.valueOf(regionAttributes.getDataPolicy()))
|
||||
.withDetail(cacheRegionKey(regionName, "initial-capacity"), regionAttributes.getInitialCapacity())
|
||||
.withDetail(cacheRegionKey(regionName, "load-factor"), regionAttributes.getLoadFactor())
|
||||
.withDetail(cacheRegionKey(regionName, "key-constraint"), nullSafeClassName(regionAttributes.getKeyConstraint()))
|
||||
.withDetail(cacheRegionKey(regionName, "off-heap"), toYesNoString(regionAttributes.getOffHeap()))
|
||||
.withDetail(cacheRegionKey(regionName, "pool-name"), emptyIfUnset(regionAttributes.getPoolName()))
|
||||
.withDetail(cacheRegionKey(regionName, "scope"), String.valueOf(regionAttributes.getScope()))
|
||||
.withDetail(cacheRegionKey(regionName, "statistics-enabled"), toYesNoString(regionAttributes.getStatisticsEnabled()))
|
||||
.withDetail(cacheRegionKey(regionName, "value-constraint"), nullSafeClassName(regionAttributes.getValueConstraint())); }
|
||||
};
|
||||
}
|
||||
|
||||
private BiConsumer<Region<?, ?>, Health.Builder> withPartitionRegionDetails() {
|
||||
|
||||
return (region, builder) -> {
|
||||
|
||||
if (isRegionAttributesPresent(region)) {
|
||||
|
||||
PartitionAttributes<?, ?> partitionAttributes = region.getAttributes().getPartitionAttributes();
|
||||
|
||||
if (partitionAttributes != null) {
|
||||
|
||||
String regionName = region.getName();
|
||||
|
||||
builder.withDetail(cachePartitionRegionKey(regionName, "collocated-with"), emptyIfUnset(partitionAttributes.getColocatedWith()))
|
||||
.withDetail(cachePartitionRegionKey(regionName, "local-max-memory"), partitionAttributes.getLocalMaxMemory())
|
||||
.withDetail(cachePartitionRegionKey(regionName, "redundant-copies"), partitionAttributes.getRedundantCopies())
|
||||
//.withDetail(cachePartitionRegionKey(regionName, "total-max-memory"), partitionAttributes.getTotalMaxMemory())
|
||||
.withDetail(cachePartitionRegionKey(regionName, "total-number-of-buckets"), partitionAttributes.getTotalNumBuckets());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private BiConsumer<Region<?, ?>, Health.Builder> withRegionEvictionPolicyDetails() {
|
||||
|
||||
return (region, builder) -> {
|
||||
|
||||
if (isRegionAttributesPresent(region)) {
|
||||
|
||||
EvictionAttributes evictionAttributes = region.getAttributes().getEvictionAttributes();
|
||||
|
||||
if (evictionAttributes != null) {
|
||||
|
||||
String regionName = region.getName();
|
||||
|
||||
builder.withDetail(cacheRegionEvictionKey(regionName, "action"), String.valueOf(evictionAttributes.getAction()))
|
||||
.withDetail(cacheRegionEvictionKey(regionName, "algorithm"), String.valueOf(evictionAttributes.getAlgorithm()));
|
||||
|
||||
EvictionAlgorithm evictionAlgorithm = evictionAttributes.getAlgorithm();
|
||||
|
||||
// NOTE: Eviction Maximum does not apply when Eviction Algorithm is Heap LRU.
|
||||
if (evictionAlgorithm != null && !evictionAlgorithm.isLRUHeap()) {
|
||||
builder.withDetail(cacheRegionEvictionKey(regionName,"maximum"),
|
||||
evictionAttributes.getMaximum());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private BiConsumer<Region<?, ?>, Health.Builder> withRegionExpirationPolicyDetails() {
|
||||
|
||||
return (region, builder) -> {
|
||||
|
||||
if (isRegionAttributesPresent(region)) {
|
||||
|
||||
String regionName = region.getName();
|
||||
|
||||
RegionAttributes<?, ?> regionAttributes = region.getAttributes();
|
||||
|
||||
ExpirationAttributes entryTimeToLive = regionAttributes.getEntryTimeToLive();
|
||||
|
||||
if (entryTimeToLive != null) {
|
||||
builder.withDetail(cacheRegionExpirationKey(regionName, "entry.ttl.action"), String.valueOf(entryTimeToLive.getAction()))
|
||||
.withDetail(cacheRegionExpirationKey(regionName, "entry.ttl.timeout"), entryTimeToLive.getTimeout());
|
||||
}
|
||||
|
||||
ExpirationAttributes entryIdleTimeout = regionAttributes.getEntryIdleTimeout();
|
||||
|
||||
if (entryIdleTimeout != null) {
|
||||
builder.withDetail(cacheRegionExpirationKey(regionName, "entry.tti.action"), String.valueOf(entryIdleTimeout.getAction()))
|
||||
.withDetail(cacheRegionExpirationKey(regionName, "entry.tti.timeout"), entryIdleTimeout.getTimeout());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private BiConsumer<Region<?, ?>, Health.Builder> withRegionStatisticsDetails() {
|
||||
|
||||
return (region, builder) -> {
|
||||
|
||||
String regionName = region.getName();
|
||||
|
||||
Optional.of(region)
|
||||
.filter(this::isNotLocalDataSet)
|
||||
.filter(this::isStatisticsEnabled)
|
||||
.map(RegionStatisticsResolver::resolve)
|
||||
.ifPresent(cacheStatistics -> builder
|
||||
.withDetail(cacheRegionStatisticsKey(regionName, "cache-statistics-type"), nullSafeClassName(cacheStatistics.getClass()))
|
||||
.withDetail(cacheRegionStatisticsKey(regionName, "hit-count"), cacheStatistics.getHitCount())
|
||||
.withDetail(cacheRegionStatisticsKey(regionName, "hit-ratio"), cacheStatistics.getHitRatio())
|
||||
.withDetail(cacheRegionStatisticsKey(regionName, "last-accessed-time"), cacheStatistics.getLastAccessedTime())
|
||||
.withDetail(cacheRegionStatisticsKey(regionName, "last-modified-time"), cacheStatistics.getLastModifiedTime())
|
||||
.withDetail(cacheRegionStatisticsKey(regionName, "miss-count"), cacheStatistics.getMissCount()));
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isLocalDataSet(Region<?, ?> region) {
|
||||
return region instanceof LocalDataSet;
|
||||
}
|
||||
|
||||
private boolean isNotLocalDataSet(Region<?, ?> region) {
|
||||
return !isLocalDataSet(region);
|
||||
}
|
||||
|
||||
private boolean isRegionAttributesPresent(Region<?, ?> region) {
|
||||
return region != null && region.getAttributes() != null;
|
||||
}
|
||||
|
||||
private boolean isStatisticsEnabled(Region<?, ?> region) {
|
||||
return isRegionAttributesPresent(region) && region.getAttributes().getStatisticsEnabled();
|
||||
}
|
||||
|
||||
private String cachePartitionRegionKey(String regionName, String suffix) {
|
||||
return cacheRegionKey(regionName, String.format("partition.%s", suffix));
|
||||
}
|
||||
|
||||
private String cacheRegionKey(String regionName, String suffix) {
|
||||
return String.format("geode.cache.regions.%1$s.%2$s", regionName, suffix);
|
||||
}
|
||||
|
||||
private String cacheRegionEvictionKey(String regionName, String suffix) {
|
||||
return cacheRegionKey(regionName, String.format("eviction.%s", suffix));
|
||||
}
|
||||
|
||||
private String cacheRegionExpirationKey(String regionName, String suffix) {
|
||||
return cacheRegionKey(regionName, String.format("expiration.%s", suffix));
|
||||
}
|
||||
|
||||
private String cacheRegionStatisticsKey(String regionName, String suffix) {
|
||||
return cacheRegionKey(regionName, String.format("statistics.%s", suffix));
|
||||
}
|
||||
|
||||
private String emptyIfUnset(String value) {
|
||||
return StringUtils.hasText(value) ? value : "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate.health;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The {@link AbstractGeodeHealthIndicator} class is an abstract base class encapsulating functionality common to all
|
||||
* Apache Geode {@link HealthIndicator} objects.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.springframework.boot.actuate.health.AbstractHealthIndicator
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class AbstractGeodeHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
protected static final String UNKNOWN = "unknown";
|
||||
|
||||
private final GemFireCache gemfireCache;
|
||||
|
||||
/**
|
||||
* Default constructor to construct an uninitialized instance of {@link AbstractGeodeHealthIndicator},
|
||||
* which will not provide any health information.
|
||||
*/
|
||||
public AbstractGeodeHealthIndicator(String healthCheckedFailedMessage) {
|
||||
super(healthCheckedFailedMessage);
|
||||
this.gemfireCache = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link AbstractGeodeHealthIndicator} initialized with a reference to
|
||||
* the {@link GemFireCache} instance.
|
||||
*
|
||||
* @param gemfireCache reference to the {@link GemFireCache} instance used to collect health information.
|
||||
* @throws IllegalArgumentException if {@link GemFireCache} is {@literal null}.
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
*/
|
||||
public AbstractGeodeHealthIndicator(GemFireCache gemfireCache) {
|
||||
|
||||
Assert.notNull(gemfireCache, "GemFireCache must not be null");
|
||||
|
||||
this.gemfireCache = gemfireCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the {@link GemFireCache} instance.
|
||||
*
|
||||
* @return a reference to the {@link GemFireCache} instance.
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
*/
|
||||
protected Optional<GemFireCache> getGemFireCache() {
|
||||
return Optional.ofNullable(this.gemfireCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the {@link String name} of the {@link Class} type safely by handling {@literal null}.
|
||||
*
|
||||
* @param type {@link Class} type to evaluate.
|
||||
* @return the {@link String name} of the {@link Class} type.
|
||||
* @see java.lang.Class#getName()
|
||||
*/
|
||||
protected String nullSafeClassName(Class<?> type) {
|
||||
return type != null ? type.getName() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link Boolean} value into a {@literal yes} / {@literal no} {@link String}.
|
||||
*
|
||||
* @param value {@link Boolean} value to convert.
|
||||
* @return a {@literal yes} / {@literal no} response for the given {@link Boolean} value.
|
||||
*/
|
||||
protected String toYesNoString(Boolean value) {
|
||||
return Boolean.TRUE.equals(value) ? "Yes" : "No";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate.health.support;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.geode.cache.server.ServerLoad;
|
||||
import org.apache.geode.cache.server.ServerLoadProbe;
|
||||
import org.apache.geode.cache.server.ServerMetrics;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The ActuatorServerLoadProbeWrapper class is an implementation of Apache Geode's {@link ServerLoadProbe} interface
|
||||
* used to capture the current {@link ServerMetrics} and access the latest {@link ServerLoad} details.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.server.ServerLoad
|
||||
* @see org.apache.geode.cache.server.ServerLoadProbe
|
||||
* @see org.apache.geode.cache.server.ServerMetrics
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ActuatorServerLoadProbeWrapper implements ServerLoadProbe {
|
||||
|
||||
private AtomicReference<ServerMetrics> currentServerMetrics = new AtomicReference<>(null);
|
||||
|
||||
private final ServerLoadProbe delegate;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link ActuatorServerLoadProbeWrapper} initialized with the required
|
||||
* {@link ServerLoadProbe} used as the delegate.
|
||||
*
|
||||
* @param serverLoadProbe required {@link ServerLoadProbe}.
|
||||
* @throws IllegalArgumentException if {@link ServerLoadProbe} is {@literal null}.
|
||||
* @see org.apache.geode.cache.server.ServerLoadProbe
|
||||
*/
|
||||
public ActuatorServerLoadProbeWrapper(ServerLoadProbe serverLoadProbe) {
|
||||
|
||||
Assert.notNull(serverLoadProbe, "ServerLoaderProbe is required");
|
||||
|
||||
this.delegate = serverLoadProbe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current, most up-to-date details on the {@link ServerLoad} if possible.
|
||||
*
|
||||
* @return the current {@link ServerLoad}.
|
||||
* @see org.apache.geode.cache.server.ServerLoad
|
||||
* @see #getCurrentServerMetrics()
|
||||
* @see java.util.Optional
|
||||
*/
|
||||
public Optional<ServerLoad> getCurrentServerLoad() {
|
||||
return getCurrentServerMetrics().map(getDelegate()::getLoad);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current, provided {@link ServerMetrics} if available.
|
||||
*
|
||||
* @return the current, provided {@link ServerMetrics} if available.
|
||||
*/
|
||||
public Optional<ServerMetrics> getCurrentServerMetrics() {
|
||||
return Optional.ofNullable(this.currentServerMetrics.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying, wrapped {@link ServerLoadProbe} backing this instance.
|
||||
*
|
||||
* @return the underlying, wrapped {@link ServerLoadProbe}.
|
||||
* @see org.apache.geode.cache.server.ServerLoadProbe
|
||||
*/
|
||||
protected ServerLoadProbe getDelegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerLoad getLoad(ServerMetrics metrics) {
|
||||
|
||||
this.currentServerMetrics.set(metrics);
|
||||
|
||||
return getDelegate().getLoad(metrics);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
getDelegate().open();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
getDelegate().close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate.health.support;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.geode.cache.CacheStatistics;
|
||||
import org.apache.geode.cache.DataPolicy;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.StatisticsDisabledException;
|
||||
import org.apache.geode.cache.partition.PartitionRegionHelper;
|
||||
import org.apache.geode.internal.cache.BucketRegion;
|
||||
import org.apache.geode.internal.cache.PartitionedRegion;
|
||||
import org.apache.geode.internal.cache.PartitionedRegionDataStore;
|
||||
|
||||
import org.springframework.data.gemfire.util.RegionUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The {@link RegionStatisticsResolver} class is a utility class for resolving the {@link CacheStatistics}
|
||||
* for a {@link Region}, regardless of {@link Region} type, or more specifically {@link Region Region's}
|
||||
* {@link DataPolicy data management policy}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.CacheStatistics
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.partition.PartitionRegionHelper
|
||||
* @see org.apache.geode.internal.cache.BucketRegion
|
||||
* @see org.apache.geode.internal.cache.PartitionedRegion
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class RegionStatisticsResolver {
|
||||
|
||||
public static CacheStatistics resolve(Region<?, ?> region) {
|
||||
|
||||
return region != null
|
||||
? PartitionRegionHelper.isPartitionedRegion(region)
|
||||
? new PartitionRegionCacheStatistics(region)
|
||||
: region.getStatistics()
|
||||
: null;
|
||||
}
|
||||
|
||||
protected static class PartitionRegionCacheStatistics implements CacheStatistics {
|
||||
|
||||
private final PartitionedRegion partitionRegion;
|
||||
|
||||
private float hitRatio = 0.0f;
|
||||
|
||||
private long hitCount = 0L;
|
||||
private long lastAccessedTime = 0L;
|
||||
private long lastModifiedTime = 0L;
|
||||
private long missCount = 0L;
|
||||
|
||||
protected PartitionRegionCacheStatistics(Region<?, ?> region) {
|
||||
|
||||
Assert.isInstanceOf(PartitionedRegion.class, region, () ->
|
||||
String.format("Region [%1$s] must be of type [%2$s]", RegionUtils.toRegionPath(region),
|
||||
PartitionedRegion.class.getName()));
|
||||
|
||||
this.partitionRegion = computeStatistics((PartitionedRegion) region);
|
||||
}
|
||||
|
||||
protected PartitionedRegion computeStatistics(PartitionedRegion region) {
|
||||
|
||||
float totalHitRatio = 0.0f;
|
||||
|
||||
int totalCount = 0;
|
||||
|
||||
long totalHitCount = 0L;
|
||||
long maxLastAccessedTime = 0L;
|
||||
long maxLastModifiedTime = 0L;
|
||||
long totalMissCount = 0L;
|
||||
|
||||
Set<BucketRegion> bucketRegions = Optional.of(region)
|
||||
.map(PartitionedRegion::getDataStore)
|
||||
.map(PartitionedRegionDataStore::getAllLocalBucketRegions)
|
||||
.orElseGet(Collections::emptySet);
|
||||
|
||||
for (BucketRegion bucket : bucketRegions) {
|
||||
|
||||
CacheStatistics bucketStatistics = bucket.getStatistics();
|
||||
|
||||
if (bucketStatistics != null) {
|
||||
|
||||
totalCount++;
|
||||
|
||||
totalHitCount += bucketStatistics.getHitCount();
|
||||
totalHitRatio += bucketStatistics.getHitRatio();
|
||||
maxLastAccessedTime = Math.max(maxLastAccessedTime, bucketStatistics.getLastAccessedTime());
|
||||
maxLastModifiedTime = Math.max(maxLastModifiedTime, bucketStatistics.getLastModifiedTime());
|
||||
totalMissCount += bucketStatistics.getMissCount();
|
||||
}
|
||||
}
|
||||
|
||||
if (totalCount > 0) {
|
||||
this.hitCount = totalHitCount / totalCount;
|
||||
this.hitRatio = totalHitRatio / totalCount;
|
||||
this.lastAccessedTime = maxLastAccessedTime;
|
||||
this.lastModifiedTime = maxLastModifiedTime;
|
||||
this.missCount = totalMissCount / totalCount;
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
protected PartitionedRegion getPartitionRegion() {
|
||||
return this.partitionRegion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getHitCount() throws StatisticsDisabledException {
|
||||
return this.hitCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHitRatio() throws StatisticsDisabledException {
|
||||
return this.hitRatio;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastAccessedTime() throws StatisticsDisabledException {
|
||||
return this.lastAccessedTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastModifiedTime() {
|
||||
return this.lastModifiedTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMissCount() throws StatisticsDisabledException {
|
||||
return this.missCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetCounts() throws StatisticsDisabledException {
|
||||
|
||||
this.hitCount = 0L;
|
||||
this.hitRatio = 0.0f;
|
||||
this.lastAccessedTime = 0L;
|
||||
this.lastModifiedTime = 0L;
|
||||
this.missCount = 0L;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.asyncqueue.AsyncEventQueue;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.wan.GatewaySender;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.data.gemfire.tests.mock.AsyncEventQueueMockObjects;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GeodeAsyncEventQueuesHealthIndicator}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.asyncqueue.AsyncEventQueue
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.data.gemfire.tests.mock.AsyncEventQueueMockObjects
|
||||
* @see org.springframework.geode.boot.actuate.GeodeAsyncEventQueuesHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GeodeAsyncEventQueuesHealthIndicatorUnitTests {
|
||||
|
||||
@Mock
|
||||
private Cache mockCache;
|
||||
|
||||
private GeodeAsyncEventQueuesHealthIndicator asyncEventQueuesHealthIndicator;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.asyncEventQueuesHealthIndicator = new GeodeAsyncEventQueuesHealthIndicator(this.mockCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckCapturesDetails() throws Exception {
|
||||
|
||||
Set<AsyncEventQueue> mockAsyncEventQueues = new HashSet<>();
|
||||
|
||||
mockAsyncEventQueues.add(AsyncEventQueueMockObjects.mockAsyncEventQueue("aeqOne", true,
|
||||
250, 10000, "testDiskStoreOne", true, 16,
|
||||
true, 65536, GatewaySender.OrderPolicy.THREAD, true,
|
||||
true, true, 1024));
|
||||
|
||||
mockAsyncEventQueues.add(AsyncEventQueueMockObjects.mockAsyncEventQueue("aeqTwo", false,
|
||||
100, 1000, "testDiskStoreTwo", false, 8,
|
||||
false, 32768, GatewaySender.OrderPolicy.KEY, false,
|
||||
true, false, 8192));
|
||||
|
||||
when(this.mockCache.getAsyncEventQueues()).thenReturn(mockAsyncEventQueues);
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
this.asyncEventQueuesHealthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
|
||||
Map<String, Object> healthDetails = health.getDetails();
|
||||
|
||||
assertThat(healthDetails).isNotNull();
|
||||
assertThat(healthDetails).isNotEmpty();
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.count", mockAsyncEventQueues.size());
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqOne.batch-conflation-enabled", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqOne.batch-size", 250);
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqOne.batch-time-interval", 10000);
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqOne.disk-store-name", "testDiskStoreOne");
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqOne.disk-synchronous", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqOne.dispatcher-threads", 16);
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqOne.forward-expiration-destroy", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqOne.max-queue-memory", 65536);
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqOne.order-policy", GatewaySender.OrderPolicy.THREAD);
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqOne.parallel", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqOne.persistent", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqOne.primary", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqOne.size", 1024);
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqTwo.batch-conflation-enabled", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqTwo.batch-size", 100);
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqTwo.batch-time-interval", 1000);
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqTwo.disk-store-name", "testDiskStoreTwo");
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqTwo.disk-synchronous", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqTwo.dispatcher-threads", 8);
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqTwo.forward-expiration-destroy", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqTwo.max-queue-memory", 32768);
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqTwo.order-policy", GatewaySender.OrderPolicy.KEY);
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqTwo.parallel", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqTwo.persistent", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqTwo.primary", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.async-event-queue.aeqTwo.size", 8192);
|
||||
|
||||
verify(this.mockCache, times(1)).getAsyncEventQueues();
|
||||
}
|
||||
|
||||
public void testHealthCheckFailsWhenGemFireCacheIsInvalid(GemFireCache gemfireCache) throws Exception {
|
||||
|
||||
GeodeAsyncEventQueuesHealthIndicator healthIndicator = gemfireCache != null
|
||||
? new GeodeAsyncEventQueuesHealthIndicator(gemfireCache)
|
||||
: new GeodeAsyncEventQueuesHealthIndicator();
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
healthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getDetails()).isEmpty();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckFailsWhenGemFireCacheIsNotPeerCache() throws Exception {
|
||||
testHealthCheckFailsWhenGemFireCacheIsInvalid(mock(ClientCache.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckFailsWhenGemFireCacheIsNotPresent() throws Exception {
|
||||
testHealthCheckFailsWhenGemFireCacheIsInvalid(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.apache.geode.CancelCriterion;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.control.ResourceManager;
|
||||
import org.apache.geode.distributed.DistributedMember;
|
||||
import org.apache.geode.distributed.DistributedSystem;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.data.gemfire.tests.mock.CacheMockObjects;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GeodeCacheHealthIndicator}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.apache.geode.CancelCriterion
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.control.ResourceManager
|
||||
* @see org.apache.geode.distributed.DistributedMember
|
||||
* @see org.apache.geode.distributed.DistributedSystem
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.data.gemfire.tests.mock.CacheMockObjects
|
||||
* @see org.springframework.geode.boot.actuate.GeodeCacheHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GeodeCacheHealthIndicatorUnitTests {
|
||||
|
||||
@Mock
|
||||
private GemFireCache mockGemFireCache;
|
||||
|
||||
private GeodeCacheHealthIndicator cacheHealthIndicator;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.cacheHealthIndicator = new GeodeCacheHealthIndicator(this.mockGemFireCache);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Set<DistributedMember> mockDistributedMembers(int size) {
|
||||
|
||||
return IntStream.range(0, size)
|
||||
.mapToObj(it -> mock(DistributedMember.class))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckCapturesDetails() throws Exception {
|
||||
|
||||
DistributedMember mockDistributedMember =
|
||||
CacheMockObjects.mockDistributedMember("TestMember", "TestGroup", "MockGroup");
|
||||
|
||||
when(mockDistributedMember.getHost()).thenReturn("Skullbox");
|
||||
when(mockDistributedMember.getProcessId()).thenReturn(12345);
|
||||
|
||||
DistributedSystem mockDistributedSystem = CacheMockObjects.mockDistributedSystem(mockDistributedMember);
|
||||
|
||||
when(mockDistributedSystem.getAllOtherMembers()).thenAnswer(invocation -> mockDistributedMembers(8));
|
||||
when(mockDistributedSystem.isConnected()).thenReturn(true);
|
||||
when(mockDistributedSystem.isReconnecting()).thenReturn(false);
|
||||
|
||||
ResourceManager mockResourceManager = CacheMockObjects.mockResourceManager(0.9f,
|
||||
0.95f, 0.85f, 0.9f);
|
||||
|
||||
GemFireCache mockGemFireCache = CacheMockObjects.mockGemFireCache(this.mockGemFireCache,
|
||||
"MockGemFireCache", mockDistributedSystem, mockResourceManager);
|
||||
|
||||
CancelCriterion mockCancelCriterion = mock(CancelCriterion.class);
|
||||
|
||||
when(mockCancelCriterion.isCancelInProgress()).thenReturn(false);
|
||||
when(mockGemFireCache.getCancelCriterion()).thenReturn(mockCancelCriterion);
|
||||
when(mockGemFireCache.isClosed()).thenReturn(false);
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
this.cacheHealthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
|
||||
Map<String, Object> healthDetails = health.getDetails();
|
||||
|
||||
assertThat(healthDetails).isNotNull();
|
||||
assertThat(healthDetails).isNotEmpty();
|
||||
assertThat(healthDetails).containsEntry("geode.cache.name", "MockGemFireCache");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.closed", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.cancel-in-progress", "No");
|
||||
assertThat(healthDetails).containsKey("geode.distributed-member.id");
|
||||
assertThat(String.valueOf(healthDetails.get("geode.distributed-member.id"))).isNotEqualToIgnoringCase("null");
|
||||
assertThat(healthDetails).containsEntry("geode.distributed-member.name", "TestMember");
|
||||
assertThat(healthDetails).containsEntry("geode.distributed-member.groups", Arrays.asList("TestGroup", "MockGroup"));
|
||||
assertThat(healthDetails).containsEntry("geode.distributed-member.host", "Skullbox");
|
||||
assertThat(healthDetails).containsEntry("geode.distributed-member.process-id", 12345);
|
||||
assertThat(healthDetails).containsEntry("geode.distributed-system.member-count", 9);
|
||||
assertThat(healthDetails).containsEntry("geode.distributed-system.connection", "Connected");
|
||||
assertThat(healthDetails).containsEntry("geode.distributed-system.reconnecting", "No");
|
||||
//assertThat(healthDetails).containsKey("geode.distributed-member.properties-location");
|
||||
//assertThat(healthDetails).containsKey("geode.distributed-member.security-properties-location");
|
||||
assertThat(healthDetails).containsEntry("geode.resource-manager.critical-heap-percentage", 0.9f);
|
||||
assertThat(healthDetails).containsEntry("geode.resource-manager.critical-off-heap-percentage", 0.95f);
|
||||
assertThat(healthDetails).containsEntry("geode.resource-manager.eviction-heap-percentage", 0.85f);
|
||||
assertThat(healthDetails).containsEntry("geode.resource-manager.eviction-off-heap-percentage", 0.9f);
|
||||
|
||||
verify(this.mockGemFireCache, times(1)).getCancelCriterion();
|
||||
verify(this.mockGemFireCache, times(2)).getDistributedSystem();
|
||||
verify(this.mockGemFireCache, times(1)).getResourceManager();
|
||||
verify(mockDistributedSystem, times(1)).getDistributedMember();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckFailsWhenGemFireCacheIsNotPresent() throws Exception {
|
||||
|
||||
GeodeCacheHealthIndicator healthIndicator = new GeodeCacheHealthIndicator();
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
healthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getDetails()).isEmpty();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.server.CacheServer;
|
||||
import org.apache.geode.cache.server.ServerLoadProbe;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.data.gemfire.tests.mock.CacheServerMockObjects;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GeodeCacheServersHealthIndicator}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.server.CacheServer
|
||||
* @see org.apache.geode.cache.server.ServerLoadProbe
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.data.gemfire.tests.mock.CacheServerMockObjects
|
||||
* @see org.springframework.geode.boot.actuate.GeodeCacheServersHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GeodeCacheServersHealthIndicatorUnitTests {
|
||||
|
||||
@Mock
|
||||
private Cache mockCache;
|
||||
|
||||
private GeodeCacheServersHealthIndicator cacheServersHealthIndicator;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.cacheServersHealthIndicator = new GeodeCacheServersHealthIndicator(this.mockCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckCapturesDetails() throws Exception {
|
||||
|
||||
List<CacheServer> mockCacheServers = new ArrayList<>();
|
||||
|
||||
ServerLoadProbe mockServerLoadProbe = mock(ServerLoadProbe.class);
|
||||
|
||||
mockCacheServers.add(CacheServerMockObjects.mockCacheServer("10.11.111.1", null,
|
||||
"Mailbox", 15000L, mockServerLoadProbe, 100, 500,
|
||||
8, 20000, 30000, 41414, true, 16384,
|
||||
true));
|
||||
|
||||
mockCacheServers.add(CacheServerMockObjects.mockCacheServer("10.12.120.2", null,
|
||||
"Skullbox", 10000L, mockServerLoadProbe, 250, 50,
|
||||
16, 5000, 15000, 42424, false, 8192,
|
||||
false));
|
||||
|
||||
when(this.mockCache.getCacheServers()).thenReturn(mockCacheServers);
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
this.cacheServersHealthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
|
||||
Map<String, Object> healthDetails = health.getDetails();
|
||||
|
||||
assertThat(healthDetails).isNotNull();
|
||||
assertThat(healthDetails).isNotEmpty();
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.count", 2);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.bind-address", "10.11.111.1");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.hostname-for-clients", "Mailbox");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.load-poll-interval", 15000L);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.max-connections", 100);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.max-message-count", 500);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.max-threads", 8);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.max-time-between-pings", 20000);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.message-time-to-live", 30000);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.port", 41414);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.running", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.socket-buffer-size", 16384);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.0.tcp-no-delay", "Yes");
|
||||
assertThat(healthDetails).doesNotContainKeys("geode.cache.server.0.client-subscription-config",
|
||||
"geode.cache.server.0.metrics.client-count", "geode.cache.server.0.load.connection-load");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.1.bind-address", "10.12.120.2");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.1.hostname-for-clients", "Skullbox");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.1.load-poll-interval", 10000L);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.1.max-connections", 250);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.1.max-message-count", 50);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.1.max-threads", 16);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.1.max-time-between-pings", 5000);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.1.message-time-to-live", 15000);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.1.port", 42424);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.1.running", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.1.socket-buffer-size", 8192);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.server.1.tcp-no-delay", "No");
|
||||
assertThat(healthDetails).doesNotContainKeys("geode.cache.server.1.client-subscription-config",
|
||||
"geode.cache.server.1.metrics.client-count", "geode.cache.server.1.load.connection-load");
|
||||
|
||||
verify(this.mockCache, times(1)).getCacheServers();
|
||||
}
|
||||
|
||||
private void testHealthCheckFailsWhenGemFireCacheIsInvalid(GemFireCache gemfireCache) throws Exception {
|
||||
|
||||
GeodeCacheServersHealthIndicator healthIndicator = gemfireCache != null
|
||||
? new GeodeCacheServersHealthIndicator(gemfireCache)
|
||||
: new GeodeCacheServersHealthIndicator();
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
healthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getDetails()).isEmpty();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckFailsWhenGemFireCacheIsNotPeerCache() throws Exception {
|
||||
testHealthCheckFailsWhenGemFireCacheIsInvalid(mock(ClientCache.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckFailsWhenGemFireCacheIsNotPresent() throws Exception {
|
||||
testHealthCheckFailsWhenGemFireCacheIsInvalid(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.geode.cache.query.CqQuery;
|
||||
import org.apache.geode.cache.query.CqServiceStatistics;
|
||||
import org.apache.geode.cache.query.CqState;
|
||||
import org.apache.geode.cache.query.CqStatistics;
|
||||
import org.apache.geode.cache.query.Query;
|
||||
import org.apache.geode.cache.query.QueryService;
|
||||
import org.apache.geode.cache.query.QueryStatistics;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.data.gemfire.listener.ContinuousQueryListenerContainer;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GeodeContinuousQueriesHealthIndicator}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.apache.geode.cache.query.CqQuery
|
||||
* @see org.apache.geode.cache.query.Query
|
||||
* @see org.apache.geode.cache.query.QueryService
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.data.gemfire.listener.ContinuousQueryListenerContainer
|
||||
* @see org.springframework.geode.boot.actuate.GeodeContinuousQueriesHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GeodeContinuousQueriesHealthIndicatorUnitTests {
|
||||
|
||||
private GeodeContinuousQueriesHealthIndicator continuousQueriesHealthIndicator;
|
||||
|
||||
@Mock
|
||||
private QueryService mockQueryService;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
|
||||
ContinuousQueryListenerContainer container = new ContinuousQueryListenerContainer();
|
||||
|
||||
container.setQueryService(this.mockQueryService);
|
||||
|
||||
this.continuousQueriesHealthIndicator = new GeodeContinuousQueriesHealthIndicator(container);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckCapturesDetails() throws Exception {
|
||||
|
||||
CqQuery mockContinuousQuery = mock(CqQuery.class, "MockContinuousQuery");
|
||||
|
||||
when(mockContinuousQuery.getName()).thenReturn("MockContinuousQuery");
|
||||
when(mockContinuousQuery.getQueryString()).thenReturn("SELECT * FROM /Example WHERE status = 'RUNNING'");
|
||||
when(mockContinuousQuery.isClosed()).thenReturn(false);
|
||||
when(mockContinuousQuery.isDurable()).thenReturn(true);
|
||||
when(mockContinuousQuery.isRunning()).thenReturn(true);
|
||||
when(mockContinuousQuery.isStopped()).thenReturn(false);
|
||||
|
||||
CqState mockContinuousQueryState = mock(CqState.class);
|
||||
|
||||
when(mockContinuousQueryState.isClosing()).thenReturn(false);
|
||||
when(mockContinuousQuery.getState()).thenReturn(mockContinuousQueryState);
|
||||
|
||||
CqStatistics mockContinuousQueryStatistics = mock(CqStatistics.class);
|
||||
|
||||
when(mockContinuousQueryStatistics.numDeletes()).thenReturn(1024L);
|
||||
when(mockContinuousQueryStatistics.numEvents()).thenReturn(4096000L);
|
||||
when(mockContinuousQueryStatistics.numInserts()).thenReturn(8192L);
|
||||
when(mockContinuousQueryStatistics.numUpdates()).thenReturn(1638400L);
|
||||
when(mockContinuousQuery.getStatistics()).thenReturn(mockContinuousQueryStatistics);
|
||||
|
||||
Query mockQuery = mock(Query.class);
|
||||
|
||||
QueryStatistics mockQueryStatistics = mock(QueryStatistics.class);
|
||||
|
||||
when(mockQueryStatistics.getNumExecutions()).thenReturn(1024L);
|
||||
when(mockQueryStatistics.getTotalExecutionTime()).thenReturn(123456789L);
|
||||
when(mockQuery.getStatistics()).thenReturn(mockQueryStatistics);
|
||||
when(mockContinuousQuery.getQuery()).thenReturn(mockQuery);
|
||||
|
||||
CqQuery[] mockContinuousQueries = { mockContinuousQuery };
|
||||
|
||||
when(this.mockQueryService.getCqs()).thenReturn(mockContinuousQueries);
|
||||
|
||||
CqServiceStatistics mockContinuousQueryServiceStatistics = mock(CqServiceStatistics.class);
|
||||
|
||||
when(mockContinuousQueryServiceStatistics.numCqsActive()).thenReturn(42L);
|
||||
when(mockContinuousQueryServiceStatistics.numCqsClosed()).thenReturn(8L);
|
||||
when(mockContinuousQueryServiceStatistics.numCqsCreated()).thenReturn(51L);
|
||||
when(mockContinuousQueryServiceStatistics.numCqsStopped()).thenReturn(16L);
|
||||
when(mockContinuousQueryServiceStatistics.numCqsOnClient()).thenReturn(64L);
|
||||
when(this.mockQueryService.getCqStatistics()).thenReturn(mockContinuousQueryServiceStatistics);
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
this.continuousQueriesHealthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
|
||||
Map<String, Object> healthDetails = health.getDetails();
|
||||
|
||||
assertThat(healthDetails).isNotNull();
|
||||
assertThat(healthDetails).isNotEmpty();
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.count", mockContinuousQueries.length);
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.number-of-active", 42L);
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.number-of-closed", 8L);
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.number-of-created", 51L);
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.number-of-stopped", 16L);
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.number-on-client", 64L);
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.MockContinuousQuery.oql-query-string", "SELECT * FROM /Example WHERE status = 'RUNNING'");
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.MockContinuousQuery.closed", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.MockContinuousQuery.closing", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.MockContinuousQuery.durable", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.MockContinuousQuery.running", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.MockContinuousQuery.stopped", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.MockContinuousQuery.query.number-of-executions", 1024L);
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.MockContinuousQuery.query.total-execution-time", 123456789L);
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.MockContinuousQuery.statistics.number-of-deletes", 1024L);
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.MockContinuousQuery.statistics.number-of-events", 4096000L);
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.MockContinuousQuery.statistics.number-of-inserts", 8192L);
|
||||
assertThat(healthDetails).containsEntry("geode.continuous-query.MockContinuousQuery.statistics.number-of-updates", 1638400L);
|
||||
|
||||
verify(this.mockQueryService, times(1)).getCqs();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckFailsWhenContinuousQueryListenerContainerIsNotPresent() throws Exception {
|
||||
|
||||
GeodeContinuousQueriesHealthIndicator healthIndicator = new GeodeContinuousQueriesHealthIndicator();
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
healthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getDetails()).isEmpty();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.geode.cache.DiskStore;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.gemfire.tests.mock.DiskStoreMockObjects;
|
||||
import org.springframework.data.gemfire.util.ArrayUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GeodeDiskStoresHealthIndicator}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.apache.geode.cache.DiskStore
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see org.springframework.data.gemfire.tests.mock.DiskStoreMockObjects
|
||||
* @see org.springframework.geode.boot.actuate.GeodeDiskStoresHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GeodeDiskStoresHealthIndicatorUnitTests {
|
||||
|
||||
@Mock
|
||||
private ApplicationContext mockApplicationContext;
|
||||
|
||||
private GeodeDiskStoresHealthIndicator diskStoresHealthIndicator;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.diskStoresHealthIndicator = new GeodeDiskStoresHealthIndicator(this.mockApplicationContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckCapturesDetails() throws Exception {
|
||||
|
||||
File mockDirectoryOne = mock(File.class);
|
||||
File mockDirectoryTwo = mock(File.class);
|
||||
|
||||
when(mockDirectoryOne.getAbsolutePath()).thenReturn("/ext/gemfire/disk/stores/one");
|
||||
when(mockDirectoryTwo.getAbsolutePath()).thenReturn("/ext/gemfire/disk/stores/two");
|
||||
|
||||
int[] diskDirectorySizes = { 1024, 8192 };
|
||||
|
||||
Map<String, DiskStore> mockDiskStores = new HashMap<>();
|
||||
|
||||
mockDiskStores.put("MockDiskStoreOne", DiskStoreMockObjects.mockDiskStore("MockDiskStoreOne",
|
||||
true, true, 90,
|
||||
ArrayUtils.asArray(mockDirectoryOne, mockDirectoryTwo), diskDirectorySizes, 0.95f,
|
||||
0.90f, 1024000L, 16384, 5000L, 32768));
|
||||
|
||||
mockDiskStores.put("MockDiskStoreTwo", DiskStoreMockObjects.mockDiskStore("MockDiskStoreTwo",
|
||||
false, true, 50,null, null,
|
||||
0.90f,0.80f, 2048000L, 4096,
|
||||
15000L, 8192));
|
||||
|
||||
when(this.mockApplicationContext.getBeansOfType(DiskStore.class)).thenReturn(mockDiskStores);
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
this.diskStoresHealthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
|
||||
Map<String, Object> healthDetails = health.getDetails();
|
||||
|
||||
assertThat(healthDetails).isNotNull();
|
||||
assertThat(healthDetails).isNotEmpty();
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.count", mockDiskStores.size());
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreOne.allow-force-compaction", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreOne.auto-compact", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreOne.compaction-threshold", 90);
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreOne.disk-directories", "[/ext/gemfire/disk/stores/one, /ext/gemfire/disk/stores/two]");
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreOne.disk-directory-sizes", "[1024, 8192]");
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreOne.disk-usage-critical-percentage", 0.95f);
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreOne.disk-usage-warning-percentage", 0.90f);
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreOne.max-oplog-size", 1024000L);
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreOne.queue-size", 16384);
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreOne.time-interval", 5000L);
|
||||
assertThat(healthDetails).containsKey("geode.disk-store.MockDiskStoreOne.uuid");
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreOne.write-buffer-size", 32768);
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreTwo.allow-force-compaction", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreTwo.auto-compact", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreTwo.compaction-threshold", 50);
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreTwo.disk-directories", "[]");
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreTwo.disk-directory-sizes", "[]");
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreTwo.disk-usage-critical-percentage", 0.90f);
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreTwo.disk-usage-warning-percentage", 0.80f);
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreTwo.max-oplog-size", 2048000L);
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreTwo.queue-size", 4096);
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreTwo.time-interval", 15000L);
|
||||
assertThat(healthDetails).containsKey("geode.disk-store.MockDiskStoreOne.uuid");
|
||||
assertThat(healthDetails).containsEntry("geode.disk-store.MockDiskStoreTwo.write-buffer-size", 8192);
|
||||
|
||||
verify(this.mockApplicationContext, times(1)).getBeansOfType(eq(DiskStore.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckFailsWhenApplicationContextIsNotPresent() throws Exception {
|
||||
|
||||
GeodeDiskStoresHealthIndicator healthIndicator = new GeodeDiskStoresHealthIndicator();
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
healthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getDetails()).isEmpty();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.wan.GatewayReceiver;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.data.gemfire.tests.mock.GatewayMockObjects;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GeodeGatewayReceiversHealthIndicator}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.wan.GatewayReceiver
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.data.gemfire.tests.mock.GatewayMockObjects
|
||||
* @see org.springframework.geode.boot.actuate.GeodeGatewayReceiversHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GeodeGatewayReceiversHealthIndicatorUnitTests {
|
||||
|
||||
@Mock
|
||||
private Cache mockCache;
|
||||
|
||||
private GeodeGatewayReceiversHealthIndicator gatewayReceiversHealthIndicator;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.gatewayReceiversHealthIndicator = new GeodeGatewayReceiversHealthIndicator(this.mockCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckCapturesDetails() throws Exception {
|
||||
|
||||
GatewayReceiver mockGatewayReceiverOne = GatewayMockObjects.mockGatewayReceiver("10.101.112.1",
|
||||
8192, "CardboardBox", "Mailbox", false, 15000,
|
||||
4096, true, null, 16384, 1024);
|
||||
|
||||
GatewayReceiver mockGatewayReceiverTwo = GatewayMockObjects.mockGatewayReceiver("10.101.112.4",
|
||||
8192, "Skullbox", "PostOfficeBox", true, 5000,
|
||||
8192, false, null, 65536, 1024);
|
||||
|
||||
Set<GatewayReceiver> mockGatewayReceivers =
|
||||
new TreeSet<>(Comparator.comparing(GatewayReceiver::getBindAddress));
|
||||
|
||||
mockGatewayReceivers.addAll(asSet(mockGatewayReceiverOne, mockGatewayReceiverTwo));
|
||||
|
||||
when(this.mockCache.getGatewayReceivers()).thenReturn(mockGatewayReceivers);
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
this.gatewayReceiversHealthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
|
||||
Map<String, Object> healthDetails = health.getDetails();
|
||||
|
||||
assertThat(healthDetails).isNotNull();
|
||||
assertThat(healthDetails).isNotEmpty();
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.count", mockGatewayReceivers.size());
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.0.bind-address", "10.101.112.1");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.0.end-port", 8192);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.0.host", "CardboardBox");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.0.max-time-between-pings", 15000);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.0.port", 4096);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.0.running", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.0.socket-buffer-size", 16384);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.0.start-port", 1024);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.1.bind-address", "10.101.112.4");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.1.end-port", 8192);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.1.host", "Skullbox");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.1.max-time-between-pings",5000);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.1.port", 8192);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.1.running", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.1.socket-buffer-size", 65536);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-receiver.1.start-port", 1024);
|
||||
|
||||
verify(this.mockCache, times(1)).getGatewayReceivers();
|
||||
}
|
||||
|
||||
private void testHealthCheckFailsWhenGemFireCacheIsInvalid(GemFireCache gemfireCache) throws Exception {
|
||||
|
||||
GeodeGatewayReceiversHealthIndicator healthIndicator = gemfireCache != null
|
||||
? new GeodeGatewayReceiversHealthIndicator(gemfireCache)
|
||||
: new GeodeGatewayReceiversHealthIndicator();
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
healthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getDetails()).isEmpty();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckFailsWhenGemFireCacheIsNotPeerCache() throws Exception {
|
||||
testHealthCheckFailsWhenGemFireCacheIsInvalid(mock(ClientCache.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckFailsWhenGemFireCacheIsNotPresent() throws Exception {
|
||||
testHealthCheckFailsWhenGemFireCacheIsInvalid(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.wan.GatewaySender;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.data.gemfire.tests.mock.GatewayMockObjects;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GeodeGatewaySendersHealthIndicator}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.wan.GatewaySender
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.data.gemfire.tests.mock.GatewayMockObjects
|
||||
* @see org.springframework.geode.boot.actuate.GeodeGatewaySendersHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GeodeGatewaySendersHealthIndicatorUnitTests {
|
||||
|
||||
@Mock
|
||||
private Cache mockCache;
|
||||
|
||||
private GeodeGatewaySendersHealthIndicator gatewaySendersHealthIndicator;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.gatewaySendersHealthIndicator = new GeodeGatewaySendersHealthIndicator(this.mockCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckCapturesDetails() throws Exception {
|
||||
|
||||
GatewaySender mockGatewaySenderOne = GatewayMockObjects.mockGatewaySender("MockGatewaySenderOne",
|
||||
100, true, 250, 30000, "TestDiskStore",
|
||||
true, 8, 16384, 24,
|
||||
GatewaySender.OrderPolicy.THREAD, true, true, 123,
|
||||
true, 32768, 15000);
|
||||
|
||||
GatewaySender mockGatewaySenderTwo = GatewayMockObjects.mockGatewaySender("MockGatewaySenderTwo",
|
||||
99, false, 500, 20000, null,
|
||||
false, 16, 8192, 32,
|
||||
GatewaySender.OrderPolicy.KEY, false, false, 789,
|
||||
false, 65536, 20000);
|
||||
|
||||
Set<GatewaySender> mockGatewaySenders =
|
||||
new TreeSet<>(Comparator.comparing(GatewaySender::getId));
|
||||
|
||||
mockGatewaySenders.addAll(asSet(mockGatewaySenderOne, mockGatewaySenderTwo));
|
||||
|
||||
when(this.mockCache.getGatewaySenders()).thenReturn(mockGatewaySenders);
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
this.gatewaySendersHealthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
|
||||
Map<String, Object> healthDetails = health.getDetails();
|
||||
|
||||
assertThat(healthDetails).isNotNull();
|
||||
assertThat(healthDetails).isNotEmpty();
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.count", mockGatewaySenders.size());
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.alert-threshold", 100);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.batch-conflation-enabled", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.batch-size", 250);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.batch-time-interval", 30000);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.disk-store-name", "TestDiskStore");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.disk-synchronous", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.dispatcher-threads", 8);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.max-queue-memory", 16384);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.max-parallelism-for-replicated-region", 24);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.order-policy", GatewaySender.OrderPolicy.THREAD);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.parallel", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.persistent", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.remote-distributed-system-id", 123);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.running", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.socket-buffer-size", 32768);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderOne.socket-read-timeout", 15000);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderTwo.alert-threshold", 99);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderTwo.batch-conflation-enabled", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderTwo.batch-size", 500);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderTwo.batch-time-interval", 20000);
|
||||
assertThat(healthDetails).containsKey("geode.gateway-sender.MockGatewaySenderTwo.disk-store-name");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderTwo.disk-synchronous", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderTwo.dispatcher-threads", 16);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderTwo.max-queue-memory", 8192);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderTwo.max-parallelism-for-replicated-region", 32);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderTwo.order-policy", GatewaySender.OrderPolicy.KEY);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderTwo.parallel", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderTwo.persistent", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderTwo.remote-distributed-system-id", 789);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderTwo.running", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderTwo.socket-buffer-size", 65536);
|
||||
assertThat(healthDetails).containsEntry("geode.gateway-sender.MockGatewaySenderTwo.socket-read-timeout", 20000);
|
||||
|
||||
verify(this.mockCache, times(1)).getGatewaySenders();
|
||||
}
|
||||
|
||||
private void testHealthCheckFailsWithInvalidGemFireCache(GemFireCache gemfireCache) throws Exception {
|
||||
|
||||
GeodeGatewaySendersHealthIndicator healthIndicator = gemfireCache != null
|
||||
? new GeodeGatewaySendersHealthIndicator(gemfireCache)
|
||||
: new GeodeGatewaySendersHealthIndicator();
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
healthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);
|
||||
assertThat(health.getDetails()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckFailsWhenGemFireCacheIsNotPeerCache() throws Exception {
|
||||
testHealthCheckFailsWithInvalidGemFireCache(mock(ClientCache.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckFailsWhenGemFireCacheIsNotPresent() throws Exception {
|
||||
testHealthCheckFailsWithInvalidGemFireCache(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.geode.cache.DataPolicy;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.apache.geode.cache.query.IndexStatistics;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.gemfire.IndexType;
|
||||
import org.springframework.data.gemfire.tests.mock.CacheMockObjects;
|
||||
import org.springframework.data.gemfire.tests.mock.IndexMockObjects;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GeodeIndexesHealthIndicator}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @see org.apache.geode.cache.query.IndexStatistics
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see org.springframework.data.gemfire.tests.mock.CacheMockObjects
|
||||
* @see org.springframework.data.gemfire.tests.mock.IndexMockObjects
|
||||
* @see org.springframework.geode.boot.actuate.GeodeIndexesHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GeodeIndexesHealthIndicatorUnitTests {
|
||||
|
||||
@Mock
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private GeodeIndexesHealthIndicator indexesHealthIndicator;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.indexesHealthIndicator = new GeodeIndexesHealthIndicator(this.applicationContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckCapturesDetails() throws Exception {
|
||||
|
||||
Region mockRegion = CacheMockObjects.mockRegion("MockRegion", DataPolicy.PARTITION);
|
||||
|
||||
IndexStatistics mockIndexStatistics = IndexMockObjects.mockIndexStatistics(226,
|
||||
100000, 6000, 1024000L, 51515L,
|
||||
512, 2048L, 4096L);
|
||||
|
||||
Index mockIndex = IndexMockObjects.mockIndex("MockIndex", "/Example",
|
||||
"id", "one, two", mockRegion, mockIndexStatistics,
|
||||
IndexType.PRIMARY_KEY.getGemfireIndexType());
|
||||
|
||||
Map<String, Index> mockIndexes = Collections.singletonMap("MockIndex", mockIndex);
|
||||
|
||||
when(this.applicationContext.getBeansOfType(eq(Index.class))).thenReturn(mockIndexes);
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
this.indexesHealthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
|
||||
Map<String, Object> healthDetails = health.getDetails();
|
||||
|
||||
assertThat(healthDetails).isNotNull();
|
||||
assertThat(healthDetails).isNotEmpty();
|
||||
assertThat(healthDetails).containsEntry("geode.index.count", mockIndexes.size());
|
||||
assertThat(healthDetails).containsEntry("geode.index.MockIndex.from-clause", "/Example");
|
||||
assertThat(healthDetails).containsEntry("geode.index.MockIndex.indexed-expression", "id");
|
||||
assertThat(healthDetails).containsEntry("geode.index.MockIndex.projection-attributes", "one, two");
|
||||
assertThat(healthDetails).containsEntry("geode.index.MockIndex.region", "/MockRegion");
|
||||
assertThat(healthDetails).containsEntry("geode.index.MockIndex.type",
|
||||
IndexType.PRIMARY_KEY.getGemfireIndexType().toString());
|
||||
assertThat(healthDetails).containsEntry("geode.index.MockIndex.statistics.number-of-bucket-indexes", 226);
|
||||
assertThat(healthDetails).containsEntry("geode.index.MockIndex.statistics.number-of-keys", 100000L);
|
||||
assertThat(healthDetails).containsEntry("geode.index.MockIndex.statistics.number-of-map-index-keys", 6000L);
|
||||
assertThat(healthDetails).containsEntry("geode.index.MockIndex.statistics.number-of-values", 1024000L);
|
||||
assertThat(healthDetails).containsEntry("geode.index.MockIndex.statistics.number-of-updates", 51515L);
|
||||
assertThat(healthDetails).containsEntry("geode.index.MockIndex.statistics.read-lock-count", 512);
|
||||
assertThat(healthDetails).containsEntry("geode.index.MockIndex.statistics.total-update-time", 2048L);
|
||||
assertThat(healthDetails).containsEntry("geode.index.MockIndex.statistics.total-uses", 4096L);
|
||||
|
||||
verify(this.applicationContext, times(1)).getBeansOfType(eq(Index.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckFailsWhenApplicationContextContainsIsNotPresent() throws Exception {
|
||||
|
||||
GeodeIndexesHealthIndicator healthIndicator = new GeodeIndexesHealthIndicator();
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
healthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getDetails()).isEmpty();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.client.Pool;
|
||||
import org.apache.geode.distributed.DistributedSystem;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.data.gemfire.tests.mock.PoolMockObjects;
|
||||
import org.springframework.data.gemfire.util.CacheUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GeodePoolsHealthIndicator}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
* @see org.apache.geode.distributed.DistributedSystem
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.data.gemfire.tests.mock.PoolMockObjects
|
||||
* @see org.springframework.geode.boot.actuate.GeodePoolsHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GeodePoolsHealthIndicatorUnitTests {
|
||||
|
||||
@Mock
|
||||
private ClientCache mockClientCache;
|
||||
|
||||
private GeodePoolsHealthIndicator poolsHealthIndicator;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.poolsHealthIndicator = spy(new GeodePoolsHealthIndicator(mockDurableClient(this.mockClientCache)));
|
||||
}
|
||||
|
||||
private ClientCache mockDurableClient(ClientCache mockClientCache) {
|
||||
|
||||
Properties gemfireProperties = new Properties();
|
||||
|
||||
gemfireProperties.setProperty(CacheUtils.DURABLE_CLIENT_ID_PROPERTY_NAME, "test-durable-client");
|
||||
|
||||
DistributedSystem mockDistributedSystem = mock(DistributedSystem.class);
|
||||
|
||||
when(mockDistributedSystem.isConnected()).thenReturn(true);
|
||||
when(mockDistributedSystem.getProperties()).thenReturn(gemfireProperties);
|
||||
when(mockClientCache.getDistributedSystem()).thenReturn(mockDistributedSystem);
|
||||
|
||||
return mockClientCache;
|
||||
}
|
||||
|
||||
private InetSocketAddress testSocketAddress(String hostname, int port) {
|
||||
return new InetSocketAddress(hostname, port);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckCapturesDetails() {
|
||||
|
||||
List<InetSocketAddress> mockLocators =
|
||||
Arrays.asList(testSocketAddress("mailbox", 1234),
|
||||
testSocketAddress("skullbox", 6789));
|
||||
|
||||
Pool mockPool = PoolMockObjects.mockPool("MockPool", false, 5000,
|
||||
60000L, 1000, mockLocators, 500, 50,
|
||||
true, mockLocators.subList(0, 1), 75, 15000L,
|
||||
true, null, 10000, 2, "TestGroup",
|
||||
Collections.emptyList(), 65536, 30000, 5000,
|
||||
10000, true, 5000,
|
||||
2, 8, false);
|
||||
|
||||
when(this.poolsHealthIndicator.findAllPools()).thenReturn(Collections.singletonMap("MockPool", mockPool));
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
this.poolsHealthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
|
||||
Map<String, Object> healthDetails = health.getDetails();
|
||||
|
||||
assertThat(healthDetails).isNotNull();
|
||||
assertThat(healthDetails).isNotEmpty();
|
||||
assertThat(healthDetails).containsEntry("geode.pool.count", 1);
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.destroyed", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.free-connection-timeout", 5000);
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.idle-timeout", 60000L);
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.load-conditioning-interval", 1000);
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.locators", "mailbox:1234,skullbox:6789");
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.max-connections", 500);
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.min-connections", 50);
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.multi-user-authentication", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.online-locators", "mailbox:1234");
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.pending-event-count", 75);
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.ping-interval", 15000L);
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.pr-single-hop-enabled", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.read-timeout", 10000);
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.retry-attempts", 2);
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.server-group", "TestGroup");
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.servers", "");
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.socket-buffer-size", 65536);
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.statistic-interval", 5000);
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.subscription-ack-interval", 10000);
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.subscription-enabled", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.subscription-message-tracking-timeout", 5000);
|
||||
assertThat(healthDetails).containsEntry("geode.pool.MockPool.subscription-redundancy", 2);
|
||||
//assertThat(healthDetails).containsEntry("geode.pool.MockPool.thread-local-connections", "No");
|
||||
|
||||
verify(this.poolsHealthIndicator, times(1)).findAllPools();
|
||||
}
|
||||
|
||||
public void testHealthCheckFailsWhenGemFireCacheIsInvalid(GemFireCache gemfireCache) {
|
||||
|
||||
GeodePoolsHealthIndicator healthIndicator = gemfireCache != null
|
||||
? new GeodePoolsHealthIndicator(gemfireCache)
|
||||
: new GeodePoolsHealthIndicator();
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
healthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getDetails()).isEmpty();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckFailsWhenGemFireCacheIsNotClientCache() throws Exception {
|
||||
testHealthCheckFailsWhenGemFireCacheIsInvalid(mock(Cache.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckFailsWhenGemFireCacheIsNotPresent() throws Exception {
|
||||
testHealthCheckFailsWhenGemFireCacheIsInvalid(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.actuate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Currency;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.apache.geode.cache.CacheStatistics;
|
||||
import org.apache.geode.cache.DataPolicy;
|
||||
import org.apache.geode.cache.EvictionAction;
|
||||
import org.apache.geode.cache.EvictionAlgorithm;
|
||||
import org.apache.geode.cache.EvictionAttributes;
|
||||
import org.apache.geode.cache.ExpirationAction;
|
||||
import org.apache.geode.cache.ExpirationAttributes;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.PartitionAttributes;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.Scope;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.data.gemfire.tests.mock.CacheMockObjects;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GeodeRegionsHealthIndicator}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.apache.geode.cache.CacheStatistics
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.springframework.boot.actuate.health.Health
|
||||
* @see org.springframework.boot.actuate.health.HealthIndicator
|
||||
* @see org.springframework.data.gemfire.tests.mock.CacheMockObjects
|
||||
* @see org.springframework.geode.boot.actuate.GeodeRegionsHealthIndicator
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GeodeRegionsHealthIndicatorUnitTests {
|
||||
|
||||
@Mock
|
||||
private GemFireCache mockGemFireCache;
|
||||
|
||||
private GeodeRegionsHealthIndicator regionsHealthIndicator;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.regionsHealthIndicator = new GeodeRegionsHealthIndicator(this.mockGemFireCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void healthCheckCapturesDetails() {
|
||||
|
||||
Region<?, ?> mockRegionOne = CacheMockObjects.mockRegion("MockRegionOne", DataPolicy.PARTITION);
|
||||
|
||||
when(mockRegionOne.getAttributes().getCloningEnabled()).thenReturn(true);
|
||||
when(mockRegionOne.getAttributes().getInitialCapacity()).thenReturn(101);
|
||||
when(mockRegionOne.getAttributes().getLoadFactor()).thenReturn(0.75f);
|
||||
when(mockRegionOne.getAttributes().getKeyConstraint()).thenReturn((Class) Long.class);
|
||||
when(mockRegionOne.getAttributes().getOffHeap()).thenReturn(true);
|
||||
when(mockRegionOne.getAttributes().getPoolName()).thenReturn("");
|
||||
when(mockRegionOne.getAttributes().getScope()).thenReturn(Scope.DISTRIBUTED_ACK);
|
||||
when(mockRegionOne.getAttributes().getStatisticsEnabled()).thenReturn(false);
|
||||
when(mockRegionOne.getAttributes().getValueConstraint()).thenReturn((Class) Currency.class);
|
||||
|
||||
PartitionAttributes<?, ?> mockPartitionAttributes = mock(PartitionAttributes.class);
|
||||
|
||||
when(mockPartitionAttributes.getColocatedWith()).thenReturn("CollocatedRegion");
|
||||
when(mockPartitionAttributes.getLocalMaxMemory()).thenReturn(10240);
|
||||
when(mockPartitionAttributes.getRedundantCopies()).thenReturn(2);
|
||||
//when(mockPartitionAttributes.getTotalMaxMemory()).thenReturn(4096000L);
|
||||
when(mockPartitionAttributes.getTotalNumBuckets()).thenReturn(226);
|
||||
when(mockRegionOne.getAttributes().getPartitionAttributes()).thenReturn(mockPartitionAttributes);
|
||||
|
||||
EvictionAttributes mockEvictionAttributes = mock(EvictionAttributes.class);
|
||||
|
||||
when(mockEvictionAttributes.getAction()).thenReturn(EvictionAction.LOCAL_DESTROY);
|
||||
when(mockEvictionAttributes.getAlgorithm()).thenReturn(EvictionAlgorithm.LRU_ENTRY);
|
||||
when(mockEvictionAttributes.getMaximum()).thenReturn(10000);
|
||||
when(mockRegionOne.getAttributes().getEvictionAttributes()).thenReturn(mockEvictionAttributes);
|
||||
|
||||
Region<?, ?> mockRegionTwo = CacheMockObjects.mockRegion("MockRegionTwo", DataPolicy.EMPTY);
|
||||
|
||||
when(mockRegionTwo.getAttributes().getCloningEnabled()).thenReturn(false);
|
||||
when(mockRegionTwo.getAttributes().getInitialCapacity()).thenReturn(0);
|
||||
when(mockRegionTwo.getAttributes().getLoadFactor()).thenReturn(0.0f);
|
||||
when(mockRegionTwo.getAttributes().getKeyConstraint()).thenReturn((Class) Integer.class);
|
||||
when(mockRegionTwo.getAttributes().getOffHeap()).thenReturn(false);
|
||||
when(mockRegionTwo.getAttributes().getPoolName()).thenReturn("TestPool");
|
||||
when(mockRegionTwo.getAttributes().getScope()).thenReturn(Scope.DISTRIBUTED_NO_ACK);
|
||||
when(mockRegionTwo.getAttributes().getStatisticsEnabled()).thenReturn(true);
|
||||
when(mockRegionTwo.getAttributes().getValueConstraint()).thenReturn((Class) String.class);
|
||||
|
||||
ExpirationAttributes mockIdleTimeoutEntryExpirationAttributes =
|
||||
mock(ExpirationAttributes.class, "Entry-TTI");
|
||||
|
||||
when(mockIdleTimeoutEntryExpirationAttributes.getAction()).thenReturn(ExpirationAction.INVALIDATE);
|
||||
when(mockIdleTimeoutEntryExpirationAttributes.getTimeout()).thenReturn(600);
|
||||
when(mockRegionTwo.getAttributes().getEntryIdleTimeout()).thenReturn(mockIdleTimeoutEntryExpirationAttributes);
|
||||
|
||||
ExpirationAttributes mockTimeToLiveEntryExpirationAttributes =
|
||||
mock(ExpirationAttributes.class, "Entry-TTL");
|
||||
|
||||
when(mockTimeToLiveEntryExpirationAttributes.getAction()).thenReturn(ExpirationAction.DESTROY);
|
||||
when(mockTimeToLiveEntryExpirationAttributes.getTimeout()).thenReturn(900);
|
||||
when(mockRegionTwo.getAttributes().getEntryTimeToLive()).thenReturn(mockTimeToLiveEntryExpirationAttributes);
|
||||
|
||||
CacheStatistics mockCacheStatistics = mock(CacheStatistics.class);
|
||||
|
||||
when(mockCacheStatistics.getHitCount()).thenReturn(202408L);
|
||||
when(mockCacheStatistics.getHitRatio()).thenReturn(0.82f);
|
||||
when(mockCacheStatistics.getLastAccessedTime()).thenReturn(1L);
|
||||
when(mockCacheStatistics.getLastModifiedTime()).thenReturn(2L);
|
||||
when(mockCacheStatistics.getMissCount()).thenReturn(767L);
|
||||
when(mockRegionTwo.getStatistics()).thenReturn(mockCacheStatistics);
|
||||
|
||||
Set<Region<?, ?>> mockRegions = asSet(mockRegionOne, mockRegionTwo);
|
||||
|
||||
when(this.mockGemFireCache.rootRegions()).thenReturn(mockRegions);
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
this.regionsHealthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
|
||||
Map<String, Object> healthDetails = health.getDetails();
|
||||
|
||||
assertThat(healthDetails).isNotNull();
|
||||
assertThat(healthDetails).isNotEmpty();
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions", Arrays.asList("/MockRegionOne", "/MockRegionTwo"));
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.count", (long) mockRegions.size());
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.cloning-enabled", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.data-policy", DataPolicy.PARTITION.toString());
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.initial-capacity", 101);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.load-factor", 0.75f);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.key-constraint", Long.class.getName());
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.off-heap", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.eviction.action", EvictionAction.LOCAL_DESTROY.toString());
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.eviction.algorithm", EvictionAlgorithm.LRU_ENTRY.toString());
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.eviction.maximum", 10000);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.partition.collocated-with", "CollocatedRegion");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.partition.local-max-memory", 10240);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.partition.redundant-copies", 2);
|
||||
//assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.partition.total-max-memory", 4096000L);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.partition.total-number-of-buckets", 226);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.pool-name", "");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.scope", Scope.DISTRIBUTED_ACK.toString());
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.statistics-enabled", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.value-constraint", Currency.class.getName());
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.cloning-enabled", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.data-policy", DataPolicy.EMPTY.toString());
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.initial-capacity", 0);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.load-factor", 0.0f);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.key-constraint", Integer.class.getName());
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.off-heap", "No");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.pool-name", "TestPool");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.scope", Scope.DISTRIBUTED_NO_ACK.toString());
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.statistics-enabled", "Yes");
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.expiration.entry.tti.action", ExpirationAction.INVALIDATE.toString());
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.expiration.entry.tti.timeout", 600);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.expiration.entry.ttl.action", ExpirationAction.DESTROY.toString());
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.expiration.entry.ttl.timeout", 900);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.statistics.hit-count", 202408L);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.statistics.hit-ratio", 0.82f);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.statistics.last-accessed-time", 1L);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.statistics.last-modified-time", 2L);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.statistics.miss-count", 767L);
|
||||
assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.value-constraint", String.class.getName());
|
||||
|
||||
verify(this.mockGemFireCache, times(1)).rootRegions();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheckFailsWhenGemFireCacheIsNotPresent() {
|
||||
|
||||
GeodeRegionsHealthIndicator healthIndicator = new GeodeRegionsHealthIndicator();
|
||||
|
||||
Health.Builder builder = new Health.Builder();
|
||||
|
||||
healthIndicator.doHealthCheck(builder);
|
||||
|
||||
Health health = builder.build();
|
||||
|
||||
assertThat(health).isNotNull();
|
||||
assertThat(health.getDetails()).isEmpty();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# This file is generated by the 'io.freefair.lombok' Gradle plugin
|
||||
config.stopBubbling = true
|
||||
lombok.addLombokGeneratedAnnotation = true
|
||||
@@ -0,0 +1,43 @@
|
||||
plugins {
|
||||
id "io.freefair.lombok" version "6.3.0"
|
||||
}
|
||||
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
description = "Spring Boot Auto-Configuration for Apache Geode"
|
||||
|
||||
dependencies {
|
||||
|
||||
api project(":spring-geode")
|
||||
|
||||
implementation "jakarta.annotation:jakarta.annotation-api"
|
||||
|
||||
compileOnly "com.google.code.findbugs:jsr305:$findbugsVersion"
|
||||
|
||||
optional project(':apache-geode-extensions')
|
||||
|
||||
optional "org.springframework.boot:spring-boot-autoconfigure-processor"
|
||||
optional "org.springframework.boot:spring-boot-configuration-processor"
|
||||
optional "org.springframework.session:spring-session-data-geode"
|
||||
|
||||
// See additional testImplementation dependencies declared in the testDependencies project extension
|
||||
// defined in the DependencySetPlugin.
|
||||
testImplementation "jakarta.servlet:jakarta.servlet-api"
|
||||
testImplementation "org.springframework.boot:spring-boot-starter-test"
|
||||
testImplementation "org.springframework.boot:spring-boot-starter-web"
|
||||
|
||||
testCompileOnly "com.google.code.findbugs:jsr305:$findbugsVersion"
|
||||
|
||||
testRuntimeOnly "javax.cache:cache-api"
|
||||
testRuntimeOnly "org.apache.geode:geode-http-service:$apacheGeodeVersion"
|
||||
testRuntimeOnly "org.apache.geode:geode-web:$apacheGeodeVersion"
|
||||
testRuntimeOnly "org.springframework.boot:spring-boot-starter-jetty"
|
||||
testRuntimeOnly "org.springframework.boot:spring-boot-starter-json"
|
||||
testRuntimeOnly "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
|
||||
// Runtime Test dependency on Spring Cloud Services (SCS) to verify workaround to SCS problem!
|
||||
//testRuntimeOnly("io.pivotal.spring.cloud:spring-cloud-services-starter-service-registry:2.0.3.RELEASE") {
|
||||
// exclude group: "org.apache.logging.log4j", module: "log4j-core"
|
||||
//}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.gemfire.CacheFactoryBean;
|
||||
import org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer;
|
||||
import org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer;
|
||||
import org.springframework.geode.boot.autoconfigure.condition.ConditionalOnMissingProperty;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} class used to configure the Apache Geode
|
||||
* {@link ClientCache} application or peer {@link Cache} member node name (i.e. {@literal gemfire.name})
|
||||
* with the Spring Boot {@literal spring.application.name} property.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.core.env.Environment
|
||||
* @see org.springframework.data.gemfire.CacheFactoryBean
|
||||
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
|
||||
* @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@ConditionalOnClass({ CacheFactoryBean.class, GemFireCache.class })
|
||||
@SuppressWarnings("unused")
|
||||
public class CacheNameAutoConfiguration {
|
||||
|
||||
private static final String GEMFIRE_NAME_PROPERTY = "name";
|
||||
private static final String SPRING_APPLICATION_NAME_PROPERTY = "spring.application.name";
|
||||
private static final String SPRING_DATA_GEMFIRE_CACHE_NAME_PROPERTY = "spring.data.gemfire.cache.name";
|
||||
private static final String SPRING_DATA_GEMFIRE_NAME_PROPERTY = "spring.data.gemfire.name";
|
||||
private static final String SPRING_DATA_GEODE_CACHE_NAME_PROPERTY = "spring.data.geode.cache.name";
|
||||
private static final String SPRING_DATA_GEODE_NAME_PROPERTY = "spring.data.geode.name";
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE + 1) // apply next (e.g. after @UseMemberName)
|
||||
@ConditionalOnMissingProperty({
|
||||
SPRING_DATA_GEMFIRE_CACHE_NAME_PROPERTY,
|
||||
SPRING_DATA_GEMFIRE_NAME_PROPERTY,
|
||||
SPRING_DATA_GEODE_CACHE_NAME_PROPERTY,
|
||||
SPRING_DATA_GEODE_NAME_PROPERTY,
|
||||
})
|
||||
ClientCacheConfigurer clientCacheNameConfigurer(Environment environment) {
|
||||
return (beanName, clientCacheFactoryBean) -> configureCacheName(environment, clientCacheFactoryBean);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE + 1) // apply next (e.g. after @UseMemberName)
|
||||
@ConditionalOnMissingProperty({
|
||||
SPRING_DATA_GEMFIRE_CACHE_NAME_PROPERTY,
|
||||
SPRING_DATA_GEMFIRE_NAME_PROPERTY,
|
||||
SPRING_DATA_GEODE_CACHE_NAME_PROPERTY,
|
||||
SPRING_DATA_GEODE_NAME_PROPERTY,
|
||||
})
|
||||
PeerCacheConfigurer peerCacheNameConfigurer(Environment environment) {
|
||||
return (beanName, peerCacheFactoryBean) -> configureCacheName(environment, peerCacheFactoryBean);
|
||||
}
|
||||
|
||||
private void configureCacheName(Environment environment, CacheFactoryBean cacheFactoryBean) {
|
||||
|
||||
String springApplicationName = resolveSpringApplicationName(environment);
|
||||
|
||||
if (StringUtils.hasText(springApplicationName)) {
|
||||
setGemFireName(cacheFactoryBean, springApplicationName);
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveSpringApplicationName(Environment environment) {
|
||||
|
||||
return Optional.ofNullable(environment)
|
||||
.filter(it -> it.containsProperty(SPRING_APPLICATION_NAME_PROPERTY))
|
||||
.map(it -> it.getProperty(SPRING_APPLICATION_NAME_PROPERTY))
|
||||
.filter(StringUtils::hasText)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private void setGemFireName(CacheFactoryBean cacheFactoryBean, String gemfireName) {
|
||||
cacheFactoryBean.getProperties().setProperty(GEMFIRE_NAME_PROPERTY, gemfireName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizers;
|
||||
import org.springframework.boot.autoconfigure.cache.CacheProperties;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.data.gemfire.cache.GemfireCacheManager;
|
||||
import org.springframework.data.gemfire.cache.config.EnableGemfireCaching;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} for Spring's Cache Abstraction
|
||||
* using Apache Geode as the caching provider.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see jakarta.annotation.PostConstruct
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.cache.CacheManagerCustomizers
|
||||
* @see org.springframework.boot.autoconfigure.cache.CacheProperties
|
||||
* @see org.springframework.cache.CacheManager
|
||||
* @see org.springframework.data.gemfire.cache.GemfireCacheManager
|
||||
* @see org.springframework.data.gemfire.cache.config.EnableGemfireCaching
|
||||
* @see org.springframework.geode.boot.autoconfigure.ClientCacheAutoConfiguration
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@AutoConfigureAfter(ClientCacheAutoConfiguration.class)
|
||||
@Conditional(CachingProviderAutoConfiguration.SpringCacheTypeCondition.class)
|
||||
@ConditionalOnBean(GemFireCache.class)
|
||||
@ConditionalOnClass({ GemfireCacheManager.class, GemFireCache.class })
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@EnableGemfireCaching
|
||||
@SuppressWarnings("unused")
|
||||
public class CachingProviderAutoConfiguration {
|
||||
|
||||
protected static final Set<String> SPRING_CACHE_TYPES = asSet("gemfire", "geode");
|
||||
|
||||
protected static final String SPRING_CACHE_TYPE_PROPERTY = "spring.cache.type";
|
||||
|
||||
private final CacheManagerCustomizers cacheManagerCustomizers;
|
||||
|
||||
private final CacheProperties cacheProperties;
|
||||
|
||||
@Autowired
|
||||
private GemfireCacheManager cacheManager;
|
||||
|
||||
CachingProviderAutoConfiguration(
|
||||
@Autowired(required = false) CacheProperties cacheProperties,
|
||||
@Autowired(required = false) CacheManagerCustomizers cacheManagerCustomizers) {
|
||||
|
||||
this.cacheProperties = cacheProperties;
|
||||
this.cacheManagerCustomizers = cacheManagerCustomizers;
|
||||
}
|
||||
|
||||
GemfireCacheManager getCacheManager() {
|
||||
|
||||
Assert.state(this.cacheManager != null, "GemfireCacheManager was not properly configured");
|
||||
|
||||
return this.cacheManager;
|
||||
}
|
||||
|
||||
Optional<CacheManagerCustomizers> getCacheManagerCustomizers() {
|
||||
return Optional.ofNullable(this.cacheManagerCustomizers);
|
||||
}
|
||||
|
||||
Optional<CacheProperties> getCacheProperties() {
|
||||
return Optional.ofNullable(this.cacheProperties);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void onGeodeCachingInitialization() {
|
||||
getCacheManagerCustomizers()
|
||||
.ifPresent(cacheManagerCustomizers -> cacheManagerCustomizers.customize(getCacheManager()));
|
||||
}
|
||||
|
||||
public static class SpringCacheTypeCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
|
||||
String springCacheType = context.getEnvironment().getProperty(SPRING_CACHE_TYPE_PROPERTY);
|
||||
|
||||
return !StringUtils.hasText(springCacheType) || SPRING_CACHE_TYPES.contains(springCacheType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.distributed.Locator;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
|
||||
import org.springframework.data.gemfire.config.annotation.ClientCacheApplication;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} for bootstrapping an Apache Geode {@link ClientCache}
|
||||
* instance constructed, configured and initialized with Spring Data for Apache Geode.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.distributed.Locator
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
|
||||
* @see org.springframework.data.gemfire.config.annotation.ClientCacheApplication
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@ConditionalOnClass({ ClientCacheFactoryBean.class, ClientCache.class })
|
||||
@ConditionalOnMissingBean({ GemFireCache.class, Locator.class })
|
||||
@ClientCacheApplication
|
||||
public class ClientCacheAutoConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.cloud.CloudPlatform;
|
||||
import org.springframework.boot.env.EnvironmentPostProcessor;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
|
||||
import org.springframework.data.gemfire.config.annotation.EnableSecurity;
|
||||
import org.springframework.data.gemfire.config.annotation.support.AutoConfiguredAuthenticationInitializer;
|
||||
import org.springframework.geode.core.env.VcapPropertySource;
|
||||
import org.springframework.geode.core.env.support.CloudCacheService;
|
||||
import org.springframework.geode.core.env.support.User;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} enabling Apache Geode's Security functionality,
|
||||
* and specifically Authentication between a client and server using Spring Data Geode Security annotations.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.Properties
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.springframework.boot.SpringApplication
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.AutoConfigureBefore
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.condition.AllNestedConditions
|
||||
* @see org.springframework.boot.autoconfigure.condition.AnyNestedCondition
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnClass
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||
* @see org.springframework.boot.cloud.CloudPlatform
|
||||
* @see org.springframework.boot.env.EnvironmentPostProcessor
|
||||
* @see org.springframework.context.annotation.Conditional
|
||||
* @see org.springframework.core.env.ConfigurableEnvironment
|
||||
* @see org.springframework.core.env.Environment
|
||||
* @see org.springframework.core.env.PropertySource
|
||||
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
|
||||
* @see org.springframework.data.gemfire.config.annotation.EnableSecurity
|
||||
* @see org.springframework.data.gemfire.config.annotation.support.AutoConfiguredAuthenticationInitializer
|
||||
* @see org.springframework.geode.boot.autoconfigure.ClientCacheAutoConfiguration
|
||||
* @see org.springframework.geode.core.env.VcapPropertySource
|
||||
* @see org.springframework.geode.core.env.support.CloudCacheService
|
||||
* @see org.springframework.geode.core.env.support.Service
|
||||
* @see org.springframework.geode.core.env.support.User
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@AutoConfigureBefore(ClientCacheAutoConfiguration.class)
|
||||
@Conditional(ClientSecurityAutoConfiguration.EnableSecurityCondition.class)
|
||||
@ConditionalOnClass({ ClientCacheFactoryBean.class, ClientCache.class })
|
||||
@ConditionalOnMissingBean(GemFireCache.class)
|
||||
@EnableSecurity
|
||||
//@Import(HttpBasicAuthenticationSecurityConfiguration.class)
|
||||
@SuppressWarnings("unused")
|
||||
public class ClientSecurityAutoConfiguration {
|
||||
|
||||
public static final String CLOUD_CACHE_SERVICE_INSTANCE_NAME_PROPERTY =
|
||||
"spring.boot.data.gemfire.cloud.cloudfoundry.service.cloudcache.name";
|
||||
|
||||
public static final String CLOUD_SECURITY_ENVIRONMENT_POST_PROCESSOR_ENABLED_PROPERTY =
|
||||
"spring.boot.data.gemfire.security.auth.environment.post-processor.enabled";
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ClientSecurityAutoConfiguration.class);
|
||||
|
||||
private static final String CLOUD_CACHE_PROPERTY_SOURCE_NAME = "boot.data.gemfire.cloudcache";
|
||||
|
||||
private static final String MANAGEMENT_HTTP_HOST_PROPERTY = "spring.data.gemfire.management.http.host";
|
||||
private static final String MANAGEMENT_HTTP_PORT_PROPERTY = "spring.data.gemfire.management.http.port";
|
||||
private static final String MANAGEMENT_REQUIRE_HTTPS_PROPERTY = "spring.data.gemfire.management.require-https";
|
||||
private static final String MANAGEMENT_USE_HTTP_PROPERTY = "spring.data.gemfire.management.use-http";
|
||||
|
||||
private static final String POOL_LOCATORS_PROPERTY = "spring.data.gemfire.pool.locators";
|
||||
|
||||
private static final String SECURITY_USERNAME_PROPERTY =
|
||||
AutoConfiguredAuthenticationInitializer.SDG_SECURITY_USERNAME_PROPERTY;
|
||||
|
||||
private static final String SECURITY_PASSWORD_PROPERTY =
|
||||
AutoConfiguredAuthenticationInitializer.SDG_SECURITY_PASSWORD_PROPERTY;
|
||||
|
||||
private static final String SSL_USE_DEFAULT_CONTEXT_PROPERTY =
|
||||
"spring.data.gemfire.security.ssl.use-default-context";
|
||||
|
||||
private static final String VCAP_PROPERTY_SOURCE_NAME = "vcap";
|
||||
|
||||
public static class AutoConfiguredCloudSecurityEnvironmentPostProcessor implements EnvironmentPostProcessor {
|
||||
|
||||
@Override
|
||||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
|
||||
|
||||
Optional.of(environment)
|
||||
.filter(this::isEnabled)
|
||||
.filter(this::isCloudFoundryEnvironment)
|
||||
.ifPresent(this::configureSecurityContext);
|
||||
}
|
||||
|
||||
private boolean isCloudFoundryEnvironment(Environment environment) {
|
||||
return CloudPlatform.CLOUD_FOUNDRY.isActive(environment);
|
||||
}
|
||||
|
||||
private boolean isEnabled(Environment environment) {
|
||||
|
||||
boolean clientSecurityAutoConfigurationEnabled =
|
||||
environment.getProperty(CLOUD_SECURITY_ENVIRONMENT_POST_PROCESSOR_ENABLED_PROPERTY,
|
||||
Boolean.class, true);
|
||||
|
||||
logger.debug("{} enabled? [{}]", ClientSecurityAutoConfiguration.class.getSimpleName(),
|
||||
clientSecurityAutoConfigurationEnabled);
|
||||
|
||||
return clientSecurityAutoConfigurationEnabled;
|
||||
}
|
||||
|
||||
private boolean isSecurityPropertiesSet(Environment environment) {
|
||||
|
||||
boolean securityPropertiesSet = environment.containsProperty(SECURITY_USERNAME_PROPERTY)
|
||||
&& environment.containsProperty(SECURITY_PASSWORD_PROPERTY);
|
||||
|
||||
logger.debug("Security Properties set? [{}]", securityPropertiesSet);
|
||||
|
||||
return securityPropertiesSet;
|
||||
}
|
||||
|
||||
private boolean isSecurityPropertiesNotSet(Environment environment) {
|
||||
return !isSecurityPropertiesSet(environment);
|
||||
}
|
||||
|
||||
private void configureAuthentication(Environment environment, VcapPropertySource vcapPropertySource,
|
||||
CloudCacheService cloudCacheService, Properties cloudCacheProperties) {
|
||||
|
||||
if (isSecurityPropertiesNotSet(environment)) {
|
||||
if (environment.containsProperty(SECURITY_USERNAME_PROPERTY)) {
|
||||
|
||||
String targetUsername = environment.getProperty(SECURITY_USERNAME_PROPERTY);
|
||||
|
||||
vcapPropertySource.findUserByName(cloudCacheService, targetUsername)
|
||||
.flatMap(User::getPassword)
|
||||
.map(password -> {
|
||||
|
||||
cloudCacheProperties.setProperty(SECURITY_USERNAME_PROPERTY, targetUsername);
|
||||
cloudCacheProperties.setProperty(SECURITY_PASSWORD_PROPERTY, password);
|
||||
|
||||
return password;
|
||||
|
||||
})
|
||||
.orElseThrow(() -> newIllegalStateException(
|
||||
"No User with name [%s] was configured for Cloud Cache service [%s]",
|
||||
targetUsername, cloudCacheService.getName()));
|
||||
}
|
||||
else {
|
||||
vcapPropertySource.findFirstUserByRoleClusterOperator(cloudCacheService)
|
||||
.ifPresent(user -> {
|
||||
|
||||
cloudCacheProperties.setProperty(SECURITY_USERNAME_PROPERTY, user.getName());
|
||||
|
||||
user.getPassword().ifPresent(password ->
|
||||
cloudCacheProperties.setProperty(SECURITY_PASSWORD_PROPERTY, password));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void configureLocators(Environment environment, VcapPropertySource vcapPropertySource,
|
||||
CloudCacheService cloudCacheService, Properties cloudCacheProperties) {
|
||||
|
||||
cloudCacheService.getLocators().ifPresent(locators ->
|
||||
cloudCacheProperties.setProperty(POOL_LOCATORS_PROPERTY, locators));
|
||||
}
|
||||
|
||||
private void configureManagementRestApiAccess(Environment environment, VcapPropertySource vcapPropertySource,
|
||||
CloudCacheService cloudCacheService, Properties cloudCacheProperties) {
|
||||
|
||||
cloudCacheService.getGfshUrl().ifPresent(url -> {
|
||||
cloudCacheProperties.setProperty(MANAGEMENT_HTTP_HOST_PROPERTY, url.getHost());
|
||||
cloudCacheProperties.setProperty(MANAGEMENT_HTTP_PORT_PROPERTY, String.valueOf(url.getPort()));
|
||||
cloudCacheProperties.setProperty(MANAGEMENT_REQUIRE_HTTPS_PROPERTY, Boolean.TRUE.toString());
|
||||
cloudCacheProperties.setProperty(MANAGEMENT_USE_HTTP_PROPERTY, Boolean.TRUE.toString());
|
||||
});
|
||||
}
|
||||
|
||||
private void configureSsl(Environment environment, VcapPropertySource vcapPropertySource,
|
||||
CloudCacheService cloudCacheService, Properties cloudCacheProperties) {
|
||||
|
||||
if (cloudCacheService.isTlsEnabled()) {
|
||||
cloudCacheProperties.setProperty(SSL_USE_DEFAULT_CONTEXT_PROPERTY, Boolean.TRUE.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void configureSecurityContext(ConfigurableEnvironment environment) {
|
||||
|
||||
String cloudcacheServiceInstanceName = environment.getProperty(CLOUD_CACHE_SERVICE_INSTANCE_NAME_PROPERTY);
|
||||
|
||||
VcapPropertySource vcapPropertySource = StringUtils.hasText(cloudcacheServiceInstanceName)
|
||||
? toVcapPropertySource(environment).withVcapServiceName(cloudcacheServiceInstanceName)
|
||||
: toVcapPropertySource(environment);
|
||||
|
||||
vcapPropertySource.findFirstCloudCacheService()
|
||||
.map(cloudCacheService -> {
|
||||
|
||||
Properties cloudCacheProperties = new Properties();
|
||||
|
||||
configureAuthentication(environment, vcapPropertySource, cloudCacheService, cloudCacheProperties);
|
||||
configureLocators(environment, vcapPropertySource, cloudCacheService, cloudCacheProperties);
|
||||
configureManagementRestApiAccess(environment, vcapPropertySource, cloudCacheService, cloudCacheProperties);
|
||||
configureSsl(environment, vcapPropertySource, cloudCacheService, cloudCacheProperties);
|
||||
|
||||
environment.getPropertySources()
|
||||
.addLast(newPropertySource(CLOUD_CACHE_PROPERTY_SOURCE_NAME, cloudCacheProperties));
|
||||
|
||||
return cloudCacheService;
|
||||
})
|
||||
.orElseGet(() -> {
|
||||
|
||||
if (StringUtils.hasText(cloudcacheServiceInstanceName)) {
|
||||
throw newIllegalStateException("No Cloud Cache service instance with name [%s] was found",
|
||||
cloudcacheServiceInstanceName);
|
||||
}
|
||||
else {
|
||||
logger.warn("No Cloud Cache service instance was found");
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private PropertySource<?> newPropertySource(String name, Properties properties) {
|
||||
return new SpringDataGemFirePropertiesPropertySource(name, properties);
|
||||
}
|
||||
|
||||
private VcapPropertySource toVcapPropertySource(Environment environment) {
|
||||
return VcapPropertySource.from(environment);
|
||||
}
|
||||
}
|
||||
|
||||
static class EnableSecurityCondition extends AllNestedConditions {
|
||||
|
||||
EnableSecurityCondition() {
|
||||
super(ConfigurationPhase.PARSE_CONFIGURATION);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(name = CLOUD_SECURITY_ENVIRONMENT_POST_PROCESSOR_ENABLED_PROPERTY,
|
||||
havingValue = "true", matchIfMissing = true)
|
||||
static class SpringBootDataGemFireSecurityAuthEnvironmentPostProcessorEnabled { }
|
||||
|
||||
@Conditional(SecurityTriggersCondition.class)
|
||||
static class AnySecurityTriggerCondition { }
|
||||
|
||||
}
|
||||
|
||||
static class SecurityTriggersCondition extends AnyNestedCondition {
|
||||
|
||||
SecurityTriggersCondition() {
|
||||
super(ConfigurationPhase.PARSE_CONFIGURATION);
|
||||
}
|
||||
|
||||
@ConditionalOnCloudPlatform(CloudPlatform.CLOUD_FOUNDRY)
|
||||
static class CloudPlatformSecurityContextCondition { }
|
||||
|
||||
@ConditionalOnProperty({
|
||||
"spring.data.gemfire.security.username",
|
||||
"spring.data.gemfire.security.password",
|
||||
})
|
||||
static class SpringDataGeodeSecurityContextCondition { }
|
||||
|
||||
@ConditionalOnProperty({
|
||||
"gemfire.security-username",
|
||||
"gemfire.security-password",
|
||||
})
|
||||
static class UsingApacheGeodeSecurityContextCondition { }
|
||||
|
||||
}
|
||||
|
||||
// This custom PropertySource is required to prevent Pivotal Spring Cloud Services
|
||||
// (spring-cloud-services-starter-service-registry) from losing the Apache Geode or Cloud Cache Security Context
|
||||
// credentials stored in the Environment.
|
||||
static class SpringDataGemFirePropertiesPropertySource extends PropertySource<Properties> {
|
||||
|
||||
private static final String SPRING_DATA_GEMFIRE_PROPERTIES_PROPERTY_SOURCE_NAME =
|
||||
"spring.data.gemfire.properties";
|
||||
|
||||
SpringDataGemFirePropertiesPropertySource(Properties springDataGemFireProperties) {
|
||||
this(SPRING_DATA_GEMFIRE_PROPERTIES_PROPERTY_SOURCE_NAME, springDataGemFireProperties);
|
||||
}
|
||||
|
||||
SpringDataGemFirePropertiesPropertySource(String name, Properties springDataGemFireProperties) {
|
||||
super(name, springDataGemFireProperties);
|
||||
}
|
||||
|
||||
@Nullable @Override
|
||||
public Object getProperty(String name) {
|
||||
return getSource().getProperty(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsProperty(String name) {
|
||||
return getSource().containsKey(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
|
||||
import org.springframework.data.gemfire.config.annotation.EnableContinuousQueries;
|
||||
import org.springframework.geode.boot.autoconfigure.support.EnableSubscriptionConfiguration;
|
||||
import org.springframework.geode.config.annotation.ClusterAvailableConfiguration;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} enabling Apache Geode's Continuous Query (CQ)
|
||||
* functionality in a {@link ClientCache} application.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.context.annotation.Conditional
|
||||
* @see org.springframework.context.annotation.Import
|
||||
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
|
||||
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
|
||||
* @see org.springframework.data.gemfire.config.annotation.EnableContinuousQueries
|
||||
* @see org.springframework.geode.boot.autoconfigure.support.EnableSubscriptionConfiguration
|
||||
* @see org.springframework.geode.config.annotation.ClusterAvailableConfiguration.AnyClusterAvailableCondition
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@Conditional(ClusterAvailableConfiguration.AnyClusterAvailableCondition.class)
|
||||
@ConditionalOnBean(ClientCacheFactoryBean.class)
|
||||
@ConditionalOnMissingBean(name = "continuousQueryBeanPostProcessor",
|
||||
type = "org.springframework.data.gemfire.listener.ContinuousQueryListenerContainer")
|
||||
@EnableContinuousQueries
|
||||
@Import(EnableSubscriptionConfiguration.class)
|
||||
@SuppressWarnings("unused")
|
||||
public class ContinuousQueryAutoConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.env.EnvironmentPostProcessor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.data.gemfire.CacheFactoryBean;
|
||||
import org.springframework.geode.boot.autoconfigure.support.PdxInstanceWrapperRegionAspect;
|
||||
import org.springframework.geode.cache.SimpleCacheResolver;
|
||||
import org.springframework.geode.data.AbstractCacheDataImporterExporter;
|
||||
import org.springframework.geode.data.CacheDataImporterExporter;
|
||||
import org.springframework.geode.data.json.JsonCacheDataImporterExporter;
|
||||
import org.springframework.geode.data.support.LifecycleAwareCacheDataImporterExporter;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} for cache data import/export.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.condition.AnyNestedCondition
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnBean
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnClass
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.context.annotation.Condition
|
||||
* @see org.springframework.context.annotation.Conditional
|
||||
* @see org.springframework.core.env.ConfigurableEnvironment
|
||||
* @see org.springframework.core.env.Environment
|
||||
* @see org.springframework.data.gemfire.CacheFactoryBean
|
||||
* @see org.springframework.geode.boot.autoconfigure.support.PdxInstanceWrapperRegionAspect
|
||||
* @see org.springframework.geode.data.CacheDataImporterExporter
|
||||
* @see org.springframework.geode.data.json.JsonCacheDataImporterExporter
|
||||
* @see org.springframework.geode.data.support.LifecycleAwareCacheDataImporterExporter
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@ConditionalOnBean(GemFireCache.class)
|
||||
@ConditionalOnClass({ CacheFactoryBean.class, GemFireCache.class })
|
||||
@SuppressWarnings("unused")
|
||||
public class DataImportExportAutoConfiguration {
|
||||
|
||||
protected static final String GEMFIRE_DISABLE_SHUTDOWN_HOOK = "gemfire.disableShutdownHook";
|
||||
protected static final String PDX_READ_SERIALIZED_PROPERTY = "spring.data.gemfire.pdx.read-serialized";
|
||||
protected static final String REGION_ADVICE_ENABLED_PROPERTY =
|
||||
"spring.boot.data.gemfire.cache.region.advice.enabled";
|
||||
|
||||
@Bean
|
||||
CacheDataImporterExporter jsonCacheDataImporterExporter() {
|
||||
return new LifecycleAwareCacheDataImporterExporter(newCacheDataImporterExporter());
|
||||
}
|
||||
|
||||
protected CacheDataImporterExporter newCacheDataImporterExporter() {
|
||||
return new JsonCacheDataImporterExporter();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(RegionAdviceConditions.class)
|
||||
PdxInstanceWrapperRegionAspect pdxInstanceWrapperAspect() {
|
||||
return new PdxInstanceWrapperRegionAspect();
|
||||
}
|
||||
|
||||
static class RegionAdviceConditions extends AnyNestedCondition {
|
||||
|
||||
RegionAdviceConditions() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(name = REGION_ADVICE_ENABLED_PROPERTY, havingValue = "true")
|
||||
static class AdviseRegionOnRegionAdviceEnabledProperty { }
|
||||
|
||||
@Conditional(PdxReadSerializedCondition.class)
|
||||
static class AdviseRegionOnPdxReadSerializedCondition { }
|
||||
|
||||
}
|
||||
|
||||
static class PdxReadSerializedCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
return isPdxReadSerializedEnabled(context.getEnvironment()) || isCachePdxReadSerializedEnabled();
|
||||
}
|
||||
|
||||
private boolean isCachePdxReadSerializedEnabled() {
|
||||
|
||||
return SimpleCacheResolver.getInstance().resolve()
|
||||
.filter(GemFireCache::getPdxReadSerialized)
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
private boolean isPdxReadSerializedEnabled(@NonNull Environment environment) {
|
||||
|
||||
return Optional.ofNullable(environment)
|
||||
.filter(env -> env.getProperty(PDX_READ_SERIALIZED_PROPERTY, Boolean.class, false))
|
||||
.isPresent();
|
||||
}
|
||||
}
|
||||
|
||||
private static final boolean DEFAULT_EXPORT_ENABLED = false;
|
||||
|
||||
private static final Predicate<Environment> disableGemFireShutdownHookPredicate = environment ->
|
||||
Optional.ofNullable(environment)
|
||||
.filter(env -> env.getProperty(CacheDataImporterExporterReference.EXPORT_ENABLED_PROPERTY_NAME,
|
||||
Boolean.class, DEFAULT_EXPORT_ENABLED))
|
||||
.isPresent();
|
||||
|
||||
static abstract class AbstractDisableGemFireShutdownHookSupport {
|
||||
|
||||
boolean shouldDisableGemFireShutdownHook(@Nullable Environment environment) {
|
||||
return disableGemFireShutdownHookPredicate.test(environment);
|
||||
}
|
||||
|
||||
/**
|
||||
* If we do not disable Apache Geode's {@link org.apache.geode.distributed.DistributedSystem} JRE/JVM runtime
|
||||
* shutdown hook then the {@link org.apache.geode.cache.Region} is prematurely closed by the JRE/JVM shutdown hook
|
||||
* before Spring's {@link org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor}s can do
|
||||
* their work of exporting data from the {@link org.apache.geode.cache.Region} as JSON.
|
||||
*/
|
||||
void disableGemFireShutdownHook(@Nullable Environment environment) {
|
||||
System.setProperty(GEMFIRE_DISABLE_SHUTDOWN_HOOK, Boolean.TRUE.toString());
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class CacheDataImporterExporterReference extends AbstractCacheDataImporterExporter {
|
||||
static final String EXPORT_ENABLED_PROPERTY_NAME =
|
||||
AbstractCacheDataImporterExporter.CACHE_DATA_EXPORT_ENABLED_PROPERTY_NAME;
|
||||
}
|
||||
|
||||
static class DisableGemFireShutdownHookCondition extends AbstractDisableGemFireShutdownHookSupport
|
||||
implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
return shouldDisableGemFireShutdownHook(context.getEnvironment());
|
||||
}
|
||||
}
|
||||
|
||||
public static class DisableGemFireShutdownHookEnvironmentPostProcessor
|
||||
extends AbstractDisableGemFireShutdownHookSupport implements EnvironmentPostProcessor {
|
||||
|
||||
@Override
|
||||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
|
||||
|
||||
if (shouldDisableGemFireShutdownHook(environment)) {
|
||||
disableGemFireShutdownHook(environment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.data.gemfire.CacheFactoryBean;
|
||||
import org.springframework.data.gemfire.GemFireProperties;
|
||||
import org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer;
|
||||
import org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer;
|
||||
import org.springframework.data.gemfire.util.ArrayUtils;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} enabling the processing of
|
||||
* {@literal gemfire.properties}, or Geode {@link Properties} declared in Spring Boot {@literal application.properties}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.Properties
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.core.Ordered
|
||||
* @see org.springframework.core.annotation.Order
|
||||
* @see org.springframework.core.env.ConfigurableEnvironment
|
||||
* @see org.springframework.core.env.EnumerablePropertySource
|
||||
* @see org.springframework.core.env.MutablePropertySources
|
||||
* @see org.springframework.data.gemfire.CacheFactoryBean
|
||||
* @see org.springframework.data.gemfire.GemFireProperties
|
||||
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
|
||||
* @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer
|
||||
* @see <a href="https://geode.apache.org/docs/guide/112/reference/topics/gemfire_properties.html">Geode Properties</a>
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@ConditionalOnClass({ GemFireCache.class, CacheFactoryBean.class })
|
||||
@AutoConfigureBefore({ ClientCacheAutoConfiguration.class })
|
||||
@SuppressWarnings("unused")
|
||||
public class EnvironmentSourcedGemFirePropertiesAutoConfiguration {
|
||||
|
||||
private static final String GEMFIRE_PROPERTY_PREFIX = GemFireProperties.PROPERTY_NAME_PREFIX;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(EnvironmentSourcedGemFirePropertiesAutoConfiguration.class);
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
@SuppressWarnings("all")
|
||||
public ClientCacheConfigurer clientCacheGemFirePropertiesConfigurer(ConfigurableEnvironment environment) {
|
||||
return (beanName, bean) -> configureGemFireProperties(environment, bean);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
@SuppressWarnings("all")
|
||||
public PeerCacheConfigurer peerCacheGemFirePropertiesConfigurer(ConfigurableEnvironment environment) {
|
||||
return (beanName, bean) -> configureGemFireProperties(environment, bean);
|
||||
}
|
||||
|
||||
protected void configureGemFireProperties(@NonNull ConfigurableEnvironment environment,
|
||||
@NonNull CacheFactoryBean cache) {
|
||||
|
||||
Assert.notNull(environment, "Environment must not be null");
|
||||
Assert.notNull(cache, "CacheFactoryBean must not be null");
|
||||
|
||||
MutablePropertySources propertySources = environment.getPropertySources();
|
||||
|
||||
if (propertySources != null) {
|
||||
|
||||
Set<String> gemfirePropertyNames = propertySources.stream()
|
||||
.filter(EnumerablePropertySource.class::isInstance)
|
||||
.map(EnumerablePropertySource.class::cast)
|
||||
.map(EnumerablePropertySource::getPropertyNames)
|
||||
.map(propertyNamesArray -> ArrayUtils.nullSafeArray(propertyNamesArray, String.class))
|
||||
.flatMap(Arrays::stream)
|
||||
.filter(this::isGemFireDotPrefixedProperty)
|
||||
.filter(this::isValidGemFireProperty)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Properties gemfireProperties = cache.getProperties();
|
||||
|
||||
gemfirePropertyNames.stream()
|
||||
.filter(gemfirePropertyName -> isNotSet(gemfireProperties, gemfirePropertyName))
|
||||
.filter(this::isValidGemFireProperty)
|
||||
.forEach(gemfirePropertyName -> {
|
||||
|
||||
String propertyName = normalizeGemFirePropertyName(gemfirePropertyName);
|
||||
String propertyValue = environment.getProperty(gemfirePropertyName);
|
||||
|
||||
if (StringUtils.hasText(propertyValue)) {
|
||||
gemfireProperties.setProperty(propertyName, propertyValue);
|
||||
}
|
||||
else {
|
||||
getLogger().warn("Apache Geode Property [{}] was not set", propertyName);
|
||||
}
|
||||
});
|
||||
|
||||
cache.setProperties(gemfireProperties);
|
||||
}
|
||||
}
|
||||
|
||||
protected Logger getLogger() {
|
||||
return this.logger;
|
||||
}
|
||||
|
||||
private boolean isGemFireDotPrefixedProperty(@NonNull String propertyName) {
|
||||
return StringUtils.hasText(propertyName) && propertyName.startsWith(GEMFIRE_PROPERTY_PREFIX);
|
||||
}
|
||||
|
||||
private boolean isNotSet(Properties gemfireProperties, String propertyName) {
|
||||
return !gemfireProperties.containsKey(normalizeGemFirePropertyName(propertyName));
|
||||
}
|
||||
|
||||
private boolean isValidGemFireProperty(String propertyName) {
|
||||
try {
|
||||
GemFireProperties.from(normalizeGemFirePropertyName(propertyName));
|
||||
return true;
|
||||
}
|
||||
catch (IllegalArgumentException cause) {
|
||||
getLogger().warn(String.format("[%s] is not a valid Apache Geode property", propertyName));
|
||||
// TODO: uncomment line below and replace line above when SBDG is rebased on SDG 2.3.0.RC2 or later.
|
||||
//getLogger().warn(cause.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private String normalizeGemFirePropertyName(@NonNull String propertyName) {
|
||||
|
||||
int index = propertyName.lastIndexOf(".");
|
||||
|
||||
return index > -1 ? propertyName.substring(index + 1) : propertyName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.gemfire.function.config.EnableGemfireFunctions;
|
||||
import org.springframework.data.gemfire.function.execution.GemfireFunctionOperations;
|
||||
import org.springframework.geode.function.config.GemFireFunctionExecutionAutoConfigurationRegistrar;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} enabling Apache Geode's Function Execution
|
||||
* functionality in a {@link GemFireCache} application.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.context.annotation.Import
|
||||
* @see org.springframework.data.gemfire.function.config.EnableGemfireFunctions
|
||||
* @see org.springframework.data.gemfire.function.config.EnableGemfireFunctionExecutions
|
||||
* @see org.springframework.geode.function.config.GemFireFunctionExecutionAutoConfigurationRegistrar
|
||||
* @see org.springframework.data.gemfire.function.execution.GemfireFunctionOperations
|
||||
* @see org.springframework.geode.boot.autoconfigure.ClientCacheAutoConfiguration
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@AutoConfigureAfter(ClientCacheAutoConfiguration.class)
|
||||
@ConditionalOnBean(GemFireCache.class)
|
||||
@ConditionalOnClass({ GemfireFunctionOperations.class, GemFireCache.class })
|
||||
@EnableGemfireFunctions
|
||||
@Import(GemFireFunctionExecutionAutoConfigurationRegistrar.class)
|
||||
@SuppressWarnings("unused")
|
||||
public class FunctionExecutionAutoConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.gemfire.CacheFactoryBean;
|
||||
import org.springframework.geode.boot.autoconfigure.configuration.GemFireProperties;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} class used to configure Spring Boot
|
||||
* {@link ConfigurationProperties} classes and beans from the Spring {@link Environment} containing Apache Geode
|
||||
* configuration properties.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.boot.context.properties.ConfigurationProperties
|
||||
* @see org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
* @see org.springframework.core.env.Environment
|
||||
* @see org.springframework.data.gemfire.CacheFactoryBean
|
||||
* @see org.springframework.geode.boot.autoconfigure.configuration.GemFireProperties
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@ConditionalOnBean(GemFireCache.class)
|
||||
@ConditionalOnClass({ GemFireCache.class, CacheFactoryBean.class })
|
||||
@EnableConfigurationProperties({ GemFireProperties.class })
|
||||
@SuppressWarnings("unused")
|
||||
public class GemFirePropertiesAutoConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.data.gemfire.repository.config.EnableGemfireRepositories;
|
||||
import org.springframework.data.gemfire.repository.config.GemfireRepositoryConfigurationExtension;
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
|
||||
|
||||
/**
|
||||
* Spring {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Geode Repositories.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport
|
||||
* @see org.springframework.data.gemfire.repository.config.EnableGemfireRepositories
|
||||
* @see org.springframework.data.gemfire.repository.config.GemfireRepositoryConfigurationExtension
|
||||
* @see org.springframework.geode.boot.autoconfigure.RepositoriesAutoConfiguration
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class GemFireRepositoriesAutoConfigurationRegistrar extends AbstractRepositoryConfigurationSourceSupport {
|
||||
|
||||
@Override
|
||||
protected Class<? extends Annotation> getAnnotation() {
|
||||
return EnableGemfireRepositories.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getConfiguration() {
|
||||
return EnableGemFireRepositoriesConfiguration.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {
|
||||
return new GemfireRepositoryConfigurationExtension();
|
||||
}
|
||||
|
||||
@EnableGemfireRepositories
|
||||
private static class EnableGemFireRepositoriesConfiguration { }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.data.gemfire.CacheFactoryBean;
|
||||
import org.springframework.data.gemfire.config.annotation.EnableLogging;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-Configuration} for Apache Geode logging.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnBean
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnClass
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
* @see org.springframework.data.gemfire.CacheFactoryBean
|
||||
* @see org.springframework.data.gemfire.config.annotation.EnableLogging
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@ConditionalOnBean(GemFireCache.class)
|
||||
@ConditionalOnClass(CacheFactoryBean.class)
|
||||
@ConditionalOnMissingBean(name = {
|
||||
"org.springframework.data.gemfire.config.annotation.LoggingConfiguration.ClientGemFirePropertiesConfigurer",
|
||||
"org.springframework.data.gemfire.config.annotation.LoggingConfiguration.LocatorGemFirePropertiesConfigurer",
|
||||
"org.springframework.data.gemfire.config.annotation.LoggingConfiguration.PeerGemFirePropertiesConfigurer",
|
||||
})
|
||||
@EnableLogging
|
||||
@SuppressWarnings("unused")
|
||||
// TODO Find a more reliable way to refer to the LoggingConfiguration Configurer beans defined above other than by name!
|
||||
public class LoggingAutoConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.data.gemfire.config.annotation.EnablePdx;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} enabling Apache Geode's PDX Serialization
|
||||
* functionality in a either a {@link Cache peer cache} or {@link ClientCache} application.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.data.gemfire.config.annotation.EnablePdx
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@ConditionalOnBean(GemFireCache.class)
|
||||
@ConditionalOnMissingBean(
|
||||
name = { "clientCachePdxConfigurer", "peerCachePdxConfigurer" },
|
||||
type = "org.springframework.data.gemfire.config.support.PdxDiskStoreAwareBeanFactoryPostProcessor"
|
||||
)
|
||||
@EnablePdx
|
||||
public class PdxSerializationAutoConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
|
||||
import org.springframework.data.gemfire.config.annotation.ApacheShiroSecurityConfiguration;
|
||||
import org.springframework.data.gemfire.config.annotation.GeodeIntegratedSecurityConfiguration;
|
||||
import org.springframework.geode.config.annotation.EnableSecurityManager;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} enabling Apache Geode's Security functionality,
|
||||
* and specifically Authentication between a client and server using Spring Data Geode Security annotations.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.security.SecurityManager
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.context.annotation.Import
|
||||
* @see org.springframework.data.gemfire.CacheFactoryBean
|
||||
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
|
||||
* @see org.springframework.data.gemfire.config.annotation.ApacheShiroSecurityConfiguration
|
||||
* @see org.springframework.data.gemfire.config.annotation.GeodeIntegratedSecurityConfiguration
|
||||
* @see org.springframework.geode.config.annotation.EnableSecurityManager
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@ConditionalOnBean(org.apache.geode.security.SecurityManager.class)
|
||||
@ConditionalOnMissingBean({
|
||||
ClientCacheFactoryBean.class,
|
||||
ApacheShiroSecurityConfiguration.class,
|
||||
GeodeIntegratedSecurityConfiguration.class
|
||||
})
|
||||
@EnableSecurityManager
|
||||
//@Import(HttpBasicAuthenticationSecurityConfiguration.class)
|
||||
@SuppressWarnings("unused")
|
||||
public class PeerSecurityAutoConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.type.StandardMethodMetadata;
|
||||
import org.springframework.data.gemfire.GemfireOperations;
|
||||
import org.springframework.data.gemfire.GemfireTemplate;
|
||||
import org.springframework.data.gemfire.GemfireUtils;
|
||||
import org.springframework.data.gemfire.ResolvableRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.config.xml.GemfireConstants;
|
||||
import org.springframework.data.gemfire.util.ArrayUtils;
|
||||
import org.springframework.data.gemfire.util.CollectionUtils;
|
||||
import org.springframework.data.gemfire.util.SpringUtils;
|
||||
import org.springframework.geode.config.annotation.support.TypelessAnnotationConfigSupport;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} class used to configure a {@link GemfireTemplate}
|
||||
* for each Apache Geode cache {@link Region} declared/defined in the Spring {@link ConfigurableApplicationContext}
|
||||
* in order to perform {@link Region} data access operations.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.springframework.beans.factory.BeanFactory
|
||||
* @see org.springframework.beans.factory.config.BeanDefinition
|
||||
* @see org.springframework.beans.factory.config.BeanFactoryPostProcessor
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory
|
||||
* @see org.springframework.beans.factory.support.BeanDefinitionBuilder
|
||||
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.AutoConfigureAfter
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnBean
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnClass
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see org.springframework.context.ConfigurableApplicationContext
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.context.event.EventListener
|
||||
* @see org.springframework.data.gemfire.GemfireTemplate
|
||||
* @see org.springframework.data.gemfire.ResolvableRegionFactoryBean
|
||||
* @see org.springframework.geode.config.annotation.support.TypelessAnnotationConfigSupport
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@AutoConfigureAfter(ClientCacheAutoConfiguration.class)
|
||||
@ConditionalOnBean(GemFireCache.class)
|
||||
@ConditionalOnClass(GemfireTemplate.class)
|
||||
@SuppressWarnings("unused")
|
||||
public class RegionTemplateAutoConfiguration extends TypelessAnnotationConfigSupport {
|
||||
|
||||
private static final Object NON_BEAN = new Object();
|
||||
|
||||
private static final String TEMPLATE = "Template";
|
||||
|
||||
private final Set<String> autoConfiguredRegionTemplateBeanNames = Collections.synchronizedSet(new HashSet<>());
|
||||
private final Set<String> regionNamesWithTemplates = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
@Bean
|
||||
BeanFactoryPostProcessor regionTemplateBeanFactoryPostProcessor() {
|
||||
|
||||
return beanFactory -> {
|
||||
|
||||
if (beanFactory instanceof BeanDefinitionRegistry) {
|
||||
|
||||
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
|
||||
|
||||
List<String> beanDefinitionNames =
|
||||
Arrays.asList(ArrayUtils.nullSafeArray(registry.getBeanDefinitionNames(), String.class));
|
||||
|
||||
Set<String> userRegionTemplateNames = new HashSet<>();
|
||||
|
||||
for (String beanName : beanDefinitionNames) {
|
||||
|
||||
String regionTemplateBeanName = toRegionTemplateBeanName(beanName);
|
||||
|
||||
if (!beanDefinitionNames.contains(regionTemplateBeanName)) {
|
||||
|
||||
BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
|
||||
|
||||
Class<?> resolvedBeanType = resolveBeanClass(beanDefinition, registry).orElse(null);
|
||||
|
||||
if (isRegionBeanDefinition(resolvedBeanType)) {
|
||||
register(newGemfireTemplateBeanDefinition(beanName), regionTemplateBeanName, registry);
|
||||
}
|
||||
else if (isGemfireTemplateBeanDefinition(resolvedBeanType)) {
|
||||
userRegionTemplateNames.add(beanName);
|
||||
}
|
||||
else if (isBeanWithGemfireTemplateDependency(beanFactory, beanDefinition)) {
|
||||
SpringUtils.addDependsOn(beanDefinition, GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setAutoConfiguredRegionTemplateDependencies(registry, userRegionTemplateNames);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isBeanWithGemfireTemplateDependency(@NonNull BeanFactory beanFactory,
|
||||
@NonNull BeanDefinition beanDefinition) {
|
||||
|
||||
Predicate<Object> isGemfireTemplate = value -> value instanceof RuntimeBeanReference
|
||||
? beanFactory.isTypeMatch(((RuntimeBeanReference) value).getBeanName(), GemfireOperations.class)
|
||||
: value instanceof GemfireOperations;
|
||||
|
||||
boolean match = beanDefinition.getConstructorArgumentValues().getGenericArgumentValues().stream()
|
||||
.map(ConstructorArgumentValues.ValueHolder::getValue)
|
||||
.anyMatch(isGemfireTemplate);
|
||||
|
||||
match |= match || beanDefinition.getPropertyValues().getPropertyValueList().stream()
|
||||
.map(PropertyValue::getValue)
|
||||
.anyMatch(isGemfireTemplate);
|
||||
|
||||
match |= match || Optional.of(beanDefinition)
|
||||
.filter(AnnotatedBeanDefinition.class::isInstance)
|
||||
.map(AnnotatedBeanDefinition.class::cast)
|
||||
.map(AnnotatedBeanDefinition::getFactoryMethodMetadata)
|
||||
.filter(StandardMethodMetadata.class::isInstance)
|
||||
.map(StandardMethodMetadata.class::cast)
|
||||
.map(StandardMethodMetadata::getIntrospectedMethod)
|
||||
.map(method -> Arrays.stream(ArrayUtils.nullSafeArray(method.getParameterTypes(), Class.class))
|
||||
.filter(Objects::nonNull)
|
||||
.anyMatch(GemfireOperations.class::isAssignableFrom)
|
||||
).orElse(false);
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
private boolean isGemfireTemplateBeanDefinition(@Nullable Class<?> beanType) {
|
||||
return beanType != null && GemfireOperations.class.isAssignableFrom(beanType);
|
||||
}
|
||||
|
||||
private boolean isRegionBeanDefinition(@Nullable Class<?> beanType) {
|
||||
return beanType != null && ResolvableRegionFactoryBean.class.isAssignableFrom(beanType);
|
||||
}
|
||||
|
||||
private BeanDefinition newGemfireTemplateBeanDefinition(String regionBeanName) {
|
||||
|
||||
BeanDefinitionBuilder builder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(GemfireTemplate.class);
|
||||
|
||||
builder.addConstructorArgReference(regionBeanName);
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
// Register BeanDefinition with bean name in BeanDefinitionRegistry
|
||||
private boolean register(BeanDefinition beanDefinition, String beanName, BeanDefinitionRegistry registry) {
|
||||
|
||||
if (this.autoConfiguredRegionTemplateBeanNames.add(beanName)) {
|
||||
registry.registerBeanDefinition(beanName, beanDefinition);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setAutoConfiguredRegionTemplateDependencies(BeanDefinitionRegistry registry,
|
||||
Set<String> dependencyBeanNames) {
|
||||
|
||||
String[] dependencyBeanNamesArray = dependencyBeanNames.toArray(new String[0]);
|
||||
|
||||
this.autoConfiguredRegionTemplateBeanNames.stream()
|
||||
.map(registry::getBeanDefinition)
|
||||
.forEach(beanDefinition -> SpringUtils.addDependsOn(beanDefinition, dependencyBeanNamesArray));
|
||||
}
|
||||
|
||||
// Required by @EnableClusterDefinedRegions & Native-Defined Regions (e.g. Regions defined in "cache.xml").
|
||||
@Bean
|
||||
BeanPostProcessor regionTemplateBeanPostProcessor(ConfigurableApplicationContext applicationContext) {
|
||||
|
||||
handlePrematureCacheCreation(applicationContext);
|
||||
|
||||
return new BeanPostProcessor() {
|
||||
|
||||
/**
|
||||
* User-defined {@link GemfireTemplate} beans should be post processed before
|
||||
* auto-configured {@link GemfireTemplate} beans!
|
||||
*
|
||||
* @see RegionTemplateAutoConfiguration#setAutoConfiguredRegionTemplateDependencies(BeanDefinitionRegistry, Set)
|
||||
*/
|
||||
@Nullable @Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
|
||||
if (bean instanceof GemfireTemplate) {
|
||||
if (autoConfiguredRegionTemplateBeanNames.contains(beanName)) {
|
||||
if (regionNamesWithTemplates.contains(((GemfireTemplate) bean).getRegion().getName())) {
|
||||
// Returning NO_BEAN means an existing, user-defined GemfireTemplate bean already exists
|
||||
// for the target Region and the auto-configured GemfireTemplate bean is not required.
|
||||
bean = NON_BEAN;
|
||||
}
|
||||
}
|
||||
else {
|
||||
regionNamesWithTemplates.add(((GemfireTemplate) bean).getRegion().getName());
|
||||
}
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
|
||||
if (bean instanceof GemFireCache) {
|
||||
|
||||
GemFireCache cache = (GemFireCache) bean;
|
||||
|
||||
registerRegionTemplatesForCacheRegions(applicationContext, cache);
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Remove this logic when DATAGEODE-231 is resolved!
|
||||
private void handlePrematureCacheCreation(ConfigurableApplicationContext applicationContext) {
|
||||
|
||||
Optional.ofNullable(GemfireUtils.resolveGemFireCache())
|
||||
.ifPresent(cache -> registerRegionTemplatesForCacheRegions(applicationContext, cache));
|
||||
}
|
||||
|
||||
// Required by @EnableCachingDefinedRegions
|
||||
@EventListener({ ContextRefreshedEvent.class })
|
||||
public void regionTemplateContextRefreshedEventListener(ContextRefreshedEvent event) {
|
||||
|
||||
this.regionNamesWithTemplates.clear();
|
||||
|
||||
ApplicationContext applicationContext = event.getApplicationContext();
|
||||
|
||||
if (applicationContext instanceof ConfigurableApplicationContext) {
|
||||
|
||||
ConfigurableApplicationContext configurableApplicationContext =
|
||||
(ConfigurableApplicationContext) applicationContext;
|
||||
|
||||
GemFireCache cache = configurableApplicationContext.getBean(GemFireCache.class);
|
||||
|
||||
registerRegionTemplatesForCacheRegions(configurableApplicationContext, cache);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerRegionTemplatesForCacheRegions(@NonNull ConfigurableApplicationContext applicationContext,
|
||||
@NonNull GemFireCache cache) {
|
||||
|
||||
for (Region<?, ?> region : CollectionUtils.nullSafeSet(cache.rootRegions())) {
|
||||
|
||||
String regionTemplateBeanName = toRegionTemplateBeanName(region.getName());
|
||||
|
||||
registerRegionTemplateBean(applicationContext, region, regionTemplateBeanName);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerRegionTemplateBean(@NonNull ConfigurableApplicationContext applicationContext,
|
||||
@NonNull Region<?, ?> region, String regionTemplateBeanName) {
|
||||
|
||||
Optional.of(applicationContext)
|
||||
.filter(it -> isNotBean(it, regionTemplateBeanName))
|
||||
.map(ConfigurableApplicationContext::getBeanFactory)
|
||||
.ifPresent(beanFactory -> register(newGemfireTemplate(region), regionTemplateBeanName, beanFactory));
|
||||
}
|
||||
|
||||
private boolean isNotBean(@NonNull ApplicationContext applicationContext, @Nullable String beanName) {
|
||||
return !(StringUtils.hasText(beanName) && applicationContext.containsBean(beanName));
|
||||
}
|
||||
|
||||
private GemfireTemplate newGemfireTemplate(@NonNull Region<?, ?> region) {
|
||||
return new GemfireTemplate(region);
|
||||
}
|
||||
|
||||
// Register Singleton Object with bean name in BeanDefinitionRegistry
|
||||
private void register(Object singletonObject, String beanName, ConfigurableBeanFactory beanFactory) {
|
||||
|
||||
if (this.autoConfiguredRegionTemplateBeanNames.add(beanName)) {
|
||||
beanFactory.registerSingleton(beanName, singletonObject);
|
||||
}
|
||||
}
|
||||
|
||||
private String toRegionTemplateBeanName(@NonNull String regionName) {
|
||||
return StringUtils.uncapitalize(regionName) + TEMPLATE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.gemfire.repository.GemfireRepository;
|
||||
import org.springframework.data.gemfire.repository.config.EnableGemfireRepositories;
|
||||
import org.springframework.data.gemfire.repository.config.GemfireRepositoryConfigurationExtension;
|
||||
import org.springframework.data.gemfire.repository.support.GemfireRepositoryFactoryBean;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} for Spring Data for Apache Geode (SDG) Repositories.
|
||||
*
|
||||
* Activates when there is a bean of type {@link Cache} or {@link ClientCache} configured in the Spring context,
|
||||
* the Spring Data Geode {@link GemfireRepository} type is on the classpath, and no other existing
|
||||
* {@link GemfireRepository GemfireRepositories} are configured.
|
||||
*
|
||||
* Once in effect, the auto-configuration is the equivalent of enabling Geode Repositories using the
|
||||
* {@link EnableGemfireRepositories} annotation.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.context.annotation.Import
|
||||
* @see org.springframework.data.gemfire.repository.GemfireRepository
|
||||
* @see org.springframework.data.gemfire.repository.config.EnableGemfireRepositories
|
||||
* @see org.springframework.data.gemfire.repository.config.GemfireRepositoryConfigurationExtension
|
||||
* @see org.springframework.data.gemfire.repository.support.GemfireRepositoryFactoryBean
|
||||
* @see org.springframework.geode.boot.autoconfigure.ClientCacheAutoConfiguration
|
||||
* @see org.springframework.geode.boot.autoconfigure.GemFireRepositoriesAutoConfigurationRegistrar
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@AutoConfigureAfter(ClientCacheAutoConfiguration.class)
|
||||
@ConditionalOnBean(GemFireCache.class)
|
||||
@ConditionalOnClass(GemfireRepository.class)
|
||||
@ConditionalOnMissingBean({ GemfireRepositoryConfigurationExtension.class, GemfireRepositoryFactoryBean.class })
|
||||
@ConditionalOnProperty(prefix = "spring.data.gemfire.repositories", name = "enabled", havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
@Import(GemFireRepositoriesAutoConfigurationRegistrar.class)
|
||||
public class RepositoriesAutoConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.env.EnvironmentPostProcessor;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.PropertiesPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.geode.boot.autoconfigure.support.EnableSubscriptionConfiguration;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession;
|
||||
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
|
||||
import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} for configuring Apache Geode
|
||||
* as an (HTTP) {@link Session} state management provider in Spring Session.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.Properties
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.springframework.boot.SpringApplication
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.AutoConfigureAfter
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnBean
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnClass
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication
|
||||
* @see org.springframework.context.annotation.Condition
|
||||
* @see org.springframework.context.annotation.ConditionContext
|
||||
* @see org.springframework.context.annotation.Conditional
|
||||
* @see org.springframework.context.annotation.Import
|
||||
* @see org.springframework.core.env.ConfigurableEnvironment
|
||||
* @see org.springframework.core.env.PropertiesPropertySource
|
||||
* @see org.springframework.core.env.PropertySource
|
||||
* @see org.springframework.core.type.AnnotatedTypeMetadata
|
||||
* @see org.springframework.geode.boot.autoconfigure.support.EnableSubscriptionConfiguration
|
||||
* @see org.springframework.session.Session
|
||||
* @see org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession
|
||||
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
|
||||
* @see org.springframework.session.web.http.SessionRepositoryFilter
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@AutoConfigureAfter(ClientCacheAutoConfiguration.class)
|
||||
@Conditional(SpringSessionAutoConfiguration.SpringSessionStoreTypeCondition.class)
|
||||
@ConditionalOnBean(GemFireCache.class)
|
||||
@ConditionalOnClass({ GemFireCache.class, GemFireHttpSessionConfiguration.class })
|
||||
@ConditionalOnMissingBean(SessionRepositoryFilter.class)
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@EnableGemFireHttpSession(poolName = "DEFAULT")
|
||||
@Import(EnableSubscriptionConfiguration.class)
|
||||
@SuppressWarnings("unused")
|
||||
public class SpringSessionAutoConfiguration {
|
||||
|
||||
protected static final Set<String> SPRING_SESSION_STORE_TYPES = asSet("gemfire", "geode");
|
||||
|
||||
protected static final String SERVER_SERVLET_SESSION_TIMEOUT_PROPERTY = "server.servlet.session.timeout";
|
||||
protected static final String SPRING_SESSION_DATA_GEMFIRE_SESSION_EXPIRATION_TIMEOUT =
|
||||
"spring.session.data.gemfire.session.expiration.max-inactive-interval-seconds";
|
||||
protected static final String SPRING_SESSION_PROPERTY_SOURCE_NAME = "SpringSessionProperties";
|
||||
protected static final String SPRING_SESSION_STORE_TYPE_PROPERTY = "spring.session.store-type";
|
||||
protected static final String SPRING_SESSION_TIMEOUT_PROPERTY = "spring.session.timeout";
|
||||
|
||||
public static class SpringSessionPropertiesEnvironmentPostProcessor implements EnvironmentPostProcessor {
|
||||
|
||||
@Override
|
||||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
|
||||
|
||||
if (isNotSet(environment, SPRING_SESSION_DATA_GEMFIRE_SESSION_EXPIRATION_TIMEOUT)) {
|
||||
|
||||
Properties springSessionProperties = new Properties();
|
||||
|
||||
if (isSet(environment, SPRING_SESSION_TIMEOUT_PROPERTY)) {
|
||||
springSessionProperties.setProperty(SPRING_SESSION_DATA_GEMFIRE_SESSION_EXPIRATION_TIMEOUT,
|
||||
environment.getProperty(SPRING_SESSION_TIMEOUT_PROPERTY));
|
||||
}
|
||||
else if (isSet(environment, SERVER_SERVLET_SESSION_TIMEOUT_PROPERTY)) {
|
||||
springSessionProperties.setProperty(SPRING_SESSION_DATA_GEMFIRE_SESSION_EXPIRATION_TIMEOUT,
|
||||
environment.getProperty(SERVER_SERVLET_SESSION_TIMEOUT_PROPERTY));
|
||||
}
|
||||
|
||||
if (!springSessionProperties.isEmpty()) {
|
||||
environment.getPropertySources()
|
||||
.addFirst(newPropertySource(SPRING_SESSION_PROPERTY_SOURCE_NAME, springSessionProperties));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PropertySource<?> newPropertySource(String name, Properties properties) {
|
||||
return new PropertiesPropertySource(name, properties);
|
||||
}
|
||||
}
|
||||
|
||||
protected static boolean isNotSet(ConfigurableEnvironment environment, String propertyName) {
|
||||
return !isSet(environment, propertyName);
|
||||
}
|
||||
|
||||
protected static boolean isSet(ConfigurableEnvironment environment, String propertyName) {
|
||||
|
||||
return environment.containsProperty(propertyName)
|
||||
&& StringUtils.hasText(environment.getProperty(propertyName));
|
||||
}
|
||||
|
||||
protected static class SpringSessionStoreTypeCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
|
||||
String springSessionStoreTypeValue =
|
||||
context.getEnvironment().getProperty(SPRING_SESSION_STORE_TYPE_PROPERTY);
|
||||
|
||||
return !StringUtils.hasText(springSessionStoreTypeValue)
|
||||
|| SPRING_SESSION_STORE_TYPES.contains(springSessionStoreTypeValue.trim().toLowerCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.gemfire.CacheFactoryBean;
|
||||
import org.springframework.geode.boot.autoconfigure.configuration.SpringSessionProperties;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} class used to configure Spring Boot
|
||||
* {@link ConfigurationProperties} classes and beans from the Spring {@link Environment} containing Spring Session
|
||||
* configuration properties used to configure either Apache Geode to manage (HTTP) Session state.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.boot.context.properties.ConfigurationProperties
|
||||
* @see org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
* @see org.springframework.core.env.Environment
|
||||
* @see org.springframework.geode.boot.autoconfigure.configuration.SpringSessionProperties
|
||||
* @see org.springframework.session.SessionRepository
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@ConditionalOnBean({ GemFireCache.class, SessionRepository.class })
|
||||
@ConditionalOnClass({ GemFireCache.class, CacheFactoryBean.class, GemFireHttpSessionConfiguration.class })
|
||||
@EnableConfigurationProperties({ SpringSessionProperties.class })
|
||||
@SuppressWarnings("unused")
|
||||
public class SpringSessionPropertiesAutoConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.env.EnvironmentPostProcessor;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertiesPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.data.gemfire.CacheFactoryBean;
|
||||
import org.springframework.data.gemfire.config.annotation.EnableSsl;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link EnableAutoConfiguration auto-configuration} enabling Apache Geode's SSL transport
|
||||
* between client and servers when using the client/server topology.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.io.File
|
||||
* @see java.net.URL
|
||||
* @see java.util.Properties
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.springframework.boot.SpringApplication
|
||||
* @see org.springframework.boot.SpringBootConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.AutoConfigureBefore
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnClass
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||
* @see org.springframework.boot.env.EnvironmentPostProcessor
|
||||
* @see org.springframework.context.annotation.Condition
|
||||
* @see org.springframework.context.annotation.ConditionContext
|
||||
* @see org.springframework.context.annotation.Conditional
|
||||
* @see org.springframework.core.env.ConfigurableEnvironment
|
||||
* @see org.springframework.core.env.Environment
|
||||
* @see org.springframework.core.env.PropertiesPropertySource
|
||||
* @see org.springframework.core.env.PropertySource
|
||||
* @see org.springframework.core.io.ClassPathResource
|
||||
* @see org.springframework.core.io.Resource
|
||||
* @see org.springframework.core.type.AnnotatedTypeMetadata
|
||||
* @see org.springframework.data.gemfire.CacheFactoryBean
|
||||
* @see org.springframework.data.gemfire.config.annotation.EnableSsl
|
||||
* @see org.springframework.geode.boot.autoconfigure.ClientCacheAutoConfiguration
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SpringBootConfiguration
|
||||
@AutoConfigureBefore(ClientCacheAutoConfiguration.class)
|
||||
@Conditional(SslAutoConfiguration.EnableSslCondition.class)
|
||||
@ConditionalOnClass({ CacheFactoryBean.class, GemFireCache.class })
|
||||
@EnableSsl
|
||||
@SuppressWarnings("unused")
|
||||
public class SslAutoConfiguration {
|
||||
|
||||
public static final String SECURITY_SSL_ENVIRONMENT_POST_PROCESSOR_ENABLED_PROPERTY =
|
||||
"spring.boot.data.gemfire.security.ssl.environment.post-processor.enabled";
|
||||
|
||||
private static final String CURRENT_WORKING_DIRECTORY = System.getProperty("user.dir");
|
||||
private static final String GEMFIRE_SSL_KEYSTORE_PROPERTY = "gemfire.ssl-keystore";
|
||||
private static final String GEMFIRE_SSL_PROPERTY_SOURCE_NAME = "gemfire-ssl";
|
||||
private static final String GEMFIRE_SSL_TRUSTSTORE_PROPERTY = "gemfire.ssl-truststore";
|
||||
private static final String SECURITY_SSL_PROPERTY_PREFIX = "spring.data.gemfire.security.ssl";
|
||||
private static final String SECURITY_SSL_KEYSTORE_PROPERTY = SECURITY_SSL_PROPERTY_PREFIX + ".keystore";
|
||||
private static final String SECURITY_SSL_TRUSTSTORE_PROPERTY = SECURITY_SSL_PROPERTY_PREFIX + ".truststore";
|
||||
private static final String SECURITY_SSL_USE_DEFAULT_CONTEXT = SECURITY_SSL_PROPERTY_PREFIX + ".use-default-context";
|
||||
private static final String TRUSTED_KEYSTORE_FILENAME = "trusted.keystore";
|
||||
private static final String TRUSTED_KEYSTORE_FILENAME_PROPERTY = "spring.boot.data.gemfire.security.ssl.keystore.name";
|
||||
private static final String USER_HOME_DIRECTORY = System.getProperty("user.home");
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SslAutoConfiguration.class);
|
||||
|
||||
private static boolean isSslConfigured(Environment environment) {
|
||||
|
||||
return (environment.containsProperty(SECURITY_SSL_KEYSTORE_PROPERTY)
|
||||
&& environment.containsProperty(SECURITY_SSL_TRUSTSTORE_PROPERTY))
|
||||
|| (environment.containsProperty(GEMFIRE_SSL_KEYSTORE_PROPERTY)
|
||||
&& environment.containsProperty(GEMFIRE_SSL_TRUSTSTORE_PROPERTY));
|
||||
}
|
||||
|
||||
private static boolean isSslNotConfigured(Environment environment) {
|
||||
return !isSslConfigured(environment);
|
||||
}
|
||||
|
||||
private static String resolveTrustedKeyStore(Environment environment) {
|
||||
|
||||
return locateKeyStoreInFileSystem(environment)
|
||||
.map(File::getAbsolutePath)
|
||||
.orElseGet(() -> locateKeyStoreInUserHome(environment)
|
||||
.map(File::getAbsolutePath)
|
||||
.orElseGet(() -> resolveKeyStoreFromClassPathAsPathname(environment)
|
||||
.orElse(null)));
|
||||
}
|
||||
|
||||
private static String resolveTrustedKeystoreName(Environment environment) {
|
||||
|
||||
return environment != null && environment.containsProperty(TRUSTED_KEYSTORE_FILENAME_PROPERTY)
|
||||
? environment.getProperty(TRUSTED_KEYSTORE_FILENAME_PROPERTY)
|
||||
: TRUSTED_KEYSTORE_FILENAME;
|
||||
}
|
||||
|
||||
private static Optional<String> resolveKeyStoreFromClassPathAsPathname(Environment environment) {
|
||||
|
||||
return resolveKeyStoreFromClassPath(environment)
|
||||
.filter(File::isFile)
|
||||
.map(File::getAbsolutePath)
|
||||
.filter(StringUtils::hasText);
|
||||
}
|
||||
|
||||
private static Optional<File> resolveKeyStoreFromClassPath(Environment environment) {
|
||||
|
||||
return locateKeyStoreInClassPath(environment)
|
||||
.map(resource -> {
|
||||
|
||||
File trustedKeyStore = null;
|
||||
|
||||
try {
|
||||
|
||||
URL url = resource.getURL();
|
||||
|
||||
if (ResourceUtils.isFileURL(url)) {
|
||||
trustedKeyStore = new File(url.toURI());
|
||||
}
|
||||
else if (ResourceUtils.isJarURL(url)) {
|
||||
trustedKeyStore = new File(CURRENT_WORKING_DIRECTORY, resolveTrustedKeystoreName(environment));
|
||||
FileCopyUtils.copy(url.openStream(), new FileOutputStream(trustedKeyStore));
|
||||
}
|
||||
}
|
||||
catch (IOException | URISyntaxException cause) {
|
||||
|
||||
if (logger.isWarnEnabled()) {
|
||||
|
||||
logger.warn("Trusted KeyStore {} found in Class Path but is not resolvable as a File: {}",
|
||||
resource, cause.getMessage());
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Caused by:", cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return trustedKeyStore;
|
||||
});
|
||||
}
|
||||
|
||||
private static Optional<ClassPathResource> locateKeyStoreInClassPath(Environment environment) {
|
||||
return locateKeyStoreInClassPath(resolveTrustedKeystoreName(environment));
|
||||
}
|
||||
|
||||
private static Optional<ClassPathResource> locateKeyStoreInClassPath(String keystoreName) {
|
||||
|
||||
return Optional.of(new ClassPathResource(keystoreName))
|
||||
.filter(Resource::exists);
|
||||
}
|
||||
|
||||
private static Optional<File> locateKeyStoreInFileSystem(Environment environment) {
|
||||
return locateKeyStoreInFileSystem(environment, new File(CURRENT_WORKING_DIRECTORY));
|
||||
}
|
||||
|
||||
private static Optional<File> locateKeyStoreInFileSystem(Environment environment, File directory) {
|
||||
return locateKeyStoreInFileSystem(directory, resolveTrustedKeystoreName(environment));
|
||||
}
|
||||
|
||||
private static Optional<File> locateKeyStoreInFileSystem(String keystoreName) {
|
||||
return locateKeyStoreInFileSystem(new File(CURRENT_WORKING_DIRECTORY), keystoreName);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private static Optional<File> locateKeyStoreInFileSystem(File directory, String keystoreFilename) {
|
||||
|
||||
assertDirectory(directory);
|
||||
|
||||
for (File file : nullSafeListFiles(directory)) {
|
||||
|
||||
if (isDirectory(file)) {
|
||||
|
||||
Optional<File> theFile = locateKeyStoreInFileSystem(file, keystoreFilename);
|
||||
|
||||
if (theFile.isPresent()) {
|
||||
return theFile;
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (file.getName().equals(keystoreFilename)) {
|
||||
return Optional.of(file);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static Optional<File> locateKeyStoreInUserHome(Environment environment) {
|
||||
return locateKeyStoreInUserHome(resolveTrustedKeystoreName(environment));
|
||||
}
|
||||
|
||||
private static Optional<File> locateKeyStoreInUserHome(String keystoreFilename) {
|
||||
|
||||
return Optional.of(new File(USER_HOME_DIRECTORY, keystoreFilename))
|
||||
.filter(File::isFile);
|
||||
}
|
||||
|
||||
private static void assertDirectory(File path) {
|
||||
Assert.isTrue(isDirectory(path), String.format("[%s] is not a valid directory", path));
|
||||
}
|
||||
|
||||
private static boolean isDirectory(File path) {
|
||||
return path != null && path.isDirectory();
|
||||
}
|
||||
|
||||
private static File[] nullSafeListFiles(File directory) {
|
||||
return nullSafeArray(directory.listFiles(), File.class);
|
||||
}
|
||||
|
||||
public static class SslEnvironmentPostProcessor implements EnvironmentPostProcessor {
|
||||
|
||||
@Override
|
||||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
|
||||
|
||||
Optional.of(environment)
|
||||
.filter(this::isEnabled)
|
||||
.filter(SslAutoConfiguration::isSslNotConfigured)
|
||||
.map(SslAutoConfiguration::resolveTrustedKeyStore)
|
||||
.filter(StringUtils::hasText)
|
||||
.ifPresent(trustedKeyStore -> configureSsl(environment, trustedKeyStore));
|
||||
}
|
||||
|
||||
private PropertySource<?> newPropertySource(String name, Properties properties) {
|
||||
return new PropertiesPropertySource(name, properties);
|
||||
}
|
||||
|
||||
private boolean isEnabled(Environment environment) {
|
||||
return environment.getProperty(SECURITY_SSL_ENVIRONMENT_POST_PROCESSOR_ENABLED_PROPERTY,
|
||||
Boolean.class, true);
|
||||
}
|
||||
|
||||
private void configureSsl(ConfigurableEnvironment environment, String trustedKeyStore) {
|
||||
|
||||
Properties gemfireSslProperties = new Properties();
|
||||
|
||||
gemfireSslProperties.setProperty(SECURITY_SSL_KEYSTORE_PROPERTY, trustedKeyStore);
|
||||
gemfireSslProperties.setProperty(SECURITY_SSL_TRUSTSTORE_PROPERTY, trustedKeyStore);
|
||||
|
||||
environment.getPropertySources()
|
||||
.addFirst(newPropertySource(GEMFIRE_SSL_PROPERTY_SOURCE_NAME, gemfireSslProperties));
|
||||
}
|
||||
}
|
||||
|
||||
static class EnableSslCondition extends AllNestedConditions {
|
||||
|
||||
public EnableSslCondition() {
|
||||
super(ConfigurationPhase.PARSE_CONFIGURATION);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(name = SECURITY_SSL_ENVIRONMENT_POST_PROCESSOR_ENABLED_PROPERTY,
|
||||
havingValue = "true", matchIfMissing = true)
|
||||
static class SpringBootDataGemFireSecuritySslEnvironmentPostProcessorEnabled { }
|
||||
|
||||
@Conditional(SslTriggersCondition.class)
|
||||
static class AnySslTriggerCondition { }
|
||||
|
||||
}
|
||||
|
||||
static class SslTriggersCondition extends AnyNestedCondition {
|
||||
|
||||
public SslTriggersCondition() {
|
||||
super(ConfigurationPhase.PARSE_CONFIGURATION);
|
||||
}
|
||||
|
||||
@Conditional(TrustedKeyStoreIsPresentCondition.class)
|
||||
static class TrustedKeyStoreCondition { }
|
||||
|
||||
@ConditionalOnProperty(prefix = SECURITY_SSL_PROPERTY_PREFIX, name = { "keystore", "truststore" })
|
||||
static class SpringDataGemFireSecuritySslKeyStoreAndTruststorePropertiesSet { }
|
||||
|
||||
@ConditionalOnProperty(SECURITY_SSL_USE_DEFAULT_CONTEXT)
|
||||
static class SpringDataGeodeSslUseDefaultContextPropertySet { }
|
||||
|
||||
@ConditionalOnProperty({ GEMFIRE_SSL_KEYSTORE_PROPERTY, GEMFIRE_SSL_TRUSTSTORE_PROPERTY })
|
||||
static class ApacheGeodeSslKeyStoreAndTruststorePropertiesSet { }
|
||||
|
||||
}
|
||||
|
||||
static class TrustedKeyStoreIsPresentCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
|
||||
Environment environment = context.getEnvironment();
|
||||
|
||||
return locateKeyStoreInClassPath(environment).isPresent()
|
||||
|| locateKeyStoreInFileSystem(environment).isPresent()
|
||||
|| locateKeyStoreInUserHome(environment).isPresent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure.condition;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
/**
|
||||
* The {@link ConditionalOnMissingProperty} annotation is a Spring {@link Conditional} used to conditionally enable
|
||||
* or disable functionality based on the absence of any declared properties.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.context.annotation.Conditional
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Conditional(OnMissingPropertyCondition.class)
|
||||
@SuppressWarnings("unused")
|
||||
public @interface ConditionalOnMissingProperty {
|
||||
|
||||
/**
|
||||
* The {@link String names} of the properties to test.
|
||||
*
|
||||
* If a {@link String prefix} has been defined, it is applied to compute the full key of each property.
|
||||
*
|
||||
* For instance, if the {@link String prefix} is {@code app.config} and one value is {@code my-value},
|
||||
* the full key would be {@code app.config.my-value}.
|
||||
*
|
||||
* Use dashed notation to specify each property, that is all lower case with a "-" to separate words
|
||||
* (e.g. {@code my-long-property}).
|
||||
*
|
||||
* @return the {@link String names} of the properties to test.
|
||||
* @see #prefix()
|
||||
*/
|
||||
@AliasFor("value")
|
||||
String[] name() default {};
|
||||
|
||||
/**
|
||||
* A {@link String prefix} that should be applied to each property.
|
||||
*
|
||||
* The {@link String prefix} automatically ends with a dot if not specified. A valid {@link String prefix}
|
||||
* is defined by one or more words separated with dots (e.g. {@code "acme.system.feature"}).
|
||||
*
|
||||
* @return the property {@link String prefix}.
|
||||
* @see #name()
|
||||
*/
|
||||
String prefix() default "";
|
||||
|
||||
/**
|
||||
* Alias for {@link #name()}.
|
||||
*
|
||||
* @return the {@link String names} of the properties to test.
|
||||
* @see #name()
|
||||
*/
|
||||
@AliasFor("name")
|
||||
String[] value() default {};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure.condition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.env.PropertyResolver;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The {@link OnMissingPropertyCondition} class is a {@link SpringBootCondition}, Spring {@link Condition} type
|
||||
* asserting whether the specified, declared properties are missing.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionOutcome
|
||||
* @see org.springframework.boot.autoconfigure.condition.SpringBootCondition
|
||||
* @see org.springframework.context.annotation.Condition
|
||||
* @see org.springframework.context.annotation.ConditionContext
|
||||
* @see org.springframework.core.annotation.AnnotationAttributes
|
||||
* @see org.springframework.core.env.PropertyResolver
|
||||
* @see org.springframework.core.type.AnnotatedTypeMetadata
|
||||
* @see org.springframework.geode.boot.autoconfigure.condition.ConditionalOnMissingProperty
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class OnMissingPropertyCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
|
||||
String annotationName = ConditionalOnMissingProperty.class.getName();
|
||||
|
||||
Collection<AnnotationAttributes> annotationAttributesCollection =
|
||||
toAnnotationAttributesFromMultiValueMap(metadata.getAllAnnotationAttributes(annotationName));
|
||||
|
||||
PropertyResolver propertyResolver = getPropertyResolver(context);
|
||||
|
||||
Collection<String> allMatchingProperties = new ArrayList<>();
|
||||
|
||||
annotationAttributesCollection.forEach(annotationAttributes -> {
|
||||
|
||||
List<String> propertyNames = collectPropertyNames(annotationAttributes);
|
||||
|
||||
allMatchingProperties.addAll(findMatchingProperties(propertyResolver, propertyNames));
|
||||
});
|
||||
|
||||
return determineConditionOutcome(allMatchingProperties);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends Collection<AnnotationAttributes>> T toAnnotationAttributesFromMultiValueMap(
|
||||
MultiValueMap<String, Object> map) {
|
||||
|
||||
List<AnnotationAttributes> annotationAttributesList = new ArrayList<>();
|
||||
|
||||
map.forEach((key, value) -> {
|
||||
for (int index = 0, size = value.size(); index < size; index++) {
|
||||
|
||||
AnnotationAttributes annotationAttributes =
|
||||
resolveAnnotationAttributes(annotationAttributesList, index);
|
||||
|
||||
annotationAttributes.put(key, value.get(index));
|
||||
}
|
||||
});
|
||||
|
||||
return (T) annotationAttributesList;
|
||||
}
|
||||
|
||||
private AnnotationAttributes resolveAnnotationAttributes(List<AnnotationAttributes> annotationAttributesList,
|
||||
int index) {
|
||||
|
||||
if (index < annotationAttributesList.size()) {
|
||||
return annotationAttributesList.get(index);
|
||||
}
|
||||
else {
|
||||
AnnotationAttributes newAnnotationAttributes = new AnnotationAttributes();
|
||||
annotationAttributesList.add(newAnnotationAttributes);
|
||||
return newAnnotationAttributes;
|
||||
}
|
||||
}
|
||||
|
||||
private PropertyResolver getPropertyResolver(ConditionContext context) {
|
||||
return context.getEnvironment();
|
||||
}
|
||||
|
||||
private List<String> collectPropertyNames(AnnotationAttributes annotationAttributes) {
|
||||
|
||||
String prefix = getPrefix(annotationAttributes);
|
||||
|
||||
String[] names = getNames(annotationAttributes);
|
||||
|
||||
return Arrays.stream(names).map(name -> prefix + name).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private String[] getNames(AnnotationAttributes annotationAttributes) {
|
||||
|
||||
String[] names = annotationAttributes.getStringArray("name");
|
||||
String[] values = annotationAttributes.getStringArray("value");
|
||||
|
||||
Assert.isTrue(names.length > 0 || values.length > 0,
|
||||
String.format("The name or value attribute of @%s is required",
|
||||
ConditionalOnMissingProperty.class.getSimpleName()));
|
||||
|
||||
// TODO remove; not needed when using @AliasFor.
|
||||
/*
|
||||
Assert.isTrue(names.length * values.length == 0,
|
||||
String.format("The name and value attributes of @%s are exclusive",
|
||||
ConditionalOnMissingProperty.class.getSimpleName()));
|
||||
*/
|
||||
|
||||
return names.length > 0 ? names : values;
|
||||
}
|
||||
|
||||
private String getPrefix(AnnotationAttributes annotationAttributes) {
|
||||
|
||||
String prefix = annotationAttributes.getString("prefix");
|
||||
|
||||
return StringUtils.hasText(prefix) ? prefix.trim().endsWith(".") ? prefix.trim() : prefix.trim() + "." : "";
|
||||
}
|
||||
|
||||
private Collection<String> findMatchingProperties(PropertyResolver propertyResolver, List<String> propertyNames) {
|
||||
return propertyNames.stream().filter(propertyResolver::containsProperty).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private ConditionOutcome determineConditionOutcome(Collection<String> matchingProperties) {
|
||||
|
||||
if (!matchingProperties.isEmpty()) {
|
||||
|
||||
return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnMissingProperty.class)
|
||||
.found("property already defined", "properties already defined")
|
||||
.items(matchingProperties));
|
||||
}
|
||||
|
||||
return ConditionOutcome.match();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure.configuration;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import org.springframework.geode.boot.autoconfigure.configuration.support.CacheProperties;
|
||||
import org.springframework.geode.boot.autoconfigure.configuration.support.ClusterProperties;
|
||||
import org.springframework.geode.boot.autoconfigure.configuration.support.DiskStoreProperties;
|
||||
import org.springframework.geode.boot.autoconfigure.configuration.support.EntityProperties;
|
||||
import org.springframework.geode.boot.autoconfigure.configuration.support.LocatorProperties;
|
||||
import org.springframework.geode.boot.autoconfigure.configuration.support.LoggingProperties;
|
||||
import org.springframework.geode.boot.autoconfigure.configuration.support.ManagementProperties;
|
||||
import org.springframework.geode.boot.autoconfigure.configuration.support.ManagerProperties;
|
||||
import org.springframework.geode.boot.autoconfigure.configuration.support.PdxProperties;
|
||||
import org.springframework.geode.boot.autoconfigure.configuration.support.PoolProperties;
|
||||
import org.springframework.geode.boot.autoconfigure.configuration.support.SecurityProperties;
|
||||
import org.springframework.geode.boot.autoconfigure.configuration.support.ServiceProperties;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link ConfigurationProperties} for well-known, documented Spring Data for Apache Geode (SDG)
|
||||
* {@link Properties}.
|
||||
*
|
||||
* This class assists the application developer in the auto-completion / content-assist of the well-known, documented
|
||||
* SDG {@link Properties}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.Properties
|
||||
* @see org.springframework.boot.context.properties.ConfigurationProperties
|
||||
* @see org.springframework.boot.context.properties.NestedConfigurationProperty
|
||||
* @see org.springframework.geode.boot.autoconfigure.configuration.support.CacheProperties
|
||||
* @see org.springframework.geode.boot.autoconfigure.configuration.support.ClusterProperties
|
||||
* @see org.springframework.geode.boot.autoconfigure.configuration.support.DiskStoreProperties
|
||||
* @see org.springframework.geode.boot.autoconfigure.configuration.support.EntityProperties
|
||||
* @see org.springframework.geode.boot.autoconfigure.configuration.support.LocatorProperties
|
||||
* @see org.springframework.geode.boot.autoconfigure.configuration.support.LoggingProperties
|
||||
* @see org.springframework.geode.boot.autoconfigure.configuration.support.ManagementProperties
|
||||
* @see org.springframework.geode.boot.autoconfigure.configuration.support.ManagerProperties
|
||||
* @see org.springframework.geode.boot.autoconfigure.configuration.support.PdxProperties
|
||||
* @see org.springframework.geode.boot.autoconfigure.configuration.support.PoolProperties
|
||||
* @see org.springframework.geode.boot.autoconfigure.configuration.support.SecurityProperties
|
||||
* @see org.springframework.geode.boot.autoconfigure.configuration.support.ServiceProperties
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@ConfigurationProperties(prefix = "spring.data.gemfire")
|
||||
public class GemFireProperties {
|
||||
|
||||
private static final boolean DEFAULT_USE_BEAN_FACTORY_LOCATOR = false;
|
||||
|
||||
private boolean useBeanFactoryLocator = DEFAULT_USE_BEAN_FACTORY_LOCATOR;
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final CacheProperties cache = new CacheProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final ClusterProperties cluster = new ClusterProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final DiskStoreProperties disk = new DiskStoreProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final EntityProperties entities = new EntityProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final LocatorProperties locator = new LocatorProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final LoggingProperties logging = new LoggingProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final ManagementProperties management = new ManagementProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final ManagerProperties manager = new ManagerProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final PdxProperties pdx = new PdxProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final PoolProperties pool = new PoolProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final SecurityProperties security = new SecurityProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final ServiceProperties service = new ServiceProperties();
|
||||
|
||||
private String name;
|
||||
|
||||
private String[] locators;
|
||||
|
||||
public CacheProperties getCache() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
public ClusterProperties getCluster() {
|
||||
return this.cluster;
|
||||
}
|
||||
|
||||
public DiskStoreProperties getDisk() {
|
||||
return this.disk;
|
||||
}
|
||||
|
||||
public EntityProperties getEntities() {
|
||||
return this.entities;
|
||||
}
|
||||
|
||||
public LocatorProperties getLocator() {
|
||||
return this.locator;
|
||||
}
|
||||
|
||||
public String[] getLocators() {
|
||||
return this.locators;
|
||||
}
|
||||
|
||||
public void setLocators(String[] locators) {
|
||||
this.locators = locators;
|
||||
}
|
||||
|
||||
public LoggingProperties getLogging() {
|
||||
return this.logging;
|
||||
}
|
||||
|
||||
public ManagementProperties getManagement() {
|
||||
return this.management;
|
||||
}
|
||||
|
||||
public ManagerProperties getManager() {
|
||||
return this.manager;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public PdxProperties getPdx() {
|
||||
return this.pdx;
|
||||
}
|
||||
|
||||
public PoolProperties getPool() {
|
||||
return this.pool;
|
||||
}
|
||||
|
||||
public SecurityProperties getSecurity() {
|
||||
return this.security;
|
||||
}
|
||||
|
||||
public ServiceProperties getService() {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
public boolean isUseBeanFactoryLocator() {
|
||||
return this.useBeanFactoryLocator;
|
||||
}
|
||||
|
||||
public void setUseBeanFactoryLocator(boolean useBeanFactoryLocator) {
|
||||
this.useBeanFactoryLocator = useBeanFactoryLocator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure.configuration;
|
||||
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link ConfigurationProperties} used to configure Spring Session for Apache Geode (SSDG) in order to
|
||||
* manage (HTTP) Session state with Spring Session backed by Apache Geode.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.boot.context.properties.ConfigurationProperties
|
||||
* @see org.springframework.boot.context.properties.NestedConfigurationProperty
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@ConfigurationProperties(prefix = "spring.session.data.gemfire")
|
||||
public class SpringSessionProperties {
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final CacheProperties cache = new CacheProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final SessionProperties session = new SessionProperties();
|
||||
|
||||
public CacheProperties getCache() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
public SessionProperties getSession() {
|
||||
return this.session;
|
||||
}
|
||||
|
||||
public static class CacheProperties {
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final CacheServerProperties server = new CacheServerProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final ClientCacheProperties client = new ClientCacheProperties();
|
||||
|
||||
public ClientCacheProperties getClient() {
|
||||
return this.client;
|
||||
}
|
||||
|
||||
public CacheServerProperties getServer() {
|
||||
return this.server;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CacheServerProperties {
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final ServerRegionProperties region = new ServerRegionProperties();
|
||||
|
||||
public ServerRegionProperties getRegion() {
|
||||
return region;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ClientCacheProperties {
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final ClientRegionProperties region = new ClientRegionProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final PoolProperties pool = new PoolProperties();
|
||||
|
||||
public PoolProperties getPool() {
|
||||
return this.pool;
|
||||
}
|
||||
|
||||
public ClientRegionProperties getRegion() {
|
||||
return this.region;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ClientRegionProperties {
|
||||
|
||||
public static final ClientRegionShortcut DEFAULT_CLIENT_REGION_SHORTCUT = ClientRegionShortcut.PROXY;
|
||||
|
||||
private ClientRegionShortcut shortcut = ClientRegionShortcut.PROXY;
|
||||
|
||||
public ClientRegionShortcut getShortcut() {
|
||||
return this.shortcut != null ? this.shortcut : DEFAULT_CLIENT_REGION_SHORTCUT;
|
||||
}
|
||||
|
||||
public void setShortcut(ClientRegionShortcut shortcut) {
|
||||
this.shortcut = shortcut;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PoolProperties {
|
||||
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ServerRegionProperties {
|
||||
|
||||
public static final RegionShortcut DEFAULT_SERVER_REGION_SHORTCUT = RegionShortcut.PARTITION;
|
||||
|
||||
private RegionShortcut shortcut;
|
||||
|
||||
public RegionShortcut getShortcut() {
|
||||
return this.shortcut != null ? this.shortcut : DEFAULT_SERVER_REGION_SHORTCUT;
|
||||
}
|
||||
|
||||
public void setShortcut(RegionShortcut shortcut) {
|
||||
this.shortcut = shortcut;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SessionProperties {
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final SessionAttributesProperties attributes = new SessionAttributesProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final SessionExpirationProperties expiration = new SessionExpirationProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final SessionRegionProperties region = new SessionRegionProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final SessionSerializerProperties serializer = new SessionSerializerProperties();
|
||||
|
||||
public SessionAttributesProperties getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
public SessionExpirationProperties getExpiration() {
|
||||
return this.expiration;
|
||||
}
|
||||
|
||||
public SessionRegionProperties getRegion() {
|
||||
return this.region;
|
||||
}
|
||||
|
||||
public SessionSerializerProperties getSerializer() {
|
||||
return this.serializer;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SessionAttributesProperties {
|
||||
|
||||
private String[] indexable;
|
||||
|
||||
public String[] getIndexable() {
|
||||
return this.indexable;
|
||||
}
|
||||
|
||||
public void setIndexable(String[] indexable) {
|
||||
this.indexable = indexable;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SessionExpirationProperties {
|
||||
|
||||
private int maxInactiveIntervalSeconds;
|
||||
|
||||
public int getMaxInactiveIntervalSeconds() {
|
||||
return this.maxInactiveIntervalSeconds;
|
||||
}
|
||||
|
||||
public void setMaxInactiveIntervalSeconds(int maxInactiveIntervalSeconds) {
|
||||
this.maxInactiveIntervalSeconds = maxInactiveIntervalSeconds;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SessionRegionProperties {
|
||||
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SessionSerializerProperties {
|
||||
|
||||
private String beanName;
|
||||
|
||||
public String getBeanName() {
|
||||
return this.beanName;
|
||||
}
|
||||
|
||||
public void setBeanName(String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure.configuration.support;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.control.ResourceManager;
|
||||
import org.apache.geode.cache.server.CacheServer;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link ConfigurationProperties} used to configure Apache Geode peer {@link Cache}, {@link ClientCache}
|
||||
* and {@link CacheServer} objects.
|
||||
*
|
||||
* The configuration {@link Properties} are based on well-known, documented Spring Data for Apache Geode (SDG)
|
||||
* {@link Properties}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.Properties
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.control.ResourceManager
|
||||
* @see org.apache.geode.cache.server.CacheServer
|
||||
* @see org.springframework.boot.context.properties.ConfigurationProperties
|
||||
* @see org.springframework.boot.context.properties.NestedConfigurationProperty
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class CacheProperties {
|
||||
|
||||
private static final boolean DEFAULT_COPY_ON_READ = false;
|
||||
private static final boolean DEFAULT_AUTO_REGION_LOOKUP = true;
|
||||
|
||||
private static final float DEFAULT_CRITICAL_OFF_HEAP_PERCENTAGE = 0.0f;
|
||||
private static final float DEFAULT_EVICTION_OFF_HEAP_PERCENTAGE = 0.0f;
|
||||
|
||||
private static final String DEFAULT_LOG_LEVEL = "config";
|
||||
|
||||
private boolean copyOnRead = DEFAULT_COPY_ON_READ;
|
||||
private boolean enableAutoRegionLookup = DEFAULT_AUTO_REGION_LOOKUP;
|
||||
|
||||
private float criticalHeapPercentage = ResourceManager.DEFAULT_CRITICAL_PERCENTAGE;
|
||||
private float criticalOffHeapPercentage = DEFAULT_CRITICAL_OFF_HEAP_PERCENTAGE;
|
||||
private float evictionHeapPercentage = ResourceManager.DEFAULT_EVICTION_PERCENTAGE;
|
||||
private float evictionOffHeapPercentage = DEFAULT_EVICTION_OFF_HEAP_PERCENTAGE;
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final CacheServerProperties server = new CacheServerProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final ClientCacheProperties client = new ClientCacheProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final CompressionProperties compression = new CompressionProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final OffHeapProperties offHeap = new OffHeapProperties();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final PeerCacheProperties peer = new PeerCacheProperties();
|
||||
|
||||
private String logLevel = DEFAULT_LOG_LEVEL;
|
||||
private String name;
|
||||
|
||||
public ClientCacheProperties getClient() {
|
||||
return this.client;
|
||||
}
|
||||
|
||||
public CompressionProperties getCompression() {
|
||||
return this.compression;
|
||||
}
|
||||
|
||||
public boolean isCopyOnRead() {
|
||||
return copyOnRead;
|
||||
}
|
||||
|
||||
public void setCopyOnRead(boolean copyOnRead) {
|
||||
this.copyOnRead = copyOnRead;
|
||||
}
|
||||
|
||||
public float getCriticalHeapPercentage() {
|
||||
return this.criticalHeapPercentage;
|
||||
}
|
||||
|
||||
public void setCriticalHeapPercentage(float criticalHeapPercentage) {
|
||||
this.criticalHeapPercentage = criticalHeapPercentage;
|
||||
}
|
||||
|
||||
public float getCriticalOffHeapPercentage() {
|
||||
return this.criticalOffHeapPercentage;
|
||||
}
|
||||
|
||||
public void setCriticalOffHeapPercentage(float criticalOffHeapPercentage) {
|
||||
this.criticalOffHeapPercentage = criticalOffHeapPercentage;
|
||||
}
|
||||
|
||||
public boolean isEnableAutoRegionLookup() {
|
||||
return this.enableAutoRegionLookup;
|
||||
}
|
||||
|
||||
public void setEnableAutoRegionLookup(boolean enableAutoRegionLookup) {
|
||||
this.enableAutoRegionLookup = enableAutoRegionLookup;
|
||||
}
|
||||
|
||||
public float getEvictionHeapPercentage() {
|
||||
return this.evictionHeapPercentage;
|
||||
}
|
||||
|
||||
public void setEvictionHeapPercentage(float evictionHeapPercentage) {
|
||||
this.evictionHeapPercentage = evictionHeapPercentage;
|
||||
}
|
||||
|
||||
public float getEvictionOffHeapPercentage() {
|
||||
return this.evictionOffHeapPercentage;
|
||||
}
|
||||
|
||||
public void setEvictionOffHeapPercentage(float evictionOffHeapPercentage) {
|
||||
this.evictionOffHeapPercentage = evictionOffHeapPercentage;
|
||||
}
|
||||
|
||||
public String getLogLevel() {
|
||||
return this.logLevel;
|
||||
}
|
||||
|
||||
public void setLogLevel(String logLevel) {
|
||||
this.logLevel = logLevel;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public OffHeapProperties getOffHeap() {
|
||||
return this.offHeap;
|
||||
}
|
||||
|
||||
public PeerCacheProperties getPeer() {
|
||||
return this.peer;
|
||||
}
|
||||
|
||||
public CacheServerProperties getServer() {
|
||||
return this.server;
|
||||
}
|
||||
|
||||
public static class CompressionProperties {
|
||||
|
||||
private String compressorBeanName;
|
||||
|
||||
private String[] regionNames = {};
|
||||
|
||||
public String getCompressorBeanName() {
|
||||
return this.compressorBeanName;
|
||||
}
|
||||
|
||||
public void setCompressorBeanName(String compressorBeanName) {
|
||||
this.compressorBeanName = compressorBeanName;
|
||||
}
|
||||
|
||||
public String[] getRegionNames() {
|
||||
return this.regionNames;
|
||||
}
|
||||
|
||||
public void setRegionNames(String[] regionNames) {
|
||||
this.regionNames = regionNames;
|
||||
}
|
||||
}
|
||||
|
||||
public static class OffHeapProperties {
|
||||
|
||||
private String memorySize;
|
||||
|
||||
private String[] regionNames = {};
|
||||
|
||||
public String getMemorySize() {
|
||||
return this.memorySize;
|
||||
}
|
||||
|
||||
public void setMemorySize(String memorySize) {
|
||||
this.memorySize = memorySize;
|
||||
}
|
||||
|
||||
public String[] getRegionNames() {
|
||||
return this.regionNames;
|
||||
}
|
||||
|
||||
public void setRegionNames(String[] regionNames) {
|
||||
this.regionNames = regionNames;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure.configuration.support;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.geode.cache.server.CacheServer;
|
||||
import org.apache.geode.cache.server.ClientSubscriptionConfig;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.data.gemfire.server.SubscriptionEvictionPolicy;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link ConfigurationProperties} used to configure an Apache Geode {@link CacheServer}.
|
||||
*
|
||||
* The configuration {@link Properties} are based on well-known, documented Spring Data for Apache Geode (SDG)
|
||||
* {@link Properties}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.Properties
|
||||
* @see org.apache.geode.cache.server.CacheServer
|
||||
* @see org.springframework.boot.context.properties.ConfigurationProperties
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class CacheServerProperties {
|
||||
|
||||
private static final boolean DEFAULT_AUTO_STARTUP = true;
|
||||
|
||||
private boolean autoStartup = DEFAULT_AUTO_STARTUP;
|
||||
private boolean tcpNoDelay = CacheServer.DEFAULT_TCP_NO_DELAY;
|
||||
|
||||
private int maxConnections = CacheServer.DEFAULT_MAX_CONNECTIONS;
|
||||
private int maxMessageCount = CacheServer.DEFAULT_MAXIMUM_MESSAGE_COUNT;
|
||||
private int maxThreads = CacheServer.DEFAULT_MAX_THREADS;
|
||||
private int maxTimeBetweenPings = CacheServer.DEFAULT_MAXIMUM_TIME_BETWEEN_PINGS;
|
||||
private int messageTimeToLive = CacheServer.DEFAULT_MESSAGE_TIME_TO_LIVE;
|
||||
private int port = CacheServer.DEFAULT_PORT;
|
||||
private int socketBufferSize = CacheServer.DEFAULT_SOCKET_BUFFER_SIZE;
|
||||
private int subscriptionCapacity = ClientSubscriptionConfig.DEFAULT_CAPACITY;
|
||||
|
||||
private long loadPollInterval = CacheServer.DEFAULT_LOAD_POLL_INTERVAL;
|
||||
|
||||
private String bindAddress = CacheServer.DEFAULT_BIND_ADDRESS;
|
||||
private String hostnameForClients = CacheServer.DEFAULT_HOSTNAME_FOR_CLIENTS;
|
||||
private String subscriptionDiskStoreName;
|
||||
|
||||
private SubscriptionEvictionPolicy subscriptionEvictionPolicy = SubscriptionEvictionPolicy.NONE;
|
||||
|
||||
public boolean isAutoStartup() {
|
||||
return this.autoStartup;
|
||||
}
|
||||
|
||||
public void setAutoStartup(boolean autoStartup) {
|
||||
this.autoStartup = autoStartup;
|
||||
}
|
||||
|
||||
public String getBindAddress() {
|
||||
return this.bindAddress;
|
||||
}
|
||||
|
||||
public void setBindAddress(String bindAddress) {
|
||||
this.bindAddress = bindAddress;
|
||||
}
|
||||
|
||||
public String getHostnameForClients() {
|
||||
return this.hostnameForClients;
|
||||
}
|
||||
|
||||
public void setHostnameForClients(String hostnameForClients) {
|
||||
this.hostnameForClients = hostnameForClients;
|
||||
}
|
||||
|
||||
public long getLoadPollInterval() {
|
||||
return this.loadPollInterval;
|
||||
}
|
||||
|
||||
public void setLoadPollInterval(long loadPollInterval) {
|
||||
this.loadPollInterval = loadPollInterval;
|
||||
}
|
||||
|
||||
public int getMaxConnections() {
|
||||
return this.maxConnections;
|
||||
}
|
||||
|
||||
public void setMaxConnections(int maxConnections) {
|
||||
this.maxConnections = maxConnections;
|
||||
}
|
||||
|
||||
public int getMaxMessageCount() {
|
||||
return this.maxMessageCount;
|
||||
}
|
||||
|
||||
public void setMaxMessageCount(int maxMessageCount) {
|
||||
this.maxMessageCount = maxMessageCount;
|
||||
}
|
||||
|
||||
public int getMaxThreads() {
|
||||
return this.maxThreads;
|
||||
}
|
||||
|
||||
public void setMaxThreads(int maxThreads) {
|
||||
this.maxThreads = maxThreads;
|
||||
}
|
||||
|
||||
public int getMaxTimeBetweenPings() {
|
||||
return this.maxTimeBetweenPings;
|
||||
}
|
||||
|
||||
public void setMaxTimeBetweenPings(int maxTimeBetweenPings) {
|
||||
this.maxTimeBetweenPings = maxTimeBetweenPings;
|
||||
}
|
||||
|
||||
public int getMessageTimeToLive() {
|
||||
return this.messageTimeToLive;
|
||||
}
|
||||
|
||||
public void setMessageTimeToLive(int messageTimeToLive) {
|
||||
this.messageTimeToLive = messageTimeToLive;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public int getSocketBufferSize() {
|
||||
return this.socketBufferSize;
|
||||
}
|
||||
|
||||
public void setSocketBufferSize(int socketBufferSize) {
|
||||
this.socketBufferSize = socketBufferSize;
|
||||
}
|
||||
|
||||
public int getSubscriptionCapacity() {
|
||||
return this.subscriptionCapacity;
|
||||
}
|
||||
|
||||
public void setSubscriptionCapacity(int subscriptionCapacity) {
|
||||
this.subscriptionCapacity = subscriptionCapacity;
|
||||
}
|
||||
|
||||
public String getSubscriptionDiskStoreName() {
|
||||
return this.subscriptionDiskStoreName;
|
||||
}
|
||||
|
||||
public void setSubscriptionDiskStoreName(String subscriptionDiskStoreName) {
|
||||
this.subscriptionDiskStoreName = subscriptionDiskStoreName;
|
||||
}
|
||||
|
||||
public SubscriptionEvictionPolicy getSubscriptionEvictionPolicy() {
|
||||
return this.subscriptionEvictionPolicy;
|
||||
}
|
||||
|
||||
public void setSubscriptionEvictionPolicy(SubscriptionEvictionPolicy subscriptionEvictionPolicy) {
|
||||
this.subscriptionEvictionPolicy = subscriptionEvictionPolicy;
|
||||
}
|
||||
|
||||
public boolean isTcpNoDelay() {
|
||||
return this.tcpNoDelay;
|
||||
}
|
||||
|
||||
public void setTcpNoDelay(boolean tcpNoDelay) {
|
||||
this.tcpNoDelay = tcpNoDelay;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure.configuration.support;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link ConfigurationProperties} used to configure an Apache Geode {@link ClientCache}.
|
||||
*
|
||||
* The configuration {@link Properties} are based on well-known, documented Spring Data for Apache Geode (SDG)
|
||||
* {@link Properties}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.Properties
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.springframework.boot.context.properties.ConfigurationProperties
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ClientCacheProperties {
|
||||
|
||||
private static final boolean DEFAULT_KEEP_ALIVE = false;
|
||||
|
||||
private static final int DEFAULT_DURABLE_CLIENT_TIMEOUT_IN_SECONDS = 300;
|
||||
|
||||
private boolean keepAlive = DEFAULT_KEEP_ALIVE;
|
||||
|
||||
private int durableClientTimeout = DEFAULT_DURABLE_CLIENT_TIMEOUT_IN_SECONDS;
|
||||
|
||||
private String durableClientId;
|
||||
|
||||
public String getDurableClientId() {
|
||||
return this.durableClientId;
|
||||
}
|
||||
|
||||
public void setDurableClientId(String durableClientId) {
|
||||
this.durableClientId = durableClientId;
|
||||
}
|
||||
|
||||
public int getDurableClientTimeout() {
|
||||
return this.durableClientTimeout;
|
||||
}
|
||||
|
||||
public void setDurableClientTimeout(int durableClientTimeout) {
|
||||
this.durableClientTimeout = durableClientTimeout;
|
||||
}
|
||||
|
||||
public boolean isKeepAlive() {
|
||||
return this.keepAlive;
|
||||
}
|
||||
|
||||
public void setKeepAlive(boolean keepAlive) {
|
||||
this.keepAlive = keepAlive;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure.configuration.support;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link ConfigurationProperties} used to configure an Apache Geode {@link ClientCache} Security
|
||||
* (authentication & authorization).
|
||||
*
|
||||
* The configuration {@link Properties} are based on well-known, documented Spring Data for Apache Geode (SDG)
|
||||
* {@link Properties}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.Properties
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.springframework.boot.context.properties.ConfigurationProperties
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ClientSecurityProperties {
|
||||
|
||||
private String accessor;
|
||||
private String accessorPostProcessor;
|
||||
private String authenticationInitializer;
|
||||
private String authenticator;
|
||||
private String diffieHellmanAlgorithm;
|
||||
|
||||
public String getAccessor() {
|
||||
return this.accessor;
|
||||
}
|
||||
|
||||
public void setAccessor(String accessor) {
|
||||
this.accessor = accessor;
|
||||
}
|
||||
|
||||
public String getAccessorPostProcessor() {
|
||||
return this.accessorPostProcessor;
|
||||
}
|
||||
|
||||
public void setAccessorPostProcessor(String accessorPostProcessor) {
|
||||
this.accessorPostProcessor = accessorPostProcessor;
|
||||
}
|
||||
|
||||
public String getAuthenticationInitializer() {
|
||||
return this.authenticationInitializer;
|
||||
}
|
||||
|
||||
public void setAuthenticationInitializer(String authenticationInitializer) {
|
||||
this.authenticationInitializer = authenticationInitializer;
|
||||
}
|
||||
|
||||
public String getAuthenticator() {
|
||||
return this.authenticator;
|
||||
}
|
||||
|
||||
public void setAuthenticator(String authenticator) {
|
||||
this.authenticator = authenticator;
|
||||
}
|
||||
|
||||
public String getDiffieHellmanAlgorithm() {
|
||||
return this.diffieHellmanAlgorithm;
|
||||
}
|
||||
|
||||
public void setDiffieHellmanAlgorithm(String diffieHellmanAlgorithm) {
|
||||
this.diffieHellmanAlgorithm = diffieHellmanAlgorithm;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure.configuration.support;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.geode.cache.DataPolicy;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link ConfigurationProperties} used to configure the {@link DataPolicy} of all {@link Region Regions}
|
||||
* in an Apache Geode cluster.
|
||||
*
|
||||
* The configuration {@link Properties} are based on well-known, documented Spring Data for Apache Geode (SDG)
|
||||
* {@link Properties}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.Properties
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.springframework.boot.context.properties.ConfigurationProperties
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ClusterProperties {
|
||||
|
||||
private final RegionProperties regionProperties = new RegionProperties();
|
||||
|
||||
public RegionProperties getRegion() {
|
||||
return this.regionProperties;
|
||||
}
|
||||
|
||||
public static class RegionProperties {
|
||||
|
||||
private RegionShortcut peerRegionType;
|
||||
|
||||
public RegionShortcut getType() {
|
||||
return this.peerRegionType;
|
||||
}
|
||||
|
||||
public void setType(RegionShortcut peerRegionType) {
|
||||
this.peerRegionType = peerRegionType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.geode.boot.autoconfigure.configuration.support;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.geode.cache.DiskStore;
|
||||
import org.apache.geode.cache.DiskStoreFactory;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Spring Boot {@link ConfigurationProperties} used to configure Apache Geode {@link DiskStore DiskStores}.
|
||||
*
|
||||
* The configuration {@link Properties} are based on well-known, documented Spring Data for Apache Geode (SDG)
|
||||
* {@link Properties}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.Properties
|
||||
* @see org.apache.geode.cache.DiskStore
|
||||
* @see org.apache.geode.cache.DiskStoreFactory
|
||||
* @see org.springframework.boot.context.properties.ConfigurationProperties
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DiskStoreProperties {
|
||||
|
||||
private final StoreProperties storeProperties = new StoreProperties();
|
||||
|
||||
public StoreProperties getStore() {
|
||||
return this.storeProperties;
|
||||
}
|
||||
|
||||
public static class DirectoryProperties {
|
||||
|
||||
private int size = DiskStoreFactory.DEFAULT_DISK_DIR_SIZE;
|
||||
|
||||
private String location;
|
||||
|
||||
public String getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StoreProperties {
|
||||
|
||||
private boolean allowForceCompaction = DiskStoreFactory.DEFAULT_ALLOW_FORCE_COMPACTION;
|
||||
private boolean autoCompact = DiskStoreFactory.DEFAULT_AUTO_COMPACT;
|
||||
|
||||
private float diskUsageCriticalPercentage = DiskStoreFactory.DEFAULT_DISK_USAGE_CRITICAL_PERCENTAGE;
|
||||
private float diskUsageWarningPercentage = DiskStoreFactory.DEFAULT_DISK_USAGE_WARNING_PERCENTAGE;
|
||||
|
||||
private int compactionThreshold = DiskStoreFactory.DEFAULT_COMPACTION_THRESHOLD;
|
||||
private int queueSize = DiskStoreFactory.DEFAULT_QUEUE_SIZE;
|
||||
private int writeBufferSize = DiskStoreFactory.DEFAULT_WRITE_BUFFER_SIZE;
|
||||
|
||||
private long maxOplogSize = DiskStoreFactory.DEFAULT_MAX_OPLOG_SIZE;
|
||||
private long timeInterval = DiskStoreFactory.DEFAULT_TIME_INTERVAL;
|
||||
|
||||
private DirectoryProperties[] directoryProperties = {};
|
||||
|
||||
public boolean isAllowForceCompaction() {
|
||||
return this.allowForceCompaction;
|
||||
}
|
||||
|
||||
public void setAllowForceCompaction(boolean allowForceCompaction) {
|
||||
this.allowForceCompaction = allowForceCompaction;
|
||||
}
|
||||
|
||||
public boolean isAutoCompact() {
|
||||
return this.autoCompact;
|
||||
}
|
||||
|
||||
public void setAutoCompact(boolean autoCompact) {
|
||||
this.autoCompact = autoCompact;
|
||||
}
|
||||
|
||||
public int getCompactionThreshold() {
|
||||
return this.compactionThreshold;
|
||||
}
|
||||
|
||||
public void setCompactionThreshold(int compactionThreshold) {
|
||||
this.compactionThreshold = compactionThreshold;
|
||||
}
|
||||
|
||||
public DirectoryProperties[] getDirectory() {
|
||||
return this.directoryProperties;
|
||||
}
|
||||
|
||||
public void setDirectory(DirectoryProperties[] directoryProperties) {
|
||||
this.directoryProperties = directoryProperties;
|
||||
}
|
||||
|
||||
public float getDiskUsageCriticalPercentage() {
|
||||
return this.diskUsageCriticalPercentage;
|
||||
}
|
||||
|
||||
public void setDiskUsageCriticalPercentage(float diskUsageCriticalPercentage) {
|
||||
this.diskUsageCriticalPercentage = diskUsageCriticalPercentage;
|
||||
}
|
||||
|
||||
public float getDiskUsageWarningPercentage() {
|
||||
return this.diskUsageWarningPercentage;
|
||||
}
|
||||
|
||||
public void setDiskUsageWarningPercentage(float diskUsageWarningPercentage) {
|
||||
this.diskUsageWarningPercentage = diskUsageWarningPercentage;
|
||||
}
|
||||
|
||||
public long getMaxOplogSize() {
|
||||
return this.maxOplogSize;
|
||||
}
|
||||
|
||||
public void setMaxOplogSize(long maxOplogSize) {
|
||||
this.maxOplogSize = maxOplogSize;
|
||||
}
|
||||
|
||||
public int getQueueSize() {
|
||||
return this.queueSize;
|
||||
}
|
||||
|
||||
public void setQueueSize(int queueSize) {
|
||||
this.queueSize = queueSize;
|
||||
}
|
||||
|
||||
public long getTimeInterval() {
|
||||
return this.timeInterval;
|
||||
}
|
||||
|
||||
public void setTimeInterval(long timeInterval) {
|
||||
this.timeInterval = timeInterval;
|
||||
}
|
||||
|
||||
public int getWriteBufferSize() {
|
||||
return this.writeBufferSize;
|
||||
}
|
||||
|
||||
public void setWriteBufferSize(int writeBufferSize) {
|
||||
this.writeBufferSize = writeBufferSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user