I've got some legacy code that runs in JBoss which looks something like:
#Stateless
#Remote(MyClass.class)
#RemoteBinding(jndiBinding = "app/Service")
public class myServiceBean {
// Some methods
}
When I look up the Bean in JNDI I have to use a string that looks like:
ear-name/Service/remote
I'm OK with the last two parts of the name, but I have an issue with "ear-file" being used as the context name. Because I build with Maven by default ear-file will contain the version number (which I do want for traceability), however it means I would have to change all the references to the service each time I issue a new version of the service!
How do I force the the context to something other than the name of the ear-file?
You can set up your ear name in application.xml like this:
<application-name>ear-name</application-name>
So you can have ear-namexxx.ear but your lookups will be made to ear-name
You can do the same for ejb modules as well:
<ejb-jar>
<module-name>ejb-name</module-name>
</ejb-jar>
Hope it helps!
Source https://developer.jboss.org/thread/158207
Related
I'm trying to run an application using a Datasource on JBOSS EAP 6.4
In the standalone.xml file my data source is well defined.
When I try a :
Context context = new InitialContext();
NamingEnumeration<NameClassPair> list = context.list("");
while (list.hasMore())
{
String name = list.next().getName();
System.out.println(name);
}
I only get TransactionManager while I'm expecting as well my data source named in the standalone.xml as jndi-name="java:jboss/datasources/OracleDS".
Why my datasource is not defined in the jndi environnement? Am I missing some configuration?
The Context.list(Name) does not include subcontexts. In other words you cannot iterate through all the registered names using context.list(""). If you want to list the data sources you'd need to use context.list("java:jboss/datasources).
The reason you only get the /TransactionManager is because it's the only one defined under the root namespace.
Although there already are quite some StackOverflow questions, blog entries, etc. on the web, I still cannot figure out a solution to the problem stated below.
Similar to this question (Injecting EJB within JAX-RS resource on JBoss7) I'd like to inject a EJB instance into a JAX-RS class. I tried with JBoss 5, JBoss 7, and WildFly 8. I either get no injection at all (field is null), or the server does not deploy (as soon as I try to combine all sorts of annotations).
Adding #Stateless to the JAX-RS makes the application server know both classes as beans. However, no injection takes place.
Is there a way to inject EJBs into a REST application? What kind of information (in addition to that contained in the question linked to above) could I provide to help?
EDIT: I created a Github project showing code that works (with Glassfish 4.0) and does not work (with JBoss 5).
https://github.com/C-Otto/beantest
Commit 4bf2f3d23f49d106a435f068ed9b30701bbedc9d works using Glassfish
4.0.
Commit 50d137674e55e1ceb512fe0029b9555ff7c2ec21 uses Jersey 1.8, which does not work.
Commit 86004b7fb6263d66bda7dd302f2d2a714ff3b939
uses Jersey 2.6, which also does not work.
EDIT2:
Running the Code which I tried on JBoss 5 on Glassfish 4.0 gives:
Exception while loading the app : CDI deployment failure:WELD-001408 Unsatisfied dependencies for type [Ref<ContainerRequest>] with qualifiers [#Default] at injection point [[BackedAnnotatedParameter] Parameter 1 of [BackedAnnotatedConstructor] #Inject org.glassfish.jersey.server.internal.routing.UriRoutingContext(Ref<ContainerRequest>, ProcessingProviders)]
org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [Ref<ContainerRequest>] with qualifiers [#Default] at injection point [[BackedAnnotatedParameter] Parameter 1 of [BackedAnnotatedConstructor] #Inject org.glassfish.jersey.server.internal.routing.UriRoutingContext(Ref<ContainerRequest>, ProcessingProviders)]
at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:403)
EDIT3: The crucial information might be that I'd like a solution that works on JBoss 5
If you don't want to make your JAX-RS resource an EJB too (#Stateless) and then use #EJB or #Resource to inject it, you can always go with JNDI lookup (I tend to write a "ServiceLocator" class that gets a service via its class.
A nice resource to read about the topic:
https://docs.jboss.org/author/display/AS71/Remote+EJB+invocations+via+JNDI+-+EJB+client+API+or+remote-naming+project
A sample code:
try {
// 1. Retreive the Home Interface using a JNDI Lookup
// Retrieve the initial context for JNDI. // No properties needed when local
Context context = new InitialContext();
// Retrieve the home interface using a JNDI lookup using
// the java:comp/env bean environment variable // specified in web.xml
helloHome = (HelloLocalHome) context.lookup("java:comp/env/ejb/HelloBean");
//2. Narrow the returned object to be an HelloHome object. // Since the client is local, cast it to the correct object type.
//3. Create the local Hello bean instance, return the reference
hello = (HelloLocal)helloHome.create();
} catch(NamingException e) {
} catch(CreateException e) {
}
This is not "injecting" per-se, but you don't use "new" as-well, and you let the application server give you an instance which is managed.
I hope this was useful and I'm not telling you something you already know!
EDIT:
This is an excellent example: https://docs.jboss.org/author/display/AS72/EJB+invocations+from+a+remote+client+using+JNDI
EDIT 2:
As you stated in your comment, you'd like to inject it via annotations.
If the JNDI lookup is currently working for you without problems, and
If you're using Java EE 6+ (which I'm guessing you are), you can do the following:
#EJB(lookup = "jndi-lookup-string-here")
private RemoteInterface bean;
I already have a integration-test phase, when I ran the selenium tests. I also want to run some unit tests in this phase, because the app is too much complex and have a lot of dependencies between his modules (a hell), so, after a week fighting against OpenEJB and Arquillian, I believe that this would be easier.
The thing is: how do I made it work?
I have the instance already running, if I instantiate an InitialContext and try to lookup some bean, I got an exception telling me that I have not set the java.naming.initial.factory, and I don't know what to put in there.
I'm also complaining about the annotated beans.
Suppose a Bean like this:
#Stateless
public class ABeanImpl implements ABean {
#EJB
private BBean;
}
Will the container automatically get right the BBean?
Thanks in advance
How to connect to JBoss 7.1 remote JNDI:
Here is the code snippet that I use for JBoss 7.1:
Properties props = new Properties();
String JBOSS_CONTEXT = "org.jboss.naming.remote.client.InitialContextFactory";
props.put("jboss.naming.client.ejb.context", true);
props.put(Context.INITIAL_CONTEXT_FACTORY, JBOSS_CONTEXT);
props.put(Context.PROVIDER_URL, "remote://localhost:4447");
props.put(Context.SECURITY_PRINCIPAL, "jboss");
props.put(Context.SECURITY_CREDENTIALS, "jboss123");
InitialContext ctx = new InitialContext(props);
Resolution of ambiguous ejb references:
According to JBoss EJB 3 reference, if at any level of your EJB environment (EJB/EAR/Server) are duplicates in used interfaces, exception will be thrown during resolution of injected beans.
Based on above, if you have got a reference to EJB bean which interface:
has two implementations in your EJB module (JAR/WAR) - exception will be thrown
has two implementations in your application (other EJB JAR's in same EAR) - exception will be thrown
has two implementations, one in module with bean ABeanImpl, second somewhere else - implemetation from current module is used.
I am new in the world of EJB 3.1 and trying to get some basics with the JBoss Application Server 7.1.
At the moment I am stuck at a - really basic - problem. When a bean on the server wants to use another bean I need to use the InitialContext.lookup() method. If I look in the literature I found calls like:
TheBean = (<Interface>) new InitialContext().lookup("<NameOfTheBean>/local");
But this call doesn’t work for me. Every time I get an error like this:
javax.ejb.EJBException: javax.naming.NameNotFoundException
After hours of looking for a solution I found code examples which use another call, something like this:
TheBean = (<Interface>) new InitialContext().lookup("ejb:/<Package>//<NameOfTheBean>!<Package>.<Interface>");
Well this solution works for me but the question is why? Does somebody know why the first call produces exceptions while the second one works fine?
Thanks a lot!
Why? Different versions of JBoss deploys beans with differently default names in JNDI namespace.
ctx.lookup("BeanName/local")
was right for the JBoss 4.x.x and higher but not for JBoss v7.
You can see in you server.log of JB7 how your beans mapped to JNDI names,
for example (see java:/jboss/exported/... and how it correspond to your second successive call):
13:57:05,550 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-4) JNDI bindings for session bean named ProductionHistoryBean in deployment unit deployment "navi-ejb3.jar" are as follows:
java:global/navi-ejb3/ProductionHistoryBean!navi.ejb3.production.history
.ProductionHistoryRemote
java:app/navi-ejb3/ProductionHistoryBean!navi.ejb3.production.history.Pr
oductionHistoryRemote
java:module/ProductionHistoryBean!navi.ejb3.production.history.Productio
nHistoryRemote
java:jboss/exported/navi-ejb3/ProductionHistoryBean!navi.ejb3.production
.history.ProductionHistoryRemote
java:global/navi-ejb3/ProductionHistoryBean
java:app/navi-ejb3/ProductionHistoryBean
java:module/ProductionHistoryBean
I am new to EJB3 and am missing something when it comes to accessing a #Remote #Stateless bean deployed as an ejb module inside an ear file. I want to access a remote bean in lima.ear from soup.ear.
Here is what I am doing now (somewhat abbreviated):
//deployed under lima.ear
#Remote
#Stateless
public interface LimaBean {
String sayName();
}
I want to put LimaBean in the Soup:
//deployed in soup.ear
#Stateless
public class Soup implements SoupLocal {
#EJB
private LimaBean limaBean;
public String taste() {
return limaBean.sayName();
}
}
When I start JBoss I get the following error:
java.lang.RuntimeException: could not resolve global JNDI name for #EJB for container Soup: reference class: com.example.LimaBean ejbLink: not used by any EJBs
I have had a hard time finding out what this ejbLink is about, if that is the right path to go down.
If I deploy LimaBean as a jar file in jboss then everything works great!
I ran accross an article that had a section called "2.5.3. References between beans in different jars and different ears"
(http://jonas.ow2.org/doc/howto/jboss2_4-to-jonas3_0/html/x111.html)
Example of jboss.xml file for SB_BrowseRegions:
<jboss>
<session>
<ejb-name>SB_BrowseRegions</ejb-name>
<ejb-ref>
<ejb-ref-name>ejb/Region</ejb-ref-name>
<jndi-name>protocol://serverName/directory/RegionHome</jndi-name>
</ejb-ref>
</session>
</jboss>
If I touch the soup.ear, after JBoss starts up then it deploys fine, so I am assuming I need to specify a dependency like the above article says.
But even after it deploys then I get an error when accessing the remote LimaBean:
Caused by: java.lang.IllegalArgumentException: Can not set com.soup.LimaBean field com.soup.Soup.limaBean to $Proxy147
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63)
at java.lang.reflect.Field.set(Field.java:657)
at org.jboss.injection.JndiFieldInjector.inject(JndiFieldInjector.java:115)
... 49 more
I have tried a few things but, if anyone can point me in the right direction about this I would appreciate it.
It looks like the JNDI properties need to be set as if it were a remote client outside of the app server because of the ear isolation we have setup.
properties.put(Context.PROVIDER_URL, url);
InitialContext ctx = new InitialContext(properties);
Just specify the URL for the InitialContext and that should do the trick.