I'm creating topic in Kafka with the below method,
public class KafkaTopicAdmin {
public void createTopic(final String topicName) {
final AdminClient client = getKafkaClient();
final List<NewTopic> topics = Collections.synchronizedList(new ArrayList<>());
final NewTopic newTopic = new NewTopic(topicName, connectionConfig.getNoOfPartition(), (short) connectionConfig.getNoOfReplicas());
topics.add(newTopic);
client.createTopics(topics);
}
private AdminClient getKafkaClient() {
final Map<String, Object> configs = new ConcurrentHashMap<>();
configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, "bootstrap-ip");
return AdminClient.create(configs);
}
}
and my test class is,
#EmbeddedKafka
public class KafkaTopicAdminTest {
private KafkaTopicAdmin kafkaTopicAdmin;
private AdminClient kafkaAdminClient;
#Before
public void setUp(){
kafkaTopicAdmin = new KafkaTopicAdmin();
Properties properties = new Properties();
properties.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, StringUtils.arrayToCommaDelimitedString(new EmbeddedKafkaBroker(2).getBrokerAddresses()));
kafkaAdminClient = KafkaAdminClient.create(properties);
}
#Test
public void shouldCreateTopic() throws ExecutionException, InterruptedException {
kafkaTopicAdmin.createTopic("TestTopic");
ListTopicsOptions listTopicsOptions = new ListTopicsOptions();
listTopicsOptions.listInternal(true);
System.out.println("topics:" + kafkaAdminClient.listTopics(listTopicsOptions).names().get());
}
}
I'm getting the below error,
[AdminClient clientId=adminclient-1] Error connecting to node 127.0.0.1:0 (id: -2 rack: null)
java.net.BindException: Can't assign requested address
I use #EmbeddedKafka I just wanted to make sure the topic present in the list. Is this correct approach or any other suggestion please?
From the error it looks like you specified the bootstrap.servers property with no port: 127.0.0.1:0
This property takes the port of your Kafka bootstrap server too, which by default is 9092, so try this:
configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, "bootstrap-server-ip:9092");
Related
I am writing an SQS publisher/consumer application using Spring Cloud AWS 2.3.2
<dependency>
<groupId>io.awspring.cloud</groupId>
<artifactId>spring-cloud-aws-messaging</artifactId>
<version>2.3.2</version>
</dependency>
I have gotten to the point where I can successfully publish msgs to my SQS, but my #SqsListener annotated method does not consume the msgs. I looked at other Q&A here but none seemed to provide any proper insight to solve this issue.
I am following the API docs here: https://docs.awspring.io/spring-cloud-aws/docs/current/reference/html/index.html#annotation-driven-listener-endpoints
I have my configuration defined as below:
#Configuration
public class SqsMessagingConfig {
#Value("${cloud.aws.credentials.secret-key}")
private String secretKey;
#Value("${cloud.aws.credentials.access-key}")
private String accessKey;
private AWSCredentialsProvider awsCredentialsProvider() {
return new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey,
secretKey));
}
#Bean
#Primary
public AmazonSQSAsync amazonSQSAsync() {
return AmazonSQSAsyncClientBuilder
.standard()
.withRegion("us-east-2")
.withCredentials(awsCredentialsProvider())
.build();
}
#Bean
public QueueMessagingTemplate queueMessagingTemplate(AmazonSQSAsync amazonSQSAsync) {
return new QueueMessagingTemplate(amazonSQSAsync);
}
#Bean
public SimpleMessageListenerContainerFactory simpleMessageListenerContainerFactory(AmazonSQSAsync amazonSQSAsync) {
SimpleMessageListenerContainerFactory factory = new SimpleMessageListenerContainerFactory();
factory.setAmazonSqs(amazonSQSAsync);
factory.setAutoStartup(true);
factory.setMaxNumberOfMessages(10);
return factory;
}
#Bean()
public QueueMessageHandlerFactory queueMessageHandlerFactory(final ObjectMapper mapper, final AmazonSQSAsync amazonSQSAsync) {
final QueueMessageHandlerFactory queueHandlerFactory = new QueueMessageHandlerFactory();
queueHandlerFactory.setAmazonSqs(amazonSQSAsync);
queueHandlerFactory.setArgumentResolvers(Collections.singletonList(new PayloadMethodArgumentResolver(jackson2MessageConverter(mapper))));
return queueHandlerFactory;
}
private MessageConverter jackson2MessageConverter(final ObjectMapper mapper) {
final MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setObjectMapper(mapper);
return converter;
}
}
And then my SqsService looks like the following:
#Service
public class SqsQueueService {
private static final Logger logger = LoggerFactory.getLogger(SqsQueueService.class);
private final QueueMessagingTemplate queueMessagingTemplate;
private final ObjectWriter objectWriter;
private final String QUEUE_NAME = "SCHEDULES";
public SqsQueueService(QueueMessagingTemplate queueMessagingTemplate, ObjectMapper mapper) {
this.queueMessagingTemplate = queueMessagingTemplate;
this.objectWriter = mapper.writer();
}
public void send(List<Schedule> schedules) {
List<String> originatingIds = schedules.stream().map(Schedule::getOriginatingId).collect(Collectors.toList());
try {
Message<String> message = MessageBuilder.withPayload(objectWriter.writeValueAsString(schedules))
.build();
this.queueMessagingTemplate.convertAndSend(QUEUE_NAME, message);
logger.info("Successfully sent {} schedule(s) to SQS, with originatingId={}", schedules.size(),
originatingIds);
} catch (Exception e) {
logger.error("Failed to send the following schedule(s) to SQS=" + originatingIds, e);
}
}
// NO_REDRIVE ensures we do not re-queue messages forever. They will be sent to a DLQ if they exceed maxReceiveCount
#SqsListener(value = "SCHEDULES", deletionPolicy = SqsMessageDeletionPolicy.NO_REDRIVE)
private void receiveMessage(List<Schedule> schedules) String partnerId) {
List<String> originatingIds = schedules.stream().map(Schedule::getOriginatingId).collect(Collectors.toList());
logger.info("Received request from SQS for originatingId={}", originatingIds);
try {
someService.createSchedules(schedules);
} catch (Exception e) {
throw new RuntimeException("An issue occurred during ingest for originatingId=" + originatingIds, e);
}
}
}
I also tried the aws-autoconfigured dependency, but that added ton of extra noise and I still was not able to get it to consume from SQS. Hoping someone can spot where I am messing up/missing something. The docs that I saw as reference directly from spring devs point to me doing the right thing, but obviously, that is not the case.
After I send the message to the queue, I can see it waiting to be consumed but nothing happens. Any help is greatly appreciated.
Add the spring cloud aws autoconfigure dependency:
<dependency>
<groupId>io.awspring.cloud</groupId>
<artifactId>spring-cloud-aws-autoconfigure</artifactId>
</dependency>
https://docs.awspring.io/spring-cloud-aws/docs/current/reference/html/index.html#maven-dependencies
I am using AEM Mocks to test a custom servlet that uses a configuration, as such:
#Activate
void activate(final Config config) { ... }
I am following the approach described here and here to register and inject the service together with a HashMap, as such:
private static Map<String, Object> myHashMap = new HashMap<>();
...
myHashMap.put("a", "b");
myHashMap.put("c", "d");
...
servlet = context.registerInjectActivateService(new MyServlet(), myHashMap);
However, this approach doesn't work. The config object passed above, inside the activate function, is corrupted. For every key-value pair above, it sets null as the value. So instead of:
a -> b
c -> d
It sets:
a -> null
c -> null
Inside the HashMap. Can anyone please help? Thanks!
P.S. I should add that I am using version 2.3.0 of AEM Mocks since the recent versions cause an issue with an older artifact. For more info on that, see here.
I tested it, and it works with version 2.3.0 too. Could you check the following example? After that, it is probably a maven issue. Then we would need more information.
Here is my test servlet:
#Component(service = Servlet.class,
property = {
SLING_SERVLET_PATHS + "=/bin/servlet/test",
SLING_SERVLET_METHODS + "=GET",
SLING_SERVLET_EXTENSIONS + "=text"
})
#Designate(ocd = TestServlet.Config.class)
public class TestServlet extends SlingSafeMethodsServlet {
#ObjectClassDefinition
public #interface Config {
#AttributeDefinition(
name = "Name",
description = "Name used in the hello world text"
)
String name() default "Alex";
#AttributeDefinition(
name = "Greeting",
description = "Greeting - Morning, to demonstrate the dot-replacement"
)
String greeting_morning() default "Good Morning";
}
private Config config;
#Override
protected void doGet(#Nonnull SlingHttpServletRequest request, #Nonnull SlingHttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
response.getWriter().println(this.getGreeting());
}
public String getGreeting() {
return config.greeting_morning() + ", " + config.name();
}
#Activate
void activate(final Config config) {
this.config = config;
}
}
Here is a JUnit 4 test:
public class TestServletTest {
#Rule
public final AemContext context = new AemContext();
#Test
public void testWithoutConfig() {
final TestServlet testServlet = context.registerInjectActivateService(new TestServlet());
assertEquals("Good Morning, Alex", testServlet.getGreeting());
}
#Test
public void testWithConfig() {
final Map<String, Object> properties = new HashMap<>();
properties.put("name", "Berndt");
properties.put("greeting.morning", "Keep sleeping");
final TestServlet testServlet = context.registerInjectActivateService(new TestServlet(), properties);
assertEquals("Keep sleeping, Berndt", testServlet.getGreeting());
}
}
I am self-hosting a duplex-contract, WCF service.
In composing a test that exercises if my client is receiving messages from the service, I have found that I can't debug the service itself.
Thus, I made a simple example that seems to help me repeat the issue.
This is an example of the test I'm attempting:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
ServiceRunner.Run(null);
var client = new ServiceReference1.Service1Client();
var result = client.GetData(11);
Assert.IsNotNull(result);
ServiceRunner.Host.Close();
}
}
ServiceRunner will host the WCF contract in a singleton. The client is from a service reference that points to the self-hosted service. When I call GetData(11) I get a response, it's just that my breakpoint in the service is never hit.
Why is that?
Here's the implementation of the service for completeness:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
namespace CanYouDebugThis
{
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
}
[ServiceBehaviorAttribute(InstanceContextMode = InstanceContextMode.Single)]
public class Service1 : IService1
{
public string GetData(int value)
{
Console.WriteLine($"Get data with {value}");
return string.Format("You entered: {0}", value);
}
}
public class ServiceRunner
{
public static ServiceHost Host;
public static void Run(String[] args)
{
var serviceInstance = new Service1();
Uri baseAddress = new Uri("http://localhost:8080/hello");
Host = new ServiceHost(serviceInstance, baseAddress);
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
Host.Description.Behaviors.Add(smb);
Host.Open();
}
}
}
There is something wrong with hosting the service. We should add service endpoint and MEX endpoint for exchanging metadata. Please refer to the below code segments.
public static ServiceHost Host;
public static void Main(String[] args)
{
var serviceInstance = new Service1();
Uri baseAddress = new Uri("http://localhost:8080/hello");
BasicHttpBinding binding = new BasicHttpBinding();
//Host = new ServiceHost(serviceInstance, baseAddress);
Host = new ServiceHost(typeof(Service1), baseAddress);
Host.AddServiceEndpoint(typeof(IService1), binding, "");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
Host.Description.Behaviors.Add(smb);
Binding mexbinding = MetadataExchangeBindings.CreateMexHttpBinding();
Host.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "mex");
Host.Open();
Console.WriteLine("Service is ready...");
//pause, accepting a word would teminate the service.
Console.ReadLine();
Host.Close();
Console.WriteLine("Service is closed....");
}
Please host the service in an individual Console project first. Then on the client-side, we generate the client proxy by adding the service reference. Please pay attention to the auto-generated service endpoint, which should be corresponding to the actual server endpoint.
Result.
Feel free to let me know if there is anything I can help with.
Updated.
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
ServiceRunner.Run(null);
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
var result = client.GetData(34);
Assert.IsNotNull(result);
}
}
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
}
[ServiceBehaviorAttribute(InstanceContextMode = InstanceContextMode.Single)]
public class Service1 : IService1
{
public string GetData(int value)
{
Console.WriteLine($"Get data with {value}");
return string.Format("You entered: {0}", value);
}
}
public class ServiceRunner
{
public static ServiceHost Host;
public static void Run(String[] args)
{
var serviceInstance = new Service1();
Uri baseAddress = new Uri("http://localhost:8080/hello");
Host = new ServiceHost(serviceInstance, baseAddress);
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
Host.Description.Behaviors.Add(smb);
Host.Open();
}
}
Result.
At last, please pay attention to the automatically generated client endpoint address.
I am getting an error while performing the database operation.
In my project when I try to access deleteAll() from Dao class ie.e,AuthenticationDaoof Room Database from my test cases I am getting below error
Refer to the below code:
#Dao
public interface AuthenticationDao {
#Insert
void insert(Authentication authentication);
#Query("delete from authentication")
void deleteAll();
#Query("select * from authentication")
Authentication getAuthInformation();
}
AppDatabase.java
#Database(entities = {Authentication.class}, version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
private static AppDatabase INSTANCE;
public static AppDatabase getAppDatabase(Context context) {
if (INSTANCE == null) {
INSTANCE =
Room.databaseBuilder(context,
AppDatabase.class,
"my-database")
.allowMainThreadQueries()
.build();
}
return INSTANCE;
}
public abstract AuthenticationDao authenticationDao();
}
What is the issue?
Is it because I am using AppDatabase dbInstance = Room.databaseBuilder(context,AppDatabase.class,"my-database")
.allowMainThreadQueries()
.build(); to initialize my database object?
If I use AppDatabase dbInstance = Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getContext(), AppDatabase.class).allowMainThreadQueries().build(); then it works fine.
What could be the reason?
I am new to web services and spring boot. I have written a service for which I am now writing a test case.
My application gets Soap request, parses the body and saves contents into database.
My test case tests this service.
When I run the application and send a request from Postman, it runs alright. But when I call my service method from test case, I get nullpointer for JaxBcontext.
I have declared Jaxbcontext in my AppConfig.java (which is annotated with #Configuration and my jaxb is a bean with #Bean annotation) in my service, I have #autowire to use jaxbcontext.
I have pasted code snippets for clarity. Please advise me what I am doing wrongly here.
My test case
public class ReferralExchangeEndpointTest {
ReferralExchangeEndpoint referralExchangeEndpoint = new ReferralExchangeEndpoint();
JAXBContext jbcTest;
Marshaller marshaller;
Unmarshaller unmarshaller;
public ReferralExchangeEndpointTest() throws JAXBException {
}
#Before
public void setUp() throws Exception {
jbcTest = JAXBContext.newInstance(
"our app schema"); // this is working fine, I have replaced schema with this text for posting it in stack.
ObjectFactory factory = new ObjectFactory();
marshaller = jbcTest.createMarshaller();
unmarshaller = jbcTest.createUnmarshaller();
}
#Test
public void send() throws Exception {
File payload = new File("payload.xml");
Object x = unmarshaller.unmarshal(payload);
JAXBElement jbe = (JAXBElement) x;
System.out.println(jbe.getName());
Object test = jbe.getValue();
SendRequestMessage sendRequestMessage = (SendRequestMessage) jbe.getValue();
// Method in test.
referralExchangeEndpoint.send(sendRequestMessage);
}
}
My service class
#Endpoint
public class ReferralExchangeEndpoint {
public static final Logger logger = LoggerFactory.getLogger(ReferralExchangeEndpoint.class);
#Autowired
private JAXBContext jaxbContext;
#Autowired
.
.
.
private Form parseBody(String payLoadBody) {
try {
Unmarshaller um = jaxbContext.createUnmarshaller();
return (Form) um.unmarshal(new StringReader(payLoadBody));
} catch (Exception e) {
throw new RuntimeException("Failed to extract the form from the payload body", e);
}
}
My appconfig file
#Configuration
public class AppConfig {
#Bean
public JAXBContext jaxbContext() throws JAXBException {
return
JAXBContext.newInstance("packagename");
}
#Bean public MessagingService messagingService() {
return new MessagingService();
}
}
Thanks.
Kavitha.
** Solved **
My test case now looks like this.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {AppConfig.class})`
public class ReferralExchangeEndpointTest {
#Autowired
ReferralExchangeEndpoint referralExchangeEndpoint;
#Autowired
private JAXBContext jaxbContext;
private Marshaller marshaller;
private Unmarshaller unmarshaller;
#Before
public void setUp() throws Exception {
marshaller = jaxbContext.createMarshaller();
unmarshaller = jaxbContext.createUnmarshaller();
}
#Test
public void send() throws Exception {
File payload = new File("src/test/resources/payload.xml");
JAXBElement jbe = (JAXBElement) unmarshaller.unmarshal(payload);
SendRequestMessage sendRequestMessage = (SendRequestMessage) jbe.getValue();
JAXBElement<SendResponseMessage> response = referralExchangeEndpoint.send(sendRequestMessage);
//TODO add remaining assertions on response after confirming what should the service return for these attributes.
assertEquals("SiteId wrong in response: ", "siteId", response.getValue().getSiteId());
}
}`