Rename modules.

Rename geode-spring-boot to spring-geode.

Rename geode-spring-boot-autoconfigure to spring-geode-autoconfigure.

Rename geode-spring-boot-starter to spring-geode-starter.

Rename gemfire-spring-boot-starter to spring-gemfire-starter.

Resolves GitHub Issue #6.
This commit is contained in:
John Blum
2018-06-19 18:35:09 -07:00
parent c830817ed3
commit 330dc7fec3
84 changed files with 5 additions and 5 deletions

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.cache.support;
import org.apache.geode.cache.CacheLoader;
/**
* The {@link CacheLoaderSupport} interface is an extension of {@link CacheLoader} and a {@link FunctionalInterface}
* useful in Lambda expressions.
*
* @author John Blum
* @see org.apache.geode.cache.CacheLoader
* @since 1.0.0
*/
@FunctionalInterface
public interface CacheLoaderSupport<K, V> extends CacheLoader<K, V> {
/**
* Closes any resources opened and used by this {@link CacheLoader}.
*
* @see org.apache.geode.cache.CacheLoader#close()
*/
@Override
default void close() {}
}

View File

@@ -0,0 +1,131 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.config.annotation;
import java.lang.annotation.Annotation;
import java.util.Optional;
import org.apache.geode.cache.Cache;
import org.apache.shiro.util.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer;
import org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer;
import org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport;
/**
* The {@link DistributedSystemIdConfiguration} class is a Spring {@link Configuration} class used to configure
* the {@literal distributed-system-id} for a {@link Cache peer Cache member} in a cluster
* when using the P2P topology.
*
* @author John Blum
* @see org.apache.geode.cache.Cache
* @see org.springframework.context.annotation.Bean
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.context.annotation.ImportAware
* @see org.springframework.core.annotation.AnnotationAttributes
* @see org.springframework.core.type.AnnotationMetadata
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
* @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer
* @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport
* @see org.springframework.geode.config.annotation.UseDistributedSystemId
* @since 1.0.0
*/
@Configuration
@SuppressWarnings("unused")
public class DistributedSystemIdConfiguration extends AbstractAnnotationConfigSupport implements ImportAware {
private static final String GEMFIRE_DISTRIBUTED_SYSTEM_ID_PROPERTY = "distributed-system-id";
private Integer distributedSystemId;
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
protected Class<? extends Annotation> getAnnotationType() {
return UseDistributedSystemId.class;
}
@Override
@SuppressWarnings("all")
public void setImportMetadata(AnnotationMetadata importMetadata) {
if (isAnnotationPresent(importMetadata)) {
AnnotationAttributes distributedSystemIdAttributes = getAnnotationAttributes(importMetadata);
setDistributedSystemId(distributedSystemIdAttributes.containsKey("value")
? distributedSystemIdAttributes.getNumber("value") : null);
setDistributedSystemId(distributedSystemIdAttributes.containsKey("id")
? distributedSystemIdAttributes.getNumber("id") : null);
}
}
protected void setDistributedSystemId(Integer distributedSystemId) {
this.distributedSystemId = Optional.ofNullable(distributedSystemId)
.filter(id -> id > -1)
.orElse(this.distributedSystemId);
}
protected Optional<Integer> getDistributedSystemId() {
return Optional.ofNullable(this.distributedSystemId)
.filter(id -> id > -1);
}
protected Logger getLogger() {
return this.logger;
}
private int validateDistributedSystemId(int distributedSystemId) {
Assert.isTrue(distributedSystemId >= -1 && distributedSystemId < 256,
String.format("Distributed System ID [%d] must be between -1 and 255", distributedSystemId));
return distributedSystemId;
}
@Bean
ClientCacheConfigurer clientCacheDistributedSystemIdConfigurer() {
return (beanName, clientCacheFactoryBean) -> getDistributedSystemId().ifPresent(distributedSystemId -> {
Logger logger = getLogger();
if (logger.isWarnEnabled()) {
logger.warn("Distributed System Id [{}] was set on the ClientCache instance, which will not have any effect",
distributedSystemId);
}
});
}
@Bean
PeerCacheConfigurer peerCacheDistributedSystemIdConfigurer() {
return (beanName, cacheFactoryBean) ->
getDistributedSystemId().ifPresent(id -> cacheFactoryBean.getProperties()
.setProperty(GEMFIRE_DISTRIBUTED_SYSTEM_ID_PROPERTY,
String.valueOf(validateDistributedSystemId(id))));
}
}

View File

@@ -0,0 +1,156 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.config.annotation;
import java.lang.annotation.Annotation;
import java.util.Optional;
import org.apache.geode.cache.client.ClientCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer;
import org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer;
import org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport;
import org.springframework.util.StringUtils;
/**
* The {@link DurableClientConfiguration} class is a Spring {@link Configuration} class used to configure
* this {@link ClientCache} instance as a {@literal Durable Client} by setting the {@literal durable-client-id}
* and {@literal durable-client-timeout} properties in addition to enabling {@literal keepAlive}
* on {@link ClientCache} shutdown.
*
* @author John Blum
* @see org.apache.geode.cache.client.ClientCache
* @see org.springframework.context.annotation.Bean
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.context.annotation.ImportAware
* @see org.springframework.core.annotation.AnnotationAttributes
* @see org.springframework.core.type.AnnotationMetadata
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
* @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer
* @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport
* @see org.springframework.geode.config.annotation.EnableDurableClient
* @since 1.0.0
*/
@Configuration
@SuppressWarnings("unused")
public class DurableClientConfiguration extends AbstractAnnotationConfigSupport implements ImportAware {
public static final boolean DEFAULT_KEEP_ALIVE = true;
public static final boolean DEFAULT_READY_FOR_EVENTS = true;
public static final int DEFAULT_DURABLE_CLIENT_TIMEOUT = 300;
private Boolean keepAlive = DEFAULT_KEEP_ALIVE;
private Boolean readyForEvents = DEFAULT_READY_FOR_EVENTS;
private Integer durableClientTimeout = DEFAULT_DURABLE_CLIENT_TIMEOUT;
private final Logger logger = LoggerFactory.getLogger(getClass());
private String durableClientId;
@Override
protected Class<? extends Annotation> getAnnotationType() {
return EnableDurableClient.class;
}
@Override
@SuppressWarnings("all")
public void setImportMetadata(AnnotationMetadata importMetadata) {
if (isAnnotationPresent(importMetadata)) {
AnnotationAttributes enableDurableClientAttributes = getAnnotationAttributes(importMetadata);
this.durableClientId = enableDurableClientAttributes.containsKey("id")
? enableDurableClientAttributes.getString("id")
: null;
this.durableClientTimeout = enableDurableClientAttributes.containsKey("timeout")
? enableDurableClientAttributes.getNumber("timeout")
: DEFAULT_DURABLE_CLIENT_TIMEOUT;
this.keepAlive = enableDurableClientAttributes.containsKey("keepAlive")
? enableDurableClientAttributes.getBoolean("keepAlive")
: DEFAULT_KEEP_ALIVE;
this.readyForEvents = enableDurableClientAttributes.containsKey("readyForEvents")
? enableDurableClientAttributes.getBoolean("readyForEvents")
: DEFAULT_READY_FOR_EVENTS;
}
}
protected Optional<String> getDurableClientId() {
return Optional.ofNullable(this.durableClientId)
.filter(StringUtils::hasText);
}
protected Integer getDurableClientTimeout() {
return Optional.ofNullable(this.durableClientTimeout)
.orElse(DEFAULT_DURABLE_CLIENT_TIMEOUT);
}
protected Boolean getKeepAlive() {
return Optional.ofNullable(this.keepAlive)
.orElse(DEFAULT_KEEP_ALIVE);
}
protected Boolean getReadyForEvents() {
return Optional.ofNullable(this.readyForEvents)
.orElse(DEFAULT_READY_FOR_EVENTS);
}
protected Logger getLogger() {
return this.logger;
}
@Bean
ClientCacheConfigurer clientCacheDurableClientConfigurer() {
return (beanName, clientCacheFactoryBean) -> getDurableClientId().ifPresent(durableClientId -> {
clientCacheFactoryBean.setDurableClientId(durableClientId);
clientCacheFactoryBean.setDurableClientTimeout(getDurableClientTimeout());
clientCacheFactoryBean.setKeepAlive(getKeepAlive());
clientCacheFactoryBean.setReadyForEvents(getReadyForEvents());
});
}
@Bean
PeerCacheConfigurer peerCacheDurableClientConfigurer() {
return (beanName, cacheFactoryBean) -> getDurableClientId().ifPresent(durableClientId -> {
Logger logger = getLogger();
if (logger.isWarnEnabled()) {
logger.warn("Durable Client ID [{}] was set on a peer Cache instance, which will not have any effect",
durableClientId);
}
});
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.config.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.apache.geode.cache.client.ClientCache;
import org.springframework.context.annotation.Import;
/**
* The {@link EnableDurableClient} annotation configures a {@link ClientCache} instance as a {@literal Durable Client}.
*
* @author John Blum
* @see java.lang.annotation.Documented
* @see java.lang.annotation.Inherited
* @see java.lang.annotation.Retention
* @see java.lang.annotation.Target
* @see org.apache.geode.cache.client.ClientCache
* @see org.springframework.context.annotation.Import
* @see org.springframework.geode.config.annotation.DurableClientConfiguration
* @since 1.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DurableClientConfiguration.class)
@SuppressWarnings("unused")
public @interface EnableDurableClient {
/**
* Used only for clients in a client/server installation. If set, this indicates that the client is durable
* and identifies the client. The ID is used by servers to reestablish any messaging that was interrupted
* by client downtime.
*/
String id();
/**
* Configure whether the server should keep the durable client's queues alive for the timeout period.
*
* Defaults to {@literal true}.
*/
boolean keepAlive() default DurableClientConfiguration.DEFAULT_KEEP_ALIVE;
/**
* Configures whether the {@link ClientCache} is ready to recieve events on startup.
*
* Defaults to {@literal true}.
*/
boolean readyForEvents() default DurableClientConfiguration.DEFAULT_READY_FOR_EVENTS;
/**
* Used only for clients in a client/server installation. Number of seconds this client can remain disconnected
* from its server and have the server continue to accumulate durable events for it.
*
* Defaults to {@literal 300 seconds}, or {@literal 5 minutes}.
*/
int timeout() default DurableClientConfiguration.DEFAULT_DURABLE_CLIENT_TIMEOUT;
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.config.annotation;
import java.lang.annotation.Annotation;
import java.util.Optional;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.client.ClientCache;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
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.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport;
import org.springframework.util.StringUtils;
/**
* The {@link GroupsConfiguration} class is a Spring {@link Configuration} class used to configure the {@literal groups}
* in which is member belongs in an Apache Geode/Pivotal GemFire distributed system, whether the member
* is a {@link ClientCache} in a client/server topology or a {@link Cache peer Cache} in a cluster
* using the P2P topology.
*
* @author John Blum
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.client.ClientCache
* @see org.springframework.context.annotation.Bean
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.context.annotation.ImportAware
* @see org.springframework.core.annotation.AnnotationAttributes
* @see org.springframework.core.type.AnnotationMetadata
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
* @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer
* @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport
* @see org.springframework.geode.config.annotation.UseGroups
* @since 1.0.0
*/
@Configuration
@SuppressWarnings("unused")
public class GroupsConfiguration extends AbstractAnnotationConfigSupport implements ImportAware {
private static final String GEMFIRE_GROUPS_PROPERTY = "groups";
private String[] groups = {};
@Override
protected Class<? extends Annotation> getAnnotationType() {
return UseGroups.class;
}
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
if (isAnnotationPresent(importMetadata)) {
AnnotationAttributes inGroupsAttributes = getAnnotationAttributes(importMetadata);
setGroups(inGroupsAttributes.containsKey("value")
? inGroupsAttributes.getStringArray("value") : null);
setGroups(inGroupsAttributes.containsKey("groups")
? inGroupsAttributes.getStringArray("groups") : null);
}
}
protected void setGroups(String[] groups) {
this.groups = Optional.ofNullable(groups)
.filter(it -> it.length > 0)
.orElse(this.groups);
}
protected Optional<String[]> getGroups() {
return Optional.ofNullable(this.groups)
.filter(it -> it.length > 0);
}
@Bean
ClientCacheConfigurer clientCacheGroupsConfigurer() {
return (beaName, clientCacheFactoryBean) -> configureGroups(clientCacheFactoryBean);
}
@Bean
PeerCacheConfigurer peerCacheGroupsConfigurer() {
return (beaName, peerCacheFactoryBean) -> configureGroups(peerCacheFactoryBean);
}
private void configureGroups(CacheFactoryBean cacheFactoryBean) {
getGroups().ifPresent(groups -> cacheFactoryBean.getProperties()
.setProperty(GEMFIRE_GROUPS_PROPERTY, StringUtils.arrayToCommaDelimitedString(groups)));
}
}

View File

@@ -0,0 +1,112 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.config.annotation;
import java.lang.annotation.Annotation;
import java.util.Optional;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.client.ClientCache;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
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.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport;
import org.springframework.util.StringUtils;
/**
* The {@link MemberNameConfiguration} class is a Spring {@link Configuration} class used to configure
* an Apache Geode or Pivotal GemFire's member name in the distributed system, whether the member
* is a {@link ClientCache client} in the client/server topology or a {@link Cache peer} in a cluster
* using the P2P topology.
*
* @author John Blum
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.client.ClientCache
* @see org.springframework.context.annotation.Bean
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.context.annotation.ImportAware
* @see org.springframework.core.annotation.AnnotationAttributes
* @see org.springframework.core.type.AnnotationMetadata
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
* @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer
* @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport
* @see org.springframework.geode.config.annotation.UseMemberName
* @since 1.0.0
*/
@Configuration
@SuppressWarnings("unused")
public class MemberNameConfiguration extends AbstractAnnotationConfigSupport implements ImportAware {
private static final String GEMFIRE_NAME_PROPERTY = "name";
private String memberName;
@Override
protected Class<? extends Annotation> getAnnotationType() {
return UseMemberName.class;
}
@Override
@SuppressWarnings("all")
public void setImportMetadata(AnnotationMetadata importMetadata) {
if (isAnnotationPresent(importMetadata)) {
AnnotationAttributes memberNameAttributes = getAnnotationAttributes(importMetadata);
setMemberName(memberNameAttributes.containsKey("value")
? memberNameAttributes.getString("value") : null);
setMemberName(memberNameAttributes.containsKey("name")
? memberNameAttributes.getString("name") : null);
}
}
protected void setMemberName(String memberName) {
this.memberName = Optional.ofNullable(memberName)
.filter(StringUtils::hasText)
.orElse(this.memberName);
}
protected Optional<String> getMemberName() {
return Optional.ofNullable(this.memberName)
.filter(StringUtils::hasText);
}
@Bean
ClientCacheConfigurer clientCacheMemberNameConfigurer() {
return (beaName, clientCacheFactoryBean) -> configureMemberName(clientCacheFactoryBean);
}
@Bean
PeerCacheConfigurer peerCacheMemberNameConfigurer() {
return (beaName, peerCacheFactoryBean) -> configureMemberName(peerCacheFactoryBean);
}
private void configureMemberName(CacheFactoryBean cacheFactoryBean) {
getMemberName().ifPresent(memberName ->
cacheFactoryBean.getProperties().setProperty(GEMFIRE_NAME_PROPERTY, memberName));
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.config.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.client.ClientCache;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.AliasFor;
/**
* The {@link UseDistributedSystemId} annotation configures the {@literal distributed-system-id} property
* of a {@link Cache peer Cache member} in an Apache Geode/Pivotal GemFire P2P topology.
*
* This configuration annotation is only applicable on {@link Cache peer Cache members}
* and has no effect on {@link ClientCache} instances.
*
* @author John Blum
* @see java.lang.annotation.Documented
* @see java.lang.annotation.Inherited
* @see java.lang.annotation.Retention
* @see java.lang.annotation.Target
* @see org.apache.geode.cache.Cache
* @see org.springframework.context.annotation.Import
* @see org.springframework.core.annotation.AliasFor
* @see org.springframework.geode.config.annotation.DistributedSystemIdConfiguration
* @since 1.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DistributedSystemIdConfiguration.class)
@SuppressWarnings("unused")
public @interface UseDistributedSystemId {
/**
* Configures the identifier used to distinguish messages from different distributed systems.
*
* This is required for Portable Data eXchange (PDX) data serialization.
*
* Set distributed-system-id to different values for different systems in a multi-site (WAN) configuration,
* and to different values for production vs. development environments. This setting must be the same
* for every member of a given distributed system and unique to each distributed system within a WAN installation.
*
* Valid values are integers in the range -1…255. -1 means no setting.
*
* Defaults to {@literal -1}.
*/
@AliasFor("id")
int value() default -1;
/**
* Configures the identifier used to distinguish messages from different distributed systems.
*
* Alias for {@literal #value()}.
*/
@AliasFor("value")
int id() default -1;
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.config.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.client.ClientCache;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.AliasFor;
/**
* The {@link UseGroups} annotation configures the groups in which the member belongs in an Apache Geode
* or Pivotal GemFire distributed system, whether the member is a {@link ClientCache} in a client/server topology
* or a {@link Cache peer Cache} in a cluster using the P2P topology.
*
* @author John Blum
* @see java.lang.annotation.Documented
* @see java.lang.annotation.Inherited
* @see java.lang.annotation.Retention
* @see java.lang.annotation.Target
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.client.ClientCache
* @see org.springframework.context.annotation.Import
* @see org.springframework.core.annotation.AliasFor
* @see org.springframework.geode.config.annotation.GroupsConfiguration
* @since 1.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(GroupsConfiguration.class)
@SuppressWarnings("unused")
public @interface UseGroups {
@AliasFor("groups")
String[] value() default {};
@AliasFor("value")
String[] groups() default {};
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.config.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.client.ClientCache;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.AliasFor;
/**
* The {@link UseMemberName} annotation configures the {@literal name} of the member in the Apache Geode
* or Pivotal GemFire distributed system, whether the member is a {@link ClientCache client} in
* the client/server topology or a {@link Cache peer Cache member} in the cluster using the P2P topology.
*
* @author John Blum
* @see java.lang.annotation.Documented
* @see java.lang.annotation.Inherited
* @see java.lang.annotation.Retention
* @see java.lang.annotation.Target
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.client.ClientCache
* @see org.springframework.context.annotation.Import
* @see org.springframework.core.annotation.AliasFor
* @see org.springframework.geode.config.annotation.MemberNameConfiguration
* @since 1.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(MemberNameConfiguration.class)
public @interface UseMemberName {
/**
* {@link String Name} used for the Apache Geode/Pivotal GemFire distributed system member.
*
* @see #name()
*/
@AliasFor("name")
String value() default "";
/**
* Alias for the {@link String name} of the Apache Geode/Pivotal GemFire distributed system member.
*
* @see #value()
*/
@AliasFor("value")
String name() default "";
}

View File

@@ -0,0 +1,239 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.core.env;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.geode.core.env.support.CloudCacheService;
import org.springframework.geode.core.env.support.Service;
import org.springframework.geode.core.env.support.User;
import org.springframework.geode.core.util.ObjectUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
/**
* The {@link VcapPropertySource} class is a Spring {@link PropertySource} to process
* {@literal VCAP} environment properties in Pivotal CloudFoundry.
*
* @author John Blum
* @see java.lang.Iterable
* @see java.net.URL
* @see java.util.Properties
* @see java.util.function.Predicate
* @see org.springframework.core.env.EnumerablePropertySource
* @see org.springframework.core.env.Environment
* @see org.springframework.core.env.PropertiesPropertySource
* @see org.springframework.core.env.PropertySource
* @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
*/
@SuppressWarnings("unused")
public class VcapPropertySource extends PropertySource<EnumerablePropertySource<?>> implements Iterable<String> {
private static final String CLOUD_CACHE_TAG_NAME = "cloudcache";
private static final String GEMFIRE_TAG_NAME = "gemfire";
private static final String THIS_PROPERTY_SOURCE_NAME = "boot.data.gemfire.vcap";
private static final String VCAP_APPLICATION_PROPERTY = "vcap.application.";
private static final String VCAP_APPLICATION_NAME_PROPERTY = VCAP_APPLICATION_PROPERTY + "name";
private static final String VCAP_APPLICATION_URIS_PROPERTY = VCAP_APPLICATION_PROPERTY + "uris";
private static final String VCAP_PROPERTY_SOURCE_NAME = "vcap";
private static final String VCAP_SERVICES_PROPERTY = "vcap.services.";
private static final String VCAP_SERVICES_SERVICE_NAME_GFSH_URL_PROPERTY = "vcap.services.%s.credentials.urls.gfsh";
private static final String VCAP_SERVICES_SERVICE_NAME_LOCATORS_PROPERTY = "vcap.services.%s.credentials.locators";
private static final String VCAP_SERVICES_SERVICE_NAME_USERS_PROPERTY = "vcap.services.%s.credentials.users[%d]";
private static final Predicate<Object> CLOUD_CACHE_SERVICE_PREDICATE =
propertyValue -> String.valueOf(propertyValue).toLowerCase().contains(CLOUD_CACHE_TAG_NAME);
private static final Predicate<Object> GEMFIRE_SERVICE_PREDICATE =
propertyValue -> String.valueOf(propertyValue).toLowerCase().contains(GEMFIRE_TAG_NAME);
private static final Predicate<Object> CLOUD_CACHE_AND_GEMFIRE_SERVICE_PREDICATE =
CLOUD_CACHE_SERVICE_PREDICATE.and(GEMFIRE_SERVICE_PREDICATE);
private static final Predicate<String> VCAP_APPLICATION_PROPERTIES_PREDICATE =
propertyName -> String.valueOf(propertyName).trim().toLowerCase().startsWith(VCAP_APPLICATION_PROPERTY);
private static final Predicate<PropertySource> VCAP_REQUIRED_PROPERTIES_PREDICATE =
propertySource -> propertySource.containsProperty(VCAP_APPLICATION_NAME_PROPERTY)
&& propertySource.containsProperty(VCAP_APPLICATION_URIS_PROPERTY);
private static final Predicate<String> VCAP_SERVICES_PROPERTIES_PREDICATE =
propertyName -> String.valueOf(propertyName).trim().toLowerCase().startsWith(VCAP_SERVICES_PROPERTY);
public static VcapPropertySource from(Environment environment) {
return Optional.ofNullable(environment)
.filter(env -> env instanceof ConfigurableEnvironment)
.map(env -> ((ConfigurableEnvironment) env).getPropertySources())
.map(propertySources -> propertySources.get(VCAP_PROPERTY_SOURCE_NAME))
.map(VcapPropertySource::from)
.orElseThrow(() -> newIllegalArgumentException(
"Environment was not configurable or does not contain an enumerable [%s] PropertySource",
VCAP_PROPERTY_SOURCE_NAME));
}
public static VcapPropertySource from(Properties properties) {
return Optional.ofNullable(properties)
.map(it -> new PropertiesPropertySource(THIS_PROPERTY_SOURCE_NAME, properties))
.filter(VCAP_REQUIRED_PROPERTIES_PREDICATE)
.map(VcapPropertySource::new)
.orElseThrow(() -> newIllegalArgumentException("Properties are required"));
}
public static VcapPropertySource from(PropertySource<?> propertySource) {
return Optional.ofNullable(propertySource)
.filter(it -> VCAP_PROPERTY_SOURCE_NAME.equals(it.getName()))
.filter(it -> it instanceof EnumerablePropertySource)
.filter(VCAP_REQUIRED_PROPERTIES_PREDICATE)
.map(it -> (EnumerablePropertySource) it)
.map(VcapPropertySource::new)
.orElseThrow(() -> newIllegalArgumentException(
"A valid EnumerablePropertySource named [%s] with VCAP properties is required",
VCAP_PROPERTY_SOURCE_NAME));
}
private VcapPropertySource(EnumerablePropertySource<?> propertySource) {
super(THIS_PROPERTY_SOURCE_NAME, propertySource);
}
protected Set<String> findAllPropertiesByNameMatching(Predicate<String> predicate) {
return findAllPropertiesByNameMatching(this, predicate);
}
protected Set<String> findAllPropertiesByNameMatching(Iterable<String> properties, Predicate<String> predicate) {
return StreamSupport.stream(properties.spliterator(), false)
.filter(predicate)
.collect(Collectors.toSet());
}
protected Set<String> findAllPropertiesByValueMatching(Predicate<Object> predicate) {
return findAllPropertiesByValueMatching(this, predicate);
}
protected Set<String> findAllPropertiesByValueMatching(Iterable<String> properties, Predicate<Object> predicate) {
return StreamSupport.stream(properties.spliterator(), false)
.filter(propertyName -> predicate.test(getProperty(propertyName)))
.collect(Collectors.toSet());
}
public Set<String> findAllVcapApplicationProperties() {
return findAllPropertiesByNameMatching(VCAP_APPLICATION_PROPERTIES_PREDICATE);
}
public Set<String> findAllVcapServicesProperties() {
return findAllPropertiesByNameMatching(VCAP_SERVICES_PROPERTIES_PREDICATE);
}
public CloudCacheService findFirstCloudCacheService() {
String serviceName = findFirstCloudCacheServiceName();
CloudCacheService service = CloudCacheService.with(serviceName);
Optional.ofNullable(getProperty(String.format(VCAP_SERVICES_SERVICE_NAME_LOCATORS_PROPERTY, serviceName)))
.map(String::valueOf)
.ifPresent(service::withLocators);
Optional.ofNullable(getProperty(String.format(VCAP_SERVICES_SERVICE_NAME_GFSH_URL_PROPERTY, service)))
.map(String::valueOf)
.map(urlString -> ObjectUtils.doOperationSafely(() -> new URL(urlString)))
.ifPresent(service::withGfshUrl);
return service;
}
public String findFirstCloudCacheServiceName() {
Iterable<String> vcapServicesProperties = findAllVcapServicesProperties();
return findAllPropertiesByValueMatching(vcapServicesProperties, CLOUD_CACHE_AND_GEMFIRE_SERVICE_PREDICATE)
.stream()
.filter(propertyName -> propertyName.endsWith(".tags"))
.map(propertyName -> propertyName.substring(VCAP_SERVICES_PROPERTY.length()))
.map(propertyName -> propertyName.substring(0, propertyName.indexOf(".")))
.filter(StringUtils::hasText)
.sorted(String.CASE_INSENSITIVE_ORDER)
.findFirst()
.orElseThrow(() ->
newIllegalStateException("No service with tags [%1$s, %2$s] was found",
CLOUD_CACHE_TAG_NAME, GEMFIRE_TAG_NAME));
}
public Optional<User> findFirstUserByRoleClusterOperator(Service service) {
String serviceName = service.getName();
String userPropertyName = String.format(VCAP_SERVICES_SERVICE_NAME_USERS_PROPERTY, serviceName, 0);
for (int index = 1; containsProperty(userPropertyName+".roles"); index++) {
String roles = String.valueOf(getProperty(userPropertyName+".roles"));
if (roles.contains(User.Role.CLUSTER_OPERATOR.name().toLowerCase())) {
break;
}
userPropertyName = String.format(VCAP_SERVICES_SERVICE_NAME_USERS_PROPERTY, serviceName, index);
}
if (containsProperty(userPropertyName+".username")) {
String username = String.valueOf(getProperty(userPropertyName+".username"));
String password = String.valueOf(getProperty(userPropertyName+".password"));
return Optional.of(User.with(username).withPassword(password).withRole(User.Role.CLUSTER_OPERATOR));
}
return Optional.empty();
}
@Nullable
@Override
@SuppressWarnings("all")
public Object getProperty(String name) {
return getSource().getProperty(name);
}
@Override
@SuppressWarnings("all")
public Iterator<String> iterator() {
return Collections.unmodifiableList(Arrays.asList(getSource().getPropertyNames())).iterator();
}
}

View File

@@ -0,0 +1,345 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.core.env.support;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.data.gemfire.GemfireUtils;
import org.springframework.geode.core.util.ObjectUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* The {@link CloudCacheService} class is an Abstract Data Type (ADT) modeling the Pivotal Cloud Cache service
* in Pivotal CloudFoundry (PCF).
*
* @author John Blum
* @see java.net.URL
* @see org.springframework.geode.core.env.support.Service
* @since 1.0.0
*/
public class CloudCacheService extends Service {
/**
* Factory method used to construct a new {@link CloudCacheService} initialized with the given {@link String name}.
*
* @param name {@link String} containing the name of the {@link CloudCacheService}.
* @throws IllegalArgumentException if the {@link String name} is {@literal null} or empty.
* @return the new {@link CloudCacheService} with the given {@link String name}.
* @see #CloudCacheService(String)
*/
public static CloudCacheService with(String name) {
return new CloudCacheService(name);
}
private String locators;
private URL gfshUrl;
/**
* Construct a new instance of {@link CloudCacheService} initialized with the given {@link String name}.
*
* @param name {@link String} containing the name of the {@link CloudCacheService}.
* @throws IllegalArgumentException if the {@link String name} is {@literal null} or empty.
*/
private CloudCacheService(String name) {
super(name);
}
/**
* Returns an {@link Optional} Gfsh {@link URL}, if configured, used to connect to Pivotal GemFire's
* Management REST API (service).
*
* @return an {@link Optional} Gfsh {@link URL} used to connect to Pivotal GemFire's Management REST API (service).
* @see #withGfshUrl(URL)
* @see java.util.Optional
* @see java.net.URL
*/
public Optional<URL> getGfshUrl() {
return Optional.ofNullable(this.gfshUrl);
}
/**
* Returns an {@link Optional} {@link String} containing the list of Pivotal GemFire Locator network endpoints.
*
* The format of the {@link String}, if present, is {@literal host1[port1],host2[port2], ...,hostN[portN]}.
*
* @return an {@link Optional} {@link String} containing the list of Pivotal GemFire Locator network endpoints.
* @see #withLocators(String)
*/
public Optional<String> getLocators() {
return Optional.ofNullable(this.locators).filter(StringUtils::hasText);
}
/**
* Returns a {@link List} of Pivotal GemFire Locator network endpoints.
*
* Returns an {@link Collections#emptyList() empty List} if no Locators were configured.
*
* @return a {@link List} of Pivotal GemFire Locator network endpoints.
* @see #getLocators()
*/
public List<Locator> getLocatorList() {
return getLocators()
.map(Locator::parseLocators)
.orElseGet(Collections::emptyList);
}
/**
* Builder method used to configure the Gfsh {@link URL} to connect to the Pivotal GemFire
* Management REST API (service).
*
* @param gfshUrl {@link URL} used to connect to the Pivotal GemFire Management REST API (service).
* @return this {@link CloudCacheService}.
* @see #getGfshUrl()
*/
public CloudCacheService withGfshUrl(URL gfshUrl) {
this.gfshUrl = gfshUrl;
return this;
}
/**
* Builder method used to configure the {@link String list of Locator} network endpoints.
*
* @param locators {@link String} containing a comma-delimited list of Locator network endpoints
* of the format: {@literal host1[port1],host2[port2], ...,hostN[portN]}.
* @return this {@link CloudCacheService}.
* @see #getLocators()
*/
public CloudCacheService withLocators(String locators) {
this.locators = locators;
return this;
}
public static class Locator implements Comparable<Locator> {
static final int DEFAULT_LOCATOR_PORT = GemfireUtils.DEFAULT_LOCATOR_PORT;
static final String DEFAULT_LOCATOR_HOST = "localhost";
private Integer port;
private String host;
/**
* Factory method used to construct a new {@link Locator} on the default {@link String host}
* and {@link Integer port}.
*
* @return a new, default {@link Locator}.
* @see #newLocator(String, int)
*/
public static Locator newLocator() {
return newLocator(DEFAULT_LOCATOR_HOST, DEFAULT_LOCATOR_PORT);
}
/**
* Factory method used to construct a new {@link Locator} running on the default {@link String host}
* and configured to listen on the given {@link Integer port}.
*
* @param port {@link Integer} containing the port number on which the {@link Locator} is listening.
* @return a new {@link Locator} running on the default {@link String host},
* listening on the given {@link Integer port}.
* @throws IllegalArgumentException if the {@link Integer port} is less than {@literal 0}.
* @see #newLocator(String, int)
*/
public static Locator newLocator(int port) {
return newLocator(DEFAULT_LOCATOR_HOST, port);
}
/**
* Factory method used to construct a new {@link Locator} configured to run on the given {@link String host}
* and listening on the default {@link Integer port}.
*
* @param host {@link String} containing the name of the host on which the {@link Locator} is running.
* @return a new {@link Locator} running on the configured {@link String host},
* listening on the default {@link Integer port}.
* @throws IllegalArgumentException if {@link String host} is {@literal null} or empty.
* @see #newLocator(String, int)
*/
public static Locator newLocator(String host) {
return newLocator(host, DEFAULT_LOCATOR_PORT);
}
/**
* Factory method used to construct a new {@link Locator} running on the configured {@link String host}
* and listening on the configured {@link Integer port}.
*
* @param host {@link String} containing the name of the host on which the {@link Locator} is running.
* @param port {@link Integer} containing the port number on which the {@link Locator} is listening.
* @throws IllegalArgumentException if {@link String host} is {@literal null} or empty,
* or the {@link Integer port} is less than {@literal 0}.
* @return a new {@link Locator} on the configured {@link String host} and {@link Integer port}.
*/
public static Locator newLocator(String host, int port) {
Assert.hasText(host, String.format("Host [%s] is required", host));
Assert.isTrue(port > -1, String.format("Port [%d] must be greater than equal to 0", port));
return new Locator(host, port);
}
/**
* Factory method used to parse a {@link String comma-delimited list of Locator network endpoints}
* into a {@link List} of {@link Locator} objects.
*
* The {@link String comma-delimited list of Locators} must be formatted as
* {@literal host1[port1],host2[port2], ...,hostN[portN]}.
*
* @param locators {@link String} containing a comma-delimited list of Locator network endpoints.
* @return a new {@link List} of {@link Locator} objects or an empty {@link List}
* if no Locators were specified.
* @throws IllegalArgumentException if an individual Locator {@link String host[port]} is not valid.
* @see #parse(String)
*/
public static List<Locator> parseLocators(String locators) {
return Arrays.stream(String.valueOf(locators).split(","))
.filter(StringUtils::hasText)
.map(Locator::parse)
.collect(Collectors.toList());
}
/**
* Factory method used to parse an individual {@link String host[port]} network endpoint for a Locator.
*
* @param hostPort {@link String} containing the Locator host and port to parse.
* @return a new {@link Locator} configured from the given {@link String}.
* @throws IllegalArgumentException if the {@link String hostPort} are not valid.
* @see #parseHost(String)
* @see #parsePort(String)
* @see #newLocator(String, int)
*/
public static Locator parse(String hostPort) {
return Optional.ofNullable(hostPort)
.filter(StringUtils::hasText)
.map(it -> {
String host = parseHost(it);
int port = parsePort(it);
return newLocator(host, port);
})
.orElseThrow(() -> newIllegalArgumentException("Locator host/port [%s] is not valid", hostPort));
}
private static String parseHost(String value) {
int index = String.valueOf(value).trim().indexOf("[");
return index > 0 ? value.trim().substring(0, index).trim()
: (index != 0 && StringUtils.hasText(value) ? value.trim() : DEFAULT_LOCATOR_HOST);
}
private static int parsePort(String value) {
StringBuilder digits = new StringBuilder();
for (char chr : String.valueOf(value).toCharArray()) {
if (Character.isDigit(chr)) {
digits.append(chr);
}
}
return digits.length() > 0 ? Integer.valueOf(digits.toString()) : DEFAULT_LOCATOR_PORT;
}
/**
* Construct a new {@link Locator} initialized with the {@link String host} and {@link Integer port}
* on which this {@link Locator} is running and listening for connections.
*
* @param host {@link String} containing the name of the host on which this {@link Locator} is running.
* @param port {@link Integer} specifying the port number on which this {@link Locator} is listening.
*/
private Locator(String host, Integer port) {
this.host = host;
this.port = port;
}
/**
* Return the {@link String name} of the host on which this {@link Locator} is running.
*
* Defaults to {@literal localhost}.
*
* @return the {@link String name} of the host on which this {@link Locator} is running.
*/
public String getHost() {
return Optional.ofNullable(this.host).filter(StringUtils::hasText).orElse(DEFAULT_LOCATOR_HOST);
}
/**
* Returns the {@link Integer port} on which this {@link Locator} is listening.
*
* Defaults to {@literal 10334}.
*
* @return the {@link Integer port} on which this {@link Locator} is listening.
*/
public int getPort() {
return Optional.ofNullable(this.port).orElse(DEFAULT_LOCATOR_PORT);
}
@Override
@SuppressWarnings("all")
public int compareTo(Locator other) {
int result = this.getHost().compareTo(other.getHost());
return result != 0 ? result : (this.getPort() - other.getPort());
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Locator)) {
return false;
}
Locator that = (Locator) obj;
return this.getHost().equals(that.getHost())
&& this.getPort() == that.getPort();
}
@Override
public int hashCode() {
int hashValue = 17;
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getHost());
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getPort());
return hashValue;
}
@Override
public String toString() {
return String.format("%s[%d]", getHost(), getPort());
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.core.env.support;
import org.springframework.util.Assert;
/**
* The {@link Service} class is an Abstract Data Type (ADT) modeling a Pivotal CloudFoundry Service.
*
* @author John Blum
* @since 1.0.0
*/
@SuppressWarnings("unused")
public class Service {
/**
* Factory method to construct a new {@link Service} initialized with a {@link String name}.
*
* @param name {@link String} containing the name of the {@link Service}.
* @return a new {@link Service} configured with the given {@link String name}.
* @throws IllegalArgumentException if the {@link String name} is {@literal null} or empty.
* @see #Service(String)
*/
public static Service with(String name) {
return new Service(name);
}
private final String name;
/**
* Constructs a new {@link Service} initialized with a {@link String name}.
*
* @param name {@link String} containing the name of the {@link Service}.
* @throws IllegalArgumentException if the {@link String name} is {@literal null} or empty.
*/
Service(String name) {
Assert.hasText(name, String.format("Service name [%s] is required", name));
this.name = name;
}
/**
* Returns the {@link String name} of this {@link Service}.
*
* @return this {@link Service Service's} {@link String name}.
*/
public String getName() {
return this.name;
}
@Override
public String toString() {
return getName();
}
}

View File

@@ -0,0 +1,182 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.core.env.support;
import java.util.Arrays;
import java.util.Optional;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* The {@link User} class is an Abstract Data Type (ADT) modeling a user in Pivotal CloudFoundry (PCF).
*
* @author John Blum
* @since 1.0.0
*/
@SuppressWarnings("unused")
public class User implements Comparable<User> {
private Role role;
private final String name;
private String password;
/**
* Factory method used to construct a new {@link User} initialized with the given {@link String name}.
*
* @param name {@link String} containing the name of the {@link User}.
* @return a new {@link User} initialized witht he given {@link String name}.
* @throws IllegalArgumentException if {@link String name} is {@literal null} or empty.
* @see #User(String)
*/
public static User with(String name) {
return new User(name);
}
/**
* Constructs a new {@link User} initialized with the given {@link String name}.
*
* @param name {@link String} containing the name of the {@link User}.
* @throws IllegalArgumentException if {@link String name} is {@literal null} or empty.
*/
private User(String name) {
Assert.hasText(name, String.format("User name [%s] is required", name));
this.name = name;
}
/**
* Returns the {@link String name} of this {@link User}.
*
* @return a {@link String} containing the {@link User User's} name.
*/
public String getName() {
return this.name;
}
/**
* Returns an {@link Optional} {@link String} containing {@link User User's} password.
*
* @return an {@link Optional} {@link String} containing {@link User User's} password.
* @see java.util.Optional
*/
public Optional<String> getPassword() {
return Optional.ofNullable(this.password).filter(StringUtils::hasText);
}
/**
* Returns an {@link Optional} {@link Role} for this {@link User}.
*
* @return an {@link Optional} {@link Role} for this {@link User}.
* @see org.springframework.geode.core.env.support.User.Role
* @see java.util.Optional
*/
public Optional<Role> getRole() {
return Optional.ofNullable(this.role);
}
/**
* Builder method used to set this {@link User User's} {@link String password}.
*
* @param password {@link String} containing this {@link User User's} password.
* @return this {@link User}.
*/
public User withPassword(String password) {
this.password = password;
return this;
}
/**
* Builder method used to set this {@link User User's} {@link Role}.
*
* @param role assigned {@link Role} of this {@link User}.
* @return this {@link User}.
* @see org.springframework.geode.core.env.support.User
*/
public User withRole(Role role) {
this.role = role;
return this;
}
@Override
@SuppressWarnings("all")
public int compareTo(User other) {
return this.getName().compareTo(other.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 + ObjectUtils.nullSafeHashCode(getName());
return hashValue;
}
@Override
public String toString() {
return getName();
}
public enum Role {
CLUSTER_OPERATOR,
DEVELOPER;
public static Role of(String name) {
return Arrays.stream(values())
.filter(role -> role.name().equalsIgnoreCase(String.valueOf(name).trim()))
.findFirst()
.orElse(null);
}
public boolean isClusterOperator() {
return CLUSTER_OPERATOR.equals(this);
}
public boolean isDeveloper() {
return DEVELOPER.equals(this);
}
@Override
public String toString() {
return name().toLowerCase();
}
}
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.core.util;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.Nullable;
/**
* The {@link ObjectUtils} class is an abstract utility class with operations for {@link Object objects}.
*
* @author John Blum
* @see java.lang.Object
* @since 1.0.0
*/
@SuppressWarnings("all")
public abstract class ObjectUtils extends org.springframework.util.ObjectUtils {
private static final Logger logger = LoggerFactory.getLogger(ObjectUtils.class);
/**
* Executes the given {@link ExceptionThrowingOperation} handling any checked {@link Exception} thrown during
* the normal execution of the operation by rethrowing an {@link IllegalStateException} wrapping
* the checked {@link Exception}.
*
* @param <T> {@link Class type} of the operation result.
* @param operation {@link ExceptionThrowingOperation} to execute.
* @return the result of the given {@link ExceptionThrowingOperation} or throw an {@link IllegalStateException}
* wrapping the checked {@link Exception} thrown by the operation.
* @see org.springframework.geode.core.util.ObjectUtils.ExceptionThrowingOperation
* @see #doOperationSafely(ExceptionThrowingOperation, Object)
*/
@Nullable
public static <T> T doOperationSafely(ExceptionThrowingOperation<T> operation) {
return doOperationSafely(operation, null);
}
/**
* Executes the given {@link ExceptionThrowingOperation} handling any checked {@link Exception} thrown
* during the normal execution of the operation, returning the {@link Object default value} in its place
* or throwing a {@link RuntimeException} if the {@link Object default value} is {@literal null}.
*
* @param <T> {@link Class type} of the operation result as well as the {@link Object default value}.
* @param operation {@link ExceptionThrowingOperation} to execute.
* @param defaultValue {@link Object value} to return if the operation results in a checked {@link Exception}.
* @return the result of the given {@link ExceptionThrowingOperation}, returning the {@link Object default value}
* if the operation throws a checked {@link Exception} or throws an {@link IllegalStateException} wrapping
* the checked {@link Exception} if the {@link Object default value} is {@literal null}.
* @throws IllegalStateException if the {@link ExceptionThrowingOperation} throws a checked {@link Exception}
* and {@link Object default value} is {@literal null}.
* @see org.springframework.geode.core.util.ObjectUtils.ExceptionThrowingOperation
* @see #returnValueThrowOnNull(Object, RuntimeException)
*/
@Nullable
public static <T> T doOperationSafely(ExceptionThrowingOperation<T> operation, T defaultValue) {
try {
return operation.doExceptionThrowingOperation();
}
catch (Exception cause) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Failed to execute operation [%s]", operation), cause);
}
return returnValueThrowOnNull(defaultValue,
newIllegalStateException(cause, "Failed to execute operation"));
}
}
/**
* Returns the given {@link Object value} or throws an {@link IllegalArgumentException}
* if {@link Object value} is {@literal null}.
*
* @param <T> {@link Class type} of the {@link Object value}.
* @param value {@link Object} to return.
* @return the {@link Object value} or throw an {@link IllegalArgumentException}
* if {@link Object value} is {@literal null}.
* @see #returnValueThrowOnNull(Object, RuntimeException)
*/
public static <T> T returnValueThrowOnNull(T value) {
return returnValueThrowOnNull(value, newIllegalArgumentException("Value must not be null"));
}
/**
* Returns the given {@link Object value} or throws the given {@link RuntimeException}
* if {@link Object value} is {@literal null}.
*
* @param <T> {@link Class type} of the {@link Object value}.
* @param value {@link Object} to return.
* @param exception {@link RuntimeException} to throw if {@link Object value} is {@literal null}.
* @return the {@link Object value} or throw the given {@link RuntimeException}
* if {@link Object value} is {@literal null}.
*/
public static <T> T returnValueThrowOnNull(T value, RuntimeException exception) {
if (value == null) {
throw exception;
}
return value;
}
@FunctionalInterface
public interface ExceptionThrowingOperation<T> {
T doExceptionThrowingOperation() throws Exception;
}
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.function.config;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import java.util.Optional;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.Function;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.data.gemfire.function.config.AbstractFunctionExecutionConfigurationSource;
import org.springframework.data.gemfire.function.config.AnnotationFunctionExecutionConfigurationSource;
import org.springframework.data.gemfire.function.config.FunctionExecutionBeanDefinitionRegistrar;
/**
* The {@link AbstractFunctionExecutionAutoConfigurationExtension} class extends SDG's {@link FunctionExecutionBeanDefinitionRegistrar}
* to redefine the location of application POJO {@link Function} {@link Execution} interfaces.
*
* @author John Blum
* @see org.apache.geode.cache.execute.Execution
* @see org.apache.geode.cache.execute.Function
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.boot.autoconfigure.AutoConfigurationPackages
* @see org.springframework.core.type.AnnotationMetadata
* @see org.springframework.data.gemfire.function.config.FunctionExecutionBeanDefinitionRegistrar
* @since 1.0.0
*/
public abstract class AbstractFunctionExecutionAutoConfigurationExtension
extends FunctionExecutionBeanDefinitionRegistrar implements BeanFactoryAware {
private BeanFactory beanFactory;
@Override
@SuppressWarnings("all")
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@SuppressWarnings("all")
protected BeanFactory getBeanFactory() {
return Optional.ofNullable(this.beanFactory)
.orElseThrow(() -> newIllegalStateException("BeanFactory was not properly configured"));
}
protected abstract Class<?> getConfiguration();
@SuppressWarnings("unused")
@Override
protected AbstractFunctionExecutionConfigurationSource newAnnotationBasedFunctionExecutionConfigurationSource(
AnnotationMetadata annotationMetadata) {
StandardAnnotationMetadata metadata =
new StandardAnnotationMetadata(getConfiguration(), true);
return new AnnotationFunctionExecutionConfigurationSource(metadata) {
@Override
public Iterable<String> getBasePackages() {
return AutoConfigurationPackages.get(getBeanFactory());
}
};
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.function.config;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.Function;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.data.gemfire.function.config.EnableGemfireFunctionExecutions;
/**
* The {@link GemFireFunctionExecutionAutoConfigurationRegistrar} class is a Spring {@link ImportBeanDefinitionRegistrar}
* used to register SDG POJO interfaces defining Apache Geode/Pivotal GemFire
* {@link Function} {@link Execution Executions}
*
* @author John Blum
* @see org.apache.geode.cache.execute.Execution
* @see org.apache.geode.cache.execute.Function
* @see org.springframework.data.gemfire.function.config.EnableGemfireFunctionExecutions
* @see org.springframework.geode.function.config.AbstractFunctionExecutionAutoConfigurationExtension
* @since 1.0.0
*/
public class GemFireFunctionExecutionAutoConfigurationRegistrar
extends AbstractFunctionExecutionAutoConfigurationExtension {
@Override
protected Class<?> getConfiguration() {
return EnableGemfireFunctionExecutionsConfiguration.class;
}
@EnableGemfireFunctionExecutions
private static class EnableGemfireFunctionExecutionsConfiguration { }
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.function.support;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.geode.cache.execute.FunctionException;
import org.apache.geode.cache.execute.ResultCollector;
/**
* The {@link AbstractResultCollector} class is an abstract base implementation of the {@link ResultCollector} interface
* encapsulating common functionality for collecting results from a Function execution.
*
* @author John Blum
* @see org.apache.geode.cache.execute.ResultCollector
* @since 1.0.0
*/
@SuppressWarnings("unused")
public abstract class AbstractResultCollector<T, S> implements ResultCollector<T, S> {
protected static final String NOT_IMPLEMENTED = "Not Implemented";
protected static final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.MILLISECONDS;
private AtomicBoolean resultsEnded = new AtomicBoolean(false);
private S result = null;
@Override
public synchronized S getResult() throws FunctionException {
return this.result;
}
@Override
public S getResult(long duration, TimeUnit unit) throws FunctionException, InterruptedException {
unit = resolveTimeUnit(unit);
long durationInMilliseconds = unit.toMillis(duration);
long timeout = System.currentTimeMillis() + unit.toMillis(duration);
long waitInMilliseconds = Math.max(50, Math.min(durationInMilliseconds / 5, durationInMilliseconds));
synchronized (this) {
while (getResult() == null && System.currentTimeMillis() < timeout) {
unit.timedWait(this, waitInMilliseconds);
}
}
return getResult();
}
protected synchronized void setResult(S result) {
this.result = result;
}
protected TimeUnit resolveTimeUnit(TimeUnit unit) {
return unit != null ? unit : DEFAULT_TIME_UNIT;
}
@Override
public void clearResults() {
setResult(null);
}
@Override
public void endResults() {
this.resultsEnded.set(true);
}
protected boolean hasResultsEnded() {
return this.resultsEnded.get();
}
protected boolean hasResultsNotEnded() {
return !this.resultsEnded.get();
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.function.support;
import java.util.Collections;
import java.util.Iterator;
import java.util.Optional;
import org.apache.geode.cache.execute.ResultCollector;
import org.apache.geode.distributed.DistributedMember;
/**
* The {@link SingleResultReturningCollector} class is an implementation of the {@link ResultCollector} interface
* which returns a single {@link Object result}.
*
* @author John Blum
* @see org.apache.geode.cache.execute.ResultCollector
* @see org.springframework.geode.function.support.AbstractResultCollector
* @since 1.0.0
*/
@SuppressWarnings("unused")
public class SingleResultReturningCollector<T> extends AbstractResultCollector<T, T> {
@Override
public void addResult(DistributedMember memberID, T resultOfSingleExecution) {
setResult(extractSingleResult(resultOfSingleExecution));
}
@SuppressWarnings("unchecked")
private <T> T extractSingleResult(Object result) {
return (T) Optional.ofNullable(result)
.filter(this::isInstanceOfIterableOrIterator)
.map(this::toIterator)
.filter(Iterator::hasNext)
.map(Iterator::next)
.map(this::extractSingleResult)
.orElseGet(() -> isInstanceOfIterableOrIterator(result) ? null : result);
}
private boolean isInstanceOfIterableOrIterator(Object obj) {
return obj instanceof Iterable || obj instanceof Iterator;
}
@SuppressWarnings("unchecked")
private <T> Iterator<T> toIterator(Object obj) {
return obj instanceof Iterator ? (Iterator<T>) obj : toIterator((Iterable<T>) obj);
}
private <T> Iterator<T> toIterator(Iterable<T> iterable) {
return iterable != null ? iterable.iterator() : Collections.emptyIterator();
}
}

View File

@@ -0,0 +1,163 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.security.support;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.geode.security.AuthenticationFailedException;
import org.apache.geode.security.ResourcePermission;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.gemfire.support.LazyWiringDeclarableSupport;
import org.springframework.util.Assert;
/**
* The {@link SecurityManagerProxy} class is an Apache Geode {@link org.apache.geode.security.SecurityManager}
* proxy implementation delegating to a backing {@link org.apache.geode.security.SecurityManager} implementation
* which is registered as a managed bean in a Spring context.
*
* The idea behind this {@link org.apache.geode.security.SecurityManager} is to enable users to be able to configure
* and manage the {@code SecurityManager} as a Spring bean. However, Apache Geode/Pivotal GemFire require
* the {@link org.apache.geode.security.SecurityManager} to be configured using a System property when launching
* Apache Geode Servers with Gfsh, which makes it difficult to "manage" the {@code SecurityManager} instance.
*
* Therefore, this implementation allows a developer to set the Apache Geode System property using this proxy...
*
* <code>
* gemfire.security-manager=org.springframework.geode.security.support.SecurityManagerProxy
* </code>
*
* And then declare and define a bean in the Spring context implementing the
* {@link org.apache.geode.security.SecurityManager} interface...
*
* <code>
* Configuration
* class MyApplicationConfiguration {
*
* Bean
* ExampleSecurityManager exampleSecurityManager(Environment environment) {
* return new ExampleSecurityManager(environment);
* }
*
* ...
* }
* </code>
*
* @author John Blum
* @see org.apache.geode.security.ResourcePermission
* @see org.apache.geode.security.SecurityManager
* @see org.springframework.beans.factory.annotation.Autowired
* @see org.springframework.data.gemfire.support.LazyWiringDeclarableSupport
* @since 1.0.0
*/
@SuppressWarnings("unused")
public class SecurityManagerProxy extends LazyWiringDeclarableSupport
implements org.apache.geode.security.SecurityManager, DisposableBean {
private static final AtomicReference<SecurityManagerProxy> INSTANCE = new AtomicReference<>();
private org.apache.geode.security.SecurityManager securityManager;
/**
* Returns a reference to the single {@link SecurityManagerProxy} instance configured by
* Apache Geode/Pivotal GemFire in startup.
*
* @return a reference to the single {@link SecurityManagerProxy} instance.
*/
public static SecurityManagerProxy getInstance() {
return Optional.ofNullable(INSTANCE.get())
.orElseThrow(() -> newIllegalStateException("SecurityManagerProxy was not configured"));
}
/**
* Constructs a new instance of {@link SecurityManagerProxy}, which will delegate all Apache Geode
* security operations to a Spring managed {@link org.apache.geode.security.SecurityManager} bean.
*/
public SecurityManagerProxy() {
// TODO remove init() call when GEODE-2083 (https://issues.apache.org/jira/browse/GEODE-2083) is resolved!
// NOTE: the init(:Properties) call in the constructor is less than ideal since...
// 1) it allows the *this* reference to escape, and...
// 2) it is Geode's responsibility to identify Geode Declarable objects and invoke their init(:Properties) method
// However, the init(:Properties) method invocation in the constructor is necessary to enable this Proxy to be
// identified and auto-wired in a Spring context.
INSTANCE.compareAndSet(null, this);
init(new Properties());
}
/**
* Configures a reference to the Apache Geode {@link org.apache.geode.security.SecurityManager} instance
* delegated to by this {@link SecurityManagerProxy}.
*
* @param securityManager reference to the underlying Apache Geode {@link org.apache.geode.security.SecurityManager}
* instance delegated to by this {@link SecurityManagerProxy}.
* @throws IllegalArgumentException if the {@link org.apache.geode.security.SecurityManager} reference
* is {@literal null}.
* @see org.apache.geode.security.SecurityManager
*/
@Autowired
public void setSecurityManager(org.apache.geode.security.SecurityManager securityManager) {
Assert.notNull(securityManager, "SecurityManager must not be null");
this.securityManager = securityManager;
}
/**
* Returns a reference to the Apache Geode {@link org.apache.geode.security.SecurityManager} instance
* delegated to by this {@link SecurityManagerProxy}.
*
* @return a reference to the underlying {@link org.apache.geode.security.SecurityManager} instance
* delegated to by this {@link SecurityManagerProxy}.
* @throws IllegalStateException if the configured {@link org.apache.geode.security.SecurityManager}
* was not properly configured.
* @see org.apache.geode.security.SecurityManager
*/
protected org.apache.geode.security.SecurityManager getSecurityManager() {
Assert.state(this.securityManager != null, "No SecurityManager configured");
return this.securityManager;
}
@Override
public Object authenticate(Properties properties) throws AuthenticationFailedException {
return getSecurityManager().authenticate(properties);
}
@Override
public boolean authorize(Object principal, ResourcePermission permission) {
return getSecurityManager().authorize(principal, permission);
}
@Override
public void close() {
getSecurityManager().close();
}
@Override
public void destroy() throws Exception {
super.destroy();
INSTANCE.set(null);
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.security.support;
import java.util.Properties;
import org.apache.geode.security.AuthenticationFailedException;
import org.apache.geode.security.ResourcePermission;
/**
* {@link SecurityManagerSupport} is an abstract base class implementing Apache Geode/Pivotal GemFire's
* {@link org.apache.geode.security.SecurityManager} interface, providing default implementations of the
* {@literal SecurityManager's} auth methods.
*
* @author John Blum
* @see org.apache.geode.security.SecurityManager
* @since 1.0.0
*/
@SuppressWarnings("unused")
public abstract class SecurityManagerSupport implements org.apache.geode.security.SecurityManager {
protected static final boolean DEFAULT_AUTHORIZATION = false;
@Override
public void init(Properties securityProperties) { }
@Override
public Object authenticate(Properties credentials) throws AuthenticationFailedException {
return new AuthenticationFailedException("Authentication Provider Not Present");
}
@Override
public boolean authorize(Object principal, ResourcePermission permission) {
return DEFAULT_AUTHORIZATION;
}
@Override
public void close() { }
}