View Javadoc
1   /*
2    * $Id$
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  package org.apache.struts.faces.renderer;
23  
24  
25  import java.beans.Beans;
26  import java.io.IOException;
27  import java.util.Iterator;
28  import java.util.Locale;
29  
30  import org.apache.struts.Globals;
31  import org.apache.struts.action.ActionMessage;
32  import org.apache.struts.action.ActionMessages;
33  import org.apache.struts.util.MessageResources;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  
37  import jakarta.faces.application.FacesMessage;
38  import jakarta.faces.component.UIComponent;
39  import jakarta.faces.context.FacesContext;
40  import jakarta.faces.context.ResponseWriter;
41  
42  
43  /**
44   * <p><code>Renderer</code> implementation for the <code>errors</code> tag
45   * from the <em>Struts-Faces Integration Library</em>.</p>
46   *
47   * @version $Rev$ $Date$
48   */
49  
50  public class ErrorsRenderer extends AbstractRenderer {
51  
52  
53      // -------------------------------------------------------- Static Variables
54  
55  
56      /**
57       * The {@code Log} instance for this class.
58       */
59      private final Logger log =
60          LoggerFactory.getLogger(ErrorsRenderer.class);
61  
62  
63      /**
64       * The dummy message resources for this package.
65       */
66      protected static MessageResources dummy =
67        MessageResources.getMessageResources
68          ("org.apache.struts.faces.renderer.Dummy");
69  
70      // ---------------------------------------------------------- Public Methods
71  
72  
73      /**
74       * <p>Render a combination of error messages from JavaServer Faces
75       * <code>Validator</code>s, and Struts messages from form bean
76       * <code>validate()</code> methods and corresponding business logic
77       * error checks.</p>
78       *
79       * @param context FacesContext for the request we are processing
80       * @param component UIComponent to be rendered
81       *
82       * @exception IOException if an input/output error occurs while rendering
83       * @exception NullPointerException if <code>context</code>
84       *  or <code>component</code> is null
85       */
86      public void encodeEnd(FacesContext context, UIComponent component)
87          throws IOException {
88  
89          if ((context == null) || (component == null)) {
90              throw new NullPointerException();
91          }
92  
93          log.debug("encodeEnd() started");
94  
95          // Look up availability of our predefined resource keys
96          MessageResources resources = resources(context, component);
97          if (Beans.isDesignTime() && (resources == null)) {
98              resources = dummy;
99          }
100         Locale locale = context.getViewRoot().getLocale();
101         boolean headerPresent = resources.isPresent(locale, "errors.header");
102         boolean footerPresent = resources.isPresent(locale, "errors.footer");
103         boolean prefixPresent = resources.isPresent(locale, "errors.prefix");
104         boolean suffixPresent = resources.isPresent(locale, "errors.suffix");
105 
106         // Set up to render the error messages appropriately
107         boolean headerDone = false;
108         ResponseWriter writer = context.getResponseWriter();
109         String id = component.getId();
110         String property = (String) component.getAttributes().get("property");
111         if (id != null) {
112             writer.startElement("span", component);
113             if (id != null) {
114                 writer.writeAttribute("id", component.getClientId(context),
115                                       "id");
116             }
117         }
118 
119         // Render any JavaServer Faces messages
120         Iterator<FacesMessage> messages = context.getMessages(property);
121         while (messages.hasNext()) {
122             FacesMessage message = messages.next();
123             log.trace("Processing FacesMessage: {}", message.getSummary());
124             if (!headerDone) {
125                 if (headerPresent) {
126                     writer.write
127                         (resources.getMessage(locale, "errors.header"));
128                 }
129                 headerDone = true;
130             }
131             if (prefixPresent) {
132                 writer.write(resources.getMessage(locale, "errors.prefix"));
133             }
134             writer.write(message.getSummary());
135             if (suffixPresent) {
136                 writer.write(resources.getMessage(locale, "errors.suffix"));
137             }
138         }
139 
140         // Render any Struts messages
141         ActionMessages errors = (ActionMessages)
142             context.getExternalContext().getRequestMap().get
143             (Globals.ERROR_KEY);
144         if (errors != null) {
145             log.trace("Processing Struts messages for property '{}'",
146                 property);
147             Iterator<ActionMessage> reports = null;
148             if (property == null) {
149                 reports = errors.get();
150             } else {
151                 reports = errors.get(property);
152             }
153             while (reports.hasNext()) {
154                 ActionMessage report = reports.next();
155                 log.trace("Processing Struts message key='{}'",
156                     report.getKey());
157                 if (!headerDone) {
158                     writer = context.getResponseWriter();
159                     if (headerPresent) {
160                         writer.write
161                             (resources.getMessage(locale, "errors.header"));
162                     }
163                     headerDone = true;
164                 }
165                 if (prefixPresent) {
166                     writer.write
167                         (resources.getMessage(locale, "errors.prefix"));
168                 }
169                 writer.write(resources.getMessage(locale, report.getKey(),
170                                                   report.getValues()));
171                 if (suffixPresent) {
172                     writer.write
173                         (resources.getMessage(locale, "errors.suffix"));
174                 }
175             }
176         }
177 
178         // Append the list footer if needed
179         if (headerDone && footerPresent) {
180             writer.write(resources.getMessage(locale, "errors.footer"));
181         }
182         if (id != null) {
183             writer.endElement("span");
184         }
185 
186         log.debug("encodeEnd() finished");
187 
188     }
189 
190 
191 
192     // ------------------------------------------------------ Protected Methods
193 
194 
195     /**
196      * <p>Return the <code>MessageResources</code> bundle from which
197      * we should return any Struts based error messages.  If no such
198      * bundle can be located, return <code>null</code>.</p>
199      *
200      * @param context FacesContext for the request we are processing
201      * @param component UIComponent to be rendered
202      */
203     protected MessageResources resources(FacesContext context,
204                                          UIComponent component) {
205 
206         String bundle = (String) component.getAttributes().get("bundle");
207         if (bundle == null) {
208             bundle = Globals.MESSAGES_KEY;
209         }
210         return ((MessageResources)
211                 context.getExternalContext().getApplicationMap().get(bundle));
212 
213     }
214 }