I'm going to pass by the setup issue setup issue that abuzittin gillifirca mentioned in his comment, and the input sanitizing input sanitizing that jimmycarr pointed to, because I have little to add to that. And since you asked about the layering, I'm going to focus on the layering.
I'm going to pass by the setup issue that abuzittin gillifirca mentioned in his comment, and the input sanitizing that jimmycarr pointed to, because I have little to add to that. And since you asked about the layering, I'm going to focus on the layering.
I'm going to pass by the setup issue that abuzittin gillifirca mentioned in his comment, and the input sanitizing that jimmycarr pointed to, because I have little to add to that. And since you asked about the layering, I'm going to focus on the layering.
Edit:
But one question: UserRegistirationService#registerAppUser method has no checks. Should I put the null checks in this layer? or in this layer AS WELL?
Your service layer should check its input at any rate, and it should be your baseline. It is best positioned to know what input it accepts, so it should be the authority on checking it. When you write services, not all input may come from sources that you control, so you need to be defensive in checking. And even if you do control the sources, checking anyway will catch bugs quickly.
For the presentation layer, often some quick & dirty checks are also made. This lets you provide feedback to users without contacting the service layer (potentially on another physical machine). It can check that required fields are filled out, basic syntax followed, and so on. Null checks and length checks are a good choice here, but others are outside its possibilities (such as checking that a user name is not already taken).
There is some balance to be sought, though. Checking in multiple layers also gives you some duplicated code. Usually, it's not so bad, but it's something you'll want to document.
Edit:
But one question: UserRegistirationService#registerAppUser method has no checks. Should I put the null checks in this layer? or in this layer AS WELL?
Your service layer should check its input at any rate, and it should be your baseline. It is best positioned to know what input it accepts, so it should be the authority on checking it. When you write services, not all input may come from sources that you control, so you need to be defensive in checking. And even if you do control the sources, checking anyway will catch bugs quickly.
For the presentation layer, often some quick & dirty checks are also made. This lets you provide feedback to users without contacting the service layer (potentially on another physical machine). It can check that required fields are filled out, basic syntax followed, and so on. Null checks and length checks are a good choice here, but others are outside its possibilities (such as checking that a user name is not already taken).
There is some balance to be sought, though. Checking in multiple layers also gives you some duplicated code. Usually, it's not so bad, but it's something you'll want to document.
I'm going to pass by the setup issue that abuzittin gillifirca mentioned in his comment, and the input sanitizing that jimmycarr pointed to, because I have little to add to that. And since you asked about the layering, I'm going to focus on the layering.
First things first: the layers are well divided. You separate the different layers without going overboard and, aside from initialisation, each layer has at most to contend with the one below and/or the one above. That's the very essence, and you have that basic idea right.
Because the basic idea is right, I'll focus on a smaller issue that may or may not trip you up later on.
The important thing to keep in mind about layering is that it is all about isolation. You require the minimum that is needed to function correctly and, in turn, you expose the minimum that is needed to provide a reliable, consistent, and useful service. This makes it easier to change bits in layer X without endangering layers Y and Z.
UserRegistirationService
(typo there, should be "registration") has a fieldAppUserAccessObject appUserAccessObject
that can probably be aDataAccessObject
instead. Unless you require specific functionality that onlyAppUserAccessObject
provides, go through the interface instead (require less).AppUserAccessObject.insertUser
andUserRegistirationService.registerAppUser
are declared to throwSQLException
, but shouldn't (expose less).In casu the access objects, if your project is small, this is acceptable, but still not recommended. It is the DAO implementation's job to sort out any issues it may encounter, and to translate or at least wrap exceptions it can't handle.
For the service, though, this is a no-no. You don't want to force users of your service to deal with database protocol exceptions. What can your web layer or my console app really do at this point?
The exceptions you (declare to) throw are as much a part of your API as your return and parameters types. If returning a ResultSet
would look out of place, throwing SQLException
probably will be, too.
There are three main ways to deal with exceptions:
Log and ignore. If you don't know what to do with it, and the other two options can't help you, this is a viable option. You'll want to be careful not to ignore out of convenience, though.
Wrap and rethrow. The quick way out, and one many people choose when faced with checked exceptions. Wrap in a
RuntimeException
and bubble away. When done right, it simplifies APIs and speeds up your development. (I don't see it done right often.)Analyse and decide. The hard way out. Analyse the exception you caught, check for type and error codes, and decide what to do with it. You can throw another exception type (
NameTooLongException
,InvalidEmailAddressException
), try another route, or wait a bit and try again. This takes the most work and effort, and may be overkill for small projects.
No size fits all. Pick what you feel is appropriate in a given situation and the effort you can afford to put into it.
Two points not related to layering:
Instead of writing passwords plaintext into your database, store a salted hash of them.
Remember to close your
PreparedStatement
after use!