Source Code Cross Referenced for GrowableInternationalString.java in  » GIS » GeoTools-2.4.1 » org » geotools » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2004-2006, Geotools Project Managment Committee (PMC)
005:         *    (C) 2004, Institut de Recherche pour le D�veloppement
006:         *
007:         *    This library is free software; you can redistribute it and/or
008:         *    modify it under the terms of the GNU Lesser General Public
009:         *    License as published by the Free Software Foundation; either
010:         *    version 2.1 of the License, or (at your option) any later version.
011:         *
012:         *    This library is distributed in the hope that it will be useful,
013:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         *    Lesser General Public License for more details.
016:         */
017:        package org.geotools.util;
018:
019:        // J2SE dependencies
020:        import java.io.IOException;
021:        import java.io.ObjectInputStream;
022:        import java.io.Serializable;
023:        import java.lang.reflect.Field;
024:        import java.lang.reflect.Modifier;
025:        import java.util.Collections;
026:        import java.util.HashMap;
027:        import java.util.Iterator;
028:        import java.util.Locale;
029:        import java.util.Map;
030:        import java.util.Set;
031:
032:        // OpenGIS utilities
033:        import org.opengis.util.InternationalString;
034:        import org.geotools.util.logging.Logging;
035:        import org.geotools.resources.Utilities;
036:        import org.geotools.resources.i18n.Errors;
037:        import org.geotools.resources.i18n.ErrorKeys;
038:
039:        /**
040:         * An implementation of international string using a {@linkplain Map map}
041:         * of strings for different {@linkplain Locale locales}. Strings for new
042:         * locales can be {@linkplain #add(Locale,String) added}, but existing
043:         * strings can't be removed or modified. This behavior is a compromise
044:         * between making constructionss easier, and being suitable for use in
045:         * immutable objects.
046:         *
047:         * @since 2.1
048:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/util/GrowableInternationalString.java $
049:         * @version $Id: GrowableInternationalString.java 27848 2007-11-12 13:10:32Z desruisseaux $
050:         * @author Martin Desruisseaux
051:         */
052:        public class GrowableInternationalString extends
053:                AbstractInternationalString implements  Serializable {
054:            /**
055:             * Serial number for interoperability with different versions.
056:             */
057:            private static final long serialVersionUID = 5760033376627376937L;
058:
059:            /**
060:             * The set of locales created in this virtual machine through methods of this class.
061:             * Used in order to get a {@linkplain #unique unique} instance of {@link Locale} objects.
062:             */
063:            private static final Map LOCALES = new HashMap();
064:
065:            /**
066:             * The string values in different locales (never {@code null}).
067:             * Keys are {@link Locale} objects and values are {@link String}s.
068:             */
069:            private Map localMap;
070:
071:            /**
072:             * An unmodifiable view of the entry set in {@link #localMap}. This is the set of locales
073:             * defined in this international string. Will be constructed only when first requested.
074:             */
075:            private transient Set localSet;
076:
077:            /**
078:             * Constructs an initially empty international string. Localized strings can been added
079:             * using one of {@link #add add(...)} methods.
080:             */
081:            public GrowableInternationalString() {
082:                localMap = Collections.EMPTY_MAP;
083:            }
084:
085:            /**
086:             * Constructs an international string initialized with the specified string.
087:             * Additional localized strings can been added using one of {@link #add add(...)}
088:             * methods. The string specified to this constructor is the one that will be
089:             * returned if no localized string is found for the {@link Locale} argument
090:             * in a call to {@link #toString(Locale)}.
091:             *
092:             * @param string The string in no specific locale.
093:             */
094:            public GrowableInternationalString(final String string) {
095:                if (string != null) {
096:                    localMap = Collections.singletonMap(null, string);
097:                } else {
098:                    localMap = Collections.EMPTY_MAP;
099:                }
100:            }
101:
102:            /**
103:             * Add a string for the given locale.
104:             *
105:             * @param  locale The locale for the {@code string} value, or {@code null}.
106:             * @param  string The localized string.
107:             * @throws IllegalArgumentException if a different string value was already set for
108:             *         the given locale.
109:             */
110:            public synchronized void add(final Locale locale,
111:                    final String string) throws IllegalArgumentException {
112:                if (string != null) {
113:                    switch (localMap.size()) {
114:                    case 0: {
115:                        localMap = Collections.singletonMap(locale, string);
116:                        defaultValue = null; // Will be recomputed when first needed.
117:                        return;
118:                    }
119:                    case 1: {
120:                        localMap = new HashMap(localMap);
121:                        break;
122:                    }
123:                    }
124:                    String old = (String) localMap.get(locale);
125:                    if (old != null) {
126:                        if (string.equals(old)) {
127:                            return;
128:                        }
129:                        // TODO: provide a localized message "String value already set for locale ...".
130:                        throw new IllegalArgumentException();
131:                    }
132:                    localMap.put(locale, string);
133:                    defaultValue = null; // Will be recomputed when first needed.
134:                }
135:            }
136:
137:            /**
138:             * Add a string for the given property key. This is a convenience method for constructing an
139:             * {@code AbstractInternationalString} during iteration through the
140:             * {@linkplain java.util.Map.Entry entries} in a {@link Map}. It infers the {@link Locale}
141:             * from the property {@code key}, using the following steps:
142:             * <ul>
143:             *   <li>If the {@code key} do not starts with the specified {@code prefix}, then
144:             *       this method do nothing and returns {@code false}.</li>
145:             *   <li>Otherwise, the characters after the {@code prefix} are parsed as an ISO language
146:             *       and country code, and the {@link #add(Locale,String)} method is
147:             *       invoked.</li>
148:             * </ul>
149:             *
150:             * <P>For example if the prefix is <code>"remarks"</code>, then the <code>"remarks_fr"</code>
151:             * property key stands for remarks in {@linkplain Locale#FRENCH French} while the
152:             * <code>"remarks_fr_CA"</code> property key stands for remarks in
153:             * {@linkplain Locale#CANADA_FRENCH French Canadian}.</P>
154:             *
155:             * @param  prefix The prefix to skip at the begining of the {@code key}.
156:             * @param  key The property key.
157:             * @param  string The localized string for the specified {@code key}.
158:             * @return {@code true} if the key has been recognized, or {@code false} otherwise.
159:             * @throws IllegalArgumentException if the locale after the prefix is an illegal code, or a
160:             *         different string value was already set for the given locale.
161:             */
162:            public boolean add(final String prefix, final String key,
163:                    final String string) throws IllegalArgumentException {
164:                if (!key.startsWith(prefix)) {
165:                    return false;
166:                }
167:                int position = prefix.length();
168:                final int length = key.length();
169:                final String[] parts = new String[] { "", "", "" };
170:                for (int i = 0; /*break condition inside*/; i++) {
171:                    if (position == length) {
172:                        final Locale locale = (i == 0) ? (Locale) null
173:                                : unique(new Locale(parts[0] /* language */,
174:                                        parts[1] /* country  */, parts[2] /* variant  */));
175:                        add(locale, string);
176:                        return true;
177:                    }
178:                    if (key.charAt(position) != '_' || i == parts.length) {
179:                        // Unknow character, or two many characters
180:                        break;
181:                    }
182:                    int next = key.indexOf('_', ++position);
183:                    if (next < 0) {
184:                        next = length;
185:                    } else if (next == position) {
186:                        // Found two consecutive '_' characters
187:                        break;
188:                    }
189:                    parts[i] = key.substring(position, position = next);
190:                }
191:                throw new IllegalArgumentException(Errors.format(
192:                        ErrorKeys.ILLEGAL_ARGUMENT_$2, "locale", key
193:                                .substring(prefix.length())));
194:            }
195:
196:            /**
197:             * Returns a canonical instance of the given locale.
198:             *
199:             * @param  locale The locale to canonicalize.
200:             * @return The canonical instance of {@code locale}.
201:             */
202:            private static synchronized Locale unique(final Locale locale) {
203:                /**
204:                 * Initialize the LOCALES map with the set of locales defined in the Locale class.
205:                 * This operation is done only once.
206:                 */
207:                if (LOCALES.isEmpty())
208:                    try {
209:                        final Field[] fields = Locale.class.getFields();
210:                        for (int i = 0; i < fields.length; i++) {
211:                            final Field field = fields[i];
212:                            if (Modifier.isStatic(field.getModifiers())) {
213:                                if (Locale.class.isAssignableFrom(field
214:                                        .getType())) {
215:                                    final Locale toAdd = (Locale) field
216:                                            .get(null);
217:                                    LOCALES.put(toAdd, toAdd);
218:                                }
219:                            }
220:                        }
221:                    } catch (Exception exception) {
222:                        /*
223:                         * Not a big deal if this operation fails (this is actually just an
224:                         * optimization for reducing memory usage). Log a warning and continue.
225:                         */
226:                        Logging.unexpectedException("org.geotools.util",
227:                                GrowableInternationalString.class, "unique",
228:                                exception);
229:                    }
230:                /*
231:                 * Now canonicalize the locale.
232:                 */
233:                final Locale candidate = (Locale) LOCALES.get(locale);
234:                if (candidate != null) {
235:                    return candidate;
236:                }
237:                LOCALES.put(locale, locale);
238:                return locale;
239:            }
240:
241:            /**
242:             * Returns the set of locales defined in this international string.
243:             */
244:            public Set getLocales() {
245:                // No need to synchronize; this is not a big deal if this object is built twice.
246:                if (localSet == null) {
247:                    localSet = Collections.unmodifiableSet(localMap.entrySet());
248:                }
249:                return localSet;
250:            }
251:
252:            /**
253:             * Returns a string in the specified locale. If there is no string for the specified
254:             * {@code locale}, then this method search for a locale without the
255:             * {@linkplain Locale#getVariant variant} part. If no string are found,
256:             * then this method search for a locale without the {@linkplain Locale#getCountry country}
257:             * part. For example if the <code>"fr_CA"</code> locale was requested but not found, then
258:             * this method looks for the <code>"fr"</code> locale. The {@code null} locale
259:             * (which stand for unlocalized message) is tried last.
260:             *
261:             * @param  locale The locale to look for, or {@code null}.
262:             * @return The string in the specified locale, or in a default locale.
263:             */
264:            public String toString(Locale locale) {
265:                String text;
266:                while (locale != null) {
267:                    text = (String) localMap.get(locale);
268:                    if (text != null) {
269:                        return text;
270:                    }
271:                    final String language = locale.getLanguage();
272:                    final String country = locale.getCountry();
273:                    final String variant = locale.getVariant();
274:                    if (variant.length() != 0) {
275:                        locale = new Locale(language, country);
276:                        continue;
277:                    }
278:                    if (country.length() != 0) {
279:                        locale = new Locale(language);
280:                        continue;
281:                    }
282:                    break;
283:                }
284:
285:                // Try the string in the 'null' locale.
286:                text = (String) localMap.get(null);
287:                if (text == null) {
288:                    // No 'null' locale neither. Returns the first string in whatever locale.
289:                    final Iterator it = localMap.values().iterator();
290:                    if (it.hasNext()) {
291:                        return (String) it.next();
292:                    }
293:                }
294:                return text;
295:            }
296:
297:            /**
298:             * Returns {@code true} if all localized texts stored in this international string are
299:             * contained in the specified object. More specifically:
300:             *
301:             * <ul>
302:             *   <li><p>If {@code candidate} is an instance of {@link InternationalString}, then this method
303:             *       returns {@code true} if, for all <var>{@linkplain Locale locale}</var>-<var>{@linkplain
304:             *       String string}</var> pairs contained in {@code this}, <code>candidate.{@linkplain
305:             *       InternationalString#toString(Locale) toString}(locale)</code> returns a string
306:             *       {@linkplain String#equals equals} to {@code string}.</p></li>
307:             *
308:             *   <li><p>If {@code candidate} is an instance of {@link CharSequence}, then this method
309:             *       returns {@code true} if {@link #toString(Locale)} returns a string {@linkplain
310:             *       String#equals equals} to <code>candidate.{@linkplain CharSequence#toString()
311:             *       toString()}</code> for all locales.</p></li>
312:             *
313:             *   <li><p>If {@code candidate} is an instance of {@link Map}, then this methods returns
314:             *       {@code true} if all <var>{@linkplain Locale locale}</var>-<var>{@linkplain String
315:             *       string}</var> pairs are contained into {@code candidate}.</p></li>
316:             *
317:             *   <li><p>Otherwise, this method returns {@code false}.</p></li>
318:             * </ul>
319:             *
320:             * @since 2.3
321:             */
322:            public boolean isSubsetOf(final Object candidate) {
323:                if (candidate instanceof  InternationalString) {
324:                    final InternationalString string = (InternationalString) candidate;
325:                    for (final Iterator it = localMap.entrySet().iterator(); it
326:                            .hasNext();) {
327:                        final Map.Entry entry = (Map.Entry) it.next();
328:                        final Locale locale = (Locale) entry.getKey();
329:                        final String text = (String) entry.getValue();
330:                        if (!text.equals(string.toString(locale))) {
331:                            return false;
332:                        }
333:                    }
334:                } else if (candidate instanceof  CharSequence) {
335:                    final String string = candidate.toString();
336:                    for (final Iterator it = localMap.values().iterator(); it
337:                            .hasNext();) {
338:                        final String text = (String) it.next();
339:                        if (!text.equals(string)) {
340:                            return false;
341:                        }
342:                    }
343:                } else if (candidate instanceof  Map) {
344:                    return ((Map) candidate).entrySet().containsAll(
345:                            localMap.entrySet());
346:                } else {
347:                    return false;
348:                }
349:                return true;
350:            }
351:
352:            /**
353:             * Compares this international string with the specified object for equality.
354:             */
355:            public boolean equals(final Object object) {
356:                if (object != null && object.getClass().equals(getClass())) {
357:                    final GrowableInternationalString that = (GrowableInternationalString) object;
358:                    return Utilities.equals(this .localMap, that.localMap);
359:                }
360:                return false;
361:            }
362:
363:            /**
364:             * Returns a hash code value for this international text.
365:             */
366:            public int hashCode() {
367:                return (int) serialVersionUID ^ localMap.hashCode();
368:            }
369:
370:            /**
371:             * Canonicalize the locales after deserialization.
372:             */
373:            private void readObject(final ObjectInputStream in)
374:                    throws IOException, ClassNotFoundException {
375:                in.defaultReadObject();
376:                final int size = localMap.size();
377:                if (size == 0) {
378:                    return;
379:                }
380:                final Map.Entry[] entries;
381:                entries = (Map.Entry[]) localMap.entrySet().toArray(
382:                        new Map.Entry[size]);
383:                if (size == 1) {
384:                    final Map.Entry entry = entries[0];
385:                    localMap = Collections.singletonMap(unique((Locale) entry
386:                            .getKey()), entry.getValue());
387:                } else {
388:                    localMap.clear();
389:                    for (int i = 0; i < entries.length; i++) {
390:                        final Map.Entry entry = entries[i];
391:                        localMap.put(unique((Locale) entry.getKey()), entry
392:                                .getValue());
393:                    }
394:                }
395:            }
396:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.