JNDI in Stateless Bean not found in Wildfly 10 - java

I am using wildfly 10.
For some reason I've got error like this:
javax.naming.NameNotFoundException: ServiceAImpl-- service jboss.naming.context.java.global.ServiceAImpl: javax.naming.NameNotFoundException: ServiceAImpl -- service
The way that I access to jndi:
InitialContext initialContext = new InitialContext();
Context context = (Context) initialContext.lookup("java:global/");
IWorker worker = (IWorker) context.lookup("ServiceAImpl");
worker.createTimer(task);
rest of code:
public interface IWorker{
void createTimer(ExecutableTask aExecutableTask);
}
#Stateless
#Local(IServiceA.class)
public class IServiceAImpl
implements IServiceA {
#Override
public void createTimer(ExecutableTask aExecutableTask) {
System.out.println("I am doing some jobs");
}
}
#Local
public interface IServiceAextends IWorker{
}
How can I get access to this IWorker? How to get this JNDI?

Take a look here. You are going to find something similar to this in your Wildfly logs when it is starting.
java:global/<your-project>/bus-facade-fumo/WUFFacade!<your-project>.wuf.WUFFacadeRemote
java:app/bus-facade-<your-project>/WUFFacade!<your-project>.wuf.WUFFacadeRemote
java:module/WUFFacade!<your-project>.wuf.WUFFacadeRemote
java:jboss/exported/<your-project>/bus-facade-<your-project>/WUFFacade!<your-project>.wuf.WUFFacadeRemote
java:global/<your-project>/bus-facade-<your-project>/WUFFacade
java:app/bus-facade-<your-project>/WUFFacade
java:module/WUFFacade
So you can find the JNDIs you need in your console logs, just like the example above. In you case, you are almost there, but you have to complete this piece of code with the complete information:
Context context = (Context) initialContext.lookup("java:global/<HereYouNeedMoreInformation>");

Related

Why doesn't Websphere 9 detect Annotated mappedName value for EJBs?

Following is my Sample Code:
AddStatelessBean.java:
#Stateless(name = "AddStatelessBean", mappedName="ASBean")
#Remote(AddStatelessBean.class)
#LocalBean
public class AddStatelessBeanImpl implements AddStatelessBean {
public int add(int a, int b) {
return a + b;
}
}
My Calling Code:
CallAddBean.java:
public static AddStatelessBean getAsbByName() throws Exception {
Context initialContext = new InitialContext();
AddStatelessBean asbObj = (AddStatelessBean) initialContext.lookup("ASBean");
return asbObj;
}
But I get the following error:
javax.naming.NameNotFoundException: Context: VRDWIN7WAS9Node03Cell/nodes/VRDWIN7WAS9Node03/servers/server1, name: ASBean: First component in name ASBean not found. [Root exception is org.omg.CosNaming.NamingContextPackage.NotFound: IDL:omg.org/CosNaming/NamingContext/NotFound:1.0]
BUT, if I go to Websphere Admin Console -> Applications -> Websphere Enterprise Applications -> -> EJB JNDI Names and assign the same JNDI name there and try to lookup, it is working.
I don't want to do that extra step or configure any XMLs (ibm-ejb-jar-bnd.xml) for making that happen during App Deployment itself.
How do I make this binding from pure JAVA Code itself? My main motive is to make my code run Server independent.

JAVA Lookup Failed for bean name in SerialContext

The Scenario goes as follows :
i'm coding a java enterprise application
first i created entity classes from database table "Derby" then i made a helper classes in a java library project then i created a session bean in the enterprise application bean and created a bean facade remote in the java library project
here is the important code part of the session bean :
#Stateless(mappedName = "officefacade")
public class OfficeFacade implements OwnerFacadeRemote {
#PersistenceContext
private EntityManager em;
and then i coded a simple client to test the methods
client code :
public class Client {
private OwnerFacadeRemote request;
public static void main(String[] args) {
// TODO code application logic here
Client x = new Client();
}
public Object getEJBBean(String beanName)
{
try
{
InitialContext ctx = new InitialContext();
return ctx.lookup(beanName);
}
catch(Exception ex)
{
System.err.println("Error : " + ex.getMessage() + "\n\n\n");
}
return null;
}
private void insert()
{
request.createOwner(new OwnerDetails("1","M","444","M","afcdv"));
}
private void display()
{
List<OwnerDetails> xx = request.getAllOwner();
}
public Client()
{
request = (OwnerFacadeRemote) getEJBBean("officefacade");
insert();
display();
}
the problem is every time i run the client i get the error that Lookup failed for 'officefacade'
here is the complete error text
> Error : Lookup failed for 'officefacade' in SerialContext[myEnv{java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFac tory, java.naming.factory.url.pkgs=com.sun.enterprise.naming, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl}
how to make sure the mapped name is being available and how to fix it so the it can be found by the lookup even if it means hard coding the mapped name in the serial context "i don't know what this is but it seem as the problem is coming from it"
any help is much appreciated and thanks in advance for your efforts and i'm pretty sure everything is implemented correctly so it's a mapped name related problem
tools of development is netbeans 8.0.2 and glassfish 4.1
Try to replace #Stateless(mappedName = "officefacade") with #Stateless(name = "officefacade"), the lookup method of the InitialContext seems to work with the bean name
See the related JavaDoc section and the related method for more details
UPDATE
Just checked Oracle's documentation on this topic - according to the information available there you might need to actually lookup for "java:module/officefacade" instead of pure "officefacade", depending on the bean context.

Initialcontext in a standalone Java program

I'm using a JNDI for creating connection pool. It works great in a web application. I believe the InitialContext is provided by the tomcat server.
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
dataSource = (DataSource)envContext.lookup("jdbc/testdb");
But when I try to call the same utility from a standalone Java program, the initContext object is null. How can I explicitly provide all the necessary properties that Context object is expecting.
Error : 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
Here is an example adapted from the accepted answer but doing everything inline to avoid creating extra classes.
public static void main(String[] args) {
setupInitialContext();
//do something that looks up a datasource
}
private static void setupInitialContext() {
try {
NamingManager.setInitialContextFactoryBuilder(new InitialContextFactoryBuilder() {
#Override
public InitialContextFactory createInitialContextFactory(Hashtable<?, ?> environment) throws NamingException {
return new InitialContextFactory() {
#Override
public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
return new InitialContext(){
private Hashtable<String, DataSource> dataSources = new Hashtable<>();
#Override
public Object lookup(String name) throws NamingException {
if (dataSources.isEmpty()) { //init datasources
MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
ds.setURL("jdbc:mysql://localhost:3306/mydb");
ds.setUser("mydbuser");
ds.setPassword("mydbpass");
dataSources.put("jdbc/mydbname", ds);
//add more datasources to the list as necessary
}
if (dataSources.containsKey(name)) {
return dataSources.get(name);
}
throw new NamingException("Unable to find datasource: "+name);
}
};
}
};
}
});
}
catch (NamingException ne) {
ne.printStackTrace();
}
}
You could also create your own custom context.
LocalContext ctx = LocalContextFactory.createLocalContext();
ctx.addDataSource("jdbc/testdb", driverName, url, usr, pwd);
See Running Beans Locally that use Application Server Data Sources for more details.
UPDATE
You can use the class org.springframework.mock.jndi.SimpleNamingContextBuilder of Spring. e.g.:
Setup:
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
builder.bind("jdbc/Oracle", ods);
builder.activate();
Use:
DataSource ds = InitialContext.doLookup("jdbc/Oracle");
You can create your own Context by sub-classing javax.naming.InitialContext and implementing only a small subset of methods, typically the bind and the lookup methods.
Then you can create your data source and bind it to your initial context to a specific key. After this you are ready to go and query from any place your JNDI context in your stand-alone Java programme.
This is the code you can use to create your own context:
InitialContext initialContext = new InitialContext() {
private Map<String, Object> table = new HashMap<>();
public void bind(String key, Object value) {
table.put(key, value);
}
public Object lookup(String key) throws NamingException {
return table.get(key);
}
};
// Activate the initial context
NamingManager.setInitialContextFactoryBuilder(environment -> environment1 -> initialContext);
Then you can initialise your data source, whichever you choose:
InitialContext ic = new InitialContext();
BasicDataSource bds = new BasicDataSource();
bds.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
bds.setUrl(url);
bds.setUsername(username);
bds.setPassword(password);
ic.bind(jndiPath, bds);
And somewhere else in your code, you can use the existing data source by retrieving it from the JNDI context:
InitialContext ic2 = new InitialContext();
DataSource ds = (DataSource) ic2.lookup(jndiPath);
assertNotNull(ds);
Connection conn = ds.getConnection();
assertNotNull(conn);
conn.close();
There isn't a way to directly use the Tomcat Context Factory, see here for a little more documentation on the alternatives. But I recommend you try running a registry outside of Tomcat...
// select the registry context factory for creating a context
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
// specify where that factory is running.
env.put(Context.PROVIDER_URL, "rmi://server:1099");
// create an initial context that accesses the registry
Context ctx = new InitialContext(env);
You could change your code in Tomcat to also use this external RegistryContext and then both set(s) would be using the same JNDI provider. This question seems very similar.
Tomcat provides Context & DataSource implementations that work with the InitialContext class. When running Tomcat the Context.INITIAL_CONTEXT_FACTORY property is set to point to Tomcat's implementations. When not running Tomcat, you don't have this ability... you need to use a third-party-library like c3p0 for connection pooling.
You can create an initial context using blow code.
InitialContext ic = new InitialContext();
// Retrieve the Home interface using JNDI lookup
Object helloObject = ic.lookup("java:comp/env/ejb/HelloBean");
if you want create custom initial context, you can extends javax.naming.InitailContext class
You can configure a standalone app (or unit tests!) to use your server's INITIAL_CONTEXT_FACTORY without running the server.
This is how to do that for a Apache Tomcat initialization, but you should have enough information to adapt it for another server.
Starting configuration from the server
This example presumes you want to mimic something like this from your context.xml file:
<Resource name="jdbc/testdb" auth="Container"
type="javax.sql.DataSource"
driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
username="someuser" password="somepassword"
url="jdbc:sqlserver://localhost\SQLEXPRESS;databaseName=somedb;applicationName=someapp"/>
Create the resource to go into the Context
This example is database specific, but you can put things other than a DataSource in the Context. Here is one way you might be able to create a DataSource for this SQL Server example. (It requires the JDBC driver and tomcat-dbcp.jar in your classpath. This code is for an older version of the driver, new versions probably have SQLServerXADataSource and would not need tomcat-dbcp.jar.)
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(SQLServerDriver.class.getName());
dataSource.setUrl(url);
dataSource.setUsername(getUserName());
dataSource.setPassword(getPassword());
Initialize using Tomcat INITIAL_CONTEXT_FACTORY
See this old blog post.
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.naming.java.javaURLContextFactory");
System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");
InitialContext ctxt = new InitialContext();`
The reference to org.apache.naming.java.javaURLContextFactory means you should have catalina.jar in your classpath. You should be able to find variants for the INITIAL_CONTEXT_FACTORY and URL_PGK_PREFIXES values for other application servers.
Register the resource for future lookups
Then register your DataSource dataSource for future lookups, at java:/comp/env/jdbc/testdb. Unfortunately, you have to make sure all the intermediate subcontext levels are created before you can add the resource. (Exercise for the reader: You can create a method to figure out the subcontext names from the resourceName instead of hard-coding the list as this example does.)
// Create all the intermediate levels
for (String resource : new String[]{ "java:", "java:comp", "java:comp/env", "java:/comp/env/jdbc" })
{
try
{
ctxt.lookup(subContext);
}
catch (NameNotFoundException nnfe)
{
ctxt.createSubcontext(subContext);
}
}
// Finally, register the resource
ctxt.bind(resourceName, dataSource);
This completes the setup portion, mimicking what is normally done in the Tomcat application server context.xml.
Do the lookup
Then the rest of your application can create InitialContexts and do lookups as normal (in a single lookup call):
Context ic = new InitialContext();
DataSource ds = (DataSource)ic.lookup("java:/comp/env/jdbc/testdb");

How to look up an object of a class

There is an application ABC which dependency is on an ejb module 'XYZ' but both are deployed & running on different server machine.
ABC deployed on JBoss AS & IP address is 192.108.1.1
XYZ deployed on JBOss As & IP address is 192.108.1.2
in XYZ ejb module, there is a xyzService class which access db and populates the data into a bean class, please see below
#Stateless(mappedName = "ejb/xyzService")
#TransactionManagement(TransactionManagementType.BEAN)
public class XyzService extends XyzPersistenceService implements xyzRemote, xyzLocal {
public List<xyzBean> fetchDataFromDB (List<String> idList) throws Exception
{
List<xyzBean> detailList = null;
try {
// gets data from DB and populate into a bean class i.e. xyzBean
} catch (Exception e) {
new myExceptionClass("error", e);
}
return detailList;
}
}
//Bean class
public class xyzBean{
String Id;
String name;
// getter-setter here
}
Now i want,
1. lookup the object of service class of XYZ module
2. invoke the method
3. gets the list of bean class
Could you please guide me how to do that, while i am bit confused how to start doing this from my ABC application ?
This example is geared towards connecting to the XYZ bean, but you could easily use it with a little adjustment for the ABC bean. Anyway, here is how you can lookup your xyzService.
Explicitly
By #EJB annotation
By ejb-ref
Explicitly
// Lookup the EJB from JNDI
InitialContext ctx = new InitialContext();
xyzRemote remoteobj = (xyzRemote)ctx.lookup("ejb/xyzService");
By annotation
#EJB (mappedName="ejb/xyzService")
private xyzRemote remoteobj;
With annotation the container injects an instance of the remote EJB bean through DI.
By ejb-ref
In your client class, add the below code. This is only a
InitialContext ctx = new InitialContext();
xyzRemote remoteobj = (xyzRemote) ctx.lookup("java:comp/env/ejb/xyzService");
As for configuring your client's InitialContext, you'll need a jndi.properties file
### JBossNS properties
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=jnp://192.108.1.2:1099
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces

EJB Factory Class

I'm trying to create an EJB factory class, which works like this: You have a method which takes as argument a class of an EJB, then it checks whether the EJB has a remote interface (if not throw an exception) and if it does, it returns the concerning EJB.
The code below does exactly this. However the object it returns is of the type of the remote interface of the concerning bean and not of the bean itself. How can I change this? Is there a way to tell Java that the generic type T is of the same type as the class passed to the methods.
import java.util.Properties;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.naming.*;
public class EJBFactory
{
private InitialContext ctx;
public EJBFactory() throws NamingException {
ctx = new InitialContext();
}
public EJBFactory(String host, String port) throws NamingException {
Properties props = new Properties();
props.setProperty("org.omg.CORBA.ORBInitialHost", host);
props.setProperty("org.omg.CORBA.ORBInitialPort", port);
ctx = new InitialContext(props);
}
.
// To improve: The object returned should be of the type ejbClass
// instead of the remote interface, which it implements
public <T> T createEJB(Class ejbClass) throws NamingException
{
Class remoteInterface = null;
for(Class interface_: ejbClass.getInterfaces()) {
if(interface_.isAnnotationPresent(Remote.class))
remoteInterface = interface_;
}
if(remoteInterface == null)
throw new IllegalArgumentException(
"EJB Requires a remote interface");
// Get the stateless annotation, then get the jndiName
Stateless stateless =
(Stateless)ejbClass.getAnnotation(Stateless.class);
String jndiName = stateless.mappedName();
T ejbObj = (T) ctx.lookup(jndiName);
return ejbObj;
}
}
Example of a unit test which uses the Factory.
import junit.framework.TestCase;
public class SimpleEJBTest extends TestCase
{
TestRemote testBean;
#Override
protected void setUp() throws Exception {
super.setUp();
EJBFactory ejbFactory = new EJBFactory();
testBean = ejbFactory.createEJB(TestBean.class);
}
public void testSayHello() {
assertEquals("Hello", testBean.sayHello());
}
}
Note: The example works with Glassfish, I didn't test it with any other app server.
Clients of EJBs interact with them through the local/ remote interface that the EJBs implement. Client applications never have direct access to an actual session bean class instance. This is done to make instance pooling possible, where the container can reuse EJB instances to service different requests.
I'm not sure why you need to access the actual bean's object (since obviously I dont know your requirement). But if you still need to create an instance of that you can do it as follows using reflection Class.forName(className).newInstance(); Again the instance that you create like this is not an EJB. It is just a POJO thats all.
EDIT - after your comment regarding junit testing: When you access business methods from a JavaSE as follows, you are actually calling the methods in the EJB - just that you interact thru the interface. So if you want to test any business methods you can still do it from an object got thru a JNDI lookup in a Junit test.
//MyGreatBean implements MyGreat. MyGreat has #Remote, MyGreatBean has #Stateless
ref = jndiContext.lookup("MyGreatBean/remote");
MyGreat bean = (MyGreat) ref;
String retValue = bean.businessMethod();
assertEquals("Success", retValue);
From an earlier comment, I get a feeling you want to check what kind of annotations have been added to the actual EJB class - if you want to do that kind of checking without actually running the business methods, you can create an instance using Class.forName... like I mentioned above. When you create an instance like this you can only call methods that don't do any "Java EE" stuff. For example you can call a method in the EJB class that is as follows
public String someMethod(){
return "I am a POJO but I look like an EJB";
}
I do not think that you can get the EJB object. You can only get the interface. The createEJB should be called with the interface and it returns the interface.
try replacing
public <T> T createEJB(Class ejbClass) throws NamingException
with
public <T> T createEJB(Class<T> ejbClass) throws NamingException
Can you try this?
Create a interface. Make it have #Remote. Your ejb that is annotated with #Stateless should implement the above created interface. Now try to do the same thing that you are doing I think it should give you the desired result. Typing it down here without copying from an ide so excuse any errors. But you should get the drift I guess.
#Remote
public interface Example{
String some();
}
#stateless
public class ExampleBean implements Example{
}

Categories