I have Tomcat 7.0.47 and I'm hosting a REST Easy JAXRS service. The service uses two external JARs, one that has a base repository interface and default implementation and one that creates a concrete repository derived from the base (i.e. these two JARs have a dependency).
The service works, i.e. I can send a request and get back data from the database.
Now what I'm trying to do is get the repository injected into the REST service, to do this I've changed the REST code to look like
#Path("/country")
public class CountryService {
#Inject
ICountriesRepository repository;
#GET
#Produces({"application/json", "application/xml"})
public List<Country> getCountries() throws NamingException, SQLException {
return repository.getCountries();
}
}
I've added a beans.xml file to the web application's WAR file (it's in the META-INF directory) and I've added beans.xml to both the JARS.
When I deploy the app I see the following message:
INFO: Adding scanned resource: com.mantiso.cricket.service.CountryService
but I don't see similar messages for the repository class in the JAR.
The JAR is deployed; the beans.xml file is in the JAR's META-INF directory; I've tried adding #ManagedBean to the repository class.
I'm sure I'm missing something simple, but lots of searching has turned up not a lot.
This is Tomcat 7.0.47; Weld 2.1.0; RESTEasy 3.0.5
What else should I try?
And the answer is: The beans.xml file for the web app must be in the WEB-INF directory. If it's in the META-INF directory then it's not parsed.
Although, this did appear to work OK when I tried injecting into a servlet
Related
I have two spring boot apps. The first is an API library that's pulled into the second (a web application) as a dependent jar.
The first, is an API library that houses functions to create "cases" in an IBM solution. It's a standalone type jar that has a service class that exposes methods like getCaseXMLForDocId(String docId) or createCaseForAgreementNumber(String agreementNumber)
The first library called CaseInvocationAPI has an application.properties file which has several properties. For example:
caseinvocation.query.fetchNonProcessedCaseXml=SELECT Id, CaptureSource, AgreementNumber, CaptureSourceID FROM CaseInvocation WHERE ProcessIndicator IN (0, 2)
The service class has a method which makes a query, grabbing that query string from a member variable that's populated with a property from the application.properties file:
#Value("${caseinvocation.query.fetchNonProcessedCaseXml}")
private String selectNonProcessedQueryString;
The second SpringBoot app is a webapplication that has REST controllers. These controllers expose endpoints that call the CaseInvocationAPI library, specifically the CaseInvocationService class.
The problem I am having is that when the SpringBoot WEBAPPLICATION starts up, the context configuration blows up with the following error:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'caseinvocation.query.fetchNonProcessedCaseXml' in string value "${caseinvocation.query.fetchNonProcessedCaseXml}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:219)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:193)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:813)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1039)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1019)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:349)
... 45 common frames omitted
It appears that when the WebApp starts up, when it's trying to build the classes from the dependent jar, those properties are not being found.
I didn't think I had to copy each and every property out of the dependent jar application.properties file into an application.properties file in the Webapp project.
Why isn't the WebApp project (CaseInvocationWebApp) picking up the application.properties file from the dependent jar file (CaseInvocationAPI)?
I checked the compiled jar file (CaseInvocationAPI) and the application.properties file is there in the jar.
Looks like the problem was related to the fact that both the child jar and the webapp have application.properties files. I wasn't aware that the parent WebApp application.properties sort of overwrites the others (ignoring all others really).
Special thanks to Paschoal for his response.
You can see details on the answer here:
Adding multiple application.properties files
There are 3 ways (that I can think of) you can approach this:
The dependency, API library, should not have an application.properties since it's a library and not an executable Spring boot application in itself. You only define the properties in your web application's application.properties, even for the API library.
But, here the assumption is that you have access to the API library jar.
You can redefine all the properties in web application's application.properties essentially overriding them.
Explicitly configure the Spring boot application to use both the application.properties files, each for different set of properties.
Caveat: The file names must be different, as config location is classpath for both.
#SpringBootApplication
public class WebApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplicationBuilder(WebApplication.class)
.properties("spring.config.location=classpath:api-application.properties,classpath:application.properties")
app.run(args);
}
}
We got Java EE 7 project with the following structure:
app.ear
META-INF
application.xml
lib
framework.jar
webapp.war
core.jar
Framework.jar is our framework that uses some kind of command pattern.
This is how it works. Each command has it's own ejb attached to it that does all the business logic. This command ejb extends CommandEJB class that have an execute method.
For example, this is an example of a command ejb:
public class cmdCreateBookEJB<T extends cmdCreateBook> extends CommandEJB<T> {
#Override
public void execute() {
//do something
}
}
And in our framework, we also have CommandExecutorEJB that sets the appropriate ejb for the command and execute it.
Example:
CmdCreateBook cmdCreateBook = new cmdCreateBook();
cmdCreateBook.setEjb(cmdCreateBookEJB.class.getSimpleName());
commandExecutorEJB.execute(cmdCreateBook);
The problem is our framework, specifically CommandExecutorEJB(that is packed in framework.jar inside lib folder) needs to know about ejb's from core.jar, so it can handle the command. What actually happens in the framework is that the the specific command ejb(cmdCreateBookEJB) in my example is cast to CommandEJB and then it's execute method is called.
The question is how to make the framework know about command ejbs.
I know that one option is to specify am env-entry in ejb-jar.xml with the core jar module name, and then use #Resource in commandExecutorEJB to find the entry, and then use the JNDI lookup to find the resource that would be cast to CommandBean.
But, I would like not to use ejb-jar.xml as we're using ejb 3.2 and ejb-jar.xml isn't necessary anymore.
EDIT:
To better explain here is how the jndi lookup string would look like for my example: java:app/core.jar/cmdCreateBookEJB
Because framework isn't and shouldn't be aware of the core.jar(The name core.jar name is just an example, someone could name it BookStoreCore.jar), I somehow need to pass module name(in my example core.jar), so that the framework know where to look for classes to find a specific command EJB, in my example cmdCreateBookEJB.
I know that I can use an env-var in ejb-jar.xml to pass module name to the framework. Here's an example:
<session>
<ejb-name>CommandExecutorEJB</ejb-name>
<ejb-class>com.mypackage.CommandExecutorEJB</ejb-class>
<session-type>Stateless</session-type>
<env-entry>
<env-entry-name>com.mypackage.CommandExecutorEJB/moduleName</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>core</env-entry-value>
</env-entry>
</session>
But, I would love to eliminate ejb-jar.xml from our project setup
You're using Java EE 7.
You can completely avoid class visibility problems by putting everything in your WAR file. core.jar and framework.jar can both be added to your WEB-INF/lib directory.
You can then directly inject EJBs where ever they're needed.
I am building a project for a class that I am taking, and it consists of 4 modules
-impl (business logic/dao access)
-ejb (encapsulates business logic and provides access to it via a remote interface)
-war (web tier)
-ear (contains the war and ejb modules)
One utility class that I have inside the impl is able to populate an H2 database. It does this by running an ingestor that reads in an processes an xml file that resides in a maven repository, using various dao classes/methods to ingest the data:
String fileName = "xml/proj-data.xml";
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
When I run the ingestor through a unit test, it runs fine, but when I have everything layered, I get the NoClassDefFoundException on xml/proj-data.xml
So the basic outline that I have is:
-the war has dependencies on the impl and ejb modules
-the ejb has dependency on the impl module
-the ear has dependency on the impl, ejb, and war
This is a maven project. When I deploy the EAR to the server, the start page for the war is displayed (as I expect).
-The html page has a button that when pressed, does a post to a servlet
-The servlet has an ejb injected into it that it calls (via its remote interface).
-The ejb method makes a call back to the populate method in the impl, and thats when the exception happens, and I get a webpage back showing the exception.
Do I need to declare that repository in the WAR pom file as well?
In typing the question, I think I know what the problem may be. The repository that the xml file resides in is declared in the root pom for the project(the impl parent), NOT the pom for the impl module. Since the impl is the module that gets packaged with the EAR, I may need to declare the repository in the impl pom file as well.
I am using Glassfish 4. And I have an EAR which has a WAR and a JAR (with the EJBs).
I want to call the EJBs from my WAR but am not really sure if I need to use Local or Remote interfaces.
Inside my JAR, my Bean looks like this :
#Stateless
public class Test implements TestLocal {
#Override
public void testing() {
}
}
And my local :
#Local
public interface TestLocal {
void testing();
}
Inside my WAR I have a web service and it looks like this :
#WebService(serviceName = "TestWS")
public class TestWS {
private #EJB TestLocal testBean;
#WebMethod(operationName = "test")
public String test() {
testBean.test();
}
}
Both of these are packaged into an EAR.
When I call my WebService method I get an AccessLocalException :
Warnung: javax.ejb.AccessLocalException: Client not authorized for
this invocation at
com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:1895)
at
com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:210)
Firstly :
Is this the correct way to call the EJB. Can a WAR inside an EAR use Local interfaces from an included JAR?
If so then does anyone know what I am doing wrong? Do I need to setup some kind of security configuration?
To look up a remote EJB, it must have a remote interface exposed. Include that remote interface into your war.
The GlassFish documentation has an entry for this error:
javax.ejb.AccessLocalException: Client Not Authorized Error
Description
Role-mapping information is available in Sun-specific XML (for example, sun-ejb-jar.xml), and authentication is okay, but the following error message is displayed:
[...INFO|sun-appserver-pe8.0|javax.enterprise.system.container.ejb|...|
javax.ejb.AccessLocalException: Client not authorized for this invocation.
at com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:...
at com.sun.ejb.containers.EJBObjectInvocationHandler.invoke(...)
Solution
Check whether the EJB module (.jar) or web module (.war) is packaged in an application (.ear) and does not have role-mapping information in application level, Sun-specific, sun-application.xml. For any application (.ear), security role-mapping information must be specified in sun-application.xml. It is acceptable to have both module-level XML and application-level XML.
#Remote is usefull if you deploy separately your jar which contain your EJBs on a different server, for example.
There, war and jar are in the same ear so you just have to use the Local annotation.
Tips : since EJB 3.1 interfaces are not required, you can use #LocalBean directly on your "Test" class and remove the TestLocal interface.
To call a ejb method into a class which is your war, you firstly have to create a link between war and jar. Being in the same ear is not enough.
If you use Maven, you can simply add the jar reference into your dependencies in the pom of your war.
The issue I am currently experiencing is that my entityManager fails to be injected during the execution of a web application deployed within an ear.
The ear is setup as follows:
/META-INF -application.xml (EJBJar +
WAR)
-MANIFEST.MF
-weblogic-application.xml (currently just the default one that eclipse
generates)
/APP-INF
-lib
-EJBClientJar (interfaces + pojos)
-other jars
-classes
EJBJar
/META-INF
-persistence.xml
/src
-Annotated classes
WAR
-Service classes
Classes are as follows:
DAO inside EJBJar
#Stateless(mappedName="AwesomeBean")
public class Awesome implements AwesomeRemote //AwesomeRemote in EJBClientJar
{
#PersistenceContext
EntityManager em;
}
public class AwesomeService //Inside WAR
{
AwesomeRemote = context.lookup (Awesome.path.to.AwesomeRemote) //Is found
}
The call stack is like this:
War -> EJBClientJar -> EJBJar
On the EJB jar the entity manager is null. Question being how do I ensure that the PersistenceContext gets injected? The JNDI lookup succeeds on the AwesomeRemote Interface. The Interface has no annotations on it.
It's probably due to the fact that you try to inject on POJO class, not on managed component. Could you try to mark it as #Stateless and public and check whether it works?
For simple testing you can also add #WebService annotation and invoke your bean with SoapUI for example.
You should read about "packaging" part of ejb specifications.
This structure should be sufficient and work:
/
/lib
EJBClientJar (interfaces + pojos)
/META-INF
persistence.xml
application.xml
EJBJar.jar
WAR.war
As some formatting was lost, I'm not sure about what wasn't right in yours.
If this still doesn't work, try removing the only tricky part from above: put all classes from EJBClientJar in root. You the just have the most simple EAR packaging possible, it just will work.
Also, if you don't use your session bean outside a web application, you could use #Local instead of #Remote .