0

As long as my EJB is deployed inside the war of the app using it everything works fine, I only have to @Inject it, no xml, and no local or remote interfaces. The webapp is a Vaadin 7.5.6 app using vaadin-cdi.

When deploying the ejb as a separate jar, the web-app calling it fails with "Forbidden". I've annotated it with

@SecurityDomain("other")
@RolesAllowed({ "guest" })

However, still "Forbidden". Probably some config is needed in the webapp as well. All examples I've found so far mentions jndi-lookup, ejb-jar.xml, web.xml, jboss-ejb.xml, ejb interfaces and whatnot. Is it even possible to have the ejb deployed separately and accessible, while avoiding all this extra config? I'd like to break up my app so that I don't have to deploy everything each time I make changes to the gui, but if I have to revert to "old school" ejb config I'm not sure there is a point.

Using Wildfly 9.0.2, Java 8 and Maven.

Edit:

EJB : The Hello World EJB lives in a maven sub-project, it has jar-packaging. It has no xml-configuration and no local or remote interface. There is no usage of maven-ejb-plugin. The implementation looks like this:

import javax.ejb.Stateless;

@Stateless
public class ReceptionService {
    public String welcome() {
        return "Hello, Developer! No XML, No Configuration, and it works!";
    }
}

There is also a number of real-world session beans that use JPA inside methods that look like this (below) so there might be some persistence and transaction issues popping up as well here, but not until the simple hello-world case is working. The hello-world-webapp does not include any of these EJBs, just the simple hello-world-EJB.

@Stateless
@TransactionManagement(value = TransactionManagementType.CONTAINER)
public class DealerSession {

    private Logger logger = LoggerFactory.getLogger(DealerSession.class);

    @PersistenceContext(unitName = "MyUnit")
    protected EntityManager em;

    @TransactionAttribute(REQUIRED)
    public Long create(DealerUpdate update) {
        notNull(update, "update"); // and so on ....

The persistence unit is defined in the EJB project, and it connects to an datasource in Wildfly. In the real-world-beans transactions are rolled back on failure.

WAR : This is a Vaadin 7 webapp. It simply looks like this:

@CDIUI("")
@Theme("valo")
public class WelcomePage extends UI {

    @Inject
    ReceptionService service;

    @Override
    protected void init(VaadinRequest request) {
        setSizeFull();
        String message = service.welcome();
        Label label = new Label("this is the message: " + message);
        setContent(new HorizontalLayout(label));
    } ....

The EJB jar-file is referenced in the dependencies. So it is included, and everything works as if the EJB bean was just a .class-file in the war. This is very convenient, because there is almost no configuration involved. But as the real-world-project here grows, I'd like to split up the deployment, so that I do not have to deploy all EJBs as part of the war each time the gui is updated, because it slows down the development cycle.

The war project depends on vaadin-cdi 1.0.3 and vaadin-bom 7.5.6, and of course the jar with the EJB (which has jar and not ejb packaging). Also vaadin-maven-plugin, maven-resource-plugin and maven-war-plugin is used.

Both projects also use wildly-plugin 1.0.2.Final. and depend on java javaee-api 7.0.

NOW, my naïve attempt so far has been to change packaging of the EJB jar to "ejb", add maven-ejb-plugin, specify scope provided in the dependency in the pom file of the war-project, and deploy war and jar separately. So far there are no error-messages or warning, both are deployed. But access to the ejb is "Forbidden", there is an error message in the gui saying that, strangely not in the wildfly console. I've tried to add @SecurityDomain and @RolesAllowed annotations to the EJB (see above), but stuff has to be configured on the webapp as well. If it is so that CDI only will inject the EJB as a pojo anyway, or I have to add Local and/or Remote interfaces, perform JNDI-lookups, add lots of stuff to xml configuration files and so on, I can manage that, because there are sample apps and documentation for that, but also everything gets a lot more complicated, and I want to avoid that.

jon martin solaas
  • 459
  • 1
  • 4
  • 14
  • Please post more information! The bean implementation, setup (jar, war, ...). Which injection framework are you using, CDI, Guice, ...? But if it is really an EJB and not just a pojo bean you will need to lookup the bean over application boundaries. Otherwise CDI would only inject a pojo and not an EJB instance. – shillner Oct 07 '15 at 06:26
  • I just deleted a more elaborate and specific version of the question because no-one answered and thought maybe it was better to ask for a generic minimum hello-world-howto. I'll add more details during lunch break (real soon :) I was kind of hoping that moving the jar with the ejb out of the war-file would just be a packaging technicality, but if it has other consequences I might re-consider. – jon martin solaas Oct 07 '15 at 08:58

2 Answers2

1

First of all your EJBs are not not injected as such, even if they are deployed with your WAR. This is because you don't declare interfaces. In this case you will at least have to annotate them with @LocalBean which declares the no-interface-view for the bean.

When you outsource the EJBs into a jar, CDI is not able to inject the bean isntances that would be produced by EJB (the proxies) but injects pojo instances instead. To avoid this you could create a producer field or method for each EJB in your WAR. Injecting the bean with CDI then calls the producer. This producer would have to do a specific JNDI lookup (java:global/...) to get the EJB bean instance.

Then, when deploying to wildfly, you will have to add a dependency from the WAR to the JAR since both deployments have separate class loaders and can't see each other. The dependency connects both class loaders so that the one of the WAR is able to load classes of the JAR.

You will only have to activate CDI for the WAR not the JAR in this case since the EJB instances are retrieved by explicit JNDI lookups.

shillner
  • 1,806
  • 15
  • 24
  • Thanks, this clarifies a lot and I don't have to waste time trying to get the "simple" solution to work. – jon martin solaas Oct 07 '15 at 10:26
  • Thanks, this clarifies a lot and I don't have to waste time trying to get the "simple" solution to work. As a side-question: Using an app server isn't exactly very modern. If you - or I - absolutely want to use one, it should be embedded in the app, or one should just create a standalone app, using spring boot or similar. But ut would be monolithic, the entire stack would still have to be re-assebled and restarted to reflect only minimum changes in one component/layer. I could create one spring-boot-gut-rest-client-app and one rest-server-app, to achieve what I want, or use JRebel ... but ... – jon martin solaas Oct 07 '15 at 10:31
  • This depends on your requirements. I don't think that using an application server is an outdated approach. As you already noticed, the microservices approach is limited and fits well for small applications that don't have too much dependencies to other apps. But enterprise applications are still mostly running on standalone enterprise application servers (Websphere, Wildfly, ... or even Karaf, ...). You surely can extend such a microservice container with enterprise features but it's all about requirements and your decision depends on your plannings for the future. – shillner Oct 07 '15 at 11:06
  • For my requirements appserver makes sense because there is no operations-department that restricts my access or dictates anything, and my deployment artifacts doesn't have to be thick. JPA-implementation and other stuff is provided. Hence the code-deploy-cycle is pretty quick (especially if Wildfly run in eclipse), and breaking up the app into smaller pieces would make it even quicker. I don't see how I could achieve the same with for instance a monolithic spring-boot-app. It makes sense if you can't have many app server instances and still need the jvm exclusive for the app, though ... – jon martin solaas Oct 07 '15 at 13:58
  • Adding a dependency from war to jar using maven-war-plugin to add the entry to Manifest just gives me "org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type ReceptionService with qualifiers *Default at injection point [BackedAnnotatedField] *Inject WelcomePage.service" The manifest entry is just deployment.nameofmyfile.jar which is deployed and visible in the wildly console. – jon martin solaas Oct 07 '15 at 22:50
  • LocalBean javadoc says "This annotation is optional if a session bean exposes only a no-interface view. " so I think it wouldn't make a difference here. – jon martin solaas Oct 07 '15 at 22:58
  • Yes sure, you are right, the LocalBean annotation is optional but I always prefer to be explicit and don't rely on implicit asumptions. F.i. what if you add an interface in future? And what if the interface gets a Local annotation? Here is a good overview: http://stackoverflow.com/questions/10889563/ejb-3-1-localbean-vs-no-annotation Your problem: have you created a CDI producer which does the EJB lookup for your WAR? Please post this producer. – shillner Oct 08 '15 at 05:08
  • I will give producers a try, but as it seems I cannot avoid using JNDI, hidden behind CDI or not, I might just look up the EJBs directly instead of injecting them. I want to keep it simple, but I'm not really sure what is simplest. Injecting is very convenient, but adds an extra layer on top of JNDI. – jon martin solaas Oct 09 '15 at 06:43
  • Sure, if you want to inject EJB instances using CDI between different applications then you will have to create producers that lookup the EJBs, otherwise you will only get "CDI beans" without the EJB stuff. You can also omit the whole CDI stuff and go with EJB and lookups only, but you can also think over banning EJBs from your apps and just use CDI, JTA, ... I think most of the features are also available without EJBs (transactions, stateless and stateful behavior (via CDI scopes), interceptors, ...). It's a design decision and may be really tricky with heavy impact for the future! – shillner Oct 09 '15 at 07:48
  • For the service layer the goal is to have it separately deployable. Adding dependencies via manifest.mf or boss-deployment-structure didn't work with cdi, so if I have to use jndi just because the service jar is separately deployed, so be it. It's all running in the same jvm, so it'd really be nice to avoid jndi for convenience. – jon martin solaas Oct 14 '15 at 13:33
1

The answer I have approved for my question might be the right one if you absolutely need to use cdi-injection. I never came as far as I got it working, though.

Instead I decided to try use the @EJB annotation, instead of @Inject. When I deploy my ejb (in a separate jar from my web-app, that lives in a war-file) Wildfly registers jndi-names and reports this in the console. One of the names is "java:global/template-service-1.0.0-SNAPSHOT/ReceptionService". Note the "global" scope.

The @EJB annotation has a parameter called mappedName. Injecting and using the ejb like this did the trick:

@EJB(mappedName = "java:global/template-service-1.0.0-SNAPSHOT/ReceptionService")
ReceptionService service;

@Override
protected void init(VaadinRequest request) {
    UI.getCurrent().setLocale(new Locale("nb","no"));
    setSizeFull();
    String message = service.welcome();
    Label label = new Label("message: " + message);
    setContent(new HorizontalLayout(label));
}

It is also still needed to register module dependency, so that the client class loader can see the service. I do it in the webapp pom.xml using the war-plugin:

         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <configuration>
                <archive>
                    <manifestEntries>
                        <Dependencies>deployment.template-service-1.0.0-SNAPSHOT.jar</Dependencies>
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>

This way I am able to deploy my ejbs separately, and I can then deploy my war-file as a "thin" deployment. My real-world project has a bunch of ejbs and jpa-stuff which slows down the develops-compile-deploy cycle when I work on the gut-stuff, with this setup I can save quite some time when fiddling with the gui.

The EJB looks like this, no ejb-jar.xml.

@Stateless
public class ReceptionService {
    public String welcome() {
        return "Hello, Developer! No XML, No Configuration, and it works!!!";
    }
}

The no-xml-part in the message would only be true if you added the module dependency to your manifest manually, and not using war-plugin :o)

Edit: to include dependencies in the ejb jar one can use one-jar plugin or similar.

jon martin solaas
  • 459
  • 1
  • 4
  • 14