Package org.gomba

Source Code of org.gomba.UpdateServlet

package org.gomba;

import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* Perform a write operation on a JDBC data store. the SQL in the
* <code>query</code> init-param can be an INSERT, UPDATE or DELETE statement.
* This servlet inherits the init-params of {@link org.gomba.AbstractServlet},
* plus:
* <dl>
* <dt>query</dt>
* <dd>The SQL update to execute. May contain ${} parameters. This init-param
* also accepts a path to a dynamic resource (a JSP) when dynamic SQL generation
* is needed. The path must begin with a "/" and is interpreted as relative to
* the current context root. (Required)</dd>
* <dt>batch</dt>
* <dd>true if the SQL contains multiple statements separated by semicolons.
* Muliple updates are performed as part of single transaction. (Optional)</dd>
* <dt>http-method</dt>
* <dd>The value can be POST, PUT or DELETE. (Required)</dd>
* </dl>
*
* Note about HTTP method usage. The POST method is normally used for creation
* (INSERT in SQL) operations. The PUT method is normally used for update
* (UPDATE in SQL) operations. The DELETE method is obviously used for deletion
* (DELETE in SQL) operations.
*
* @author Flavio Tordini
* @version $Id: UpdateServlet.java,v 1.12 2005/10/19 13:00:21 flaviotordini Exp $
*/
public class UpdateServlet extends AbstractServlet {

    private final static String INIT_PARAM_HTTP_METHOD = "http-method";

    private final static String INIT_PARAM_QUERY = "query";

    private final static String INIT_PARAM_BATCH = "batch";

    /**
     * <code>true</code> if this servlet supports the POST HTTP method.
     */
    private boolean supportPost;

    /**
     * <code>true</code> if this servlet supports the PUT HTTP method.
     */
    private boolean supportPut;

    /**
     * <code>true</code> if this servlet supports the DELETE HTTP method.
     */
    private boolean supportDelete;

    /**
     * The parsed query definitions. It is null when the query is dynamic, i.e.
     * a dynamic resource (a JSP) is used to generate the SQL. List of
     * QueryDefinition.
     */
    private List queryDefinitions;

    /**
     * The path of a resource that dynamically generates a SQL query.
     */
    private String queryResource;

    private boolean batch;

    /**
     * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
     */
    public void init(ServletConfig config) throws ServletException {
        super.init(config);

        // supported HTTP method
        String httpMethod = config.getInitParameter(INIT_PARAM_HTTP_METHOD);
        if (httpMethod == null) {
            throw new ServletException("Missing init-param: "
                    + INIT_PARAM_HTTP_METHOD);
        }
        if (httpMethod.equals("POST")) {
            this.supportPost = true;
        } else if (httpMethod.equals("PUT")) {
            this.supportPut = true;
        } else if (httpMethod.equals("DELETE")) {
            this.supportDelete = true;
        } else {
            throw new ServletException("Unsupported HTTP method: " + httpMethod);
        }

        // is batch?
        String batchStr = config.getInitParameter(INIT_PARAM_BATCH);
        this.batch = Boolean.valueOf(batchStr).booleanValue();

        // parse the query definition(s)
        try {
            String query = config.getInitParameter(INIT_PARAM_QUERY);
            if (!query.startsWith("/")) {
                this.queryDefinitions = parseQueryDefinitions(query);
            } else {
                this.queryResource = query;
            }
        } catch (Exception e) {
            throw new ServletException("Error parsing query definition(s).", e);
        }

    }

    private List parseBatchQueryDefinitions(String query) throws Exception {
        StringTokenizer st = new StringTokenizer(query, ";");
        List queryDefinitions = new ArrayList(st.countTokens());
        while (st.hasMoreTokens()) {
            String token = st.nextToken().trim();
            if (token.length() == 0) {
                continue;
            }
            QueryDefinition queryDefinition = new QueryDefinition(token);
            queryDefinitions.add(queryDefinition);
        }
        return queryDefinitions;
    }

    private List parseQueryDefinitions(String query) throws Exception {
        List queryDefinitions;
        if (this.batch) {
            queryDefinitions = parseBatchQueryDefinitions(query);
        } else {
            queryDefinitions = Collections.singletonList(new QueryDefinition(
                    query));
        }
        return queryDefinitions;
    }

    /**
     * @see javax.servlet.http.HttpServlet#doDelete(javax.servlet.http.HttpServletRequest,
     *           javax.servlet.http.HttpServletResponse)
     */
    protected void doDelete(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        if (this.supportDelete) {
            processRequest(request, response);
        } else {
            response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
        }
    }

    /**
     * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest,
     *           javax.servlet.http.HttpServletResponse)
     */
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        if (this.supportPost) {
            processRequest(request, response);
        } else {
            response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
        }
    }

    /**
     * @see javax.servlet.http.HttpServlet#doPut(javax.servlet.http.HttpServletRequest,
     *           javax.servlet.http.HttpServletResponse)
     */
    protected void doPut(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        if (this.supportPut) {
            processRequest(request, response);
        } else {
            response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
        }
    }

    /**
     * Get the QueryDefinition, it can be a fixed QueryDefinition created at
     * init-time. Or a dynamic one created by evaluating a JSP.
     */
    private List getQueryDefinitions(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        List requestQueryDefinitions;
        if (this.queryDefinitions == null) {
            // dynamic query
            String sql = getDynamicQuery(this.queryResource, request, response);
            try {
                requestQueryDefinitions = parseQueryDefinitions(sql);
            } catch (Exception e) {
                throw new ServletException(
                        "Error parsing query definition(s).", e);
            }
        } else {
            // fixed query
            requestQueryDefinitions = this.queryDefinitions;
        }
        return requestQueryDefinitions;
    }

    /**
     * The real work is done here.
     *
     * @param request
     *                   The HTTP request
     * @param response
     *                   The HTTP response
     */
    protected final void processRequest(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {

        // get current time for benchmarking purposes
        final long startTime = System.currentTimeMillis();

        // create the parameter resolver that will help us throughout this
        // request
        final ParameterResolver parameterResolver = new ParameterResolver(
                request);

        // get the query definition(s)
        List requestQueryDefinitions = getQueryDefinitions(request, response);
        if (requestQueryDefinitions.isEmpty()) {
            throw new ServletException("Missing query definitions.");
        }

        // find out if this request is part of a transaction
        Transaction transaction = getTransaction(parameterResolver);

        Connection connection = null;
        Query.QueryResult queryResult = null;

        // surround everything in this try/finally to be able to free JDBC
        // resources even in case of exceptions
        try {

            // get a JDBC connection
            try {
                if (transaction == null) {
                    connection = getDataSource().getConnection();
                    if (this.batch) {
                        connection.setAutoCommit(false);
                    }
                } else {
                    if (isDebugMode()) {
                      log("Request is part of transaction: "
                              + transaction.getUri());
                    }
                    connection = transaction.getConnection();
                }
            } catch (SQLException e) {
                throw new ServletException("Error getting JDBC connection.", e);
            }

            // loop through query definitions
            for (Iterator qdIterator = requestQueryDefinitions.iterator(); qdIterator
                    .hasNext();) {

                QueryDefinition requestQueryDefinition = (QueryDefinition) qdIterator
                        .next();

                // build the Query
                final Query query = getQuery(requestQueryDefinition,
                        parameterResolver);

                // execute the query
                Query.QueryResult newQueryResult = query.execute(connection);
                if (newQueryResult != null) {

                    // now that we've (maybe) used the data from the previous query,
                    // let's free the ResultSet
                    if (queryResult != null) {
                        try {
                            queryResult.close();
                        } catch (Exception e) {
                            throw new ServletException(
                                    "Error freeing JDBC resources.", e);
                        }
                    }

                    queryResult = newQueryResult;
                    ResultSet resultSet = queryResult.getResultSet();
                    maybeMoveCursor(resultSet);
                    parameterResolver.setResultSet(resultSet);
                }

            }

            // set the response headers
            setResponseHeaders(response, parameterResolver);

            // set the HTTP status code
            int httpStatus = getHttpStatusCode();
            if (httpStatus != HttpServletResponse.SC_OK) {
                response.setStatus(httpStatus);
            }
           
            if (transaction == null && this.batch) {
                connection.commit();
            }

        } catch (Exception e) {
            if (transaction == null && connection != null && this.batch) {
                try {
                    connection.rollback();
                } catch (Exception e2) {
                    log("Error rolling back JDBC connection.", e2);
                }
            }
            if (e instanceof ServletException) {
                throw (ServletException) e;
            }
            if (e instanceof IOException) {
                throw (IOException) e;
            }
            throw new ServletException("Error processing request.", e);
        } finally {

            // *always* free the JDBC resources!
            if (queryResult != null) {
                try {
                    queryResult.close();
                } catch (Exception e) {
                    log("Error freeing JDBC resources.", e);
                }
            }

            // close the JDBC connection if this request is not part of a
            // transaction
            if (transaction == null && connection != null) {
                try {
                    if (this.batch) {
                        connection.setAutoCommit(true);
                    }
                    connection.close();
                } catch (Exception e) {
                    throw new ServletException(
                            "Error closing JDBC connection.", e);
                }
            }

            // processing time
            if (isDebugMode()) {
                log(getProfilingMessage(request, startTime));
            }

        }
    }
}
TOP

Related Classes of org.gomba.UpdateServlet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.