001    package net.sf.jolene.struts;
002    
003    import net.sf.jolene.util.PrefsReader;
004    import net.sf.jolene.dom.Document;
005    import net.sf.jolene.dom.HTMLElement;
006    import net.sf.jolene.dom.Label;
007    import net.sf.jolene.dom.Text;
008    import net.sf.jolene.factories.DocumentFactory;
009    import org.apache.log4j.LogManager;
010    import org.apache.log4j.Logger;
011    import org.apache.struts.action.ActionForm;
012    import org.apache.struts.action.ActionForward;
013    import org.apache.struts.action.ActionMapping;
014    import org.apache.struts.actions.DispatchAction;
015    import org.apache.struts.util.MessageResources;
016    
017    import javax.servlet.http.HttpServletRequest;
018    import javax.servlet.http.HttpServletResponse;
019    import java.io.IOException;
020    
021    /**
022     * Default action servlet for jolene.  Implements a modified DispatchAction which can match request uri string
023     * to the method name of the action class. The primary purpose is to associate a uri to a document object.
024     * There are several ways to do this see the method descriptions.
025     *
026     * @author Dan Howard
027     * @since Sep 23, 2006 5:40:15 PM
028     */
029    public class DomletAction extends DispatchAction {
030    
031        private static final Logger log = LogManager.getLogger(DomletAction.class);
032    
033        /**
034         * Performs a basic dispatch of the request looking for the parameter from the struts mapping or by using
035         * the struts action name itself.
036         *
037         * @param mapping  ActionMapping
038         * @param form     ActionForm
039         * @param request  HttpServletRequest
040         * @param response HttpServletResponse
041         * @return ActionForward
042         * @throws Exception
043         */
044        @Override
045        public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
046    
047            log.info("DomletAction Initializing PrefsReader...");
048            PrefsReader.init();
049    
050            // Identify the request parameter containing the method name
051            log.debug("QUERY_STRING :" + request.getQueryString());
052    
053            // Identify the method name to be dispatched to.
054            // Either it's the parameter or the path name itself minus .do etc.
055            String parameter = mapping.getParameter();
056            String name;
057            if (parameter != null) {
058                name = request.getParameter(parameter);
059            } else {
060                String path = mapping.getPath();
061                name = path;
062                if (path.lastIndexOf("/") != -1) {
063                    name = path.substring(path.lastIndexOf("/") + 1);
064                }
065            }
066    
067            // Invoke the named method, and return the result
068            return dispatchMethod(mapping, form, request, response, name);
069    
070        }
071    
072    
073        /**
074         * Retrives a document object based on the mapping input attribute and attaches it to the proper scope.
075         * The reason for this method is to allow a default document to be associated with an action since
076         * actions can have many forwards.
077         * <p/>
078         * For example, calling this method would get the document from the <code>/domlet/login.html<code> uri.
079         * <p/>
080         * <pre>
081         * &lt;action
082         * path="/login"
083         * type="domlet.kbsample.web.actions.LoginAction"
084         * name="LoginForm"
085         * scope="session"
086         * validate="false"
087         * input="/domlet/login.html"&gt;
088         * &nbsp;
089         * &lt;forward name="success" path="/browse.do"/&gt;
090         * &lt;forward name="fail" path="/domlet/error.html"/&gt;
091         * &lt;forward name="login" path="/domlet/login.html"/&gt;
092         * &lt;/action&gt;
093         * </pre>
094         *
095         * @param mapping ActionMapping
096         * @param request HttpServletRequest
097         * @return Document or null if the uri for input mapping is undefined in struts-config.xml
098         * @throws IOException if an IOException occurs
099         */
100        public Document getDocument(ActionMapping mapping, HttpServletRequest request) throws IOException {
101            String uri = mapping.getInput();
102            log.debug("mapping URI: " + uri);
103            if (uri == null) {
104                log.error("NO URI Specified in struts-config.xml for " + mapping.getPath());
105                return null;
106            }
107            return getDocument(request, uri, mapping);
108        }
109    
110        /**
111         * Retrives a document object based on the specified forward.
112         * <p/>
113         * For example, using the following in struts-config.xml:
114         * <p/>
115         * <pre>
116         * &lt;action
117         * path="/login"
118         * type="domlet.kbsample.web.actions.LoginAction"
119         * name="LoginForm"
120         * scope="session"
121         * validate="false"
122         * input="/domlet/login.html"&gt;
123         * &nbsp;
124         * &lt;forward name="success" path="/browse.do"/&gt;
125         * &lt;forward name="fail" path="/domlet/error.html"/&gt;
126         * &lt;forward name="login" path="/domlet/login.html"/&gt;
127         * &lt;/action&gt;
128         * </pre>
129         * <p/>
130         * <code>getDocument(mapping, "fail", request); </code> Returns document from /domlet/error.html <br>
131         * <code>getDocument(mapping, "login", request);</code> Returns document from /domlet/login.html
132         *
133         * @param mapping ActionMapping
134         * @param forward forward string
135         * @param request HttpServletRequest
136         * @return Document or null if the forward cannot be found in struts-config.xml
137         * @throws IOException if an IOException occurs
138         */
139        public Document getDocument(ActionMapping mapping, String forward, HttpServletRequest request) throws IOException {
140    
141            String uri = mapping.findForward(forward).getPath();
142            log.debug("Mapping URI from forward: " + forward + ": " + uri);
143            return getDocument(request, uri, mapping);
144    
145        }
146    
147        private Document getDocument(HttpServletRequest request, String uri, ActionMapping mapping) throws IOException {
148            String file;
149            file = request.getSession().getServletContext().getRealPath(uri);
150    
151            Document document;
152            if ("request".equalsIgnoreCase(mapping.getScope())) {
153                if (request.getAttribute(uri) == null) {
154                    document = DocumentFactory.getInstance().getDocument(file, request.getContextPath(), uri);
155                } else {
156                    document = (Document) request.getAttribute(uri);
157                }
158                request.setAttribute(uri, document);
159            } else {
160                if (request.getSession().getAttribute(uri) == null) {
161                    document = DocumentFactory.getInstance().getDocument(file, request.getContextPath(), uri);
162                } else {
163                    document = (Document) request.getSession().getAttribute(uri);
164                }
165                request.getSession().setAttribute(uri, document);
166            }
167    
168            translate(document, request);
169            return document;
170        }
171    
172        /**
173         * Translates labels texts and input type button/submit
174         *
175         * @param document
176         * @param request
177         */
178        private void translate(Document document, HttpServletRequest request) {
179            if (document.isTranslated()) {
180                return;
181            }
182    
183            MessageResources messages = getResources(request);
184    
185            // Get the URI /somfolder/somehtml.html to convert to somefolder.somehtml as a start key for the resources
186            String docKey = document.getUri();
187            if (docKey.startsWith("/")) {
188                docKey = docKey.substring(1);
189            }
190            int n = docKey.indexOf(".");
191            if (n > -1) {
192                docKey = docKey.substring(0, n);
193            }
194            docKey = docKey.replace("/", ".");
195            docKey = docKey.replace("\\", ".");
196            docKey = docKey.toLowerCase();
197            //---------------------------------
198            log.debug("docKey " + docKey);
199    
200            HTMLElement element;
201            String formKey;
202            for (int j = 0; j < document.getFormCount(); j++) {
203                formKey = document.forms(j).getName();
204                if (formKey.trim().length() == 0) {
205                    formKey = "form" + (j + 1);
206                }
207    
208                String elementName;
209                for (int k = 0; k < document.forms(j).getElementCount(); k++) {
210                    element = document.forms(j).elements(k);
211                    elementName = docKey + "." + formKey + "." + element.getName();
212                    log.debug("Element name " + elementName);
213    
214                    // Check for labels.
215                    if (element instanceof Label && !(element instanceof Text)) {
216    
217                        if (messages.isPresent(elementName)) {
218                            element.setValue(messages.getMessage(elementName));
219                        }
220                    } else {
221                        // Check for buttons - buttons display the value attribute
222                        if (element.hasAttribute("type") && (element.getAttribute("type").equalsIgnoreCase("button") || element.getAttribute("type").equalsIgnoreCase("submit"))) {
223    
224                            if (messages.isPresent(elementName)) {
225                                log.debug("setting element " + elementName);
226                                element.setValue(messages.getMessage(elementName));
227                            }
228                        }
229                    }
230    
231                    // check for title attribute
232                    if (element.hasAttribute("title")) {
233                        log.debug("Element name title: " + elementName + ".title");
234                        if (messages.isPresent(elementName + ".title")) {
235                            log.debug("setting title " + elementName);
236                            element.setAttribute("title", messages.getMessage(elementName + ".title"));
237                        }
238                    }
239                }
240            }
241            document.setTranslated(true);
242    
243        }
244    
245    
246    }