First off, I don't know a lot about web design or even the design of these pages in particular. I outsourced the design part, got html files, and am now implementing functionality using JSF 2.0. I don't actually even know what makes the button look like it's supposed to in the first place.
I have code that looks like this:
which outputs something that looks like this:
That is obviously not what it should look like. The button is being rendered as a broken image. But it works perfectly.
If I take away the name attribute of the commandButton and have code that looks like this:
Then I get something that looks like this:
This is what it should look like, but... when I press the button it causes this error:
I have tried taking out the Class attribute and it doesn't do anything. I changed it to styleClass and still no effect at all. The only thing that makes any difference is removing the name attribute (which makes it not work as stated before)
1. Writing your own login code is suicide and I don't care how many J2EE books use a "login page" as an example. I've never run into a user-written security system that couldn't be hacked, usually fairly quickly, and I've been doing J2EE since before they invented JSPs. Use a pre-debugged professionally-designed security framework such as the one that comes standard with J2EE and integrates directly into web.xml.
2. "class" is a reserved word in Java, so in order to reduce conflicts, JSF uses "styleClass" instead.
3. In JSF you don't write Controllers. The Controllers are the FacesServlet and logic in the JSF UIComponents. Backing beans are not Controllers, they are Models.
4. My bleary eyes cannot spot an image tag in your sample View Definition, but apparently you didn't include everything. You should be able to use your browser's source examination features to get the actual URL being requested. If we have that plus the source of the image tag (or CSS), we should be able to un-break it.
5. That last message would see to say that your WAR doesn't contain an OHP-Site/faces/index.xhtml resource. Although come to think of it, that resource path looks a lot like a JSF URL that wasn't configured to route to the FacesServlet. Meaning that your web.xml definitions are not set up properly.
An IDE is no substitute for an Intelligent Developer.
Thanks Tim, especially for touching on some other issues as well.
Regarding the issue at hand, I posted all jsf code on that page. The other code on that page is inconsequential html code. I have no idea where that image is supposed to be. I have looked in the css file, but can't find anything...
Here is the source for that button when the name attribute is present (and therefore works but does not render properly):
Here is the source when the name attribute is not present (and therefore renders properly but does not work):
index.xhtml is the name of the page on which this is all happening and I can get to it fine by going to http://localhost:8080/OHP-Site/faces/index.xhtml, not to mention the error only happens when that button is pressed and doesn't have a name attribute. So there is likely nothing wrong with web.xml.
and for your viewing pleasure, here's the entire css file:
I never liked the "/faces/" URL convention. Aside from making the URL path longer, it makes it too easy for people to confuse URLs and resource paths. I prefer URLs in the form of "http://localhost:8080/OHP-Site/index.jsf".
When you get stuff on a web page that isn't in the View Definition, such as H1-style captions and images, I have to conclude that one of 3 things is happening:
1. You aren't retrieving from the server you think you are or you're not accessing the webapp you think you are.
2. You are retrieving from the right server, but you're retrieving stale data. Which is why when I use Tomcat, I make a point of cleaning out the temp, work and log directories when re-deploying.
3. You are getting you view definition from an intermediary that is decorating it. Most commonly that would be because there was some sort of "tiling" mechanism at work, but custom login processors often muck around with user requests, which means that anything could be happening.
I am certain that 1 and 2 are not issues here. When I make changes to the code and restart the server, that changes are immediately visible, including the name/no name change. Therefore, I am clearly connecting to that server and getting the latest data.
As far as an intermediary, I'm not sure what you mean. My "custom login processor" is one line that returns the String "success" so that the navigation rule in faces-config.xml will send the user off to another page. It doesn't even check what was entered in those fields.
OK. Next question is what does the "success" navigation rule look like. Because if the login screen isn't coming through an interception and it contains text and image items that aren't in the login View Definition, there's almost got to be something tiling it.
Once again, it all works as long as there is a name attribute in that button. If there was a problem with the navigation rule itself, I wouldn't imagine it would ever work at all. By the way, it has nothing to do with the wild card. I just changed it to that.
OK. Then I am going to understand that to mean that the page with the login form that you posted is index.html. Technically, that's the page whose resource path is /index.html and I won't worry about its URL just yet.
The problem I'm having is that the sample View Definition you gave not only seems to lack a graphics tag - whether raw HTML or JSF - but also doesn't match your sample screen in that the sample screen has a boldface large-print page title on it that isn't accounted for on your View Definition.
JSF doesn't just make stuff like that up, so where does it come from?
right. There is nothing like that. If you look at the css file I posted starting at line 199, I think you may find where the graphics are coming from. I know very little about css but it looks to me like that's defining images to use for buttons.
I can work my way towards that, but if you don't have the proper JSF view tags wrapping the h:form, the page will generally neither render nor respond properly, which is why I wanted to see the entire thing and not just the form.
Unless I'm being blind (again ), there is no "name=" attribute for the JSF commandLink tag. However, I do recommend putting 'id=" attributes on your form and input control elements. Otherwise JSF will generate internal automatic IDs that are hard to use for debugging.
Thanks. You don't have f:view tags, although for JSF2 they are no longer mandatory.
I do recommend using explicit id attributes, since like I said, you get more meaningful debug messages.
The broken image is probably because your relative URL was relative to the JSF "/faces/" URL, and CSS shouldn't be going through that. Another reason why I prefer the ".jsf" URL format convention over the "/faces/" convention.
I think that the navigation action is probably the usual confusion between URL paths and resource paths, but we'll look at that tomorrow.
Just to be clear, your navigation rule should look something like this:
Assuming that it does and that your debugger indicates that the JSF Action method named "login" is being successfully invoked, then a blank page would indicate that there is something wrong with the user.xhtml View Definition file. Unlike Struts which can be annoyingly fond of displaying blank pages when there is failure in the form-processing code, JSF normally only presents blank pages when the page definitions themselves are at fault, so replacing this file with a simpler definition usually verifies that you're navigating to the right place. Once you're satisfied with that, you should be able to build up the page a piece at a time.
Are you sure about that first part? I don't think that's the case. Eclipse's built in faces-config editor does not do it that way, and it's hard to believe they would make such an egregious error. I changed it anyway and it made it do all kinds of weird things like ignore the template when redirected. I changed it back to .xhtml in the navigation rule.
Just to be clear, user.xhtml displays fine when I navigate to http://localhost:8080/OHP-Site/user.jsf It also displays fine when redirected there by that form (when the name attribute is present making the form work at all)
It seems to me then unlikely that the definition of user.xhtml is at fault. It's more likely a problem that occurs in the postback before it even tries to redirect?
I'd also like to reiterate that it works fine (but renders wrong) if there is a name attribute in the tag. There is a clue there that seems to be getting ignored. And yes I realize there is no name attribute in commandButton which makes this even more mysterious.
I'm afraid that the Eclipse faces-config editor isn't very impressive. That particular example was snipped from a very old and very functional project. On the whole, in fact, Eclipse support for JSF is less than exciting. I tend to ignore most of what it does provide, although they've apparently finally got a semi-decent approximation to WYSIWYG view definition editing working in Eclipse Indigo. And it actually seems to be working. Even simple XML editing was a problem for longer than I want to recall.
A navigation rule consists of one or more source patterns and a destination URL or "view-id", which is relative to the webapp context root. You can make a rule global by supplying just a target name (for example, "Home"), or you can narrow its scope to a given source view(s) and/or a given action method. Prior to JSF2, I usually defined rules for my actions linked to results of "success", "failure", and occasionally specific types of success or failure, and so my preferred approach was to scope by action method name, since success on one action might not lead to the same destination as success on a different action.
Normally, a code Exception will dump a stacktrace. not a blank page. A botched navigation (misspelled target view id, bad name, usw. would cause the index.jsf to redisplay, since the default is not to navigate. Only a navigation to a page which doesn't render should give a blank page.
Of course, a blank page isn't always really blank, so it's always wise to use the browser's View Page Source function in case there are clues there. I like to put comments in my view templates so that I'll know if the proper view was being processed.
Views that include other views are a specific case where you can be presented with a blank page if the included view has a problem rendering and that particular situation can be a to debug.
In any case, it seems to work fine in general when I leave it as .xhtml, and not work fine if I change it to .jsf so I'll just keep it. I have actually used the *.jsf mapping on the other test projects I made while learning jsf 2.0 and never changed the navigation rules to say .jsf instead of .xhtml and never had an issue.
but I did discover it is not ever invoking the login() method when the name attribute is not present, which is the issue at hand. hmm...
This worked fine when the pages were just html, but something about how jsf rendered it, made this screw everything up. I can't even find where that form() function is and have no idea what it does because everything seems to be working fine by just removing those lines.
By the way, do you have any good places to get started with that J2EE security framework you talked about? The next thing I need to do is actually implement a real login.
Ouch! Nothing worse than finding that everything you thought was OK has been silently sabotaged.
J2EE container-managed security is covered in just about any decent introductory text on J2EE. Unfortunately, they usually then go and confuse the issue by showing a sample app with a user-written login process.
Since even user-designed security systems usually have enough wit to use SSL, there's usually a section on setting up transport security in web.xml. A properly thorough text will then cover URL patterns and roles.
The J2EE standard security system is primarily wrapped around the webapp rather than coded into it. That means that less coding is required and many exploits will be turned away by the server without every being able to interact with application code at all, thereby ensuring that application bugs cannot be exploited.
The heart of this architecture is based on secured URL patterns and security roles, both of which you define and associate in web.xml. If an incoming URL request matches one of the defined patterns, then the server checks to see if the user is logged in. If the user is not logged in, the server intercepts the request, sidelines it, presents the login page defined in web.xml (this must be a straight HTML or JSP form, JSF doesn't work here), then (assuming the user logged in) resumes the sidelined request as though nothing had happened. If the request requires a role that the user doesn't possess, the server rejects the request, instead.
You can also augment this system in application code where needed using the HttpServletRequest method isUserInRole() to query for authorization. I do this, for example, when a URL can handle multiple roles, but only some roles are allowed to update data. Also available on the HttpServletRequest are the userName and userPrincipal properties. userPrincipal isn't much use directly, but it holds the userName, as supplied to the login service. The userName method is a shortcut way to retrieve this.
The actual configuration of userids, passwords and roles is done external to the web application, typically using a plug-in security services provider called a Realm. Most common J2EE servers come with support for many different types of Realms. For example, among those available for the Tomcat server are the MemoryRealm, which is a crude service that uses an XML user/role configuration file and is good for testing, the JDBCRealm, which authorizes and authenticates using a database, and the LDAPRealm, which uses an LDAP server such as Microsoft's Active Directory. The webapp neither knows nor cares which Realm is in use, so it's easy to swap Realms for testing.
Because JSF abstracts the underlying server and transport mechanisms. if you need any of the properties and functions available from the HttpServletRequest, you have to dig through JSF's FacesConfig to get it. Rather than splatter a lot of JSF-specific code all over my webapps, I prefer to isolate this functionality into a security manager object, which can be at session or application scope, depending on whether I want my security manager to hold additional security information of its own or simply statically access the HttpServletRequest security features. So I can say "if ( userSecurity.inRole(UserSecurity.ROLE_AUDITOR)) ...".
One thing to be aware of in JSF, however. The container-managed security system secures URLs, not resources. That's an important thing to know, since in JSF, the URL paths don't always track the resource paths. To ensure that there are no security holes introduced on this account, use the "<redirect/>" navigation element to force the URL to match the resource path.