/* Copyright (c) 2008 Health Market Science, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA You can contact Health Market Science at info@healthmarketscience.com or at the following address: Health Market Science 2700 Horizon Drive Suite 200 King of Prussia, PA 19406 */ package com.healthmarketscience.sqlbuilder; import com.healthmarketscience.common.util.AppendableExt; /** * Object which maintains context for the sqlbuilder classes when a SQL * statement is being generated. The object is passed from one SqlObject to * another via the {@link com.healthmarketscience.common.util.AppendableExt#setContext} * and {@link com.healthmarketscience.common.util.AppendableExt#getContext} methods. * This class enables the various SqlObject SQL generation methods to behave * differently depending on where they are being used in a query. * * Note, users of the sqlbuilder classes may extend this context to pass * through more information as any copying of SqlContexts is done via cloning. * The custom context may be introduced to the current SQL generation context * via the {@link SqlObject#toString(int,SqlContext)} method call. * * @author James Ahlborn */ public class SqlContext implements Cloneable { /** Previous context replaced by this context, if any */ private SqlContext _parent; /** flag indicating whether or not table aliases should be used in the current SQL generation context */ private boolean _useTableAliases = true; /** flag indicating whether constraints apply to a column or a table */ private boolean _useTableConstraints = true; /** handle to the immediate wrapping query */ private Query<?> _query; public SqlContext() { } /** * Gets the SqlContext which was in effect before this SqlContext was * "pushed" onto the context stack. */ public SqlContext getParent() { return _parent; } /** * Sets the SqlContext which was in effect before this SqlContext was * "pushed" onto the context stack. Used by {@link #pushContext}. */ private void setParent(SqlContext newParentContext) { _parent = newParentContext; } /** * @return the flag indicating whether or not table aliases should be used * in the current SQL generation context. */ public boolean getUseTableAliases() { return _useTableAliases; } /** * Sets flag indicating whether or not table aliases should be used in the * current SQL generation context. */ public void setUseTableAliases(boolean newUseTableAliases) { _useTableAliases = newUseTableAliases; } /** * @return the flag indicating whether or not table constraints should be * used in the current SQL generation context. */ public boolean getUseTableConstraints() { return _useTableConstraints; } /** * Sets flag indicating whether or not table constraints should be used in * the current SQL generation context. */ public void setUseTableConstraints(boolean newUseTableConstraints) { _useTableConstraints = newUseTableConstraints; } /** * Gets the handle to the immediate wrapping query */ public Query<?> getQuery() { return _query; } /** * Sets the handle to the immediate wrapping query */ public void setQuery(Query<?> newQuery) { _query = newQuery; } @Override public SqlContext clone() { try { return (SqlContext)super.clone(); } catch(CloneNotSupportedException e) { throw new RuntimeException("should never get here", e); } } /** * Gets the current SqlContext from the given AppendableExt, creating one if * necessary. Should be used by any subclasses of SqlObject wishing to * retrieve the current context. */ public static SqlContext getContext(AppendableExt app) { SqlContext context = (SqlContext)app.getContext(); if(context == null) { context = new SqlContext(); app.setContext(context); } return context; } /** * Creates a new SqlContext (cloning current one if available), replaces the * current SqlContext with the new SqlContext, and returns the new * SqlContext. All <code>pushContext</code> calls should have a * corresponding {@link #popContext} call. */ public static final SqlContext pushContext(AppendableExt app) { SqlContext parentContext = (SqlContext)app.getContext(); SqlContext context = null; if(parentContext != null) { context = parentContext.clone(); context.setParent(parentContext); } else { context = new SqlContext(); } app.setContext(context); return context; } /** * Replaces the current SqlContext (checking it against the given * SqlContext) with the parent SqlContext (stored within the new one). All * <code>popContext</code> calls should come after a corresponding * {@link #pushContext} call. */ public static void popContext(AppendableExt app, SqlContext context) { if(app.getContext() != context) { throw new IllegalStateException("Mismatched push/pop SqlContext"); } app.setContext((context != null) ? context.getParent() : null); } }