call Remote EJB from client JAVA - ejb

I have to implement two simples java projects ; the first is an EJB projectwho contains a simple service which implement a remote interface, and the second project is a java client which try to call this ejb project ,
so here is what I did until now :
Context context = new InitialContext(jndiProperties);
TestServiceRemote proxy = (TestServiceRemote) context
.lookup("java:global/testEJB/TestService!services.TestServiceRemote");
System.out.println(proxy.showHello());
and this my ejb service :
#Stateless
public class TestService implements TestServiceRemote {
public TestService() {
}
#Override
public String showHello() {
return "Hello";
}
}
finally this my Remote interface :
#Remote
public interface TestServiceRemote {
public String showHello();
}
I had deployed the EJB in WIldfly 9 , but when I launch the java client i get this error shown in console :
Exception in thread "main" javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:662)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:350)
at javax.naming.InitialContext.lookup(InitialContext.java:417)
at swing.testClient.main(testClient.java:22)
Can someone tell me what I had wrong in my code ?

The java: namespace is not available by default in Java. You can either package your main class as an application client JAR inside an EAR and run it using an application client container launcher, or you can configure the InitialContext to have access to the java: namespace as described in this blog post.

Related

Initialising OAuth WebClient Bean in Spring MVC

I have a WebApp JSP project deployed on Weblogic 12 as a WAR.
My gradle build includes mvc and webflux:
implementation 'org.springframework.boot:spring-boot-starter-web:2.3.2.RELEASE'
implementation ("org.springframework.boot:spring-boot-starter-security:2.3.2.RELEASE")
implementation ("org.springframework.boot:spring-boot-starter-oauth2-client:2.3.2.RELEASE")
implementation ("org.springframework.boot:spring-boot-starter-webflux:2.3.2.RELEASE")
I am trying to configure OAuth2 to use client_credentials flow from my client JSP application.
I need the #Controller class to use WebClient and propagate the access token to a Resource Server.
My Bean to create the WebClient is seen below.
#Bean
public ReactiveClientRegistrationRepository getRegistration() {
ClientRegistration registration = ClientRegistration
.withRegistrationId("ei-gateway")
.tokenUri("https://xxxxx.xxxxxxx.net/auth/oauth/v2/token")
.clientId("xxx-xxxx-43e9-a407-xxxxx")
.clientSecret("xxxxxx-3d21-4905-b6e5-xxxxxxxxxx")
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.build();
return new InMemoryReactiveClientRegistrationRepository(registration);
}
#Bean
public WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations, ServerOAuth2AuthorizedClientRepository authorizedClients) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients);
oauth.setDefaultOAuth2AuthorizedClient(true);
return WebClient.builder()
.filter(oauth)
.defaultHeader("accept", "application/json")
.defaultHeader("content-type", "application/json")
.defaultHeader("environment", environment)
.filter(logRequest())
.filter(logResponse())
.build();
}
However I get the following error during compile:
Could not autowire. There is more than one bean of 'ReactiveClientRegistrationRepository' type.
Beans:
clientRegistrationRepository   (ReactiveOAuth2ClientConfigurations.class)
getRegistration   (WebSecurityConfiguration.java)
However when I uncomment out the getRegistration Bean method and configure the oauth client registration via the web.xml, then when deploying the application I get this error:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}:org.springframework.beans.factory.NoSuchBeanDefinitionException:No qualifying bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
I see from the ReactiveOAuth2ClientAutoConfiguration source code that the Reactive OAuth2 Auto Configuration is not run when ReactiveOAuth2ClientAutoConfiguration.NonServletApplicationCondition is set.
#Configuration(proxyBeanMethods = false)
#AutoConfigureBefore(ReactiveSecurityAutoConfiguration.class)
#EnableConfigurationProperties(OAuth2ClientProperties.class)
#Conditional(ReactiveOAuth2ClientAutoConfiguration.NonServletApplicationCondition.class)
#ConditionalOnClass({ Flux.class, EnableWebFluxSecurity.class, ClientRegistration.class })
#Import({ ReactiveOAuth2ClientConfigurations.ReactiveClientRegistrationRepositoryConfiguration.class,
ReactiveOAuth2ClientConfigurations.ReactiveOAuth2ClientConfiguration.class })
public class ReactiveOAuth2ClientAutoConfiguration {
}
Can anyone suggest a course of action? Is is possible to manually configure the ReactiveOAuth2ClientConfiguration?
Thanks
Form what I understand ReactiveClientRegistrationRepository is not available since you are not using a reactive stack, and here's how you can set up WebClient to be used in a Servlet environment.
Setup application properties so Spring autowires ClientRegistrationRepository and OAuth2AuthorizedClientRepository for you.
spring.security.oauth2.client.provider.my-oauth-provider.token-uri=https://xxxxx.xxxxxxx.net/auth/oauth/v2/token
spring.security.oauth2.client.registration.ei-gateway.client-id=xxx-xxxx-43e9-a407-xxxxx
spring.security.oauth2.client.registration.ei-gateway.client-xxxxxx-3d21-4905-b6e5-xxxxxxxxxx
spring.security.oauth2.client.registration.ei-gateway.provider=my-oauth-provider
spring.security.oauth2.client.registration.ei-gateway.scope=read,write
spring.security.oauth2.client.registration.ei-gateway.authorization-grant-type=client_credentials
Setup configuration to indicate that your application needs to act as an oauth2 Client
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.oauth2Client();
}
}
Expose WebClient bean configured to use client credentials
#Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
#Bean
WebClient webClient(OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(
oAuth2AuthorizedClientManager);
// default registrationId - Only if you are not using the webClient to talk to different external APIs
oauth2Client.setDefaultClientRegistrationId("ei-gateway");
return WebClient.builder()
.apply(oauth2Client.oauth2Configuration())
.build();
}
Now you can use WebClient in your code to access external protected resources.
references:
https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2client
https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2Client-webclient-servlet
https://docs.spring.io/spring-security/site/docs/current/reference/html5/#defaulting-the-authorized-client
This set up worked for me when the application is not configured as a resource server, I had to use a different configuration when the application needs to use WebClient, but also configured to be a resource server.

Provider test integration with pact broker for Spring Boot junit5 + configuration in application properties

The pact-jvm-provider-spring states that for junit5 provider test, it is not required to use the spring library.
However, #PactBroker annotation depends on the system properties. Is there a way to get this working for application properties via the Spring Property Resolver. I tried to create something similar to SpringEnvironmentResolver.kt and used it in the context setup. But that did not work.
#Provider("api-provider-app")
#PactBroker
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ActiveProfiles("test")
public class PactVerificationTest {
#LocalServerPort
private int port;
#Autowired
private Environment environment;
#TestTemplate
#ExtendWith(PactVerificationInvocationContextProvider.class)
void testTemplate(Pact pact, Interaction interaction, HttpRequest request,
PactVerificationContext context) {
context.setTarget(new HttpTestTarget("localhost", port));
context.setValueResolver(new SpringResolver(environment));
context.verifyInteraction();
}
}
I get the following error
Invalid pact broker host specified ('${pactbroker.host:}'). Please provide a valid host or specify the system property 'pactbroker.host'.
Update
After some more searching found out that the setTarget was not working and that needs to be moved to #BeforeEach method.
#BeforeEach
void setContext(PactVerificationContext context) {
context.setValueResolver(new SpringResolver(environment));
context.setTarget(new HttpTestTarget("localhost", port));
}
The following snippet helped it work with #PactFolder annotation. But the #PactBroker with properties is still not working
There is a new module added to Pact-JVM that extends the JUnit5 support to allow values to be configured in the Spring Context. See https://github.com/DiUS/pact-jvm/tree/master/provider/pact-jvm-provider-junit5-spring. It will be released with the next version of Pact-JVM, which will be 4.0.7.

Unknown JNDI Lookup String

I am new to EJB concept. I have seen the following in different website :
Sample 1:
#Stateless
#EJB(name="audit", beanInterface=AnotherEJBLocal.class)
public class EmployeeBean implements EmployeeServiceLocal, EmployeeServiceRemote {
#PersistenceContext(unitName = "EmployeeService")
private EntityManager manager;
public void doAction(){
try {
Context ctx = new InitialContext();
AnotherEJBLocal audit = (AnotherEJBLocal) ctx.lookup("java:comp/env/audit");
audit.doAnother();
} catch (NamingException e) {
throw new EJBException(e);
}
}
}
Sample 2:
public static void main(String[] a) throws Exception {
EmployeeServiceRemote service = null;
service = (EmployeeServiceRemote) new InitialContext().lookup("EmployeeBean/remote");
service.doAction();
}
Sample 3:
obj = ctx.lookup(ejb/CBDWebAppEAR/CBDWebApp.jar/<EJB name>/<Remote Interface Class Name>);
CBDWebApp is the project name in which the bean resides.
My question is:
What is the need & MEANING of java:comp/env/audit
Why same type of string is not used in case of Sample 2. I guess as
it is a remote EJB not local.
Why is the meaning of the EJB look up string in the Sample 3.
The java:comp/env/audit string is looking up the EJB reference that was declared earlier by the #EJB(name="audit", beanInterface=AnotherEJBLocal.class). Names declared by #EJB (and #Resource and all other EE references) are implicitly declared in the java:comp/env context. With this reference, the deployer can retarget the "audit" reference to any EJB in the application that implements the AnotherEJBLocal interface, or if the deployer doesn't specify anything, the javadoc for the #EJB annotation requires it to target a single EJB within the same application that implements the interface.
This main method is (probably) declared by a standalone Java program. In that case, it (probably) is configured via system properties to connect the JNDI server of an application server, which will return the remote reference to the client. The name that is looked up is vendor-specific, and it was probably configured for the EJB during deployment.
This is very similar to #2, the only difference being the specific string being used. In this case, it is probably relying on an application server's "default" binding name if none was configured for the EJB during deployment using the pattern ejb/<app>/<module>/<bean>/<interface>.

EJB3.1 classpath issue

I have 2 POJOs, in which one of them is an EJB and the other is a helper class.
//EJB Bean class
#Singleton
#LocalBean
#Startup
public class EJBBean{
#PostConstruct
public void init(){
HelperClass helper = new HelperClass();
helper.init();
}
}
//Helper class
public class HelperClass{
private static Log LOG = LogFactory.getLog("HelperClass");
private static Long currentTime = new Date().getTime();
public void init(){
//Some statements that use Log and do other Initialization
}
}
When I deploy this EJB jar I am getting an error
java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
I have the commons-logging-1.1.1.jar in the classpath; also, I have configured it to use Log4J. As a standalone app that is without EJB meta-data it works fine. Am I missing some EJB config?
BTW I am pretty new to EJB. I am using GlassFish 3.1, Eclipse Helios as IDE and EJB3.1.
This could be because you put the commons-logging-1.1.1.jar into the wrong directory or because your server already provides server-wide library which consists of logging classes.
By the way - I remember a lot of strange 'NoClassDefFoundError' because of mixing commons-logging, log4j and slf4j (especially in mismatching versions).

How to expose an EJB as a web service that is not transactional?

I have an EJB (coded using Java EE 6 annotations) that is defined as follows:
#Stateless
#WebService
public class SecurityWebService {
public void registerUser(RegistrationRequest request) {
...
}
}
Note that this EJB is also exposed as a web service. However, I am running into an issue with the generated web service. The WSDL generated by my container (GlassFish) contains WS-Atomic Transaction policies because a stateless session bean by default is transactional (see details here). Unfortunately my .NET client is choking on the WSDL because it does not understand WS-AT policies.
So what I really want is a nice-clean web service that is not transactional, but the associated EJB should be transactional (it has to insert records in the database). How do I do this? The only approach I can think of is to create a "normal" web service that passes all its calls to an EJB like this - not elegant at all:
#WebService
public class SecurityWebService {
#Inject
private SecurityService securityService;
public void registerUser(RegistrationRequest request) {
securityService.registerUser(request);
}
}
#Stateless
public class SecurityService {
public void registerUser(RegistrationRequest request) {
...
}
}
Is there a better way?
Thanks.
Naresh
You can try annotating the method:
#TransactionAttribute(TransactionAttributeType.NEVER)
or
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
Dunno if the web service will pick that up or not, but it's worth a shot.
Edit for comment:
Did you try REQUIRES_NEW? They may well not propagate back out to the web service.
Otherwise, yea, you'll be stuck facading the transactional part with the non-transactional web service.

Resources