001: // Copyright 2006, 2007 The Apache Software Foundation
002: //
003: // Licensed under the Apache License, Version 2.0 (the "License");
004: // you may not use this file except in compliance with the License.
005: // You may obtain a copy of the License at
006: //
007: // http://www.apache.org/licenses/LICENSE-2.0
008: //
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014:
015: package org.apache.tapestry.ioc.internal.util;
016:
017: import java.util.Iterator;
018: import java.util.Locale;
019: import java.util.NoSuchElementException;
020:
021: /**
022: * Used in a wide variety of resource searches. Generates a series of name variations from a path
023: * (which must include a suffix) and locale.
024: * <P>
025: * This class is not threadsafe.
026: */
027: public class LocalizedNameGenerator implements Iterator<String>,
028: Iterable<String> {
029: private final int _baseNameLength;
030:
031: private final String _suffix;
032:
033: private final StringBuilder _builder;
034:
035: private final String _language;
036:
037: private final String _country;
038:
039: private final String _variant;
040:
041: private int _state;
042:
043: private int _prevState;
044:
045: private static final int INITIAL = 0;
046:
047: private static final int LCV = 1;
048:
049: private static final int LC = 2;
050:
051: private static final int LV = 3;
052:
053: private static final int L = 4;
054:
055: private static final int BARE = 5;
056:
057: private static final int EXHAUSTED = 6;
058:
059: public LocalizedNameGenerator(String path, Locale locale) {
060: int dotx = path.lastIndexOf('.');
061:
062: // TODO: Case where there is no suffix
063:
064: String baseName = path.substring(0, dotx);
065:
066: _suffix = path.substring(dotx);
067:
068: _baseNameLength = dotx;
069:
070: _language = locale.getLanguage();
071: _country = locale.getCountry();
072: _variant = locale.getVariant();
073:
074: _state = INITIAL;
075: _prevState = INITIAL;
076:
077: _builder = new StringBuilder(baseName);
078:
079: advance();
080: }
081:
082: private void advance() {
083: _prevState = _state;
084:
085: while (_state != EXHAUSTED) {
086: _state++;
087:
088: switch (_state) {
089: case LCV:
090:
091: if (InternalUtils.isBlank(_variant))
092: continue;
093:
094: return;
095:
096: case LC:
097:
098: if (InternalUtils.isBlank(_country))
099: continue;
100:
101: return;
102:
103: case LV:
104:
105: // If _country is null, then we've already generated this string
106: // as state LCV and we can continue directly to state L
107:
108: if (InternalUtils.isBlank(_variant)
109: || InternalUtils.isBlank(_country))
110: continue;
111:
112: return;
113:
114: case L:
115:
116: if (InternalUtils.isBlank(_language))
117: continue;
118:
119: return;
120:
121: case BARE:
122: default:
123: return;
124: }
125: }
126: }
127:
128: /**
129: * Returns true if there are more name variants to be returned, false otherwise.
130: */
131:
132: public boolean hasNext() {
133: return _state != EXHAUSTED;
134: }
135:
136: /**
137: * Returns the next localized variant.
138: *
139: * @throws NoSuchElementException
140: * if all variants have been returned.
141: */
142:
143: public String next() {
144: if (_state == EXHAUSTED)
145: throw new NoSuchElementException();
146:
147: String result = build();
148:
149: advance();
150:
151: return result;
152: }
153:
154: private String build() {
155: _builder.setLength(_baseNameLength);
156:
157: if (_state == LC || _state == LCV || _state == L) {
158: _builder.append('_');
159: _builder.append(_language);
160: }
161:
162: // For LV, we want two underscores between language
163: // and variant.
164:
165: if (_state == LC || _state == LCV || _state == LV) {
166: _builder.append('_');
167:
168: if (_state != LV)
169: _builder.append(_country);
170: }
171:
172: if (_state == LV || _state == LCV) {
173: _builder.append('_');
174: _builder.append(_variant);
175: }
176:
177: if (_suffix != null)
178: _builder.append(_suffix);
179:
180: return _builder.toString();
181: }
182:
183: public Locale getCurrentLocale() {
184: switch (_prevState) {
185: case LCV:
186:
187: return new Locale(_language, _country, _variant);
188:
189: case LC:
190:
191: return new Locale(_language, _country, "");
192:
193: case LV:
194:
195: return new Locale(_language, "", _variant);
196:
197: case L:
198:
199: return new Locale(_language, "", "");
200:
201: default:
202: return null;
203: }
204: }
205:
206: /** @throws UnsupportedOperationException */
207: public void remove() {
208: throw new UnsupportedOperationException();
209: }
210:
211: /** So that LNG may be used with the for loop. */
212: public Iterator<String> iterator() {
213: return this;
214: }
215:
216: }
|