ejb remote client giving EJBCLIENT000025: No EJB receiver available for handling error - ejb-3.0

I am getting an error while running a remote client for EJB3 and wildfly.
My ejb looks something like bellow.
package com.tst.ejb;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
/**
* Session Bean implementation class TestWLDFly
*/
#Stateless
#LocalBean
public class TestWLDFly implements TestWLDFlyRemote {
/**
* Default constructor.
*/
public TestWLDFly() {
// TODO Auto-generated constructor stub
}
#Override
public void TestPrint() {
// TODO Auto-generated method stub
}
}
Remote interface is as follows
package com.tst.ejb;
import javax.ejb.Remote;
#Remote
public interface TestWLDFlyRemote {
public void TestPrint();
}
Remote client is as bellow...
package com.tst.ejb;
import java.util.Hashtable;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.jboss.ejb.client.ContextSelector;
import org.jboss.ejb.client.EJBClientConfiguration;
import org.jboss.ejb.client.EJBClientContext;
import org.jboss.ejb.client.PropertiesBasedEJBClientConfiguration;
import org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector;
public class EJBClient {
public static void main(String[] args) throws NamingException {
final Hashtable<String, Object> jndiProperties = new Hashtable<>();
Properties p = new Properties();
p.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
p.put("remote.connections", "one");
p.put("remote.connection.one.port", "8080");
p.put("remote.connection.one.host", "localhost");
EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(p);
ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc);
EJBClientContext.setSelector(selector);
Properties props = new Properties();
props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
InitialContext context = new InitialContext(props);
final String rcal = "ejb:/TSTWLDFLY/TestWLDFly!com.tst.ejb.TestWLDFlyRemote";
final TestWLDFlyRemote remote = (TestWLDFlyRemote) context.lookup(rcal);
remote.TestPrint();
}
}
Wildfly log shows JNDI names as bellow
java:global/TSTWLDFLY/TestWLDFly!com.tst.ejb.TestWLDFlyRemote
java:app/TSTWLDFLY/TestWLDFly!com.tst.ejb.TestWLDFlyRemote
java:module/TestWLDFly!com.tst.ejb.TestWLDFlyRemote
java:jboss/exported/TSTWLDFLY/TestWLDFly!com.tst.ejb.TestWLDFlyRemote
java:global/TSTWLDFLY/TestWLDFly!com.tst.ejb.TestWLDFly
java:app/TSTWLDFLY/TestWLDFly!com.tst.ejb.TestWLDFly
java:module/TestWLDFly!com.tst.ejb.TestWLDFly
I am getting an exception I run the client.
Nov 19, 2015 4:46:36 PM org.jboss.ejb.client.EJBClient <clinit>
INFO: JBoss EJB Client version 2.1.1.Final
Nov 19, 2015 4:46:36 PM org.xnio.Xnio <clinit>
INFO: XNIO version 3.3.1.Final
Nov 19, 2015 4:46:36 PM org.xnio.nio.NioXnio <clinit>
INFO: XNIO NIO Implementation Version 3.3.1.Final
Nov 19, 2015 4:46:36 PM org.jboss.remoting3.EndpointImpl <clinit>
INFO: JBoss Remoting version 4.0.9.Final
Nov 19, 2015 4:46:41 PM org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector setupEJBReceivers
WARN: Could not register a EJB receiver for connection to localhost:8080
java.lang.RuntimeException: Operation failed with status WAITING
at org.jboss.ejb.client.remoting.IoFutureHelper.get(IoFutureHelper.java:94)
at org.jboss.ejb.client.remoting.ConnectionPool.getConnection(ConnectionPool.java:80)
at org.jboss.ejb.client.remoting.RemotingConnectionManager.getConnection(RemotingConnectionManager.java:51)
at org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector.setupEJBReceivers(ConfigBasedEJBClientContextSelector.java:158)
at org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector.getCurrent(ConfigBasedEJBClientContextSelector.java:115)
at org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector.getCurrent(ConfigBasedEJBClientContextSelector.java:47)
at org.jboss.ejb.client.EJBClientContext.getCurrent(EJBClientContext.java:279)
at org.jboss.ejb.client.EJBClientContext.requireCurrent(EJBClientContext.java:289)
at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:178)
at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:146)
at com.sun.proxy.$Proxy0.TestPrint(Unknown Source)
at com.tst.ejb.EJBClient.main(EJBClient.java:40)
Exception in thread "main" java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling [appName:, moduleName:TSTWLDFLY, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext#5c5a1b69
at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:774)
at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:116)
at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:186)
at org.jboss.ejb.client.EJBInvocationHandler.sendRequestWithPossibleRetries(EJBInvocationHandler.java:255)
at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:200)
at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:183)
at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:146)
at com.sun.proxy.$Proxy0.TestPrint(Unknown Source)
at com.tst.ejb.EJBClient.main(EJBClient.java:40)
I tried all the JNDI names. May be I am doing something wrong. Any help is appreciated.

You should not use #LocalBean annotation. It makes impossible remote access to this EJB. Just remove it.

Related

Fabric8 failed to watch custom resource in the junit test

I am trying to learn how to test custom resource watcher in the Fabric8, I follow the example from this link https://github.com/r0haaaan/kubernetes-mockserver-demo/blob/master/src/test/java/io/fabric8/demo/kubernetes/mockserver/CustomResourceMockTest.java
My custom resource is "UserACL", I am using Java junit5, this is my fabric8 version.
implementation group: 'io.fabric8', name: 'kubernetes-client', version: '5.9.0'
implementation group: 'io.fabric8', name: 'kubernetes-api', version: '3.0.12'
testImplementation group: 'io.fabric8', name: 'kubernetes-server-mock', version: '5.9.0'
This test case failed, seem there is no any WatchEvent emitted, so countLatch never count down.
Could anybody help take a look and point out what's wrong here? Anything is missing in the following code. I appreciate it in advanced.
import io.fabric8.kubernetes.api.model.Condition;
import io.fabric8.kubernetes.api.model.KubernetesResourceList;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.fabric8.kubernetes.api.model.WatchEvent;
import io.fabric8.kubernetes.api.model.WatchEventBuilder;
import io.fabric8.kubernetes.client.CustomResource;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.Watch;
import io.fabric8.kubernetes.client.Watcher;
import io.fabric8.kubernetes.client.WatcherException;
import io.fabric8.kubernetes.client.dsl.MixedOperation;
import io.fabric8.kubernetes.client.dsl.Resource;
import io.fabric8.kubernetes.client.server.mock.KubernetesServer;
import io.fabric8.kubernetes.internal.KubernetesDeserializer;
import io.fabric8.kubernetes.model.annotation.Group;
import io.fabric8.kubernetes.model.annotation.Kind;
import io.fabric8.kubernetes.model.annotation.Version;
import io.vertx.junit5.VertxExtension;
import java.net.HttpURLConnection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.Rule;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
public class TestKafkaHelperUtilFourth {
#Rule
public KubernetesServer server = new KubernetesServer(true, true);
#Test
#DisplayName("Should watch all custom resources")
public void testWatch() throws InterruptedException {
// Given
server.expect().withPath("/apis/custom.example.com/v1/namespaces/default/useracls?watch=true")
.andUpgradeToWebSocket()
.open()
.waitFor(10L)
.andEmit(new WatchEvent(getUserACL("test-resource"), "ADDED"))
.waitFor(10L)
.andEmit(new WatchEventBuilder()
.withNewStatusObject()
.withMessage("410 - the event requested is outdated")
.withCode(HttpURLConnection.HTTP_GONE)
.endStatusObject()
.build()).done().always();
KubernetesClient client = server.getClient();
MixedOperation<
UserACL,
KubernetesResourceList<UserACL>,
Resource<UserACL>>
userAclClient = client.resources(UserACL.class);
// When
CountDownLatch eventRecieved = new CountDownLatch(1);
KubernetesDeserializer.registerCustomKind("custom.example.com/v1", "UserACL", UserACL.class);
Watch watch = userAclClient.inNamespace("default").watch(new Watcher<UserACL>() {
#Override
public void eventReceived(Action action, UserACL userAcl) {
if (action.name().contains("ADDED"))
eventRecieved.countDown();
}
#Override
public void onClose(WatcherException e) { }
});
// Then
eventRecieved.await(20, TimeUnit.SECONDS);
Assertions.assertEquals(0, eventRecieved.getCount());
watch.close();
}
private UserACL getUserACL(String resourceName) {
UserACLSpec spec = new UserACLSpec();
spec.setUserName("test-user-name");
UserACL createdUserACL = new UserACL();
createdUserACL.setMetadata(
new ObjectMetaBuilder().withName(resourceName).build());
createdUserACL.setSpec(spec);
Condition condition = new Condition();
condition.setMessage("Last reconciliation succeeded");
condition.setReason("Successful");
condition.setStatus("True");
condition.setType("Successful");
UserACLStatus status = new UserACLStatus();
status.setCondition(new Condition[]{condition});
createdUserACL.setStatus(status);
return createdUserACL;
}
#Group("custom.example.com")
#Version("v1")
#Kind("UserACL")
public static final class UserACL
extends CustomResource<UserACLSpec, UserACLStatus> {
}
public static final class UserACLSpec {
private String userName;
public UserACLSpec() {}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
public static final class UserACLStatus {
Condition[] condition;
public UserACLStatus() {};
public Condition[] getCondition() {
return condition;
}
public void setCondition(Condition[] condition) {
this.condition = condition;
}
}
}
I checked your code; after resolving these problems I was able to get test working:
You're setting MockServer expectations using server.expect() for mocking watch call. But you've initialized KubernetesMockServer to enable CRUD mode (this doesn't require any expectations). You need to do this instead (see false being passed as second argument which disables CRUD mode):
#Rule
public KubernetesServer server = new KubernetesServer(true, false);
In Watch expectations path I can see that UserACL resource is a namespaced one. All Namespaced scope resources in KubernetesClient must implement io.fabric8.kubernetes.api.model.Namespaced interface:
#Group("custom.example.com")
#Version("v1")
#Kind("UserACL")
public static final class UserACL extends CustomResource<UserACLSpec, UserACLStatus> implements Namespaced { }
(Optional) I'm not sure whether you're using JUnit4 or JUnit5, I also had to update org.junit.Test to org.junit.jupiter.api.Test and also add #EnableRuleMigrationSupport annotation in order to run this test on my JUnit5 project:
#EnableRuleMigrationSupport
public class TestKafkaHelperUtilFourth {
After making these changes, test seemed to run okay for me:
$ mvn -Dtest=io.fabric8.demo.kubernetes.mockserver.TestKafkaHelperUtilFourth test
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running io.fabric8.demo.kubernetes.mockserver.TestKafkaHelperUtilFourth
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
जुल॰ 08, 2022 10:29:31 अपराह्न okhttp3.mockwebserver.MockWebServer$2 execute
INFO: MockWebServer[49697] starting to accept connections
जुल॰ 08, 2022 10:29:31 अपराह्न okhttp3.mockwebserver.MockWebServer$3 processOneRequest
INFO: MockWebServer[49697] received request: GET /apis/custom.example.com/v1/namespaces/default/useracls?watch=true HTTP/1.1 and responded: HTTP/1.1 101 Switching Protocols
जुल॰ 08, 2022 10:29:31 अपराह्न okhttp3.mockwebserver.MockWebServer$2 acceptConnections
INFO: MockWebServer[49697] done accepting connections: Socket closed
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.779 s - in io.fabric8.demo.kubernetes.mockserver.TestKafkaHelperUtilFourth

Not able to perform query using vertx-db2-client with Spring Boot and getting error

I'm trying to connect and query to DB2 using vertx-db2-client, but it is not working. I'm using Spring Boot 2.6.6 and vertx-db2-client library to perform query in reactive way. I've created a class which implements CommandLineRunner
Dependency in my build.gradle
implementation 'io.vertx:vertx-db2-client:4.2.6'
implementation 'io.vertx:vertx-reactive-streams:4.2.6'
Below is my CommandLineRunner class.
import io.vertx.db2client.DB2ConnectOptions;
import io.vertx.db2client.DB2Pool;
import io.vertx.sqlclient.PoolOptions;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.RowSet;
import io.vertx.sqlclient.SqlClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;
#Configuration
#Slf4j
public class DB2DataLoader implements CommandLineRunner {
/**
* Callback used to run the bean.
*
* #param args incoming main method arguments
* #throws Exception on error
*/
#Override
public void run(String... args) throws Exception {
DB2ConnectOptions connectOptions =
new DB2ConnectOptions()
.setPort(50001)
.setHost("db_host_name")
.setDatabase("db_name")
.setUser("username")
.setPassword("password");
// Pool options
PoolOptions poolOptions = new PoolOptions().setMaxSize(5);
// Create the client pool
SqlClient client = DB2Pool.client(connectOptions, poolOptions);
// A simple query
client
.query("SELECT * FROM SCHEMA.TABLE")
.execute(
ar -> {
if (ar.succeeded()) {
RowSet<Row> result = ar.result();
System.out.println("Got " + result.size() + " rows ");
} else {
System.out.println("Failure: " + ar.cause().getMessage());
}
// Now close the pool
client.close();
});
}
}
I'm not seeing any connection issues. The error that I see right after the deployment is below:
2022-04-11 15:35:11.740 INFO 2736 --- [ main] c.h.t.p.ServiceApp : Started ServiceApp in 3.746 seconds (JVM running for 4.719)
Failure: SQLState.NET_VCM_VCS_LENGTHS_INVALID: VCM and VCS lengths are mutually exclusive but both were set: vcsLen=255 vcmLen=12336
I'm not sure what is this "Failure: **" means. Can anyone please help me understand this and how to fix. Database connection parameters are correct. I've just masked here. I was following this documentation for the example.

How to stop polling after a message is received? Spring Integration

I want to poll for a file in a directory and stop the polling once the file is found. I am very new to Spring framework and a lot of it still is very confusing. After doing some research, I found out a couple of ways of doing this but haven't any luck with any of them.
One of the ways is using a control bus as shown here. However, it just seems that the polling just stops after 2 seconds. I am not sure how to include the condition to stop only when a file is received.
Another way is to use "Smart Polling" as answered here. The link in the answer is old but it points to the official Spring docs here: Smart Polling. Through the article, I learned about AbstractMessageSourceAdvice and SimpleActiveIdleMessageSourceAdvice. The latter seems to suit my goal and would be the simplest to implement, so I decided to give that a go. My codes are as below:
IntegrationConfig.java
package com.example.springexample;
import java.io.File;
import org.aopalliance.aop.Advice;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.InboundChannelAdapter;
import org.springframework.integration.annotation.Poller;
import org.springframework.integration.aop.SimpleActiveIdleMessageSourceAdvice;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.file.FileReadingMessageSource;
import org.springframework.integration.file.filters.SimplePatternFileListFilter;
import org.springframework.integration.util.DynamicPeriodicTrigger;
import org.springframework.messaging.MessageChannel;
#Configuration
#EnableIntegration
public class IntegrationConfig {
#Bean
public IntegrationFlow advised() {
return IntegrationFlows.from("fileInputChannel")
.handle("runBatchScript", "run", c -> c.advice(stopPollingAdvice()))
.get();
}
#Bean
public MessageChannel fileInputChannel() {
return new DirectChannel();
}
#Bean
#InboundChannelAdapter(value = "fileInputChannel", poller = #Poller(fixedDelay = "1000"))
public MessageSource<File> fileReadingMessageSource() {
FileReadingMessageSource source = new FileReadingMessageSource();
source.setDirectory(new File("."));
source.setFilter(new SimplePatternFileListFilter("*.bat"));
return source;
}
#Bean
public RunBatchScript runBatchScript() {
return new RunBatchScript();
}
#Bean
public Advice stopPollingAdvice() {
DynamicPeriodicTrigger trigger = new DynamicPeriodicTrigger(10000);
SimpleActiveIdleMessageSourceAdvice advice = new SimpleActiveIdleMessageSourceAdvice(trigger);
advice.setActivePollPeriod(60000);
return advice;
}
}
RunBatchScript.java
package com.example.springexample;
import java.io.IOException;
import java.util.Date;
import java.util.logging.Logger;
public class RunBatchScript {
Logger logger = Logger.getLogger(RunBatchScript.class.getName());
public void run() throws IOException {
logger.info("Running the batch script at " + new Date());
Runtime.getRuntime().exec("cmd.exe /c simplebatchscript.bat");
logger.info("Finished running the batch script at " + new Date());
}
}
SpringExampleApplication.java
package com.example.springexample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class SpringExampleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringExampleApplication.class, args);
}
}
I used this and this as the base for my codes. However, it doesn't seem to be working as the poller still polls every 1 second instead of the new 10 seconds or 60 seconds. Moreover, I am not sure how to actually stop the poller. I tried putting null into the constructor for SimpleActiveIdleMessageSource but it just returns NullPointerException.
The output when I run the application:
2020-03-15 13:57:46.081 INFO 37504 --- [ask-scheduler-1] c.example.springexample.RunBatchScript : Running the batch script at Sun Mar 15 13:57:46 SRET 2020
2020-03-15 13:57:46.084 INFO 37504 --- [ask-scheduler-1] c.example.springexample.RunBatchScript : Finished running the batch script at Sun Mar 15 13:57:46 SRET 2020
2020-03-15 13:57:47.085 INFO 37504 --- [ask-scheduler-2] c.example.springexample.RunBatchScript : Running the batch script at Sun Mar 15 13:57:47 SRET 2020
2020-03-15 13:57:47.087 INFO 37504 --- [ask-scheduler-2] c.example.springexample.RunBatchScript : Finished running the batch script at Sun Mar 15 13:57:47 SRET 2020
2020-03-15 13:57:48.089 INFO 37504 --- [ask-scheduler-1] c.example.springexample.RunBatchScript : Running the batch script at Sun Mar 15 13:57:48 SRET 2020
2020-03-15 13:57:48.092 INFO 37504 --- [ask-scheduler-1] c.example.springexample.RunBatchScript : Finished running the batch script at Sun Mar 15 13:57:48 SRET 2020
2020-03-15 13:57:49.093 INFO 37504 --- [ask-scheduler-3] c.example.springexample.RunBatchScript : Running the batch script at Sun Mar 15 13:57:49 SRET 2020
2020-03-15 13:57:49.096 INFO 37504 --- [ask-scheduler-3] c.example.springexample.RunBatchScript : Finished running the batch script at Sun Mar 15 13:57:49 SRET 2020
Any help with some code is greatly appreciated.
You should apply SimpleActiveIdleMessageSourceAdvice to #InboundChannelAdapter. Also , the trigger of SimpleActiveIdleMessageSourceAdvice should be the same as the trigger that is used to poll the files:
#Bean
#EndpointId("fileInboundChannelAdapter")
#InboundChannelAdapter(value = "fileInputChannel", poller = #Poller("fileReadingMessageSourcePollerMetadata"))
public MessageSource<File> fileReadingMessageSource() {
FileReadingMessageSource source = new FileReadingMessageSource();
source.setDirectory(new File("."));
source.setFilter(new SimplePatternFileListFilter("*.bat"));
return source;
}
#Bean
public PollerMetadata fileReadingMessageSourcePollerMetadata() {
PollerMetadata meta = new PollerMetadata();
DynamicPeriodicTrigger trigger = new DynamicPeriodicTrigger(1000);
SimpleActiveIdleMessageSourceAdvice advice = new SimpleActiveIdleMessageSourceAdvice(trigger);
advice.setActivePollPeriod(60000);
meta.setTrigger(trigger);
meta.setAdviceChain(List.of(advice));
meta.setMaxMessagesPerPoll(1);
return meta;
}
Please note that SimpleActiveIdleMessageSourceAdvice just change the next time to poll files. You can set it to a very large number such as several thousand years later which can somehow achieve your intention which never poll the file again in your lifetime. But the scheduler thread that poll the file still active.
If you really want to shut down this scheduler thread too, you can send a shut down signal to the control bus.
First define a control bus :
#Bean
public IntegrationFlow controlBusFlow() {
return IntegrationFlows.from("controlBus")
.controlBus()
.get();
}
Then implements an AbstractMessageSourceAdvice that send a shutdown signal to the control bus after a file is polled :
#Service
public class StopPollingAdvice extends AbstractMessageSourceAdvice{
#Lazy
#Qualifier("controlBus")
#Autowired
private MessageChannel controlBusChannel;
#Override
public boolean beforeReceive(MessageSource<?> source) {
return super.beforeReceive(source);
}
#Override
public Message<?> afterReceive(Message<?> result, MessageSource<?> source) {
Message operation = MessageBuilder.withPayload("#fileInboundChannelAdapter.stop()").build();
controlBusChannel.send(operation);
return result;
}
}
and change the PollerMetadata that poll files to :
#Bean
public PollerMetadata fileReadingMessageSourcePollerMetadata(StopPollingAdvice stopPollingAdvice) {
PollerMetadata meta = new PollerMetadata();
meta.setTrigger(new PeriodicTrigger(1000));
meta.setAdviceChain(List.of(stopPollingAdvice));
meta.setMaxMessagesPerPoll(1);
return meta;
}

Spring Boot test Kafka

I'm using Spring Boot version 2.1.8.RELEASE, and I have this problem:
Have you a solution please ?
[Thread-2] ERROR o.a.k.t.TestUtils - Error deleting C:\Users\usr\AppData\Local\Temp\kafka-255644115154741962
java.nio.file.FileSystemException: C:\Users\usr\AppData\Local\Temp\kafka-255644115154741962\version-2\log.1:
The process cannot access the file because it is being used by another process.
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
at sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:269)
at sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:103)
at java.nio.file.Files.delete(Files.java:1126)
at org.apache.kafka.common.utils.Utils$2.visitFile(Utils.java:734)
at org.apache.kafka.common.utils.Utils$2.visitFile(Utils.java:723)
at java.nio.file.Files.walkFileTree(Files.java:2670)
at java.nio.file.Files.walkFileTree(Files.java:2742)
at org.apache.kafka.common.utils.Utils.delete(Utils.java:723)
at org.apache.kafka.test.TestUtils$1.run(TestUtils.java:184)
This is my test, i use a windows 10 like OS,
This is my test,
import org.I0Itec.zkclient.ZkClient;
import org.junit.Test;
import kafka.utils.ZKStringSerializer$;
import kafka.utils.ZkUtils;
import kafka.zk.EmbeddedZookeeper;
public class BaseTest {
private static final String ZKHOST = "127.0.0.1";
#Test
public void producerTest(){
// setup Zookeeper
EmbeddedZookeeper zkServer = new EmbeddedZookeeper();
String zkConnect = ZKHOST + ":" + zkServer.port();
ZkClient zkClient = new ZkClient(zkConnect, 30000, 30000, ZKStringSerializer$.MODULE$);
ZkUtils zkUtils = ZkUtils.apply(zkClient, false);
zkClient.close();
zkServer.shutdown();
}
}

Spring: register advice programmatically at runtime

Is it possible to register AOP advices programmatically, after the application has booted and the context has been initialized?
When I tried, the advices didn't work, supposedly because they need to wrap the bean BEFORE it gets available in the context.
Something like this (it doesn't work):
#Bean
private AspectJExpressionPointcutAdvisor createPointcutAdvisor(AWSXRayRecorder awsxRayRecorder, String name, String pointcut) {
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
advisor.setExpression("execution ...()");
advisor.setAdvice(new CustomAdvice("custom bean"));
return advisor;
}
Clarification: I need to read a list of advice from a config file, and register the pointcuts accordingly. I need the label for bookeeping purposes. The file contents are unknown at compile time.
label: execution(* com.my.ns.OtherClass(..))
label2: execution(* com.my.ns.Class(..))
The previous solution is too invasive as it not only creates advice on the fly but also handles advising beans. This replicates functionality of Spring's AbstractAdvisorAutoProxyCreator, specifically the getAdvicesAndAdvisorsForBean method, where Spring will locate and apply eligible Advisors to each bean. A better approach is to simply programmatically create Advisors and let Spring handle the rest of the plumbing of advising beans, creating proxies, and so forth.
A simple way of creating a Advisor is to create a Advisor bean using the #Bean annotation:
#Bean
public Advisor advisorBean() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* com.testit.MyAspectedService.*(..))");
return new DefaultPointcutAdvisor(pointcut, new MyMethodInterceptor());
}
Where the class MyMethodInterceptor implements the MethodInterceptor interface:
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.reflect.Method;
public class MyMethodInterceptor implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("in interceptor");
//get the method and arguments we are intercepting
Method method = invocation.getMethod();
Object[] arguments = invocation.getArguments();
//... do stuff before the method
//call the underlying method
return invocation.proceed();
}
}
What this does is to create a around advice Advisor bean named "advisorBean" for all methods calls to a Spring bean MyAspectedService declared as
#Service
public class MyAspectedService {
//various service methods
}
This approach focuses on only creating the necessary Advisors and interception implementation and delegates the weaving of the aspect to the Spring framework.
Maybe programmatic creation of #AspectJ Proxies according to the Spring AOP manual does what you want. Quoting from there because answers with external links only are frowned upon on SO:
// create a factory that can generate a proxy for the given target object
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
// add an aspect, the class must be an #AspectJ aspect
// you can call this as many times as you need with different aspects
factory.addAspect(SecurityManager.class);
// you can also add existing aspect instances, the type of the
// object supplied must be an #AspectJ aspect
factory.addAspect(usageTracker);
// now get the proxy object...
MyInterfaceType proxy = factory.getProxy();
Update:
So actually I played around a bit, not being a Spring user but rather an AspectJ expert. But anyway I found a way to dynamically register an advisor with a custom pointcut. The thing is, though, you need to know which beans you want to apply it to, and be careful to differentiate between beans which are already proxied and ones which are not.
Question: When in your application lifecycle and to which beans do you want to add the advisors? Have your other beans already been instantiated and wired (injected) into others? I am asking because it is quite easy to register advisors to beans you have direct references to, wrapping them into proxies or adding the advisors to existing proxies. But there is no obvious way to wrap a bean which has already been injected into other beans and not proxied yet. So how easy or difficult the solution is depends on your requirements.
P.S.: I am still wondering why your pointcuts are in a properties file instead of just in a Spring XML config file, which would be the standard way. That XML file is also loaded during application start-up. Where does the requirement to use another file come from? Both are basically editable (text) resource files.
Update 2: Tedious manual solution, adapted from another sample project
Okay, I have created a GitHub repo for you. Just build with Maven and run the class with the main(..) method. It looks like this:
package de.scrum_master.performancemonitor;
import org.aopalliance.aop.Advice;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class PerformanceApp {
public static DefaultPointcutAdvisor createAdvisor(String pointcutExpression, Advice advice) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(pointcutExpression);
return new DefaultPointcutAdvisor(pointcut, advice);
}
public static Object adviseIfNecessary(Object bean, DefaultPointcutAdvisor advisor) {
final String pointcutExpression = advisor.getPointcut().toString().replaceAll(".*\\(\\) ", "");
if (!advisor.getPointcut().getClassFilter().matches(bean.getClass())) {
System.out.println("Pointcut " + pointcutExpression + " does not match class " + bean.getClass());
return bean;
}
System.out.println("Pointcut " + pointcutExpression + " matches class " + bean.getClass() + ", advising");
Advised advisedBean = createProxy(bean);
advisedBean.addAdvisor(advisor);
return advisedBean;
}
public static Advised createProxy(Object bean) {
if (bean instanceof Advised) {
System.out.println("Bean " + bean + " is already an advised proxy, doing nothing");
return (Advised) bean;
}
System.out.println("Creating proxy for bean " + bean);
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(bean);
return (Advised) proxyFactory.getProxy();
}
public static void main(String[] args) {
DefaultPointcutAdvisor advisor = createAdvisor(
// Just load this from your YAML file as needed
"execution(public int de.scrum_master.performancemonitor.PersonService.getAge(..))",
new MyPerformanceMonitorInterceptor(true)
);
ApplicationContext context = new AnnotationConfigApplicationContext(AopConfiguration.class);
Person person = (Person) adviseIfNecessary(context.getBean("person"), advisor);
PersonService personService = (PersonService) adviseIfNecessary(context.getBean("personService"), advisor);
System.out.println();
System.out.println("Name: " + personService.getFullName(person));
System.out.println("Age: " + personService.getAge(person));
System.out.println();
// BTW, you can also unadvise a bean like this.
// Write your own utility method for it if you need it.
((Advised) personService).removeAdvisor(advisor);
System.out.println("Name: " + personService.getFullName(person));
System.out.println("Age: " + personService.getAge(person));
}
}
The console log looks like this:
Pointcut execution(public int de.scrum_master.performancemonitor.PersonService.getAge(..)) does not match class class de.scrum_master.performancemonitor.Person
Pointcut execution(public int de.scrum_master.performancemonitor.PersonService.getAge(..)) matches class class de.scrum_master.performancemonitor.PersonService$$EnhancerBySpringCGLIB$$965d1d14, advising
Bean de.scrum_master.performancemonitor.PersonService#2fd1433e is already an advised proxy, doing nothing
web - 2018-03-10 09:14:29,229 [main] TRACE d.s.performancemonitor.PersonService - StopWatch 'de.scrum_master.performancemonitor.PersonService.getFullName': running time (millis) = 2
Name: Albert Einstein
web - 2018-03-10 09:14:29,235 [main] INFO d.s.performancemonitor.PersonService - Method de.scrum_master.performancemonitor.PersonService.getAge execution started at: Sat Mar 10 09:14:29 ICT 2018
web - 2018-03-10 09:14:29,332 [main] INFO d.s.performancemonitor.PersonService - Method de.scrum_master.performancemonitor.PersonService.getAge execution lasted: 100 ms
web - 2018-03-10 09:14:29,332 [main] INFO d.s.performancemonitor.PersonService - Method de.scrum_master.performancemonitor.PersonService.getAge execution ended at: Sat Mar 10 09:14:29 ICT 2018
web - 2018-03-10 09:14:29,332 [main] WARN d.s.performancemonitor.PersonService - Method execution longer than 10 ms!
Age: 146
web - 2018-03-10 09:14:29,334 [main] TRACE d.s.performancemonitor.PersonService - StopWatch 'de.scrum_master.performancemonitor.PersonService.getFullName': running time (millis) = 0
Name: Albert Einstein
Age: 146
You can nicely see how log output from the advisor gets printed. After detaching the advisor again, the log output goes away and only the log output from the advisor defined in class AopConfiguration remains. I.e. you can mix Spring configuration with your own dynamically attached advisors.
BTW, if you comment out the #Bean annotation in AopConfiguration like this
//#Bean
public Advisor performanceMonitorAdvisor() {
then class PersonService will not be proxied already by the time you attach your dynamic advisor and the console output changes to:
Pointcut execution(public int de.scrum_master.performancemonitor.PersonService.getAge(..)) does not match class class de.scrum_master.performancemonitor.Person
Pointcut execution(public int de.scrum_master.performancemonitor.PersonService.getAge(..)) matches class class de.scrum_master.performancemonitor.PersonService, advising
Creating proxy for bean de.scrum_master.performancemonitor.PersonService#6a03bcb1
Name: Albert Einstein
web - 2018-03-10 09:43:04,633 [main] INFO d.s.performancemonitor.PersonService - Method de.scrum_master.performancemonitor.PersonService.getAge execution started at: Sat Mar 10 09:43:04 ICT 2018
web - 2018-03-10 09:43:04,764 [main] INFO d.s.performancemonitor.PersonService - Method de.scrum_master.performancemonitor.PersonService.getAge execution lasted: 136 ms
web - 2018-03-10 09:43:04,769 [main] INFO d.s.performancemonitor.PersonService - Method de.scrum_master.performancemonitor.PersonService.getAge execution ended at: Sat Mar 10 09:43:04 ICT 2018
web - 2018-03-10 09:43:04,769 [main] WARN d.s.performancemonitor.PersonService - Method execution longer than 10 ms!
Age: 146
Name: Albert Einstein
Age: 146
Please note that not only the log lines produces by the Spring-configured advisor go away as expected but that also the line
Bean de.scrum_master.performancemonitor.PersonService#2fd1433e is already an advised proxy, doing nothing
changes to
Creating proxy for bean de.scrum_master.performancemonitor.PersonService#6a03bcb1
Update 3: More elegant solution according to James W's answer
According to James W's answer, I have modified my solution in order to let Spring automatically create proxy, advisor and let it add the advisor, see commit #ff53e57. The credit for that goes completely to James! Like I said before, I am not a Spring user and was unaware of the handy base class MethodInterceptor which is key to this solution, like James suggested.
For reference, I kept my trick to unadvise the service manually on demand, just had to modify the code to get a reference to the advisor because now it is created by Spring. The updated main program looks like this:
public class PerformanceApp {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AopConfiguration.class);
Person person = (Person) context.getBean("person");
PersonService personService = (PersonService) context.getBean("personService");
System.out.println("Name: " + personService.getFullName(person));
System.out.println("Age: " + personService.getAge(person));
System.out.println();
System.out.println("Unadvising PersonService bean");
Arrays.stream(((Advised) personService).getAdvisors())
.filter(advisor -> advisor.getAdvice() instanceof MyPerformanceMonitorInterceptor)
.findFirst()
.ifPresent(((Advised) personService)::removeAdvisor);
System.out.println("Name: " + personService.getFullName(person));
System.out.println("Age: " + personService.getAge(person));
}
}
It produces this output:
web - 2021-01-11 10:18:09,277 [main] INFO d.s.p.MyPerformanceMonitorInterceptor - Method public java.lang.String de.scrum_master.performancemonitor.PersonService.getFullName(de.scrum_master.performancemonitor.Person) execution started at: Mon Jan 11 10:18:09 ICT 2021
web - 2021-01-11 10:18:09,293 [main] INFO d.s.p.MyPerformanceMonitorInterceptor - Method public java.lang.String de.scrum_master.performancemonitor.PersonService.getFullName(de.scrum_master.performancemonitor.Person) execution lasted: 18 ms
web - 2021-01-11 10:18:09,293 [main] INFO d.s.p.MyPerformanceMonitorInterceptor - Method public java.lang.String de.scrum_master.performancemonitor.PersonService.getFullName(de.scrum_master.performancemonitor.Person) execution ended at: Mon Jan 11 10:18:09 ICT 2021
web - 2021-01-11 10:18:09,293 [main] WARN d.s.p.MyPerformanceMonitorInterceptor - Method execution longer than 10 ms!
Name: Albert Einstein
Age: 149
Unadvising PersonService bean
Name: Albert Einstein
Age: 149
Define a abstract Aop Class,like this:
public abstract class ControllerAop {
public abstract void webaop();
#Around(value = "webaop()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
...
}
}
in your project,you can define a child class extends above aop class.
import com.chuxingyouhui.pdsc.knc.aop.ControllerAop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
#Aspect
#Component
#Order(2)
public class ApiControllerAop extends ControllerAop {
#Override
#Pointcut(value = "execution(* com.chuxingyouhui.white..*.controller..*.*(..))")
public void webaop() {
}
}
if you have more pointcut path,you define more child class .

Resources