Source Code Cross Referenced for DatabaseAction.java in  » Content-Management-System » apache-lenya-2.0 » org » apache » cocoon » acting » modular » 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 » Content Management System » apache lenya 2.0 » org.apache.cocoon.acting.modular 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         * 
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         * 
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:
0018:        package org.apache.cocoon.acting.modular;
0019:
0020:        import java.io.IOException;
0021:        import java.sql.Connection;
0022:        import java.sql.PreparedStatement;
0023:        import java.sql.SQLException;
0024:        import java.util.Map;
0025:
0026:        import org.apache.avalon.excalibur.datasource.DataSourceComponent;
0027:        import org.apache.avalon.framework.activity.Disposable;
0028:        import org.apache.avalon.framework.configuration.Configuration;
0029:        import org.apache.avalon.framework.configuration.ConfigurationException;
0030:        import org.apache.avalon.framework.parameters.Parameters;
0031:        import org.apache.avalon.framework.service.ServiceException;
0032:        import org.apache.avalon.framework.service.ServiceManager;
0033:        import org.apache.avalon.framework.service.ServiceSelector;
0034:        import org.apache.avalon.framework.thread.ThreadSafe;
0035:
0036:        import org.apache.cocoon.Constants;
0037:        import org.apache.cocoon.ProcessingException;
0038:        import org.apache.cocoon.acting.AbstractComplementaryConfigurableAction;
0039:        import org.apache.cocoon.components.modules.database.AutoIncrementModule;
0040:        import org.apache.cocoon.components.modules.input.InputModule;
0041:        import org.apache.cocoon.components.modules.output.OutputModule;
0042:        import org.apache.cocoon.environment.Redirector;
0043:        import org.apache.cocoon.environment.SourceResolver;
0044:        import org.apache.cocoon.util.HashMap;
0045:        import org.apache.cocoon.util.JDBCTypeConversions;
0046:        import org.apache.commons.lang.BooleanUtils;
0047:
0048:        /**
0049:         * Abstract action for common function needed by database actions.
0050:         * The difference to the other Database*Actions is, that the actions
0051:         * in this package use additional components ("modules") for reading
0052:         * and writing parameters. In addition the descriptor format has
0053:         * changed to accomodate the new features.
0054:         *
0055:         * <p>This action is heavily based upon the original DatabaseAddActions.</p>
0056:         *
0057:         * <p>Modes have to be configured in cocoon.xconf. Mode names from
0058:         * descriptor.xml file are looked up in the component service. Default
0059:         * mode names can only be set during action setup. </p>
0060:         *
0061:         * <p>The number of affected rows is returned to the sitemap with the
0062:         * "row-count" parameter if at least one row was affected.</p>
0063:         *
0064:         * <p>All known column types can be found in 
0065:         * {@link org.apache.cocoon.util.JDBCTypeConversions JDBCTypeConversions}.</p>
0066:         *
0067:         * <table>
0068:         * <tr><td colspan="2">Configuration options (setup):</td></tr>
0069:         * <tr><td>input            </td><td>default mode name for reading values (request-param)</td></tr>
0070:         * <tr><td>autoincrement    </td><td>default mode name for obtaining values from autoincrement columns (auto)</td></tr>
0071:         * <tr><td>append-row       </td><td>append row number in square brackets to column name for output (yes)</td></tr>
0072:         * <tr><td>append-table-name</td><td>add table name to column name for both in- and output (yes)</td></tr>
0073:         * <tr><td>first-row        </td><td>row index of first row (0)</td></tr>
0074:         * <tr><td>path-separator   </td><td>string to separate table name from column name (.)</td></tr>
0075:         * </table>
0076:         *
0077:         * <table>
0078:         * <tr><td colspan="2">Configuration options (setup and per invocation):</td></tr>
0079:         * <tr><td>throw-exception  </td><td>throw an exception when an error occurs (default: false)</td></tr>
0080:         * <tr><td>descriptor       </td><td>file containing database description</td></tr>
0081:         * <tr><td>table-set        </td><td>table-set name to work with         </td></tr>
0082:         * <tr><td>output           </td><td>mode name for writing values (request-attr)</td></tr>
0083:         * <tr><td>reloadable       </td><td>dynamically reload descriptor file if change is detected</td></tr>
0084:         * <tr><td>use-transactions </td><td>defaults to yes</td></tr>
0085:         * <tr><td>connection       </td><td>configured datasource connection to use (overrides value from descriptor file)</td></tr>
0086:         * <tr><td>fail-on-empty    </td><td>(boolean) fail is statement affected zero rows (true)</td></tr>
0087:         * </table>
0088:         *
0089:         * @author <a href="mailto:haul@apache.org">Christian Haul</a>
0090:         * @version $Id: DatabaseAction.java 433543 2006-08-22 06:22:54Z crossley $
0091:         * @see org.apache.cocoon.components.modules.input
0092:         * @see org.apache.cocoon.components.modules.output
0093:         * @see org.apache.cocoon.components.modules.database
0094:         * @see org.apache.cocoon.util.JDBCTypeConversions
0095:         */
0096:        public abstract class DatabaseAction extends
0097:                AbstractComplementaryConfigurableAction implements  Disposable,
0098:                ThreadSafe {
0099:
0100:            // ========================================================================
0101:            // constants
0102:            // ========================================================================
0103:
0104:            static final Integer MODE_AUTOINCR = new Integer(0);
0105:            static final Integer MODE_OTHERS = new Integer(1);
0106:            static final Integer MODE_OUTPUT = new Integer(2);
0107:
0108:            static final String ATTRIBUTE_KEY = "org.apache.cocoon.action.modular.DatabaseAction.outputModeName";
0109:
0110:            // These can be overidden from cocoon.xconf
0111:            static final String inputHint = "request-param"; // default to request parameters
0112:            static final String outputHint = "request-attr"; // default to request attributes
0113:            static final String databaseHint = "manual"; // default to manual auto increments
0114:
0115:            static final String INPUT_MODULE_SELECTOR = InputModule.ROLE
0116:                    + "Selector";
0117:            static final String OUTPUT_MODULE_SELECTOR = OutputModule.ROLE
0118:                    + "Selector";
0119:            static final String DATABASE_MODULE_SELECTOR = AutoIncrementModule.ROLE
0120:                    + "Selector";
0121:
0122:            // ========================================================================
0123:            // instance vars
0124:            // ========================================================================
0125:
0126:            protected ServiceSelector dbselector;
0127:            protected Map defaultModeNames = new HashMap(3);
0128:            protected final HashMap cachedQueryData = new HashMap();
0129:            protected String pathSeparator = ".";
0130:            protected int firstRow = 0;
0131:            protected boolean failOnEmpty = true;
0132:
0133:            // ========================================================================
0134:            // inner helper classes
0135:            // ========================================================================
0136:
0137:            /**
0138:             * Structure that takes all processed data for one column.
0139:             */
0140:            protected static class Column {
0141:                boolean isKey = false;
0142:                boolean isSet = false;
0143:                boolean isAutoIncrement = false;
0144:                String mode = null;
0145:                Configuration modeConf = null;
0146:                Configuration columnConf = null;
0147:            }
0148:
0149:            /**
0150:             * Structure that takes all processed data for a table depending
0151:             * on current default modes
0152:             */
0153:            protected static class CacheHelper {
0154:                /**
0155:                 * Generated query string
0156:                 */
0157:                public String queryString = null;
0158:                /**
0159:                 * if a set is used, column number which is used to determine
0160:                 * the number of rows to insert.
0161:                 */
0162:                public int setMaster = -1;
0163:                public boolean isSet = false;
0164:                public int noOfKeys = 0;
0165:                public Column[] columns = null;
0166:
0167:                public CacheHelper(int cols) {
0168:                    this (0, cols);
0169:                }
0170:
0171:                public CacheHelper(int keys, int cols) {
0172:                    noOfKeys = keys;
0173:                    columns = new Column[cols];
0174:                    for (int i = 0; i < cols; i++) {
0175:                        columns[i] = new Column();
0176:                    }
0177:                }
0178:            }
0179:
0180:            /**
0181:             * Structure that takes up both current mode types for database
0182:             * operations and table configuration data. Used to access parsed
0183:             * configuration data.
0184:             */
0185:            protected static class LookUpKey {
0186:                public Configuration tableConf = null;
0187:                public Map modeTypes = null;
0188:
0189:                public LookUpKey(Configuration tableConf, Map modeTypes) {
0190:                    this .tableConf = tableConf;
0191:                    this .modeTypes = modeTypes;
0192:                }
0193:
0194:                /* (non-Javadoc)
0195:                 * @see java.lang.Object#equals(java.lang.Object)
0196:                 */
0197:                public boolean equals(Object obj) {
0198:                    boolean result = false;
0199:                    if (obj != null && obj instanceof  LookUpKey) {
0200:                        LookUpKey luk = (LookUpKey) obj;
0201:                        result = true;
0202:                        result = result
0203:                                && (luk.tableConf == null ? this .tableConf == null
0204:                                        : luk.tableConf.equals(this .tableConf));
0205:                        result = result
0206:                                && (luk.modeTypes == null ? this .modeTypes == null
0207:                                        : luk.modeTypes.equals(this .modeTypes));
0208:                    }
0209:
0210:                    return result;
0211:                }
0212:
0213:                /* (non-Javadoc)
0214:                 * @see java.lang.Object#hashCode()
0215:                 */
0216:                public int hashCode() {
0217:                    return (this .tableConf != null ? this .tableConf.hashCode()
0218:                            : (this .modeTypes != null ? this .modeTypes
0219:                                    .hashCode() : super .hashCode()));
0220:                }
0221:            }
0222:
0223:            // set up default modes
0224:            // <input/>
0225:            // <output/>
0226:            // <autoincrement/>
0227:            //
0228:            // all other modes need to be declared in cocoon.xconf
0229:            // no need to declare them per action (anymore!)
0230:            public void configure(Configuration conf)
0231:                    throws ConfigurationException {
0232:                super .configure(conf);
0233:                if (this .settings != null) {
0234:                    this .defaultModeNames.put(MODE_OTHERS, this .settings.get(
0235:                            "input", inputHint));
0236:                    this .defaultModeNames.put(MODE_OUTPUT, this .settings.get(
0237:                            "output", outputHint));
0238:                    this .defaultModeNames.put(MODE_AUTOINCR, this .settings.get(
0239:                            "autoincrement", databaseHint));
0240:                    this .pathSeparator = (String) this .settings.get(
0241:                            "path-separator", this .pathSeparator);
0242:                    String tmp = (String) this .settings.get("first-row", null);
0243:                    if (tmp != null) {
0244:                        try {
0245:                            this .firstRow = Integer.parseInt(tmp);
0246:                        } catch (NumberFormatException nfe) {
0247:                            if (getLogger().isWarnEnabled())
0248:                                getLogger().warn(
0249:                                        "problem parsing first row option "
0250:                                                + tmp
0251:                                                + " using default instead.");
0252:                        }
0253:                    }
0254:                    tmp = (String) this .settings.get("fail-on-empty", String
0255:                            .valueOf(this .failOnEmpty));
0256:                    this .failOnEmpty = BooleanUtils.toBoolean(tmp);
0257:                }
0258:            }
0259:
0260:            // ========================================================================
0261:            // Avalon methods
0262:            // ========================================================================
0263:
0264:            /**
0265:             * Compose the Actions so that we can select our databases.
0266:             */
0267:            public void service(ServiceManager manager) throws ServiceException {
0268:                super .service(manager);
0269:                this .dbselector = (ServiceSelector) manager
0270:                        .lookup(DataSourceComponent.ROLE + "Selector");
0271:            }
0272:
0273:            /**
0274:             *  dispose
0275:             */
0276:            public void dispose() {
0277:                this .manager.release(dbselector);
0278:            }
0279:
0280:            // ========================================================================
0281:            // protected utility methods
0282:            // ========================================================================
0283:
0284:            /**
0285:             * Get the Datasource we need.
0286:             */
0287:            protected DataSourceComponent getDataSource(Configuration conf,
0288:                    Parameters parameters) throws ServiceException {
0289:
0290:                String sourceName = parameters.getParameter("connection",
0291:                        (String) settings.get("connection"));
0292:                if (sourceName == null) {
0293:                    Configuration dsn = conf.getChild("connection");
0294:                    return (DataSourceComponent) this .dbselector.select(dsn
0295:                            .getValue(""));
0296:                } else {
0297:                    if (getLogger().isDebugEnabled())
0298:                        getLogger().debug("Using datasource: " + sourceName);
0299:                    return (DataSourceComponent) this .dbselector
0300:                            .select(sourceName);
0301:                }
0302:            }
0303:
0304:            /**
0305:             * Return whether a type is a Large Object (BLOB/CLOB).
0306:             */
0307:            protected final boolean isLargeObject(String type) {
0308:                if ("ascii".equals(type))
0309:                    return true;
0310:                if ("binary".equals(type))
0311:                    return true;
0312:                if ("image".equals(type))
0313:                    return true;
0314:                return false;
0315:            }
0316:
0317:            /**
0318:             * Store a key/value pair in the output attributes. We prefix the key
0319:             * with the name of this class to prevent potential name collisions.
0320:             */
0321:            protected void setOutputAttribute(Map objectModel,
0322:                    String outputMode, String key, Object value) {
0323:
0324:                ServiceSelector outputSelector = null;
0325:                OutputModule output = null;
0326:                try {
0327:                    outputSelector = (ServiceSelector) this .manager
0328:                            .lookup(OUTPUT_MODULE_SELECTOR);
0329:                    if (outputMode != null && outputSelector != null
0330:                            && outputSelector.isSelectable(outputMode)) {
0331:                        output = (OutputModule) outputSelector
0332:                                .select(outputMode);
0333:                    }
0334:                    if (output != null) {
0335:                        output.setAttribute(null, objectModel, key, value);
0336:                    } else if (getLogger().isWarnEnabled()) {
0337:                        getLogger().warn(
0338:                                "Could not select output mode " + outputMode);
0339:                    }
0340:                } catch (Exception e) {
0341:                    if (getLogger().isWarnEnabled()) {
0342:                        getLogger().warn(
0343:                                "Could not select output mode " + outputMode
0344:                                        + ":" + e.getMessage());
0345:                    }
0346:                } finally {
0347:                    if (outputSelector != null) {
0348:                        if (output != null)
0349:                            outputSelector.release(output);
0350:                        this .manager.release(outputSelector);
0351:                    }
0352:                }
0353:            }
0354:
0355:            /**
0356:             * Inserts a row or a set of rows into the given table based on the
0357:             * request parameters
0358:             *
0359:             * @param table the table's configuration
0360:             * @param conn the database connection
0361:             * @param objectModel the objectModel
0362:             */
0363:            protected int processTable(Configuration table, Connection conn,
0364:                    Map objectModel, Map results, Map modeTypes)
0365:                    throws SQLException, ConfigurationException, Exception {
0366:
0367:                PreparedStatement statement = null;
0368:                int rows = 0;
0369:                try {
0370:                    LookUpKey luk = new LookUpKey(table, modeTypes);
0371:                    CacheHelper queryData = null;
0372:
0373:                    if (getLogger().isDebugEnabled())
0374:                        getLogger().debug("modeTypes : " + modeTypes);
0375:
0376:                    // get cached data
0377:                    // synchronize complete block since we don't want 100s of threads
0378:                    // generating the same cached data set. In the long run all data
0379:                    // is cached anyways so this won't cost much.
0380:                    synchronized (this .cachedQueryData) {
0381:                        queryData = (CacheHelper) this .cachedQueryData.get(luk,
0382:                                null);
0383:                        if (queryData == null) {
0384:                            queryData = this .getQuery(table, modeTypes,
0385:                                    defaultModeNames);
0386:                            this .cachedQueryData.put(luk, queryData);
0387:                        }
0388:                    }
0389:
0390:                    if (getLogger().isDebugEnabled())
0391:                        getLogger().debug("query: " + queryData.queryString);
0392:                    statement = conn.prepareStatement(queryData.queryString);
0393:
0394:                    Object[][] columnValues = this .getColumnValues(table,
0395:                            queryData, objectModel);
0396:
0397:                    int setLength = 1;
0398:                    if (queryData.isSet) {
0399:                        if (columnValues[queryData.setMaster] != null) {
0400:                            setLength = columnValues[queryData.setMaster].length;
0401:                        } else {
0402:                            setLength = 0;
0403:                        }
0404:                    }
0405:
0406:                    for (int rowIndex = 0; rowIndex < setLength; rowIndex++) {
0407:                        if (getLogger().isDebugEnabled()) {
0408:                            getLogger().debug("====> row no. " + rowIndex);
0409:                        }
0410:                        rows += processRow(objectModel, conn, statement,
0411:                                (String) modeTypes.get(MODE_OUTPUT), table,
0412:                                queryData, columnValues, rowIndex, results);
0413:                    }
0414:                } finally {
0415:                    try {
0416:                        if (statement != null) {
0417:                            statement.close();
0418:                        }
0419:                    } catch (SQLException e) {
0420:                    }
0421:                }
0422:                return rows;
0423:            }
0424:
0425:            /**
0426:             * Choose a mode configuration based on its name.
0427:             * @param conf Configuration (i.e. a column's configuration) that might have
0428:             * several children configurations named "mode".
0429:             * @param type desired type (i.e. every mode has a type
0430:             * attribute), find the first mode that has a compatible type.
0431:             * Special mode "all" matches all queried types.
0432:             * @return configuration that has desired type or type "all" or null.
0433:             */
0434:            protected Configuration getMode(Configuration conf, String type)
0435:                    throws ConfigurationException {
0436:
0437:                String modeAll = "all";
0438:                Configuration[] modes = conf.getChildren("mode");
0439:                Configuration modeConfig = null;
0440:
0441:                for (int i = 0; i < modes.length; i++) {
0442:                    String modeType = modes[i].getAttribute("type", "others");
0443:                    if (modeType.equals(type) || modeType.equals(modeAll)) {
0444:                        if (getLogger().isDebugEnabled())
0445:                            getLogger().debug(
0446:                                    "requested mode was \"" + type
0447:                                            + "\" returning \"" + modeType
0448:                                            + "\"");
0449:                        modeConfig = modes[i];
0450:                        break;
0451:                    }
0452:                }
0453:                return modeConfig;
0454:            }
0455:
0456:            /**
0457:             * compose name for output a long the lines of "table.column"
0458:             */
0459:            protected String getOutputName(Configuration tableConf,
0460:                    Configuration columnConf) {
0461:
0462:                return getOutputName(tableConf, columnConf, -1);
0463:            }
0464:
0465:            /**
0466:             * compose name for output a long the lines of "table.column[row]" or
0467:             * "table.column" if rowIndex is -1.
0468:             * If the section of the sitemap corresponding to the action contains
0469:             * <append-table-name>false</append-table-name>
0470:             * the name for output is "column[row]"
0471:             * If the section of the sitemap corresponding to the action contains
0472:             * <append-row>false</append-row>
0473:             * the name for output is "column"
0474:             */
0475:            protected String getOutputName(Configuration tableConf,
0476:                    Configuration columnConf, int rowIndex) {
0477:
0478:                if (rowIndex != -1
0479:                        && this .settings.containsKey("append-row")
0480:                        && (this .settings.get("append-row").toString()
0481:                                .equalsIgnoreCase("false") || this .settings
0482:                                .get("append-row").toString().equalsIgnoreCase(
0483:                                        "0"))) {
0484:                    rowIndex = -1;
0485:                } else {
0486:                    rowIndex = rowIndex + this .firstRow;
0487:                }
0488:                if (this .settings.containsKey("append-table-name")
0489:                        && (this .settings.get("append-table-name").toString()
0490:                                .equalsIgnoreCase("false") || this .settings
0491:                                .get("append-table-name").toString()
0492:                                .equalsIgnoreCase("0"))) {
0493:                    return (columnConf.getAttribute("name", null) + (rowIndex == -1 ? ""
0494:                            : "[" + rowIndex + "]"));
0495:                } else {
0496:                    return (tableConf.getAttribute("alias", tableConf
0497:                            .getAttribute("name", null))
0498:                            + this .pathSeparator
0499:                            + columnConf.getAttribute("name", null) + (rowIndex == -1 ? ""
0500:                            : "[" + rowIndex + "]"));
0501:                }
0502:            }
0503:
0504:            /*
0505:             * Read all values for a column from an InputModule
0506:             *
0507:             * If the given column is an autoincrement column, an empty array
0508:             * is returned, otherwise if it is part of a set, all available
0509:             * values are fetched, or only the first one if it is not part of
0510:             * a set.
0511:             *
0512:             */
0513:            protected Object[] getColumnValue(Configuration tableConf,
0514:                    Column column, Map objectModel)
0515:                    throws ConfigurationException, ServiceException {
0516:
0517:                if (column.isAutoIncrement) {
0518:                    return new Object[1];
0519:                } else {
0520:                    Object[] values;
0521:                    String cname = getOutputName(tableConf, column.columnConf);
0522:
0523:                    // obtain input module and read values
0524:                    ServiceSelector inputSelector = null;
0525:                    InputModule input = null;
0526:                    try {
0527:                        inputSelector = (ServiceSelector) this .manager
0528:                                .lookup(INPUT_MODULE_SELECTOR);
0529:                        if (column.mode != null && inputSelector != null
0530:                                && inputSelector.isSelectable(column.mode)) {
0531:                            input = (InputModule) inputSelector
0532:                                    .select(column.mode);
0533:                        }
0534:
0535:                        if (column.isSet) {
0536:                            if (getLogger().isDebugEnabled()) {
0537:                                getLogger()
0538:                                        .debug(
0539:                                                "Trying to set column "
0540:                                                        + cname
0541:                                                        + " from "
0542:                                                        + column.mode
0543:                                                        + " using getAttributeValues method");
0544:                            }
0545:                            values = input.getAttributeValues(cname,
0546:                                    column.modeConf, objectModel);
0547:                        } else {
0548:                            if (getLogger().isDebugEnabled()) {
0549:                                getLogger().debug(
0550:                                        "Trying to set column " + cname
0551:                                                + " from " + column.mode
0552:                                                + " using getAttribute method");
0553:                            }
0554:                            values = new Object[1];
0555:                            values[0] = input.getAttribute(cname,
0556:                                    column.modeConf, objectModel);
0557:                        }
0558:
0559:                        if (values != null) {
0560:                            for (int i = 0; i < values.length; i++) {
0561:                                if (getLogger().isDebugEnabled()) {
0562:                                    getLogger().debug(
0563:                                            "Setting column " + cname + " ["
0564:                                                    + i + "] " + values[i]);
0565:                                }
0566:                            }
0567:                        }
0568:                    } finally {
0569:                        if (inputSelector != null) {
0570:                            if (input != null) {
0571:                                inputSelector.release(input);
0572:                            }
0573:                            this .manager.release(inputSelector);
0574:                        }
0575:                    }
0576:                    return values;
0577:                }
0578:            }
0579:
0580:            /**
0581:             * Setup parsed attribute configuration object
0582:             */
0583:            protected void fillModes(Configuration[] conf, boolean isKey,
0584:                    Map defaultModeNames, Map modeTypes, CacheHelper set)
0585:                    throws ConfigurationException {
0586:
0587:                String setMode = null;
0588:                int offset = (isKey ? 0 : set.noOfKeys);
0589:
0590:                for (int i = offset; i < conf.length + offset; i++) {
0591:                    if (getLogger().isDebugEnabled()) {
0592:                        getLogger().debug("i=" + i);
0593:                    }
0594:                    set.columns[i].columnConf = conf[i - offset];
0595:                    set.columns[i].isSet = false;
0596:                    set.columns[i].isKey = isKey;
0597:                    set.columns[i].isAutoIncrement = false;
0598:                    if (isKey & this .honourAutoIncrement()) {
0599:                        set.columns[i].isAutoIncrement = set.columns[i].columnConf
0600:                                .getAttributeAsBoolean("autoincrement", false);
0601:                    }
0602:                    set.columns[i].modeConf = getMode(
0603:                            set.columns[i].columnConf, selectMode(
0604:                                    set.columns[i].isAutoIncrement, modeTypes));
0605:                    set.columns[i].mode = (set.columns[i].modeConf != null ? set.columns[i].modeConf
0606:                            .getAttribute("name", selectMode(isKey,
0607:                                    defaultModeNames))
0608:                            : selectMode(isKey, defaultModeNames));
0609:                    // Determine set mode for a whole column ...
0610:                    setMode = set.columns[i].columnConf.getAttribute("set",
0611:                            null); // master vs slave vs null
0612:                    if (setMode == null && set.columns[i].modeConf != null) {
0613:                        // ... or for each mode individually
0614:                        setMode = set.columns[i].modeConf.getAttribute("set",
0615:                                null);
0616:                    }
0617:                    if (setMode != null) {
0618:                        set.columns[i].isSet = true;
0619:                        set.isSet = true;
0620:                        if (setMode.equals("master")) {
0621:                            set.setMaster = i;
0622:                        }
0623:                    }
0624:                }
0625:            }
0626:
0627:            /**
0628:             * create a unique name using the getOutputName method and write
0629:             * the value to the output module and the results map if present.
0630:             *
0631:             */
0632:            protected void setOutput(Map objectModel, String outputMode,
0633:                    Map results, Configuration table, Configuration column,
0634:                    int rowIndex, Object value) {
0635:
0636:                String param = this .getOutputName(table, column, rowIndex);
0637:                if (getLogger().isDebugEnabled()) {
0638:                    getLogger().debug(
0639:                            "Setting column " + param + " to " + value);
0640:                }
0641:                this .setOutputAttribute(objectModel, outputMode, param, value);
0642:                if (results != null) {
0643:                    results.put(param, String.valueOf(value));
0644:                }
0645:            }
0646:
0647:            /**
0648:             * set a column in a statement using the appropriate JDBC setXXX method.
0649:             *
0650:             */
0651:            protected void setColumn(PreparedStatement statement, int position,
0652:                    Configuration entry, Object value) throws Exception {
0653:                JDBCTypeConversions.setColumn(statement, position, value,
0654:                        (Integer) JDBCTypeConversions.typeConstants.get(entry
0655:                                .getAttribute("type")));
0656:            }
0657:
0658:            /**
0659:             * set a column in a statement using the appropriate JDBC setXXX
0660:             * method and propagate the value to the output module and results
0661:             * map if present. Effectively combines calls to setColumn and
0662:             * setOutput.
0663:             *
0664:             */
0665:            protected void setColumn(Map objectModel, String outputMode,
0666:                    Map results, Configuration table, Configuration column,
0667:                    int rowIndex, Object value, PreparedStatement statement,
0668:                    int position) throws Exception {
0669:
0670:                if (results != null) {
0671:                    this .setOutput(objectModel, outputMode, results, table,
0672:                            column, rowIndex, value);
0673:                }
0674:                this .setColumn(statement, position, column, value);
0675:            }
0676:
0677:            // ========================================================================
0678:            // main method
0679:            // ========================================================================
0680:
0681:            /**
0682:             * Add a record to the database.  This action assumes that
0683:             * the file referenced by the "descriptor" parameter conforms
0684:             * to the AbstractDatabaseAction specifications.
0685:             */
0686:            public Map act(Redirector redirector, SourceResolver resolver,
0687:                    Map objectModel, String source, Parameters param)
0688:                    throws Exception {
0689:
0690:                DataSourceComponent datasource = null;
0691:                Connection conn = null;
0692:                Map results = new HashMap();
0693:                int rows = 0;
0694:                boolean failed = false;
0695:
0696:                // read global parameter settings
0697:                boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
0698:
0699:                // call specific default modes apart from output mode are not supported
0700:                // set request attribute
0701:                String outputMode = param.getParameter("output",
0702:                        (String) defaultModeNames.get(MODE_OUTPUT));
0703:
0704:                if (this .settings.containsKey("reloadable")) {
0705:                    reloadable = Boolean.valueOf(
0706:                            (String) this .settings.get("reloadable"))
0707:                            .booleanValue();
0708:                }
0709:                // read local parameter settings
0710:                try {
0711:                    Configuration conf = this .getConfiguration(param
0712:                            .getParameter("descriptor", (String) this .settings
0713:                                    .get("descriptor")), resolver, param
0714:                            .getParameterAsBoolean("reloadable", reloadable));
0715:
0716:                    // get database connection and try to turn off autocommit
0717:                    datasource = this .getDataSource(conf, param);
0718:                    conn = datasource.getConnection();
0719:                    if (conn.getAutoCommit() == true) {
0720:                        try {
0721:                            conn.setAutoCommit(false);
0722:                        } catch (Exception ex) {
0723:                            String tmp = param.getParameter("use-transactions",
0724:                                    (String) this .settings.get(
0725:                                            "use-transactions", null));
0726:                            if (tmp != null
0727:                                    && (tmp.equalsIgnoreCase("no")
0728:                                            || tmp.equalsIgnoreCase("false") || tmp
0729:                                            .equalsIgnoreCase("0"))) {
0730:                                if (getLogger().isErrorEnabled())
0731:                                    getLogger()
0732:                                            .error(
0733:                                                    "This DB connection does not support transactions. If you want to risk your data's integrity by continuing nonetheless set parameter \"use-transactions\" to \"no\".");
0734:                                throw ex;
0735:                            }
0736:                        }
0737:                    }
0738:
0739:                    // find tables to work with
0740:                    Configuration[] tables = conf.getChildren("table");
0741:                    String tablesetname = param.getParameter("table-set",
0742:                            (String) this .settings.get("table-set"));
0743:
0744:                    Map modeTypes = null;
0745:
0746:                    if (tablesetname == null) {
0747:                        modeTypes = new HashMap(6);
0748:                        modeTypes.put(MODE_AUTOINCR, "autoincr");
0749:                        modeTypes.put(MODE_OTHERS, "others");
0750:                        modeTypes.put(MODE_OUTPUT, outputMode);
0751:                        for (int i = 0; i < tables.length; i++) {
0752:                            rows += processTable(tables[i], conn, objectModel,
0753:                                    results, modeTypes);
0754:                        }
0755:                    } else {
0756:                        // new set based behaviour
0757:
0758:                        // create index for table names / aliases
0759:                        Map tableIndex = new HashMap(2 * tables.length);
0760:                        String tableName = null;
0761:                        Object result = null;
0762:                        for (int i = 0; i < tables.length; i++) {
0763:                            tableName = tables[i].getAttribute("alias",
0764:                                    tables[i].getAttribute("name", ""));
0765:                            result = tableIndex.put(tableName, new Integer(i));
0766:                            if (result != null) {
0767:                                throw new IOException(
0768:                                        "Duplicate table entry for "
0769:                                                + tableName + " at positions "
0770:                                                + result + " and " + i);
0771:                            }
0772:                        }
0773:
0774:                        Configuration[] tablesets = conf
0775:                                .getChildren("table-set");
0776:                        String setname = null;
0777:                        boolean found = false;
0778:
0779:                        // find tables contained in tableset
0780:                        int j = 0;
0781:                        for (j = 0; j < tablesets.length; j++) {
0782:                            setname = tablesets[j].getAttribute("name", "");
0783:                            if (tablesetname.trim().equals(setname.trim())) {
0784:                                found = true;
0785:                                break;
0786:                            }
0787:                        }
0788:                        if (!found) {
0789:                            throw new IOException(" given set " + tablesetname
0790:                                    + " does not exists in a description file.");
0791:                        }
0792:
0793:                        Configuration[] set = tablesets[j].getChildren("table");
0794:
0795:                        for (int i = 0; i < set.length; i++) {
0796:                            // look for alternative mode types
0797:                            modeTypes = new HashMap(6);
0798:                            modeTypes.put(MODE_AUTOINCR, set[i].getAttribute(
0799:                                    "autoincr-mode", "autoincr"));
0800:                            modeTypes.put(MODE_OTHERS, set[i].getAttribute(
0801:                                    "others-mode", "others"));
0802:                            modeTypes.put(MODE_OUTPUT, outputMode);
0803:                            tableName = set[i].getAttribute("name", "");
0804:                            if (tableIndex.containsKey(tableName)) {
0805:                                j = ((Integer) tableIndex.get(tableName))
0806:                                        .intValue();
0807:                                rows += processTable(tables[j], conn,
0808:                                        objectModel, results, modeTypes);
0809:                            } else {
0810:                                throw new IOException(
0811:                                        " given table "
0812:                                                + tableName
0813:                                                + " does not exists in a description file.");
0814:                            }
0815:                        }
0816:                    }
0817:
0818:                    if (conn.getAutoCommit() == false) {
0819:                        conn.commit();
0820:                    }
0821:
0822:                    // obtain output mode module and rollback output
0823:                    ServiceSelector outputSelector = null;
0824:                    OutputModule output = null;
0825:                    try {
0826:                        outputSelector = (ServiceSelector) this .manager
0827:                                .lookup(OUTPUT_MODULE_SELECTOR);
0828:                        if (outputMode != null && outputSelector != null
0829:                                && outputSelector.isSelectable(outputMode)) {
0830:                            output = (OutputModule) outputSelector
0831:                                    .select(outputMode);
0832:                        }
0833:                        if (output != null) {
0834:                            output.commit(null, objectModel);
0835:                        } else if (getLogger().isWarnEnabled()) {
0836:                            getLogger().warn(
0837:                                    "Could not select output mode "
0838:                                            + outputMode);
0839:                        }
0840:                    } catch (ServiceException e) {
0841:                        if (getLogger().isWarnEnabled()) {
0842:                            getLogger()
0843:                                    .warn(
0844:                                            "Could not select output mode "
0845:                                                    + outputMode + ":"
0846:                                                    + e.getMessage());
0847:                        }
0848:                    } finally {
0849:                        if (outputSelector != null) {
0850:                            if (output != null) {
0851:                                outputSelector.release(output);
0852:                            }
0853:                            this .manager.release(outputSelector);
0854:                        }
0855:                    }
0856:                } catch (Exception e) {
0857:                    failed = true;
0858:                    if (conn != null) {
0859:                        try {
0860:                            if (getLogger().isDebugEnabled()) {
0861:                                getLogger().debug(
0862:                                        "Rolling back transaction. Caused by "
0863:                                                + e.getMessage());
0864:                                e.printStackTrace();
0865:                            }
0866:                            conn.rollback();
0867:                            results = null;
0868:
0869:                            // obtain output mode module and commit output
0870:                            ServiceSelector outputSelector = null;
0871:                            OutputModule output = null;
0872:                            try {
0873:                                outputSelector = (ServiceSelector) this .manager
0874:                                        .lookup(OUTPUT_MODULE_SELECTOR);
0875:                                if (outputMode != null
0876:                                        && outputSelector != null
0877:                                        && outputSelector
0878:                                                .isSelectable(outputMode)) {
0879:                                    output = (OutputModule) outputSelector
0880:                                            .select(outputMode);
0881:                                }
0882:                                if (output != null) {
0883:                                    output.rollback(null, objectModel, e);
0884:                                } else if (getLogger().isWarnEnabled()) {
0885:                                    getLogger().warn(
0886:                                            "Could not select output mode "
0887:                                                    + outputMode);
0888:                                }
0889:                            } catch (ServiceException e2) {
0890:                                if (getLogger().isWarnEnabled()) {
0891:                                    getLogger().warn(
0892:                                            "Could not select output mode "
0893:                                                    + outputMode + ":"
0894:                                                    + e2.getMessage());
0895:                                }
0896:                            } finally {
0897:                                if (outputSelector != null) {
0898:                                    if (output != null) {
0899:                                        outputSelector.release(output);
0900:                                    }
0901:                                    this .manager.release(outputSelector);
0902:                                }
0903:                            }
0904:                        } catch (SQLException se) {
0905:                            if (getLogger().isDebugEnabled())
0906:                                getLogger()
0907:                                        .debug(
0908:                                                "There was an error rolling back the transaction",
0909:                                                se);
0910:                        }
0911:                    }
0912:
0913:                    //throw new ProcessingException("Could not add record :position = " + currentIndex, e);
0914:
0915:                    // don't throw an exception, an error has been signalled, that should suffice
0916:
0917:                    String throwException = (String) this .settings.get(
0918:                            "throw-exception", param.getParameter(
0919:                                    "throw-exception", null));
0920:                    if (throwException != null
0921:                            && BooleanUtils.toBoolean(throwException)) {
0922:                        throw new ProcessingException(
0923:                                "Cannot process the requested SQL statement ",
0924:                                e);
0925:                    }
0926:                } finally {
0927:                    if (conn != null) {
0928:                        try {
0929:                            conn.close();
0930:                        } catch (SQLException sqe) {
0931:                            getLogger()
0932:                                    .warn(
0933:                                            "There was an error closing the datasource",
0934:                                            sqe);
0935:                        }
0936:                    }
0937:
0938:                    if (datasource != null)
0939:                        this .dbselector.release(datasource);
0940:                }
0941:                if (results != null) {
0942:                    if (rows > 0 || (!failed && !this .failOnEmpty)) {
0943:                        results.put("row-count", new Integer(rows));
0944:                    } else {
0945:                        results = null;
0946:                    }
0947:                } else {
0948:                    if (rows > 0) {
0949:                        results = new HashMap(1);
0950:                        results.put("row-count", new Integer(rows));
0951:                    }
0952:                }
0953:
0954:                return results; // (results == null? results : Collections.unmodifiableMap(results));
0955:            }
0956:
0957:            // ========================================================================
0958:            // abstract methods
0959:            // ========================================================================
0960:
0961:            /**
0962:             * set all necessary ?s and execute the query
0963:             * return number of rows processed
0964:             *
0965:             * This method is intended to be overridden by classes that
0966:             * implement other operations e.g. delete
0967:             */
0968:            protected abstract int processRow(Map objectModel, Connection conn,
0969:                    PreparedStatement statement, String outputMode,
0970:                    Configuration table, CacheHelper queryData,
0971:                    Object[][] columnValues, int rowIndex, Map results)
0972:                    throws SQLException, ConfigurationException, Exception;
0973:
0974:            /**
0975:             * determine which mode to use as default mode
0976:             *
0977:             * This method is intended to be overridden by classes that
0978:             * implement other operations e.g. delete
0979:             */
0980:            protected abstract String selectMode(boolean isAutoIncrement,
0981:                    Map modes);
0982:
0983:            /**
0984:             * determine whether autoincrement columns should be honoured by
0985:             * this operation. This is usually snsible only for INSERTs.
0986:             *
0987:             * This method is intended to be overridden by classes that
0988:             * implement other operations e.g. delete
0989:             */
0990:            protected abstract boolean honourAutoIncrement();
0991:
0992:            /**
0993:             * Fetch all values for all columns that are needed to do the
0994:             * database operation.
0995:             *
0996:             * This method is intended to be overridden by classes that
0997:             * implement other operations e.g. delete
0998:             */
0999:            abstract Object[][] getColumnValues(Configuration tableConf,
1000:                    CacheHelper queryData, Map objectModel)
1001:                    throws ConfigurationException, ServiceException;
1002:
1003:            /**
1004:             * Get the String representation of the PreparedStatement.  This is
1005:             * mapped to the Configuration object itself, so if it doesn't exist,
1006:             * it will be created.
1007:             *
1008:             * This method is intended to be overridden by classes that
1009:             * implement other operations e.g. delete
1010:             *
1011:             * @param table the table's configuration object
1012:             * @return the insert query as a string
1013:             */
1014:            protected abstract CacheHelper getQuery(Configuration table,
1015:                    Map modeTypes, Map defaultModeNames)
1016:                    throws ConfigurationException, ServiceException;
1017:
1018:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.