View Javadoc

1   /*
2    * $Id: I18n.java 651946 2008-04-27 13:41:38Z apetrelli $
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.struts2.components;
23  
24  import java.io.Writer;
25  import java.util.Locale;
26  import java.util.ResourceBundle;
27  
28  import org.apache.struts2.views.annotations.StrutsTag;
29  import org.apache.struts2.views.annotations.StrutsTagAttribute;
30  import org.apache.struts2.StrutsException;
31  
32  import com.opensymphony.xwork2.ActionContext;
33  import com.opensymphony.xwork2.LocaleProvider;
34  import com.opensymphony.xwork2.TextProviderFactory;
35  import com.opensymphony.xwork2.TextProvider;
36  import com.opensymphony.xwork2.inject.Container;
37  import com.opensymphony.xwork2.inject.Inject;
38  import com.opensymphony.xwork2.util.LocalizedTextUtil;
39  import com.opensymphony.xwork2.util.ValueStack;
40  import com.opensymphony.xwork2.util.logging.Logger;
41  import com.opensymphony.xwork2.util.logging.LoggerFactory;
42  
43  /***
44   * <!-- START SNIPPET: javadoc -->
45   *
46   * Gets a resource bundle and place it on the value stack. This allows
47   * the text tag to access messages from any bundle, and not just the bundle
48   * associated with the current action.
49   *
50   * <!-- END SNIPPET: javadoc -->
51   *
52   * <p/>
53   *
54   * <!-- START SNIPPET: params-->
55   *
56   * <ul>
57   *      <li>name* - the resource bundle's name (eg foo/bar/customBundle)</li>
58   * </ul>
59   *
60   * <!-- END SNIPPET: params -->
61   *
62   * <p/>
63   *
64   * Example:
65   *
66   * <pre>
67   * <!-- START SNIPPET: example -->
68   *
69   * &lt;s:i18n name="myCustomBundle"&gt;
70   *    The i18n value for key aaa.bbb.ccc in myCustomBundle is &lt;s:property value="text('aaa.bbb.ccc')" /&gt;
71   * &lt;/s:i18n&gt;
72   *
73   * <!-- END SNIPPET: example -->
74   * </pre>
75   *
76   *
77   * <pre>
78   * <!-- START SNIPPET: i18nExample -->
79   *
80   * &lt;s:i18n name="some.package.bundle" &gt;
81   *      &lt;s:text name="some.key" /&gt;
82   * &lt;/s:i18n&gt;
83   *
84   * <!-- END SNIPPET: i18nExample -->
85   * </pre>
86   *
87   */
88  @StrutsTag(name="i18n", tldTagClass="org.apache.struts2.views.jsp.I18nTag", description="Get a resource bundle" +
89                  " and place it on the value stack")
90  public class I18n extends Component {
91  
92      private static final Logger LOG = LoggerFactory.getLogger(I18n.class);
93  
94      protected boolean pushed;
95      protected String name;
96      protected Container container;
97      private TextProvider textProvider;
98  
99      public I18n(ValueStack stack) {
100         super(stack);
101     }
102     
103     @Inject
104     public void setContainer(Container container) {
105         this.container = container;
106     }
107 
108     public boolean start(Writer writer) {
109         boolean result = super.start(writer);
110 
111         try {
112             String name = this.findString(this.name, "name", "Resource bundle name is required. Example: foo or foo_en");
113             ResourceBundle bundle = (ResourceBundle) findValue("getTexts('" + name + "')");
114 
115             if (bundle == null) {
116                 bundle = LocalizedTextUtil.findResourceBundle(name, (Locale) getStack().getContext().get(ActionContext.LOCALE));
117             }
118 
119             if (bundle != null) {
120                 final Locale locale = (Locale) getStack().getContext().get(ActionContext.LOCALE);
121                 TextProviderFactory tpf = new TextProviderFactory();
122                 container.inject(tpf);
123                 textProvider = tpf.createInstance(bundle, new LocaleProvider() {
124                     public Locale getLocale() {
125                         return locale;
126                     }
127                 });
128                 getStack().push(textProvider);
129                 pushed = true;
130             }
131         } catch (Exception e) {
132             String msg = "Could not find the bundle " + name;
133             throw new StrutsException(msg, e);
134         }
135 
136         return result;
137     }
138 
139     public boolean end(Writer writer, String body) throws StrutsException {
140         if (pushed) {
141             Object o = getStack().pop();
142             if ((o == null) || (!o.equals(textProvider))) {
143                 LOG.error("A closing i18n tag attempted to pop its own TextProvider from the top of the ValueStack but popped an unexpected object ("+(o != null ? o.getClass() : "null")+"). " +
144                             "Refactor the page within the i18n tags to ensure no objects are pushed onto the ValueStack without popping them prior to the closing tag. " +
145                             "If you see this message it's likely that the i18n's TextProvider is still on the stack and will continue to provide message resources after the closing tag.");
146                 throw new StrutsException("A closing i18n tag attempted to pop its TextProvider from the top of the ValueStack but popped an unexpected object ("+(o != null ? o.getClass() : "null")+")");
147             }
148         }
149 
150         return super.end(writer, body);
151     }
152 
153     @StrutsTagAttribute(description="Name of resource bundle to use (eg foo/bar/customBundle)", required=true, defaultValue="String")
154     public void setName(String name) {
155         this.name = name;
156     }
157 }