I had this picture lying around (in a git branch) and I figured I might as well make it available to others. It might not be totally accurate anymore with regards to the methods, but it is an accurate depiction of the framework.
What you see here is how persistence is structured in human-task: to start with, we have a
TaskService instance. When a human-task server or service instance gets a request (via a method call or message) to perform an operation, the
TaskService instance creates a
TaskServiceSession is our “request session”: it encapsulates the logic state and persistence state needed when handling the request. By logic state, I mean the variables and retrieve information needed to handle the task operation, and by persistence state, I mean the persistence context (entity manager) and transaction control state.
Actually, in order to seperate the persistence logic from the task logic, the persistence logic has been put into the
TaskPersistenceManager. That makes it easier to maintain (I hope?) and at least, for me, easier to read.
So far I’ve described the left hand side of the diagram:
The upper right hand side describes how the
TaskServiceSession instance is created: via a
Factory, of course. However, we wanted to provide Spring compatibility, so we have to implementations: one for “normal” situations, and one when using the human-task code with Spring. When we use Spring, we create a spring bean using the TaskSessionSpringFactoryImpl and inject that into our TaskService bean. Otherwise, the default is to use the (normal)
Transactions are also a concern that can differ: on the bottom right hand side, you’ll see we have 3 implementations of the TaskTransactionManager class: one for JTA, one for Local transactions and one for Spring transactions.
If you’re wondering what Spring transactions are, well, Spring provides an abstraction around local or JTA transactions. For example, Spring ‘local’ transactions actually have a synchronization point, even though normal local transactions don’t support that functionality.
Well, that’s about everything, I guess!
When I was in college, I saw the movie “The Matrix” a couple times. I only watched it 3 times maybe, but I never watch movies multiple times (Okay, except for my favorite movie ever, but that’s another story).
In any case, I would get so psyched to code after watching that. When I had a project I needed to code for school that I just wasn’t enjoying that much — or when I just wasn’t motivated to work, I’d watch the Matrix and it would just psyche me up to build the worlds I was building in my code.
I think it was the sense of discovering and creating your own worlds that “The Matrix” conveys — the way it brought me in touch with that feeling in myself, and how I’ve always enjoyed that.
The (“leaked”) Valve handbook does that for me now — if I had theoretically read it, of course. But if I had read it, I would say that it is infused with that joy of creating. And I can’t help but be contaminated by that when I read it.
Hey you.. listen up!
I know, I know, I also felt the pain. Git: “Huuhh?? I have to commit and push? Uh.. And what’s the difference between git fetch and git pull?”
I know. But here’s something that will help: SVN and CVS are CVCS’s: Centralized Version Control Systems. Git is much closer to a file system. And please, don’t use Git like you used SVN or CVS.
The picture on the left is from a interesting talk on language developments from the creator of Clojure, Rick Hickey. You can find the talk here.
But it also (coincidentally) has a decent representation of how the Git ‘file’ system works. We can look at the two “trees” in this picture as branches in a Git repository.
However, what I really want you to take away from the minutes spent reading this is that you need to stop using Git as if it was SVN or CVS. You need to stop using merge unless you wanted to shout at everyone who looks at that merge commit later that “YES, I MERGED STUFF HERE!”.
This is the leap that Git has achieved: Git has made commits into a form of documentation. Commits with Git are so transparent and easy to manage and follow that everyone sees the commits — and wants to look at them.
However, most people use merge because they run into the following:
My teammate/colleague just committed something and I can no longer push to the repository!
So what do we do? What we do not do, is merge. Okay?
The first thing we do do is copy the name of the commit we’ve made. Now that the changes have been committed, that commit now exists on the “Git filesystem”, regardless of whether or not it’s part of a branch.
$ git commit -m"Added tests for new Fromungulator logic" [master 0ca7df5] Added tests for new Fromungulator logic 4 files changed, 3 insertions(+), 1 deletions(-)
0ca7df5 is of course your commit hash — or, if we’re thinking in terms of the Git file system, it’s the reference to the “git file” that contains your commit. Of course, if your colleague went ahead and pushed a commit to the repository before you could, you’ll see this:
$ git push origin master To email@example.com:mrietveld/frunubucation.git ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to 'firstname.lastname@example.org:mrietveld/frunubucation.git' To prevent you from losing history, non-fast-forward updates were rejected Merge the remote changes (e.g. 'git pull') before pushing again. See the 'Note about fast-forwards' section of 'git push --help' for details.
They lie.. Do not, I repeat, do not then go do this:
git pull origin master
(unless you’ve setup your branch with auto-rebasing. There’s a funny post about that here.)
There are lots of ways to avoid merge bubbles, but the fastest is probably to do the following:
git fetch origin git rebase origin/master
Rebase! Man, I love git! Rebase is the equivalent to doing this:
git reset --hard HEAD^1 git merge --ff origin/master git cherry-pick 0ca7df5
And once you’re done, you’ll want to push that commit to the origin repository:
git push origin master
Why do we nog cause merge bubbles? Because:
- Merge bubbles make it hard to determine which commit caused which change in the code
- Merge bubbles make it hard to retroactively fork off a branch from a different commit.
The first reason, determining which commit caused what, is really enough, though. That’s one of the main reasons you’re using a versioning system!
Your (IBM) DB2 JDBC driver might throw the following error in some situations:
Caused by: com.ibm.db2.jcc.am.SqlException: [jcc][t4][4.12.55] Invalid operation: result set is closed. ERRORCODE=-4470, SQLSTATE=null
If you look around the internets, you’ll find pages like this, which state things like this:
The IBM Data Server Driver for JDBC and SQLJ automatically closes the cursor when all rows have been retrieved from a ResultSet. When ResultSet.next is executed after the cursor is closed the SQLException is thrown.
It might even suggest an eccentric solution, like:
Alternatively, you can may enable the allowNextOnExhaustedResultSet datasource property. When the allowNextOnExhaustedResultSet property is set to DB2BaseDataSource.YES (1), and a forward-only cursor is positioned after the last row of a result set, a call to ResultSet.next returns false, instead of throwing an SQLException.
Don’t listen. Okay, maybe, in your case, the above applies. In that case, congratulations on fixing your bug and please get the heck out of here. If you’re still stumped, listen up to my extrapolations:
You’re running a query somewhere, and you need to put a transaction around it. That’s what this unreadable, confusing error means.
Let’s start with cursors: cursors are also subject to transaction boundaries. In fact, the way I see it, cursors were made for programmatic SQL languages, such as Transact-SQL or PL/SQL — and, okay, for SQL. More info on wiki.
But cursors are, in essence, database-level constructs that are exposed to users so that they can take advantage of them. What I mean to say by that is that cursors are sometimes used when you don’t expect them to be — like in a normal query.
And cursors need transactions! Because it’s a non-atomic set of operations on a set of results — but we’re expecting it to act atomically: get records from database. Bam.
So go find the query that’s causing the error, and put a transaction around it. It’ll help — or at least, it helped me.