I am trying to read my excel file using drool I am able to successfully read the file from s3 but the problem comes when I make changes to that file and replace the existing file with new file my rule engine still reads old file values can anyone tell what can be done to resolve this issue
Dto
package com.example.demo;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
#Getter
#Setter
#ToString
#Component
#RefreshScope
public class DataDTO {
String firstName;
String lastName;
}
Drool Config
package com.example.demo.Config;
import lombok.extern.slf4j.Slf4j;
import org.drools.decisiontable.DecisionTableProviderImpl;
import org.kie.api.KieServices;
import org.kie.api.builder.*;
import org.kie.api.io.Resource;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.internal.io.ResourceFactory;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
#Configuration
#Slf4j
#RefreshScope
public class DroolConfig {
private KieServices kieServices = KieServices.Factory.get();
public KieFileSystem getKieFileSystem() throws IOException {
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
Resource resource;
log.info("File read form local resource folder");
resource = ResourceFactory
.newUrlResource("awsurl/123.xlsx");
kieFileSystem.write(resource);
DecisionTableProviderImpl decisionTableProvider
= new DecisionTableProviderImpl();
String leadBox = decisionTableProvider.loadFromResource(resource, null);
log.info("Rules Loaded from LeadBoxFile:{}", leadBox);
return kieFileSystem;
}
#Bean
#RefreshScope
public KieContainer getKieContainer() throws IOException {
getKieRepository();
KieBuilder abc = kieServices.newKieBuilder(getKieFileSystem());
abc.buildAll();
KieModule kieModule = abc.getKieModule();
KieContainer kContainer = kieServices.newKieContainer(kieModule.getReleaseId());
return kContainer;
}
private void getKieRepository() {
final KieRepository kieRepository = kieServices.getRepository();
kieRepository.addKieModule(new KieModule() {
public ReleaseId getReleaseId() {
return kieRepository.getDefaultReleaseId();
}
});
}
#Bean
public KieSession getKieSession() throws IOException {
return getKieContainer().newKieSession();
}
}
Controller
package com.example.demo;
import com.example.demo.Config.DroolConfig;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
#RestController
#RequestMapping("/v2")
public class LoadData {
#Autowired
private KieSession kieSession;
#Autowired
private final KieContainer kieContainer;
#Autowired
DroolConfig droolConfig;
public LoadData(KieSession kieSession, KieContainer kieContainer) {
this.kieSession = kieSession;
this.kieContainer = kieContainer;
}
#PostMapping("/printData")
public String printData(#RequestBody DataDTO dataDTO) throws IOException {
KieSession kieSession = kieContainer.newKieSession();
kieSession.insert(dataDTO);
kieSession.fireAllRules();
kieSession.dispose();
return dataDTO.getLastName();
}
#GetMapping("/loadDroolFile")
public String getDroolData() throws IOException {
droolConfig.getKieFileSystem();
kieContainer.getKieSessionConfiguration();
return "Done";
}
}
Whenever I try to hit loadDroolFile I am able to get refreshed data but the data does not get injected I still get the result from drool engine using old values
Related
I have a spring boot app with an Endpoint Test Configuration class and a unit test to test my http client. I am trying to get my server address and port from my application.properties which is located in my src/test.(All the classes are in my src/test.)
Here is my config class code :
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import javax.xml.bind.JAXBException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;
import com.nulogix.billing.service.PredictionEngineService;
import com.nulogix.billing.ws.endpoint.AnalyzeEndPoint;
import com.nulogix.billing.ws.endpoint.GetVersionEndPoint;
#Configuration
public class EndPointTestConfiguration {
#Value("${billing.engine.address}")
private String mockAddress;
#Value("${billing.engine.port}")
private String mockPort;
#Bean
public String getAddress() {
String serverAddress = "http://" + mockAddress + ":" + mockPort;
return serverAddress;
}
#Bean
public GetVersionEndPoint getVersionEndPoint() {
return new GetVersionEndPoint();
}
I annotated the values from my .properties with #value and then created a method that I instantiated with a bean to to return my server address string.
I then use that string value here in my HttpClientTest class:
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.Map;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.ContentType;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ConfigurableApplicationContext;
import com.google.gson.Gson;
import com.nulogix.billing.configuration.EndPointTestConfiguration;
import com.nulogix.billing.mockserver.MockServerApp;
#SpringBootTest(classes = EndPointTestConfiguration.class)
public class HttpClientTest {
#Autowired
EndPointTestConfiguration endpoint;
public static final String request_bad = "ncs|56-2629193|1972-03-28|20190218|77067|6208|3209440|self|";
public static final String request_good = "ncs|56-2629193|1972-03-28|20190218|77067|6208|3209440|self|-123|-123|-123|0.0|0.0|0.0|0.0|0.0|0.0|0.0";
//gets application context
static ConfigurableApplicationContext context;
//call mock server before class
#BeforeClass
static public void setup(){
SpringApplication springApplication = new SpringApplicationBuilder()
.sources(MockServerApp.class)
.build();
context = springApplication.run();
}
//shutdown mock server after class
#AfterClass
static public void tearDown(){
SpringApplication.exit(context);
}
#Test
public void test_bad() throws ClientProtocolException, IOException {
// missing parameter
String result = Request.Post(endpoint.getAddress())
.connectTimeout(2000)
.socketTimeout(2000)
.bodyString(request_bad, ContentType.TEXT_PLAIN)
.execute().returnContent().asString();
Map<?, ?> resultJsonObj = new Gson().fromJson(result, Map.class);
// ensure the key exists
assertEquals(resultJsonObj.containsKey("status"), true);
assertEquals(resultJsonObj.containsKey("errorMessage"), true);
// validate values
Boolean status = (Boolean) resultJsonObj.get("status");
assertEquals(status, false);
String errorMessage = (String) resultJsonObj.get("errorMessage");
assertEquals(errorMessage.contains("Payload has incorrect amount of parts"), true);
}
#Test
public void test_good() throws ClientProtocolException, IOException {
String result = Request.Post(endpoint.getAddress())
.connectTimeout(2000)
.socketTimeout(2000)
.bodyString(request_good, ContentType.TEXT_PLAIN)
.execute().returnContent().asString();
Map<?, ?> resultJsonObj = new Gson().fromJson(result, Map.class);
// ensure the key exists
assertEquals(resultJsonObj.containsKey("status"), true);
assertEquals(resultJsonObj.containsKey("errorMessage"), false);
assertEquals(resultJsonObj.containsKey("HasCopay"), true);
assertEquals(resultJsonObj.containsKey("CopayAmount"), true);
assertEquals(resultJsonObj.containsKey("HasCoinsurance"), true);
assertEquals(resultJsonObj.containsKey("CoinsuranceAmount"), true);
assertEquals(resultJsonObj.containsKey("version"), true);
// validate values
Boolean status = (Boolean) resultJsonObj.get("status");
assertEquals(status, true);
String version = (String) resultJsonObj.get("version");
assertEquals(version, "0.97");
}
}
I use it in the request.post, I didn't want to hardcode in my IP address and port number.
When I run the test it says
[ERROR] HttpClientTest.test_bad:63 NullPointer
[ERROR] HttpClientTest.test_good:86 NullPointer
But I am not sure why it is null? I am pretty sure I have everything instantiated and the string is clearly populated..
My package structure for my config is com.billing.mockserver and my package structure for my unit test is com.billing.ws.endpoint.
Here is my application.properties
server.port=9119
server.ssl.enabled=false
logging.config=classpath:logback-spring.xml
logging.file=messages
logging.file.max-size=50MB
logging.level.com.nulogix=DEBUG
billing.engine.address=127.0.0.1
billing.engine.port=9119
billing.engine.api.version=0.97
billing.engine.core.name=Patient_Responsibility
You are missing springboot basic understanding. #Configuration class is to initialize other spring beans and other things and are the first classes which get initialized. You should not #Autowire #configuration class.
In your Configuration class you can either create Spring bean for username and password and autowire that in your test class or directly use #Value in your Test class.
Example: in your configuration class you are creating bean of GetVersionEndPoint and you can autowire that in your Test class.
Update 2:
For test classes, you need to add application.properties file in src\test\resource
I'm using spring batch with java configuration (new to this) and I'm running into a error when trying to use a ClassifierCompositeItemWriter so generate separate files based on a classifier.
The error im getting is org.springframework.batch.item.WriterNotOpenException: Writer must be open before it can be written to
My configuration looks like follows:
package com.infonova.btcompute.batch.geneva.job;
import com.infonova.btcompute.batch.billruntransfer.BillRunTranStatusFinishedJobAssignment;
import com.infonova.btcompute.batch.billruntransfer.BillRunTranStatusInprogressJobAssignment;
import com.infonova.btcompute.batch.billruntransfer.BillRunTransferStatus;
import com.infonova.btcompute.batch.geneva.camel.GenevaJobLauncher;
import com.infonova.btcompute.batch.geneva.dto.GenevaDetailsResultsDto;
import com.infonova.btcompute.batch.geneva.dto.GenveaDetailsTransactionDto;
import com.infonova.btcompute.batch.geneva.properties.GenevaDetailsExportJobProperties;
import com.infonova.btcompute.batch.geneva.rowmapper.GenevaDetailsTransactionsRowMapper;
import com.infonova.btcompute.batch.geneva.steps.*;
import com.infonova.btcompute.batch.repository.BillrunTransferStatusMapper;
import com.infonova.btcompute.batch.utils.FileNameGeneration;
import com.infonova.product.batch.camel.CamelEnabledJob;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.item.file.FlatFileItemWriter;
import org.springframework.batch.item.support.ClassifierCompositeItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.classify.BackToBackPatternClassifier;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.FileSystemResource;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public abstract class AbstractGenevaDetailsExportJob extends CamelEnabledJob {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractGenevaDetailsExportJob.class);
#Autowired
protected JobBuilderFactory jobBuilders;
#Autowired
protected StepBuilderFactory stepBuilders;
#Autowired
protected DataSource datasource;
#Autowired
private BillrunTransferStatusMapper billrunTransferStatusMapper;
#Autowired
protected JdbcTemplate jdbcTemplate;
public abstract GenevaDetailsExportJobProperties jobProperties();
#Bean
public RouteBuilder routeBuilder(final GenevaDetailsExportJobProperties jobProperties, final Job job) {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from(jobProperties.getConsumer())
.transacted("PROPAGATION_REQUIRED")
.routeId(jobProperties.getInputRouteName())
.process(genevaJobLauncher(job));
//.to("ftp://app#127.0.0.1?password=secret");
}
};
}
#Bean
public Processor genevaJobLauncher(Job job) {
return new GenevaJobLauncher(job);
}
#Bean
#StepScope
public GenevaDetailsReader reader() {
GenevaDetailsReader reader = new GenevaDetailsReader(jobProperties().getMandatorKey(),
jobProperties().getInvoiceType(), jobProperties().getSqlResourcePath());
reader.setSql("");
reader.setDataSource(datasource);
reader.setRowMapper(new GenevaDetailsTransactionsRowMapper());
reader.setFetchSize(jobProperties().getFetchSize());
return reader;
}
#Bean
#StepScope
public GenevaDetailsItemProcessor processor() {
return new GenevaDetailsItemProcessor();
}
#Bean
#StepScope
public ClassifierCompositeItemWriter writer() {
List<String> serviceCodes = new ArrayList<>();//billrunTransferStatusMapper.getServiceCodes(jobProperties().getMandatorKey());
Long billingTaskId = billrunTransferStatusMapper.getCurrentTaskId(jobProperties().getMandatorKey());
String countryKey = billrunTransferStatusMapper.getCountryKey(billingTaskId);
serviceCodes.add("BTCC");
serviceCodes.add("CCMS");
BackToBackPatternClassifier classifier = new BackToBackPatternClassifier();
classifier.setRouterDelegate(new GenveaDetailsRouterClassifier());
HashMap<String, Object> map = new HashMap<>();
for (String serviceCode : serviceCodes) {
map.put(serviceCode, genevaDetailsWriter(serviceCode, countryKey));
}
classifier.setMatcherMap(map);
ClassifierCompositeItemWriter<GenveaDetailsTransactionDto> writer = new ClassifierCompositeItemWriter<>();
writer.setClassifier(classifier);
return writer;
}
#Bean
#StepScope
public GenevaDetailsFlatFileItemWriter genevaDetailsWriter(String serviceCode, String countryKey) {
GenevaDetailsFlatFileItemWriter writer = new GenevaDetailsFlatFileItemWriter(jobProperties().getDelimiter());
FileNameGeneration fileNameGeneration = new FileNameGeneration();
try {
FileSystemResource fileSystemResource = new FileSystemResource(new File(jobProperties().getExportDir(), fileNameGeneration.generateFileName(jdbcTemplate,
serviceCode, countryKey)));
writer.setResource(fileSystemResource);
} catch (SQLException e) {
LOGGER.error("Error creating FileSystemResource : " + e.getMessage());
}
return writer;
}
#Bean
public Job job() {
return jobBuilders.get(jobProperties().getJobName())
.start(setBillRunTransferStatusDetailInprogressStep())
.next(processGenevaDetailsStep())
.next(setBillRunTransferStatusProcessedStep())
.build();
}
#Bean
public Step setBillRunTransferStatusDetailInprogressStep() {
return stepBuilders.get("setBillRunTransferStatusDetailInprogressStep")
.tasklet(setBillRunTransferStatusDetailInprogress())
.build();
}
#Bean
public Tasklet setBillRunTransferStatusDetailInprogress() {
return new BillRunTranStatusInprogressJobAssignment(BillRunTransferStatus.SUMMARY.toString(), BillRunTransferStatus.DETAILS_INPROGRESS.toString(),
jobProperties().getMandatorKey(), jobProperties().getInvoiceTypeNum(), jobProperties().getReportTypeNum());
}
#Bean
public Step setBillRunTransferStatusProcessedStep() {
return stepBuilders.get("setBillRunTransferStatusProcessedStep")
.tasklet(setBillRunTransferStatusProcessed())
.build();
}
#Bean
public Tasklet setBillRunTransferStatusProcessed() {
return new BillRunTranStatusFinishedJobAssignment(BillRunTransferStatus.PROCESSED.toString());
}
#Bean
public Step processGenevaDetailsStep() {
return stepBuilders.get("processGenevaDetailsStep")
.<GenveaDetailsTransactionDto, GenevaDetailsResultsDto>chunk(jobProperties().getChunkSize())
.reader(reader())
.processor(processor())
.writer(writer())
.build();
}
}
and my writer looks like:
package com.infonova.btcompute.batch.geneva.steps;
import com.infonova.btcompute.batch.geneva.dto.GenevaDetailsResultsDto;
import com.infonova.btcompute.batch.repository.BillrunTransferStatusMapper;
import com.infonova.btcompute.batch.utils.FileNameGeneration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.annotation.BeforeStep;
import org.springframework.batch.item.*;
import org.springframework.batch.item.file.FlatFileHeaderCallback;
import org.springframework.batch.item.file.FlatFileItemWriter;
import org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor;
import org.springframework.batch.item.file.transform.DelimitedLineAggregator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
#Component
public class GenevaDetailsFlatFileItemWriter extends FlatFileItemWriter<GenevaDetailsResultsDto> {
private static final Logger LOGGER = LoggerFactory.getLogger(GenevaDetailsFlatFileItemWriter.class);
#Autowired
protected JdbcTemplate jdbcTemplate;
#Autowired
private BillrunTransferStatusMapper billrunTransferStatusMapper;
private String delimiter;
public GenevaDetailsFlatFileItemWriter(String delimiter) {
this.delimiter = delimiter;
this.setLineAggregator(getLineAggregator());
this.setHeaderCallback(getHeaderCallback());
}
private DelimitedLineAggregator<GenevaDetailsResultsDto> getLineAggregator() {
DelimitedLineAggregator<GenevaDetailsResultsDto> delLineAgg = new DelimitedLineAggregator<>();
delLineAgg.setDelimiter(delimiter);
BeanWrapperFieldExtractor<GenevaDetailsResultsDto> fieldExtractor = new BeanWrapperFieldExtractor<>();
fieldExtractor.setNames(getNames());
delLineAgg.setFieldExtractor(fieldExtractor);
return delLineAgg;
}
private String[] getHeaderNames() {
return new String[] {"Record ID", "Service Identifier", "Billing Account Reference", "Cost Description", "Event Cost",
"Event Date and Time", "Currency Code", "Charge Category", "Order Identifier", "Net Usage", "UOM",
"Quantity", "Service Start Date", "Service End Date"};
}
private String[] getNames() {
return new String[] {"RECORD_ID", "SERVICE_CODE", "BILLING_ACCOUNT_REFERENCE", "COST_DESCRIPTION", "EVENT_COST",
"EVENT_DATE_AND_TIME", "CURRENCY_CODE", "CHARGE_CATEGORY", "ORDER_IDENTIFIER", "NET_USAGE", "UOM",
"QUANTITY", "SERVICE_START_DATE", "SERVICE_END_DATE"};
}
private FlatFileHeaderCallback getHeaderCallback()
{
return new FlatFileHeaderCallback() {
#Override
public void writeHeader(Writer writer) throws IOException {
writer.write(String.join(delimiter, getHeaderNames()));
}
};
}
// #BeforeStep
// public void beforeStep(StepExecution stepExecution) {
// billingTaskId = (Long) stepExecution.getJobExecution().getExecutionContext().get("billingTaskId");
// FileNameGeneration fileNameGeneration = new FileNameGeneration();
//
// try {
// FileSystemResource fileSystemResource = new FileSystemResource(new File(exportDir, fileNameGeneration.generateFileName(jdbcTemplate,
// serviceCode, billrunTransferStatusMapper.getCountryKey(billingTaskId))));
// setResource(fileSystemResource);
// } catch (SQLException e) {
// LOGGER.error("Error creating FileSystemResource : " + e.getMessage());
// }
// }
}
I have searched the web and cannot find a solution to this issue.
What #Hansjoerg Wingeier wrote about ClassifierCompositeItemWriter is correct, but the right way to resolve the problem is to register delegated writer(s) as stream(s) using AbstractTaskletStepBuilder.stream() to let SB manage execution context lifecycle.
ClassifierCompositeItemWriter does not implement the ItemStream interface, hence the open method of your FlatFileItemWriter is never called.
The easiest thing to do is to call the open method when you create your classifier map:
for (String serviceCode : serviceCodes) {
FlatFileItemWriter writer =genevaDetailsWriter(serviceCode, countryKey);
writer.open (new ExecutionContext ());
map.put(serviceCode, writer);
}
I have below code for making a POST call to RestAPI for Tableau system, which is working and seeing response output.
However, I would like to capture cookie from this output and need to be used for further consumption! Can somebody help me on this problem?
Code:
package com.abc.it.automation.service;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Properties;
import org.springframework.http.HttpHeaders;
import org.springframework.http.RequestEntity.HeadersBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestTemplate;
import com.abc.it.automation.utils.SSLUtil;
public class BIaaSTableauService {
private static Properties tableau_properties = new Properties();
static {
// Loads the values from configuration file into the Properties instance
try {
tableau_properties.load(new FileInputStream("res/config.properties"));
} catch (IOException e) {
System.out.println(e);
}
}
private static final String loginURL = tableau_properties.getProperty("server.host");
private static final String siteSearchURL = tableau_properties.getProperty("site.search.url");
public static void main(String[] args) throws KeyManagementException, NoSuchAlgorithmException {
RestTemplate restTableau = new RestTemplate();
String requestLogin = "<tsRequest>"+
"<credentials name=\"svc_tableau\" password=\"xxxxxxxxx\" >"+
"<site contentUrl=\"\"/>"+
"</credentials>"+
"</tsRequest>";
SSLUtil.turnOffSslChecking();
ResponseEntity<String> responseLogin = restTableau.postForEntity(loginURL, requestLogin, String.class);
System.out.println(responseLogin.getBody());
You need to build your RestTemplate as follows.
RestTemplate restTableau = new RestTemplate(new MyClientHttpRequestFactory());
Extend ClientHttpRequestFactory as follows.
public class MyClientHttpRequestFactory extends SimpleClientHttpRequestFactory {
private Cookie cookie;
//setters and getters.
#Override
protected void prepareConnection(HttpURLConnection connection, String httpMethod) {
this.setCookie(connection.getRequestProperty("Cookie"));
}
}
I have a simple chat application set up using Spring Boot (1.3.2) and Atmosphere (2.4.2).
Here is my WebSocketConfigurer:
package com.chat.shared.websocket;
import java.util.Collections;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.apache.catalina.Context;
import org.apache.tomcat.websocket.server.WsSci;
import org.atmosphere.cpr.AtmosphereFramework;
import org.atmosphere.cpr.AtmosphereServlet;
import org.atmosphere.cpr.MetaBroadcaster;
import org.springframework.boot.context.embedded.ServletContextInitializer;
import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.chat.privatechat.ChatChannel;
#Configuration
public class WebSocketConfigurer implements ServletContextInitializer {
#Bean
public TomcatEmbeddedServletContainerFactory tomcatContainerFactory() {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.setTomcatContextCustomizers(Collections.singletonList(tomcatContextCustomizer()));
return factory;
}
#Bean
public TomcatContextCustomizer tomcatContextCustomizer() {
return new TomcatContextCustomizer() {
#Override
public void customize(Context context) {
context.addServletContainerInitializer(new WsSci(), null);
}
};
}
#Bean
public AtmosphereServlet atmosphereServlet() {
return new AtmosphereServlet();
}
#Bean
public AtmosphereFramework atmosphereFramework() {
return atmosphereServlet().framework();
}
#Bean
public MetaBroadcaster metaBroadcaster() {
AtmosphereFramework framework = atmosphereFramework();
return framework.metaBroadcaster();
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
configureAtmosphere(atmosphereServlet(), servletContext);
}
private void configureAtmosphere(AtmosphereServlet servlet, ServletContext servletContext) {
ServletRegistration.Dynamic reg = servletContext.addServlet("atmosphereServlet", servlet);
reg.setInitParameter("org.atmosphere.cpr.packages", ChatChannel.class.getPackage().getName());
reg.setInitParameter("org.atmosphere.cpr.broadcasterClass", "org.atmosphere.plugin.hazelcast.HazelcastBroadcaster");
reg.setInitParameter("org.atmosphere.cpr.broadcaster.maxProcessingThreads", "10");
reg.setInitParameter("org.atmosphere.cpr.broadcaster.maxAsyncWriteThreads", "10");
reg.setInitParameter("org.atmosphere.interceptor.HeartbeatInterceptor.clientHeartbeatFrequencyInSeconds", "10");
servletContext.addListener(new org.atmosphere.cpr.SessionSupport());
reg.addMapping("/chat/*");
reg.setLoadOnStartup(0);
reg.setAsyncSupported(true);
}
}
And here is how I'm currently leveraging it in the ChatChannel:
package com.chat.privatechat;
import com.chat.privatechat.DTOs.ChatMessageDTO;
import com.chat.shared.localmessagebus.LocalMessage;
import com.chat.shared.localmessagebus.LocalMessageBus;
import org.atmosphere.config.service.Disconnect;
import org.atmosphere.config.service.Get;
import org.atmosphere.config.service.ManagedService;
import org.atmosphere.config.service.PathParam;
import org.atmosphere.config.service.Ready;
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.AtmosphereResourceEvent;
import org.atmosphere.cpr.AtmosphereResourceFactory;
import org.atmosphere.cpr.BroadcasterFactory;
import org.atmosphere.cpr.MetaBroadcaster;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import javax.inject.Inject;
#ManagedService(path = "/chat/{channel: [a-zA-Z][a-zA-Z_0-9]*}")
public class ChatChannel {
#PathParam("channel")
private String channelUuid;
#Inject
private BroadcasterFactory factory;
#Inject
private AtmosphereResourceFactory resourceFactory;
#Inject
private MetaBroadcaster metaBroadcaster;
#Get
public void init(AtmosphereResource resource) {
resource.getResponse().setCharacterEncoding(StandardCharsets.UTF_8.name());
}
#Ready
public void onReady(final AtmosphereResource resource) {
String userId = resource.getRequest().getHeader("userId");
System.out.println("User " + userId + " has connected.");
}
#Disconnect
public void onDisconnect(AtmosphereResourceEvent event) {
String userId = event.getResource().getRequest().getHeader("userId");
System.out.println("User " + userId + " has disconnected");
}
#org.atmosphere.config.service.Message(encoders = MessageEncoderDecoder.class, decoders = MessageEncoderDecoder.class)
public ChatMessageDTO onMessage(ChatMessageDTO chatMessage) throws IOException {
LocalMessageBus.manager().send(new LocalMessage<ChatMessageDTO>(chatMessage));
return chatMessage;
}
}
This setup works great (users in a conversation are connected to a "channel" and the messages are sent/received immediately. LocalMessageBus is a simple message bus that will eventually be replaced by a proper message broker).
Although I don't have a use case for this, I went to set up a MetaBroadcaster in my ChatController to see if I could broadcast messages from there. Unfortunately, I am not able to properly inject/reference the MetaBroadcaster as it is always null. Here's the important bits of the ChatController:
package com.chat.privatechat;
import java.util.List;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import com.chat.privatechat.DTOs.ChatMessageDTO;
import com.chat.privatechat.DTOs.ChatSessionInitializationDTO;
import com.chat.privatechat.DTOs.EstablishedChatSessionDTO;
import com.chat.shared.http.JSONResponseHelper;
import com.chat.user.UserService;
import com.chat.user.exceptions.IsSameUserException;
import com.chat.user.exceptions.UserNotFoundException;
import com.chat.user.strategies.UserRetrievalByIdStrategy;
#Controller
public class ChatController {
#Autowired
private ChatService chatService;
#Autowired
private BeanFactory beanFactory;
#Autowired
private UserService userService;
#Inject
private MetaBroadcaster metaBroadcaster;
#RequestMapping(value="/api/chat/session", method=RequestMethod.PUT, produces="application/json", consumes="application/json")
public ResponseEntity<String> establishChatSession(#RequestBody ChatSessionInitializationDTO initialChatSession) throws IsSameUserException, BeansException, UserNotFoundException {
...
}
#RequestMapping(value="/api/chat/session/{channelUuid}", method=RequestMethod.GET, produces="application/json")
public ResponseEntity<String> getExistingChatSessionMessages(#PathVariable("channelUuid") String channelUuid) {
...
}
}
Injecting/Autowiring MetaBroadcaster nor bringing in metaBroadcaster bean from the BeanFactory work. I've searched and searched and searched without a good solution. It seems like the bean in not accessible in this Spring Controller context and I'm running out of ideas.
Thanks you for any input!
NOTE: These are the Atmosphere deps I have:
<dependency>
<groupId>org.atmosphere</groupId>
<artifactId>atmosphere-runtime</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>org.atmosphere</groupId>
<artifactId>atmosphere-spring</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>atmosphere-javascript</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>org.atmosphere</groupId>
<artifactId>atmosphere-hazelcast</artifactId>
<version>2.4.2</version>
</dependency>
How to send file with Java RabbitMQ?
Especially using message converter.
I'm using Spring Framework, can send String or ArrayList but can't send File. I'm only use convertAndSend and convertAndReceive to send File but get :
org.springframework.amqp.AmqpIOException: java.io.FileNotFoundException
I don't know how to use message converter. The code from here and change some class :
HelloWorldHandler.java
package org.springframework.amqp.helloworld.async;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import org.springframework.amqp.core.Message;
public class HelloWorldHandler {
public void handleMessage(File message) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(message));
System.out.println(br.readLine());
}
}
ProducerConfiguration.java
package org.springframework.amqp.helloworld.async;
import java.io.File;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor;
#Configuration
public class ProducerConfiguration {
protected final String helloWorldQueueName = "hello.world.queue";
#Bean
public RabbitTemplate rabbitTemplate() {
RabbitTemplate template = new RabbitTemplate(connectionFactory());
template.setRoutingKey(this.helloWorldQueueName);
return template;
}
#Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory("x.x.x.x");
connectionFactory.setUsername("username");
connectionFactory.setPassword("password");
return connectionFactory;
}
#Bean
public ScheduledProducer scheduledProducer() {
return new ScheduledProducer();
}
#Bean
public BeanPostProcessor postProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
static class ScheduledProducer {
#Autowired
private volatile RabbitTemplate rabbitTemplate;
private final AtomicInteger counter = new AtomicInteger();
#Scheduled(fixedRate = 3000)
public void sendMessage() {
rabbitTemplate.convertAndSend(new File("test.txt"));
}
}
}
You can convert the file content into byte array and send the byte[] as below.
byte[] fileData = // get content from file as byte[] [Refer Here][1]
String fileType = // get file type from file
Message message = MessageBuilder.withBody(fileData).setHeader("ContentType", fileType).build();
rabbitTemplate.send("exchnage name", "routing key", message);