Accessing singleton EJB from another webapp in TomEE - java

I have 2 webapps deployed on Apache TomEE+. In the first webapp I have created a singleton EJB class declared like this:
#Singleton
#Remote
#Startup
#Lock(READ)
public class SolverRegistryBean implements SolverRegistry
{
// ...
From openejb.log I can see, that the singleton is available:
2011-12-05 20:43:22,696 - INFO - Jndi(name=SolverRegistryBeanRemote) --> Ejb(deployment-id=SolverRegistryBean)
2011-12-05 20:43:22,696 - INFO - Jndi(name=global/localhost/SolverCore-1.0/SolverRegistryBean!grid.solver.SolverRegistry) --> Ejb(deployment-id=SolverRegistryBean)
2011-12-05 20:43:22,696 - INFO - Jndi(name=global/localhost/SolverCore-1.0/SolverRegistryBean) --> Ejb(deployment-id=SolverRegistryBean)
2011-12-05 20:43:22,750 - INFO - Started Ejb(deployment-id=SolverRegistryBean, ejb-name=SolverRegistryBean, container=My Singleton Container)
From my other app I want to access that singleton bean, so I do:
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.openejb.client.RemoteInitialContextFactory");
p.put("java.naming.provider.url", "http://127.0.0.1:8080/openejb/ejb");
try {
ctx = new InitialContext(p);
SolverRegistry reg = (SolverRegistry)ctx.lookup(
"openejb:global/global/localhost/SolverCore-1.0/SolverRegistryBean");
but then I get ClassCastException
java.lang.ClassCastException: $Proxy94 cannot be cast to grid.solver.SolverRegistry
I checked that this $Proxy94 class implements interfaces: grid.solver.SolverRegistry, org.apache.openejb.core.ivm.IntraVmProxy and org.apache.openejb.BeanContext$Removable.
Why this doesn't work?

I have resolved my problem by changing the lookup line to:
SolverRegistry reg = (SolverRegistry)ctx.lookup("SolverRegistryBeanRemote");
Still don't know what is openejb:global/global/localhost/SolverCore-1.0/SolverRegistryBean for.

Related

Storing Singleton Bean in JNDI with GlassFish 5

I have a working Glassfish 5 setup inside of Eclipse.
I have modules set up like this:
common
contains remote interface for singleton bean with #remote and #local annotation
included in all other modules as a pom dependency
core
contains a singleton bean that implements the interface in common
intended to contain service classes stored in JNDI that allow any number of clients to lookup and store data and/or access other service logic
builds a war file that deploys onto GlassFish
desktop
does an InitialContext lookup of the singleton bean. (I intend to abstract this into the Service Lookup design pattern).
intended to be a desktop client that remotely accesses beans stored on the server.
Right now, I'm just trying to get it to remotely access the service in core and print some text to the console proving it worked.
I think my problem stems from a misunderstanding of how to store a custom bean in JNDI in the first place. I looked on Google, but I mostly find articles and answers to questions telling me to add name and mappedName to the Singleton annotation or they only show how to add a predefined bean into JDNI such as a Boolean or String, and not something custom defined.
My bean is defined like this:
#Singleton(name = "BookService", mappedName = "ejb/BookService")
public class BookServiceImpl implements BookService {
private static final long serialVersionUID = 1L;
which results in this on the Glassfish server:
Core Server Screenshot
but nothing appears in JNDI:
JNDI Screenshot
The client does it's InitialContext lookup like this (I've tried multiple ways of writing the JNDI name):
BookService bookService = (BookService) initialContext.lookup("java:global/core/BookService");
using these configurations (I defined my domain with a base port of 8000, so every port is 8000 + something):
glashfishEnvironmentTable = new Hashtable<String, String>();
glashfishEnvironmentTable.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.enterprise.naming.impl.SerialInitContextFactory");
glashfishEnvironmentTable.put(Context.STATE_FACTORIES,
"com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
glashfishEnvironmentTable.put(Context.URL_PKG_PREFIXES, "com.sun.enterprise.naming");
//glashfishEnvironmentTable.put(Context.PROVIDER_URL, "ejbd://localhost:8080/");
// on a different host than the appserver
glashfishEnvironmentTable.put("org.omg.CORBA.ORBInitialHost", "localhost");
// optional. Defaults to 3700. Only needed if target orb port is not 3700.
glashfishEnvironmentTable.put("org.omg.CORBA.ORBInitialPort", "8037");
I get an error like this when I run it:
Exception in thread "main" javax.naming.CommunicationException: Communication exception for SerialContext[myEnv={org.omg.CORBA.ORBInitialPort=8037, java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, org.omg.CORBA.ORBInitialHost=localhost, java.naming.factory.url.pkgs=com.sun.enterprise.naming, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl} [Root exception is java.rmi.MarshalException: CORBA MARSHAL 1330446343 No; nested exception is:
org.omg.CORBA.MARSHAL: FINE: 00810007: Underflow in BufferManagerReadStream after last fragment in message vmcid: OMG minor code: 7 completed: No]
I think my InitialContext is configured properly because when I manually define the bean in JNDI like this (The ServiceFactory doesn't do anything, because I don't know how to properly extend ObjectFactory):
Bean defined in JNDI
I get this:
Exception in thread "main" java.lang.ClassCastException: javax.naming.Reference cannot be cast to common.service.BookService
Is there simple fix to this I am missing, or am I mixing oil and water trying to get an EJB Singleton into JNDI? Or am I missing something big like an EJBHome or a Servlet?
Do I need to extend the factory class to add my service classes into JDNI, or should ObjectFactory work? If I must extend the factory class, how would I go about it?
I hope I've defined the scope of the question well enough, but this is all new to me, so if anybody has experience implementing something like this, I appreciate any input that gets me closer to doing it right.
I figured it out. I did two things I shouldn't have.
I forgot to maven install my common module before building my war file... doh!
It seems that the #Remote and the #Local annotations cannot be in the same interface or it will fail (which is a shame, because I was trying to set it up so I didn't have to have two nearly identical interfaces).
Here are some more details in case someone else has a similar issue and needs to see something that works (I haven't done #Local here, because I haven't tried it yet. It should be trivial to add though):
For remote execution, you need an interface annotated with #Remote that extends Serializable (Serialization is required for Client/Server interface).
import java.io.Serializable;
public interface Remote extends Serializable{
}
import javax.ejb.Remote;
#Remote
public interface BookServiceRemote extends Remote {
public String readBook();
}
Your war file needs to contain the BookServiceImpl
import javax.ejb.Singleton;
import us.boggs.template.common.service.BookServiceRemote;
#Singleton(name = "BookService")
public class BookServiceImpl implements BookServiceRemote {
private static final long serialVersionUID = 1L;
#Override
public String readBook() {
return "Read the book.";
}
}
Your client pom.xml must include the common module and this:
<dependency>
<groupId>org.glassfish.main.appclient</groupId>
<artifactId>gf-client</artifactId>
<version>5.1.0</version>
</dependency>
Your client main method can use this by creating an InitialContext and doing a lookup(My base port was 8000, so my ORBInitialPort is 8000+37=8037):
private static Hashtable<String, String> glashfishEnvironmentTable;
static {
glashfishEnvironmentTable = new Hashtable<String, String>();
glashfishEnvironmentTable.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.enterprise.naming.impl.SerialInitContextFactory");
glashfishEnvironmentTable.put(Context.STATE_FACTORIES,
"com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
glashfishEnvironmentTable.put(Context.URL_PKG_PREFIXES, "com.sun.enterprise.naming");
glashfishEnvironmentTable.put("org.omg.CORBA.ORBInitialHost", "localhost");
// optional. Defaults to 3700. Only needed if target orb port is not 3700.
glashfishEnvironmentTable.put("org.omg.CORBA.ORBInitialPort", "8037");
}
InitialContext initialContext = new InitialContext(glashfishEnvironmentTable);
BookServiceRemote bookService = (BookServiceRemote) initialContext.lookup("java:global/core/BookService");
System.out.println(bookService.readBook());

How to disable debug logs in spring shell(cli)?

I use spring shell (not spring boot) in my app and want to disable debug logs.
After I run commands console print some debug logs. For example:
"DEBUG - DefaultListableBeanFactory - Returning cached instance of singleton bean 'myPromptProvider'"
"DEBUG - DefaultListableBeanFactory - Returning cached instance of singleton
bean 'defaultPromptProvider'"
Note that i run my app in windows cmd with java - jar *.jar
Here is my code:
#Component
public class Test implements CommandMarker {
//------------------------------------------------------ create
#CliCommand(value = {"test"})
public void test(
#CliOption(key = {"str"}, mandatory = true) final String str
) {
System.out.println(str);
}
}
and here is output:
spring-shell>test --str aaa
aaa
DEBUG - DefaultListableBeanFactory - Returning cached instance of singleton bean 'defaultPromptProvider'
DEBUG - DefaultListableBeanFactory - Returning cached instance of singleton bean 'myPromptProvider'
I want to eliminate those debug lines.

Stateful and Stateless EJBs - what exactly initiates the State? [duplicate]

I have a JAX-RS webservice with a resource for generating testdata. During tests I found out, that the injected EJB is not reinitialized and still contains data from the last request.
I have a jar file server.jar containing my business logic with EJBs. To show my problem I have created a stateless bean:
#Stateless
public class TestService
{
#EJB
SubsequentTestService state2Service;
private String value;
public void testIt()
{
System.out.println("####### VALUE: " + value);
value = "TestValue";
state2Service.testIt();
}
}
I am using the subsequent call to SubsequentTestService to show the odd behaviour also exists for call of another stateless EJB:
#Stateless
public class SubsequentTestService
{
private String value;
public void testIt()
{
System.out.println("####### VALUE2: " + value);
value = "TestValue2";
}
}
Changing the annotation form #EJB to #Inject does not change anything.
In my web.war I have simple JAX-RS beans. The one which is called to show the strange behaviour is defined as follows:
#Path("/test")
public class TestResource
{
#Inject
TestService testService;
#GET
#Path("/state")
public void testState()
{
testService.testIt();
}
}
The JAX-RS application configuration looks as follows:
#ApplicationPath("/api")
public class JaxRsConfiguration extends Application
{
}
The war file contains the beans.xml, but no other configuration file. Everything is packaged into an ear file and is deployed in wildfly 10.0.0.Final. If I call the webservice as GET request via http://localhost:8080/api/test/state I get the expected output:
INFO [stdout] (default task-7) ####### VALUE: null
INFO [stdout] (default task-7) ####### VALUE2: null
But on the second request I get following unexpected output:
INFO [stdout] (default task-8) ####### VALUE: TestValue
INFO [stdout] (default task-8) ####### VALUE2: TestValue2
What is my problem here? Might be anything misconfigured in the wildfly? But I have only changed the logging and the datasource definition.
You have the meaning of #Stateless backwards.
This does not mean like so:
Hey container, here's an arbitrary class, please make it a stateless bean.
This actually means like so:
Hey container, here's a stateless class, you can safely use it as a stateless bean.
You have a stateful class. You should mark it as a #Stateful bean. Otherwise, get rid of all the state (unmanaged instance variables) so you can safely use it as a #Stateless bean.
See also:
Why Stateless session beans?
JSF request scoped bean keeps recreating new Stateful session beans on every request?
When using #EJB, does each managed bean get its own #EJB instance?

Inject EJB into startup singleton bean

In my application, I have the following startup bean:
#Startup
#Singleton
#DependsOn("RecordAcumulator")
public class StartupBean {
private static final Logger logger = Logger.getLogger(StartupBean.class);
#Inject
RecordAcumulator recordAcumulator;
/**
* Initializes the EJB system on the post construct event
*/
#PostConstruct
public void init() {
The record accumulator is an EJB that accesses the database. The startup is intended to preload database tables into the cache.
#Stateless
public class RecordAcumulator {
When this launches, I get
Caused by: com.ibm.ws.exception.RuntimeWarning: CNTR0200E: The StartupBean singleton session bean in the EJB.jar module depends on the RecordAcumulator enterprise bean in the EJB.jar, but the target is not a singleton session bean.
I have tried many variations of this and I can't seem to get the thing to inject. My log file indicates that the RecordAcumulator EJB was bound prior to the startup bean being loaded, so I can't figure out why I can't inject the EJB into my startup.
If I remove the #DependsOn I get this:
Caused by: javax.ejb.NoSuchEJBException: An error occurred during initialization of singleton session bean bla#EJB.jar#StartupBean, resulting in the discarding of the singleton instance.; nested exception is: javax.ejb.EJBException: The #Inject java.lang.reflect.Field.recordAcumulator reference of type com.foo.bar.accum.RecordAcumulator for the StartupBean component in the EJB.jar module of the bla application cannot be resolved.
Any ideas how to pull this off?
EDIT----------
I found this link:
Controlling CDI Startup inside EJB 3.1
But the issue with that is i'm using WAS 8.5.5.0, That issue was supposed to be resolved in 8.5.0.2
From what I can see:
Remove the #DependsOn
Make your EJB #Singleton
There can be complexities with singleton EJBs, as all the traffic going through your application will go through that one instance. In your case that may not be an issue.

NameNotFoundException when calling a EJB in Weblogic 10.3

I have a EJB defined as this:
package com.foo;
#Stateless (mappedName="HelloWorld")
public class HelloWorldBean implements HelloWorld, HelloWorldLocal
....
When it's deployed to Weblogic (WL), it gets the name myBean. I'm not sure if this is important.
I try to call the bean with this code:
Hashtable ht = new Hashtable();
ht.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL, "t3://localhost:7001");
ic = new InitialContext(ht);
tp = (HelloWorld) ic.lookup("HelloWorld#com.foo.HelloWorldBean");
Anyone know why I get the following error?
javax.naming.NameNotFoundException: While trying to lookup 'HelloWorld#com.foo.HelloWorldBean' didn't find subcontext 'HelloWorld#com'.
Resolved '' [Root exception is javax.naming.NameNotFoundException: While trying
to lookup 'HelloWorld#com.foo.HelloWorldBean' didn't find
subcontext 'HelloWorld#com'. Resolved '']; remaining name 'HelloWorld#com/foo/HelloWorldBean'
To lookup a Remote Interface of a Session Bean with multiple Remote Business interfaces (e.g.com.acme.FooBusiness1, com.acme.FooBusiness2), you need to lookup a name derived from the combination of the target ejb's global JNDI name (the mappedName() in #Stateless) and the specific Remote Business Interface, separated by a "#":
InitialContext ic = new InitialContext();
FooBusiness1 bean1 = (FooBusiness1) ic.lookup("FooEJB#com.acme.FooBusiness1");
FooBusiness2 bean2 = (FooBusiness2) ic.lookup("FooEJB#com.acme.FooBusiness2");
In the typical case of a bean only having one Remote Business Interface, this fully-qualified form is not needed. In that case, the bean's JNDI name can be used directly :
FooBusiness bean = (FooBusiness) ic.lookup("FooEJB");
That was the theoretical part. Now the practice. In your case, from what I can see, you are accessing the EJB from Weblogic so I'd rather use the no-arg InitialContext() constructor (and use a jndi.properties configuration file for other environments) but this is just a side note. Then, you should look up com.foo.HelloWorld, the Remote Interface, not com.foo.HelloWorldBean, the implementation:
InitialContext ic = new InitialContext();
(HelloWorld) ic.lookup("HelloWorld#com.foo.HelloWorld");
And if your bean has only one Remote Business Interface, this should work:
(HelloWorld) ic.lookup("HelloWorld");

Categories

Resources