I am getting below error in a random way. It doesn't throw error initially but after a while the error is thrown. Once I restart my server everything gets reset and error is not thrown.
XA resource 'XXXXAtomikosDataSource': resume for XID '31302E3137382E36382E3235302E746D30303031353030303138:31302E3137382E36382E3235302E746D3135' raised -7: the XA resource has become unavailable
I am using below dependencies.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
<version>1.4.2.RELEASE</version>
</dependency>
And with configuration beans
#Bean(name= "userTransaction")
public UserTransaction userTransaction() throws Throwable {
UserTransactionImp userTransactionImp = new UserTransactionImp();
return userTransactionImp;
}
#Bean
#Primary
public TransactionManager atomTransactionManager() throws Throwable {
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(false);
return userTransactionManager;
}
#Bean("atomikosTransactionManager")
public PlatformTransactionManager platformTransactionManager() throws Throwable {
UserTransaction userTransaction = userTransaction();
TransactionManager transactionManager = atomTransactionManager();
JtaTransactionManager jtaTransactionManager = new JtaTransactionManager(userTransaction, transactionManager);
jtaTransactionManager.setAllowCustomIsolationLevels(true);
jtaTransactionManager.setDefaultTimeout(1000);
return jtaTransactionManager;
}
#Bean(name = "atomikosDataSources")
public Map<String, DataSource> atomikosDataSources(PropertiesFactoryBean databaseProperties, Environment environment, BcusDefaultEncrytor bcusDefaultEncrytor) throws SQLException, IOException {
List<String> databases= Collections.list(databaseProperties.getObject().propertyNames()).stream().map(key->key.toString()).filter(key-> key.contains("url")).collect(Collectors.toList());
Map<String, DataSource> collect = databases.stream().collect(Collectors.toMap(dbName -> dbName.split("\\.")[0].toUpperCase() + "AtomikosDataSource", dbName -> {
OracleXADataSource dataSource = null;
try {
dataSource = new OracleXADataSource();
dataSource.setURL(environment.getProperty(dbName));
dataSource.setUser(environment.getProperty("database.username"));
dataSource.setPassword(bcusDefaultEncrytor.decryptQAPassword(environment.getProperty("database.password")));
}
catch (SQLException e)
{
LOG.error(
"DatabaseConditionException [errorCode= Error while configuring atomikos data sources- Could not OracleXADataSource object, errorMessage= {} ]",
e.getMessage());
}
catch (Exception e) {
LOG.error(
"DatabaseConditionException [errorCode= Error while configuring atomikos data sources- Could not decrypt QA Password make sure you have proper **QA** Encryption password in your folder, errorMessage= {} ]",
e.getMessage());
}
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(dataSource);
xaDataSource.setUniqueResourceName(dbName.split("\\.")[0].toUpperCase() + "AtomikosDataSource");
xaDataSource.setPoolSize(5);
return xaDataSource;
}));
return collect;
}
The issue is because of a bug in atomikos 3.9.3 version in spring-boot-starter-jta-atomikos brings:1.4.2.RELEASE.
Once you update the version to atomikos 4.0.4, the issue resolves.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
<exclusions>
<exclusion>
<artifactId>transactions-jdbc</artifactId>
<groupId>com.atomikos</groupId>
</exclusion>
<exclusion>
<artifactId>transactions-jms</artifactId>
<groupId>com.atomikos</groupId>
</exclusion>
<exclusion>
<artifactId>transactions-jta</artifactId>
<groupId>com.atomikos</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jms</artifactId>
<version>${transaction.version}</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jta</artifactId>
<version>${transaction.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jta_1.0.1B_spec</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jdbc</artifactId>
<version>${transaction.version}</version>
</dependency>
Related
I am trying to send the websocket message larger than 65536 size and getting connection closed exception and error message.
**Connection closed: 1009 - Text message size [67000] exceeds maximum size [65536] **
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.websocketMaxTextClient</groupId>
<artifactId>websocketMaxTextClient</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>websocketMaxTextClient</name>
<description>Websocket response message limitation</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-client</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Websocket server configuration
#Component
public class WebsocketEndPoint extends TextWebSocketHandler{
private final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message)
throws InterruptedException, IOException {
System.out.println("message : "+message.getPayload());
session.sendMessage(message);
}
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
session.setTextMessageSizeLimit(13900000);
System.out.println("textmessage limit : "+session.getTextMessageSizeLimit());
sessions.add(session);
super.afterConnectionEstablished(session);
}
#Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session);
super.afterConnectionClosed(session, status);
}
}
WebsocketConfig
#EnableWebSocket
#Configuration
public class WebsocketConfig implements WebSocketConfigurer {
#Autowired
private WebsocketEndPoint websocketEndPoint;
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(websocketEndPoint, "/web-socket").setHandshakeHandler(handshakeHandler());
}
public DefaultHandshakeHandler handshakeHandler() {
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
policy.setMaxTextMessageBufferSize(17981302);
policy.setMaxTextMessageSize(13800000);
policy.setMaxBinaryMessageBufferSize(18981302);
policy.setMaxBinaryMessageSize(15981302);
policy.setInputBufferSize( 15981302);
return new DefaultHandshakeHandler(
new JettyRequestUpgradeStrategy(new WebSocketServerFactory()));
}
#Bean
public ServletServerContainerFactoryBean createServletServerContainerFactoryBean() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxTextMessageBufferSize(1024*1024);
// container.setMaxBinaryMessageBufferSize(32768);
return container;
}
}
`
Websocket clientt code
#SpringBootApplication
public class WebsocketMaxTextClientApplication {
/*
* WebSocket client connection
*/
public static void main(String[] args) throws URISyntaxException, IOException {
String url = "ws://127.0.0.1:8082/web-socket";
WebSocketClient client = new WebSocketClient();
try
{
client.setMaxTextMessageBufferSize(13300000);
client.getPolicy().setMaxTextMessageSize(1329705);
client.getPolicy().delegateAs(WebSocketBehavior.CLIENT);
client.start();
URI echoUri = new URI(url);
ClientUpgradeRequest request = new ClientUpgradeRequest();
client.connect(socket, echoUri, request);
// wait for closed socket connection.
socket.awaitClose(5, TimeUnit.SECONDS);
}
catch (Throwable t)
{
t.printStackTrace();
}
finally
{
try
{
client.stop();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
Websocketclient end point
#WebSocket
public class WebsocketMaxTextClientEndPoint {
private final CountDownLatch closeLatch;
#SuppressWarnings("unused")
private Session session;
public WebsocketMaxTextClientEndPoint()
{
this.closeLatch = new CountDownLatch(1);
}
public boolean awaitClose(int duration, TimeUnit unit) throws InterruptedException
{
return this.closeLatch.await(duration, unit);
}
#OnWebSocketClose
public void onClose(int statusCode, String reason)
{
System.out.printf("Connection closed: %d - %s%n", statusCode, reason);
this.session = null;
this.closeLatch.countDown(); // trigger latch
}
#OnWebSocketConnect
public void onConnect(Session session)
{
System.out.printf("Got connect: %s%n", session);
this.session = session;
try
{
session.getRemote().sendString("Thanks for the conversation.");
String json = randomString(67000);
System.out.println("default textmessage Length in websocket : "+session.getPolicy().getMaxTextMessageSize());
session.getRemote().sendString(json);
}
catch (Throwable t)
{
t.printStackTrace();
}
}
#OnWebSocketMessage
public void onMessage(String msg)
{
System.out.printf("Got msg: %s%n", msg);
}
#OnWebSocketError
public void onError(Throwable cause)
{
System.out.print("WebSocket Error: ");
cause.printStackTrace(System.out);
}
private String randomString(int size) {
return RandomStringUtils.random(size, true, true);
}
}
The log details are
Connection closed: 1009 - Text message size [67000] exceeds maximum size [65536]
10:12:19.175 [main] DEBUG org.eclipse.jetty.util.component.AbstractLifeCycle - stopping WebSocketClient#29c17a75[httpClient=HttpClient#614c5515{STARTED},openSessions.size=1]
10:12:19.175 [main] DEBUG org.eclipse.jetty.websocket.client.WebSocketClient - Stopping WebSocketClient#29c17a75[httpClient=HttpClient#614c5515{STARTED},openSessions.size=1]
10:12:19.175 [main] DEBUG org.eclipse.jetty.util.component.AbstractLifeCycle - stopping SessionTracker#548b7f67{STARTED}
10:12:19.175 [main] DEBUG org.eclipse.jetty.util.component.AbstractLifeCycle - stopping WebSocketSession[websocket=JettyAnnotatedEventDriver[com.websocketMaxTextClient.websocketMaxTextClient.endPoint.WebsocketMaxTextClientEndPoint#17c1bced],behavior=CLIENT,connection=WebSocketClientConnection#66e7e62f::SocketChannelEndPoint#7f4cda1a{l=/127.0.0.1:64098,r=/127.0.0.1:8082,OPEN,fill=-,flush=-,to=3/300000}{io=0/0,kio=0,kro=1}->WebSocketClientConnection#66e7e62f[s=ConnectionState#44b79a43[CLOSING],f=Flusher#21d129b1[IDLE][queueSize=0,aggregateSize=-1,terminated=null],g=Generator[CLIENT,validating],p=Parser#42399352[ExtensionStack,s=START,c=0,len=56,f=CLOSE[len=56,fin=true,rsv=...,masked=false]]],remote=WebSocketRemoteEndpoint#55dc6bce[batching=true],incoming=JettyAnnotatedEventDriver[com.websocketMaxTextClient.websocketMaxTextClient.endPoint.WebsocketMaxTextClientEndPoint#17c1bced],outgoing=ExtensionStack[queueSize=0,extensions=[],incoming=org.eclipse.jetty.websocket.common.WebSocketSession,outgoing=org.eclipse.jetty.websocket.client.io.WebSocketClientConnection]]
10:12:19.176 [main] DEBUG org.eclipse.jetty.websocket.common.WebSocketSession - stopping - WebSocketSession[websocket=JettyAnnotatedEventDriver[com.websocketMaxTextClient.websocketMaxTextClient.endPoint.WebsocketMaxTextClientEndPoint#17c1bced],behavior=CLIENT,connection=WebSocketClientConnection#66e7e62f::SocketChannelEndPoint#7f4cda1a{l=/127.0.0.1:64098,r=/127.0.0.1:8082,OPEN,fill=-,flush=-,to=4/300000}{io=0/0,kio=0,kro=1}->WebSocketClientConnection#66e7e62f[s=ConnectionState#44b79a43[CLOSING],f=Flusher#21d129b1[IDLE][queueSize=0,aggregateSize=-1,terminated=null],g=Generator[CLIENT,validating],p=Parser#42399352[ExtensionStack,s=START,c=0,len=56,f=CLOSE[len=56,fin=true,rsv=...,masked=false]]],remote=WebSocketRemoteEndpoint#55dc6bce[batching=true],incoming=JettyAnnotatedEventDriver[com.websocketMaxTextClient.websocketMaxTextClient.endPoint.WebsocketMaxTextClientEndPoint#17c1bced],outgoing=ExtensionStack[queueSize=0,extensions=[],incoming=org.eclipse.jetty.websocket.common.WebSocketSession,outgoing=org.eclipse.jetty.websocket.client.io.WebSocketClientConnection]]
10:12:19.176 [WebSocketClient#1632392469-20] DEBUG org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection - outgoingFrame(CLOSE[len=56,fin=true,rsv=...,masked=true], org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection$CallbackBridge#7ce49efe)
10:12:19.176 [main] DEBUG org.eclipse.jetty.websocket.common.WebSocketSession - callApplicationOnClose(CloseInfo[code=1006,reason=Disconnected])
10:12:19.176 [main] DEBUG org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection - CLIENT disconnect()
10:12:19.176 [WebSocketClient#1632392469-20] DEBUG org.eclipse.jetty.websocket.common.io.FrameFlusher - Enqueued FrameEntry[CLOSE[len=56,fin=true,rsv=...,masked=true],org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection$CallbackBridge#7ce49efe,OFF,null] to Flusher#21d129b1[IDLE][queueSize=1,aggregateSize=-1,terminated=null]
10:12:19.176 [main] DEBUG org.eclipse.jetty.websocket.common.io.FrameFlusher - Terminating Flusher#21d129b1[PROCESSING][queueSize=1,aggregateSize=-1,terminated=java.io.EOFException: Disconnected]
10:12:19.176 [WebSocketClient#1632392469-20] DEBUG org.eclipse.jetty.websocket.common.io.FrameFlusher - Flushing Flusher#21d129b1[PROCESSING][queueSize=1,aggregateSize=-1,terminated=java.io.EOFException: Disconnected]
10:12:19.176 [main] DEBUG org.eclipse.jetty.io.AbstractEndPoint - shutdownOutput SocketChannelEndPoint#7f4cda1a{l=/127.0.0.1:64098,r=/127.0.0.1:8082,OPEN,fill=-,flush=-,to=4/300000}{io=0/0,kio=0,kro=1}->WebSocketClientConnection#66e7e62f[s=ConnectionState#44b79a43[DISCONNECTED],f=Flusher#21d129b1[FAILED][queueSize=1,aggregateSize=-1,terminated=java.io.EOFException: Disconnected],g=Generator[CLIENT,validating],p=Parser#42399352[ExtensionStack,s=START,c=0,len=56,f=CLOSE[len=56,fin=true,rsv=...,masked=false]]]
10:12:19.179 [WebSocketClient#1632392469-20] DEBUG org.eclipse.jetty.websocket.common.WebSocketSession - callApplicationOnError()
java.io.EOFException: Disconnected
I want to send more than 10 MB data from websocket client to server.
Please help me, Tried to resolve it but unable to find the exact root cause.
Unable to send websocket client message larger than 65536 to websocket server in spring boot 2.7 and want to send 10 mb websocket client response to websocket server.Please provide solution, Thanks
I have used keycloak-admin-client in a jaxrs application, and use swagger to generate API documentation. Swagger generates documents for all methods in keycloak-admin-client. How can I exclude this library from documentation in swagger ?
Dependency:
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-admin-client</artifactId>
<version>7.0.0</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-servlet-initializer</artifactId>
<version>2.1.0</version>
</dependency>
by this solution assign only my package for scan
#ApplicationPath("/api")
public class ApplicationInitializer extends Application {
public ApplicationInitializer(#Context ServletConfig servletConfig) {
super();
OpenAPI oas = new OpenAPI();
try {
Set<String> resource = new HashSet<>();
resource.add("my.company.api.path");
SwaggerConfiguration oasConfig = new SwaggerConfiguration()
.openAPI(oas)
.prettyPrint(true)
.resourcePackages(resource);
OpenApiContext oac = new JaxrsOpenApiContextBuilder()
.servletConfig(servletConfig)
.application(this)
.openApiConfiguration(oasConfig)
.buildContext(true);
oac.read();
} catch (OpenApiConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
I am able to send and receive the message using code:
#EnableBinding(Processor.class)
public class KafkaStreamsConfiguration {
#StreamListener(Processor.INPUT)
#SendTo(Processor.OUTPUT)
public String processMessage(String message) {
System.out.println("message = " + message);
return message.replaceAll("my", "your");
}
}
#RunWith(SpringRunner.class)
#SpringBootTest
#DirtiesContext
public class StreamApplicationIT {
private static String topicToPublish = "eventUpdateFromEventModel";
#BeforeClass
public static void setup() {
System.setProperty("spring.kafka.bootstrap-servers", embeddedKafka.getBrokersAsString());
}
#Autowired
private KafkaMessageSender<String> kafkaMessageSenderToTestErrors;
#Autowired
private KafkaMessageSender<EventNotificationDto> kafkaMessageSender;
#ClassRule
public static KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, topicToPublish);
#Autowired
private Processor pipe;
#Autowired
private MessageCollector messageCollector;
#Rule
public OutputCapture outputCapture = new OutputCapture();
#Test
public void working() {
pipe.input()
.send(MessageBuilder.withPayload("This is my message")
.build());
Object payload = messageCollector.forChannel(pipe.output())
.poll()
.getPayload();
assertEquals("This is your message", payload.toString());
}
#Test
public void non_working() {
kafkaMessageSenderToTestErrors.send(topicToPublish, "This was my message");
assertTrue(isMessageReceived("This was your message", 50));
}
private boolean isMessageReceived(final String msg, final int maxAttempt) {
return IntStream.rangeClosed(0, maxAttempt)
.peek(a -> {
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
fail();
}
}).anyMatch(i -> outputCapture.toString().contains(msg));
}
}
#Service
#Slf4j
public class KafkaMessageSender<T> {
private final KafkaTemplate<String, byte[]> kafkaTemplate;
private final ObjectWriter objectWriter;
public KafkaMessageSender(KafkaTemplate<String, byte[]> kafkaTemplate, ObjectMapper objectMapper) {
this.kafkaTemplate = kafkaTemplate;
this.objectWriter = objectMapper.writer();
}
public void send(String topicName, T payload) {
try {
kafkaTemplate.send(topicName, objectWriter.writeValueAsString(payload).getBytes());
} catch (JsonProcessingException e) {
log.info("error converting object into byte array {}", payload.toString().substring(0, 50));
}
log.info("sent payload to topic='{}'", topicName);
}
}
But when I send the message using kafkaTemplate to any topic, StreamListener doesn't receive the message.
spring.cloud.stream.bindings.input.group=test
spring.cloud.stream.bindings.input.destination=eventUpdateFromEventModel
my pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-test-support</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring boot version -->
<spring.boot.version>1.5.7.RELEASE</spring.boot.version>
<spring-cloud.version>Edgware.SR3</spring-cloud.version>
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
working
Object payload = messageCollector.forChannel(pipe.output())
.poll()
.getPayload();
...
not working
KafkaTemplate
This is because you are using the TestBinder in your test, not the real Kafka broker and kafka binder.
The message collector is simply fetching it from the channel. If you want to test with a real Kafka broker, see the test-embedded-kafka sample app.
EDIT
I just tested the Ditmars (boot 1.5.x) version of the sample and it works fine...
I am new to Groovy spock test framework, trying to write my 1st test using Groovy spock. I have few questions around my below test which is keep failing, not getting what to change code to make it working???
What I am trying is?
One thing I am not understanding is when should I use mock, when
should I use spy
Under then section I am trying to call classUnderTest.loadFromFile() in order to test it.
Always I see in CommonDataCache class, instance variable hazelcastCache is always showing null while I debug the test, but at the same time, I see cache is getting non-null Object. Due to this I am always getting null pointer exception as shown in below error logs.
Please anybody suggest why am I missing to make it working???
Error log:
Members [1] {
Member [127.0.0.1]:5001 - a43cbef2-ddf7-431b-9300-2b53c3ea9294 this
}
Dec 13, 2017 3:53:53 PM com.hazelcast.core.LifecycleService
INFO: [127.0.0.1]:5001 [dev] [3.7.3] [127.0.0.1]:5001 is STARTED
Dec 13, 2017 3:53:54 PM com.hazelcast.internal.partition.impl.PartitionStateManager
INFO: [127.0.0.1]:5001 [dev] [3.7.3] Initializing cluster partition table arrangement...
Condition not satisfied:
commonDataCache.getFromCache("28ef4a8f-bfbc-4ad5-bc8a-88fd96ad82a8") != null
| | |
| null false
com.realdoc.symphony.common.CommonDataCache#144ab54
at com.realdoc.symphony.common.store.MemoryStoreManagerTest.populate hazlecast cache from symphony dat file(MemoryStoreManagerTest.groovy:65)
Dec 13, 2017 3:53:54 PM com.hazelcast.instance.Node
INFO: [127.0.0.1]:5001 [dev] [3.7.3] Running shutdown hook... Current state: ACTIVE
This is my Groovy test class:
import org.springframework.core.io.ClassPathResource
import spock.lang.Specification
import spock.lang.Subject
import static io.dropwizard.testing.FixtureHelpers.fixture
class MemoryStoreManagerTest extends Specification {
/**
* Mock the any config DTOs that carries static configuration data
**/
def dw = Mock(SymphonyConfig)
def cacheConfig = Mock(CacheConfig)
/**
* This has to be spied because there is actual call happening in the target method which converts
* json string format to MemoryStoreFileData DTO object
*/
def jsonUtils = Spy(JsonUtils)
def hazelcastInstance = TestHazelcastInstanceFactory.newInstance().newHazelcastInstance()
/**
* This class is under test
**/
#Subject
def commonDataCache = new CommonDataCache(hazelcastInstance: hazelcastInstance,hazelcastCache: hazelcastInstance.getMap("default"), config: dw)
/**
* This class is under test
**/
#Subject
def classUnderTest = new MemoryStoreManager(dw:dw, jsonUtils: jsonUtils, commonDataCache: commonDataCache)
/**
* Test whether populating symphony.dat file into hazelcast cache is working
*/
def "populate hazlecast cache from symphony dat file"() {
setup:
def datFile = fixture("symphony.dat")
def resource = new ClassPathResource("symphony.dat")
def file = resource.getFile()
when:
cacheConfig.getStoreLocation() >> ""
cacheConfig.getStoreFileName() >> "symphony.dat"
dw.getUseHazelcastCache() >> true
dw.getCacheConfig() >> cacheConfig
cacheConfig.getFile() >> file
commonDataCache.postConstruct()
then:
classUnderTest.loadFromFile()
expect:
commonDataCache.getFromCache("28ef4a8f-bfbc-4ad5-bc8a-88fd96ad82a8") != null
}
}
This is my target class on which I am trying to test loadFromFile() method
#Component
public class MemoryStoreManager {
private static final Logger LOG = LoggerFactory.getLogger(MemoryStoreManager.class);
#Autowired
SymphonyConfig dw;
#Autowired
JsonUtils jsonUtils;
#Autowired
CommonDataCache commonDataCache;
private final Properties properties = new Properties();
#PostConstruct
public void loadFromFile() {
File file = dw.getCacheConfig().getFile();
LOG.info("Loading Data from file-{}", file.getAbsolutePath());
FileInputStream inStream = null;
try {
if (!file.exists()) {
Files.createFile(file.toPath());
}
inStream = new FileInputStream(file);
properties.load(inStream);
String property = properties.getProperty("data");
MemoryStoreFileData fileData;
if (StringUtils.isNotEmpty(property)) {
fileData = jsonUtils.jsonToObject(property, MemoryStoreFileData.class);
} else {
fileData = new MemoryStoreFileData(Collections.emptyMap(), Collections.emptyMap());
}
Long lastUpdatedTimeInFile = fileData.getLastUpdatedTime();
LOG.info("Last updated time in File-{}", lastUpdatedTimeInFile);
Long lastUpdatedTimeInCache = (Long) commonDataCache.getFromCache("lastUpdatedTime");
LOG.info("Last updated time in Cache-{}", lastUpdatedTimeInCache);
Map<String, DocData> loadedMap = fileData.getDocDataMap();
if (MapUtils.isEmpty(loadedMap)) {
loadedMap = new HashMap<>();
}
Map<String, ProcessStatusDto> processStatusMap = fileData.getProcessStatusMap();
if (MapUtils.isEmpty(processStatusMap)) {
processStatusMap = new HashMap<>();
}
if (lastUpdatedTimeInFile != null && (lastUpdatedTimeInCache == null || lastUpdatedTimeInCache < lastUpdatedTimeInFile)) {
LOG.info("Overwriting data from File");
commonDataCache.addAllToCache(loadedMap, processStatusMap);
} else {
String requestId;
DocData fileDocData;
DocData cacheDocData;
Map<String, String> filePageStatusMap;
Map<String, String> cachePageStatusMap;
String pageId;
String fileStatus;
String cacheStatus;
for (Entry<String, DocData> entry : loadedMap.entrySet()) {
requestId = entry.getKey();
fileDocData = entry.getValue();
cacheDocData = (DocData) commonDataCache.getFromCache(requestId);
filePageStatusMap = fileDocData.getPageStatusMap();
cachePageStatusMap = cacheDocData.getPageStatusMap();
for (Entry<String, String> pageStatus : filePageStatusMap.entrySet()) {
pageId = pageStatus.getKey();
fileStatus = pageStatus.getValue();
cacheStatus = cachePageStatusMap.get(pageId);
if (StringUtils.equals("IN_PROCESS", cacheStatus) && !StringUtils.equals("IN_PROCESS", fileStatus)) {
cachePageStatusMap.put(pageId, fileStatus);
LOG.info("PageId: {} status: {} updated", pageId, fileStatus);
}
}
commonDataCache.addToCache(requestId, cacheDocData);
}
}
} catch (Exception e) {
LOG.error("ErrorCode-{}, Component-{}, Message-{}. Error Loading cache data from file-{}. Exiting system", "OR-51010", "ORCHESTRATION", "Symphony cache loading exception", file.getAbsoluteFile(), e);
System.exit(0);
}
}
}
This is my cache utility class where store and retrieve methods are defines.
#Component
public class CommonDataCache {
private static final Logger LOG = LoggerFactory.getLogger(CommonDataCache.class);
#Autowired
HazelcastInstance hazelcastInstance;
#Autowired
SymphonyConfig config;
public static String LAST_UPDATED_TIME = "lastUpdatedTime";
private IMap<String, Object> hazelcastCache = null;
private boolean useHazelcast = false;
private final Map<String, Object> cache = new ConcurrentHashMap<>();
#PostConstruct
public void postConstruct() {
hazelcastCache = hazelcastInstance.getMap("default");
// Enable only if logging level is DEBUG
if (LOG.isDebugEnabled()) {
hazelcastCache.addEntryListener(new HazelcastMapListener(), true);
}
useHazelcast = config.getUseHazelcastCache();
}
public Map<String, Object> getAllDataFromCache() {
return hazelcastCache;
}
public void addToCache(String key, Object value) {
if (useHazelcast) {
hazelcastCache.put(key, value);
hazelcastCache.put(LAST_UPDATED_TIME, System.currentTimeMillis());
} else {
cache.put(key, value);
cache.put(LAST_UPDATED_TIME, System.currentTimeMillis());
}
}
public Object getAndRemoveFromCache(String key) {
if (useHazelcast) {
return hazelcastCache.remove(key);
} else {
return cache.remove(key);
}
}
public Object getFromCache(String key) {
if (useHazelcast) {
return hazelcastCache.get(key);
} else {
return cache.get(key);
}
}
/**
*
* #param cacheDataMap
*/
public void addAllToCache(Map<String, DocData> cacheDataMap, Map<String, ProcessStatusDto> processStatusMap) {
hazelcastCache.putAll(cacheDataMap);
hazelcastCache.putAll(processStatusMap);
hazelcastCache.put(LAST_UPDATED_TIME, System.currentTimeMillis());
}
public void lockKey(String key) {
if (useHazelcast) {
hazelcastCache.lock(key);
}
}
public void unlockKey(String key) {
if (useHazelcast) {
hazelcastCache.unlock(key);
}
}
public Map<String, Object> getByKeyContains(String keyString) {
Map<String, Object> values;
if (useHazelcast) {
Set<String> foundKeys = hazelcastCache.keySet(entry -> ((String)entry.getKey()).contains(keyString));
values = hazelcastCache.getAll(foundKeys);
} else {
values = Maps.filterEntries(cache, entry -> entry.getKey().contains(keyString));
}
return values;
}
}
Here is maven dependencies for groovy tests.
<!-- Dependencies for GROOVY TEST -->
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
<version>${hazelcast.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
<version>${hazelcast.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<!-- GROOVY TEST FRAMEWORK -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-core</artifactId>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-assets</artifactId>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-testing</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>realdoc</groupId>
<artifactId>dropwizard-spring</artifactId>
<version>${realdoc.dropwizard-spring.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<!-- any version of Groovy \>= 1.5.0 should work here -->
<version>${groovy-all.version}</version>
<!--<scope>test</scope>-->
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>${spock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>${spock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>${cglib-nodep.version}</version>
<scope>test</scope>
</dependency>
<!-- GROOVY TEST FRAMEWORK -->
<build>
<testSourceDirectory>src/test/groovy</testSourceDirectory>
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
</testResource>
</testResources>
...
...
</build>
I am checking out how to send an email using Spring Boot.
Send an e-mail using standard Spring Boot modules and prepare HTML content for a message using Thymeleaf template engine.
This is the dependencies I use
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.icegreen</groupId>
<artifactId>greenmail</artifactId>
<version>1.5.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Here my MailClient
#Service
public class MailClient {
private JavaMailSender mailSender;
private MailContentBuilder mailContentBuilder;
#Autowired
public MailClient(JavaMailSender mailSender, MailContentBuilder mailContentBuilder) {
this.mailSender = mailSender;
this.mailContentBuilder = mailContentBuilder;
}
public void prepareAndSend(String recipient, String message) {
MimeMessagePreparator messagePreparator = mimeMessage -> {
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage);
messageHelper.setFrom("amadeu.cabanilles#gmail.com");
messageHelper.setTo("amadeu.cabanilles#gmail.com");
messageHelper.setSubject("Sample mail subject");
String content = mailContentBuilder.build(message);
messageHelper.setText(content, true);
};
try {
mailSender.send(messagePreparator);
} catch (MailException e) {
e.printStackTrace();
}
}
}
This is my Test Class
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(Application.class)
public class MailClientTest {
#Autowired
private MailClient mailClient;
private GreenMail smtpServer;
#Before
public void setUp() throws Exception {
smtpServer = new GreenMail(new ServerSetup(25, null, "smtp"));
smtpServer.start();
}
#Test
public void shouldSendMail() throws Exception {
//given
String recipient = "amadeu.cabanilles#gmail.com";
String message = "Test message content";
//when
mailClient.prepareAndSend(recipient, message);
//then
String content = "<span>" + message + "</span>";
assertReceivedMessageContains(content);
}
private void assertReceivedMessageContains(String expected) throws IOException, MessagingException {
MimeMessage[] receivedMessages = smtpServer.getReceivedMessages();
assertEquals(1, receivedMessages.length);
String content = (String) receivedMessages[0].getContent();
System.out.println(content);
assertTrue(content.contains(expected));
}
#After
public void tearDown() throws Exception {
smtpServer.stop();
}
}
Executing the Test in my computer is OK, I pass the test but I don't receive any email.
You don't receive any email because this integration test uses local testing SMTP server stub - GreenMail. The test doesn't send real emails, only verifies if the mail is prepared and sent correctly if a real SMTP server is available in the production.
In order to send emails from your local environment, you need to setup some SMTP server, but then, automated verification if the mail is actually sent is a completely different story.