001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019: package org.netbeans.modules.etl.codegen;
020:
021: import java.util.Iterator;
022: import java.util.List;
023: import org.netbeans.modules.etl.codegen.impl.OnePassETLStrategyBuilderImpl;
024: import org.netbeans.modules.etl.codegen.impl.PipelinedStrategyBuilderImpl;
025: import org.netbeans.modules.etl.codegen.impl.SimpleETLStrategyBuilderImpl;
026: import org.netbeans.modules.etl.codegen.impl.StagingStrategyBuilder;
027: import org.netbeans.modules.etl.codegen.impl.ValidatingStrategyBuilderImpl;
028: import org.netbeans.modules.sql.framework.model.SQLConstants;
029: import org.netbeans.modules.sql.framework.model.SQLDefinition;
030: import org.netbeans.modules.sql.framework.model.TargetTable;
031: import com.sun.sql.framework.exception.BaseException;
032: import com.sun.sql.framework.utils.StringUtil;
033: import net.java.hulp.i18n.Logger;
034: import org.netbeans.modules.etl.logger.Localizer;
035: import org.netbeans.modules.etl.logger.LogUtil;
036: import org.netbeans.modules.sql.framework.model.DBConnectionDefinition;
037: import org.netbeans.modules.sql.framework.model.DBTable;
038:
039: /**
040: * Factory for ETLStrategyBuilder. Based a matching pattern I will create an appropriate
041: * ETLStrategyBuilder. This allow us to optimize the ETL process based on a given
042: * situation.
043: *
044: * @author Ahimanikya Satapathy
045: * @author Jonathan Giron
046: * @author Girish Patil
047: * @version $Revision$
048: */
049: public class PatternFinder {
050:
051: private static transient final Logger mLogger = LogUtil
052: .getLogger(PatternFinder.class.getName());
053: private static transient final Localizer mLoc = Localizer.get();
054:
055: public static boolean allDBTablesAreInternal(Iterator tableIterator)
056: throws BaseException {
057: while (tableIterator.hasNext()) {
058: DBTable srcTable = (DBTable) tableIterator.next();
059: // as soon as you find a non-axion db , return false.
060: if (!isInternalDBTable(srcTable)) {
061: return false;
062: }
063: }
064: return true;
065: }
066:
067: public static ETLStrategyBuilder createETLStrategyBuilder(
068: TargetTable tt, ETLScriptBuilderModel model)
069: throws BaseException {
070: // Optimization: Depending on the pattern decide which strategy to use
071: List sourceTables = tt.getSourceTableList();
072: ETLStrategyBuilder builder = null;
073: SQLDefinition definition = model.getSqlDefinition();
074: int strategyOverride = SQLDefinition.EXECUTION_STRATEGY_BEST_FIT;
075: strategyOverride = definition.getExecutionStrategyCode()
076: .intValue();
077:
078: if (strategyOverride == SQLDefinition.EXECUTION_STRATEGY_PIPELINE) {
079: // Force pipeline execution
080: builder = (definition.hasValidationConditions()) ? new ValidatingStrategyBuilderImpl(
081: model)
082: : new PipelinedStrategyBuilderImpl(model);
083: } else if (strategyOverride == SQLDefinition.EXECUTION_STRATEGY_STAGING) {
084: if (definition.requiresPipelineProcess()) {
085: String nbBundle1 = mLoc
086: .t("PRSR001: Cannot execute in Staging mode, choose Best-fit or Pipeline.");
087: String desc = Localizer.parse(nbBundle1);
088: throw new BaseException(desc);
089: }
090:
091: if (PatternFinder
092: .isSourceAndTargetAreInternalButDifferent(definition)) {
093: String nbBundle2 = mLoc
094: .t("PRSR001: Cannot execute in Staging mode, choose Best-fit or Pipeline.");
095: String desc = Localizer.parse(nbBundle2);
096: throw new BaseException(desc);
097: }
098:
099: if (isInternalDBTable(tt)
100: && allDBTablesAreInternal(sourceTables.iterator())) {
101: String nbBundle3 = mLoc
102: .t("PRSR001: Cannot execute in Staging mode, choose Best-fit or Pipeline.");
103: String desc = Localizer.parse(nbBundle3);
104: throw new BaseException(desc);
105: }
106:
107: // Extract and execute at target
108: StagingStrategyBuilder stgBuilder = new StagingStrategyBuilder(
109: model);
110: stgBuilder.setForceStaging(true);
111: builder = stgBuilder;
112: } else {
113: // strategyOverride == SQLDefinition.EXECUTION_STRATEGY_BEST_FIT
114: if (definition.requiresPipelineProcess()) {
115: builder = (definition.hasValidationConditions()) ? new ValidatingStrategyBuilderImpl(
116: model)
117: : new PipelinedStrategyBuilderImpl(model);
118: } else if (isInternalDBTable(tt)
119: && allDBTablesAreInternal(sourceTables.iterator())) {
120: builder = new SimpleETLStrategyBuilderImpl(model);
121: } else if (isSourceTargetFromSameDB(sourceTables, tt, model)) {
122: // If Source(s) and Target are both from the same DB
123: builder = new SimpleETLStrategyBuilderImpl(model);
124: } else if (isSameDBTables(sourceTables.iterator(), model)
125: && tt.getStatementType() == SQLConstants.INSERT_STATEMENT
126: && (!tt.getJoinCondition().isConditionDefined())
127: && (!tt.getFilterCondition().isConditionDefined())) {
128: // If all source table are from same DB and statement type is Insert
129: //builder = new OnePassETLStrategyBuilderImpl();
130: builder = new OnePassETLStrategyBuilderImpl(model);
131: } else {
132: // Default strategy
133: builder = new StagingStrategyBuilder(model);
134: }
135: }
136:
137: return builder;
138: }
139:
140: /**
141: * @param sqlDefinition
142: * @return
143: */
144: public static boolean hasAllInternalDBTables(
145: SQLDefinition sqlDefinition) throws BaseException {
146: List targetTables = sqlDefinition.getTargetTables();
147: Iterator iter = targetTables.iterator();
148: while (iter.hasNext()) {
149: TargetTable tt = (TargetTable) iter.next();
150: if (!isInternalDBTable(tt)) {
151: return false;
152: }
153:
154: Iterator srcIter = tt.getSourceTableList().iterator();
155: if (!allDBTablesAreInternal(srcIter)) {
156: return false;
157: }
158: }
159:
160: return true;
161: }
162:
163: public static boolean isFromSameDB(DBTable table1, DBTable table2,
164: ETLScriptBuilderModel model) throws BaseException {
165: DBConnectionDefinition conDef1 = model
166: .getConnectionDefinition(table1);
167: DBConnectionDefinition conDef2 = model
168: .getConnectionDefinition(table2);
169: return isIdenticalDBConDef(conDef1, conDef2);
170: }
171:
172: public static boolean isInternalDBConnection(
173: DBConnectionDefinition dbConnDef) {
174: boolean ret = false;
175: if (dbConnDef != null) {
176: if (dbConnDef.getDBType().equalsIgnoreCase("AXION")
177: || dbConnDef.getDBType().equalsIgnoreCase(
178: "Internal")) {
179: ret = true;
180: }
181: }
182: return ret;
183: }
184:
185: public static boolean isInternalDBTable(DBTable table)
186: throws BaseException {
187: DBConnectionDefinition newConDef = table.getParent()
188: .getConnectionDefinition();
189: if (newConDef == null) {
190: throw new BaseException(
191: "DBConnectionDefinition is null for Table: "
192: + table.getName());
193: }
194: return isInternalDBConnection(newConDef);
195: }
196:
197: /**
198: * @param sqlDefinition
199: * @return true only if Target is internal and All its source are also internal but
200: * belong to database other than Target Table's.
201: * @throws BaseException
202: */
203: public static boolean isSourceAndTargetAreInternalButDifferent(
204: SQLDefinition sqlDefinition) throws BaseException {
205: boolean ret = false;
206: boolean internalTargetTableFound = false;
207: boolean allSourcesInternal = false;
208: boolean dbDifferent = false;
209:
210: List targetTables = sqlDefinition.getTargetTables();
211: Iterator ttIter = targetTables.iterator();
212: Iterator srcIter = null;
213: DBConnectionDefinition tgtConnDef = null;
214: DBConnectionDefinition srcConnDef = null;
215:
216: while (ttIter.hasNext()) {
217: TargetTable tt = (TargetTable) ttIter.next();
218: tgtConnDef = tt.getParent().getConnectionDefinition();
219:
220: internalTargetTableFound = false;
221: allSourcesInternal = false;
222:
223: if (isInternalDBConnection(tgtConnDef)) {
224: internalTargetTableFound = true;
225: allSourcesInternal = true;
226: dbDifferent = false;
227:
228: srcIter = tt.getSourceTableList().iterator();
229: while (srcIter.hasNext()) {
230: DBTable srcTable = (DBTable) srcIter.next();
231: srcConnDef = srcTable.getParent()
232: .getConnectionDefinition();
233: if (isInternalDBConnection(srcConnDef)) {
234: if (!isIdenticalDBConDef(srcConnDef, tgtConnDef)) {
235: dbDifferent = true;
236: }
237: } else {
238: allSourcesInternal = false;
239: break;
240: }
241: }
242:
243: if (internalTargetTableFound && allSourcesInternal
244: && dbDifferent) {
245: ret = true;
246: break;
247: }
248: }
249: }
250:
251: return ret;
252: }
253:
254: // This will ignore the optional attribute "AlternateId" for datadirect db2 url
255: private static String ignoreOptional(String url) {
256: int start = url.toUpperCase().indexOf("ALTERNATEID");
257: if (start != -1) {
258: int end = url.indexOf(';', start);
259: StringBuilder buf = new StringBuilder(60);
260: buf.append(url.substring(0, start));
261: if (end != -1) {
262: buf.append(url.substring(end + 1));
263: }
264: return buf.toString();
265: } else {
266: return url;
267: }
268: }
269:
270: private static boolean isIdenticalDBConDef(
271: DBConnectionDefinition c1, DBConnectionDefinition c2) {
272: boolean identical = false;
273:
274: if (c1 != null && c2 != null) {
275: identical = StringUtil.isIdenticalIgnoreCase(
276: ignoreOptional(c1.getConnectionURL()),
277: ignoreOptional(c2.getConnectionURL()))
278: && StringUtil.isIdentical(c1.getUserName(), c2
279: .getUserName())
280: && StringUtil.isIdentical(c1.getPassword(), c2
281: .getPassword());
282: }
283: return identical;
284: }
285:
286: private static boolean isSameDBTables(Iterator tableIterator,
287: ETLScriptBuilderModel model) throws BaseException {
288: DBConnectionDefinition conDef = null;
289: while (tableIterator.hasNext()) {
290: DBTable srcTable = (DBTable) tableIterator.next();
291: DBConnectionDefinition newConDef = model
292: .getConnectionDefinition(srcTable);
293:
294: if (newConDef == null) {
295: throw new BaseException(
296: "DBConnectionDefinition is null for Source Table: "
297: + srcTable.getName());
298: }
299:
300: if (conDef == null) {
301: conDef = newConDef;
302: } else if (!isIdenticalDBConDef(conDef, newConDef)) {
303: // as soon as you find a diff db , return false.
304: return false;
305: }
306: }
307: return true;
308: }
309:
310: private static boolean isSourceTargetFromSameDB(List srcTableList,
311: DBTable trgtTable, ETLScriptBuilderModel model)
312: throws BaseException {
313: // Make sure all tables in list are themselves from the same DB.
314: if (!isSameDBTables(srcTableList.iterator(), model)) {
315: return false;
316: }
317:
318: if (srcTableList == null || srcTableList.isEmpty()) {
319: // There is no source table, so we don't need to build extractor:
320: // use the default strategy
321: return true;
322: }
323:
324: // Get the first source table and compare its DB against that of the target table
325: DBTable srcTable = (DBTable) srcTableList.get(0);
326: return isFromSameDB(srcTable, trgtTable, model);
327: }
328: }
|