tag:blogger.com,1999:blog-53913170903406463902024-03-13T14:48:23.603-06:00LightGuard's Random BytesRandom bits of information by a developerAnonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.comBlogger20125tag:blogger.com,1999:blog-5391317090340646390.post-49317698818225590712011-01-28T16:24:00.003-07:002011-01-28T16:27:39.685-07:00Seam Catch Beta 1<p><a href="http://www.seamframework.org/Seam3/CatchModuleOverview">Seam Catch Beta1</a> was released last night! I know it's been a while since I've said anything about Catch and there's been one release between now and the last blog entry, sorry for that. This release is what was scheduled for Alpha4 but we decided to call it a beta and get it setup for inclusion into the Seam 3 bundle beta scheduled shortly. This release is mostly concerned with API changes (the API should now be frozen unless there are bugs found, please see <a href="http://issues.jboss.org/browse/SEAMCATCH">JIRA</a> for more detailed info), but there are couple of features and tweaks that I'd like to highlight:</p>
<ul>
<li>Better alignment with <code>@Observers</code></li>
<li>Modification of execution of handlers</li>
<li>Special considerations for <code>SQLExceptions</code></li>
</ul>
<div id="better-alignment-with-observers"><h2>Better alignment with <code>@Observers</code></h2><p>Exception Handlers are becoming more closely aligned with <code>@Observers</code>, while still retaining the enhancements necessary to support this application; with this release the <code>@Handles</code> annotation can be placed on any parameter of the method! Best practice should still be to place the annotation on the first parameter as it reads a little better, but the following code sample will work just fine:</p><pre class="brush: java">public void trickyParamHandler(@CatchResource SomeCatchResource catchResource, @Handles CaughtException<Throwable> e, SomeOtherResource resource) {
catchResource.performActionForException(e);
resource.someAction();
}</pre>
<p>The other two parameters are injection points and will be looked up using the <code>BeanManager</code>. This follows the CDI spec according to section 10.4.</p></div>
<div id="modification-of-execution-of-handlers">
<h2>Modification of execution of handlers</h2>
<p>See <a href="http://issues.jboss.org/browse/SEAMCATCH-31">SEAMCATCH-31</a> and <a href="http://issues.jboss.org/browse/SEAMCATCH-32">SEAMCATCH-32</a> are extra detail on this change. In short, there has been some confusion about when exception handlers are executed. If your handlers rely on other handlers in the chain being executed in a particular order this very likely is a breaking change. The exception stack is still unraveled and handlers are run against the actual root cause first and Catch moves up the stack from there. The major change is how the type hierarchy for a given exception is used (also note there was an API change here). The way it works now is that any handlers that handle super types of the exception and are marked as <code>TraversalMode.BREADTH_FIRST</code> will be invoked first, followed by handlers marked with <code>TraversalMode.DEPTH_FIRST</code> starting with the actual type of the exception and working up the type hierarchy. This happens for each exception in the stack, however, a handler will still only be invoked once, unless it calls <code>unmute()</code>.</p>
</div>
<div id="special-considerations-for-sqlexception">
<h2>Special considerations for <code>SQLException</code></h2>
<p>For anyone that's ever looked at a stack trace that includes a <code>SQLException</code> and been frustrated at not actually seeing the error from the database, <a href="http://issues.jboss.org/browse/SEAMCATCH-37">SEAMCATCH-37</a> is for you. When unwrapping an exception stack, Catch will also unwrap any underlying <code>SQLException</code> instances using the <code>getNextException()</code> method and add that to the stack. Now you can finally see what your database is trying to tell you without having to debug or add your own catch block!</p>
</div>
<div id="going-forward">
<h2>Going forward</h2>
<p>Core Catch concepts should now be frozen as far as the API goes. We may add additional functions such as filtering a stack trace or other subsidiary features, but they should not affect the core API as it currently exists in this release. If you have a feature request, please add a <a href="http://issues.jboss.org/browse/SEAMCATCH">JIRA</a> ticket. Happy coding!</p>
</div>Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com0tag:blogger.com,1999:blog-5391317090340646390.post-83951205334762760112010-12-08T08:24:00.001-07:002010-12-08T08:26:13.642-07:00Seam Catch Alpha2Over the weekend <a href="http://www.seamframework.org/Seam3/CatchModuleOverview">Seam Catch Alpha2</a> was released! I'm trying to do a two week timebox release cycle for Seam Catch. <a href="https://jira.jboss.org/browse/SEAMCATCH/fixforversion/12315751">Alpha 2</a> contains some minor API changes (some additions, and a couple of renames), a new qualifier and a couple of new objects for better framework integration. The largest of these enhancements is the ability to support <a href="http://docs.jboss.org/weld/extensions/reference/1.0.0.Beta1/en-US/html/servicehandler.html">ServiceHandlers</a>.
<h2>Qualifier changes</h2>
The <code>@HandlesExceptions</code> is no longer a qualifier, this was needed to support <a href="http://docs.jboss.org/weld/extensions/reference/1.0.0.Beta1/en-US/html/servicehandler.html">ServiceHandlers</a>, and is simply a marker anyway. This shouldn't affect users.
<p>We've added a new qualifier <code>@CatchResource</code> to help distinguish resources injected into handlers that are only for Catch use. Here's an example:</p>
<pre class="brush: java">public void logToSpecialCatchLog(@Handles CaughtException<Throwable> e, @CatchResource Logger log)
{
log.warn("Unexpected exception caught: " + e.getException().getMessage());
}
</pre>
It doesn't do much, but this shows that the <code>Logger</code> instance being injected is a special log configured only for Catch. This qualifier can be applied to anything and helps the developer visually see what resources are really being used.
<h2>ServiceHandlers</h2>
This feature is a great feature that really makes exception handling easy. So far we've seen examples of creating handlers with full method implementations, if you're doing something specialized, but repetitive, such as a JAX-RS error response you end up writing the boiler plate code over and over again just to change a few things (the message and the status code). Now you can do this sort of thing with only writing the boiler plate part once, the rest is all declarative, take a look!
<pre class="brush: java">@HandlesExceptions
@ExceptionResponseService
public interface DeclarativeRestExceptionHandlers
{
@SendHttpResponse(status = 404, message = "Requested resource does not exist")
void onNoResult(@Handles @RestRequest CaughtException<NoResultException> e);
@SendHttpResponse(status = 403, message = "Access to resource denied (Annotation-configured response)")
void onNoAccess(@Handles @RestRequest CaughtException<AccessControlException> e);
@SendHttpResponse(status = 400, message = "Invalid identifier (Annotation-configured response)")
void onInvalidIdentifier(@Handles @RestRequest CaughtException<IllegalArgumentException> e);
}
</pre>
There are three handlers right there, nothing else (save the [ServiceHandler][] implemenation) is needed! These handlers all send an error response for a JAX-RS request. They all change the status code returned and the message. What does it take to implement this? Aside from the new annotation (<code>@SendHttpResponse</code>), there's two other classes that need to be written:
<pre class="brush: java">@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@ServiceHandler(ExceptionResponseServiceHandler.class)
public @interface ExceptionResponseService
{
}
public class ExceptionResponseServiceHandler
{
@Inject @CatchResource
private Instance<ResponseBuilder> builderProvider;
@AroundInvoke
public Object processException(InvocationContext ctx)
{
Method m = ctx.getMethod();
if (ctx.getParameters().length > 0 && ctx.getParameters()[0] instanceof CaughtException)
{
ResponseBuilder builder = builderProvider.get();
CaughtException<?> c = (CaughtException<?>) ctx.getParameters()[0];
if (m.isAnnotationPresent(SendHttpResponse.class))
{
SendHttpResponse r = m.getAnnotation(SendHttpResponse.class);
String message = r.message();
if (r.message().length() == 0 && r.passthru())
{
message = c.getException().getMessage();
}
builder.status(r.status());
if (message != null && message.length() > 0)
{
builder.entity(new ErrorMessageWrapper(message));
}
}
else
{
builder.entity(new ErrorMessageWrapper("Unknown error"));
}
}
return Void.TYPE;
}
}
</pre>
Most of this is building up the error from the annotation, but it's only 26 LoC, and you quite a bit of reuse from them. That's all there is to it! Framework integrations should implement some of these for basic things, but you can further create them for yourself if you have some repetitive action that you can extract in your exception handling practices. Look for another release (<a href="https://jira.jboss.org/browse/SEAMCATCH/fixforversion/12315771">Alpha3</a>) in a couple of weeks and a Beta out by the end of the year!Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com0tag:blogger.com,1999:blog-5391317090340646390.post-72220704524502866932010-11-24T09:39:00.003-07:002010-11-24T09:45:21.732-07:00Seam Catch ReleaseSeam Catch Alpha1 was released yesterday! You can read about ithere, or the <a href="http://docs.jboss.org/seam/3/catch/3.0.0.Alpha1/reference/en-US/html_single/">docs</a>. Bits can be found in the <a href="http://repository.jboss.org/nexus/content/groups/public/">JBossrepository</a> using maven:
<pre class="brush: xml">
<dependency>
<groupId>org.jboss.seam.catch</groupId>
<artifactId>seam-catch-api</groupId>
<version>3.0.0.Alpha1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jboss.seam.catch</groupId>
<artifactId>seam-catch-impl</groupId>
<version>3.0.0.Alpha1</version>
<scope>runtime</scope>
</dependency>
</pre>
Or at <a href="http://sourceforge.net/projects/jboss/files/Seam/Catch/">SourceForge</a>. I'm very interested in any feedback that you may have.
<h2>What is Catch?</h2>
Catch is the exception handling infrastructure in Seam3. I like to refer to it as Next Generation Exception Handling. It really goes beyond what was available in Seam2 and offers a complete solution for Exception Handling. It's built on top of CDI events so the entry point is very minimal and usage is quite easy.
<h2>Usage</h2>
For those who are familiar with CDI events, creating your own handlers will be very familiar. Handlers are quite similar to CDI Observers, though there are a few differences:
<ol style="list-style-type: decimal;">
<li>handlers must be contained in a bean marked by <code>@HandlesExceptions</code></li>
<li>the first parameter in the method must be annotated with <code>@Handles</code> and be an instance of <code>CaughtException&lt;T extends Throwable></code></li>
<li>handlers are ordered before they're invoked</li>
</ol>
Keep those things in mind and the rest is very easy.
<h3>Creating a Handler</h3>
The <a href="http://docs.jboss.org/seam/3/catch/3.0.0.Alpha1/reference/en-US/html_single/">docs</a> really cover this very well, but here's a simple handler to get you started:
<pre class="brush: java">
@HandlesExceptions
public class JsfHandlers {
public void redirectingHandler(@Handles(precedence = -100) CaughtException<Throwable> event, NavigationHandler nav) {
nav.handleNavigation(FacesContext.getCurrentInstance(), null, "/error.xhtml");
}
}
</pre>
NOTE: The best way to tie this handler into JSF is by adding a JSF to Catch bridge by creating an <a href="http://download.oracle.com/javaee/6/api/javax/faces/context/ExceptionHandler.html">ExceptionHandler</a> (this will be added to Catch in the next release, as a separate jar) to fire the <code>ExceptionToCatchEvent</code>.</p>
<p>There's not much there as you can see. We're saying this is a general handler (the <code>CaughtException</code> type is <code>Throwable</code>) and we want it run towards the end of the cause container traversal (<code>precedence = -100</code>). If you're not familiar with JSF, this is will navigate the user to the error page at the end of the exception handling. Of course this would require some extra JSF integration pieces to produce the <code>NavigationHandler</code> such as <a href="http://seamframework.org/Seam3/FacesModule">Seam Faces</a> or <a href="https://cwiki.apache.org/EXTCDI/">Apache CODI</a>, or your own producer. The <code>NavigationHandler</code> is injected via CDI, in fact, any additional parameters past the <code>CaughtException</code> param will be injected for you.
Anything that you need for your exception handling, as long as CDI can create it, can be injected for you.
<h3>Entering Catch</h3>
Above I mentioned the <code>ExceptionToCatchEvent</code>. This event is all that's needed to start the handling process. Something as simple as
<pre class="brush: java">
@Inject Event<ExceptionToCatchEvent> catchEvent;
...
try {
your code
} catch (Exception e) {
catchEvent.fire(new ExceptionToCatchEvent(e));
}
</pre>
will get the ball rolling.
<p>That's really all there is to it! I'm looking forward to any feedback you may have, and bugs if you find them. Bugs should be
filled in <a href="https://jira.jboss.org/browse/SEAMCATCH">JIRA</a>. In the next release look for bridges for JSF, JAX-RS and others, and the ability to filter stack traces!</p>Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com2tag:blogger.com,1999:blog-5391317090340646390.post-36424476836610650372010-02-28T23:55:00.005-07:002010-03-06T18:44:57.121-07:00Seam In Depth: Exception Handling Part III would like to thank those who provided feedback for <a href="http://lightguard-jp.blogspot.com/2010/01/seam-in-depth-exception-handling-part-i.html">Part I</a> of this exception handling series.
A special thanks goes out to <a href="http://www.mojavelinux.com/">Dan Allen</a> and <a href="http://www.evolutionnext.com/">Dan Hinojosa</a> for the wonderful constructive feedback.
I'm sure over time these posts will improve and become better.
<p>This entry was originally going to be talking about custom handlers and provide some code; however,
due to family and work factors I have not been able to finish what I wanted for this. Instead we'll be diving
even further into the built-in handlers and providing examples. At the end I'll also give a sneak peek of the
exception handling framework that will make up Part III of this series, hopefully complete in March.
To cut down on the length of this post I've linked to Seam's Fisheye install of the 2.2.0.GA release. With that, let the journey into org.jboss.seam.exception begin!</p>
<h2><a href="http://fisheye.jboss.org/browse/Seam/tags/JBoss_Seam_2_2_0_GA/src/main/org/jboss/seam/exception/Exceptions.java?r=11265">Exceptions</a></h2>
This class (<a href="http://fisheye.jboss.org/browse/Seam/tags/JBoss_Seam_2_2_0_GA/src/main/org/jboss/seam/exception/Exceptions.java?r=11265">org.jboss.seam.exception.Exceptions</a>) is a built in Seam class, all you need to do is obtain a reference to it (either via
injection <code>@In("exceptions") Exceptions</code> or <code>Exceptions.getInstance()</code>) and call the <code>getHandlers()</code> method to add your own exception handlers. Typical interaction is done by adding exception handlers via the annotations or pages.xml. Let's begin the exploration with the <code>initialize()</code>
method where all the initial setup and creation of the built-in handlers happen. Handlers are added in the following order:
<ol>
<li>AnnotationRedirectHandler</li>
<li>AnnotationErrorHandler</li>
<li>Handlers declared in pages.xml</li>
<li>User defined custom handlers (more on this later)</li>
</ol> At first
glance, it appears that an old deprecated way of adding exceptions is first
added, then the exception handlers added via page(s).xml; however, this is not the case as
each of those ExceptionHandlers is added to a list, then added at the end. Just before any
handlers that the user specifies with pages.xml or custom handlers the Seam Debug Page is
added. <blockquote><em>It's important to know that while in debug (typically only development mode) your
annotated exceptions will take precedence over the Seam Debug Page, and nothing after the
debug page will be triggered (the debug page is a global catch all handler).</em></blockquote>
<p>The parsing of the XML files happens in the <code>parse()</code> method which does some basic XML parsing
looking for the exception elements. The class and logging level (if configured) are pulled
from the exception element, and a new ConfigRedirectHandler or ConfigErrorHandler is created
(more on these handlers later). If there is no class attribute specified then a catch-all
handler, that handles Exception.class is created.</p>
<p>The private <code>createHandler()</code> method does the work of pulling additional information about the configured
handler such as
<ul>
<li>ending conversations</li>
<li>redirecting</li>
<li>adding FacesMessages</li>
<li>finding the http error code, etc.</li>
</ul> The correct handler is then created and returned to be added into the list.
</p>
<p>The only other part of this class that has any importance for the developer/user is the
<code>handle()</code> method, which is really just an iterator over the handlers looking for a handler for
the exception which was thrown. Though there is a catch: Nested exceptions are unwrapped and
handled from the bottom up (though in the Seam Debug Page the exception is recreated so you
may need to scroll to the bottom to actually find the real exception). If a long running
conversation is active then the <code>"org.jboss.seam.handledException"</code> object, which is the
exception object, is added to the conversation context. If logging is configured for the
exception handler a log message is added then two events are raised (regardless of logging):
<code>"org.jboss.seam.exceptionHandled." + cause.getClass().getName()</code> and
<code>org.jboss.seam.exceptionHandled</code> allowing a further user extension point if so desired. If
no handler is found then an event is raised (<code>"org.jboss.seam.exceptionNotHandled"</code>) and
the exception is rethrown. Even if this event is observed, (the exception is passed as
a parameter to the observer's method) it will not be able to influence the exception being rethrown.</p>
<p>Any handlers the developer creates and adds to the Exceptions list will be added at the end of
the list (unless the list is manually modified and rearranged, which is allowed).
Depending on the specific
needs of the application this is a great place to add a general catch all handler for the
application (unless a general handler in pages.xml is sufficient). When adding custom
handlers or any handler really, it is important not to create multiple handlers for the same
exception as the first in the list will be called and the list of handlers will terminate
with that handler. </p>
<h3><a href="http://fisheye.jboss.org/browse/Seam/tags/JBoss_Seam_2_2_0_GA/src/main/org/jboss/seam/exception/AnnotationErrorHandler.java">AnnotationErrorHandler</a> and <a href="http://fisheye.jboss.org/browse/Seam/tags/JBoss_Seam_2_2_0_GA/src/main/org/jboss/seam/exception/ConfigErrorHandler.java">ConfigErrorHandler</a></h3>
ErrorHandlers (<a href="http://fisheye.jboss.org/browse/Seam/tags/JBoss_Seam_2_2_0_GA/src/main/org/jboss/seam/exception/AnnotationErrorHandler.java">AnnotationErrorHandler</a> and <a href="http://fisheye.jboss.org/browse/Seam/tags/JBoss_Seam_2_2_0_GA/src/main/org/jboss/seam/exception/ConfigErrorHandler.java">ConfigErrorHandler</a>) are a specific type of ExceptionHandler, they're used to send an HTTP Error
code to the browser, probably more useful when combined with Seam's Web Service or REST integration.
There is not a lot of code to these handlers, in fact, they are only data containers used by the
parent class <a href="http://fisheye.jboss.org/browse/Seam/tags/JBoss_Seam_2_2_0_GA/src/main/org/jboss/seam/exception/ErrorHandler.java?r=11265">ErrorHandler</a> which handles sending the error to the browser. However, they are
great examples of reuse for exception handling, and make for good templates to follow in abstracting
logic in custom handlers. The two sub classes hold <ul><li>the message (if configured)</li><li> the error code number</li>
<li>and the flag to end the currently conversation.</li></ul> All of the logic to make it happen is in the <code>handle()</code> method.
<h3><a href="http://fisheye.jboss.org/browse/Seam/tags/JBoss_Seam_2_2_0_GA/src/main/org/jboss/seam/exception/AnnotationRedirectHandler.java">AnnotationRedirectHandler</a> and <a href="http://fisheye.jboss.org/browse/Seam/tags/JBoss_Seam_2_2_0_GA/src/main/org/jboss/seam/exception/ConfigRedirectHandler.java">ConfigRedirectHandler</a></h3>
The redirect handlers (<a href="http://fisheye.jboss.org/browse/Seam/tags/JBoss_Seam_2_2_0_GA/src/main/org/jboss/seam/exception/AnnotationRedirectHandler.java">AnnotationRedirectHandler</a> and <a href="http://fisheye.jboss.org/browse/Seam/tags/JBoss_Seam_2_2_0_GA/src/main/org/jboss/seam/exception/ConfigRedirectHandler.java">ConfigRedirectHandler</a>) are in the same category as the error handlers: there's not much to
them, and most of the interesting code is in the parent class <a href="http://fisheye.jboss.org/browse/Seam/tags/JBoss_Seam_2_2_0_GA/src/main/org/jboss/seam/exception/RedirectHandler.java?r=11265">RedirectHandler</a>. The
first bit of code in the <code>handle()</code> method is finding the viewId if none was specified
in the handler instance, but it really isn't related to the actual exception handling. Next is the addition of a
defined FacesMessage, ending the conversation (again, if configured), and finally
the redirect.
<h3><a href="http://fisheye.jboss.org/browse/Seam/tags/JBoss_Seam_2_2_0_GA/src/main/org/jboss/seam/exception/DebugPageHandler.java">DebugPageHandler</a></h3>
This is a great handler (<a href="http://fisheye.jboss.org/browse/Seam/tags/JBoss_Seam_2_2_0_GA/src/main/org/jboss/seam/exception/DebugPageHandler.java">source</a>) along with the associated code in the jboss-seam-debug.jar to fully
understand the potential of exception handlers in Seam. The handler is really
the entry point into the debug system in Seam. Java code wise, there's not much
to it, it's a redirect handler that sets some additional parameters for the redirect.
The whole process of Seam Debug really could be it's own blog entry or series of entries.
It's pretty involved: it includes a PhaseListener, a SerializationProvider, and some
custom Introspection. Because it's such a large, involved piece of code, I'll cover it more
fully in a future post, or perhaps a whole series.
<h2>Examples</h2>
<h3>Annotations</h3>
Consistent with the rest of the framework, Seam provides a few Annotations to help with
exception handling, these were briefly explored in <a href="http://lightguard-jp.blogspot.com/2010/01/seam-in-depth-exception-handling-part-i.html">Part I</a>. Here are some examples on
how they're applied to application code.
<pre class="brush: java">@ApplicationException(rollback=true)
@Redirect(message="This item is out of stock")
public class OutOfStockException extends Exception {
...
}</pre>
The <code>@ApplicationException</code> annotation is a mirror of <a href="http://java.sun.com/javaee/5/docs/api/javax/ejb/ApplicationException.html">javax.ejb.ApplicationException</a>
with additional support for ending a conversation. It is also the entry point Seam uses to configure annotation based exception handlers and must be used if the <code>@HttpError</code> or <code>@Redirect</code> annotations are to be used. In this particular example some of the
defaults are used such as not ending the conversation (with the end attribute) and there
is no redirect happening, but the message (which can also take an EL expression for i18n,
or substitution purposes) will be displayed on the page where the exception occurred.
<p>This next example might be useful with Seam's WebService support, it will return an
<a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1">HTTP error code 500</a> (probably not the most useful for the clients, but it's an example, right?).</p>
<pre class="brush: java">@ApplicationException(rollback=true)
@HttpError(code=501)
public class OutOfStockWsException extends Exception {
...
}</pre>
As noted earlier, these two exception handlers (AnnotationRedirectHandler and
AnnotationErrorHandler) are the first two handlers in the list and will be the first called
to handle the exception, if they are capable, as defined by <code>boolean isHandler(Exception)</code>.
The classes use the meta data from the annotations to determine
if the exception can be handled by one of these two classes. Next up is a closer look at
defining the same exception handlers in pages.xml. <blockquote>Exception handlers can only
be defined in the pages.xml, not in the individual page.xml files,
which in my opinion is a bit of a short coming. There could be times when the same exception should
be handled differently for different pages.</blockquote>
<h3>Pages.xml</h3>
Because the handlers for pages.xml are roughly the same handlers, different sub classes but they do the same
as the annotation sub classes, the above handlers could be declared via pages.xml with
the following XML:
<pre class="brush: xml"><exception class="OutOfStockException">
<redirect>
<message>This item is out of stock</message>
</redirect>
</exception>
<exception class="OutofStockWsException">
<http-error code="501" />
</exception></pre>
Pretty simple stuff. These exceptions will follow the annotations in the list (it's worth
noting that each exception that is declared in the XML creates a new instance of the associated
handler, unlike the annotation counterpart). If both were declared in the same application
the annotation ones would be used. Both ways get the job done, and for your own exceptions
it's really just a matter of preference. <blockquote>The pages.xml declaration really lends itself better
for exceptions that cannot be annotated, such as form Hibernate or JPA, please see <a href="http://lightguard-jp.blogspot.com/2010/01/seam-in-depth-exception-handling-part-i.html">Part I</a> for examples.</blockquote>
<p>Part III of this series will demonstrate an exception handler framework that could be plugged into
Seam and will allow chaining for handling (for example send an email or IRC message and create a
bug report for the exception). It should be generic enough to work with Seam, JSF2
(Ed Burns talked about JSF2 Exception handling on <a href="http://www.jsfsummit.com/blog/ed_burns/2009/09/dealing_gracefully_with_viewexpiredexception_in_jsf2">his blog</a>), or even the base JRE (yep, 1.5 added <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.UncaughtExceptionHandler.html">Exception handling</a>). It will be hosted on <a href="http://github.com/LightGuard">GitHub</a>.</p>Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com0tag:blogger.com,1999:blog-5391317090340646390.post-69113227282449819222010-01-31T22:32:00.003-07:002010-03-06T18:47:01.548-07:00Seam In Depth: Exception Handling Part IThis three part entry will focus on the mechanisms Seam provides for handling exceptions gracefully -- both out of the box and extensible. An in depth look at where this happens in the Seam code base and user programmable extension points will be covered in Part I. <a href="http://lightguard-jp.blogspot.com/2010/02/seam-in-depth-exception-handling-part.html">Part II</a> will dive even further and provide examples, and Part III will cover a custom ExceptionHandler implementation.
Exception handling in any large application is something that's typically debated at least once: What does it mean, is it simply logging, what do we show the user, can our framework help etc. etc. All software developers will run into this debate at least once in their career, even if it's as simple as "what should I put in that catch block?"
It's pretty safe to say swallowing exceptions (as a general rule of thumb) is a bad idea. Of course System.out.println(...) or log.error(...) really isn't much better. Typically the user should be informed that something they have done has resulted in an error on the server, and at the very least ask them to try again. We've all seen pages like the following: An error has occurred, please try again. If the error continues, please contact the webmaster / admin / whatever. This is a cop out and typically a sign of poor exception handling. At least the user didn't see that nasty stack trace or the 500 page from the server. If it's being left up to the user to make contact about an error, chances are it won't happen and the development team probably won't hear about it. Enter the debate about handling those exceptions, and being more pro-active about knowing about errors. Covering each of those questions is beyond the scope of this series, but the question about framework help certainly applies!
<h2>Built-in Handling</h2>
Seam proveds a simple, yet robust solution for integrating your exception handling strategy. Two methods exist out of the box for rudimentary handling: <exception> in pages.xml and annotations directly on application specific exceptions. Dan Allen covers these two options nicely in his book <em>Seam in Action</em> section 3.6, (if you don't already own a copy, go get one. It's a life saver) so these will only be briefly reviewed. A third option exists (and the before mentioned options, as well as the powerful Seam Debug page are all built on top of this mechanism) to allow complete customization of display to the end user and actions on the back-end: ExceptionHandler classes.
<h3>pages.xml</h3>
In a basic seam-gen application one will find the following stanzas of XML relating to exception handling:
<pre class="brush: xml"> <exception class="org.jboss.seam.framework.EntityNotFoundException">
<redirect view-id="/error.xhtml">
<message severity="warn">Record not found</message>
</redirect>
</exception>
<exception class="javax.persistence.EntityNotFoundException">
<redirect view-id="/error.xhtml">
<message severity="warn">Record not found</message>
</redirect>
</exception>
<exception class="javax.persistence.EntityExistsException">
<redirect view-id="/error.xhtml">
<message severity="warn">Duplicate record</message>
</redirect>
</exception>
<exception class="javax.persistence.OptimisticLockException">
<end-conversation/>
<redirect view-id="/error.xhtml">
<message severity="warn">Another user changed the same data, please try again</message>
</redirect>
</exception>
<exception class="org.jboss.seam.security.AuthorizationException">
<redirect view-id="/error.xhtml">
<message severity="error">You don't have permission to access this resource</message>
</redirect>
</exception>
<exception class="org.jboss.seam.security.NotLoggedInException">
<redirect view-id="/login.xhtml">
<message severity="warn">#{messages['org.jboss.seam.NotLoggedIn']}</message>
</redirect>
</exception>
<exception class="javax.faces.application.ViewExpiredException">
<redirect view-id="/error.xhtml">
<message severity="warn">Your session has timed out, please try again</message>
</redirect>
</exception>
<exception class="org.jboss.seam.ConcurrentRequestTimeoutException" log-level="trace">
<http-error error-code="503" />
</exception>
<exception>
<redirect view-id="/error.xhtml">
<message severity="error">Unexpected error, please try again</message>
</redirect>
</exception></pre>
The format is pretty straight forward, a fully qualified class is given in the optional class attribute (leaving this out creates a catch-all handler) and the body is as follows from the XSD:
<pre class="brush: xml"> <xs:element name="exception">
<xs:annotation>
<xs:documentation>A Seam exception handler</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" ref="pages:end-conversation"/>
<xs:choice>
<xs:element ref="pages:http-error"/>
<xs:element ref="pages:redirect"/>
</xs:choice>
</xs:sequence>
<xs:attributeGroup ref="pages:attlist.exception"/>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="attlist.exception">
<xs:attribute name="class" type="xs:token"/>
<xs:attribute name="log" type="pages:tf-boolean"/>
<xs:attribute name="log-level" type="pages:loglevel-values"/>
</xs:attributeGroup></pre>
Redirects are the typical body of these XML blocks. FacesMessages can be added to the redirect as well as ending conversations. Typically these are used for exceptions the developer does not create, and therefore cannot be annotated; however, there may be uses for this style of handling with application exceptions. Please note that order does matter. If the catch-all handler is first, none of the other handlers will be used. Each of these entries creates an ExceptionHandler instance which is then added to the chain of handlers, which is covered later in the entry.
<h3>Annotations</h3>
Seam has three annotations to help with exception handling: @Redirect, @HttpError, and @ApplicationException. Only one of @Redirect or @HttpError may be used on an exception. Both allow for an info level FacesMessage to be added via the message attribute. The @Redirect annotation allows input for a view-id to which the user will be redirected. @HttpError simply returns the specified HTTP Error code. The last annotation, @ApplicationException provides the ability to rollback the transaction and end the existing conversation. These annotations are added directly on the Exception class that is created.
Both of these built-in methods are built on top of two classes in Seam: org.jboss.seam.exception.Exceptions and org.jboss.seam.exception.ExceptionHandler. These two classes and their usage make up Seam's infrastructure for exception handling in an application, and provide customization to the developer.
<h2>Extensible Handling</h2>
The above two methods work well for simple cases. What if a team wants to be more pro-active about addressing errors? Could the application send the team emails about exceptions, or create bug tickets, or perhaps create a contextual log entry? This is where the exception handling capabilities of Seam really shine, and the answer to the above questions are all yes!
<h3>ExceptionHandler</h3>
<pre class="brush: java">package org.jboss.seam.exception;
import org.jboss.seam.faces.Navigator;
/**
* An element of the chain that knows how to handle a
* specific exception type.
*
* @author Gavin King
*
*/
public abstract class ExceptionHandler extends Navigator
{
public enum LogLevel { fatal, error, warn, info, debug, trace }
private boolean logEnabled;
private LogLevel logLevel;
public abstract void handle(Exception e) throws Exception;
public abstract boolean isHandler(Exception e);
public boolean isLogEnabled()
{
return logEnabled;
}
public void setLogEnabled(boolean logEnabled)
{
this.logEnabled = logEnabled;
}
public LogLevel getLogLevel()
{
return logLevel;
}
public void setLogLevel(LogLevel logLevel)
{
this.logLevel = logLevel;
}
}</pre>
The contract for this class is pretty straight forward. The only methods that need to be implemented are isHandler and handleException. Of course the isHandler implementation is trivial, and based on the needs of the handler the handleException implementation could be fairly simple as well. Take note that ExceptionHandler is a subclass of Navigator. There are methods defined in that class which may be helpful in some exception handlers.
<h3>Exceptions</h3>
This class is used in the org.jboss.seam.jsf.SeamPhaseListener before and after each phase of the JSF lifecycle and also in the org.jboss.seam.web.ExceptionFilter, wrapping the filter chain, and used again after any redirects that may happen after the filter chain has completed. As Dan Allen described it in <em>Seam in Action</em>: "A try-catch around the [whole request]" (Seam in Action pg. 126).
There's only one method that needs any kind of attention: getHandlers. It returns a list that is used to add or remove ExceptionHandlers as needed. This method should be called in the @Create method, or constructor of any ExceptionHandler. ExceptionHandler classes should also be marked with @BypassInterceptors as there's no need to do bi-jection. A simple POJO, though, will typically suffice.
Exception handling in Seam can be very powerful if used to it's full potential and should be an excellant tool in crafting an exception handler strategy for your application. The next entry in this series will demonstrate a custom exception handler in action.Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com0tag:blogger.com,1999:blog-5391317090340646390.post-46043967832879183802009-09-12T11:31:00.002-06:002010-03-01T14:01:06.769-07:00HornetQ JMS on JettyOver the past few days I've been working on getting HornetQ (<a href="http://www.hornetq.org" title="http://www.hornetq.org">http://www.hornetq.org</a>) to work on Jetty (<a href="http://www.mortbay.org/jetty/" title="http://www.mortbay.org/jetty/">http://www.mortbay.org/jetty/</a>) -- specifically the embedded Jetty that Gradle (<a href="http://www.gradle.org" title="http://www.gradle.org">http://www.gradle.org</a>) uses. I would first like to thank those on the HornetQ irc channel (irc://freenode.net:6667/hornetq) for helping me out and offering advice. Specifically I would like to thank Clebert Suconic and Andy Taylor for looking at some of my code and making suggestions that ultimately led me to this solution. It should be noted that the two solutions I will be discussing here are probably not the only roads to success. I'm quite confident the same could be achieved programmatically by setting up HornetQ in a bean that's loaded at application deploy time or similar fashion.
<h2>HornetQ setup using jetty-env.xml</h2>
Both of my two solutions are using jetty-env.xml to call the needed setup functions for HornetQ. The same could be achieved with jetty.xml if deploying to a standard install of Jetty. More information about these configuration files can be found at <a href="http://docs.codehaus.org/display/JETTY/Configuring+Jetty" title="http://docs.codehaus.org/display/JETTY/Configuring+Jetty">http://docs.codehaus.org/display/JETTY/Configuring+Jetty</a>. In short these files act as an XML means of working with Java objects. Objects can be instantiated, methods called, etc. All that's being done here is calling the methods in the HornetQ API to startup HornetQ in Embedded mode. Below is the jetty-env.xml I used:
<pre class="brush: xml"><?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure id="wac" class="org.mortbay.jetty.webapp.WebAppContext">
<New id="jmsServerManager" class="org.mortbay.jetty.plus.naming.Resource">
<Arg><Ref id="wac"/></Arg>
<Arg>jms/serverManager</Arg>
<Arg>
<New class="org.hornetq.jms.server.impl.JMSServerManagerImpl">
<Arg>
<Call class="org.hornetq.core.server.HornetQ" name="newHornetQServer">
<Arg>
<New class="org.hornetq.core.config.impl.ConfigurationImpl">
<Set name="persistenceEnabled">false</Set>
<Set name="securityEnabled">false</Set>
<Get name="AcceptorConfigurations">
<Call name="add">
<Arg>
<New class="org.hornetq.core.config.TransportConfiguration">
<Arg>org.hornetq.core.remoting.impl.invm.InVMAcceptorFactory</Arg>
</New>
</Arg>
</Call>
</Get>
</New>
</Arg>
</Call>
</Arg>
<Call name="start" />
<Call name="createConnectionFactory">
<Arg>HornetQConnectionFactory</Arg>
<Arg>
<New class="org.hornetq.core.config.TransportConfiguration">
<Arg>org.hornetq.core.remoting.impl.invm.InVMConnectorFactory</Arg>
</New>
</Arg>
<Arg>
<New class="java.util.ArrayList">
<Call name="add">
<Arg>java:comp/env/jms/connectionFactory</Arg>
</Call>
</New>
</Arg>
</Call>
<Set name="context">
<New class="javax.naming.InitialContext">
</New>
</Set>
<Call name="createQueue">
<Arg>testQueue</Arg>
<Arg>java:comp/env/jms/queues/testQueue</Arg>
<Arg></Arg>
<Arg type="boolean">false</Arg>
</Call>
</New>
</Arg>
</New>
</Configure>
</pre>
An instance of JMSServerManager is being created and the needed configuration objects are being created inline in this example. It's very important to make the start call on the JMSServerManager before any other calls on the object to create queues, topics or connection factories are made, otherwise you'll get exceptions in your log saying the server hasn't been started yet. It's also important to make sure the full JNDI names are used. jetty-env.xml is used to bind elements to JNDI for you but because the JMSServerManager will be doing the binding for us I found that the full JNDI name must be used. If programmatic access to the JMSServerManager is needed this is also bound to JNDI for us by Jetty under jms/serverManager -- which doesn't use the full JNDI name because Jetty is handling the binding, a slight bit confusing I know. Work with JMS can now proceed using standard JNDI lookups and JMS code to send and receive messages. All of this code is available at my GitHub repo: <a href="http://github.com/LightGuard/Research---Development--JEE-/tree/hornetq" title="http://github.com/LightGuard/Research---Development--JEE-/tree/hornetq">http://github.com/LightGuard/Research---Development--JEE-/tree/hornetq</a> feel free to check it out, fork it, whatever :)
<h2>HornetQ setup using jetty-env.xml and HornetQ configuration files</h2>
This setup is very similar to one above, only using the HornetQ configuration files. Code is located at <a href="http://github.com/LightGuard/Research---Development--JEE-/tree/hornetq-with-config-file" title="http://github.com/LightGuard/Research---Development--JEE-/tree/hornetq-with-config-file">http://github.com/LightGuard/Research---Development--JEE-/tree/hornetq-with-config-file</a>. Here's the jetty-env.xml file:
<pre class="brush: xml"><?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure id="wac" class="org.mortbay.jetty.webapp.WebAppContext">
<New id="jmsServerManager" class="org.mortbay.jetty.plus.naming.Resource">
<Arg><Ref id="wac"/></Arg>
<Arg>jms/serverManager</Arg>
<Arg>
<New class="org.hornetq.jms.server.impl.JMSServerManagerImpl">
<Arg>
<Call class="org.hornetq.core.server.HornetQ" name="newHornetQServer">
<Arg>
<New class="org.hornetq.core.config.impl.FileConfiguration">
<Set name="configurationUrl">hornetq-configuration.xml</Set>
<Call name="start" />
</New>
</Arg>
</Call>
</Arg>
<Arg>hornetq-jms.xml</Arg>
<Call name="start" />
<Set name="context">
<New class="javax.naming.InitialContext">
</New>
</Set>
</New>
</Arg>
</New>
</Configure>
</pre>
It's much smaller this time as most of the configuration has been moved into the hornetq-configuration.xml and hornetq-jms.xml files (both of which are on GitHub). That's really all there is to it! My next steps will be to get logging of hornetq (and hopefully Jetty) using log4j and same log file as the rest of the application.Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com4tag:blogger.com,1999:blog-5391317090340646390.post-28993422386721365002009-04-28T13:53:00.003-06:002009-04-28T14:19:07.060-06:00Dependency PrimerEvery software project has dependencies: your own resources, your own APIs you've created, third party APIs and projects, etc. We've all had to deal with them at some point in our career. Recently while playing with Gradle (www.gradle.org) I've come to a realization about how they should be handled correctly. In this post, I'll talk about the two most prominent kinds of dependencies, their scopes, and where they fit into an application. I will not be discussing packaging or how the different scopes must be resolved to create a distributable / deployable artifact. Being a Java developer this is seen from within the Java space, but the concepts are universal to all software projects.
<h2>Dependency Types</h2>
There are basically two types or categories of dependencies: first level and transitive. First level dependencies are those resources that your application directly relies upon. Examples of first level dependencies include the language in which the project is written, entities your project directly uses such as an XML parser, images, and classes from a third party project. Transitive dependencies are dependencies of your first level dependencies. An example from the Java world could be commons-logging which is dependent on some logging implementation, commonly log4j or JDK logging. For commons logging the log implementation is a first level dependency, but for your project it's a transitive dependency. Another example may be an SAX XML parser (or any other XML parsing API). The SAX API is used directly by your project and is therefore a first level dependency, but it requires an implementation, possibly Xerces, which would be a transitive dependency of your project.
This definition of dependencies has really been ingrained in me while using and trying Gradle (a build system [yes, another one] written in Groovy). In the past I've used Maven or Ivy (basically as a Maven alternative, but it does much more in the world of dependencies). Maven introduced me to the concept of transitive dependencies and how they fit into it's life cycle and therefore your project's life cycle. I owe a great deal to Maven for introducing me to the concepts, but Maven has a few blemishes (at least I think so) in the way it handles these different types of dependencies. Maven will by default (I don't think you can change this) include all of the transitive dependencies of the same scope in your classpath, which in my opinion, is incorrect. Here's an example taken from JSFUnit:
pom.xml:
<pre class="brush: xml">
<dependency>
<groupId>net.sourceforge.cssparser</groupId>
<artifactId>cssparser</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>xalan</groupId>
<artifactId>xalan</artifactId>
<scope>compile</scope>
</dependency>
</pre>
Dependency Tree:
<pre class="brush: plain">
[INFO] +- net.sourceforge.cssparser:cssparser:jar:0.9.5:compile
[INFO] | \- org.w3c.css:sac:jar:1.3:compile
[INFO] +- net.sourceforge.nekohtml:nekohtml:jar:1.9.9:compile
[INFO] | \- xerces:xercesImpl:jar:2.8.1:compile
[INFO] +- xalan:xalan:jar:2.7.0:compile
[INFO] | \- xml-apis:xml-apis:jar:1.0.b2:compile
</pre>
For this project cssparser, nekohtml and xalan have been configured as first level dependencies, but the effective classpath contains their compile (first level) dependencies as well. If the project relies on these libraries it should state them explicitly and not rely on the crutch of having them as transitive dependencies. Ivy usage can fall into the same problem, but this is not the case in Gradle (at least not without changing the default), which I believe is the correct way of handling first level dependencies. With Gradle the compile scoped (more in the next section) is not resolved transitively, so you'll have compile time errors if you have not declared a needed dependency.
<h2>Life cycle Scopes and Dependencies</h2>
The build life cycle for a software project can be distilled into three phases: compile (if needed), test, and runtime. Test is a little special because it contains two phases itself: testCompile and testRuntime, which are extensions of compile and runtime. So where do the different types of dependencies come into play? Your first level dependencies become your compile dependencies and runtime dependencies are pretty much your compile dependencies with transitive dependencies and a few other things that may be provided for you like container provided dependencies (though, those are arguably transitive dependencies of any third party dependency) such as a messaging provider, an HTTP implementation, transaction support, etc. The test dependencies extend compile and possibly runtime, and add their own dependencies for testing: a testing framework, mocking framework, possibly a slimed down server, and others, which of course would be first level dependencies for your tests.
<h2>Summary</h2>
To recap, there are two different kinds of dependencies: first level and transitive. First level are dependencies needed to build an run your project. Transitive dependencies are those dependencies of your dependencies. A software build life cycle essentially has three phases: compile, test, run. The compile phase should only use your first level dependencies. Runtime extends compile and is resolved transitively. Test extends both compile and runtime (though at different times) and uses its own dependencies as well. I hope this has been informative and helped others understand the relationship and distinction of dependencies and a software project.Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com0tag:blogger.com,1999:blog-5391317090340646390.post-31311138111735797262009-04-23T10:57:00.005-06:002010-03-01T14:01:06.769-07:00JPA Annotation Locations with HibernateJust ran into this one at work. If you're using Hibernate as your JPA provider (not sure if this is true for others, please comment) all of your annotations on the main entity, mapped super class, embedded classes, etc. must be in the same location (either all on the properties or all on the methods). The reason behind it is at <a href="http://stackoverflow.com/questions/305880/hibernate-annotation-placement-question">StackOverflow</a>.
Basically Hibernate expects the annotations to be in the same location as the first @Id it comes across. I experienced weird errors where it was picking up the property which was mapped to a different column on the table so when Hibernate when to validate the schema it blew up. Hope this helps someone.Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com0tag:blogger.com,1999:blog-5391317090340646390.post-59141620803484410022009-04-12T00:57:00.005-06:002009-04-12T02:31:37.299-06:00Ivy Configurations when pulling from a Maven Repository Part II heard about Ivy (<a href="http://ant.apache.org/ivy">http://ant.apache.org/ivy</a>) some time ago, but never really took the time to look into it. After all, I had Maven, and that's what we were using at work. So I really had no incentive to look into it. As I'm sure many of you have found there are some issues with Maven. With all the things it does well, there are a few things where it really falls flat on it's face. How about transitive dependencies for example? Bane of my Maven experience. The standard project layout is very nice, but at the same time it is a hindrance if, for whatever reason, you need to go against it. As most of my readers have seen I'm pretty well entrenched in the Seam camp. Seam does not play well with Maven, or maybe it's Maven that doesn't play well with Seam (Embedded JBoss to be specific, but others have found ways around this [<a href="http://www.google.com/search?q=seamtest+maven&hl=en">http://www.google.com/search?q=seamtest+maven&hl=en</a>, <a href="http://www.seamframework.org/Community/SeamTestCoverageMavencobertura">http://www.seamframework.org/Community/SeamTestCoverageMavencobertura</a>, <a href="https://jira.jboss.org/jira/browse/JBSEAM-2371">https://jira.jboss.org/jira/browse/JBSEAM-2371</a>, <a href="http://www.seamframework.org/Documentation/SeamWithMavenOverview">http://www.seamframework.org/Documentation/SeamWithMavenOverview</a>
to name a few]). For those that have been using Seam with Maven are familiar with not being able to run their Seam tests easily with Maven, unless you know to put your test scoped dependencies first in the pom. There are some other issues I have with Maven, but this is not a post about how much Maven sucks. You can google for those, there are a lot of them; back to Ivy.
A few months ago my friend Dan Allen blogged about dependancy management in a seam-gen project with Ivy (<a href="http://in.relation.to/Bloggers/ManagingTheDependenciesOfASeamgenProjectWithIv">http://in.relation.to/Bloggers/ManagingTheDependenciesOfASeamgenProjectWithIvy</a>), see his post for a decent intro to Ivy. In his code download he was unable to setup the dependencies needed for testing his project. In this post I'm going to explain why Dan ran into problems, the relationship between Maven scopes and Ivy configurations, as well as provide an updated version of his Ivy-ized seam-gen download.
<h2>IVY CONFIGURATIONS</h2>
I believe a little background information about Ivy configurations may be in order. If you're coming from the Maven world they are somewhat similar to dependency scopes and profiles. Because Ant really has no concept of a build life cycle the way Maven does (one of the things I do like about Maven) Ivy doesn't either. So if Ivy configurations aren't really Maven Dependency scopes, what exactly are they? The official Ivy site calls them "views on your module" (<a href="http://ant.apache.org/ivy/history/trunk/tutorial/conf.html">http://ant.apache.org/ivy/history/trunk/tutorial/conf.html</a>). Personally I still find that concept difficult to wrap my head around. The definition I have come up with is this: An Ivy configuration is a labeled grouping of a project's publications and that grouping's dependencies. Perhaps that's similar to the Ivy site's definition, but it helped me understand what was going on, and how to create my own configurations.
Unlike Maven scope names, Ivy configuration names are completely arbitrary, which as you guessed is both a good and a bad thing. It's a bad thing when you go to share your application, module, whatever with someone else and they use it as a dependency. They'll have to see the ivy.xml you created to determine the correct configurations to use. With Maven, we were given the scopes and we couldn't change them. I would suggest defining a company wide set of configurations or at least list the public ones in a README or something if you are distributing your project. You could also use the makepom ant task, and use that to upload to a Maven Repository but that's a different post :)
As I mentioned above, an Ivy configuration may also be used in mapping and tying together dependencies. A full discussion with examples is available at <a href="http://ant.apache.org/ivy/history/latest-milestone/ivyfile/dependency.html">http://ant.apache.org/ivy/history/latest-milestone/ivyfile/dependency.html</a> under the Configurations Mapping section (sorry, they didn't include an anchor for that section). In it's most basic form it looks like this:
<code>conf="my_conf->other_conf</code> which translates to my_conf depends on other_conf. There are some special wild cards and other kinds of mappings you can do, which are in the above link. You can also specify multiple mappings within the same attribute by separating them with a semi-colon. Very handy for say depending on the module itself and also the source. I know it sounds a little odd to depend on the source of a module, but that's how Ivy sees it.
<h2>MAPPING MAVEN SCOPES TO IVY CONFIGURATIONS</h2>
Thanks for humoring me through that long block of text to finally get to the point of this post. As Dan mentioned in his blog post, Ivy can read from Maven repos (very good move on Ivy's part I believe), but in order to do this they have to convert the Maven POM to an Ivy file. When you setup a Maven Repository as an Ivy Resolver within an Ivy settings file there are a couple of attributes which affect the resulting Ivy file (<a href="http://ant.apache.org/ivy/history/latest-milestone/resolver/ibiblio.html">http://ant.apache.org/ivy/history/latest-milestone/resolver/ibiblio.html</a>). The first one is m2compatible, which if you're using a Maven 2 repository is always going to be true. The second attribute, which is true by default if m2compatible is true is usepoms. I can understand why you would select false to conserve bandwidth (although minor), and reduce network traffic (one less call to make) but you do lose some things when it is set to false when Ivy creates the ivy.xml file for the dependency. Below are the same ivy.xml files converted from a Maven repository. The first one is not using the pom:
<pre class="brush: xml"><ivy-module version="1.0">
<info organisation="org.testng" module="testng" revision="5.6"
status="release" publication="20081031232755" default="true">
<configurations>
<conf name="default" visibility="public">
</conf></configurations>
<publications>
<artifact name="testng" type="jar" ext="jar" conf="default"></artifact>
</publications>
</info>
</ivy-module></pre>
<pre class="brush: xml"><ivy-module version="1.0" m="http://ant.apache.org/ivy/Maven">
<info organisation="org.testng" module="testng" revision="5.6" status="release" publication="20071116012303">
<license name="Apache License, Version 2.0" url="http://apache.org/licenses/LICENSE-2.0">
<description homepage="http://testng.org">
TestNG is a unit testing framework.
</description>
<m:maven.plugins>org.codehaus.mojo__dependency-Maven-plugin__null|org.apache.Maven.plugins__Maven-clean-plugin__null|org.apache.Maven.plugins__Maven-jar-plugin__null|org.apache.Maven.plugins__Maven-source-plugin__null</m:maven.plugins>
</license></info>
<configurations>
<conf name="default" visibility="public" description="runtime dependencies and master artifact can be used with this conf" extends="runtime,master"/>
<conf name="master" visibility="public" description="contains only the artifact published by this module itself, with no transitive dependencies"/>
<conf name="compile" visibility="public" description="this is the default scope, used if none is specified. Compile dependencies are available in all classpaths."/>
<conf name="provided" visibility="public" description="this is much like compile, but indicates you expect the JDK or a container to provide it. It is only available on the compilation classpath, and is not transitive."/>
<conf name="runtime" visibility="public" description="this scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath." extends="compile"/>
<conf name="test" visibility="private" description="this scope indicates that the dependency is not required for normal use of the application, and is only available for the test compilation and execution phases." extends="runtime"/>
<conf name="system" visibility="public" description="this scope is similar to provided except that you have to provide the JAR which contains it explicitly. The artifact is always available and is not looked up in a repository."/>
<conf name="sources" visibility="public" description="this configuration contains the source artifact of this module, if any."/>
<conf name="javadoc" visibility="public" description="this configuration contains the javadoc artifact of this module, if any."/>
<conf name="optional" visibility="public" description="contains all optional dependencies">
</configurations>
<publications>
<artifact name="testng" type="jar" ext="jar" conf="master">
<artifact name="testng" type="source" ext="jar" conf="sources" classifier="sources">
</artifact></artifact></publications>
<dependencies>
<dependency org="ant" name="ant" rev="1.6.5" force="true" conf="">compile(*),master(*)">
<dependency org="junit" name="junit" rev="3.8.1" force="true" conf="">compile(*),master(*);runtime->runtime(*)">
<dependency org="qdox" name="qdox" rev="1.6.1" force="true" conf="">compile(*),provided(*),runtime(*),master(*)">
<dependency org="org.beanshell" name="bsh" rev="2.0b4" force="true" conf="">compile(*),provided(*),runtime(*),master(*)">
</dependency></dependency></dependency></dependency></dependencies>
</ivy-module></pre>
The ivy.xml generated with the pom contains much more information, notably more configurations, publications, and dependencies. The configurations that are in the last file are configurations that Ivy places in every ivy.xml which is converted from a Maven POM. You can always rely on them being there if usepoms is set to true. This part, as well as really not understanding Ivy configurations (yes, they are difficult to understand as the official documentation isn't that great for configurations) is where I believe Dan had problems. I suggest always enabling usepoms, because you get everything you would normally if you were using Maven, and it easier to craft your own configurations with dependencies.
In the <a href="http://www.xmission.com/~lightguard/ivy_seam-gen.zip">download</a> (a modified version of what is in Seam 2.1.2) you'll see how powerful this can be for your builds and dependency management with Ivy. If you find / know of a better way to accomplish what I've done, please post a comment and I will make corrections as needed. I hope this helped at least one person better understand Ivy configurations. I spent about a week diving through documentation, forum postings and the Ivy source code to figure this out, I hope you don't have to go through the same experience :)
In the next part I will demonstrate how to use Ivy to manage your dependencies without needing to add them to your source control repository.Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com6tag:blogger.com,1999:blog-5391317090340646390.post-58209660240484628692009-03-28T17:28:00.002-06:002009-03-28T17:33:11.760-06:00Stay At The Hospital<p>I know I said I would blog about Ivy first but we had some other stuff that happened after that last post. My wife started to have really bad pain on her mid-section on Thursday night around 10pm or so that kept intensifying. We were worried it might be her appendix so we went into the ER.
Neither of us really like hospitals but sometimes it's just best to go. Anyway we sat there in the ER room, not the lobby, for about 30 minutes until someone to came see us. I could be wrong, but I don't think they were that busy. The whole point of this post is just to rant about being in an emergency and not being able to get any help. Very, very annoying. We found out that she has gall stones and will need to have her hall bladder out :(
Bad way to end a week, but it's been a bad couple of weeks. Here's to hoping for a better one next week. </p>
<p>Posted with <a href="http://lifecast.sleepydog.net/">LifeCast</a></p>Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com0tag:blogger.com,1999:blog-5391317090340646390.post-2070328087035549392009-03-26T08:36:00.002-06:002009-03-30T23:52:30.901-06:00Future Topic<p>I'm sure my readers have noticed I don't follow any sort of schedule or topic list in my postings, after all I did call it Random Bytes :) One of the postings I plan on doing Real Soon™ is about Ivy and what they call configurations. Unfortunately the documentation really isn't all that clear nor easy to grok. It took me almost a week of looking through examples and reading the docs to really understand how it all works. I'm hoping that by blogging about it someone will be helped. That will probably be one of the next posts I do.
I would like to take a look at Gradle, a build system, yes another one, for Java/Groovy. I saw it before and glanced at it for a sec and was interested in learning more but I haven't had the time yet. My good friend Dan Allen (if you're reading this Dan, I hope you don't mind) had a tweet about it a couple of days ago from when he was at TJSS, that just made me more interested.
I'm still working on the SeamTest man pages, and they're coming along nicely, maybe a few more weeks until I'll have a first draft ready to go.
I'm also trying to fit in some coding on DBunit (dbunit.sourceforge.net) to allow it to handle schema and table creates and drops, something that it is sorely lacking. Judging by the talk on the dev list this will probably be something that goes into a 3.0 release along with some major refactorimg of the code base.
There you have it, a rough outline of things to come on my blog. </p>
<p>Posted with <a href="http://lifecast.sleepydog.net/">LifeCast</a></p>Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com0tag:blogger.com,1999:blog-5391317090340646390.post-49894210722453847262009-03-25T13:25:00.001-06:002009-03-25T13:25:43.106-06:00New Blogging App<p>I'm trying Lifecast to keep my blog up to date with the simple updates. Larger posts will probably be done with the regular web interface or via Google Docs.
If you can't tell I'm very happy with my new iPhone!</p>
<p>Posted with <a href='http://lifecast.sleepydog.net'>LifeCast</a></p>
Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com0tag:blogger.com,1999:blog-5391317090340646390.post-8118294111357240672009-03-25T09:05:00.004-06:002009-03-25T09:10:20.477-06:00Proud iPhone ownerWe bought <span class="blsp-spelling-error" id="SPELLING_ERROR_0">iPhones</span> the other day, so both my wife and I become some of the newest members of the iPhone family. I've played with the iPhone before and was very impressed with how easy it was to use. I really enjoy having it. I think the thing I like the most is having the <span class="blsp-spelling-error" id="SPELLING_ERROR_1">internet</span> with me everywhere! I love it! Now 3G may not be as speedy as I'm used to at work or home, but you couple that with (hopefully) mobile device aware sites and it's really not that bad.
Like any good geek I downloaded the <span class="blsp-spelling-error" id="SPELLING_ERROR_2">Lightsaber</span> application. It's a very, very worthless application, but it's fun :) I also downloaded a couple of Twitter (www.twitter.com/lightguard) applications and it's pretty easy to use so I'm happy there. I am looking for a blogging app (free <span class="blsp-spelling-corrected" id="SPELLING_ERROR_3">preferably</span>, yes I'm cheap) that I can use to update this blog, maybe I'll post a little more frequently.Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com0tag:blogger.com,1999:blog-5391317090340646390.post-61918196647941026582009-02-21T07:30:00.004-07:002009-02-21T08:09:39.631-07:00Web performance benchmarks or the rule of Fast EnoughI recently saw a blog post that listed out performance benchmarks of two presentation layer technologies for Java. The posting probably wasn't as non-biased as it could have been, but that's besides the point, and not the issue of this post. The performance stats were measured in milliseconds from the time a request hit the server to the time it left the server to go back to the user. A stat worth keeping an eye on, right? We want our applications to be fast, of course we need to be focused on how long that request sits on the server processing, don't we?<div>
</div><div>As developers most of us want to squeeze out the last bit of speed we can get from our applications and technologies. We want ours to be the fastest, naturally; and most developers have a tendency to be perfectionists to some degree or another. But is it really necessary?</div><div>
</div><div>Back to the post I read. As I stated the results were measured in milliseconds. Most of recorded data (even in multi-user scenarios, the author did up to 25 concurrent users) points for both technologies were sub second. That's less than one second for a request sitting on the server processing, sounds pretty darn good to me. The author's conclusion (assuming I read it correctly) was essentially technology X should be used instead of technology A because it's faster. Now to the heart of this post: do your users really care about that much of a speed difference??</div><div>
</div><div>When we're dealing with web applications we have to remember that the users are not running this application on their local machines. Each request has to go over through the Interet, which is definitely slower than seeing something on our local development machines, or even on a local network. We also have to keep in mind the user's perception of "slow." That's really what this boils down to. If our users feel the application is sluggish then we should probably look into it. Users of the web don't expect requests to come back instantaneously. Most users are happy with a 5 - 10 second return of their request. If a couple seconds of that is spent processing the request on the server, you're probably good. There are also other considerations on the client's side for perceived web performance, namely the browser being used. How fast does it render HTML, does it wait to display the full page or does it load incrementally, etc ?</div><div>
</div><div>Basically there are a lot of variables that make up the perception of a slow web site. Your best source of knowing if something is slow is your user base, and I'm not just talking about one or two but a sizable chunk of users. If they're saying it's slow, go look into it. If you don't hear any rumblings, don't worry about it. Your site is "fast enough." Also remember web front end technologies that are mainstream are all "fast enough" otherwise no one would use them.</div>Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com2tag:blogger.com,1999:blog-5391317090340646390.post-8696903607156185742009-02-16T22:57:00.003-07:002010-03-01T14:01:06.769-07:00Documenting SeamTestI've decided to start documenting SeamTest both to help out at work, and to contribute to the project. Watch for it on www.seamframework.org I have a <a href="http://docs.google.com/Doc?id=dhm3twkv_12fnjqzsd3">working draft of AbstractSeamTest</a> that people can view. Please comment as you see fit.
I'm also interested in refactoring SeamTest for easy use with Groovy. If anyone has ideas, please post them up as comments and we'll see what we can get going.Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com0tag:blogger.com,1999:blog-5391317090340646390.post-10315530788184542652008-11-02T20:55:00.004-07:002008-11-02T21:32:10.572-07:00Final level 80 rogue buildAfter playing around with variations to the Assassination / Hunger for Blood (<span class="blsp-spelling-error" id="SPELLING_ERROR_0">HfB</span>) build I think I have finally determined the build that I will be using which is actually the same build I saw from an <span class="blsp-spelling-error" id="SPELLING_ERROR_1">Orc</span> Rogue on the closed beta. <a href="http://wotlkwiki.info/talent/rogue.html?tal=00532300535010052010330135100520500300000000000000000005000000000000000000000000000">Here's the link to the build</a>. This is probably the highest raid Damage Per Second (DPS) build, assuming you can keep it up. My current build at level 70 is the same but I only have five points into the combat tree (Dual Wield Specialization). The extra Hit rating, 3% crit and longer Slice and Dice (SnD) times will really help when I hit 80.
You have to watch <span class="blsp-spelling-error" id="SPELLING_ERROR_2">SnD</span>, <span class="blsp-spelling-error" id="SPELLING_ERROR_3">HfB</span>, and Rupture, all of which are <span class="blsp-spelling-error" id="SPELLING_ERROR_4">DoTs</span> (Damage over Time) or effects that last for a duration. The <span class="blsp-spelling-error" id="SPELLING_ERROR_5">SnD</span> is refreshed with Envenom which out does Eviscerate by quite a bit of damage now that it scales with Attack Power (AP) at constant 35% of your AP. Envenom is also a direct damage unlike Eviscerate which must factor in armor. Looking the numbers from <a href="http://www.wowace.com/projects/dr-damage/repositories/wrath-clone/files/">Dr Damage</a> (looks like Rogues are the only one which are completely done) Envenom at 5 Combo Points (<span class="blsp-spelling-error" id="SPELLING_ERROR_6">cp</span>) does about 500 more damage on average than Eviscerate, yeah it consumes your Deadly Poison charges, but it has that nice buff for 1 second per combo point which gives you an additional 15% to apply Deadly Poison, so you can get your five charges back up pretty quickly.
So far (okay just on test dummies as I just <span class="blsp-spelling-error" id="SPELLING_ERROR_7">respecced</span> today) it seems like it should be very fun. I was easily hitting 700 DPS without <span class="blsp-spelling-error" id="SPELLING_ERROR_8">HfB</span> and not really trying all that hard. Granted I'm not in very good gear either, I'm in basically first part Kara gear and my +Hit is actually pretty low, I really need to increase that so I'm at least up to 100% hit preferably 103% so I can always hit on bosses. The next thing to work on is <span class="blsp-spelling-error" id="SPELLING_ERROR_9">Crit</span> rating because the <span class="blsp-spelling-error" id="SPELLING_ERROR_10">HfB</span> is pretty dependent on critical strikes (as I get 2 energy per <span class="blsp-spelling-error" id="SPELLING_ERROR_11">crit</span>). <span class="blsp-spelling-error" id="SPELLING_ERROR_12">Unbuffed</span> I'm only at 21% :( Granted these numbers will change in a raid when I'm fully buffed, so I'm thinking DPS should look pretty good. I was constantly at 1k DPS with my other builds on bosses, so I'm not worried at all. Wrath of the <span class="blsp-spelling-error" id="SPELLING_ERROR_13">Lich</span> King looks like it should be pretty fun, plus the guild is shaping up to be a pretty good raid oriented guild. I'm looking forward to it.Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com0tag:blogger.com,1999:blog-5391317090340646390.post-88132530361186503172008-10-23T21:10:00.003-06:002010-03-01T14:01:06.770-07:00Seam generates IDEA IntelliJ project filesFor those using Seam, you've probably seen the announcement that <a href="http://in.relation.to/Bloggers/Seam210GAReleased">Seam 2.1.0.GA has been released</a>. Work continues at a fast pace for Seam 2.1.1. Dan Allen (Seam in Action author) and I have been working on generating the IDEA IntelliJ module and project files for IntelliJ 8 aka Diana, which has Seam support (check out their <a href="http://www.jetbrains.com/idea/training/demos/seam-development.html">screen cast detailing the support</a>, I think you'll be impressed). The initial versions were just checked in yesterday. The next time you run seam create-project you will have Eclipse, Netbeans and IntelliJ project files. For those that wish to tweak the iml and ipr file they're in the seam-gen/ide-project-files/idea directory. Dan continues to work on seam-gen so stay tuned for more announcements.
There are a couple of minor issues with it, but nothing an experienced IntelliJ user can't deal with (like XSDs for the namespaces in the XHTML pages, setting up the correct JDK, tying together the JPA files with a Datasource, etc). Please download trunk and let us know! Feel free to leave comments on the <a href="https://jira.jboss.org/jira/browse/JBSEAM-3616">JIRA issue</a>.Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com5tag:blogger.com,1999:blog-5391317090340646390.post-41276492314160749902008-10-19T23:07:00.003-06:002008-10-19T23:12:30.279-06:00UPDATE: Current Rogue Build<a href="http://www.worldofwarcraft.com/info/classes/rogue/talents.html?tal=00532310534010052010333105100500500000000000000000000000000000000000000000000000000"><span style="color: rgb(255, 216, 0);">Build up to 70 on Official World of Warcraft page</span></a>.
<script type="text/javascript"> variableIsSite = 1; </script> <script language="JavaScript" src="http://www.worldofwarcraft.com/shared/wow-com/includes-client/detection.js"></script> <script language="JavaScript" src="http://www.worldofwarcraft.com/shared/global/talents/includes/variables.js"></script> <script language="JavaScript" src="http://www.worldofwarcraft.com/shared/global/talents/includes/functions.js"></script> <script language="JavaScript" src="http://www.worldofwarcraft.com/shared/global/talents/rogue/data.js"></script> <script language="JavaScript" src="http://www.worldofwarcraft.com/shared/global/talents/rogue/donotlocalize.js"></script> <script language="JavaScript" src="http://www.worldofwarcraft.com/shared/global/talents/includes/localize.js"></script> <script language="JavaScript" src="http://www.worldofwarcraft.com/shared/global/talents/includes/arraysFill.js"></script> <script language="JavaScript" src="http://www.worldofwarcraft.com/shared/global/talents/includes/printOutTop.js"></script>
As I move closer to 80 my other talent points will go into Close Quarters Combat and Relentless Strikes (or maybe three into CQC and two into Opportunity, not quite sure yet)Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com0tag:blogger.com,1999:blog-5391317090340646390.post-61670671831879790092008-10-07T21:56:00.000-06:002008-10-07T21:59:56.261-06:00Wrath of the Lich King Rogue buildHere's what I'm thinking of for my rogue on WoW:
http://talent.mmo-champion.com/?rogue=00500500300000000000000000000053230053501005201033310515020000000000000000000000000
It's a raiding build as that's what I'd like to focus on in this expansion. I'm also hoping that my guild will focus on raiding as well. I struggle for a while on whether or not to get Relentless Strikes or the Close Quarter Combat talent. I think in the long run this will probably work out better, that way I know I won't hit energy starvation (which was the main thing I wanted to avoid). If someone has a better idea for a deep assassination build I'm all for hearing it.Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com0tag:blogger.com,1999:blog-5391317090340646390.post-37513411615251210642008-10-06T20:20:00.000-06:002008-10-06T20:23:49.275-06:00What to do with a blog?I signed up for this blog mostly for the OpenID, but now I'm being told this could be a spam blog, so I guess I need to post something up here :) This is actually my first blog posting!
I have interests in web development in nearly all of it's forms (I don't do Photoshop or Flash). I'm thinking I'll use this for posting my thoughts about web development. At the current time I'm a Java developer, but I also have seven years of experience with PHP so I may do posts about PHP. I am interested in Ruby and Groovy, so there may be posts about those two languages as well, I hope you enjoy.
There may also be random tidbits about World of Warcraft as I am a pretty avid WoW player.Anonymoushttp://www.blogger.com/profile/02009922943109901588noreply@blogger.com0