Source Code Cross Referenced for Entity.java in  » Database-ORM » Velosurf » velosurf » model » 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 » Database ORM » Velosurf » velosurf.model 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2003 The Apache Software Foundation.
0003:         *
0004:         * Licensed under the Apache License, Version 2.0 (the "License");
0005:         * you may not use this file except in compliance with the License.
0006:         * You may obtain a copy of the License at
0007:         *
0008:         *     http://www.apache.org/licenses/LICENSE-2.0
0009:         *
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS,
0012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         * See the License for the specific language governing permissions and
0014:         * limitations under the License.
0015:         */
0016:
0017:        package velosurf.model;
0018:
0019:        import java.lang.reflect.Constructor;
0020:        import java.sql.SQLException;
0021:        import java.sql.Types;
0022:        import java.util.*;
0023:
0024:        import velosurf.cache.Cache;
0025:        import velosurf.context.Instance;
0026:        import velosurf.context.RowIterator;
0027:        import velosurf.context.ExternalObjectWrapper;
0028:        import velosurf.sql.Database;
0029:        import velosurf.sql.PooledPreparedStatement;
0030:        import velosurf.sql.SqlUtil;
0031:        import velosurf.util.Logger;
0032:        import velosurf.util.StringLists;
0033:        import velosurf.util.UserContext;
0034:        import velosurf.validation.FieldConstraint;
0035:
0036:        import org.apache.commons.lang.StringEscapeUtils;
0037:
0038:        /** The Entity class represents an entity in the data model.
0039:         *
0040:         *  @author <a href=mailto:claude.brisson@gmail.com>Claude Brisson</a>
0041:         *
0042:         */
0043:        public class Entity {
0044:            /** Constructor reserved for the framework.
0045:             *
0046:             * @param db database connection
0047:             * @param name entity name
0048:             * @param readOnly access mode (read-write or read-only)
0049:             * @param cachingMethod caching method to be used
0050:             */
0051:            public Entity(Database db, String name, boolean readOnly,
0052:                    int cachingMethod) {
0053:                this .db = db;
0054:                this .name = name;
0055:                table = name; // default mapped table has same name
0056:                this .readOnly = readOnly;
0057:                this .cachingMethod = cachingMethod;
0058:                if (this .cachingMethod != Cache.NO_CACHE)
0059:                    cache = new Cache(this .cachingMethod);
0060:                instanceClass = Instance.class;
0061:            }
0062:
0063:            /** Add a column at the end of the sequential list of named columns. Called during the reverse engeenering of the database.
0064:             *
0065:             * @param colName column name
0066:             */
0067:            public void addColumn(String colName, int sqlType) {
0068:                colName = db.adaptCase(colName);
0069:                columns.add(colName);
0070:                types.put(colName, sqlType);
0071:                /* if (colnames as aliases) */aliases.put(colName, colName);
0072:            }
0073:
0074:            /**
0075:             * Add a column alias.
0076:             * @param alias alias
0077:             * @param column column
0078:             */
0079:            public void addAlias(String alias, String column) {
0080:                alias = db.adaptCase(alias);
0081:                column = db.adaptCase(column);
0082:                Logger.trace("added alias " + name + "." + alias + " -> "
0083:                        + name + "." + column);
0084:                aliases.put(alias, column);
0085:            }
0086:
0087:            /**
0088:             * Translates an alias to its column name.
0089:             * @param alias alias
0090:             * @return column name
0091:             */
0092:            public String resolveName(String alias) {
0093:                alias = db.adaptCase(alias);
0094:                String name = aliases.get(alias);
0095:                return name == null ? alias : name;
0096:            }
0097:
0098:            /** Add a key column to the sequential list of the key columns. Called during the reverse-engeenering of the database.
0099:             *
0100:             * @param colName name of the key column
0101:             */
0102:            public void addPKColumn(String colName) {
0103:                /* remember the alias */
0104:                keyCols.add(colName);
0105:            }
0106:
0107:            /** Add a new attribute.
0108:             * @param attribute attribute
0109:             */
0110:            public void addAttribute(Attribute attribute) {
0111:                String name = attribute.getName();
0112:                if (attributeMap.containsKey(name)) {
0113:                    Logger.warn("Ignoring second definition for attribute "
0114:                            + getName() + "." + name + "!");
0115:                } else {
0116:                    attributeMap.put(db.adaptCase(name), attribute);
0117:                    Logger.trace("defined attribute " + this .name + "." + name
0118:                            + " = " + attribute);
0119:                }
0120:            }
0121:
0122:            /** Get a named attribute.
0123:             *
0124:             * @param property attribute name
0125:             * @return the attribute
0126:             */
0127:            public Attribute getAttribute(String property) {
0128:                return (Attribute) attributeMap.get(db.adaptCase(property));
0129:            }
0130:
0131:            /**
0132:             * Add an action.
0133:             * @param action action
0134:             */
0135:            public void addAction(Action action) {
0136:                String name = action.getName();
0137:                actionMap.put(db.adaptCase(name), action);
0138:                Logger.trace("defined action " + this .name + "." + name + " = "
0139:                        + action);
0140:            }
0141:
0142:            /** get an action.
0143:             *
0144:             * @param property action name
0145:             * @return the action
0146:             */
0147:            public Action getAction(String property) {
0148:                return (Action) actionMap.get(db.adaptCase(property));
0149:            }
0150:
0151:            /** Specify a custom class to use when instanciating this entity.
0152:             *
0153:             * @param className the java class name
0154:             */
0155:            public void setInstanceClass(String className) {
0156:                try {
0157:                    instanceClass = Class.forName(className);
0158:                } catch (Exception e) {
0159:                    Logger.log(e);
0160:                }
0161:            }
0162:
0163:            /** Specify the caching method. See {@link Cache} for allowed constants.
0164:             *
0165:             * @param caching Caching method
0166:             */
0167:            public void setCachingMethod(int caching) {
0168:                if (cachingMethod != caching) {
0169:                    cachingMethod = caching;
0170:                    if (cachingMethod == Cache.NO_CACHE)
0171:                        cache = null;
0172:                    else
0173:                        cache = new Cache(cachingMethod);
0174:                }
0175:            }
0176:
0177:            /**
0178:             * Add a constraint.
0179:             * @param column column name
0180:             * @param constraint constraint
0181:             */
0182:            public void addConstraint(String column, FieldConstraint constraint) {
0183:                ;
0184:                column = resolveName(column);
0185:                Logger.trace("adding constraint on column "
0186:                        + Database.adaptContextCase(getName()) + "." + column
0187:                        + ": " + constraint);
0188:                List<FieldConstraint> list = constraints.get(column);
0189:                if (list == null) {
0190:                    list = new ArrayList<FieldConstraint>();
0191:                    constraints.put(column, list);
0192:                }
0193:                list.add(constraint);
0194:            }
0195:
0196:            /** Used by the framework to notify this entity that its reverse enginering is over.
0197:             */
0198:            public void reverseEnginered() {
0199:                if (obfuscate && keyCols.size() > 0) {
0200:                    keyColObfuscated = new boolean[keyCols.size()];
0201:                    Iterator key = keyCols.iterator();
0202:                    int i = 0;
0203:                    for (; key.hasNext(); i++)
0204:                        keyColObfuscated[i] = obfuscatedColumns.contains(key
0205:                                .next());
0206:                }
0207:                /* fills the cache for the full caching method */
0208:                if (cachingMethod == Cache.FULL_CACHE) {
0209:                    try {
0210:                        query().getRows();
0211:                    } catch (SQLException sqle) {
0212:                        Logger.error("full caching for entity " + getName()
0213:                                + ": could not fill the cache!");
0214:                        Logger.log(sqle);
0215:                    }
0216:                }
0217:            }
0218:
0219:            /** Clear the cache (not used for now).
0220:             */
0221:            protected void clearCache() {
0222:                if (cache != null)
0223:                    cache.clear();
0224:            }
0225:
0226:            /** Create a new realisation of this entity.
0227:             *
0228:             * @return the newly created instance
0229:             */
0230:            public Instance newInstance() {
0231:                Instance result = null;
0232:                try {
0233:                    if (Instance.class.isAssignableFrom(instanceClass)) {
0234:                        try {
0235:                            result = (Instance) instanceClass.newInstance();
0236:                            result.initialize(this );
0237:                        } catch (Exception e) {
0238:                            Constructor instanceConstructor = instanceClass
0239:                                    .getConstructor(new Class[] { Entity.class });
0240:                            result = (Instance) instanceConstructor
0241:                                    .newInstance(new Object[] { this  });
0242:                        }
0243:                    } else {
0244:                        result = new ExternalObjectWrapper(this , instanceClass
0245:                                .newInstance());
0246:                    }
0247:                } catch (Exception e) {
0248:                    Logger.error("could not create a new instance for entity "
0249:                            + getName());
0250:                    Logger.log(e);
0251:                    result = null;
0252:                }
0253:                return result;
0254:            }
0255:
0256:            /** Build a new instance from a Map object.
0257:             *
0258:             * @param values the Map object containing the values
0259:             * @return the newly created instance
0260:             */
0261:            public Instance newInstance(Map<String, Object> values) {
0262:                return newInstance(values, false);
0263:            }
0264:
0265:            /** Build a new instance from a Map object.
0266:             *
0267:             * @param values the Map object containing the values
0268:             * @param useSQLnames map keys use SQL column names that must be translated to aliases
0269:             * @return the newly created instance
0270:             */
0271:            public Instance newInstance(Map<String, Object> values,
0272:                    boolean useSQLnames) {
0273:                try {
0274:                    Instance result = newInstance();
0275:                    extractColumnValues(values, result, useSQLnames);
0276:                    if (cachingMethod != Cache.NO_CACHE) {
0277:                        Object key = buildKey(result);
0278:                        if (key != null) {
0279:                            cache.put(key, result);
0280:                        }
0281:                    }
0282:                    return result;
0283:                } catch (SQLException sqle) {
0284:                    Logger.log(sqle);
0285:                    return null;
0286:                }
0287:            }
0288:
0289:            /**
0290:             * Invalidate an instance in the cache.
0291:             * @param instance instance
0292:             * @throws SQLException
0293:             */
0294:            public void invalidateInstance(Map<String, Object> instance)
0295:                    throws SQLException {
0296:                if (cachingMethod != Cache.NO_CACHE) {
0297:                    Object key = buildKey(instance);
0298:                    if (key != null) {
0299:                        cache.invalidate(key);
0300:                    }
0301:                }
0302:            }
0303:
0304:            /** Extract column values from an input Map source and store result in target.
0305:             *
0306:             * @param source Map source object
0307:             * @param target Map target object
0308:             * @param SQLNames the source uses SQL names
0309:             */
0310:            private void extractColumnValues(Map<String, Object> source,
0311:                    Map<String, Object> target, boolean SQLNames)
0312:                    throws SQLException {
0313:                /* TODO: cache a case-insensitive version of the columns list and iterate on source keys, with equalsIgnoreCase (or more efficient) funtion */
0314:                /* We use keySet and not entrySet here because if the source map is a ReadOnlyMap, entrySet is not available */
0315:                for (String key : source.keySet()) {
0316:
0317:                    /* resove anyway */
0318:                    String col = resolveName(key);
0319:                    /* this is more or less a hack: we do filter columns
0320:                       only when SQLNames is false. The purpose of this
0321:                       is to allow additionnal fields in SQL attributes
0322:                       returning rowsets of entities. */
0323:
0324:                    if (!SQLNames && !isColumn(col)) {
0325:                        continue;
0326:                    }
0327:
0328:                    Object val = source.get(key);
0329:                    if (val == null || (val.getClass().isArray())) {
0330:                        continue;
0331:                    }
0332:                    target.put(col, val);
0333:                }
0334:            }
0335:
0336:            /** Build the key for the Cache from a Map.
0337:             *
0338:             * @param values the Map containing all values (unaliased)
0339:             * @exception SQLException the getter of the Map throws an
0340:             *     SQLException
0341:             * @return an array containing all key values
0342:             */
0343:            private Object buildKey(Map<String, Object> values)
0344:                    throws SQLException {
0345:                if (keyCols.size() == 0)
0346:                    return null;
0347:                Object[] key = new Object[keyCols.size()];
0348:                int c = 0;
0349:                for (String keycol : keyCols) {
0350:                    Object v = values.get(keycol);
0351:                    if (v == null) {
0352:                        return null;
0353:                    }
0354:                    key[c++] = values.get(keycol);
0355:                }
0356:                return key;
0357:            }
0358:
0359:            /** Getter for the name of this entity.
0360:             *
0361:             * @return the name of the entity
0362:             */
0363:            public String getName() {
0364:                return name;
0365:            }
0366:
0367:            /** Getter for the list of key column names.
0368:             *
0369:             * @return the list of key column names
0370:             */
0371:            public List<String> getPKCols() {
0372:                return keyCols;
0373:            }
0374:
0375:            /** Getter for the list of column names.
0376:             *
0377:             * @return the list of column names
0378:             */
0379:            public List<String> getColumns() {
0380:                return columns;
0381:            }
0382:
0383:            public boolean isColumn(String name) {
0384:                return columns.contains(name);
0385:            }
0386:
0387:            /** Check if the provided map contains all key columns
0388:             *
0389:             * @param values map of values to check
0390:             * @return true if all key columns are present
0391:             */
0392:            /* not used     
0393:             public boolean hasKey(Map<String,Object> values) {
0394:             if(keyCols.size() == 0) {
0395:             return false; // could be 'true' but indicates that 'fetch' cannot be called
0396:             }
0397:             List<String> cols = new ArrayList<String>();
0398:             for(String key:values.keySet()) {
0399:             cols.add(resolveName(key));
0400:             }
0401:             return (cols.containsAll(keyCols));
0402:             }
0403:             */
0404:            /** Insert a new row based on values of a map.
0405:             *
0406:             * @param values the  Map object containing the values
0407:             * @return success indicator
0408:             */
0409:            public boolean insert(Map<String, Object> values)
0410:                    throws SQLException {
0411:                if (readOnly) {
0412:                    Logger.error("Error: Entity " + getName()
0413:                            + " is read-only!");
0414:                    return false;
0415:                }
0416:                Instance instance = newInstance(values);
0417:                /* if found in cache because it exists, driver will issue a SQLException TODO review this*/
0418:                boolean success = instance.insert();
0419:                if (success && keyCols.size() == 1) {
0420:                    /* update last insert id */
0421:                    /* TODO review usecase, this should maybe be forbidden sometimes */
0422:                    /* FIXME for now, we catch some exceptions */
0423:                    try {
0424:                        String pk = keyCols.get(0);
0425:                        values.put(pk, instance.get(pk));
0426:                        //            catch(UnsupportedOperationException uoe)
0427:                    } catch (Exception e) {
0428:                        Logger.warn("insert: encountered " + e.getMessage()
0429:                                + " while setting last inserted id value");
0430:                        Logger
0431:                                .warn("insert: values are probably provided using a read-only map");
0432:                        Logger
0433:                                .warn("you can probably just ignore this warning, this is a reminder for the dev community");
0434:                    }
0435:                }
0436:                /* try again to put it in the cache since previous attempt may have failed
0437:                   in case there are auto-incremented columns */
0438:                if (success && cachingMethod != Cache.NO_CACHE) {
0439:                    Object key = buildKey(instance);
0440:                    if (key != null) {
0441:                        cache.put(key, instance);
0442:                    }
0443:                }
0444:
0445:                return success;
0446:            }
0447:
0448:            /** Update a row based on a set of values that must contain key values.
0449:             *
0450:             * @param values the Map object containing the values
0451:             * @return success indicator
0452:             */
0453:            public boolean update(Map<String, Object> values)
0454:                    throws SQLException {
0455:                if (readOnly) {
0456:                    Logger.error("Error: Entity " + getName()
0457:                            + " is read-only!");
0458:                    return false;
0459:                }
0460:                Instance instance = newInstance(values);
0461:                return instance.update();
0462:            }
0463:
0464:            /** Delete a row based on (key) values.
0465:             *
0466:             * @param values the Map containing the values
0467:             * @return success indicator
0468:             */
0469:            public boolean delete(Map<String, Object> values)
0470:                    throws SQLException {
0471:                if (readOnly) {
0472:                    Logger.error("Error: Entity " + getName()
0473:                            + " is read-only!");
0474:                    return false;
0475:                }
0476:                Instance instance = newInstance(values);
0477:                return instance.delete();
0478:            }
0479:
0480:            /** Delete a row based on the unique key string value.
0481:             *
0482:             * @param keyValue key value
0483:             * @return success indicator
0484:             */
0485:            public boolean delete(String keyValue) throws SQLException {
0486:                if (readOnly) {
0487:                    Logger.error("Error: Entity " + getName()
0488:                            + " is read-only!");
0489:                    return false;
0490:                }
0491:                if (keyCols.size() != 1) {
0492:                    if (keyCols.size() == 0)
0493:                        throw new SQLException("Entity.delete: Error: Entity '"
0494:                                + name + "' has no primary key!");
0495:                    else
0496:                        throw new SQLException("Entity.delete: Error: Entity '"
0497:                                + name + "' has a multi-column primary key!");
0498:                }
0499:                Instance instance = newInstance();
0500:                instance.put(keyCols.get(0), keyValue);
0501:                return instance.delete();
0502:            }
0503:
0504:            /** Delete a row based on the unique key string value.
0505:             *
0506:             * @param keyValue key value
0507:             * @return success indicator
0508:             */
0509:            public boolean delete(Number keyValue) throws SQLException {
0510:                if (readOnly) {
0511:                    Logger.error("Error: Entity " + getName()
0512:                            + " is read-only!");
0513:                    return false;
0514:                }
0515:                if (keyCols.size() != 1) {
0516:                    if (keyCols.size() == 0)
0517:                        throw new SQLException("Entity.delete: Error: Entity '"
0518:                                + name + "' has no primary key!");
0519:                    else
0520:                        throw new SQLException("Entity.delete: Error: Entity '"
0521:                                + name + "' has a multi-column primary key!");
0522:                }
0523:                Instance instance = newInstance();
0524:                instance.put(keyCols.get(0), keyValue);
0525:                return instance.delete();
0526:            }
0527:
0528:            /** Fetch an instance from key values stored in a List in natural order.
0529:             *
0530:             * @param values the List containing the key values
0531:             * @return the fetched instance
0532:             */
0533:            public Instance fetch(List<Object> values) throws SQLException {
0534:                if (values.size() != keyCols.size())
0535:                    throw new SQLException(
0536:                            "Entity.fetch: Error: Wrong number of values for '"
0537:                                    + name + "' primary key! Got "
0538:                                    + values.size() + ", was expecting "
0539:                                    + keyCols.size() + " for key list: "
0540:                                    + StringLists.join(keyCols, ","));
0541:                Instance instance = null;
0542:                // try in cache
0543:                if (cachingMethod != Cache.NO_CACHE)
0544:                    instance = (Instance) cache.get(values.toArray());
0545:                if (instance == null) {
0546:                    if (fetchQuery == null)
0547:                        buildFetchQuery();
0548:                    PooledPreparedStatement statement = db.prepare(fetchQuery);
0549:                    if (obfuscate) {
0550:                        values = new ArrayList<Object>(values);
0551:                        for (int col = 0; col < keyColObfuscated.length; col++)
0552:                            if (keyColObfuscated[col])
0553:                                values.set(col, deobfuscate(values.get(col)));
0554:                    }
0555:                    instance = (Instance) statement.fetch(values, this );
0556:                }
0557:                return instance;
0558:            }
0559:
0560:            /** Fetch an instance from key values stored in a Map.
0561:             *
0562:             * @param values the Map containing the key values
0563:             * @return the fetched instance
0564:             */
0565:            public Instance fetch(Map<String, Object> values)
0566:                    throws SQLException {
0567:                if (keyCols.size() == 0) {
0568:                    throw new SQLException(
0569:                            "entity "
0570:                                    + name
0571:                                    + ": cannot fetch an instance for an entity without key!");
0572:                }
0573:                Instance instance = null;
0574:                /* extract key values */
0575:                Object key[] = new Object[keyCols.size()];
0576:                int n = 0;
0577:                for (Map.Entry<String, Object> entry : values.entrySet()) {
0578:                    String col = resolveName(entry.getKey());
0579:                    int i = keyCols.indexOf(col);
0580:                    if (i != -1) {
0581:                        key[i] = entry.getValue();
0582:                        n++;
0583:                    }
0584:                }
0585:                if (n != keyCols.size()) {
0586:                    String missing = "";
0587:                    for (int c = 0; c < key.length; c++)
0588:                        if (key[c] == null)
0589:                            missing += keyCols.get(c) + " ";
0590:                    throw new SQLException("entity " + name
0591:                            + ".fetch(): missing key values! Missing values: "
0592:                            + missing);
0593:                }
0594:                if (cachingMethod != Cache.NO_CACHE) {
0595:                    // try in cache
0596:                    instance = (Instance) cache.get(key);
0597:                }
0598:                if (instance == null) {
0599:                    if (fetchQuery == null)
0600:                        buildFetchQuery();
0601:                    PooledPreparedStatement statement = db.prepare(fetchQuery);
0602:                    if (obfuscate) {
0603:                        for (int c = 0; c < keyCols.size(); c++) {
0604:                            if (isObfuscated(keyCols.get(c))) {
0605:                                key[c] = deobfuscate(key[c]);
0606:                            }
0607:                        }
0608:                    }
0609:                    instance = (Instance) statement.fetch(Arrays.asList(key),
0610:                            this );
0611:                }
0612:                return instance;
0613:            }
0614:
0615:            /** Fetch an instance from its key value as a string.
0616:             *
0617:             * @param keyValue the key
0618:             * @return the fetched instance
0619:             */
0620:            public Instance fetch(String keyValue) throws SQLException {
0621:                if (keyCols.size() != 1) {
0622:                    if (keyCols.size() == 0)
0623:                        throw new SQLException("Entity.fetch: Error: Entity '"
0624:                                + name + "' has no primary key!");
0625:                    else
0626:                        throw new SQLException("Entity.fetch: Error: Entity '"
0627:                                + name + "' has a multi-column primary key!");
0628:                }
0629:                Instance instance = null;
0630:                // try in cache
0631:                if (cachingMethod != Cache.NO_CACHE)
0632:                    // try in cache
0633:                    instance = (Instance) cache.get(new Object[] { keyValue });
0634:                if (instance == null) {
0635:                    if (fetchQuery == null)
0636:                        buildFetchQuery();
0637:                    PooledPreparedStatement statement = db.prepare(fetchQuery);
0638:                    if (obfuscate && keyColObfuscated[0]) {
0639:                        keyValue = deobfuscate(keyValue);
0640:                    }
0641:                    List<String> params = new ArrayList<String>();
0642:                    params.add(keyValue);
0643:                    instance = (Instance) statement.fetch(params, this );
0644:                }
0645:                return instance;
0646:            }
0647:
0648:            /** Fetch an instance from its key value specified as a Number.
0649:             *
0650:             * @param keyValue the key
0651:             * @return the fetched instance
0652:             */
0653:            public Instance fetch(Number keyValue) throws SQLException {
0654:                if (keyCols.size() != 1) {
0655:                    if (keyCols.size() == 0)
0656:                        throw new SQLException("Entity.fetch: Error: Entity '"
0657:                                + name + "' has no primary key!");
0658:                    else
0659:                        throw new SQLException("Entity.fetch: Error: Entity '"
0660:                                + name + "' has a multi-column primary key!");
0661:                }
0662:                Instance instance = null;
0663:                // try in cache
0664:                if (cachingMethod != Cache.NO_CACHE)
0665:                    // try in cache
0666:                    instance = (Instance) cache.get(new Object[] { keyValue });
0667:                if (instance == null) {
0668:                    if (fetchQuery == null)
0669:                        buildFetchQuery();
0670:                    PooledPreparedStatement statement = db.prepare(fetchQuery);
0671:                    List<Number> params = new ArrayList<Number>();
0672:                    params.add(keyValue);
0673:                    if (obfuscate && keyColObfuscated[0]) {
0674:                        Logger.warn("fetch: column '" + columns.get(0)
0675:                                + "' is obfuscated, please use $db." + name
0676:                                + ".fetch($db.obfuscate(" + keyValue + "))");
0677:                        return null;
0678:                    }
0679:                    instance = (Instance) statement.fetch(params, this );
0680:                }
0681:                return instance;
0682:            }
0683:
0684:            /** Get the SQL query string used to fetch one instance of this query.
0685:             *
0686:             * @return the SLQ query
0687:             */
0688:            public String getFetchQuery() {
0689:                if (fetchQuery == null)
0690:                    buildFetchQuery();
0691:                return fetchQuery;
0692:            }
0693:
0694:            /** Build the SQL query used to fetch one instance of this query.
0695:             */
0696:            private void buildFetchQuery() {
0697:                List<String> whereClause = new ArrayList<String>();
0698:                for (String column : keyCols) {
0699:                    whereClause.add(column + "=?");
0700:                }
0701:                fetchQuery = "select * from " + table + " where "
0702:                        + StringLists.join(whereClause, " and ");
0703:            }
0704:
0705:            /** Issue a query to iterate though all instances of this entity.
0706:             *
0707:             * @return the resulting RowIterator
0708:             */
0709:            public RowIterator query() throws SQLException {
0710:                return query(null, null);
0711:            }
0712:
0713:            /** Issue a query to iterate thought instances of this entity, with a facultative refining criteria and a facultative order by clause.
0714:             *
0715:             * @param refineCriteria a refining criteria or null to get all instances
0716:             * @param order an 'order by' clause or null to get instances in their
0717:             *     natural order
0718:             * @return the resulting RowIterator
0719:             */
0720:            public RowIterator query(List refineCriteria, String order)
0721:                    throws SQLException {
0722:                String query = "select * from " + table;
0723:                if (refineCriteria != null)
0724:                    query = SqlUtil.refineQuery(query, refineCriteria);
0725:                if (order != null && order.length() > 0)
0726:                    query = SqlUtil.orderQuery(query, order);
0727:                return db.query(query, this );
0728:            }
0729:
0730:            /** Get the database connection.
0731:             *
0732:             * @return the database connection
0733:             */
0734:            public Database getDB() {
0735:                return db;
0736:            }
0737:
0738:            /** Is this entity read-only or read-write?
0739:             *
0740:             * @return whether this entity is read-only or not
0741:             */
0742:            public boolean isReadOnly() {
0743:                return readOnly;
0744:            }
0745:
0746:            /** Set this entity to be read-only or read-write.
0747:             *
0748:             * @param readOnly the mode to switch to : true for read-only, false for
0749:             *     read-write
0750:             */
0751:            public void setReadOnly(boolean readOnly) {
0752:                this .readOnly = readOnly;
0753:            }
0754:
0755:            /** set the name of the table mapped by this entity.
0756:             *
0757:             * @param table the table mapped by this entity
0758:             *     read-write
0759:             */
0760:            public void setTableName(String table) {
0761:                this .table = table;
0762:            }
0763:
0764:            /** Get the name of the mapped table.
0765:             *
0766:             * @return name of the mapped table
0767:             */
0768:            public String getTableName() {
0769:                return table;
0770:            }
0771:
0772:            /** Indicates a column as being obfuscated.
0773:             * @param columns list of obfuscated columns
0774:             */
0775:            public void setObfuscated(List<String> columns) {
0776:                obfuscate = true;
0777:                obfuscatedColumns = columns;
0778:            }
0779:
0780:            /** Returns whether the given column is obfuscated.
0781:             * @param column the name of the column
0782:             * @return a boolean indicating whether this column is obfuscated
0783:             */
0784:            public boolean isObfuscated(String column) {
0785:                return obfuscate
0786:                        && obfuscatedColumns.contains(db.adaptCase(column));
0787:            }
0788:
0789:            /** Obfuscate given value.
0790:             * @param value value to obfuscate
0791:             *
0792:             * @return obfuscated value
0793:             */
0794:            public String obfuscate(Object value) {
0795:                return db.obfuscate(value);
0796:            }
0797:
0798:            /** Obfuscate this id value if needed.
0799:             *  @param id id value
0800:             *  @return filtered id value (that is, obfuscated if needed)
0801:             */
0802:            public Object filterID(Long id) {
0803:                if (keyCols.size() == 1
0804:                        && isObfuscated((String) keyCols.get(0)))
0805:                    return obfuscate(Long.valueOf(id));
0806:                return Long.valueOf(id);
0807:            }
0808:
0809:            /** De-obfuscate given value.
0810:             * @param value value to de-obfuscate
0811:             *
0812:             * @return obfuscated value
0813:             */
0814:            public String deobfuscate(Object value) {
0815:                return db.deobfuscate(value);
0816:            }
0817:
0818:            /** Indicates a column as being localized.
0819:             * @param columns list of localized columns
0820:             */
0821:            public void setLocalized(List columns) {
0822:                localizedColumns = columns;
0823:            }
0824:
0825:            /** Returns whether the given column is obfuscated.
0826:             * @param column the name of the column
0827:             * @return a boolean indicating whether this column is obfuscated
0828:             */
0829:            public boolean isLocalized(String column) {
0830:                return localizedColumns != null
0831:                        && localizedColumns.contains(db.adaptCase(column));
0832:            }
0833:
0834:            /** Does this entity have localized columns?
0835:             */
0836:            public boolean hasLocalizedColumns() {
0837:                return localizedColumns != null && localizedColumns.size() > 0;
0838:            }
0839:
0840:            /**
0841:             * Truncate validation error messages to a maximum number of characters.
0842:             */
0843:            private static final int MAX_DATA_DISPLAY_LENGTH = 40;
0844:
0845:            /** Validate a set of values.
0846:             */
0847:            public boolean validate(Map<String, Object> row)
0848:                    throws SQLException {
0849:                boolean ret = true;
0850:
0851:                UserContext userContext = db.getUserContext();
0852:                /* FIXME Is it a good choice to clear the user context now?
0853:                   We may want to validate several entities
0854:                   before displaying errors to the user.
0855:                 */
0856:                userContext.clearValidationErrors();
0857:                List<ValidationError> errors = new ArrayList<ValidationError>();
0858:                for (Map.Entry<String, Object> entry : row.entrySet()) {
0859:                    String col = resolveName(entry.getKey());
0860:                    Object data = entry.getValue();
0861:                    List<FieldConstraint> list = constraints.get(col);
0862:                    if (list != null) {
0863:                        for (FieldConstraint constraint : list) {
0864:                            if (!constraint.validate(data, userContext
0865:                                    .getLocale())) {
0866:                                String stringData = data.toString();
0867:                                String formatted = (data == null
0868:                                        || stringData.length() == 0 ? "empty value"
0869:                                        : stringData);
0870:                                if (formatted.length() > MAX_DATA_DISPLAY_LENGTH) {
0871:                                    formatted = formatted.substring(0,
0872:                                            MAX_DATA_DISPLAY_LENGTH)
0873:                                            + "...";
0874:                                }
0875:                                formatted = StringEscapeUtils
0876:                                        .escapeHtml(formatted);
0877:                                errors.add(new ValidationError(col, userContext
0878:                                        .localize(constraint.getMessage(),
0879:                                                Database.adaptContextCase(col),
0880:                                                formatted)));
0881:                                ret = false;
0882:                            }
0883:                        }
0884:                    }
0885:                }
0886:                if (errors.size() > 0) {
0887:                    /* sort in columns natural order... better than nothing.
0888:                       The ideal ordering would be the order of the form fields,
0889:                       but it is unreachable. */
0890:                    Collections.sort(errors);
0891:                    for (ValidationError error : errors) {
0892:                        Logger.trace("validation: new message: "
0893:                                + error.message);
0894:                        userContext.addValidationError(error.message);
0895:                    }
0896:                }
0897:                return ret;
0898:            }
0899:
0900:            class ValidationError implements  Comparable<ValidationError> {
0901:                ValidationError(String column, String message) {
0902:                    index = columns.indexOf(column);
0903:                    this .message = message;
0904:                }
0905:
0906:                public int compareTo(ValidationError cmp) {
0907:                    return index - cmp.index;
0908:                }
0909:
0910:                String message;
0911:                int index;
0912:            }
0913:
0914:            /**
0915:             * Check for the existence of an imported key with the same columns.
0916:             * @param pkEntity primary key entity
0917:             * @param fkCols foreign key columns
0918:             * @return previously defined imported key, if any
0919:             */
0920:            public ImportedKey findImportedKey(Entity pkEntity,
0921:                    List<String> fkCols) {
0922:                for (Map.Entry<String, Attribute> entry : attributeMap
0923:                        .entrySet()) {
0924:                    Attribute attribute = entry.getValue();
0925:                    if (!(attribute instanceof  ImportedKey)) {
0926:                        continue;
0927:                    }
0928:                    ImportedKey imported = (ImportedKey) attribute;
0929:                    if (imported.getResultEntity().equals(pkEntity.getName())
0930:                            && (imported.getFKCols() == null || imported
0931:                                    .getFKCols().equals(fkCols))) {
0932:                        return imported;
0933:                    }
0934:                }
0935:                return null;
0936:            }
0937:
0938:            /**
0939:             * Check for the existence of an exported key with the same columns.
0940:             * @param fkEntity foreign key entity
0941:             * @param fkCols foreign key columns
0942:             * @return previously defined exported key, if any
0943:             */
0944:            public ExportedKey findExportedKey(Entity fkEntity,
0945:                    List<String> fkCols) {
0946:                for (Map.Entry<String, Attribute> entry : attributeMap
0947:                        .entrySet()) {
0948:                    Attribute attribute = entry.getValue();
0949:                    if (!(attribute instanceof  ExportedKey)) {
0950:                        continue;
0951:                    }
0952:                    ExportedKey exported = (ExportedKey) attribute;
0953:                    if (exported.getResultEntity().equals(fkEntity.getName())
0954:                            && (exported.getFKCols() == null || exported
0955:                                    .getFKCols().equals(fkCols))) {
0956:                        return exported;
0957:                    }
0958:                }
0959:                return null;
0960:            }
0961:
0962:            public Object filterIncomingValue(String column, Object value) {
0963:                if (value == null) {
0964:                    return null;
0965:                }
0966:                /* for now, only filter boolean values */
0967:                Integer type = types.get(column);
0968:                if (type == null) {
0969:                    return value;
0970:                }
0971:                if (type == Types.BOOLEAN || type == Types.BIT) {
0972:                    if (String.class.isAssignableFrom(value.getClass())) {
0973:                        String s = (String) value;
0974:                        if ("true".equalsIgnoreCase(s)
0975:                                || "on".equalsIgnoreCase(s)
0976:                                || "1".equalsIgnoreCase(s)
0977:                                || "yes".equalsIgnoreCase(s)) {
0978:                            value = new Boolean(true);
0979:                        } else {
0980:                            value = new Boolean(false);
0981:                        }
0982:                    }
0983:                }
0984:                return value;
0985:            }
0986:
0987:            /** Name.
0988:             */
0989:            private String name = null;
0990:            /** Table.
0991:             */
0992:            private String table = null;
0993:            /** Column names in natural order.
0994:             */
0995:            private List<String> columns = new ArrayList<String>(); // list<String>
0996:            /** Column types
0997:             */
0998:            private Map<String, Integer> types = new HashMap<String, Integer>();
0999:            /** Key column names in natural order.
1000:             */
1001:            private List<String> keyCols = new ArrayList<String>();
1002:            /** Whether to obfuscate something.
1003:             */
1004:            private boolean obfuscate = false;
1005:            /** Names of obfuscated columns.
1006:             */
1007:            private List<String> obfuscatedColumns = null;
1008:            /** Obfuscation status of key columns.
1009:             */
1010:            private boolean keyColObfuscated[] = null;
1011:            /** Localized columns.
1012:             */
1013:            private List localizedColumns = null;
1014:            /** Attributes of this entity.
1015:             */
1016:
1017:            /**
1018:             * Column by alias map.
1019:             */
1020:            private Map<String, String> aliases = new HashMap<String, String>();
1021:
1022:            /** Attribute map.
1023:             *
1024:             */
1025:            private Map<String, Attribute> attributeMap = new HashMap<String, Attribute>();
1026:            /** action map.
1027:             */
1028:            private Map<String, Action> actionMap = new HashMap<String, Action>();
1029:            /** the java class to use to realize this instance.
1030:             */
1031:            private Class instanceClass = null;
1032:            /** the SQL query used to fetch one instance of this entity.
1033:             */
1034:            private String fetchQuery = null;
1035:            /** whether this entity is read-only or not.
1036:             */
1037:            private boolean readOnly;
1038:            /** the database connection.
1039:             */
1040:            private Database db = null;
1041:            /** the caching method.
1042:             */
1043:            private int cachingMethod = 0;
1044:            /** the cache.
1045:             */
1046:            private Cache cache = null;
1047:
1048:            /** Constraint by column name map.
1049:             */
1050:            private Map<String, List<FieldConstraint>> constraints = new HashMap<String, List<FieldConstraint>>();
1051:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.