(Property)MessageResources proposed changes.
Hi, ( i am trying to subscribe to STRUTS-DEV but i don't get a confirmation message so i post it first here) When the new MessageResources class (and its sub) where introduced my app didn't work anymore because of the changed behaviour in loading resouces. I have 2 fixes that i have attached here: First is the MessageResources.localeKey(Locale) method that is needed by both PropertyMessageResources that i send in. this: protected String localeKey(Locale locale) { if (locale == null) return (""); else if (locale.equals(defaultLocale)) return (""); else return (locale.toString()); } is changed to this: protected String localeKey(Locale locale) { if (locale == null) return (""); else return (locale.toString()); } Because when it is the default locale or not that doesn't matter. First it must try to load the right resources for the default locale. For example if the default locale is nl_NL then i want it to try to load: xxx.nl_NL.properties or xxx.nl.properties before it tries to load xxx.properties. Because maybe now my webapp is on a system there the default locale is nl_NL but maybe it's also getting deployed on a system with the default locale en_US. Then suddenly the struts load the wrong properties file for the locale, (What must be the xxx.properties file? English or Dutch?) ResourceBundle it self does also try to load the nl_NL first it doesn't look if the given locale is the default one or not. PropertyMessageResources.getMessage(Locale,String) changes: this piece of code: // As a last resort, try the default Locale localeKey = localeKey(defaultLocale); messageKey = messageKey(localeKey, key); loadLocale(localeKey); synchronized (messages) { message = (String) messages.get(messageKey); if (message != null) { if (addIt) messages.put(originalKey, message); return (message); } } is changed to this: // try the default Locale if current locale isn't default if(locale != defaultLocale) { localeKey = localeKey(defaultLocale); messageKey = messageKey(localeKey, key); loadLocale(localeKey); synchronized (messages) { message = (String) messages.get(messageKey); if (message != null) { if (addIt) messages.put(originalKey, message); return (message); } } } // last resort: try loading de base localeKey = ""; messageKey = messageKey(localeKey, key); loadLocale(localeKey); synchronized (messages) { message = (String) messages.get(messageKey); if (message != null) { if (addIt) messages.put(originalKey, message); return (message); } } So i my last resort isn't trying to get it with the defaultLocale I test it first (maybe equals should be used in tead of == ) so that the loading and the synchronized lock isn't invane. After that and still the message isn't returned i go to my last resort and that is loading the base (xxx.properties) But i thought why implement the exact same behaviour of the ResouceBundle? So i made my own class. Here are the 2 methods: public String getMessage(java.util.Locale locale, String key) { if(locale == null) locale = defaultLocale; String localeKey = localeKey(locale); String messageKey = messageKey(localeKey, key); String message = null; // first try to load a previous stored resource. synchronized (messages) { message = (String) messages.get(messageKey); } // if there was no previous stored resource. if(message == null) { // try loading the resources loadMessages(locale); // try getting it again. synchronized (messages) { message = (String) messages.get(messageKey); } } // If still null. if(message == null) { // Return an appropriate error indication if (returnNull) return (null); else return ("???" + messageKey(locale, key) + "???"); } return message; } protected void loadMessages(Locale locale) { String localeKey = localeKey(locale); // Have we already attempted to load messages for this locale? synchronized (locales) { if (locales.get(localeKey) != null) return; locales.put(localeKey, localeKey); } ResourceBundle bundle = java.util.ResourceBundle.getBundle(config,locale,this.getClass().getClassLoader()); if(bundle != null) { synchronized (messages) { Enumeration names = bundle.getKeys(); while (names.hasMoreElements()) { String key = (String) names.nextElement(); messages.put(messageKey(localeKey, key), bundle.getObject(key)); } } } } I use the resoucebundle class to get the properties. This has the following advantages: 1 Not having to implement and maintain the complete reading in code. 2 support for not only resource property files but also resource class files!! 3 No double keys for all the resouces when given locale = nl_NL and the properties file = xx_nl.properties explain 3: Locale = nl_NL propertie file = xxx._nl.properties first messages aren't found for that locale key.
Re: Bad Multi-Threading Performance
From: Matthew Strayer [EMAIL PROTECTED] The situation you describe does not cause deadlock because the wait() call in thread 2 releases the synchronized lock. Ahh - didn't realise that! It's not been in any docs I've read before. Now, i've found it buried now in 4 lines of page 184 of Concurrent programming in Java. The only way I can think of to alleviate this problem is use different synchronization primitives. Unfortunately, Java doesn't have them. And all libraries that simulate these use synchronization! heheheh - hooray for Java :-) Now, maybe someone here could hack some byte code (does Java have a set-and-test instruction??) and produce them... ;-) Trouble is with a test and set is it atomic? I would imagine why the lack of better sync options and test set options plus say a version of interlocked increment is perhaps due to the 'lowest common denominator' basis of java. Regards Ned _ Get Your Private, Free E-mail from MSN Hotmail at http://www.hotmail.com.
Proposal: RetroFit Struts with the Delegation Event Model
ABSTRACT It's often convenient, and sometimes necessary, to handle Struts events, such as when an action has its locale set, or when the action servlet processes an action's form. This document proposes retrofitting Struts with the delegation event model. That model, which is used by the AWT and Swing, makes event handling simple, flexible, and scalable. CREDITS Delegation and Event Model for Struts? -- posted to struts-dev by Robert Leland INTRODUCTION Currently, you can use inheritance to handle Struts events like those described above. Typically, that means extending ActionServlet and overriding a protected method, such as ActionServlet.processActionPerform. Inheritance-based event handling is inflexible and does not scale well because event sources and listeners are tightly coupled at compile time. This was evident to AWT engineers, who replaced the AWT's original inheritance-based event model with the delegation event model. The delegation event model, which has its roots in java.util, implements the Observer design pattern to loosely couple event sources and event listeners at runtime. That loose coupling makes it easy to associate disparate types of objects, so that event listeners can easily react to changes in event sources. STRUTS AND THE DELEGATION EVENT MODEL So what does it mean to retrofit Struts with the delegation event model? It means that Struts will fire events when it performs certain functions. You can register with Struts as an event listener, and handle events as you see fit. This proposal advocates firing events for all interesting Struts functions; for example, the action servlet should fire a robust set of events for processing actions and forms, performing mappings, etc. Implementing support for those events follows the same design pattern discussed in this proposal for implementing action events. This proposal illustrates how to modify Struts to fire events just before, and immediately after, a Struts action has its perform method invoked. Those events are hereafter known as action events. IMPLEMENTING ACTION EVENTS AND ACTION LISTENERS Getting Struts to fire action events is easy. First, we define a listener interface and an event class: org/struts/apache/event/action/ActionListener.java org/struts/apache/event/action/ActionEvent.java Here's the listing for ActionListener: public interface ActionListener { public void beforeActionPerform(ActionEvent event) throws ServletException; public void afterActionPerform(ActionEvent event) throws ServletException; } ActionListener methods are passed instances of ActionEvent. Here's the listing for that class: public class ActionEvent extends java.util.EventObject { public static final int BEFORE_ACTION_PERFORM=0, AFTER_ACTION_PERFORM=1; private int eventType; private HttpServletRequest request; private HttpServletResponse response; public ActionEvent(Action action, int eventType, HttpServletRequest request, HttpServletResponse response) { super(action); // specifies action as the event source this.eventType = eventType; this.request = request; this.response = response; } public int getEventType() { return eventType; } public HttpServletRequest getRequest() { return request; } public HttpServletResponse getResponse() { return response; } } Through action events, action listeners have access to: event type (BEFORE_ACTION_PERFORM, AFTER_ACTION_PERFORM) action request response HANDLING ACTION EVENTS Here's how you use action events and listeners: // first, implement a listener that handles action events public class MyListener implements org.apache.struts.event.ActionListener { public void beforeActionPerform(ActionEvent event) { // handle event } public void afterActionPerform(ActionEvent event) { // handle event } } // Then register your listener with an action: someAction.addActionListener(new MyListener()); Thereafter, MyListener.beforeActionPerform and MyListener.afterActionPerform will be called before and after someAction's perform method, respectively. Let's see what changes need to be made to Struts to make this work. STRUTS MODIFICATIONS FOR SUPPORTING ACTION EVENTS Only two Struts classes need to be modified to support firing action events: Action and ActionServlet. Methods are added to the Action class for registering action listeners and firing events: // the following is added to org.apache.struts.action.Action: import java.util.Enumeration; import java.util.Vector; import org.apache.struts.event.action.ActionEvent; import org.apache.struts.event.action.ActionListener; public class
Page Forwarding Question
In my action classes I have code which checks to see if a user has logged on. If not, the code forwards to the logon page (e.g. servlet.findForward("logon")). However this doesn't fully accomplish what I would like. If a user attempts to reference a page which requires a login, I would like to forward to the login page and, once the user has authenticated, proceed back to the page to which the user was going in the first place. In other words, I would like to forward to the logon screen, but give it a parameter which it uses to tell it which page follows the logon.Can anyone suggest a simple way to accomplish this? Thanks.
RE: Page Forwarding Question
Have the login page write a hidden field with the value of the requested url and submit it to your logon action. From your logon action you can then instantiate a new ActionForward and set the path to the requested url, as defined in the hidden form field, and return that. Alternatively, instead of instantiating a new ActionForward you could just use the request dispatcher and forward with it and then return a null to the ActionServlet. I'm using a similar method now but exapanded it so that all request parameters are written as hidden fields in the login form as well. That way, the previous form results can be submitted along with the login request (and then on to the subsequent page or action). Hope this helps. -Original Message- From: James Howe [mailto:[EMAIL PROTECTED]] Sent: Wednesday, December 20, 2000 10:06 AM To: [EMAIL PROTECTED] Subject: Page Forwarding Question In my action classes I have code which checks to see if a user has logged on. If not, the code forwards to the logon page (e.g. servlet.findForward("logon")). However this doesn't fully accomplish what I would like. If a user attempts to reference a page which requires a login, I would like to forward to the login page and, once the user has authenticated, proceed back to the page to which the user was going in the first place. In other words, I would like to forward to the logon screen, but give it a parameter which it uses to tell it which page follows the logon.Can anyone suggest a simple way to accomplish this? Thanks.
DataSource
Pardon me if I'm missing something, but is it intended that the javax.sql.DataSource be required in the ActionServlet? It's just that I downloaded a recent build and I'm now getting errors when trying to compile my actions. They relate to javax.sql.DataSource not being found on the import. Is it required to have the JDBC 2.0 Standard Extensions API now? Thanks.
Re: DataSource
"Sayles, Scott SAXONHQ" wrote: Pardon me if I'm missing something, but is it intended that the javax.sql.DataSource be required in the ActionServlet? It's just that I downloaded a recent build and I'm now getting errors when trying to compile my actions. They relate to javax.sql.DataSource not being found on the import. Is it required to have the JDBC 2.0 Standard Extensions API now? Thanks. To compile Struts itself, you will need to download the JDBC 2.0 Standard Extensions JAR file and put it on your classpath. (I need to update the README to be more explicit about this.) If you are just compiling your own classes, you should not need them, but will again at runtime (even if you do not use a DataSource in your app. Craig
Re: What's Struts ...
Steve A Drake wrote: On Mon, 19 Jun 2000, Shiraz Wasim Zaidi wrote: The action's servlet can then handle the request, and return a HTTP response to the controller, which the controller can pass back to the client. ---COMMENT I think you have a wrong understanding that action classes are servlets. No they are regular java class that implements Action interface and provide perform method definition that is the actions business logic. Moreover Action Classes never return response to the controller servlet i.e. ActionServlet. They always return ActionForward, which might be null. Just so we're all on the same page here, according to the (0.5) documentation, an Action class is not a servlet but it has a simliar lifecycle to a servlet in that only one Action object is instantiated. So, you must consider multi-threading issues when coding your Action class (like you would with a servlet). Someone please correct me if this is not the case. This is correct for all versions of Struts, although in Struts 1.0 Action is a base class that you extend, rather than an interface that you implement. In addition, the Action class now receives lifecycle indications through the call to setServlet() -- a non-null argument tells you that this Action is about to be invoked for the very first time, and a null argument tells you that this instance has been taken out of service (currently, this only happens when the web application is shut down.) JavaBeans can also be used to manage input forms. A key problem in designing Web applications is retaining and validating what a user has entered between requests. With Struts, you can store the data for a input form in a form bean, which is automatically maintained through the user's Struts session. ---COMMENT Not necessarily. FormBean would be maintained through user's session if the formbean has a scope of session. ---/COMMENT And, looking at the processActionForm() method in the ActionServlet class, session is the default scope for ActionForm beans. Session is the default scope; request is the other option. It makes for more scalable applications if you can use it, but requires that all of the properties of your ActionForm bean be included in the page. Craig McClanahan
RE: Page Forwarding Question
In my action classes I have code which checks to see if a user has logged on. If not, the code forwards to the logon page (e.g. servlet.findForward("logon")). However this doesn't fully accomplish what I would like. If a user attempts to reference a page which requires a login, I would like to forward to the login page and, once the user has authenticated, proceed back to the page to which the user was going in the first place. In other words, I would like to forward to the logon screen, but give it a parameter which it uses to tell it which page follows the logon.Can anyone suggest a simple way to accomplish this? I think you might have problem using this approach if the session expires. Let's say that a user's session expires due to time out and ur referenced page relies on session data. User was on Order List screen showing a list of orders. He goes for coffee comes after an hr. and session expires. He tries to view next page of Order List and in ur action or JSP you detect login required and forward to loginPage with somehow indicating to show OrderList page after authentication. Now ur OrderList jsp would be looking for session data to render the view and it wont find anything as the session is new. What do you think? -Shiraz
Missing message for key index.title
Can someone tell me what this error means: javax.servlet.jsp.JspException: Missing message for key index.title at org.apache.struts.taglib.bean.MessageTag.doStartTag(MessageTag.java:261) I get it when trying to run the struts-example on Orion Server. THanks
RE: Missing message for key index.title
Thanks. I actually have both of those already. I think it might have to do with the Orion Server. I did take the steps that have been posted in the past to get it to work with Orion, but still no luck. Could this be related? In my orion console I see: [root@www orion]# Orion/1.4.4 initialized resolveEntity('-//Apache Software Foundation//DTD Struts Configuration 1.0//EN', 'http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd') Not registered, use system identifier Parse Error at line 37 column -1: Element "struts-config" does not allow "form-beans" here. org.xml.sax.SAXParseException: Element "struts-config" does not allow "form-beans" here. and a bunch more errors. Neal -Original Message- From: Jason Haase [mailto:[EMAIL PROTECTED]] Sent: Wednesday, December 20, 2000 9:22 PM To: '[EMAIL PROTECTED]' Subject: RE: Missing message for key index.title It sounds like your ApplicationResources.properties file is not there. Check to make sure it is in ...\struts-example\WEB-INF\classes\org\apache\struts\example. Orion should have unpacked the struts-example.war file for you. Otherwise, look in your web.xml file to make sure your "Action Servlet Configuration" specifies the right properties file. Like this: init-param param-nameapplication/param-name param-valueorg.apache.struts.example.ApplicationResources/param-value /init-param Jason Haase -Original Message- From: Neal Kaiser [mailto:[EMAIL PROTECTED]] Sent: Wednesday, December 20, 2000 6:09 PM To: [EMAIL PROTECTED] Subject: Missing message for key index.title Can someone tell me what this error means: javax.servlet.jsp.JspException: Missing message for key index.title at org.apache.struts.taglib.bean.MessageTag.doStartTag(MessageTag.java:261) I get it when trying to run the struts-example on Orion Server. THanks
RE: What's Struts ...
an Action class is not a servlet but it has a simliar lifecycle to a servlet in that only one Action object is instantiated. Not always true. If your servlet implements SingleThreadModel interface then container creates a pool of servlet instances. And, looking at the processActionForm() method in the ActionServlet class, session is the default scope for ActionForm beans. Yeah you are correct. -Shiraz Zaidi
How can I use a java variable that was defined in the enclosing template tag?
Here is an example: // Here is the code segment for the enclosing tag, the template:insert ... . % String strToBeUsedByPageA = "Hello"; % template:insert template='aTemplate.jsp' template:put name='PageA.jsp' /template:insert // Here is the code segment for the enclosed file, PageA The enclosing tag defined the strToBeUsedByPageA variable that is being displayed here:%=strToBeUsedByPageA % ... // I get the error msg saying strToBeUsedByPageA is not define. Thanks for any help I can get. -Hay