This blog is mainly about Java...

Wednesday, November 25, 2009

s:convertDateTime

In the Seam documentation there is very little information about this tag.
In the documentation, there is only one example:
<h:outputText value="#{item.orderDate}">
   <s:convertDateTime type="both" dateStyle="full"/>
h:outputText>

This doesn't really say much. However, after some googling, I can explain some of the attributes, and what is actually useful to use.
If you want to show both date and time: dd-MM-yyyy hh:mm:ss you can use type="both" and dateStyle="full". If you want to show only date. Use type="date".

You choose from a range of different dateStyle.
default                   May 14, 2007 2:35:45 PM ( Default Value)
short                     5/14/07 12:55:42 PM
medium                 May 14, 2007 2:42:36 PM
long                      May 14, 2007 2:41:08 PM
full                        Monday, May 14, 2007 2:39:56 PM


However what I have found the most useful is just to use the pattern attribute together with the type.
So if you want the style 14.07.2009 you just write

<h:outputText value="#{item.orderDate}">
   <s:convertDateTime type="both" pattern="dd-MM-yyyy"/>
h:outputText>
And you are set to go! 

Monday, November 23, 2009

Axis 2 gotcha

Just wanted to give a quick GOTCHA I discovered with Axis 2. The other day I wanted to install and use lombok (which is AWESOME by the way).

However lombok needs Java 6 to run, and my WebService was compiled with Java 5, so I changed to Java 6, recompiled, but obviously forgot to recompile the WebService client stubs.
 I didn't get any exception that remotely told me that I had a class version issue. However, I got this exception:
com.ctc.wstx.exc.WstxEOFException: Unexpected EOF in prolog
After reverting back to Java 5, everything worked just fine. So just a heads up.

Friday, November 20, 2009

Seam / Infinispan meetup in Devoxx

So I just returned from the Seam / Infinispan meetup here in Devoxx and there where a few GOTCHA that I will come back to.

Firstly, the meeting it self was pretty awesome. Although I feel that the Seam discussion wasn't that coordinated as the Infinispan talk. There were too much focus on Weld, but I guess thats not surprising since Weld was just recently released, and most Seam developers except poor Norman Richards, where working on Weld to get it finished before the deadline.
Don't take my words literally, Norman might have done some work towards Weld for all I know, but he was at least the only one working on Seam 2.

Anyways, the ones from the Seam team who where present (forgive me if I forget someone) where: Pete Muir, Dan Allen, Norman Richards, Shane Bryzak and Christian Bauer.
Dan held a quick intro on Seam, for the 3 people who didn't know what Seam was, and then Pete talked a bunch about Weld, and finally Dan closed with showing a very cool testing framework which I cannot remember the name of now which will be implemented for Seam 3, and also Rest on Seam. Of course with a lot of Q&A in between.

So finally I got a chance to speak with Dan, Norman and Pete. I really wanted to have a chat with Shane as well, but unfortunaltly by the time I went to get a beer and come back he was gone. :-(
First I got a chance to ask Dan about the strange behaviour I found regarding injection of a stateless EJB in Seam, discussed here , and he confirmed what I suspected all along, that it was infact a bug in Seam. Now, I he didn't actually say "That is a bug" per say, but he did say "If that doesn't work, it is a bug in Seam". But from my experience I can safely conclude that this is a bug in Seam.
Before you say "Hey, why don't you file a JIRA on it", I will tell you why I will not.
After talking with Pete, I discovered that infact there WILL BE NO MORE releases of Seam. Meaning, even if there are any bugs, or even if someone in the community upload a patch, or even some core devel0per fix the bug in the Seam 2.2 branch, there will be no official release of it. You can however checkout a version of that fix and build binaries for your self.
I know, pretty lame and to be honest a big surprise from my part. But Pete did explain why, and the reason is that before shipping an official release, it has to go to the QA team for testing, and probably some other branches and this takes up rescources that JBoss doesn't want to commit to. Instead they want to focus on the development and shipping Seam 3, which is planned to come around march 2010.
So you must ask your self "What about us who are using Seam 2.x and really need to fix this and that issue? Is all hope gone, other than fixing it our selves and running a build?" The answer is no. If you REALLY want something, basically all you have to do, is buy a support deal from JBoss or a certified JBoss partner (as we are), and ask them to fix it. JBoss will then put resources into fixing that and actually commiting the fix in the branch so that it is available for everyone to checkout and build, however, they still will not release a version of that fix. You have to build it your self.

Lastly, this blog post deserves to be mentioning what Seam 3 will look like. Though this is not official or final, it is what I know has been discussed and agreed upon.
Seam 3 will be what is missing from the Java EE 6 stack. Everything thats sort of extra that didn't get into the spec. It will obviously contain all the pdf, rss, excel goodies we are familiar to from Seam 2, including JBPM 4 and Drools 5 support. Not to forget all the goodies that comes with Java EE 6, Bean validation, Servlet 3.0, EJB 3.1, JPA 2 and so on. It will also be modular based, meaning, that if you only need certain parts of Seam, then it is no need to get anything else which is irrelevant to you. There is probably more that I have forgotten, but Pete will blog about this pretty soon.
Lastly, I want to mention that I did try to encourage the people to participate on the seam forums, and help people that are struggling with their Seam 2.x apps. Because face it; those people are most likely to move to Seam 3 and Weld, and if you want them to do that, you should try to make the learning curve of Seam 2.x as little as possible.
Pete did agree, however he did say that the reason why he couldn't reallly encourage the core developers to use more time on the forums is because of all the time they spent on getting Weld finished. 14 hour(!) days jikes. But hopefully in the future, they will have more time to help the users out there.

Good night from Devoxx.

Thursday, October 8, 2009

IE8 bug in Seam 2

There seem to be a problem with IE8 and Seam applications. We are running Seam 2.1, JSF 1.2 and Facelets, and I cannot say for sure where the bug is. For all I know its a bug with IE8.

There seem to be problems when creating long-running conversations. In link using IE8 the cid doesnt appear. Somehow it is stripped or doesn't render correctly, and it causes some strange behaviour.
When trying to create a long running conversation by pushing an edit link for instance, we get a "Your session has timeout" exception.

We fixed this IE8 problem by telling Internet Explorer to emulate IE7 in pages.xml
<page view-id="*">
<header name="X-UA-Compatible">IE=EmulateIE7</header>
</page>

I suggest you do the same until the bug is identified and fixed.

Thursday, August 20, 2009

Using Enum in your entity beans

It is quite handy to use an Enum, especially with type String. This means that the enum will be translated as a text field in your database.

Imagine the following Entity Simple.java:
@Entity
public class Simple {
Process process;

@Enumerated(EnumType.STRING)
public void Process getProcess() {
return process;
}
}

And Process.java:
public enum Process {
WHAT,
THE,
BUCK
}


Now, I initally thought, that since you are defining the enum type to be string, then you can simply query the database using string as well like this:
entityManager.createQuery("from Simple s where s.process=:process").setParameter("process","WHAT").getResultList();
However this doesn't work. You will need to use an Enum type. So the solution is to use Enum.valueOf()
entityManager.createQuery("from Simple s where s.process=:process").setParameter("process",Process.valueOf("WHAT")).getResultList();

Now the query will run and return your list :-)

Tuesday, August 4, 2009

Wicket error in Seam test

The Problem

Recently we upgrade to Seam 2.1.x and suddenly our testng test using ant failed with the following message:
No wicket components directory specified to give Seam super powers to
Wicket was added to Seam 2.1.0.BETA1.
This error message doesn't really say anything. Also it said further:
Must set application-class using  in components.xml 

But we where not using wicket and didnt want to add it.

The stacktrace was as following:
WARN  [org.jboss.seam.wicket.web.WicketFilterInstantiator] No wicket components directory specified to give Seam super powers to
[testng] FAILED: getDefaultContacts
[testng] java.lang.IllegalStateException: Must set application-class using in components.xml
[testng] at org.jboss.seam.wicket.web.WicketFilterInstantiator$1.init(WicketFilterInstantiator.java:107)
[testng] at org.jboss.seam.web.WicketFilter.doFilter(WicketFilter.java:124)
[testng] at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
[testng] at org.jboss.seam.web.HotDeployFilter.doFilter(HotDeployFilter.java:53)
[testng] at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
[testng] at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
[testng] at org.jboss.seam.mock.AbstractSeamTest$Request.run(AbstractSeamTest.java:491)
[testng] at no.whatever.test.AddressBookTest.getDefaultContacts(AddressBookTest.java:18)
[testng] ... Removed 22 stack frames
[testng] FAILED: setup

The Solution


It seems like ant will just put all the libraries in the lib folder in the classpath, and eclipse obviously would not. Thus, when the wicket jars where removed, the tests where back online. I believe it is sufficient to remove jboss-seam-wicket.jar and jboss-seam-wicket-ant.jar, however I just removed all jars that included the name wicket.

Tuesday, July 14, 2009

Injecting checking of roles in Seam

It is well known that you can perform
#{s:hasRole('admin')}
on the view.
You can easily check for the role of the logged in user, by injecting the same thing.

@In(value = "#{s:hasRole('admin')}")
private boolean isAdmin;
If the user has a role of admin the boolean is set to true. You can also use the static method,
Identity.instance().checkRole("admin");

But the former is nicer right?

Sunday, June 28, 2009

Iteration on password is added in JBoss Seam 2.1.2

I blogged about how you could hash your password using Seam 2.1.1 hash-user-password-in-seam-211-manually.

In the latest production release of JBoss Seam 2.1.2 and the @UserPassword annotation, an attribute of iteration is now added with a default of 1000.

We should then modify our GeneratePasswordHash method to the following:

/**
* This method will generate a hash password
*
* @param password
* - The password in cleartext
* @param salt
* - The username is used as salt
* @return - hash password based on password and username
*/
public static String generatePasswordHash(String password, String salt) throws GeneralSecurityException {
char[] passToChar;
byte[] saltToByte;
String thePassword;
try {
passToChar = password.toCharArray();
saltToByte = salt.getBytes();
AnnotatedBeanProperty<UserPassword> userPasswordProperty = new AnnotatedBeanProperty<UserPassword>(ProcessUser.class, UserPassword.class);
// Will get the hash value from annotation UserPassword in ProcessUser.class
PasswordHash.instance().setHashAlgorithm(userPasswordProperty.getAnnotation().hash().toUpperCase());
thePassword = PasswordHash.instance().createPasswordKey(passToChar, saltToByte, userPasswordProperty.getAnnotation().iterations());
return thePassword;
} finally {
// Ensure that the password is not in memory
password = null;
passToChar = null;
salt = null;
saltToByte = null;
thePassword = null;
}
}

Wednesday, June 17, 2009

Review of Seam 2.x Web Development

So I have read the Seam 2.x Web Development
Build Robust Web Applications with Seam, Facelets, and RichFaces, using the JBoss Application Server

This book tries to cover a very very large aspect of Seam and friends.
The book has 11 chapters and almost 300 pages. If you are new Seam, this is a great kick start. Because the book covers a huge portion of the most important aspects of Seam, plus some advanced topics such as Remoting, however I feel that the chapters are too small and that they don't give a thourough and in depth explanation. Many of the examples can be found by googling a bit and reading the documentation of Seam, but this is why it is so good to have a book covering a very large portion of it.

The RichFaces chapter could have been improved alot. Around 30 pages is hardly enough to cover this very big framework. I believe you will get more out of downloading the live examples and looking at the source code and playing around with it instead.

So to sum up, this book is good for someone new to Seam, that want an overview of most of what Seam has to offer, however I would supplement with Seam in Action to cover more ground.

Wednesday, May 20, 2009

New Seam book "Seam 2.x Web Development"

I have been asked to review the new book Seam 2.x Web Development from Packt Publishing

You can buy the book here
and there is also a free chapter "Developing Seam Applications" in PDF here: http://www.packtpub.com/files/seam-2-x-web-development-sample-chapter-2-developing-seam-applications.pdf

I am quite curious as to how this book is compared to Seam in Action by Dan Allen, and I will post my review here as soon as I have read the book.

Sunday, April 26, 2009

My JavaOne 2009 schedule

I am attending JavaOne 2009 this year, and very much looking forward to it. Only one month ahead now.
This is the schedule I have chosen:




Unfortunately, many tracks go simultaneously, but I did put the tracks that I also am interested in, in "My interest"

Tuesday, Jun 02
10:50-11:50Esplanade 307-310, Moscone Remove From Interests Ajaxifying Existing Web ApplicationsSeats Available
16:40-17:40Hall E 134, Moscone Remove From Interests Spring Framework 3.0: New and NotableSeats Available
18:00-19:00Esplanade 304-306, Moscone Remove From Interests Securing Web and Service-Oriented Architectures with Apache Axis, WSS4J, Spring, and OpenLDAPSeats Available
Wednesday, Jun 03
09:45-10:45Esplanade 307-310, Moscone Remove From Interests Extreme Google Web Toolkit: Exploring Advanced Aspects of GWTSeats Available
09:45-10:45Gateway 102-103, Moscone Remove From Interests The Modular Java? Platform and Project JigsawSeats Available
09:45-10:45Hall E 134, Moscone Remove From Interests Upgrading OSGiSeats Available
11:05-12:05Esplanade 304-306, Moscone Remove From Interests RESTful Transaction SystemsSeats Available
11:05-12:05Hall E 134, Moscone Remove From Interests Developing RESTful Web Services with the Java? API for RESTful Web Services (JAX-RS)Seats Available
11:05-12:05Gateway 102-103, Moscone Remove From Interests Modularity in the Java? Programming Language: JSR 294 and BeyondSeats Available
11:05-12:05Esplanade 307-310, Moscone Remove From Interests Ajax Performance Tuning and Best PracticeSeats Available
13:30-14:30Esplanade 307-310, Moscone Remove From Interests Creating Compelling User Experiences Seats Available
13:30-14:30Gateway 102-103, Moscone Remove From Interests "Effective Java": Still Effective After All These YearsSeats Available
Thursday, Jun 04
14:50-15:50Esplanade 305, Moscone Remove From Interests FIRST (For Inspiration & Recognition of Science and Technology): FRC-FIRST Robotic Competition Seats Available
16:10-17:10Hall E 134, Moscone Remove From Interests Keeping a Relational Perspective for Optimizing the Java? Persistence API (JPA)Seats Available

I will see you there!

Monday, April 6, 2009

All unique annotations we are using in our Java EE 5 (Seam 2.1.1 GA and EJB 3 / Hibernate 3) project

Here is all the unique annoations we are using in our project (Seam 2.1.1, Hibernate, JPA, EJB 3 annotations) with a short explanation on each of them.

@AroundInvoke -- To add an interceptor to a bean, you need to write a class with a method annotated @AroundInvoke and annotate the bean with an @Interceptors annotation that specifies the name of the interceptor class.
@Asynchronous -- Specifies that the method call is processed asynchronously.
@AutoCreate -- Specifies that a component will be automatically created, even if the client does not specify create=true.
@Basic(LAZY) -- Tells the entitymanager to lazily fetch the column. This is not needed since that is the default.
@Begin(flushMode = FlushModeType.MANUAL) -- Begins a long running conversation and sets flushmode to manual. Doesnt execute operation until flush() is called.
@Begin(join = true) -- Specifies that if a long-running conversation is already in progress, the conversation context is simply propagated.
@BypassInterceptors -- disable interceptors for the component. Features such as bijection, annotated security restrictions, synchronization and others are unavailable for components marked as @ByPassInterceptors.
@CaptchaResponse(message="#{messages['verificationError']}") -- Tells what kind of message the response of the captcha should be
@CollectionOfElements --hibernate annotation that is used in conjunction with Embeddables.
@Column(length=16777215, nullable=false) -- sets an entity column to 16kb in length and not null
@Column(unique = true) -- Sets this column to be unique
@Create -- Specifies that the method should be called when an instance of the component is instantiated by Seam. Note that create methods are only supported for JavaBeans and stateful session beans.
@DataModel -- Exposes an attribute of type java.util.List to the JSF page as an instance of javax.faces.model.DataModel. This allows us to use the list in a JSF <h:dataTable> with clickable links for each row.
@DataModelSelection -- Annotation that tells Seam to inject the List element that corresponded to the clicked button
@Deprecated -- Marks the method or class as deprecated
@Documented -- Used in conjuction with creating annotations. Will make the annotation available in JavaDoc
@Duration -- Specifies that a parameter of the asynchronous call is the duration before the call is processed (or first processed for recurring calls).
@Email -- Hibernate validator for emails
@Embeddable -- Marks a class as Embeddable
@Embedded -- Classes that are Embeddable will be Embedded in the other class that uses them. IE, Address is embeddable, and is @Embedded in Person
@End -- Specifies that a long-running conversation ends when this method returns a non-null outcome without exception.
@Entity -- Marks a class as an Entity
@Expiration -- Specifies that a parameter of the asynchronous call is the datetime at which the call is processed (or first processed for recurring calls).
@Factory(value="officerAdminContact", scope=ScopeType.EVENT) -- Creates a factory with the name officerAdminContact with a scope of Event.
@Filter(name="orgFilter",condition = "organization_id = :orgid") -- Marks a class as hibernate filter with the name orgFilter, and sets the condition of the filter
@FilterDef(name="orgFilter", parameters = { @ParamDef(type="long", name="orgid")}) -- Hibernate annotation that defines a filter. The name defines which filter should be defined, and sets what kind of parameters the filter has.
@GeneratedValue -- Sets a id to be generated automatically
@Id -- Sets an attribute as Id for the entity
@In(create = true) -- Injects the field and if it is null, it will create the field
@In(required = false) -- Injects the field and tells seam that this field can be null, and will not be created if it is null
@In(required=false, scope=ScopeType.APPLICATION) -- Injects a field and sets the scope to be Application wide
@In(scope = ScopeType.BUSINESS_PROCESS) -- Injects a field and sets the scope to be BUSINESS_PROCESS
@In(value = "#{s:hasRole('sysadmin')}") -- Injects a field with an EL expression that returns true or false. In this example true if the user has role of sysadmin.
@In(value = "org.jboss.seam.bpm.jbpm") -- Injects a seam component that bootstraps a JBPM SessionFactory
@Inherited -- Indicates that an annotation type is automatically inherited. Used in conjunction with creating annotations.(?)
@Install(precedence = Install.APPLICATION) -- The @Install annotation lets you control conditional installation of components that are required in some deployment scenarios and not in others. This is useful if: *You want to mock out some infrastructural component in tests. *You want change the implementation of a component in certain deployment scenarios. *You want to install some components only if their dependencies are available (useful for framework authors). APPLICATION is the default precedence. This is appropriate for most application components.
@JoinTable(name = "ProcessUserRoles", joinColumns = @JoinColumn(name = "userId"), inverseJoinColumns = @JoinColumn(name = "roleId")) - Tells which table and what column should be joined in a table.
@Lob -- Persistence annotation that specifies that the attribute should be a large object.
@Local(ArchivingConnector.class) -- Tells the ejb which interface is the Local. An EJB can use local client view only if it is really guaranteed that other enterprise beans or clients will only address the bean within a single JVM. If this is the case, such access will be carried out with direct method calls, instead of RMI.
@Logger -- Seam's Log4J.
@ManyToOne(fetch = FetchType.LAZY, optional = true) -- Defines which filed is ManyToOne relation, with default fetch size as LAZY and that the field is optional (can be null)
@Name("lostPasswordAction") -- Creates a seam component with the name "lostPasswordAction"
@NamedQuery(name = "applicationprocess.find", query = "select ap from ApplicationProcess ap join ap.organization o where ap.name = :processName and o.name = :orgName") -- Creates a named query with the name "applicationprocess.find" which will execute the specified query. This means that you can call the query like this: entityManager.createNamedQuery("applicationprocess.find").getResultList();
@Namespace(value="http://kommuneforlaget.no/products/saksapp/process") -- Specifies the configuration namespace of a Java package containing Seam components.
@NotEmpty -- NotEmpty checks for not null and empty
@Observer("org.jboss.seam.security.loginSuccessful") -- An observer listens to the following event. In this example it will listen to successfully logins
@Officer -- Custom annotation that defines a class or a method as restricted with the role of Officer
@OneToOne(cascade = CascadeType.ALL) -- One to one relation with all cascading
@Orgadmin -- Custom annotation that defines a class or a method as restricted with the role of Orgadmin
@Out(required = false) -- Outjects the variable in the seam scope event and tell that the object can be null. Similar as request.setAttribute("bestRestaurant", restaurant);
@Out(scope = ScopeType.EVENT, required = false) -- Same as above, because the default scope in Seam is EVENT.
@Out(scope=ScopeType.SESSION, required=false) -- Same as above only the scope is set to SESSION
@Override -- Marks a method as Override. This tells the compiler that this method should override a parent method inherited.
@Parent -- A hibernate annotation that reference the property as a pointer back to the owner (generally the owning entity)
@Pattern(regex="\\D*-\\D+") -- Hibernate validator that checks the value with a regex pattern
@PermissionCheck("upgrade") -- Override the default permission action name (which is the lower case version of the annotation name) with another value. Used in conjuction with custom annotations.
@PostConstruct -- javax.annotation.PostConstruct. Used on a method that needs to be executed after dependency injection is done to perform any initialization. Only one method can be annotated with this annotation. The method MUST NOT have any parameters except in the case of EJB interceptors in which case it takes an InvocationC ontext object as defined by the EJB specification. The return type of the method MUST be void. The method MUST NOT throw a checked exception. The method on which PostConstruct is applied MAY be public, protected, package private or private. The method MUST NOT be static except for the application client. If the method throws an unchecked exception the class MUST NOT be put into service except in the case of EJBs where the EJB can handle exceptions and even recover from them.
@PrePersist -- JPA annotation that will be called right before a persist is done. Similar annotations are: PostPersist, PreUpdate, PostUpdate, PreRemove, PostRemove and PostLoad.
@RaiseEvent("templateHandler.pdf") - If a method is annotated with @RaiseEvent, it will raise an event with the name "templateHandler.pdf" after the method is finished.
@RequestParameter -- Specifies that a component attribute is to be injected with the value of a request parameter. Basic type conversions are performed automatically.
@Restrict("#{s:hasRole('orgadmin') or s:hasRole('sysadmin')}") -- Tells seam that the class can only be used if the role is orgadmin or sysadmin
@Retention(RUNTIME) -- Indicates how long annotations with the annotated type are to be retained. If no Retention annotation is present on an annotation type declaration, the retention policy defaults to RetentionPolicy.CLASS.
@Role(name="asyncReminderAction", scope=ScopeType.EVENT) -- Allows a Seam component to be bound to multiple contexts variables. The @Name/@Scope annotations define a "default role". Each @Role annotation defines an additional role. * Name — the context variable name. * scope — the context variable scope. When no scope is explicitly specified, the default depends upon the component type.
@RoleCheck -- Meta-annotation that designates an annotation as being a role, requiring a security check prior to invoking the annotated method or class.
@RoleName -- Flags an entity field or method as representing the name of a role
@Scope(ScopeType.CONVERSATION) -- Sets the scope to be CONVERSATION
@Scope(ScopeType.EVENT) -- Sets the scope to be EVENT (default)
@Scope(ScopeType.SESSION) -- Sets the scope to be SESSION
@Startup -- Specifies that an instance of this component is created at system initialization time for an application scoped component, or when a session is started for a session scoped component. May only be applied to APPLICATION or SESSION scoped components.
@Stateless -- Component-defining annotation for a stateless session bean.
@SuppressWarnings("unchecked") -- Tells the compiler to suppress warnings of type unchecked. Normally from entityManager.createQuery().getResultList()
@Sysadmin -- Custom annotation that defines a class or a method as restricted with the role of Sysadmin
@Target({TYPE, METHOD}) -- Indicates the kinds of program element to which an annotation type is applicable.
@Temporal(TemporalType.TIMESTAMP) --JPA annotation for date attributes. This will set the timestamp on a variable automatically
@Test(dependsOnMethods = "setup") -- TestNG annotation that defines this test to be dependant on a test called setup, and cant be run until that test is finished.
@Transactional -- Specifies that a JavaBean component should have a similar transactional behavior to the default behavior of a session bean component. ie. method invocations should take place in a transaction, and if no transaction exists when the method is called, a transaction will be started just for that method.
@Transient -- Defines this field to be transient. It will not be stored or serialized.
@UniqueConstraint(columnNames = "{name,organization}") -- JPA annotation that in this case defines that the attributes name and organization together should be unique.
@UserFirstName -- Flags an entity field or method as representing the first name of a user
@UserLastName -- Flags an entity field or method as representing the last name of a user
@UserPassword(hash = "md5") --Flags an entity field or method as representing the password for a user. The hash method that is used is md5 here. However sha is more secure, and "none" is also a valid option, which will not hash anything.
@UserPrincipal --Flags an entity field or method as representing the principal (username) for a user
@UserRoles --Flags an entity field or method as representing the list of role memberships for a user
@Valid -- Hibernate validator that enables recursive validation of an associated object. If used on an field, it will check all the fields validators, ie @Valid Address address = new Address(); will check all the validators of class Adress.
@Validator --Allows a Seam component to act as a JSF validator. The annotated class must be a Seam component, and must implement javax.faces.validator.Validator.
@Version --JPA annotation that specifies the version field or property of an entity class that serves as its optimistic lock value. The version is used to ensure integrity when performing the merge operation and for optimistic concurrency control. Only a single Version property or field should be used per class; applications that use more than one Version property or field will not be portable. The Version property should be mapped to the primary table for the entity class; applications that map the Version property to a table other than the primary table will not be portable.
@WebParam(name="data") --Used with WebServices and is used to customize the mapping of a single parameter to a message part or element.
@WebService -- The purpose of this annotation is to mark an endpoint implementation as implementing a web service or to mark that a service endpoint interface as defining a web service interface. All endpoint implementation classes MUST have a WebService annotation and must meet the requirements of section 3.3 of the JAX-WS 2.0 specification.
@XmlRootElement --Maps a class or an enum type to an XML element. When a top level class or an enum type is annotated with the @XmlRootElement annotation, then its value is represented as XML element in an XML document.
//Example: Code fragment
@XmlRootElement
class Point {
int x;
int y;
Point(int _x,int _y) {x=_x;y=_y;}
}

//Example: Code fragment corresponding to XML output
marshal( new Point(3,5), System.out);

<!-- Example: XML output -->
<point>
<x>3</x>
<y>5</y>
</point>

@XmlSeeAlso -- Instructs JAXB to also bind other classes when binding this class.
Java makes it impractical/impossible to list all sub-classes of a given class. This often gets in a way of JAXB users, as it JAXB cannot automatically list up the classes that need to be known to JAXBContext.
For example, with the following class definitions:

class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

The user would be required to create JAXBContext as JAXBContext.newInstance(Dog.class,Cat.class) (Animal will be automatically picked up since Dog and Cat refers to it.)
XmlSeeAlso annotation would allow you to write:
@XmlSeeAlso({Dog.class,Cat.class})
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

This would allow you to do JAXBContext.newInstance(Animal.class). By the help of this annotation, JAXB implementations will be able to correctly bind Dog and Cat.

Monday, March 30, 2009

Adding html cache on a JSF 1.2 / Seam 2.1.1 application

Adding cache in seam is very easy, and the 2.1.1 release has even made using caching easier.

It is useful to cache html typically when you have lots of hits to the database, otherwise you shouldn't use html cache.

I recently needed to read the current url, extract a part of the url, and check the database for a hit on that pattern. This was done on every request and is something that suits caching. The data I was retrieving was something that was changed very rarely thus it could also be cached infinetly. For this purpose, I have chosen the in-built treecache that ships with JBoss and Seam.

Getting the url from a JSF page can be done like this:
       
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
String uri = request.getRequestURI();
// zero so that trailing empty strings will be discarded
String[] values = uri.split("/", 0);
//Concatinate the string and create a query based on the concatinated string
Now in the xhtml page you will have to write:
<s:cache region="instructionPageFragments" key="instruction-#{instructionHandler.instructionUrl}">
#{instructionHandler.getInstruction()}
</s:cache>
Note that the key must be something unique. In this example the key value will get the current url as a key, and in our web application this is unique, thus works excellent as a key. The s:cache will use the key to retrieve the value from its HashMap.
s:cache uses pojoCache internally, but we want to configure it to use treecache and that is done in components.xml.
You do this by defining the namespace
xmlns:cache="http://jboss.com/products/seam/cache"
and then
<cache:jboss-cache-provider configuration="META-INF/treecache.xml">
Furthermore, we have defined a region on the s:cache called instructionPageFragments. This can be configured in treecache.xml where we can define timeToLive maxAgeSeconds and so on.

<region name="/instructionPageFragments" policyClass="org.jboss.cache.eviction.LRUPolicy">
<attribute name="maxNodes">0</attribute>
<attribute name="timeToLiveSeconds">0</attribute>
<attribute name="maxAgeSeconds">0</attribute>
</region>

A copy of our entire treecache.xml is here:
<?xml version="1.0" encoding="UTF-8"?>

<!-- ===================================================================== -->
<!-- -->
<!-- Sample TreeCache Service Configuration -->
<!-- -->
<!-- ===================================================================== -->

<server>

<classpath codebase="../lib" archives="jboss-cache.jar, jgroups.jar"/>


<!-- ==================================================================== -->
<!-- Defines TreeCache configuration -->
<!-- ==================================================================== -->

<mbean code="org.jboss.cache.TreeCache"
name="jboss.cache:service=TreeCache">

<depends>jboss:service=Naming</depends>
<depends>jboss:service=TransactionManager</depends>

<!--
Configure the TransactionManager
-->
<attribute name="TransactionManagerLookupClass">org.jboss.cache.JBossTransactionManagerLookup</attribute>

<!--
Isolation level : SERIALIZABLE
REPEATABLE_READ (default)
READ_COMMITTED
READ_UNCOMMITTED
NONE
-->
<attribute name="IsolationLevel">REPEATABLE_READ</attribute>

<!--
Valid modes are LOCAL
REPL_ASYNC
REPL_SYNC
INVALIDATION_ASYNC
INVALIDATION_SYNC
-->
<attribute name="CacheMode">LOCAL</attribute>

<!--
Just used for async repl: use a replication queue
-->
<attribute name="UseReplQueue">false</attribute>

<!--
Replication interval for replication queue (in ms)
-->
<attribute name="ReplQueueInterval">0</attribute>

<!--
Max number of elements which trigger replication
-->
<attribute name="ReplQueueMaxElements">0</attribute>

<!-- Name of cluster. Needs to be the same for all clusters, in order
to find each other
-->
<attribute name="ClusterName">TreeCache-Cluster</attribute>

<!-- JGroups protocol stack properties. Can also be a URL,
e.g. file:/home/bela/default.xml
<attribute name="ClusterProperties"></attribute>
-->

<attribute name="ClusterConfig">
<config>
<!-- UDP: if you have a multihomed machine,
set the bind_addr attribute to the appropriate NIC IP address -->
<!-- UDP: On Windows machines, because of the media sense feature
being broken with multicast (even after disabling media sense)
set the loopback attribute to true -->
<UDP mcast_addr="228.1.2.3" mcast_port="48866"
ip_ttl="64" ip_mcast="true"
mcast_send_buf_size="150000" mcast_recv_buf_size="80000"
ucast_send_buf_size="150000" ucast_recv_buf_size="80000"
loopback="false"/>
<PING timeout="2000" num_initial_members="3"
up_thread="false" down_thread="false"/>
<MERGE2 min_interval="10000" max_interval="20000"/>
<!-- <FD shun="true" up_thread="true" down_thread="true" />-->
<FD_SOCK/>
<VERIFY_SUSPECT timeout="1500"
up_thread="false" down_thread="false"/>
<pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"
max_xmit_size="8192" up_thread="false" down_thread="false"/>
<UNICAST timeout="600,1200,2400" window_size="100" min_threshold="10"
down_thread="false"/>
<pbcast.STABLE desired_avg_gossip="20000"
up_thread="false" down_thread="false"/>
<FRAG frag_size="8192"
down_thread="false" up_thread="false"/>
<pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
shun="true" print_local_addr="true"/>
<pbcast.STATE_TRANSFER up_thread="true" down_thread="true"/>
</config>
</attribute>

<!--
Whether or not to fetch state on joining a cluster
NOTE this used to be called FetchStateOnStartup and has been renamed to be more descriptive.
-->
<attribute name="FetchInMemoryState">true</attribute>

<!--
The max amount of time (in milliseconds) we wait until the
initial state (ie. the contents of the cache) are retrieved from
existing members in a clustered environment
-->
<attribute name="InitialStateRetrievalTimeout">20000</attribute>

<!--
Number of milliseconds to wait until all responses for a
synchronous call have been received.
-->
<attribute name="SyncReplTimeout">20000</attribute>

<!-- Max number of milliseconds to wait for a lock acquisition -->
<attribute name="LockAcquisitionTimeout">15000</attribute>


<!-- Name of the eviction policy class. -->
<attribute name="EvictionPolicyClass"></attribute>

<!--
Indicate whether to use marshalling or not. Set this to true if you are running under a scoped
class loader, e.g., inside an application server. Default is "false".
-->
<attribute name="UseMarshalling">false</attribute>


<!-- Specific eviction policy configurations. -->
<attribute name="EvictionPolicyConfig">
<config>
<attribute name="wakeUpIntervalSeconds">120</attribute>

<!-- Cache wide default -->
<region name="/_default_"
policyClass="org.jboss.cache.eviction.LRUPolicy">
<!-- This is the maximum number of nodes allowed in this region. -->
<!-- 0 denotes no limit. -->
<attribute name="maxNodes">0</attribute>

<!-- The amount of time a node is not written to or read (in seconds) before the node is swept away.-->
<!-- 0 denotes no limit. -->
<attribute name="timeToLiveSeconds">0</attribute>

<!-- Lifespan of a node (in seconds) regardless of idle time before the node is swept away. -->
<!-- 0 denotes no limit. -->
<attribute name="maxAgeSeconds">0</attribute>
</region>

<!-- We dont have to define each region if we have default 0 values, but just incase we want to change it later -->

<!--
<region name="/instructionPageFragments" policyClass="org.jboss.cache.eviction.LRUPolicy">
<attribute name="maxNodes">0</attribute>
<attribute name="timeToLiveSeconds">0</attribute>
<attribute name="maxAgeSeconds">0</attribute>
</region>

<region name="/reviewInputPageFragments" policyClass="org.jboss.cache.eviction.LRUPolicy">
<attribute name="maxNodes">0</attribute>
<attribute name="timeToLiveSeconds">0</attribute>
<attribute name="maxAgeSeconds">0</attribute>
</region>

<region name="/actorPageFragments" policyClass="org.jboss.cache.eviction.LRUPolicy">
<attribute name="maxNodes">0</attribute>
<attribute name="timeToLiveSeconds">0</attribute>
<attribute name="maxAgeSeconds">0</attribute>
</region>
-->
</config>
</attribute>


</mbean>


<!-- Uncomment to get a graphical view of the TreeCache MBean above -->
<!-- <mbean code="org.jboss.cache.TreeCacheView" name="jboss.cache:service=TreeCacheView">-->
<!-- <depends>jboss.cache:service=TreeCache</depends>-->
<!-- <attribute name="CacheService">jboss.cache:service=TreeCache</attribute>-->
<!-- </mbean>-->


</server>

Since I want everything to be cached infinetly I have uncommented the regions out and put 0 (no limit) on the _default_ region

You can also programatically add and remove content to the cache.
@In 
private CacheProvider cacheProvider;

//Removing the cache with the region instructionPageFragments, and the key instruction-'current url'
cacheProvider.remove("instructionPageFragments", "instruction-" + url);
//Adding to the cache
cacheProvider.put("instructionPageFragments", "instruction-" + url, "This text will be cached!!");

Friday, February 13, 2009

Hash user password in Seam 2.1.1 manually without using IdentityManager

In the Seam Documentation, they give a minimal schema example of how you can create Users and Roles here: http://docs.jboss.com/seam/2.1.1.GA/reference/en-US/html_single/#d0e9178

As it is explained in the documentation, you can annotate your password with

@UserPassword(hash = "md5")
public String getPasswordHash() { return passwordHash; }
public void setPasswordHash(String passwordHash) { this.passwordHash = passwordHash; }
You could also use
hash= "none"
which doesnt hash the password which is what I did at first. The reason why I didnt start using md5 at once is because you needed a default username and password to be able to log into your seam application. And since I was using an import.sql script that created a default user for me, I had no way of knowing how to hash the password.

So what I needed to do is manually somehow hash a password which I could put in my import.sql script, so that I could enable hashing and correctly log in to my seam application. However this was easier said then done.
I tried changing the @UserPassword(hash="md5") and try to log in, but for obvious reason the login failed, because it was expecting a hashed password.

So then I got the idea to call a method that doesn't require login, which creates a user for us, that is called from a button in the login page. However when I persisted the user, the password was saved as clear text. This baffled me, because I thought that seam would handle that automatically. But if you actually look at the user entity and the setHashPassword method, it is not annotated, and it only sets a string. So it was obvious it only persisted the password as string.
In Seam you can also use IdentityManager to create a user for you. This will perform the hashing for you. So I tried to call
identityManager.createUser("username","password","firstname","lastname");

However, identityManager requires that you are correctly Authenticated, and it threw an exception
org.jboss.seam.security.AuthorizationException: Authorization check failed for permission seam.user,create

So apparently IdentityManager requires the correct permissions, which must be set in your drools setting in security.drl, but I didn't want to do that, since that is not how I wanted to configure my seam application.

So what I did, was look in the seam source and IdentityManager class and find the exact code that performs the hashing for us, and do that manually. And this worked great. Here is the source.

public String saveProcessUser() {
// Check if a new password has been entered
if (currentUser.getPasswordHash() != null && !"".equals(currentUser.getPasswordHash())) {
if (!currentUser.getPasswordHash().equals(passwordVerify)) {
StatusMessages.instance().addFromResourceBundle("admin.wrongPassword");
return "failure";
}
}

// If passwordVerify is not empty, it generally means its a new password
if (!passwordVerify.equals("")) {
String hashPass = generatePasswordHash(currentUser.getPasswordHash(), currentUser.getUsername());
log.debug("Setting new hash password: " + hashPass);
currentUser.setPasswordHash(hashPass);
}

if (getCurrentUser().getId() != null) {
entityManager.flush();
} else {
entityManager.persist(currentUser);
}

FacesMessages.instance().addToControlFromResourceBundle("successMessage", "admin.user.saved");
return "success";
}

/**
* This method will generate a hash password
*
* @param password - The password in cleartext
* @param salt - The username is used as salt
* @return - hash password based on password and username
*/
private String generatePasswordHash(String password, String salt) {
AnnotatedBeanProperty<UserPassword> userPasswordProperty = new AnnotatedBeanProperty<UserPassword>(ProcessUser.class, UserPassword.class);
// Will get the hash value from annotation UserPassword in ProcessUser.class
String algorithm = userPasswordProperty.getAnnotation().hash();
return PasswordHash.instance().generateSaltedHash(password, salt, algorithm);
}


Note that the method saveProcessUser() is called from the user administration form, and the currentUser object is my User entity. Seam will inject all the methods for us, so we dont have to do that. So we check if the verifyPassword is set and correct and then we hash the password. If the @UserPassword is set to something other than none, then it will correctly save a user and you can finally copy the hashed password in your import.sql script.

PS: You first should have the @UserPassword(hash="none") and then go to your user registration and then just print out what the password is, and then copy that to your import.sql script. When the authentication correctly works with either md5 or sha, then you can safely add the user to the database.

Wednesday, February 4, 2009

How to create and use a WebService with Axis 2 and Seam 2.x in JBoss 4.x

In this example, I will show how you can create a Webservice using Axis 2.
First of all, download the latest version of Axix 2 from http://ws.apache.org/axis2/

To create a WebService in Java EE 5 you can use the annotation @WebService.
We also annotate this class as a seam component so that we can incorporate it in our existing business logic.

This is our WebService:

package somepackage.webservice;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.persistence.EntityManager;

import org.jboss.seam.Component;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.security.Credentials;
import org.jboss.seam.security.Identity;

@Name("fooService")
@Stateless
@WebService(name = "FooService", serviceName = "FooService")
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL, parameterStyle = SOAPBinding.ParameterStyle.WRAPPED)
public class FooService implements FooServiceLocal {

@In EntityManager entityManager;

@In Credentials credentials;

private boolean login(String username, String password) {
credentials.setUsername(username);
credentials.setPassword(password);
Identity.instance().login();
return Identity.instance().isLoggedIn();
}

private boolean logout() {
Identity.instance().logout();
return !Identity.instance().isLoggedIn();
}

@WebMethod
public List<FooCanonical> getFoo(@WebParam(name = "username")
String username, @WebParam(name = "password")
String password, @WebParam(name = "orgnumber")
String orgnumber) {
// orgnumber can be null!
if (username == null || password == null) {
return null;
}
//First thing we do is to login to ensure that the user has the correct username/password
//We are using basic seam login method
boolean isLoggedIn = login(username, password);

if (isLoggedIn) {

List<FooCanonical> returnList = new ArrayList<FooCanonical>();
//Do some stuff with the list
//Remember to log out
logout();
return returnList;
} else {
// Probably wrong username password
return null;
}
}

}


Next what we need to do, is create a way for this webservice to interact with JBoss through our SOAP definition. We do that by creating a xml file called
standard-jaxws-endpoint-config.xml

<jaxws-config xmlns="urn:jboss:jaxws-config:2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="urn:jboss:jaxws-config:2.0 jaxws-config_2.1.xsd">
<endpoint-config>
<config-name>Seam WebService Endpoint</config-name>
<pre-handler-chains>
<javaee:handler-chain>
<javaee:protocol-bindings>##SOAP11_HTTP</javaee:protocol-bindings>
<javaee:handler>
<javaee:handler-name>SOAP Request Handler</javaee:handler-name>
<javaee:handler-class>org.jboss.seam.webservice.SOAPRequestHandler</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</pre-handler-chains>
</endpoint-config>
</jaxws-config>

And place this file in the $JBOSS_HOME/resources/META-INF directory.
Now you are done! Deploy your application and look in
http://localhost:8080/jbossws/services 
and see if your WebService is correctly deployed and the wsdl available.
This should look something like this:

Endpoint Namejboss.ws:context=foo-foo,endpoint=FooService
Endpoint Addresshttp://localhost:8080/foo-foo/FooService?wsdl

Next, we will use the Axis2 framework to create client stubs by using axis2-1.4.1 and the script wsdl2java. Navigate to $AXIS_HOME/bin and type in the following command:
./wsdl2java.sh -uri http://127.0.0.1:8080/foo_foo/FooService?wsdl -o build/client

This command will create an ant script under the directly build/client.
Now go to build/client and type ant after setting $AXIS_HOME. This will generate FooService-test-client.jar which we now can use to retrieve data from the WebService in the client. I recommend changing the name to something more appropriate.

In your client, you can call the getFoo WebMethod like this:

FooServiceStub stub;
GetFoo getFoo;

stub = new FooServiceStub();
getFoo = new FooServiceStub.GetFoo();
getFoo.setUsername("username");
getFoo.setPassword("password");
getFoo.setOrgnumber("1234");

FooServiceStub.GetFooE fooImpl = new FooServiceStub.GetFooE();
fooImpl.setGetFoo(getFoo);

//Retrieve the List as an array
FooCanonical[] get_return = stub.getFoo(fooImpl).getGetFooResponse().get_return();
//Do what you want with the array

Note that even if you return a List from the WebService, you will get it as an array. But it is quite easy to put it in a List in the client afterwards. Also remember that the username and password is sendt in clear text, so you might want to send it through https, so it is encrypted.

Labels