I am trying to call the grpc service using stub (proto are present in the different jar file). But when I am trying to call that service I am getting caused by io.grpc.statusruntimeexception unimplemented method not found. The same is working fine in main class but not in test case.
DeviceGroupServiceImplBase deviceService = Mockito.mock(DeviceGroupServiceImplBase.class,
AdditionalAnswers.delegatesTo(new DeviceGroupServiceImplBase() {
}));
public void createInProcessServerAndChannel() throws IOException {
// Generate a unique in-process server name.
String serverName = InProcessServerBuilder.generateName();
// Create a server, add service, start, and register for automatic graceful
// shutdown.
grpcCleanup.register(
InProcessServerBuilder.forName(serverName).directExecutor().addService(deviceService).build().start());
// Create a client channel and register for automatic graceful shutdown.
ManagedChannel channel = grpcCleanup
.register(InProcessChannelBuilder.forName(serverName).directExecutor().build());
// Create a DeviceGroupServiceClient using the in-process channel;
groupStub = DeviceGroupServiceGrpc.newBlockingStub(channel);
}
// Test case code
When("user calls getDevice with valid deviceUUID {string}", (String deviceUUID) -> {
DeviceUuid request = DeviceUuid.newBuilder().setDeviceUuid(deviceUUID).build();
DeviceGroup groupData = groupStub.getDeviceGroupByDeviceUuid(request);
});
you need to implement getDeviceGroupByDeviceUuid, by default it returns unimplemented status. you can verify if it is calling ServerCall#asyncUnimplementedUnaryCall.
DeviceGroupServiceImplBase deviceService =
Mockito.mock(
DeviceGroupServiceImplBase.class,
AdditionalAnswers.delegatesTo(
new DeviceGroupServiceImplBase() {
#Override
public void getDeviceGroupByDeviceUuid(
DeviceUuid request, StreamObserver<DeviceGroup> responseObserver) {
// TODO: implement
}
}));
Related
I want to control the bukkit server through the spring web application.
For example, send a command to the console, receive his response, etc
I'm trying to figure out a way, but I can't find a good one.
How shall I do it?
Even if third-party plugins are imported through the database, I want to find a way to do basic bukkit control.
First, you need to decide how to send the request to the server. It seems to me that in your case, the easiest is run the built-in java web server (HttpServer) to receive commands, and then process them.
If you need synchronous actions, then you can always do callSyncMethod
To receive command output, simply create your own implementation of CommandSender with overridden sendMessage methods
For example, how do command execution endpoint
JavaPlugin plugin = /** get plugin **/;
HttpServer server = HttpServer.create(new InetSocketAddress("localhost", 8001), 0);
server.createContext("/executeCommand", exchange -> {
if (!exchange.getRequestMethod().equals("POST")) {
exchange.getResponseBody().write("Method not supported".getBytes(StandardCharsets.UTF_8));
return;
}
// In this example body is command
String body = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);
StringBuilder builder = new StringBuilder();
// You also need override many another methods to compile code,but just leave it empty
CommandSender sender = new CommandSender() {
#Override
public void sendMessage(#NotNull String message) {
builder.append(message);
}
#Override
public void sendMessage(#NotNull String... messages) {
for (String message : messages) {
builder.append(message + "\n");
}
}
#Override
public boolean isOp() {
return true;
}
#Override
public boolean hasPermission(#NotNull String name) {
return true;
}
#Override
public #NotNull String getName() {
return "WebServerExecutor";
}
};
// Waiting command execute finish
Bukkit.getScheduler().callSyncMethod(plugin, () -> Bukkit.dispatchCommand(sender, body)).get();
byte[] response = builder.toString().getBytes(StandardCharsets.UTF_8);
exchange.getResponseBody().write(response);
});
server.start()
The application has classes that uses quarkus-reactive-client to request external information.
Also this classes has a provider to map http errors to a custom exception.
In prod mode all works fine but in dev mode, for default, instead of returned my custom exception, the method returns a ArcUndeclaredThrowableException.
If the property quarkus.arc.dev-mode.monitoring-enabled is set to false, all works fine in dev mode.
I try to understand what does this property do and why it changes the behaviour in dev mode.
Thanks.
Rest client
#Path("/")
#RegisterRestClient
#ClientHeaderParam(name = "Connection", value = "close")
#RegisterProviders({
#RegisterProvider(value = OidcClientRequestReactiveFilter.class),
#RegisterProvider(value = SomeResponseExceptionMapper.class)})
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public interface SomeClient {
#GET
#Path("/some/url/{identifier}")
SomeDTO search(#PathParam("identifier") String identifier)
throws CustomException;
Method use rest client method
private SomeDTO search(String identifier) throws CustomException {
try {
return someClient.search(identifier);
} catch (CustomException e) {
....
}
return null;
}
Error console
(executor-thread-0) io.quarkus.arc.ArcUndeclaredThrowableException: Error invoking subclass method
Working in a Spring Boot context, I am testing a service that queries a db, then makes a remote call that updates the db, then requeries the db to get the updated data.
I am trying to use Wiremock or MockServer to mock the remote call, but can't figure out how to update the embedded database as part of the mock server response generation process.
For example, using MockServer, I tried creating a callback class that had an autowired JdbcTemplate instance, but in the context of the callback that JdbcTemplate variable is null.
public class ApprovalHappyPathCallback implements ExpectationResponseCallback {
JdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource(DataSource ds) {
jdbcTemplate = new JdbcTemplate(ds);
}
public static final HttpResponse httpResponse = response()
.withStatusCode(HttpStatusCode.ACCEPTED_202.code())
.withHeaders(
header("x-callback", "test_callback_header"),
header("Content-Length", "a_callback_response".getBytes(UTF_8).length),
header("Connection", "keep-alive")
)
.withBody("a_callback_response");
#Override
public HttpResponse handle(HttpRequest httpRequest) {
if (httpRequest.getMethod().equals("GET")) {
jdbcTemplate.execute("update communications set status = 'APPROVED_SCHEDULED' where id = 153511");
return httpResponse;
} else {
return notFoundResponse();
}
}
}
The call back executes, but the jdbcTemplate statement does not work.
The callback is referenced like this in the test:
mockServer.when(request().withMethod("GET"))
.withBody("Approved")
// );
.respond(
callback()
.withCallbackClass(ApprovalHappyPathCallback.class)
);
The service method that makes the remote call is essentially:
public CommunicationEntity approveCommunication(Long communicationId) {
String approvalToken = commRepo.approvalTokenById(communicationId);
if (approvalToken == null) {
approvalToken = UUID.randomUUID().toString();
communicationEntity.setApprovalToken(approvalToken);
commRepo.save(communicationEntity);
}
String approvalResponse = remoteCommunicationApprover.approveCommunication(communicationId, approvalToken);
CommunicationEntity communicationEntity = getCommunicationById(communicationId);
if (communicationEntity.getStatus() != CommunicationStatus.Approved_Scheduled) {
throw new BadRequestException(
"Approval request for communication " + communicationId + " and token " + approvalToken
+ " failed with remote response: " + approvalResponse,
ErrorCodes.COMMUNICATION_SVC_REMOTE_APPROVAL_REQUEST_FAILED);
}
return communicationEntity;
There were two issues causing problems: making sure the jdbcTemplate used in the callback method was configured with the correct DataSource, and making sure that the data in the embedded in memory DB was accessible from the MockServer response generation thread.
I solved the first problem by using a lambda or closure for the MockServer callback in which I use the JdbcTemplate instance created in the test class with the autowired DataSource (though solutions exist for the callback class approach as well).
The second problem was the result of the fact that the test method was within a transaction and so inserts to the DB made at the beginning of the test were not committed when the MockServer thread (note that the MockServer response generation happens in a different thread than the main thread where the test method is running) was executing the callback. Thus those inserts were not accessible to the callback.
The solution was to annotate the test method with #Transactional(propagation = Propagation.NOT_SUPPORTED)
See h2 database access to test data from separate threads
I have a CXF client configured in my Spring Boot app like so:
#Bean
public ConsumerSupportService consumerSupportService() {
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
jaxWsProxyFactoryBean.setServiceClass(ConsumerSupportService.class);
jaxWsProxyFactoryBean.setAddress("https://www.someservice.com/service?wsdl");
jaxWsProxyFactoryBean.setBindingId(SOAPBinding.SOAP12HTTP_BINDING);
WSAddressingFeature wsAddressingFeature = new WSAddressingFeature();
wsAddressingFeature.setAddressingRequired(true);
jaxWsProxyFactoryBean.getFeatures().add(wsAddressingFeature);
ConsumerSupportService service = (ConsumerSupportService) jaxWsProxyFactoryBean.create();
Client client = ClientProxy.getClient(service);
AddressingProperties addressingProperties = new AddressingProperties();
AttributedURIType to = new AttributedURIType();
to.setValue(applicationProperties.getWex().getServices().getConsumersupport().getTo());
addressingProperties.setTo(to);
AttributedURIType action = new AttributedURIType();
action.setValue("http://serviceaction/SearchConsumer");
addressingProperties.setAction(action);
client.getRequestContext().put("javax.xml.ws.addressing.context", addressingProperties);
setClientTimeout(client);
return service;
}
private void setClientTimeout(Client client) {
HTTPConduit conduit = (HTTPConduit) client.getConduit();
HTTPClientPolicy policy = new HTTPClientPolicy();
policy.setConnectionTimeout(applicationProperties.getWex().getServices().getClient().getConnectionTimeout());
policy.setReceiveTimeout(applicationProperties.getWex().getServices().getClient().getReceiveTimeout());
conduit.setClient(policy);
}
This same service bean is accessed by two different threads in the same application sequence. If I execute this particular sequence 10 times in a row, I will get a connection timeout from the service call at least 3 times. What I'm seeing is:
Caused by: java.io.IOException: Timed out waiting for response to operation {http://theservice.com}SearchConsumer.
at org.apache.cxf.endpoint.ClientImpl.waitResponse(ClientImpl.java:685) ~[cxf-core-3.2.0.jar:3.2.0]
at org.apache.cxf.endpoint.ClientImpl.processResult(ClientImpl.java:608) ~[cxf-core-3.2.0.jar:3.2.0]
If I change the sequence such that one of the threads does not call this service, then the error goes away. So, it seems like there's some sort of a race condition happening here. If I look at the logs in our proxy manager for this service, I can see that both of the service calls do return a response very quickly, but the second service call seems to get stuck somewhere in the code and never actually lets go of the connection until the timeout value is reached. I've been trying to track down the cause of this for quite a while, but have been unsuccessful.
I've read some mixed opinions as to whether or not CXF client proxies are thread-safe, but I was under the impression that they were. If this actually not the case, and I should be creating a new client proxy for each invocation, or use a pool of proxies?
Turns out that it is an issue with the proxy not being thread-safe. What I wound up doing was leveraging a solution kind of like one posted at the bottom of this post: Is this JAX-WS client call thread safe? - I created a pool for the proxies and I use that to access proxies from multiple threads in a thread-safe manner. This seems to work out pretty well.
public class JaxWSServiceProxyPool<T> extends GenericObjectPool<T> {
JaxWSServiceProxyPool(Supplier<T> factory, GenericObjectPoolConfig poolConfig) {
super(new BasePooledObjectFactory<T>() {
#Override
public T create() throws Exception {
return factory.get();
}
#Override
public PooledObject<T> wrap(T t) {
return new DefaultPooledObject<>(t);
}
}, poolConfig != null ? poolConfig : new GenericObjectPoolConfig());
}
}
I then created a simple "registry" class to keep references to various pools.
#Component
public class JaxWSServiceProxyPoolRegistry {
private static final Map<Class, JaxWSServiceProxyPool> registry = new HashMap<>();
public synchronized <T> void register(Class<T> serviceTypeClass, Supplier<T> factory, GenericObjectPoolConfig poolConfig) {
Assert.notNull(serviceTypeClass);
Assert.notNull(factory);
if (!registry.containsKey(serviceTypeClass)) {
registry.put(serviceTypeClass, new JaxWSServiceProxyPool<>(factory, poolConfig));
}
}
public <T> void register(Class<T> serviceTypeClass, Supplier<T> factory) {
register(serviceTypeClass, factory, null);
}
#SuppressWarnings("unchecked")
public <T> JaxWSServiceProxyPool<T> getServiceProxyPool(Class<T> serviceTypeClass) {
Assert.notNull(serviceTypeClass);
return registry.get(serviceTypeClass);
}
}
To use it, I did:
JaxWSServiceProxyPoolRegistry jaxWSServiceProxyPoolRegistry = new JaxWSServiceProxyPoolRegistry();
jaxWSServiceProxyPoolRegistry.register(ConsumerSupportService.class,
this::buildConsumerSupportServiceClient,
getConsumerSupportServicePoolConfig());
Where buildConsumerSupportServiceClient uses a JaxWsProxyFactoryBean to build up the client.
To retrieve an instance from the pool I inject my registry class and then do:
JaxWSServiceProxyPool<ConsumerSupportService> consumerSupportServiceJaxWSServiceProxyPool = jaxWSServiceProxyPoolRegistry.getServiceProxyPool(ConsumerSupportService.class);
And then borrow/return the object from/to the pool as necessary.
This seems to work well so far. I've executed some fairly heavy load tests against it and it's held up.
My First Question:
In my StateMachineConfiguration.class.
#Bean
public StateMachineListener<CompanyStatus, CompanyEvents> listener() {
return new StateMachineListenerAdapter<CompanyStatus, CompanyEvents>() {
#Override
public void transition(Transition<CompanyStatus, CompanyEvents> transition) {
if(transition.getTarget().getId() == CompanyStatus.COMPANY_CREATED) {
logger.info("公司创建,发送消息到用户服务和菜单服务");
// how to get stateContext in there?
StateContext stateContext;
Message message = new Message.Builder<String>().messageType(CompanyStatus.COMPANY_CREATED.toString()).build();
messageSender.sendToUaa(message);
messageSender.sendToRes(message);
}
}
};
}
In my service.
log.debug("Request to save Company : {}", companyDTO);
Company company = companyMapper.toCmpy(companyDTO);
company = companyRepository.save(company);
stateMachine.sendEvent(MessageBuilder
.withPayload(CompanyEvents.COMPANY_CREATE)
.setHeader("companyId", company.getId())
.build());
return companyMapper.toCmpyDTO(company);
How I can get message header[companyId] in listener?
My Second Question:
statechart
In StateMachineListener you could use its stateContext method which gives you access to StateContext. StateContext then have access to message headers via its getMessageHeaders.
Original listener interface didn't expose that much so we had to add new method which exposes context which were introduced to machine later than listener interface were created. This because we need not to break things and we generally like to be backward compatibility.