I am working on a new Spring MVC based application.
I have multiple flows where the controller will make request to business manager and further business manager will talk to DAO layer to retrieve data.
There can be possible cases where I don't get data back from the DAO.
I want to understand what is best way to deal with this situation.
1) When ever there is no data retrieved for a query then Throw back Custom Exception like 'Content Not Found' from DAO layer to Business Layer and then to Controller and let controller decide what to do.
2) Return blank/null Pojo object back to business manager and let manager throw the exception to Controller.
3) Controller receives null/blank from Manager and decides what to do with that.
I am finding 1st approach better as when the exception is thrown i have complete stack trace to understand where exactly the problem occurred but on downside I will end up cluttering my code with Exception in the signatures.
Number 3 will leave the code clean but I wont be able to pin point where exactly the data retrieval failed as there can be multiple calls to DAO from Business Layer.
Throw an exception on the level where the situation of not having matching records (in other words, no data to be processed) actually is exceptional.
This largely depends on the specifics of your domain, but it's often the best idea to simply return an empty container object from the DAO if there was no matching object in the database. That is: an Collections.emptyList(), Optional.empty() or something with similar semantics. Under no circumstances return null, it's 2015 after all.
If having no matching data is an exceptional situation in your business domain, translate that to a specific exception in the service layer and let the controller handle that by translating again: into an error HTML page, some specific XML or JSON response or whatever the interface your users use to interact with your system.
The DAO layer executes queries and returns the results. It doesn't care about the results, so "nothing found" cannot be an exceptional situation in the DAO layer. It can be in the business layer, but it doesn't have to.
I wont be able to pin point where exactly the data retrieval failed
If your use case is http://server/something/2 and something 2 doesn't exist in the database, then there simply is no failure on the server side. So if there is no exception, or only one in the controller, then you can be pretty confident that no data is returned to the client because no data exists.
I would suggest you to throw custom exceptions at each layer. Each layer should be aware of exception handling.
Its beautifully explained in the below link.
Handling Dao exceptions in service layer
Related
I'm using Spring/Hibernate combination for my project, with standard CRUD operations.
I wonder, is it reasonable to validate object existence before its deletion or update? If it is, where is the most appropriate place to do - service or dao layer?
EDIT:
Sorry, I didn't make the point at first when I asked this question. The only motive for existence checking is to throw friendly exception to client of service (no DAO specific).
Problem is that I 'have to do' existence checking because my service method below is transactional, and besides that, I'm using HibernateTemplate and DaoSupport helper classes for session manipulation in DAO objects.
According to mentioned, Hibernate exception (in case of deleting non-existing instance for example) is thrown at commit time, which is out of my reach, because (I suppose) commit is executed by PlatformTransactionManager in proxy object, and I have no opportunity to handle that exception in my service method and re-throw some friendly exception to the client.
But even if I keep my strategy to check existence before deletion, bad stuff is that I have problems with NonUniqueObjectException in the case that instance exist, because I re-attach (in delete-time) already loaded instance (in read-time due existence checking).
For example:
//Existence checking in this example is not so important
public void delete(Employee emp){
Employee tempEmp=employeeDao.read(emp.getId());
if(tempEmp==null)
throw new SomeAppSpecificException();
}
//Existence checking in this example is maybe 'more logical'
public void save(Assignment a){
Task t=taskDao.read(a.getTask().getId());
if(t==null)
throw new FriendlyForeignKeyConstraintException();
Employee e=employeeDao.read(a.getEmployee().getId());
if(e==null)
throw new EmployeeNotFoundExc();
//...some more integrity checking and similar...
assignmentDao.save(a);
}
The point is that I just want to throw friendly exception with appropriate message in the case of mentioned situations (integrity violations and similar).
In Hibernate terms, both update and delete operations (and corresponding methods on Session) deal with persisted entities. Their existence is, therefore, implied and verifying it again in your code is kind of pointless - Hibernate will do that on its own and throw an exception if that's not the case. You can then catch and handle (or rethrow) that exception.
On a side note (based on your sample code), it's not necessary to explicitly read the instance you're going to delete. Session provides load() method that will return proxy instance suitable for passing to delete() method without actually hitting the database. It assumes that instance associated with given PK exists and will fail (throw an exception) later if that's not the case.
Edit (based on question clarification):
When you say you want to throw "friendly" exception to the client, the definitions of "friendly" and "client" become important. In most real-life scenarios your transaction would span across more than a simple atomic "save()" or "delete()" method on one of your services.
If the client is local and you don't need separate transactions within a single client interaction (typical scenario - web app running in the same VM with service layer), it's usually a good idea to initiate / commit transaction there (see Open Session In View, for example). You can then catch and properly handle (including wrapping / re-throwing, if needed) exceptions during commit. Other scenarios are more complicated, but ultimately the exception will be propagated to your "top level" client; it's just that unwrapping it may prove to be complicated if you need to present the "root" cause to the client in a "friendly" way.
The bottom line, though, is that it's up to you. If you'd rather fail fast with your own exception (at the expense of writing some boilerplate code), there's nothing really wrong with that.
Imagine I have an application that request to the user a name, a category list. When user click on save button, application will save name and category to a database.
I have a layer that get name and category from UI. This layer check if there is a name (a string with length > 0). If this is correct, it will pass name a category to another layer. Note: category is a radiobutton list where one item is always selected.
On this second layer, application will select a suitable class to save name, depending on category.
On last layer, a class will save this name on a database. On this class I will check if name is empty or not.
My question is: where is the right place to check method's input parameters? on every layer? Maybe, I'm going to use these layers on others developments.
Is my example correct? Maybe, I can left validation on database layer and raise an exception to UI layer.
In general, in terms of the larger question about validating input that is ultimately persisted, it is best to:
Convert the input parameters to a
fully encapsulated business object as
soon as possible after you receive
it.
Validate early and fail fast then to
wait until you get to a lower layer
-- waste of resources, waste of time, possibly more complex (more things to
roll back).
Validate the business logic once and make that part of
your object instantiation process. (but note that validation of view logic and persistence logic may need to be done at the other layers and is separate from business logic)
Model how your object is persisted
using an ORM (e.g., Hibernate) so
that you could work purely at the
object level in memory and leave
persistence as an implementation
detail. Focus the business logic at
the object layer.
And in terms of method validation itself, I agree with Oded -- at every layer, and it should be done immediate upon method entry. Again, this is part of the fail fast methodology. But, as I noted above, this doesn't mean you validate business logic at every method (or every layer). I'm just referring to the basic practice of validating inputs (either by assertions or explicit checks and exceptions thrown).
where is the right place to check method's input parameters? on every layer?
Yes, on every layer. This is called defense in depth.
There are different reasons to do so on each layer:
UI/Client code: keep things responsive and avoid roundtrips when data is invalid
Business layer: Ensure business rules are kept
Data layer: Ensure that valid data is passed through
I disagree with the recommendation about every layer, all the time. It sounds too dogmatic to me.
All design represents a choice between functionality and cost. Your validation choices should reflect that as well.
I think your decisions should take into account the sharing and reuse of layers.
If the database is shared by more than one application, then the database cannot depend on every application validating properly. In that case, the database must validate to protect itself.
In this day and age of SQL injection attacks, I think binding and validating prior to reaching the persistence tier is a must. The schema should do what it must to ensure referential and business integrity (e.g. unique constraints on columns and required "not null"), but other validations should be done prior to hitting the database.
If the database is wholly owned by one and only one application, and there's a service that is the only gateway into the data, then validation can be done by the service. The cost of duplicating the validation on the database layer can be waived.
Likewise between the UI and the service layer.
Double validation on client and service tiers is common because the service is shared by many clients in a service oriented architecture. Today your service might be used by a browser based UI; suddenly there's a flock of mobile apps along side it that clamor for services, too. In that case the service absolutely must validate and bind each and every request.
No manufacturer polishes every surface to mirror quality. Sometimes a rough cast surface is permissible, because the benefit of grinding and polishing is negligible and the cost is too great.
Same with software.
I don't like dogmatic statements. It's better to understand the implications of your choices. Know the rules and when it's appropriate to break them.
If you're going for very loose coupling where other applications will also make use of these same layers, then I would recommend doing input checking at every step. Since each class/method should have no knowledge of expectation of the other classes/methods which ran before them in the stack, each one should enforce its requirements individually.
If the UI requires that a value be in the text box when the button is clicked, it should validate accordingly.
If the business logic requires that a name never be null/empty, it shouldn't allow a null/empty value to be placed in that property.
If the data layer has a constraint on that field requiring that a value be present, it should check that a value is present before trying to persist the data.
So I have this general question of where should I have certain logic for example -
var data=GetItems();
if(data==null)
//return some defaults
else
return values
//second case..
if(id<=0)
//throw some exception
else
return id
So should the above code should it be a part of data access layer (I think it should) or a par tof business layer. Also,validation of data should it generally be part of data access or business layer ?
I think the question is whether it should be between the business or the UI layer. The purpose of the data layer is to CRUD, so the logic should only be oriented towards that.
In the second example above, I'd say that's business logic. You're saying that a negative id has a meaning which should throw an exception. That meaning exists only within the logic of the application you're creating - there's nothing inherent to data storage that says that this should be the case.
So my vote is for business layer, and you should give some thought to the UI layer as well.
I looked at the example on http://solitarygeek.com/java/developing-a-simple-java-application-with-spring/comment-page-1#comment-1639
I'm trying to figure out why the service layer is needed in the first place in the example he provides. If you took it out, then in your client, you could just do:
UserDao userDao = new UserDaoImpl();
Iterator users = userDao.getUsers();
while (…) {
…
}
It seems like the service layer is simply a wrapper around the DAO. Can someone give me a case where things could get messy if the service layer were removed? I just don’t see the point in having the service layer to begin with.
Having the service layer be a wrapper around the DAO is a common anti-pattern. In the example you give it is certainly not very useful. Using a service layer means you get several benefits:
you get to make a clear distinction between web type activity best done in the controller and generic business logic that is not web-related. You can test service-related business logic separately from controller logic.
you get to specify transaction behavior so if you have calls to multiple data access objects you can specify that they occur within the same transaction. In your example there's an initial call to a dao followed by a loop, which could presumably contain more dao calls. Keeping those calls within one transaction means that the database does less work (it doesn't have to create a new transaction for every call to a Dao) but more importantly it means the data retrieved is going to be more consistent.
you can nest services so that if one has different transactional behavior (requires its own transaction) you can enforce that.
you can use the postCommit interceptor to do notification stuff like sending emails, so that doesn't junk up the controller.
Typically I have services that encompass use cases for a single type of user, each method on the service is a single action (work to be done in a single request-response cycle) that that user would be performing, and unlike your example there is typically more than a simple data access object call going on in there.
Take a look at the following article:
http://www.martinfowler.com/bliki/AnemicDomainModel.html
It all depends on where you want to put your logic - in your services or your domain objects.
The service layer approach is appropriate if you have a complex architecture and require different interfaces to your DAO's and data. It's also good to provide course grained methods for clients to call - which call out to multiple DAO's to get data.
However, in most cases what you want is a simple architecture so skip the service layer and look at a domain model approach. Domain Driven Design by Eric Evans and the InfoQ article here expand on this:
http://www.infoq.com/articles/ddd-in-practice
Using service layer is a well accepted design pattern in the java community. Yes, you could straightaway use the dao implementation but what if you want to apply some business rules.
Say, you want to perform some checks before allowing a user to login into the system. Where would you put those logics? Also, service layer is the place for transaction demarcation.
It’s generally good to keep your dao layer clean and lean. I suggest you read the article “Don’t repeat the DAO”. If you follow the principles in that article, you won’t be writing any implementation for your daos.
Also, kindly notice that the scope of that blog post was to help beginners in Spring. Spring is so powerful, that you can bend it to suit your needs with powerful concepts like aop etc.
Regards,
James
I have a method that returns lot of data, should I use #TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) for this method. The method perform a JPA query an loads the full content of a table (about 1000 rows).
The client to this method - is that already in a transaction? When you use NotSupported the caller transaction will be suspended. If not I would say, just put Never as the transaction type. Never is better since callers know they are not supposed to call this method from inside a transaction. A more straight forward contract.
We always use Never for methods that do more processing so that developers are aware right off the bat not to call if they are involved in a transaction already. Hope it helps.
I would care to disagree as it seldom happens that user is not in a transaction in almost all the systems. The best approach is to use NOT SUPPORTED so that the transaction is suspended if the caller is in any transaction already. NEVER is troublesome unless you have a series of calls which are all in NO TRANSACTION scope. In short, NOT SUPPORTED is the type one should use.
As far as I know (at least this is the case with Hibernate), you cannot use JPA outside of a transaction as the entity manager's lifecycle is linked to the transaction's lifecycle. So the actual method that does the query must be transactional.
However, you can set it to TransactionAttributeType.REQUIRES_NEW; this would suspend any existing transaction, start a new one, and stop it when the method returns. That means all your entities would be detached by the time they reach the caller, which is what it sounds like you're trying to achieve.
In more complex systems, it pays to completely separate your data layer from your business layer and create a new set of object. Your method will then call the JPA query, then use the entities returned to populate objects from your business layer, and return those. That way the caller can never get their hands on the actual JPA entities and you are free to do in your data layer what you want, since now it's just an implementation detail. (Heck, you could change the database call to a remote API call and your caller wouldn't have to know.)