I'm trying to figure out the options that I have for the architecture of my API project.
I would like to create an API using JAX-RS version 1.0. This API consumes Remote EJBs (EJB 3.0) from a bigger, old and complex application. I'm using Java 6.
So far, I can do this and works. But I'm not satisfied with the solution. See my packages disposition. My concerns are described after the code:
/api/
/com.organization.api.v1.rs -> Rest Services with the JAX-RS annotations
/com.organization.api.v1.services -> Service classes used by Rest Services. Basically, they only have the logic to transform the DTOs objects from Remote EJBs in JSON. This is separated by API version, because the JSON can be different in each version.
/com.organization.api.v1.vo -> View Objects returned by the Rest Services. They will be transformed in JSON using Gson.
/com.organization.api.services -> Service classes used by versioned Services.
Here we have the lookup for Remote EJBs and some API logic, like validations. This services can be used by any versioned of each Service.
Example of the com.organization.api.v1.rs.UserV1RS
:
@Path("/v1/user/")
public class UserV1RS {
@GET
public UserV1VO getUsername() {
UserV1VO userVO = ServiceLocator.get(UserV1Service.class).getUsername();
return userVO;
}
}
Example of the com.organization.api.v1.services.UserV1Service
:
public class UserV1Service extends UserService {
public UserV1VO getUsername() {
UserDTO userDTO = getUserName(); // method from UserService
return new UserV1VO(userDTO.getName);
}
}
Example of the com.organization.api.services.UserService
:
public class UserService {
public UserDTO getUsername() {
UserDTO userDTO = RemoteEJBLocator.lookup(UserRemote.JNDI_REMOTE_NAME).getUser();
return userDTO;
}
}
Some requirements of my project:
- The API have versions: v1, v2, etc.
- The different API versions of the same versioned Service can share code:
UserV1Service
andUserV2Service
usingUserService
. - The different API versions of different versioned Services can share code:
UserV1Service
andOrderV2Service
usingAnotherService
. - Each version have his own View Object (
UserV1VO
and notUserVO
).
What botters me about the code above:
- This
ServiceLocator
class it not a good approach for me. This class use legacy code from an old library and I have a lot of questions about how this class works. The way to use theServiceLocator
is very strange for me too and this strategy is not good to mock the services for my unit tests. I would like to create a new ServiceLocator or use some dependency injection strategy (or another better approach). - The
UserService
class is not intended to be used by another "external" service, likeOrderService
. It's only for theUserVxService
. But in the future, maybeOrderService
would like to use some code fromUserService
... - Even if I ignore the last problem, using the
ServiceLocator
I will need to do a lot oflookups
among my code. The chance of create a cyclic dependency (serviceOne lookup serviceTwo that lookup serviceThree that lookup serviceOne) is very high. - In this approach, the VOs, like
UserV1VO
, could be used in my unversioned services (com.organization.api.services
), but this cannot happen. A good architecture don't allow something that is not allowed. I have the idea to create a new project, likeapi-services
and put thecom.organization.api.services
there to avoid this. Is this a good solution?
So... ideas?