disable RabbitAutoConfiguration programmatically - spring

Is there a programmatic(properties based) way of disabling RabbitAutoConfiguration in spring boot (1.2.2).
Looks like spring.rabbitmq.dynamic=false disables just the AmqpAdmin but not the connection factory etc.
We want a model where app properties might be sourced from spring cloud config (includes control bus) or via -D jvm args. This decision is made at deployment time.
When properties are sourced from -D jvm args, we disable the spring cloud config client but rabbit keeps throwing exceptions such as :
[org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer] - [Co
nsumer raised exception, processing can restart if the connection factory suppor
ts it. Exception summary: org.springframework.amqp.AmqpConnectException: java.ne
t.ConnectException: Connection refused: connect]

First you need to exclude RabbitAutonfiguration from your app
#EnableAutoConfiguration(exclude=RabbitAutoConfiguration.class)
Then you can import it based on some property like this
#Configuration
#ConditionalOnProperty(name="myproperty",havingValue="valuetocheck",matchIfMissing=false)
#Import(RabbitAutoConfiguration.class)
class RabbitOnConditionalConfiguration{
}

Related

Spring Security Concurrent Session Control doesn't work

Following the information available here: Spring Security session
Configuring the HttpSecurity object like
http
.sessionManagement((sessionManagement) -> sessionManagement
.maximumSessions(2)
.sessionRegistry(sessionRegistry()));
When auto-wiring FindByIndexNameSessionRepository I am getting
Caused by: java.lang.IllegalStateException: RedisConnectionFactory is required
I have tried multiple things but nothing seems to work. Any help would be appreciated. My store type is Redis.
The exception log is very clear. You need to create and configure the RedisConnectionFactory instance in your session configuration class to be able to connect to the redis server.

How to safely resume cache operation on client side after Hazelcast restart?

Whenever I restart hazelcast server, without restarting client in spring boot. I'm getting following error :
03-01-2018 16:44:17.966 [http-nio-8080-exec-7] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet].log - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.hazelcast.client.HazelcastClientNotActiveException: Partition does not have owner. partitionId : 203] with root cause
java.io.IOException: Partition does not have owner. partitionId : 203
at com.hazelcast.client.spi.impl.ClientSmartInvocationServiceImpl.invokeOnPartitionOwner(ClientSmartInvocationServiceImpl.java:43)
at com.hazelcast.client.spi.impl.ClientInvocation.invokeOnSelection(ClientInvocation.java:142)
at com.hazelcast.client.spi.impl.ClientInvocation.invoke(ClientInvocation.java:122)
at com.hazelcast.client.spi.ClientProxy.invokeOnPartition(ClientProxy.java:152)
at com.hazelcast.client.spi.ClientProxy.invoke(ClientProxy.java:147)
at com.hazelcast.client.proxy.ClientMapProxy.getInternal(ClientMapProxy.java:245)
at com.hazelcast.client.proxy.ClientMapProxy.get(ClientMapProxy.java:240)
at com.hazelcast.spring.cache.HazelcastCache.lookup(HazelcastCache.java:139)
at com.hazelcast.spring.cache.HazelcastCache.get(HazelcastCache.java:57)
at org.springframework.cache.interceptor.AbstractCacheInvoker.doGet(AbstractCacheInvoker.java:71)
If I enabled hot-restart, the issue is solved. But is there a way to resume client application without restarting it and hot-restart is disabled ?
Hazelcast client tries to reconnect to the cluster if the connection drops. It uses ClientNetworkConfig.connectionAttemptLimit and ClientNetworkConfig.connectionAttemptPeriod elements to configure how frequently it will try. connectionAttemptLimit defines the number of attempts on a disconnection and connectionAttemptPeriod defines the period between two retries in ms. Please see the usage example below:
ClientConfig clientConfig = new ClientConfig();
clientConfig.getNetworkConfig().setConnectionAttemptLimit(5);
clientConfig.getNetworkConfig().setConnectionAttemptPeriod(5000);
Starting with Hazelcast 3.9, you can use reconnect-mode property to configure how the client will reconnect to the cluster after it disconnects. It has three options:
The option OFF disables the reconnection.
ON enables reconnection in a blocking manner where all the waiting invocations will be blocked until a cluster connection is established or failed.
The option ASYNC enables reconnection in a non-blocking manner where all the waiting invocations will receive a HazelcastClientOfflineException.
Its default value is ON. You can see a configuration example below:
ClientConfig clientConfig = new ClientConfig();
clientConfig.getConnectionStrategyConfig()
.setReconnectMode(ClientConnectionStrategyConfig.ReconnectMode.ON);
By using these configuration elements, you can resume your client without restarting it.

Solace NIFI JMSConnectionFactoryProvider

I am trying to connect to Solace Queues on a VPN different then default using Appache NIFI ConsumeJMS Processor. When I try to enable the JMSConnectionFactoryProvider I get the following error:
JMSConnectionFactoryProvider Failed to invoke #OnEnabled method due to
java.lang.IllegalStateException: java.lang.IllegalStateException:
Failed to load and/or instantiate class
'com.solacesystems.jms.SolConnectionFactory'
The NIFI JMSConnectionFactoryProvider provides a generic service to create vendor specific javax.jms.ConnectionFactory implementations. ConnectionFactory can be served once this service is configured successfully.
Why is NIFI Unable to find the class within the Solace JMS API Jar files?
----- Update --------
Solace JMS API 10.1.0 now contains an zero argument default constructor, and integration with NiFi is now possible.
Here is an example configuration:
Controller:
The MQ ConnectionFactory Implementation is set to com.solacesystems.jms.SolConnectionFactoryImpl.
ConsumeJMS Processor:
Username field can also take the form of "myUsername#myMessageVPN".
----- Original -------
The problem here is that Apache NiFi is not using a portable method of creating a ConnectionFactory. It is trying to create a ConnectionFactory by calling an zero argument default constructor, but there's no guarantee that one exists.
// From https://github.com/apache/nifi/blob/master/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-cf-service/src/main/java/org/apache/nifi/jms/cf/JMSConnectionFactoryProvider.java
private void createConnectionFactoryInstance(ConfigurationContext context) {
String connectionFactoryImplName = context.getProperty(CONNECTION_FACTORY_IMPL).evaluateAttributeExpressions().getValue();
this.connectionFactory = Utils.newDefaultInstance(connectionFactoryImplName);
}
Note that there's an entry over at NiFi's JIRA https://issues.apache.org/jira/browse/NIFI-2701 to "Add JNDI Factory support for JMS ConnectionFactory service". (The initial description of that entry is a bit confusing, but the comments are clearer.)
At this point, Solace only supports the creation of the ConnectionFactory through the standard JNDI lookup - javax.naming.InitialContext.lookup() and through Solace's proprietary method - SolJmsUtility.createConnectionFactory().
Solace will investigate whether it is feasible to implement a zero argument default constructor for the ConnectionFactory.
A JNDI connection provider is developed and published at http://dev.solace.com/integration-guides/nifi/. For people that are interested in this provider, it is worthwhile finding out.

Spring boot Artemis embedded broker behaviour

Morning all,
I've been struggling lately with the spring-boot-artemis-starter.
My understanding of its spring-boot support was the following:
set spring.artemis.mode=embedded and, like tomcat, spring-boot will instanciate a broker reachable through tcp (server mode). The following command should be successful: nc -zv localhost 61616
set spring.artmis.mode=native and spring-boot will only configure the jms template according to the spring.artemis.* properties (client mode).
The client mode works just fine with a standalone artemis server on my machine.
Unfortunatelly, I could never manage to reach the tcp port in server mode.
I would be grateful if somebody confirms my understanding of the embedded mode.
Thank you for tour help
After some digging I noted that the implementation provided out of the box by the spring-boot-starter-artemis uses org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory acceptor. I'm wondering if that's not the root cause (again I'm by no means an expert).
But it appears that there is a way to customize artemis configuration.
Therefore I tried the following configuration without any luck:
#SpringBootApplication
public class MyBroker {
public static void main(String[] args) throws Exception {
SpringApplication.run(MyBroker.class, args);
}
#Autowired
private ArtemisProperties artemisProperties;
#Bean
public ArtemisConfigurationCustomizer artemisConfigurationCustomizer() {
return configuration -> {
try {
configuration.addAcceptorConfiguration("netty", "tcp://localhost:" + artemisProperties.getPort());
} catch (Exception e) {
throw new RuntimeException("Failed to add netty transport acceptor to artemis instance");
}
};
}
}
You just have to add a Connector and an Acceptor to your Artemis Configuration. With Spring Boot Artemis starter Spring creates a Configuration bean which will be used for EmbeddedJMS configuration. You can see this in ArtemisEmbeddedConfigurationFactory class where an InVMAcceptorFactory will be set for the configuration. You can edit this bean and change Artemis behaviour through custom ArtemisConfigurationCustomizer bean which will be sucked up by Spring autoconfig and be applied to the Configuration.
An example config class for your Spring Boot application:
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory;
import org.springframework.boot.autoconfigure.jms.artemis.ArtemisConfigurationCustomizer;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ArtemisConfig implements ArtemisConfigurationCustomizer {
#Override
public void customize(org.apache.activemq.artemis.core.config.Configuration configuration) {
configuration.addConnectorConfiguration("nettyConnector", new TransportConfiguration(NettyConnectorFactory.class.getName()));
configuration.addAcceptorConfiguration(new TransportConfiguration(NettyAcceptorFactory.class.getName()));
}
}
My coworker and I had the exact same problem as the documentation on this link (chapter Artemis Support) says nothing about adding an individual ArtemisConfigurationCustomizer - Which is sad because we realized that without this Customizer our Spring Boot App would start and act as if everything was okay but actually it wouldn't do anything.
We also realized that without the Customizer the application.properties file is not beeing loaded so no matter what host or port you mentioned there it would not count.
After adding the Customizer as stated by the two examples it worked without a problem.
Here some results that we figured out:
It only loaded the application.properties after configuring an ArtemisConfigurationCustomizer
You don't need the broker.xml anymore with an embedded spring boot artemis client
Many examples showing the use of Artemis use a "in-vm" protocol while we just wanted to use the netty tcp protocol so we needed to add it into the configuration
For me the most important parameter was pub-sub-domain as I was using topics and not queues. If you are using topics this parameter needs to be set to true or the JMSListener won't read the messages.
See this page: stackoverflow jmslistener-usage-for-publish-subscribe-topic
When using a #JmsListener it uses a DefaultMessageListenerContainer
which extends JmsDestinationAccessor which by default has the
pubSubDomain set to false. When this property is false it is
operating on a queue. If you want to use topics you have to set this
properties value to true.
In Application.properties:
spring.jms.pub-sub-domain=true
If anyone is interested in the full example I have uploaded it to my github:
https://github.com/CorDharel/SpringBootArtemisServerExample
The embedded mode starts the broker as part of your application. There is no network protocol available with such setup, only InVM calls are allowed. The auto-configuration exposes the necessary pieces you can tune though I am not sure you can actually have a TCP/IP channel with the embedded mode.

Glassfish 4.0 serializable coonection pools not working with Oracle XA transactions

I have a problem that I don't know how solve and researching the net has not helped me much. I declare in glassfish 4.0 asadmin console a serializable connection pool and its corresponding resource.
create-jdbc-connection-pool --datasourceclassname oracle.jdbc.xa.client.OracleXADataSource --maxpoolsize 8 --isolationlevel serializable --restype javax.sql.XADataSource --property Password=A_DB:User=A_DB:URL="jdbc\:oracle\:thin\:#localhost\:1521\:orcl" ATestPool
create-jdbc-resource --connectionpoolid ATestPool jdbc/ATest
Then inside a stateless bean I build a datasource via jndi as follows:
InitialContext ic = new InitialContext();
jndiDataSource = (DataSource) ic.lookup("jdbc/ATest");
and I'm getting connection as follows
jndiDataSource.getConnection();
Connections are properly obtained and released via finally clauses in each method we they are needed.
However, pairing serializable connection pool with XA data sources seems not to work, as getting first connections throws the following pair of exceptions in the order shown below
JTS5041: The resource manager is doing work outside a global transaction
oracle.jdbc.xa.OracleXAException
at oracle.jdbc.xa.OracleXAResource.checkError(OracleXAResource.java:1110)
RAR5029:Unexpected exception while registering component
javax.transaction.SystemException
at com.sun.jts.jta.TransactionImpl.enlistResource(TransactionImpl.java:224)
with the following
RAR7132: Unable to enlist the resource in transaction. Returned resource to pool. Pool name: [ ATestPool ]]]
RAR5117 : Failed to obtain/create connection from connection pool [ ATestPool ]. Reason : com.sun.appserv.connectors.internal.api.PoolingException: javax.transaction.SystemException]]
RAR5114 : Error allocating connection : [Error in allocating a connection. Cause: javax.transaction.SystemException]]].
Now if the connection pool is recreated without --isolationlevel serializable, then application works fine without any changes into the code. Also, if one keeps the isolation parameter and uses non-XA transactions as
--datasourceclassname oracle.jdbc.pool.OracleDataSource
--restype javax.sql.DataSource
then again application works without any changes into the code.
I was wondering if anyone could explain to me what could be wrong in the above setup and how to actually make serializable work with XA data sources. Thanks.
I think you need to enable useNativeXA.

Resources