Source Code Cross Referenced for FxValue.java in  » J2EE » fleXive » com » flexive » shared » value » 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 » J2EE » fleXive » com.flexive.shared.value 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /***************************************************************
0002:         *  This file is part of the [fleXive](R) project.
0003:         *
0004:         *  Copyright (c) 1999-2008
0005:         *  UCS - unique computing solutions gmbh (http://www.ucs.at)
0006:         *  All rights reserved
0007:         *
0008:         *  The [fleXive](R) project is free software; you can redistribute
0009:         *  it and/or modify it under the terms of the GNU General Public
0010:         *  License as published by the Free Software Foundation;
0011:         *  either version 2 of the License, or (at your option) any
0012:         *  later version.
0013:         *
0014:         *  The GNU General Public License can be found at
0015:         *  http://www.gnu.org/copyleft/gpl.html.
0016:         *  A copy is found in the textfile GPL.txt and important notices to the
0017:         *  license from the author are found in LICENSE.txt distributed with
0018:         *  these libraries.
0019:         *
0020:         *  This library is distributed in the hope that it will be useful,
0021:         *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0022:         *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0023:         *  GNU General Public License for more details.
0024:         *
0025:         *  For further information about UCS - unique computing solutions gmbh,
0026:         *  please see the company website: http://www.ucs.at
0027:         *
0028:         *  For further information about [fleXive](R), please see the
0029:         *  project website: http://www.flexive.org
0030:         *
0031:         *
0032:         *  This copyright notice MUST APPEAR in all copies of the file!
0033:         ***************************************************************/package com.flexive.shared.value;
0034:
0035:        import com.flexive.shared.*;
0036:        import com.flexive.shared.exceptions.FxInvalidParameterException;
0037:        import com.flexive.shared.exceptions.FxInvalidStateException;
0038:        import com.flexive.shared.exceptions.FxNoAccessException;
0039:        import com.flexive.shared.security.UserTicket;
0040:        import com.flexive.shared.value.renderer.FxValueRendererFactory;
0041:        import org.apache.commons.lang.ArrayUtils;
0042:
0043:        import java.io.Serializable;
0044:        import java.lang.reflect.Method;
0045:        import java.util.HashMap;
0046:        import java.util.Map;
0047:        import java.util.Map.Entry;
0048:
0049:        /**
0050:         * Abstract base class of all value objects.
0051:         * Common base classed is used for multilingual properties, etc.
0052:         * <p/>
0053:         * To check if a value is empty a flag is used for each language resp. the single value.
0054:         * Use the setEmpty() method to explicity set a value to be empty
0055:         *
0056:         * @author Markus Plesser (markus.plesser@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
0057:         */
0058:        public abstract class FxValue<T, TDerived extends FxValue<T, TDerived>>
0059:                implements  Serializable, Comparable<FxValue> {
0060:            private static final long serialVersionUID = -5005063788615664383L;
0061:
0062:            public static final boolean DEFAULT_MULTILANGUAGE = true;
0063:            private boolean multiLanguage;
0064:            private long defaultLanguage = FxLanguage.SYSTEM_ID;
0065:            private long selectedLanguage;
0066:            private int maxInputLength;
0067:            private String XPath = "";
0068:
0069:            private final static Long[] SYSTEM_LANG_ARRAY = new Long[] { FxLanguage.SYSTEM_ID };
0070:
0071:            /**
0072:             * Data if <code>multiLanguage</code> is enabled
0073:             */
0074:            protected Map<Long, T> translations;
0075:            protected Map<Long, Boolean> emptyTranslations;
0076:
0077:            /**
0078:             * Data if <code>multiLanguage</code> is disabled
0079:             */
0080:            protected T singleValue;
0081:            private boolean singleValueEmpty;
0082:            private boolean readOnly;
0083:
0084:            protected FxValue() {
0085:
0086:            }
0087:
0088:            /**
0089:             * Constructor
0090:             *
0091:             * @param multiLanguage   multilanguage value?
0092:             * @param defaultLanguage the default language
0093:             * @param translations    HashMap containing language->translation mapping
0094:             */
0095:            protected FxValue(boolean multiLanguage, long defaultLanguage,
0096:                    Map<Long, T> translations) {
0097:                this .defaultLanguage = defaultLanguage;
0098:                this .multiLanguage = multiLanguage;
0099:                this .maxInputLength = -1;
0100:                this .readOnly = false;
0101:                if (multiLanguage) {
0102:                    if (translations == null) {
0103:                        //valid to pass null, create an empty one
0104:                        this .translations = new HashMap<Long, T>(5);
0105:                        this .emptyTranslations = new HashMap<Long, Boolean>(5);
0106:                    } else {
0107:                        this .translations = new HashMap<Long, T>(translations);
0108:                        this .emptyTranslations = new HashMap<Long, Boolean>(
0109:                                translations.size());
0110:                    }
0111:                    if (this .defaultLanguage < 0) {
0112:                        this .defaultLanguage = FxLanguage.SYSTEM_ID;
0113:                        this .selectedLanguage = FxLanguage.SYSTEM_ID;
0114:                        if (translations != null
0115:                                && !translations.entrySet().isEmpty())
0116:                            for (Entry<Long, T> e : translations.entrySet())
0117:                                if (e.getValue() != null) {
0118:                                    this .selectedLanguage = e.getKey();
0119:                                    break;
0120:                                }
0121:                    } else
0122:                        this .selectedLanguage = this .defaultLanguage;
0123:                    for (Long lang : this .translations.keySet())
0124:                        emptyTranslations.put(lang,
0125:                                this .translations.get(lang) == null);
0126:                } else {
0127:                    if (translations != null && !translations.isEmpty()) {
0128:                        //a translation is provided, use the defaultLanguage element or very first element if not present
0129:                        singleValue = translations.get(defaultLanguage);
0130:                        if (singleValue == null)
0131:                            singleValue = translations.values().iterator()
0132:                                    .next();
0133:                    }
0134:                    this .defaultLanguage = FxLanguage.SYSTEM_ID;
0135:                    this .selectedLanguage = FxLanguage.SYSTEM_ID;
0136:                    this .translations = null;
0137:                    this .singleValueEmpty = false;
0138:                }
0139:            }
0140:
0141:            /**
0142:             * Constructor
0143:             *
0144:             * @param defaultLanguage the default language
0145:             * @param translations    HashMap containing language->translation mapping
0146:             */
0147:            protected FxValue(long defaultLanguage, Map<Long, T> translations) {
0148:                this (DEFAULT_MULTILANGUAGE, defaultLanguage, translations);
0149:            }
0150:
0151:            /**
0152:             * Constructor
0153:             *
0154:             * @param multiLanguage multilanguage value?
0155:             * @param translations  HashMap containing language->translation mapping
0156:             */
0157:            protected FxValue(boolean multiLanguage, Map<Long, T> translations) {
0158:                this (multiLanguage, FxLanguage.SYSTEM_ID, translations);
0159:            }
0160:
0161:            /**
0162:             * Constructor
0163:             *
0164:             * @param translations HashMap containing language->translation mapping
0165:             */
0166:            protected FxValue(Map<Long, T> translations) {
0167:                this (DEFAULT_MULTILANGUAGE, FxLanguage.SYSTEM_ID, translations);
0168:            }
0169:
0170:            /**
0171:             * Constructor - create value from an array of translations
0172:             *
0173:             * @param translations HashMap containing language->translation mapping
0174:             * @param pos          position (index) in the array to use
0175:             */
0176:            protected FxValue(Map<Long, T[]> translations, int pos) {
0177:                this (DEFAULT_MULTILANGUAGE, FxLanguage.SYSTEM_ID,
0178:                        new HashMap<Long, T>((translations == null ? 5
0179:                                : translations.size())));
0180:                if (multiLanguage) {
0181:                    if (translations == null)
0182:                        return;
0183:                    for (Entry<Long, T[]> e : translations.entrySet())
0184:                        if (e.getValue()[pos] != null)
0185:                            this .translations
0186:                                    .put(e.getKey(), e.getValue()[pos]);
0187:                } else
0188:                    this .singleValue = (translations == null
0189:                            || translations.isEmpty() ? null : translations
0190:                            .values().iterator().next()[pos]);
0191:            }
0192:
0193:            /**
0194:             * Constructor
0195:             *
0196:             * @param multiLanguage   multilanguage value?
0197:             * @param defaultLanguage the default language
0198:             * @param value           single initializing value
0199:             */
0200:            protected FxValue(boolean multiLanguage, long defaultLanguage,
0201:                    T value) {
0202:                this (multiLanguage, defaultLanguage, new HashMap<Long, T>(5));
0203:                if (multiLanguage)
0204:                    this .translations.put(defaultLanguage, value);
0205:                else
0206:                    this .singleValue = value;
0207:            }
0208:
0209:            /**
0210:             * Constructor
0211:             *
0212:             * @param defaultLanguage the default language
0213:             * @param value           single initializing value
0214:             */
0215:            protected FxValue(long defaultLanguage, T value) {
0216:                this (DEFAULT_MULTILANGUAGE, defaultLanguage, value);
0217:            }
0218:
0219:            /**
0220:             * Constructor
0221:             *
0222:             * @param multiLanguage multilanguage value?
0223:             * @param value         single initializing value
0224:             */
0225:            protected FxValue(boolean multiLanguage, T value) {
0226:                this (multiLanguage, FxLanguage.DEFAULT_ID, value);
0227:            }
0228:
0229:            /**
0230:             * Constructor
0231:             *
0232:             * @param value single initializing value
0233:             */
0234:            protected FxValue(T value) {
0235:                this (DEFAULT_MULTILANGUAGE, value);
0236:            }
0237:
0238:            /**
0239:             * Constructor
0240:             *
0241:             * @param clone original FxValue to be cloned
0242:             */
0243:            @SuppressWarnings("unchecked")
0244:            protected FxValue(FxValue<T, TDerived> clone) {
0245:                this (
0246:                        clone.isMultiLanguage(),
0247:                        clone.getDefaultLanguage(),
0248:                        new HashMap<Long, T>(
0249:                                (clone.translations != null ? clone.translations
0250:                                        .size()
0251:                                        : 1)));
0252:                this .XPath = clone.XPath;
0253:                if (clone.isImmutableValueType()) {
0254:                    if (multiLanguage) {
0255:                        // clone only hashmap
0256:                        this .translations = new HashMap(clone.translations);
0257:                        this .emptyTranslations = new HashMap(
0258:                                clone.emptyTranslations);
0259:                    } else {
0260:                        this .singleValue = clone.singleValue;
0261:                        this .singleValueEmpty = clone.singleValueEmpty;
0262:                    }
0263:                } else {
0264:                    if (multiLanguage) {
0265:                        // clone hashmap values
0266:                        Method meth = null;
0267:                        for (long k : clone.translations.keySet()) {
0268:                            T t = clone.translations.get(k);
0269:                            if (t == null)
0270:                                this .translations.put(k, null);
0271:                            else {
0272:                                try {
0273:                                    if (meth != null) {
0274:                                        this .translations.put(k, (T) meth
0275:                                                .invoke(t));
0276:                                    } else {
0277:                                        Class<?> clzz = t.getClass();
0278:                                        meth = clzz.getMethod("clone");
0279:                                    }
0280:                                } catch (Exception e) {
0281:                                    throw new IllegalArgumentException(
0282:                                            "clone not supported", e);
0283:                                }
0284:                            }
0285:                        }
0286:                        this .emptyTranslations = new HashMap(
0287:                                clone.emptyTranslations);
0288:                    } else {
0289:                        try {
0290:                            this .singleValue = (T) clone.singleValue.getClass()
0291:                                    .getMethod("clone").invoke(
0292:                                            clone.singleValue);
0293:                        } catch (Exception e) {
0294:                            throw new IllegalArgumentException(
0295:                                    "clone not supported", e);
0296:                        }
0297:                        this .singleValueEmpty = clone.singleValueEmpty;
0298:                    }
0299:                }
0300:            }
0301:
0302:            /**
0303:             * Get the XPath for this value - the XPath is optional and can be an empty String if
0304:             * not explicitly assigned!
0305:             *
0306:             * @return XPath (optional! can be an empty String)
0307:             */
0308:            public String getXPath() {
0309:                return XPath;
0310:            }
0311:
0312:            /**
0313:             * Returns the name of the value from the xpath.
0314:             * <p/>
0315:             * If the xpath is an empty string the name will also return an emptry String.
0316:             *
0317:             * @return the property name
0318:             */
0319:            public String getXPathName() {
0320:                try {
0321:                    String xpathSplit[] = getXPath().split("/");
0322:                    return xpathSplit[xpathSplit.length - 1].split("\\[")[0];
0323:                } catch (Throwable t) {
0324:                    return "";
0325:                }
0326:            }
0327:
0328:            /**
0329:             * Set the XPath (unless readonly)
0330:             *
0331:             * @param XPath the XPath to set, will be ignored if readonly
0332:             * @return this
0333:             */
0334:            @SuppressWarnings({"unchecked"})
0335:            public TDerived setXPath(String XPath) {
0336:                if (!this .readOnly) {
0337:                    this .XPath = XPath;
0338:                }
0339:                return (TDerived) this ;
0340:            }
0341:
0342:            /**
0343:             * One-time operation to flag this FxValue as read only.
0344:             * This is not reversible!
0345:             */
0346:            public void setReadOnly() {
0347:                this .readOnly = true;
0348:            }
0349:
0350:            /**
0351:             * Mark this FxValue as empty
0352:             *
0353:             * @return this
0354:             */
0355:            @SuppressWarnings("unchecked")
0356:            public TDerived setEmpty() {
0357:                if (this .multiLanguage) {
0358:                    if (this .emptyTranslations == null)
0359:                        this .emptyTranslations = new HashMap<Long, Boolean>(
0360:                                this .translations.size());
0361:                    for (Long lang : this .translations.keySet())
0362:                        this .emptyTranslations.put(lang, true);
0363:                } else
0364:                    this .singleValueEmpty = true;
0365:                return (TDerived) this ;
0366:            }
0367:
0368:            /**
0369:             * Mark the entry for the given language as empty
0370:             *
0371:             * @param language the language to flag as empty
0372:             */
0373:            public void setEmpty(long language) {
0374:                if (this .multiLanguage) {
0375:                    if (this .emptyTranslations == null)
0376:                        this .emptyTranslations = new HashMap<Long, Boolean>(
0377:                                this .translations.size());
0378:                    this .emptyTranslations.put(language, true);
0379:                } else
0380:                    this .singleValueEmpty = true;
0381:            }
0382:
0383:            /**
0384:             * Return the class instance of the value type.
0385:             *
0386:             * @return the class instance of the value type.
0387:             */
0388:            public abstract Class<T> getValueClass();
0389:
0390:            /**
0391:             * Evaluates the given string value to an object of type T.
0392:             *
0393:             * @param value string value to be evaluated
0394:             * @return the value interpreted as T
0395:             */
0396:            public abstract T fromString(String value);
0397:
0398:            /**
0399:             * Converts the given instance of T to a string that can be
0400:             * parsed again by {@link FxValue#fromString(String)}.
0401:             *
0402:             * @param value the value to be converted
0403:             * @return a string representation of the given value that can be parsed again using
0404:             *         {@link FxValue#fromString(String)}.
0405:             */
0406:            public String getStringValue(T value) {
0407:                return String.valueOf(value);
0408:            }
0409:
0410:            /**
0411:             * Creates a copy of the given object (useful if the actual type is unknown).
0412:             *
0413:             * @return a copy of the given object (useful if the actual type is unknown).
0414:             */
0415:            public abstract TDerived copy();
0416:
0417:            /**
0418:             * Return true if T is immutable (e.g. java.lang.String). This prevents cloning
0419:             * of the translations in copy constructors.
0420:             *
0421:             * @return true if T is immutable (e.g. java.lang.String)
0422:             */
0423:            public boolean isImmutableValueType() {
0424:                return true;
0425:            }
0426:
0427:            /**
0428:             * Is this value editable by the user?
0429:             * This always returns true except it is a FxNoAccess value or flagged as readOnly
0430:             *
0431:             * @return if this value editable?
0432:             * @see FxNoAccess
0433:             */
0434:            public boolean isReadOnly() {
0435:                return readOnly;
0436:            }
0437:
0438:            /**
0439:             * Returns true if this value is valid for the actual type (e.g. if
0440:             * a FxNumber property actually contains only valid numbers).
0441:             *
0442:             * @return true if this value is valid for the actual type
0443:             */
0444:            public boolean isValid() {
0445:                //noinspection UnusedCatchParameter
0446:                try {
0447:                    getErrorValue();
0448:                    // an error value exists, thus this instance is invalid
0449:                    return false;
0450:                } catch (IllegalStateException e) {
0451:                    // this instance is valid, thus no error value could be retrieved
0452:                    return true;
0453:                }
0454:            }
0455:
0456:            /**
0457:             * Returns the value that caused {@link #isValid} to return false. If isValid() is true,
0458:             * a RuntimeException is thrown.
0459:             *
0460:             * @return the value that caused the validation via {@link #isValid} to fail
0461:             * @throws IllegalStateException if the instance is valid and the error value is undefined
0462:             */
0463:            @SuppressWarnings({"UnusedCatchParameter"})
0464:            public T getErrorValue() throws IllegalStateException {
0465:                if (multiLanguage) {
0466:                    for (T translation : translations.values()) {
0467:                        if (translation instanceof  String) {
0468:                            // if a string was used, check if it is a valid representation of our type
0469:                            try {
0470:                                fromString((String) translation);
0471:                            } catch (Exception e) {
0472:                                return translation;
0473:                            }
0474:                        }
0475:                    }
0476:                } else if (singleValue instanceof  String) {
0477:                    try {
0478:                        fromString((String) singleValue);
0479:                    } catch (Exception e) {
0480:                        return singleValue;
0481:                    }
0482:                }
0483:                throw new IllegalStateException();
0484:            }
0485:
0486:            /**
0487:             * Get a representation of this value in the default translation
0488:             *
0489:             * @return T
0490:             */
0491:            public T getDefaultTranslation() {
0492:                if (!multiLanguage)
0493:                    return singleValue;
0494:                T def = getTranslation(getDefaultLanguage());
0495:                if (def != null)
0496:                    return def;
0497:                if (translations.size() > 0)
0498:                    return translations.values().iterator().next(); //first available translation if default does not exist
0499:                return def; //empty as last fallback
0500:            }
0501:
0502:            /**
0503:             * Get the translation for a requested language
0504:             *
0505:             * @param lang requested language
0506:             * @return translation or an empty String if it does not exist
0507:             */
0508:            public T getTranslation(long lang) {
0509:                return (multiLanguage ? translations.get(lang) : singleValue);
0510:            }
0511:
0512:            /**
0513:             * Get a String representation of this value in the requested language or
0514:             * an empty String if the translation does not exist
0515:             *
0516:             * @param lang requested language id
0517:             * @return T translation
0518:             */
0519:            public T getTranslation(FxLanguage lang) {
0520:                if (!multiLanguage) //redundant but faster
0521:                    return singleValue;
0522:                return getTranslation((int) lang.getId());
0523:            }
0524:
0525:            /**
0526:             * Get the translation that best fits the requested language.
0527:             * The requested language is queried and if it does not exist the
0528:             * default translation is returned
0529:             *
0530:             * @param lang requested best-fit language
0531:             * @return best fit translation
0532:             */
0533:            public T getBestTranslation(long lang) {
0534:                if (!multiLanguage) //redundant but faster
0535:                    return singleValue;
0536:                T ret = getTranslation(lang);
0537:                if (ret != null)
0538:                    return ret;
0539:                return getDefaultTranslation();
0540:            }
0541:
0542:            /**
0543:             * Get the translation that best fits the requested language.
0544:             * The requested language is queried and if it does not exist the
0545:             * default translation is returned
0546:             *
0547:             * @param language requested best-fit language
0548:             * @return best fit translation
0549:             */
0550:            public T getBestTranslation(FxLanguage language) {
0551:                if (!multiLanguage) //redundant but faster
0552:                    return singleValue;
0553:                if (language == null) // user ticket language
0554:                    return getBestTranslation();
0555:                return getBestTranslation((int) language.getId());
0556:            }
0557:
0558:            /**
0559:             * Get the translation that best fits the requested users language.
0560:             * The requested users language is queried and if it does not exist the
0561:             * default translation is returned
0562:             *
0563:             * @param ticket UserTicket to obtain the users language
0564:             * @return best fit translation
0565:             */
0566:            public T getBestTranslation(UserTicket ticket) {
0567:                if (!multiLanguage) //redundant but faster
0568:                    return singleValue;
0569:                return getBestTranslation((int) ticket.getLanguage().getId());
0570:            }
0571:
0572:            /**
0573:             * Get the translation that best fits the current users language.
0574:             * The user language is obtained from the FxContext thread local.
0575:             *
0576:             * @return best fit translation
0577:             */
0578:            public T getBestTranslation() {
0579:                if (!multiLanguage) //redundant but faster
0580:                    return singleValue;
0581:                return getBestTranslation(FxContext.get().getTicket()
0582:                        .getLanguage());
0583:            }
0584:
0585:            /**
0586:             * Get all languages for which translations exist
0587:             *
0588:             * @return languages for which translations exist
0589:             */
0590:            public Long[] getTranslatedLanguages() {
0591:                return (multiLanguage ? translations.keySet().toArray(
0592:                        new Long[translations.keySet().size()])
0593:                        : SYSTEM_LANG_ARRAY.clone());
0594:            }
0595:
0596:            /**
0597:             * Does a translation exist for the given language?
0598:             *
0599:             * @param languageId language to query
0600:             * @return translation exists
0601:             */
0602:            public boolean translationExists(long languageId) {
0603:                return !multiLanguage || translations.get(languageId) != null;
0604:            }
0605:
0606:            /**
0607:             * Like empty(), for JSF EL, since empty cannot be used.
0608:             *
0609:             * @return true if the value is empty
0610:             */
0611:            public boolean getIsEmpty() {
0612:                return isEmpty();
0613:            }
0614:
0615:            /**
0616:             * Is this value empty?
0617:             *
0618:             * @return if value is empty
0619:             */
0620:            public boolean isEmpty() {
0621:                if (multiLanguage) {
0622:                    syncEmptyTranslations();
0623:                    for (boolean check : emptyTranslations.values())
0624:                        if (!check)
0625:                            return false;
0626:                    return true;
0627:                } else
0628:                    return singleValueEmpty;
0629:            }
0630:
0631:            /**
0632:             * Check if the translation for the given language is empty
0633:             *
0634:             * @param lang language to check
0635:             * @return if translation for the given language is empty
0636:             */
0637:            public boolean isTranslationEmpty(FxLanguage lang) {
0638:                return lang != null ? isTranslationEmpty(lang.getId())
0639:                        : isEmpty();
0640:            }
0641:
0642:            /**
0643:             * Check if the translation for the given language is empty
0644:             *
0645:             * @param lang language to check
0646:             * @return if translation for the given language is empty
0647:             */
0648:            public boolean isTranslationEmpty(long lang) {
0649:                if (!multiLanguage)
0650:                    return singleValueEmpty;
0651:                syncEmptyTranslations();
0652:                return !emptyTranslations.containsKey(lang)
0653:                        || emptyTranslations.get(lang);
0654:            }
0655:
0656:            /**
0657:             * Synchronize - and create if needed - empty tanslations
0658:             */
0659:            private void syncEmptyTranslations() {
0660:                if (!multiLanguage)
0661:                    return;
0662:                if (emptyTranslations == null)
0663:                    emptyTranslations = new HashMap<Long, Boolean>(translations
0664:                            .size());
0665:                if (emptyTranslations.size() != translations.size()) {
0666:                    //resync
0667:                    for (Long _lang : translations.keySet()) {
0668:                        if (!emptyTranslations.containsKey(_lang))
0669:                            emptyTranslations.put(_lang, translations
0670:                                    .get(_lang) == null);
0671:                    }
0672:                }
0673:            }
0674:
0675:            /**
0676:             * Get the language selected in user interfaces
0677:             *
0678:             * @return selected language
0679:             */
0680:            public long getSelectedLanguage() {
0681:                return selectedLanguage;
0682:            }
0683:
0684:            /**
0685:             * Set the user selected language
0686:             *
0687:             * @param selectedLanguage selected language ID
0688:             * @return self
0689:             * @throws FxNoAccessException if the selected Language is not contained
0690:             */
0691:            public FxValue setSelectedLanguage(long selectedLanguage)
0692:                    throws FxNoAccessException {
0693:                if (selectedLanguage < 0 || !multiLanguage)
0694:                    return this ;
0695:                //throw exception if selectedLanguage is not contained!
0696:                if (!translations.containsKey(selectedLanguage))
0697:                    throw new FxNoAccessException(
0698:                            "ex.content.value.invalid.language",
0699:                            selectedLanguage);
0700:                this .selectedLanguage = selectedLanguage;
0701:                return this ;
0702:            }
0703:
0704:            /**
0705:             * Set the translation for a language or override the single language value if
0706:             * this value is not flagged as multi language enabled. This method cannot be
0707:             * overridden since it not only accepts parameters of type T, but also of type
0708:             * String for web form handling.
0709:             *
0710:             * @param language language to set the translation for
0711:             * @param value    translation
0712:             * @return this
0713:             */
0714:            public final TDerived setTranslation(long language, T value) {
0715:                if (value instanceof  String) {
0716:                    try {
0717:                        value = this .fromString((String) value);
0718:                    } catch (Exception e) {
0719:                        // do nothing. The resulting FxValue will be invalid,
0720:                        // but the invalid value will be preserved.
0721:                        // TODO: use a "safer" concept of representing invalid translations,
0722:                        // since this may lead to unexpeced ClassCastExceptions in parameterized
0723:                        // methods expecting a <T> value
0724:                    }
0725:                }
0726:                if (!multiLanguage) {
0727:                    if (value == null && !isAcceptsEmptyDefaultTranslations()) {
0728:                        throw new FxInvalidParameterException("value",
0729:                                "ex.content.invalid.default.empty", getClass()
0730:                                        .getSimpleName()).asRuntimeException();
0731:                    }
0732:                    //override the single value
0733:                    if (singleValue == null || !singleValue.equals(value))
0734:                        this .singleValue = value;
0735:                    this .singleValueEmpty = value == null;
0736:                    //noinspection unchecked
0737:                    return (TDerived) this ;
0738:                }
0739:                if (language == FxLanguage.SYSTEM_ID)
0740:                    throw new FxInvalidParameterException("language",
0741:                            "ex.content.value.invalid.multilanguage.sys")
0742:                            .asRuntimeException();
0743:                if (value == null) {
0744:                    translations.remove(language);
0745:                    emptyTranslations.remove(language);
0746:                } else {
0747:                    if (!value.equals(translations.get(language))) {
0748:                        translations.put(language, value);
0749:                    }
0750:                    emptyTranslations.put(language, false);
0751:                }
0752:                //noinspection unchecked
0753:                return (TDerived) this ;
0754:            }
0755:
0756:            /**
0757:             * Set the translation for a language or override the single language value if
0758:             * this value is not flagged as multi language enabled
0759:             *
0760:             * @param lang        language to set the translation for
0761:             * @param translation translation
0762:             * @return this
0763:             */
0764:            public TDerived setTranslation(FxLanguage lang, T translation) {
0765:                return setTranslation((int) lang.getId(), translation);
0766:            }
0767:
0768:            /**
0769:             * For multilanguage values, set the default translation.
0770:             * For single language values, set the value.
0771:             *
0772:             * @param value the value to be stored
0773:             */
0774:            public void setValue(T value) {
0775:                setTranslation(getDefaultLanguage(), value);
0776:            }
0777:
0778:            /**
0779:             * Set the translation in the default language. For single-language values,
0780:             * sets the value.
0781:             *
0782:             * @param translation the default translation
0783:             * @return this
0784:             */
0785:            public FxValue setDefaultTranslation(T translation) {
0786:                return setTranslation(defaultLanguage, translation);
0787:            }
0788:
0789:            /**
0790:             * Get the default language of this value
0791:             *
0792:             * @return default language
0793:             */
0794:            public long getDefaultLanguage() {
0795:                if (!isMultiLanguage())
0796:                    return FxLanguage.SYSTEM_ID;
0797:                return this .defaultLanguage;
0798:            }
0799:
0800:            /**
0801:             * Returns the maximum input length an input field should have for this value
0802:             * (or -1 for unlimited length).
0803:             *
0804:             * @return the maximum input length an input field should have for this value
0805:             */
0806:            public int getMaxInputLength() {
0807:                return maxInputLength;
0808:            }
0809:
0810:            /**
0811:             * Set the maximum input length for this value (-1 for unlimited length).
0812:             *
0813:             * @param maxInputLength the maximum input length for this value (-1 for unlimited length).
0814:             */
0815:            public void setMaxInputLength(int maxInputLength) {
0816:                this .maxInputLength = maxInputLength;
0817:            }
0818:
0819:            /**
0820:             * Set the default language.
0821:             * It will only be set if a translation in the requested default language
0822:             * exists!
0823:             *
0824:             * @param defaultLanguage requested default language
0825:             */
0826:            public void setDefaultLanguage(long defaultLanguage) {
0827:                setDefaultLanguage(defaultLanguage, false);
0828:            }
0829:
0830:            /**
0831:             * Set the default language. Will have no effect if the value is not multi language enabled
0832:             *
0833:             * @param defaultLanguage requested default language
0834:             * @param force           if true, the default language will also be updated if no translation exists (for UI input)
0835:             */
0836:            public void setDefaultLanguage(long defaultLanguage, boolean force) {
0837:                if (multiLanguage
0838:                        && (force || translationExists(defaultLanguage))) {
0839:                    this .defaultLanguage = defaultLanguage;
0840:                }
0841:            }
0842:
0843:            /**
0844:             * Reset the default language to the system language
0845:             */
0846:            public void clearDefaultLanguage() {
0847:                this .defaultLanguage = FxLanguage.SYSTEM_ID;
0848:            }
0849:
0850:            /**
0851:             * Is a default value set for this FxValue?
0852:             *
0853:             * @return default value set
0854:             */
0855:            public boolean hasDefaultLanguage() {
0856:                return defaultLanguage != FxLanguage.SYSTEM_ID
0857:                        && isMultiLanguage();
0858:            }
0859:
0860:            /**
0861:             * Check if the passed language is the default language
0862:             *
0863:             * @param language the language to check
0864:             * @return passed language is the default language
0865:             */
0866:            public boolean isDefaultLanguage(long language) {
0867:                return hasDefaultLanguage() && language == defaultLanguage;
0868:            }
0869:
0870:            /**
0871:             * Remove the translation for the given language
0872:             *
0873:             * @param language the language to remove the translation for
0874:             */
0875:            public void removeLanguage(long language) {
0876:                if (!multiLanguage) {
0877:                    setEmpty();
0878:                } else {
0879:                    translations.remove(language);
0880:                    emptyTranslations.remove(language);
0881:                }
0882:            }
0883:
0884:            /**
0885:             * Is this value available for multiple languages?
0886:             *
0887:             * @return value available for multiple languages
0888:             */
0889:            public boolean isMultiLanguage() {
0890:                return this .multiLanguage;
0891:            }
0892:
0893:            protected boolean isAcceptsEmptyDefaultTranslations() {
0894:                return true;
0895:            }
0896:
0897:            /**
0898:             * Format this FxValue for inclusion in a SQL statement. For example,
0899:             * a string is wrapped in single quotes and escaped properly (' --> '').
0900:             * For multilanguage values the default translation is used. If the value is
0901:             * empty (@link #isEmpty()), a runtime exception is thrown.
0902:             *
0903:             * @return the formatted value
0904:             */
0905:            public String getSqlValue() {
0906:                if (isEmpty()) {
0907:                    throw new FxInvalidStateException(
0908:                            "ex.content.value.sql.empty").asRuntimeException();
0909:                }
0910:                return FxFormatUtils.escapeForSql(getDefaultTranslation());
0911:            }
0912:
0913:            /**
0914:             * {@inheritDoc}
0915:             */
0916:            @Override
0917:            public String toString() {
0918:                // format value in the current user's locale - also used in the JSF UI
0919:                return FxValueRendererFactory.getInstance().format(this );
0920:                /*if (isEmpty()) {
0921:                    return "";
0922:                }
0923:                if (!multiLanguage)
0924:                    return singleValue == null ? "" : singleValue.toString();
0925:
0926:                String ret = null;
0927:                try {
0928:                    if (translations != null && translations.size() > 0) {
0929:                        final UserTicket ticket = FxContext.get().getUserTicket();
0930:                        if (ticket != null) {
0931:                            ret = getBestTranslation(ticket.getLanguage().getId()).toString();
0932:                        } else {
0933:                            ret = getTranslation(FxLanguage.DEFAULT_ID).toString();
0934:                            if (ret == null)
0935:                                ret = translations.values().iterator().next().toString();
0936:                        }
0937:                    }
0938:                } catch (Exception e) {
0939:                    ret = null;
0940:                }
0941:                return ret != null ? ret : "";*/
0942:            }
0943:
0944:            /**
0945:             * {@inheritDoc}
0946:             */
0947:            @Override
0948:            public boolean equals(Object other) {
0949:                if (this  == other)
0950:                    return true;
0951:                if (other == null)
0952:                    return false;
0953:                if (this .getClass() != other.getClass())
0954:                    return false;
0955:                FxValue<?, ?> otherValue = (FxValue<?, ?>) other;
0956:                if (this .isEmpty() != otherValue.isEmpty())
0957:                    return false;
0958:                if (this .isMultiLanguage() != otherValue.isMultiLanguage())
0959:                    return false;
0960:                if (multiLanguage) {
0961:                    if (!ArrayUtils.isEquals(
0962:                            this .translations.keySet()
0963:                                    .toArray(
0964:                                            new Long[this .translations.keySet()
0965:                                                    .size()]),
0966:                            otherValue.translations.keySet().toArray(
0967:                                    new Long[otherValue.translations.keySet()
0968:                                            .size()])))
0969:                        return false;
0970:                    if (!ArrayUtils.isEquals(this .translations.values()
0971:                            .toArray(), otherValue.translations.values()
0972:                            .toArray()))
0973:                        return false;
0974:                } else {
0975:                    if (!this .isEmpty())
0976:                        if (!this .singleValue.equals(otherValue.singleValue))
0977:                            return false;
0978:                }
0979:                return true;
0980:            }
0981:
0982:            /**
0983:             * {@inheritDoc}
0984:             */
0985:            @Override
0986:            public int hashCode() {
0987:                int hash = 7;
0988:                for (T translation : translations.values()) {
0989:                    hash = 31 * hash + translation.hashCode();
0990:                }
0991:                hash = 31 * hash + (int) defaultLanguage;
0992:                for (long language : translations.keySet()) {
0993:                    hash = 31 * hash + (int) language;
0994:                }
0995:                return hash;
0996:            }
0997:
0998:            /**
0999:             * Convert to XML
1000:             *
1001:             * @return xml
1002:             */
1003:            public String toXML() {
1004:                StringBuilder sb = new StringBuilder(500);
1005:                sb.append("<").append(getClass().getName()).append(" m=\"")
1006:                        .append(isMultiLanguage() ? "1" : "0").append("\"");
1007:                if (hasDefaultLanguage())
1008:                    sb.append(" d=\"").append(getDefaultLanguage())
1009:                            .append("\"");
1010:                sb.append(">");
1011:                if (!isMultiLanguage())
1012:                    sb.append(FxXMLUtils.toCData(getStringValue(singleValue)));
1013:                else
1014:                    for (long i : getTranslatedLanguages())
1015:                        sb
1016:                                .append("<data l=\"")
1017:                                .append(i)
1018:                                .append("\">")
1019:                                .append(
1020:                                        FxXMLUtils
1021:                                                .toCData(getStringValue(getTranslation(i))))
1022:                                .append("</data>");
1023:                sb.append("</").append(getClass().getName()).append(">");
1024:                return sb.toString();
1025:            }
1026:
1027:            /**
1028:             * Get an FxValue from its XML representation
1029:             *
1030:             * @param xml XML representation
1031:             * @return FxValue instance
1032:             */
1033:            public static FxValue fromXML(String xml) {
1034:                String clazz = xml.substring(1, xml.indexOf(' '));
1035:                try {
1036:                    FxValue v = (FxValue) Class.forName(
1037:                            "com.flexive.shared.content.values." + clazz)
1038:                            .newInstance();
1039:                    v.multiLanguage = xml.indexOf("m=\"1\"") > 0;
1040:                    int def;
1041:                    if ((def = xml.indexOf("d=\"")) > 0)
1042:                        v.defaultLanguage = Long.parseLong(xml.substring(
1043:                                def + 2, xml.indexOf("\"", def + 2)));
1044:
1045:                    if (v.multiLanguage) {
1046:                        StringBuilder data = new StringBuilder(xml.substring(
1047:                                xml.indexOf('>'), xml.lastIndexOf("</" + clazz
1048:                                        + ">")));
1049:                        int start = 0;
1050:                        while ((start = data.indexOf("<data", start)) >= 0) {
1051:                            v.setTranslation(Long.parseLong(data.substring(data
1052:                                    .indexOf("l=\"", start + 3), data
1053:                                    .indexOf("\">"))), v.fromString(FxXMLUtils
1054:                                    .fromCData(data.substring(data.indexOf(">",
1055:                                            start), data.indexOf("</data>",
1056:                                            start)))));
1057:                        }
1058:                    } else {
1059:                        v.singleValue = v.fromString(xml.substring(xml
1060:                                .indexOf(">"), xml.lastIndexOf("</")));
1061:                    }
1062:                    return v;
1063:                } catch (Exception e) {
1064:                    e.printStackTrace();
1065:                }
1066:                return null;
1067:            }
1068:
1069:            /**
1070:             * A generic comparable implementation based on the value's string representation.
1071:             *
1072:             * @param o the other object
1073:             * @return see {@link Comparable#compareTo}.
1074:             */
1075:            @SuppressWarnings({"unchecked"})
1076:            public int compareTo(FxValue o) {
1077:                if (isEmpty() && !o.isEmpty()) {
1078:                    return -1;
1079:                }
1080:                if (isEmpty() && o.isEmpty()) {
1081:                    return 0;
1082:                }
1083:                if (!isEmpty() && o.isEmpty()) {
1084:                    return 1;
1085:                }
1086:                return FxSharedUtils.getCollator().compare(
1087:                        getStringValue(getBestTranslation()),
1088:                        o.getStringValue(o.getBestTranslation()));
1089:            }
1090:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.