Question:
I have an EJB project, to implement the system the project needs to be divided into 3.
- The database on a machine
- The User Interface on Another Host
- And the EJB(Services) in another
But the system is all developed in ejb, the EAR package is in the following way.
- EAR
- EJB
- WAR
As far as I understand I should leave the WAR package on one of the hosts, and the EJB running on another, but how do I break the project this way? We are using JBOSS EAP 6.3 on both servers, the database separation part is already done.
Answer:
As your doubt is general regarding the process of this physical separation of the components of your architecture, I will try to cover as much as possible.
The way I show you here is not the only one that exists, it's just one that I consider organized and that I adopt with JavaEE when a distributed architecture similar to your needs is used.
Well, considering that it uses maven
and also its current structure, I imagine it has three projects:
- a project with
ejb
package where your local interfaces and other things likeDAO
s, etc. are. It will undergo little change - a project with package
war
, with a dependency on packageejb
; - a project with package
ear
, with dependency on the other two ( packageejb
and packagewar
) and being modules of yourEAR
.
If this is not the scenario you are using, correct me to consider a correction in the answer.
That said, let's look at a way to make this separation. I'll put the steps and show you how you can do this separation in your project.
1. Use of local and remote interfaces
The first step to be done is to analyze your current project in search of what will be made available by remote interfaces or not. There are several ways to do this, many people usually provide a single remote interface for all services. I don't particularly like it, I think it's not very organized when you have a single remote interface, because it loses a little of the semantics of the thing.
Chances are, you'll need legal refactoring in your project so you don't have duplicates and more importantly, don't remotely expose what you don't need to expose.
2. Project Modules
For the project structure, I'm going to assume you have a project pooler, let's call it root-project
. This root-project
will have the following modules:
-
project4remote
: this project will only contain remote interfaces, no implementation, the package will beejb
and it has no dependency on other modules of your application.
An example remote interface is basically annotated with @Remote
and you say how you want the result to be serialized, it would look like this:
import javax.ejb.Remote;
@Remote
public interface RemoteInterface { }
project4local
: This is basically your project with theejb
package , changing only that it should implement the remote interfaces, the package continues asejb
and obviously has a dependency onproject4remote
.
I @Local
you already have local interfaces, but if you don't, it's just something noted as @Local
, something like this:
import javax.ejb.Local;
@Local
public interface LocalInterface { }
In its implementation it can be the same implementation as the remote interface, that is, something like this:
import javax.ejb.Stateless;
@Stateless(name = "yourServiceBean")
public class LocalRemoteImpl implements LocalInterface, RemoteInterface { }
project4web
: this is the web project, your projects will only depend onproject4remote
because it will need such interfaces to consume the services that are in the container .-
project4ear
: this is the project that will group what will be installed in theJEE
container, so it will have dependency for the projects. An example configuration could be this:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.brunocesar</groupId>
<version>0.0.1-SNAPSHOT</version>
<artifactId>root-project</artifactId>
<packaging>pom</packaging>
<build>
<finalName>${project.artifactId}</finalName>
<defaultGoal>clean install</defaultGoal>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<modules>
<module>project4ear</module>
<module>project4local</module>
<module>project4remote</module>
<module>project4web</module>
</modules>
</project>
3. How to lookup your remote interfaces?
Since you apparently aren't wearing anything that does this lookup for you, I'm just going to show you how you can do it "by hand". In a nutshell it goes something like this:
final InputStream fis = SuaClasse.class.getResourceAsStream("/ejb-client.properties")
final Properties props = new Properties();
props.load(is);
final InitialContext ic = new InitialContext(props);
final SuaInterfaceRemota interface = (SuaInterfaceRemota) ic.lookup("nome:/doRecurso/PublicadoNaJNDI");
interface.seuMetodo(args);
I suggest observing how interfaces are being published, there are always several ways to access them through JNDI. I don't remember what it's like with JBoss, so take a look at the log to be able to do the lookup correctly.
For the client properties, see here and also those present here , in case you need any of the ones that were not included in the example. An example configuration would be this:
java.naming.factory.url.pkgs=org.jboss.ejb.client.naming
remote.connections=${remote.connections}
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.${remote.connections}.host=${remote.connection.host}
remote.connection.${remote.connections}.port=${remote.connection.port}
remote.connection.${remote.connections}.username=${remote.connection.username}
remote.connection.${remote.connections}.password=${remote.connection.password}
Where remote.connections
is the connection ID, such as default
.
Note . I got these parameters from a project I've already configured, if you don't use maven property replacement in your build, just change it.