Re: Number translator message in 4.1
I agree with Sam's points. The new default messages will be more confusing to end users and should be reverted, for all of the reasons Sam mentions. -Ryan On Dec 1, 2006, at 6:06 PM, Sam Gendler wrote: +1 for new extended default messages! It is worth wading through a sea of PMs to save development stress. This is why I like HLS and Tapestry. ... No (mostly no) cryptic error messages! You are replacing developer stress with end-user stress. Upir average end user will not have a clue how to parse a standard Java format mask and presenting one to them will only confuse them. It helps a developer, sure, but applications are for end-users, not developers. You always have the option to include a more detailed message if you care. In the context of going from one 4.x release to another 4.x release, I don't think it is appropriate to include _unnecessary_ features that make the codebase lose backwards compatibility. Admittedly, Tap 4.1 really should be labelled tap 5, given the volume of changes to the api, but so long as it is labelled 4.1, I think an effort should be made to keep changes limited to things that don't destabilize the api unless absolutely necessary. In this case, we are talking about adding end-user visible features that are really only usable, in their default form, by developers. At least the old message could be used in an end-user visbile location. Now, every single validator will require a custom message override, either to restore the functionality of 4.0.x or to provide a message that isn't going to confuse the hell out of a non-technical end user. Sure, the new message is better for a developer when debugging, but since when does convenience stop with the developer rather than the end-user? At least give developers an override that will restore the original messages (Isn't hivemind supposed to make this easy?). Sure it is more work for the framework developers, but that's the point of a framework - to centralize the development effort in the framework itself, making it easier for users of the framework to utilize the provided functionality and cutting down on the total number of developer hours required to develop code. API changes like this are creating unnecessary work for the framework users, which kind of defeats the purpose of using a framework. The effort required to port an application of any complexity from 4.0.x to 4.1 is already very large. I think an effort should be made to keep such changes to a minimum or provide a backwards compatibility layer, preferably one that can be applied on a per-page basis so that migration can be gradual, if at all possible. I don't know about your projects, but this isn't just a matter of getting permission from a PM to change the message. No PM with even the slightest regard for an end user would let a message with a format string specified as a standard java format mask be visible to a non-developer user. If they wanted a message that included the correct format, they would specify it in a form that makes sense to a non-technical user - almost certainly using an example value rather than a format mask - Imagine a european user seeing $#,##0.00 in their error message. Commas and periods would be inverted, the currency symbol is not correct, and what the hell are those '#' symbols doing in there anyway? A change along these lines that would be actually useful and an improvement for the application user, would be the ability to specify an example value and have the validation mask applied to it automatically before it is inserted in the default error message. That way, I could show a european formatted example to european users, and a US formatted one for US users, all while still using the default error message. Now THAT would be useful, and would probably make it past the PM team without requiring a change. THe format mask by itself is useless to anyone but the developer, and you are only getting that by inconveniencing the majority of your current users. A message that is lacking in some information is often preferable to one that contains useless or confusing information, which is how the format mask would be perceived by most end users. It is worth remembering that, while the end user for Tapestry can often be considered the developers who use it, you also have to factor in the audience of users who will use apps developed on Tapestry by those developers. This is a classic example of windows error message syndrome. An error of type 0x34FD56ABC has occured while processing your input, while useful to a developer, is actually much more frustrating to an end user than An error has occured while processing your input. Obviously, the ideal is to tell them EXACTLY what went wrong and how to fix it, but failing that, a good design should probably prefer the latter message to the former. For me, it is becoming increasingly difficult to justify our use of Tapestry, except that we are stuck with it short of
Re: How do I override the stale session and links pages
Nevermind, looks like Andreas and Thomas answered your question. Although I have to say that overriding the page names in your hivemodule file seems like a cleaner approach than hiding the default pages in your .application. My guess is that you were running into a page resolution issue in your first attempt and Tapestry couldn't find your custom pages (?). I'll find out for myself soon enough since I have to do the same thing in a week or two... -Ryan On Oct 19, 2006, at 9:08 AM, Mats Henricson wrote: Hi! I've spent too much time trying to figure out how this is done in Tapestry 4. I found this suggestion on the net: contribution configuration-id=tapestry.InfrastructureOverrides property name=exceptionPageNamevalue=GeneralError/ property name=staleSessionPageName value=StaleSessionError/ property name=staleLinkPageNamevalue=StaleLinkError/ /contribution The exception page works fine, but the stale session/link does not. Does the accompanying Java page file need to extend a specific base? I need no dynamic info displayed on my stale pages, just static text, so I'd assume it would be a no-brainer. Any suggestion? Mats - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: LoginPage problem in T4
I'm not familiar with that exact error but if that pageValidate method is in your Login page (or it's superclass, etc.), then you're creating a sort of recursive condition where activating the Login page when the user is not logged in will redirect back to the Login page. The Vlib app uses @Meta annotations to specifically mark the Login page as anonymous and the pageValidate() method is supposed to allow access in that case rather than redirect. The above may be way off base since I can't see your superclass or more of your code... -Ryan On Oct 17, 2006, at 12:11 PM, Denis Souza wrote: Hi, I'm trying to implement a login page using VLib's mechanism so I implemented PageValidationListener in my page's superclass with the following: public void pageValidate(PageEvent event) { if (!isUserLoggedIn()) { LoginPage login = getLoginPage(); login.setCallback(new PageCallback(this)); throw new PageRedirectException(login); } } Very simple. Actually looks just like the VLib example, however I'm getting the following exception before I get to the login page: A validate cycle during page activation was detected: LoginPage; LoginPage. Anyone knows what it means and how to fix it? I even tried using the PageBeginRenderListener instead but what happens is the PageRedirectException actually gets thrown! It's not caught by tapestry and the page is not redirected. Any ideas? Thanks Denis - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Component resolution question
On Oct 16, 2006, at 2:13 PM, andyhot wrote: Here's another: I've seen (and even written) components that provide nicer gui on top of contrib:Table. They all usually define the same component class as contrib:Table does... Interesting, that's the use case I couldn't think of ;) I actually do the same thing (override some contrib components but reuse the class) and still couldn't come up with it. Must... read... more... slowly -Ryan - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: problem with images
Assuming you're talking about user uploaded images or something similar, there are of course different opinions on the best way but here are my thoughts: 1.) You are absolutely right not to store uploaded images in the application directory. They are external data just like data in a database. 2.) As far as actually storing BLOBs in the DB, it's definitely worth considering. The pros are a lack of synchronization issues between records that represent image files with the actual files on disk and of course not having to deal with the file system period (no unique file name issues, images get backed up with the rest of your data, etc.). The cons are a lack of standardized access (or no access) to BLOBs through O/RM frameworks, varying support among RDMS's / JDBC drivers, and performance overhead. If you're building a high-volume site, you really want to be able to serve images from a dedicated media server like a stripped-down Apache, Boa, kHTTPd, etc. and you can't easily do that if your images are in a database. As much as I like the idea of storing images directly in the database, I've always ended up using objects/records that represent files (via a relative file path + a global root path) and storing the files themselves in a directory structure outside the application. 3.) Buy Kent Tong's book, Enjoying Web Development with Tapestry and read the chapter on building an image upload/download service. It's really not very hard, but it's too much to squeeze into an email. HTH, -Ryan On Oct 17, 2006, at 5:54 PM, Gabriel Lozano wrote: Hi all I want some help on this issue: I want to know which is the best way to work with images. If I saved them on a folder inside the application, the next time I deploy the application I will loose all the images. I was thinking on saving them in the db, but I dont know how can I retrieve them and show them in the html. If I generate a temp file per request, then I will end up with a file representing an image for everytime the image is requested. Any help would be welcome, I was looking for this and I didnt find anything on this topic. Gabriel Lozano M. - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Component resolution question
Hi Patrick, I was referring to the class resolution ambiguity you encountered in your Navigation example. Had you specified the 'type' parameter, you would be forced to indicate whether you meant 'Navigation' or 'members/Navigation'. Specifically, I was talking about the ambiguity in the component resolution logic in ComponentAnnotationWorker when you don't specify a 'type' parameter. If you look at the ComponentAnnotationWorker source, you can see that Method.getReturnType().getSimpleName() is used to guess the component type if the 'type' parameter is an empty string. It's sort of a best effort approach, apparently provided as a convenience for those cases where the 'type' parameter is completely redundant with your method's return type. As Andreas mentioned, many components have BaseComponent as their class. Obviously, Tapestry cannot resolve a method return type of BaseComponent to a specific component. In those cases, the behavior is so ambiguous that it's useless. Even when your component has a specific class, you could conceivably have situations where your Tapestry component type differs from the return type of your @Component annotated method (although I can't honestly think of a use-case that makes good sense, even with a component class hierarchy). Having said all that, 'type' is indeed redundant in many cases and it would be great if it there was a better way. In the meantime, I would actually prefer to have only one way to specify the type of a component (not that I'm really complaining about the current component type guessing behavior -- I just probably won't use it). In short, getting rid of the 'type' parameter or significantly changing component resolution logic seems more like a Tap 5 thing and I'm more interested in seeing 4.1 stabilize. Regarding Eclipse refactoring, the 'type' parameter's value does not need to be fully qualified to be detected. For example, the type parameters in the following @Component methods will be updated correctly if you check the Update textual occurrences in comments and strings box: @Component(type = FlushLiquidSystem, bindings = poolSet=prop:poolSet) public abstract FlushLiquidSystem getFlushLiquidSystem(); -- or -- @Component(type = directoryThatDoesNotMatchThePackageName/ FlushLiquidSystem, bindings = poolSet=prop:poolSet) public abstract FlushLiquidSystem getFlushLiquidSystem(); I'm using Eclipse 3.2 and this works for @InjectPage annotations as well. It's obviously not as robust as regular type refactoring and you have to pay attention to the preview, but it does make the process pretty easy. Let me know if your experience is different, because this is an extremely handy feature. I don't mean to dampen your enthusiasm to make improvements and I think everyone has noticed that 'type' feels oddly redundant. It's just that it makes sense when you step back and realize that a Tapestry component type is not the same as Java type, except when it is ;) -Ryan On Oct 16, 2006, at 10:22 AM, Patrick Moore wrote: Hi Ryan -- Eclipse can look for fully specified names but 'members/Navigation' isn't fully specified. The component specification looks like: @Component(type=member/Navigation) public Navigation getNavigation(); (FYI, in my example I was only giving the full flassname for illustration only) You talk about the ambiguity if the 'type' parameter isn't specified. What ambiguity are you refering to? I haven't encountered a single example of such ambiguity yet. The only case I have heard of is the template-only components. But that isn't an issue for me as those components I specify anonymously in my html template. So in my situation, the type parameter is merely a source of run-time bugs when Tapestry can find a component. -Pat On 10/14/06, Ryan Holmes [EMAIL PROTECTED] wrote: Actually, eclipse will pick up @Component 'type' values during refactoring if you check the Update textual occurrences in comments and strings option when you rename a component class. The bug you illustrate is a good example of why the type parameter should be required, at least for the time being. If the @Component annotation worker could resolve class names as you expect, perhaps making 'type' optional would be nice. Of course, you also wouldn't need to do : @Component public abstract com.transparentpolitics.core.web.components.members.Navigation getNavigation(); as it's no different than: import com.transparentpolitics.core.web.components.members.Navigation public abstract Navigation getNavigation(); I think there are more important things to be done in Tap 4.1 and I prefer the predictable behavior of the 'type' parameter (which, as I mentioned, is refactorable in Eclipse) over the more elegant but potentially ambiguous behavior that arises when omitting 'type'. Just my $.02 -Ryan On Oct 13, 2006, at 10:19 AM, Patrick Moore wrote: I would vote just
Re: Component resolution question
Actually, eclipse will pick up @Component 'type' values during refactoring if you check the Update textual occurrences in comments and strings option when you rename a component class. The bug you illustrate is a good example of why the type parameter should be required, at least for the time being. If the @Component annotation worker could resolve class names as you expect, perhaps making 'type' optional would be nice. Of course, you also wouldn't need to do : @Component public abstract com.transparentpolitics.core.web.components.members.Navigation getNavigation(); as it's no different than: import com.transparentpolitics.core.web.components.members.Navigation public abstract Navigation getNavigation(); I think there are more important things to be done in Tap 4.1 and I prefer the predictable behavior of the 'type' parameter (which, as I mentioned, is refactorable in Eclipse) over the more elegant but potentially ambiguous behavior that arises when omitting 'type'. Just my $.02 -Ryan On Oct 13, 2006, at 10:19 AM, Patrick Moore wrote: I would vote just the opposite way. In this case I am returning the exact type that is declared on the abstract method. I am not returning a BaseComponent. I hate the 'type' parameter. It interfers with refactoring because eclipse doesn't know it should do anything with the type parameter. So far 100% of the times where I had to specify the type hasn't needed any clarification. The coding style I am using means that I never use the .jwc/.page files, only annotations. The current behavior points out a Tapestry bug as well. 1. Declare a method: @Component public abstract com.transparentpolitics.core.web.components.members.Navigation getNavigation(); 2. Declare the classes: com.transparentpolitics.core.web.components.members.Navigation and com.transparentpolitics.core.web.components.Navigation 3. Declare the component-class-packages: meta key=org.apache.tapestry.component-class-packages value=com.transparentpolitics.web.components/ If Tapestry looks at the com.transparentpolitics.core.web.components.members.Navigation class file, it can see that it has been annotated correctly and it should chose the class, com.transparentpolitics.core.web.components.members.Navigation, not com.transparentpolitics.core.web.components.Navigation. However, Tapestry gets really wigged out and throws this exception: Property navigation has already been accounted for by the element at Annotation @org.apache.tapestry.annotations.Parameter(cache=true, defaultValue=, required=true, name=, aliases=) of public abstract com.transparentpolitics.web.components.member.Navigation com.transparentpolitics.web.components.member.NonflowBorder.getNavigat ion(). -Pat On 10/13/06, Norbert Sándor [EMAIL PROTECTED] wrote: If this causes confusions , i'm 100% for making type required again. I would vote a +1 for changing type back to required, mainly because of new users. Discarding type results in less readable code for example when compared to omitting @InjectObject, which has a more implicit meaning. So, in a word, Tapestry cannot use the class name (neither the simple nor the full) This may not be evident for new users, especially when they read in the docs that Tapestry supports pure-java, annotation-only components... IMO Regards, Norbi andyhot wrote: Patrick Moore wrote: To my untrained eye, it looks like the problem is that the _componentResolver on line 390 of org.apache.tapestry.pageload.PageLoader doesn't have the full class name. On 10/12/06, Patrick Moore [EMAIL PROTECTED] wrote: Hi there -- I just shifted over to Tap 4.1.1 and I was hoping I could get rid of the use of 'type' in my @Component annotation. But no such luck. It's not a matter of luck... You can simply have many components all sharing the same class. Think for instance all those template-only components... their class is BaseComponent. So, in a word, Tapestry cannot use the class name (neither the simple nor the full) in order to make apart a component. It always needs the type. type has been made optional to facilitate cases where it matches the class name. I believe that's what stated at http://tapestry.apache.org/tapestry4.1/tapestry-annotations/ index.html If this causes confusions , i'm 100% for making type required again. In my application file I indicate that the components are in the 'com.transparentpolitics.web.components' directory (or its subdirectories). However, Tap doesn't find components that are in child directories of the 'com ... components' directory. So component references like this: @Component public abstract Navigation getNavigation() don't work but this does work : @Component(type=utils/Navigation) public abstract Navigation getNavigation() (Navigation is 'com.transparentpolitics.core.web.components.util.Navigation') Now I don't understand why Tap can't find the
Re: Textfield validation problem
Change this: binding name=translator value=translator:number,pattern=#.#/ to this: binding name=translator value=translator:number,pattern=#.#,omitZero=false/ The 'omitZero' property in org.apache.tapestry.form.translator.NumberTranslator is true by default. Paul Ferraro (who I believe contributed much of the translation and validation system for Tap 4.0) argues that omitZero should be false by default in this JIRA issue: http://issues.apache.org/jira/browse/TAPESTRY-633 So vote for it if you agree. -Ryan On Oct 14, 2006, at 11:44 AM, Jabbar wrote: Oops. The textfield component definition is component id=dailyHighThreshold type=TextField binding name=value value=currentChannelSetup.dailyThreshold.highThresholdDouble/ binding name=translator value=translator:number,pattern=#.#/ binding name=validators value=validators:required[You must enter {0}!], min=0/ binding name=displayName value=literal:Daily High Threshold/ binding name=disabled value=!currentChannelSetup.dailyThreshold.dailyThresholdEnabled/ /component On 14/10/06, Jabbar [EMAIL PROTECTED] wrote: Hello again, I have another problem. It concerns the textfield the definition is component id=dailyHighThreshold type=TextField binding name=value value=currentChannelSetup.dailyThreshold.highThresholdDouble/ !-- binding name=translator value=translator:number,pattern=#.#/ binding name=validators value=validators:required[You must enter {0}!], min=0/ binding name=displayName value=literal:Daily High Threshold/ -- binding name=disabled value=!currentChannelSetup.dailyThreshold.dailyThresholdEnabled/ /component when value is numeric 0 then the textfield also shows a blank. I don't understand this! Anybody got any ideas? -- Thanks A Jabbar Azam -- Thanks A Jabbar Azam - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] Ryan Holmes, CISSP [EMAIL PROTECTED] ph. (213) 626-0026 - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Confusion over persistent page properties and editing
Without seeing more of your code, my guess it that you are unconditionally calling setChannelSetup() in your pageBeginRender method. Something like this: public void pageBeginRender(PageEvent event) { setChannelSetup(new ArrayListCello6ChannelSetup()); } Remember that pageBeginRender is called *every time* the page is rendered, not just the first time the page is displayed. So, if your button calls a listener method that does something along the lines of this: public void addNewSetup() { Cello6ChannelSetup setup = new Cello6ChannelSetup(...); getChannelSetup().add(setup); } Then the pageBeginRender method runs *after* your listener method, thus wiping out the change by re-initializing the list. I can probably guess your next question, but I'll wait to see if I'm on the right track first. FYI, a good way to get a handle on Tapestry behavior for things like this is to set a breakpoint in your listener method and in your pageBeginRender method so you can see the order in which they are called. -Ryan On Oct 14, 2006, at 11:52 AM, Jabbar wrote: Hello, I've been struggling all day editing persistent page properties and finding that the values of the properties is not what I expected after the render phases The persistant page property is @Persist public abstract ListCello6ChannelSetup getChannelSetup(); public abstract void setChannelSetup(ListCello6ChannelSetup d); This gets sets in PageBeginRender when the page is first called. A button on the page is pressed which changes the property of one of the elements of the list. After the render the value of the channelSetup property is not what I expect. Does anybody have any ideas? Thanks -- Thanks A Jabbar Azam - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] Ryan Holmes, CISSP [EMAIL PROTECTED] ph. (213) 626-0026 - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Textfield validation problem
Sure, sounds like you want a numeric-only string. Tapestry has a Pattern validator, but I don't know if you can specify the pattern inside your 'validators:' value. I always set up pattern validators as beans and then reference them in the 'validators:' value, like so: bean name=numericValidator class=org.apache.tapestry.form.validator.Pattern lifecycle=page set name=pattern'^[0-9]+$'/set set name=message value=message:invalid-numeric-input / /bean component id=numericStringField type=TextField binding name=value value=myNumericString / binding name=displayName value=message:my-numeric-string- label / binding name=validators value=validators:required, $numericValidator / /component I'm using the '$' syntax to reference a bean in the 'validators:' value. Note that I'm using localizable message keys, but you can of course use literal strings for your messages. Also note that I'm setting 'lifecycle=page' in the bean definition. This should give slightly better performance by causing the bean to be instantiated only once, rather than on each page render. One more thing -- since this TextField represents a String value, you don't need to specify a translator unless you want to change the default string translation behavior (you probably already knew that). -Ryan On Oct 14, 2006, at 1:39 PM, Jabbar wrote: Ryan, Hello again. Is it possible to use a regular expression with a textfield? I don't want to use it to read a number, but a string. Thanks On 14/10/06, Ryan Holmes [EMAIL PROTECTED] wrote: Change this: binding name=translator value=translator:number,pattern=#.#/ to this: binding name=translator value=translator:number,pattern=#.#,omitZero=false/ The 'omitZero' property in org.apache.tapestry.form.translator.NumberTranslator is true by default. Paul Ferraro (who I believe contributed much of the translation and validation system for Tap 4.0) argues that omitZero should be false by default in this JIRA issue: http://issues.apache.org/jira/browse/TAPESTRY-633 So vote for it if you agree. -Ryan On Oct 14, 2006, at 11:44 AM, Jabbar wrote: Oops. The textfield component definition is component id=dailyHighThreshold type=TextField binding name=value value=currentChannelSetup.dailyThreshold.highThresholdDouble/ binding name=translator value=translator:number,pattern=#.#/ binding name=validators value=validators:required[You must enter {0}!], min=0/ binding name=displayName value=literal:Daily High Threshold/ binding name=disabled value=!currentChannelSetup.dailyThreshold.dailyThresholdEnabled/ /component On 14/10/06, Jabbar [EMAIL PROTECTED] wrote: Hello again, I have another problem. It concerns the textfield the definition is component id=dailyHighThreshold type=TextField binding name=value value=currentChannelSetup.dailyThreshold.highThresholdDouble/ !-- binding name=translator value=translator:number,pattern=#.#/ binding name=validators value=validators:required[You must enter {0}!], min=0/ binding name=displayName value=literal:Daily High Threshold/ -- binding name=disabled value=! currentChannelSetup.dailyThreshold.dailyThresholdEnabled/ /component when value is numeric 0 then the textfield also shows a blank. I don't understand this! Anybody got any ideas? -- Thanks A Jabbar Azam -- Thanks A Jabbar Azam - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] Ryan Holmes, CISSP [EMAIL PROTECTED] ph. (213) 626-0026 - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] -- Thanks A Jabbar Azam - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: tableRowsIterator nullPointerException
IIRC, an NPE from tableRowsIterator is often due to referencing an attribute of a related object in OGNL (e.g. ognl:customer.address.street) when the related object (e.g. address) is null. HTH. If not, as Karthik said, please post the relevant source code, page or component specifications and HTML. -Ryan On Aug 18, 2006, at 9:25 AM, anil wrote: Hi I'm fairly new to tapestry and am trying to create an implementation of the IBasicTableModel interface so that I can paginate results and get results (from Hibernate via Spring) when I need them. I've written my component but whenever I load the page I get a ognlException on the tableRowsIterator which seems to stem from a nullPointerException from getCurrentPageRows. Does this mean that there's no data being loaded into the table component to be displayed? I must admit I'm not entirely sure what approach to take to try and solve the problem. If anyone could shed any light on what's happening, or could give me an idea of where to start debugging this I'd be most grateful! A. -- View this message in context: http://www.nabble.com/ tableRowsIterator-nullPointerException-tf2128224.html#a5872918 Sent from the Tapestry - User forum at Nabble.com. - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] Ryan Holmes, CISSP [EMAIL PROTECTED] ph. (213) 626-0026 - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Tapestry with Hibernate vs JSF with Hibernate (Object binding question)
Just to clarify, Tapestry does not overwrite bound objects with new instances. iow, if a bound value is a Hibernate proxy, that's what you'll get -- for better or worse ;) -Ryan On Aug 19, 2006, at 7:20 AM, Vinicius Carvalho wrote: Hello there! As I said on previous emails, I'm migrating a JSF app to tapestry, I'm about to finish. One thing that is really tricking me is the way that the Hibernate entities are bound on both frameworks (I might being doing something wrong here). My edit page has an object (Event) that has a many-to-one relationship to User, so on the same screen I add/edit an user and an event. Well on the JSF, when I hit the service layer (both apps share the same model desing, with same entities and spring transaction managed classes) the Event has an user (that is a EnhancedByCGLIB user) with all it's original values (even those that are not displayed to the user on the screen), so calling: eventDAO.update(event), updates my user as well. On Tapestry side, hitting the service layer, the Event has a User (POJO) and all other values have just gone, it seems that tapestry, when binding it's values it does something like this: User user = new User(); ... //set properties present on the screen, dump all other from database event.setUser(user); This not only mess my database, but also makes hibernate to create a new user for my event, instead of updating an existing one. Well, I'm pretty sure I'm doing stupid things here, could anyone help me out? Best Regards Vinicius - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] Ryan Holmes, CISSP [EMAIL PROTECTED] ph. (213) 626-0026 - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Injecting State Objects w/ Non-Serializable Beans
Ideally, your state objects should be as simple and small as possible -- if for no other reason than to make sure your app can cluster if required. Also, if you're using a service then you're probably performing business logic and a state object is probably not the best place for this. I'm talking about session-scoped ASO's here and not global ASO's. I could see injected services making more sense in a global ASO but it still seems like the wrong architecture. In any event, to get this functionality in a clean way Tapestry/ HiveMind would have to support re-injection on deserialization as you mention, and I don't think that is or very likely will be supported (not to discourage you from looking -- I could certainly be wrong). I'm not sure if you're also asking about general Tapestry/Spring integration, but I recently switched from a custom solution based on the info at http://wiki.apache.org/tapestry/Tapestry4Spring to Howard's tapestry-spring plugin (http://howardlewisship.com/tapestry- javaforge/tapestry-spring/). I literally just ripped out my old stuff, dropped in the tapestry-spring jar and was up and running. I don't think the plugin is any better than the solution on the wiki, but having only 1 jar vs a few classes and HiveMind wiring is nice. If you can outline why you need to inject services into your state objects in the first place, maybe I can offer an alternate solution. The (rather large) application my team is working on at the moment uses Spring beans extensively in Tapestry pages and components and I've never had the need or desire to inject them into state objects. Not to say that there couldn't be a legitimate reason to do it, I just haven't run into it yet. -Ryan On Aug 14, 2006, at 1:42 PM, Michael Prescott wrote: We've got an application state object into which we're injecting some beans from Spring. Over time we've tried a number of approaches to this. Under Tapestry 3, we'd cobbled this together with some code in a pageBeginRender() listener in a base page class. The pages had access to the Spring context more directly, so as each page started to render, it would manually inject the Visit with a number of these beans from Spring. This smelled a bit, so under Tapestry 4 we moved to a model where we're injecting via Hivemind. We have a StateObjectFactory which pulls what we need out of Spring as Visits are created. The problem is that this approach is incompatible with persistent sessions: the beans we're injecting from Spring are all trussed up with proxies and aspects, so they're not in the least bit serializable. It would be lovely if the framework could handle this for us, so that we could just use @InjectSpring right inside state objects, and the framework would take care of re-injecting as necessary (e.g. when the deserialized value is null). Maybe keeping this sort of stuff out of state objects is a good idea. It's a natural factoring, given what we're doing, but this seems to make it inadvisable. Anyone else had to deal with this? Thanks, Michael Prescott Ryan Holmes, CISSP [EMAIL PROTECTED] ph. (213) 626-0026 - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Label on Property Selection List
As a matter of fact, yes, there is a simple way! Excuse my enthusiasm, but it's not often that I get to say that on the Tapestry mailing list ;) You want a LabeledPropertySelectionModel, which is a simple decorator around your existing IPropertySelectionModel: http://tapestry.apache.org/tapestry4/tapestry/apidocs/org/apache/ tapestry/form/LabeledPropertySelectionModel.html Inside the method that creates your IPropertySelectionModel just add something like: (assume your existing model is in a variable named myModel) IPropertySelectionModel labeledModel = new LabeledPropertySelectionModel(myModel, Choose your item); return labeledModel; -Ryan On Aug 16, 2006, at 11:59 AM, Mael Caldas wrote: Hi I'm using tapestry 4, and have a selection list that submits the form on change, without a button, but, when I have only one item on the list, I can't submit the form, because, of course, there is nothing to change! Does anybody knows a simple way to have a label inside the property selection list, like chose your item, in the first position of the selection list , so, if I have only one item on the list, when I change from chose your item to the Item 1, the javascript submits the form... Thanks! Ryan Holmes, CISSP [EMAIL PROTECTED] ph. (213) 626-0026 - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Unable to construct service tapestry.multipart.ServletMultipartDecoder
IIRC, the name of that service changed between Tapestry 4.0 and 4.0.1, but your stacktrace looks correct (well, as correct as a stacktrace can be). What versions of the following jars do you have: tapestry, hivemind, hivemind-lib and commons-fileupload? Also, are you specifying a maximum upload size in your hivemodule.xml file? It will look something like this: implementation service- id=tapestry.multipart.ServletMultipartDecoder create-instance class=org.apache.tapestry.multipart.MultipartDecoderImpl,maxSize=50 model=threaded / /implementation If so, copy and paste that into your response. -Ryan On Aug 16, 2006, at 7:26 AM, Andrés Nates wrote: When I’m run de example of the component upload, this example has a basic upload component for images (jpeg). This is the error message org.apache.hivemind.ApplicationRuntimeException: Unable to construct service tapestry.multipart.ServletMultipartDecoder: Could not load class org.apache.tapestry.multipart.MultipartDecoderImpl from WebappClassLoader delegate: false repositories: /WEB-INF/classes/ -- Parent Classloader: [EMAIL PROTECTED] : org/apache/commons/fileupload/servlet/ServletFileUpload org.apache.hivemind.impl.servicemodel.ThreadedServiceModel.constructSe rviceF orCurrentThread(ThreadedServiceModel.java:186) org.apache.hivemind.impl.servicemodel.ThreadedServiceModel.getServiceI mpleme ntationForCurrentThread(ThreadedServiceModel.java:157) $ServletMultipartDecoder_10d0ea93c7e._service ($ServletMultipartDecoder_10d0e a93c7e.java) $ServletMultipartDecoder_10d0ea93c7e.cleanup ($ServletMultipartDecoder_10d0ea 93c7e.java) $ServletMultipartDecoder_10d0ea93c7f.cleanup ($ServletMultipartDecoder_10d0ea 93c7f.java) org.apache.tapestry.multipart.MultipartDecoderFilter.service (MultipartDecode rFilter.java:57) $ServletRequestServicerFilter_10d0ea93cbe.service ($ServletRequestServicerFil ter_10d0ea93cbe.java) $ServletRequestServicer_10d0ea93cc6.service ($ServletRequestServicer_10d0ea93 cc6.java) org.apache.tapestry.services.impl.SetupRequestEncoding.service (SetupRequestE ncoding.java:53) $ServletRequestServicerFilter_10d0ea93cc2.service ($ServletRequestServicerFil ter_10d0ea93cc2.java) $ServletRequestServicer_10d0ea93cc6.service ($ServletRequestServicer_10d0ea93 cc6.java) $ServletRequestServicer_10d0ea93cb8.service ($ServletRequestServicer_10d0ea93 cb8.java) org.apache.tapestry.ApplicationServlet.doService (ApplicationServlet.java:123 ) org.apache.tapestry.ApplicationServlet.doPost (ApplicationServlet.java:168) javax.servlet.http.HttpServlet.service(HttpServlet.java:709) javax.servlet.http.HttpServlet.service(HttpServlet.java:802) Anybody know how to fix this error ? Cordialmente, ~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~ ANDRÉS NATES M. Director de implantación e infraestructura. Nuevos Medios Calle 25 No. 127-220 Autopista Cali-Jamundí Km. 7 Tel: (572) - 524 07 77 Ext. 2173 Email: mailto:[EMAIL PROTECTED] [EMAIL PROTECTED] Cali mailto:[EMAIL PROTECTED] - Colombia POLÍTICA DE CALIDAD Proveer soluciones tecnológicas de software para la gestión del conocimiento cumpliendo lo pactado con los clientes mediante el mejoramiento continuo y la innovación, apoyado en la sinergia corporativa de Parquesoft. Ryan Holmes, CISSP [EMAIL PROTECTED] ph. (213) 626-0026 - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Unable to construct service tapestry.multipart.ServletMultipartDecoder
All your jar versions are fine. Try replacing this: implementation service-id=tapestry.multipart.MultipartDecoder create-instance class=org.apache.tapestry.multipart.MultipartDecoderImpl,maxSize=-1 model=threaded / /implementation with this: implementation service- id=tapestry.multipart.ServletMultipartDecoder create-instance class=org.apache.tapestry.multipart.MultipartDecoderImpl,maxSize=-1 model=threaded / /implementation The service-id changed a few months ago (at 4.0.1 I think). There is now a tapestry.multipart.ServletMultipartDecoder and a tapestry.portlet.multipart.PortletMultipartDecoder service. -Ryan On Aug 16, 2006, at 3:06 PM, Andrés Nates wrote: Hello Jesse, I'm have put this version of jars tapestry-portlet-4.0.2.jar tapestry-4.0.2.jar tapestry-annotations-4.0.2.jar tapestry-contrib-4.0.2.jar commons-codec-1.3.jar commons-logging-1.0.4.jar commons-fileupload-1.1.jar commons-io-1.2-jar ognl-2.6.7.jar oro-2.0.8.jar hivemind-1.1.1.jar hivemind-lib-1.1.1.jar But the error still appear -Mensaje original- De: Jesse Kuhnert [mailto:[EMAIL PROTECTED] Enviado el: Miércoles, 16 de Agosto de 2006 04:37 p.m. Para: Tapestry users Asunto: Re: Unable to construct service tapestry.multipart.ServletMultipartDecoder You need fileupload-1.1.. http://tapestry.apache.org/tapestry4/dependencies.html On 8/16/06, Andrés Nates [EMAIL PROTECTED] wrote: I'm have this version of jar tapestry-4.0.2 hivemind-1.1 hivemind-lib-1.1 commons-fileupload-1.0 and the file Hivemind.xml look this: ?xml version=1.0? module id=com.ttdev.album version=1.0.0 service-point id=ImageService interface=org.apache.tapestry.engine.IEngineService invoke-factory construct class=com.ttdev.album.ImageService set-object property=linkFactory value=service:tapestry.url.LinkFactory/ /construct /invoke-factory /service-point contribution configuration-id=tapestry.services.ApplicationServices service name=image object=service:com.ttdev.album.ImageService/ /contribution contribution configuration- id=tapestry.url.ServiceEncoders page-service-encoder id=page extension=html service=page/ encoder id=image object=instance:com.ttdev.album.ImageServiceEncoder/ /contribution implementation service- id=tapestry.multipart.MultipartDecoder create-instance class=org.apache.tapestry.multipart.MultipartDecoderImpl,maxSize=-1 model=threaded / /implementation /module -Mensaje original- De: Ryan Holmes [mailto:[EMAIL PROTECTED] Enviado el: Miércoles, 16 de Agosto de 2006 03:57 p.m. Para: Tapestry users Asunto: Re: Unable to construct service tapestry.multipart.ServletMultipartDecoder IIRC, the name of that service changed between Tapestry 4.0 and 4.0.1, but your stacktrace looks correct (well, as correct as a stacktrace can be). What versions of the following jars do you have: tapestry, hivemind, hivemind-lib and commons-fileupload? Also, are you specifying a maximum upload size in your hivemodule.xml file? It will look something like this: implementation service- id=tapestry.multipart.ServletMultipartDecoder create-instance class=org.apache.tapestry.multipart.MultipartDecoderImpl,maxSize=500 000 model=threaded / /implementation If so, copy and paste that into your response. -Ryan On Aug 16, 2006, at 7:26 AM, Andrés Nates wrote: When I'm run de example of the component upload, this example has a basic upload component for images (jpeg). This is the error message org.apache.hivemind.ApplicationRuntimeException: Unable to construct service tapestry.multipart.ServletMultipartDecoder: Could not load class org.apache.tapestry.multipart.MultipartDecoderImpl from WebappClassLoader delegate: false repositories: /WEB-INF/classes/ -- Parent Classloader: [EMAIL PROTECTED] : org/apache/commons/fileupload/servlet/ServletFileUpload org.apache.hivemind.impl.servicemodel.ThreadedServiceModel.construct Se rviceF orCurrentThread(ThreadedServiceModel.java:186) org.apache.hivemind.impl.servicemodel.ThreadedServiceModel.getServic eI mpleme ntationForCurrentThread(ThreadedServiceModel.java:157) $ServletMultipartDecoder_10d0ea93c7e._service ($ServletMultipartDecoder_10d0e a93c7e.java) $ServletMultipartDecoder_10d0ea93c7e.cleanup ($ServletMultipartDecoder_10d0ea 93c7e.java) $ServletMultipartDecoder_10d0ea93c7f.cleanup ($ServletMultipartDecoder_10d0ea 93c7f.java) org.apache.tapestry.multipart.MultipartDecoderFilter.service (MultipartDecode rFilter.java:57) $ServletRequestServicerFilter_10d0ea93cbe.service ($ServletRequestServicerFil ter_10d0ea93cbe.java) $ServletRequestServicer_10d0ea93cc6.service ($ServletRequestServicer_10d0ea93 cc6.java
Re: Best way to do Cookies in Tapestry 4 (full example)
This is from an earlier post on the subject: @InjectObject(service:tapestry.request.CookieSource) public abstract CookieSource getCookieSource(); and then: getCookieSource().readCookieValue(name); or getCookieSource().writeCookieValue(name, value); Also, see the API docs at: http://tapestry.apache.org/tapestry4/tapestry/apidocs/org/apache/tapestry/services/CookieSource.html -Ryan albartell wrote: Jesse did a great work also this mailing list contains alot of help... I see everything Jesse and the other committers are doing and I greatly appreciate it. I know how thankless open source can be (and how little assistance you actually get) because I have been there. Hopefully my emails come across as constructive as I hope for positive resolution. With that said, let's see if we can come up with a solid way to do cookies in T4 that can be added to the Tapestry documentation (instead of hidden in archives). Anybody want to start us out with a full example of how they do cookies in T4? Aaron Bartell - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: image service?
This might help you with image resizing. It was built for a very specific purpose: take an input image, downsize it to fit a specified maximum width and output it as a JPEG. It could easily be extended to work with a maximum height as well (typical thumbnail bounding box approach). The useful thing in this code is that it demonstrates how to get good quality resized JPEG's (something people seem to have a lot of trouble with using awt imaging). This is the guts of the service with all the image processing code. import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.stream.ImageOutputStream; import org.apache.tapestry.ApplicationRuntimeException; public class ImageService { public static final float JPEG_COMPRESSION_RATIO = 0.90f; public static void saveConstrainedJpeg(InputStream input, int maxWidth, File outFile) { // Read source file into a BufferedImage. BufferedImage inputImage; try { inputImage = ImageIO.read(input); } catch (IOException ex) { throw new ApplicationRuntimeException(Cannot read image file., ex); } // Get input image width and height. int imgWidth = inputImage.getWidth(); int imgHeight = inputImage.getHeight(); // Write the original image if it is within the given constraints. if (imgWidth = maxWidth) { writeJpeg(inputImage, outFile); return; } // Calculate new width and height; double factor = (double) maxWidth / imgWidth; int newWidth = (int) Math.round(factor * imgWidth); int newHeight = (int) Math.round(factor * imgHeight); // Create and save target image. BufferedImage target = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB); writeJpeg(resize(inputImage, target), outFile); } private static BufferedImage resize(BufferedImage source, BufferedImage target) { Graphics2D g2 = target.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); double scalex = (double) target.getWidth() / source.getWidth(); double scaley = (double) target.getHeight() / source.getHeight(); AffineTransform at = AffineTransform.getScaleInstance(scalex, scaley); g2.drawRenderedImage(source, at); g2.dispose(); return target; } private static void writeJpeg(BufferedImage image, File outFile) { // Find a jpeg writer. ImageWriter writer = null; Iterator iter = ImageIO.getImageWritersByMIMEType(image/jpeg); while (iter.hasNext()) { writer = (ImageWriter) iter.next(); } // Prepare the output file. ImageOutputStream ios = null; try { ios = ImageIO.createImageOutputStream(outFile); } catch (IOException ex) { throw new ApplicationRuntimeException(Could not open file for output., ex); } writer.setOutput(ios); // Set the compression quality. ImageWriteParam param = writer.getDefaultWriteParam(); param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); param.setCompressionQuality(JPEG_COMPRESSION_RATIO); // Write the image. try { writer.write(null, new IIOImage(image, null, null), param); ios.flush(); writer.dispose(); ios.close(); } catch (IOException ex) { throw new ApplicationRuntimeException(Could not write image file., ex); } } } -Ryan Henri Dupre wrote: I seem to recall that quite a while ago someone was working on an image service. I would need a service that allows to resize pictures (hopefully cache the images). Has anyone developped such service? Thanks, Henri. - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: conditional and nested ul and li tags
First, you can't nest UL tags outside of LI tags. I'm sure most browsers will render it correctly, but a more strict parser (like the Tapestry page parser) will choke on it. Your HTML structure needs to be: ul liPost 1/li liPost 2 ul liPost 2, Reply A/li liPost 2, Reply B ul liPost 2, Reply B, Reply i/li liPost 2, Reply B, Reply ii/li /ul /li liPost 2, Reply C/li /ul /li liPost 3/li /ul Second, in page and component specifications, binding values are assumed to be OGNL calls unless you specify a prefix (unlike templates, where values are assumed to be literal strings unless there is a prefix). So there are two ways to fix your Insert component: component id=insertUlTag type=Insert binding name=value value='ul'/ binding name=raw value=true/ /component -- or -- component id=insertUlTag type=Insert binding name=value value=literal:ul/ binding name=raw value=true/ /component Note that the raw parameter is required to prevent Tapestry from escaping the HTML. Last, you're probably looking for a recursive DisplayReplies component to walk the tree of replies and created nested UL's and LI's as needed. That's a little difficult to do in Tapestry because you can't create simple recursive components. In other words, you can't easily render (conditionally or otherwise) a component inside of itself without a getting a stack overflow exception. You have to use a trick involving Block and RenderBlock to get recursive behavior. If you're interested, I can post a tiny Tapestry app that demonstrates how to do this. It uses articles and comments rather than posts and replies, but it is a stripped down demo with one page and one component demonstrating what I think you are trying to do and nothing more (and it uses UL and LI tags). -Ryan [EMAIL PROTECTED] wrote: I am trying to set up a page that has comments listed in a big list surrounded by ul tags. Under certains conditions, I want to nest more ul tags. Like this:ullithis is post 1/lilithis is post 2/liullithis is reply to post 2/lilithis is another reply to post 2/lilithis it yet an additional reply/liul liAnd this is a reply to the one above/li/ulliThe last reply to post 2/li/ullithis is post 3/li/ulHowever, I run into problem in Tapestry when I try to do something like this:span jwcid=ifSomething/ul/spanTapestry complains that I am improperly nesting a /ul tag inside a span. One way I thought of getting arround this was to use an Insert so that the html would be:span jwcid=ifSomethingspan jwcid=insertUlTag//spanWhich sort of worked until I go to the page descriptor and I couldn't figure out how to put ul in the binding:component id=insertUlTag type=Insertbinding name=value value=ul/ /componentThe parser complained and using CDATA didn't help. So I ended up making a getUlOpenTag method on the java file for the page which return ul so then I had this:component id=insertUlOpenTag type=Insertbinding name=value value=ulOpenTag/ binding name=raw value=true/ /componentand that worked.But is there not an easier way? I actually ended up creating a new library that just had open and close HTML tags just for instances like this.Thanks _ Express yourself instantly with MSN Messenger! Download today it's FREE! http://messenger.msn.click-url.com/go/onm00200471ave/direct/01/ - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: accessing page in a library
What do you mean by a page of a library? If you're talking about accessing components in a component library, as far as I know you must specify the library in your .application file. -Ryan Norbert Sándor wrote: Hello, How can I acces a page of a library, if the library is not defined in the .application file? Thanks, Norbi - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: XMLHTTPRequest within tapestry
Have you checked out DWR (http://getahead.ltd.uk/dwr/)? It might be a good fit for what you're trying to do and it's framework agnostic, so it will work fine with Tapestry 3. It's also pretty darn easy to use. -Ryan Peter Dawn wrote: just tried to implement it now. the country list example runs fine. but am not sure how should i go about with something simple like a hello world or just displaying the contents of a dummy file. it might sound a very simple thing, i guess i am trying to get the basics. - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Issues with Label Components with Tapestry 4.0
Your problem getting the span tag where you want it is due to how the FieldLabel component renders itself. Here's the relevant part of FieldLabel.renderComponent(): delegate.writeLabelPrefix(field, writer, cycle); writer.begin(label); if (id != null) writer.attribute(for, id); delegate.writeLabelAttributes(writer, cycle, field); renderInformalParameters(writer, cycle); writer.print(displayName, getRaw()); writer.end(); delegate.writeLabelSuffix(field, writer, cycle); You could argue that writeLabelPrefix() and writeLabelSuffix() should both be inside the label tag (makes sense to me), but the current code is symmetrical and not necessarily wrong. Your best bet is probably to override the FieldLabel component with your own version that renders the delegate prefix and/or suffix inside the label tag. And I'm sure you won't hesitate to file a bug report if you feel strongly about it ;) -Ryan Matt Raible wrote: Matt Raible wrote: Andreas Andreou wrote: try component.getBinding(class) if that's not null, do a getObject() on it Thanks. This works, but it also prints out duplicate class attributes. class=text large error class=text large It'd be nice to have something like: writer.appendAttribute(class, values to append); Another question - it seems my full label and input is getting wrapped with font color=red Is there anyway to get rid of that? It's problematic b/c the closing /font isn't getting rendered until right before /form. Fixed this by using: public void writeLabelPrefix(IFormComponent component, IMarkupWriter writer, IRequestCycle cycle) { // does nothing put prevent font color=red from getting written } Thanks, Matt Matt Raible wrote: Hmmm, I'm guessing the answers to my questions below are no, this isn't possible. ;-) Here's another question - is it possible in my custom Validator to get the existing CSS classes on a component? For example, I currently have: public void writeLabelAttributes(IMarkupWriter writer, IRequestCycle cycle, IFormComponent component) { if (isInError(component)) { writer.attribute(class, error); } } public void writeAttributes(IMarkupWriter writer, IRequestCycle cycle, IFormComponent component, IValidator validator) { if (isInError()) { writer.attribute(class, error); } } But I'd prefer to have something like this: public void writeLabelAttributes(IMarkupWriter writer, IRequestCycle cycle, IFormComponent component) { if (isInError(component)) { writer.attribute(class, error + component.getAttribute(class)); } } public void writeAttributes(IMarkupWriter writer, IRequestCycle cycle, IFormComponent component, IValidator validator) { if (isInError()) { writer.attribute(class, error + component.getAttribute(class)); } } In other words, is there a method on component that allows me to get the current CSS classes? Matt Matt Raible wrote: I have two different Label components I'm trying to create. Issue #1 --- The first is a simple component (just a Label.jwc and Label.html file in WEB-INF) that writes a label. I'd like to include the option to write a required indicator. However, I'm having a difficult time retrieving a parameter's value. Here's what I have so far: Label.jwc component-specification allow-informal-parameters=yes parameter name=key required=yes/ parameter name=class required=no/ component id=label type=Any inherit-informal-parameters=yes/ /component-specification Label.html label jwcid=labelspan jwcid=@Insert value=ognl:getMessages().getMessage(key)/ div jwcid=@If condition=ognl:class == 'required'span class=req */span/label I'm pretty sure class won't work as a parameter name b/c I've seen a stacktrace using this already. Regardless, let's pretend it does (I've tried using other names). Here's the desired usage: label class=required desc jwcid=@Label for=phoneNumber key=user.phoneNumberPhone Number/label produces: label class=desc jwcid=@Label for=phoneNumberPhone Numberspan class=req */label I'm fine with the result having class=required desc - I basically just need some indicator to show a field is required when I'm not wiring up it's input field as a component. Issue #2 --- I'm overriding ValidationDelegate in order to add required field indicators. I used to be pre-pending an asterisk to the beginning of the field, and I had that working. Now I want to add span class=req to the end of the label before the /label shows up. I'm using @FieldLabel and everything *almost* works. I've eliminating error styling in the class below so it's easier to read. public class Validator extends