| Recent Entries |
|
22. May 2013
|
||
|
14. May 2013
|
||
|
03. May 2013
|
||
|
02. May 2013
|
||
|
25. Apr 2013
|
||
|
22. Apr 2013
|
||
|
15. Apr 2013
|
||
|
10. Apr 2013
|
||
|
03. Apr 2013
|
||
|
23. Mar 2013
|
| Seam News | (211) |
| Hibernate | (137) |
| Seam | (131) |
| RichFaces | (92) |
| Contexts and Dependency Injection | (91) |
| News | (82) |
| Web Beans | (61) |
| JBoss Tools | (60) |
| Core Release | (59) |
| Eclipse | (56) |
| JavaServer Faces | (55) |
| Ceylon | (49) |
| Hibernate Search | (49) |
| JBoss Tools Eclipse | (44) |
| Weld | (43) |
Hibernate Tools 3.1.0.beta5 (http://tools.hibernate.org) have been made available.
The tools are for both Eclipse and ANT.
This version is where the template functionallity is finally based on FreeMarker.
As an extra treat the tools now bundle a FreeMarker plugin to help out when writing custom templates (Thanks to Joe Hudson).
ANT users also get a most-wanted feature, namely removal of the old requirement of having to specify all mapped classes in hibernate.cfg.xml when e.g. generating the schema based on EJB3 annotated classes.
The new <ejb3configuration> support in the ant task allows standard EJB3 persistence packaged projects to be automatically scanned for mappings and then used like any other Hibernate compatible configuration.
See screenshots and other noteworthy news at here for more information.
I, for one, welcome our new penguin overlords.
The last couple of months have been pretty nerve wracking. The various rumors floating about generated a fair amount of uncertainty for our customers, employees and user community at large (nevertheless, despite the uncertainty, March was a record month for sales!). In the end, Marc chose to sell to Red Hat. This is the combination that offers the greatest synergies to both companies, is most reassuring to our customers, and causes the least disruption to our overall business and technology strategy. Most of all, it clearly signals our continued commitment to Free Software. The two companies have similar business models, similar licenses and a similar record of successful evangelization and commercialization of open source.
The planned acquisition of JBoss by Red Hat will revitalize the middleware market - expect a more competitive marketplace, with all major products based on open source codebases. And expect us to be leaders in SOA. No other software company offers an open source enterprise software platform of comparable depth and maturity.
Obviously, Marc deserves all the congratulations he's getting today. He's delivered on basically everything he promised when I joined the company two and a half years ago (back when there were three people working out of our Atlanta headquaters). He's changed the middleware market for good. He's built a company where technical people have the freedom to pursue their ideas. And he's made a whole bundle of money for himself and his employees.
For a technical guy like me, JBoss is Camelot. Three years ago I was dragging myself out of bed each morning to go to my depressing job building boring web applications for organizations run by risk-averse middle managers and clueless architects
. I was thoroughly frustrated with the lack of productivity of the technology platform - always WebSphere - that was forced down my throat by these guys. And I knew I was wasting most of my life sitting in a cube reading blogs (the dirty secret is that when you sit them in a cube farm, very few developers are actually productive for more than about three of the eight hours in a workday). That was a world where an idea - however unoriginal - was valued on the basis of how many grey hairs were in evidence on the head of the person expressing the idea. But the hair was not the only thing that needed to be grey. In the world of professional services
, only the greyest personalities succeed. Passion, creativity, vision - all liabilities. Knowing no other world, I believed that that world was the whole world. At night I'd work on Hibernate, hoping that perhaps - if Hibernate became wildly successful - I might get just an ounce more respect in that world, despite my obvious lack of greyness.
My first visit to America was for a conference in Massachusetts. JBoss sent Bill Burke and Ben Sabrin to meet and recruit me. These guys are the perfect metaphor for the culture of JBoss: a culture driven equally by technology and sales. Bill is a technology guy through and through. Ben is my perfect ideal of a fast-talking American salesman. If Ben tries to sell you something, you can't possibly not buy it. Ben sold me JBoss. A few weeks later I was back in the states to meet Marc Fleury. I was expecting a difficult relationship here. I'd been warned by a several people that Marc was a difficult guy. I'm a difficult guy myself. And indeed, for a while, there were many difficult issues to work through. This was all happening during what were undoubtedly the darkest days for JBoss. A month or two earlier, three people had very noisily left the company and, through clever PR, created the impression that JBoss Group had split down the middle. The rest of the company felt deeply betrayed, angry and distrustful. But as memories of those events faded, what remained was a more unified, more motivated company. Bitterness was transformed into purposeful determination. The company grew from a headcount of less than 20 to almost 200. To my knowledge, not a single developer has left the company in the period since I joined. If you're creative, self-motivated, thick-skinned, this is perhaps the best software company in the world to work for. I look forward to seeing the continuation of this culture at Red Hat.
Recently, Simon Brown put together a set of requirements for a very simple blogger application that could be used to compare Java web frameworks. I have my reservations about the actual requirememts he put together (in particular, there is no form submission!) but since some other framework authors have bitten, I've gone ahead and ported the example to Seam. I want to put a massive caveat around this post: Seam is absolutely not designed for applications like blogs or web forums; these kind of problems are very easy to solve using something like PHP or Ruby on Rails and there is no really good reason to use Java for a problem like this (unless Java is all you know). We have a set of requirements here with /no conversations/ and /no business processes/, so all the sophisticated state management machinery of Seam is redundant. Nevertheless, frameworks need to make simple things easy, and you'll see how little Java code we need to write to solve this simple problem using Seam.
To begin, I copied the standard Seam web.xml, faces-config.xml, application.xml and build.xml files from the Seam booking demo, changing names in a couple of places, and removing all the JSF navigation rules from faces-config.xml. None of this stuff is interesting, and it is always almost identical in every Seam application. I also copied Simon's screen.css stylesheet.
Simon started out with a domain model with Blog and BlogEntry classes that in a real application would be mapped to the database via Hibernate or EJB3, along with a BlogService class, which implements a static singleton containing some test data. The static variable and static initializer is an incredibly ugly way to implement a singleton in Seam, so I took the liberty of rewriting this class as an application-scope Seam component.
@Name("blog")
@Startup
@Scope(APPLICATION)
public class BlogService
{
private Blog blog;
@Create
public void initBlog()
{
blog = new Blog();
blog.setName("Webapp framework blog");
blog.setDescription("Comparison of J2EE web application frameworks");
blog.setLocale(new Locale("en", "AU"));
blog.setTimeZone(TimeZone.getTimeZone("PST"));
blog.addBlogEntry(new BlogEntry(...);
blog.addBlogEntry(new BlogEntry(...);
blog.addBlogEntry(new BlogEntry(...);
}
@Unwrap
public Blog getBlog()
{
return blog;
}
}
I left Blog and BlogEntry the way I found them and just copied them across.
That's all we need to start work on the first page of the web application.
There is some common header information on all pages of the application, so we'll use a facelets template, template.xhtml, to define the common stuff.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"[=>http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd]">
<html xmlns="[=>http://www.w3.org/1999/xhtml]"
[=>xmlns:ui=]"=>http://java.sun.com/jsf/facelets"
[=>xmlns:h=]"=>http://java.sun.com/jsf/html"
[=>xmlns:f=]"=>http://java.sun.com/jsf/core"
[=>xml:lang=]"en"
lang="en">
<f:view>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>#{blog.name}</title>
<link href="screen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="container">
<h1>#{blog.name}</h1>
<h2>#{blog.description}</h2>
<[=>ui:insert] name="content"/>
</div>
</body>
</f:view>
</html>
Note that this is all plain XML with namespaces, no wierd
tags.
The index page, index.xhtml, in the example application displays a list of the three latest blog entries.
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"[=>http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd]">
<[=>ui:composition] xmlns="=>http://www.w3.org/1999/xhtml"
[=>xmlns:ui=]"=>http://java.sun.com/jsf/facelets"
[=>xmlns:h=]"=>http://java.sun.com/jsf/html"
[=>xmlns:f=]"=>http://java.sun.com/jsf/core"
template="template.xhtml">
<[=>ui:define] name="content">
<h:dataTable value="#{blog.recentBlogEntries}" var="blogEntry" rows="3">
<h:column>
<div class="blogEntry">
<h3>#{blogEntry.title}</h3>
<div>
#{blogEntry.excerpt==null ? blogEntry.body : blogEntry.excerpt}
</div>
<p>
<h:outputLink value="entry.seam" rendered="#{blogEntry.excerpt!=null}">
<f:param name="blogEntryId" value="#{blogEntry.id}"/>
Read more
</h:outputLink>
</p>
<p>
Posted on
<h:outputText value="#{blogEntry.date}">
<f:convertDateTime timeZone="#{blog.timeZone}" locale="#{blog.locale}" type="both"/>
</h:outputText>
</p>
</div>
</h:column>
</h:dataTable>
</[=>ui:define]>
</[=>ui:composition]>
This is of course also plain XML.
(Usually I would not need to explicitly define locales in my templates. JSF and Seam use the request locale by default. But Simon's requirements say that I have to use the locale of the Blog.)
Now, if we hit http://localhost:8080/seam-blog/index.seam, this is the result:
http://hibernate.org/~gavin/blog_index.png
Now for the blog entry page (which we get to by clicking Read more
). Assuming I've understood
them correctly, Simon's requirements say that if a nonexistent entry is requested, we are supposed
to send a 404 error and forward to an error page. Now, this is not the most natural thing to do
in JSF or Seam. Usually, JSF applications use pull
-style MVC when handling GET requests.
Normally I would write the entry page to be able to handle the case of a nonexistent entry
(this is easy). But Simon is the boss here, and his requirements call for a push
-style
design. We'll use a Seam /page action/.
@Name("entryAction")
public class EntryAction
{
@In private Blog blog;
@In private FacesContext facesContext;
@RequestParameter
private String blogEntryId;
@Out(scope=EVENT, required=false)
private BlogEntry blogEntry;
public void getBlogEntry() throws IOException
{
blogEntry = blog.getBlogEntry(blogEntryId);
if (blogEntry==null)
{
HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
response.sendError(HttpServletResponse.SC_NOT_FOUND);
facesContext.responseComplete();
}
}
}
This action is meant to run before the entry page is rendered. It retrieves the requested BlogEntry from the singleton instance of Blog and outjects it to the event context. If no BlogEntry matches the request parameter, it sends a 404 error.
We need to list the page action in WEB-INF/pages.xml.
<pages>
<page view-id="/entry.xhtml" action="#{entryAction.getBlogEntry}"/>
</pages>
Now we can write the entry page, entry.xhtml:
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"[=>http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd]">
<[=>ui:composition] xmlns="=>http://www.w3.org/1999/xhtml"
[=>xmlns:ui=]"=>http://java.sun.com/jsf/facelets"
[=>xmlns:h=]"=>http://java.sun.com/jsf/html"
[=>xmlns:f=]"=>http://java.sun.com/jsf/core"
template="template.xhtml">
<[=>ui:define] name="content">
<div class="blogEntry">
<h3>#{blogEntry.title}</h3>
<div>#{blogEntry.body}</div>
<p>
Posted on
<h:outputText value="#{blogEntry.date}">
<f:convertDateTime timezone="#{blog.timeZone}" locale="#{blog.locale}" type="both"/>
</h:outputText>
</p>
</div>
</[=>ui:define]>
</[=>ui:composition]>
Along with the 404 error page, 404.xhtml:
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"[=>http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd]">
<[=>ui:composition] xmlns="=>http://www.w3.org/1999/xhtml"
[=>xmlns:ui=]"=>http://java.sun.com/jsf/facelets"
[=>xmlns:h=]"=>http://java.sun.com/jsf/html"
[=>xmlns:f=]"=>http://java.sun.com/jsf/core"
template="template.xhtml">
<[=>ui:define] name="content">
<h3>Page not found</h3>
</[=>ui:define]>
</[=>ui:composition]>
This page needs to be listed in web.xml:
<error-page> <error-code>404</error-code> <location>/404.seam</location> </error-page>
Now if I click the Read more
link, I get to the URL
http://localhost:8080/seam-blog/entry.seam?blogEntryId=3
and see the following:
http://hibernate.org/~gavin/blog_entry.png
If I edit the URL and change the id to 6, I'll get a 404:
http://hibernate.org/~gavin/blog_404.png
And so we're done :-)
People using the Criteria API have either transparently or knowingly used a ResultTransformer . A ResultTransformer is a nice and simple interface that allows you to transform any Criteria result element. E.g. you can make any Criteria result be returned as a java.util.Map or as a non-entity Bean.
Criteria Transformers
Imagine you have a StudentDTO class:
public class StudentDTO {
private String studentName;
private String courseDescription;
public StudentDTO() { }
...
}
Then you can make the Criteria return non-entity classes instead of scalars or entities by applying a ResultTransformer:
List resultWithAliasedBean = s.createCriteria(Enrolment.class)
.createAlias("student", "st").createAlias("course", "co")
.setProjection( Projections.projectionList()
.add( Projections.property("st.name"), "studentName" )
.add( Projections.property("co.description"), "courseDescription" )
)
.setResultTransformer( Transformers.aliasToBean(StudentDTO.class) )
.list();
StudentDTO dto = (StudentDTO)resultWithAliasedBean.get(0);
This is how ResultTransformer have been available since we introduced projection to the Criteria API in Hibernate 3.
It is just one example of the built in transformers and users can provide their own transformers if they so please.
Jealous programming
Since I am more a HQL/SQL guy I have been jealous on Criteria for having this feature and I have seen many requests for adding it to all our query facilities.
Today I put an end to this jealousy and introduced ResultTransformer for HQL and SQL in Hibernate 3.2.
HQL Transformers
In HQL we already had a kind
of result transformers via the (select
new
http://www.hibernate.org/hib_docs/v3/reference/en/html/queryhql.html#queryhql-select)
syntax, but for returning non-entity beans it only provided value
injection of these beans via its constructor. Thus if you used the same
DTO in many different scenarios you could end up having many constructors
on this DTO purely for allowing the select new
functionality to work.
Now you can get the value injected via property methods or fields instead, removing the need for explicit constructors.
List resultWithAliasedBean = s.createQuery( "select e.student.name as studentName," + " e.course.description as courseDescription" + "from Enrolment as e") .setResultTransformer( Transformers.aliasToBean(StudentDTO.class)) .list(); StudentDTO dto = (StudentDTO) resultWithAliasedBean.get(0);
SQL Transformers
With native sql returning non-entity beans or Map's is often more useful instead of basic Object[]. With result transformers that is now possible.
List resultWithAliasedBean = s.createSQLQuery(
"SELECT st.name as studentName, co.description as courseDescription " +
"FROM Enrolment e " +
"INNER JOIN Student st on e.studentId=st.studentId " +
"INNER JOIN Course co on e.courseCode=co.courseCode")
.addScalar("studentName")
.addScalar("courseDescription")
.setResultTransformer( Transformers.aliasToBean(StudentDTO.class))
.list();
StudentDTO dto =(StudentDTO) resultWithAliasedBean.get(0);
Tip: the addScalar() calls were required on HSQLDB to make it match a
property name since it returns column names in all uppercase (e.g. STUDENTNAME
).
This could also be solved with a custom transformer that search the property names
instead of using exact match - maybe we should provide a fuzzyAliasToBean() method ;)
Map vs. Object[]
Since you can also use a transformer that return a Map from alias to value/entity (e.g. Transformers.ALIASTOMAP), you are no longer required to mess with index based Object arrays when working with a result.
List iter = s.createQuery(
"select e.student.name as studentName," +
" e.course.description as courseDescription" +
"from Enrolment as e")
.setResultTransformer( Transformers.ALIAS_TO_MAP )
.iterate();
String name = (Map)(iter.next()).get("studentName");
Again, this works equally well for Criteria, HQL and native SQL.
Reaching Nirvana of native sql
We still miss a few things, but with the addition of ResultTranformer support for SQL and the other additions lately to the native sql functionality in Hibernate we are close to reach the Nirvana of native sql support.
Combined with StatelessSession you actually now got a very flexible
and full powered sql executor
which transparently can map to and
from objects with native sql without any ORM overhead.
...and when you get tired of managing the sql, objectstate, lifecycles, caching etc. of your objects manually and want to benefit from the power of an ORM then you got it all readily available to you ;)
A bug report was recently
opened in Hibernate's JIRA stating that Hibernate incorrectly handles deadlock scenarios.
The basis for the report was an example in the /Pro Hibernate 3/ book (Chapter 9). For
those perhaps not familiar with the term deadlock
, the basic gist is that two processes
each hold resource locks that the other needs to complete processing. While this phenomena
is not restricted to databases, in database terms the idea is that the first process (P1)
holds a write lock on a given row (R1) while the second process (P2) holds a write lock on
another row (R2). Now, to complete its processing P1 needs to
acquire a write lock on R2, but cannot do so because P2 already holds its write lock.
Conversely, P2 needs to acquire a write lock on R1 in order to complete its processing,
but cannot because P1 already holds its write lock. So neither P1 nor P2 can complete
its processing because each is indefinitely waiting on the other to release the needed
lock, which neither can do until its processing is complete. The two processes are said
to be deadlocked in this situation.
Almost all databases have support to circumvent this scenario by specifying that locks should be timed-out after a certain period of time; after the time-out period, one of the processes is forced to rollback and release its locks, allowing the other to continue and complete. While this works, it is not ideal as it requires that the processes remained deadlocked until the underlying timeout period is exceeded. A better solution is for the database to actively seek out deadlock situations and immediately force one of the deadlock participants to rollback and release its locks, which most databases do in fact also support.
So now back to the /Pro Hibernate 3/ example. Let me say up front that I have not read
the book and so do not understand the background discussion in the chapter nor the
authors' intent/exceptations in regards to the particular example code. I only know the
expectations of a (quite possibly mis-guided) reader. So what this example attempts to
do is to spawn two threads that each use their own Hibernate Session to load the same
two objects in reverse order and then modify their properties. So the above mentioned
reader expects that this sould cause a deadlock scenario to occur. But it does not.
Or more correctly, in my running of the example, it typically does not, although the
results are inconsistent. Sometimes a deadlock is reported; but the vast majority of runs
actually just succeed
. Why is that the case?
So here is what really happens in this example code. As I mentioned before, the example
attempts to load the same two objects in reverse order. The example uses the entities Publisher
and Subscriber
. The first thread (T1) loads a given Publisher
and modifies its
state; it is then forced to wait. The second thread (T2) loads a given Subscriber
and
modified its state; it is then forced to wait. Then both threads are released from their
waiting state. From there, T1 loads the same Subscriber
previously loaded by T2 and modifies
its state; T2 loads the same Publisher
previously loaded by T1 and modifies its state. The
thing you need to keep in mind here is that so far neither of these two Sessions have actually
been flushed, thus no UPDATE statements have actually occurred against the database at this point.
The flush occurs on each Session after each thread's second load and modify
sequence. Thus,
until that point neither thread (i.e. the corresponding database process) is actually holding
any write locks on the underlying data. Clearly, the outcome here is going to depend upon the
manner in which the two threads are actually allowed to re-awaken
by the underlying threading
model, and in particular whether the UPDATE statements from the two sessions happen to get interleaved
. If the two threads happen to interleave their requests to the database (i.e. T1's UPDATE PUBLISHER happens first, T2's UPDATE SUBSCRIBER hapens second, etc) then a
deadlock will occur; if not interleaved, then the outcome will be success
.
There are three ways to inequivocally ensure that lock acquisition errors in the database force one of these two transactions to fail in this example:
- use of SERIALIZABLE transaction isolation in the database
- flushing the sesssion after each state change (and the end of the example code's step1() and step2() methods)
- use of locking (either optimistic or pessimistic)
Seems simple enough. Yet apparently not simple enough for the reader of the /Pro Hibernate 3/ book that opened the previously mentioned JIRA case. After all this was explained to him, he wrote me some ill-tempered, misconception-laden replies in private emails. I am not going to go into all the misconceptions here, but one in particular I think needs to be exposed as many developers without a lot of database background seem to stumble over various concepts relating to transactions. Isolation and locking are not the same thing. In fact, to a large degreee, they actually have completely opposite goals and purposes. Transaction isolation aims to isolate or insulate one transaction from other concurrent transactions, such that operations performed in one transaction do not effect (to varying degrees, based on the exact isolation mode employed) operations performed in others. Locking, on the other hand, has essentially the exact opposite goal; it seeks to ensure that certain operations performed in a transaction do have certain effects on other concurrent transactions. In fact locking really has nothing to do with transactions at all except for the fact that their duration is typically scoped to the transaction in which they are acquired and that their presence/absense might affect the outcome of the different transactions. Perhaps, although I cannot say for sure, this confusion comes from the fact that a lot of databases use locking as the basis for their isolation model. But that is just an implementation detail and some databases such as Oracle, Postgres, and the newest SQL Server have very sophisticated and modern isolation engines not at all based on locking.
|
|
|
Showing 1041 to 1045 of 1129 blog entries |
|
|