001: /**
002: * Sequoia: Database clustering technology.
003: * Copyright (C) 2002-2004 French National Institute For Research In Computer
004: * Science And Control (INRIA).
005: * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
006: * Contact: sequoia@continuent.org
007: *
008: * Licensed under the Apache License, Version 2.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: * Initial developer(s): Emmanuel Cecchet.
021: * Contributor(s): Sara Bouchenak.
022: */package org.continuent.sequoia.controller.cache.result.schema;
023:
024: import java.sql.SQLException;
025: import java.util.ArrayList;
026: import java.util.HashMap;
027: import java.util.Iterator;
028:
029: import org.continuent.sequoia.common.sql.schema.DatabaseColumn;
030: import org.continuent.sequoia.common.sql.schema.DatabaseTable;
031: import org.continuent.sequoia.controller.cache.result.entries.AbstractResultCacheEntry;
032: import org.continuent.sequoia.controller.requests.RequestType;
033:
034: /**
035: * A <code>CacheDatabaseTable</code> represents a database table and its
036: * associated cache entries. It has an array of <code>CacheDatabaseColumn</code>
037: * objects.
038: * <p>
039: * Keep it mind that <code>ArrayList</code> and <code>HashMap</code> are not
040: * synchronized...
041: *
042: * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
043: * @author <a href="mailto:Sara.Bouchenak@epfl.ch">Sara Bouchenak </a>
044: * @version 1.0
045: */
046: public class CacheDatabaseTable {
047: private String name;
048: private ArrayList columns;
049: private ArrayList cacheEntries; // Cache entries depending on this table
050: private HashMap pkCacheEntries; // Cache entries corresponding to a pk value
051:
052: /**
053: * Creates a new <code>CacheDatabaseTable</code> instance.
054: *
055: * @param databaseTable the database table to cache
056: */
057: public CacheDatabaseTable(DatabaseTable databaseTable) {
058: // Clone the name and the columns
059: name = databaseTable.getName();
060: ArrayList origColumns = databaseTable.getColumns();
061: int size = origColumns.size();
062: columns = new ArrayList(size);
063: for (int i = 0; i < size; i++)
064: columns.add(new CacheDatabaseColumn(
065: ((DatabaseColumn) origColumns.get(i)).getName()));
066:
067: // Create an empty cache
068: cacheEntries = new ArrayList();
069: pkCacheEntries = new HashMap();
070: }
071:
072: /**
073: * Gets the name of the table.
074: *
075: * @return the table name
076: */
077: public String getName() {
078: return name;
079: }
080:
081: /**
082: * Adds a <code>CacheDatabaseColumn</code> object to this table.
083: * <p>
084: * Warning! The underlying <code>ArrayList</code> is not synchronized.
085: *
086: * @param column a <code>CacheDatabaseColumn</code> value
087: */
088: public void addColumn(CacheDatabaseColumn column) {
089: columns.add(column);
090: }
091:
092: /**
093: * Merge the given table's columns with the current table. All missing columns
094: * are added if no conflict is detected. An exception is thrown if the given
095: * table columns conflicts with the current one.
096: *
097: * @param t the table to merge
098: * @throws SQLException if the schemas conflict
099: */
100: public void mergeColumns(CacheDatabaseTable t) throws SQLException {
101: if (t == null)
102: return;
103:
104: ArrayList otherColumns = t.getColumns();
105: if (otherColumns == null)
106: return;
107:
108: int size = otherColumns.size();
109: for (int i = 0; i < size; i++) {
110: CacheDatabaseColumn c = (CacheDatabaseColumn) otherColumns
111: .get(i);
112: CacheDatabaseColumn original = getColumn(c.getName());
113: if (original == null)
114: addColumn(c);
115: else {
116: if (!original.equals(c))
117: throw new SQLException("Column " + c.getName()
118: + " definition mismatch.");
119: }
120: }
121: }
122:
123: /**
124: * Returns a list of <code>CacheDatabaseColumn</code> objects describing the
125: * columns of this table.
126: * <p>
127: * Warning! The underlying <code>ArrayList</code> is not synchronized.
128: *
129: * @return an <code>ArrayList</code> of <code>CacheDatabaseColumn</code>
130: */
131: public ArrayList getColumns() {
132: return columns;
133: }
134:
135: /**
136: * Returns the <code>CacheDatabaseColumn</code> object matching the given
137: * column name or <code>null</code> if not found.
138: *
139: * @param columnName column name to look for
140: * @return a <code>CacheDatabaseColumn</code> value or <code>null</code>
141: */
142: public CacheDatabaseColumn getColumn(String columnName) {
143: for (Iterator i = columns.iterator(); i.hasNext();) {
144: CacheDatabaseColumn c = (CacheDatabaseColumn) i.next();
145: if (columnName.compareToIgnoreCase(c.getName()) == 0)
146: return c;
147: }
148: return null;
149: }
150:
151: /**
152: * Two <code>CacheDatabaseColumn</code> are equals if they have the same
153: * name and the same columns.
154: *
155: * @param other the object to compare with
156: * @return true if the objects are the same
157: */
158: public boolean equals(Object other) {
159: if (!(other instanceof CacheDatabaseTable))
160: return false;
161:
162: CacheDatabaseTable t = (CacheDatabaseTable) other;
163: return t.getName().equals(name)
164: && t.getColumns().equals(columns);
165: }
166:
167: /**
168: * Adds an <code>AbstractResultCacheEntry</code> object whose consistency
169: * depends on this table.
170: *
171: * @param ce an <code>AbstractResultCacheEntry</code> value
172: */
173: public synchronized void addCacheEntry(AbstractResultCacheEntry ce) {
174: cacheEntries.add(ce);
175: }
176:
177: /**
178: * Adds an <code>AbstractResultCacheEntry</code> object associated to a pk
179: * entry.
180: *
181: * @param pk the pk entry
182: * @param ce an <code>AbstractResultCacheEntry</code> value
183: */
184: public void addPkCacheEntry(String pk, AbstractResultCacheEntry ce) {
185: synchronized (pkCacheEntries) {
186: pkCacheEntries.put(pk, ce);
187: }
188: }
189:
190: /**
191: * Gets a <code>CacheEntry</code> object associated to a pk entry.
192: *
193: * @param pk the pk entry
194: * @return the corresponding cache entry if any or null if nothing is found
195: */
196: public AbstractResultCacheEntry getPkResultCacheEntry(String pk) {
197: if (pk == null)
198: return null;
199: synchronized (pkCacheEntries) {
200: return (AbstractResultCacheEntry) pkCacheEntries.get(pk);
201: }
202: }
203:
204: /**
205: * Remove a <code>CacheEntry</code> object associated to a pk entry.
206: *
207: * @param pk the pk entry
208: */
209: public void removePkResultCacheEntry(Object pk) {
210: synchronized (pkCacheEntries) {
211: AbstractResultCacheEntry rce = (AbstractResultCacheEntry) pkCacheEntries
212: .remove(pk);
213: rce.invalidate();
214: }
215: }
216:
217: /**
218: * Invalidates all cache entries of every column of this table. This does also
219: * affect the entries based on pk values.
220: */
221: public void invalidateAll() {
222: synchronized (this ) {
223: for (Iterator i = cacheEntries.iterator(); i.hasNext();)
224: ((AbstractResultCacheEntry) i.next()).invalidate();
225: cacheEntries.clear();
226:
227: for (int i = 0; i < columns.size(); i++)
228: ((CacheDatabaseColumn) columns.get(i)).invalidateAll();
229: }
230: synchronized (pkCacheEntries) { // All pk cache entries have been invalidated as a side effect by the
231: // above loop.
232: pkCacheEntries.clear();
233: }
234: }
235:
236: /**
237: * Invalidates all cache entries of every column of this table. This does not
238: * affect the entries based on pk values.
239: */
240: public synchronized void invalidateAllExceptPk() {
241: for (Iterator i = cacheEntries.iterator(); i.hasNext();) {
242: AbstractResultCacheEntry qce = (AbstractResultCacheEntry) i
243: .next();
244: if (qce.getRequest().getCacheAbility() != RequestType.UNIQUE_CACHEABLE)
245: qce.invalidate();
246: }
247: cacheEntries.clear();
248: }
249:
250: /**
251: * Returns information about the database table and its columns.
252: *
253: * @param longFormat true for a long format, false for a short summary
254: * @return String
255: */
256: public String getInformation(boolean longFormat) {
257: String result = "Table " + name + ": ";
258: int size = columns.size();
259: for (int i = 0; i < size; i++) {
260: CacheDatabaseColumn c = (CacheDatabaseColumn) columns
261: .get(i);
262: if (longFormat)
263: result += "\n";
264: result += c.getInformation();
265: if (!longFormat && (i < size - 1))
266: result += ",";
267: }
268: return result;
269: }
270: }
|