001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.sql.framework.ui.model.impl;
042:
043: import java.awt.Point;
044: import java.io.StringReader;
045: import java.sql.Types;
046: import java.util.Collection;
047: import java.util.Collections;
048: import java.util.Iterator;
049: import java.util.List;
050: import java.util.Map;
051:
052: import org.netbeans.modules.sql.framework.model.DBColumn;
053: import org.netbeans.modules.sql.framework.common.utils.XmlUtil;
054: import org.netbeans.modules.sql.framework.model.GUIInfo;
055: import org.netbeans.modules.sql.framework.model.RuntimeDatabaseModel;
056: import org.netbeans.modules.sql.framework.model.RuntimeOutput;
057: import org.netbeans.modules.sql.framework.model.SQLCanvasObject;
058: import org.netbeans.modules.sql.framework.model.SQLCondition;
059: import org.netbeans.modules.sql.framework.model.SQLConnectableObject;
060: import org.netbeans.modules.sql.framework.model.SQLConstants;
061: import org.netbeans.modules.sql.framework.model.SQLDBModel;
062: import org.netbeans.modules.sql.framework.model.SQLDBTable;
063: import org.netbeans.modules.sql.framework.model.SQLDefinition;
064: import org.netbeans.modules.sql.framework.model.SQLFilter;
065: import org.netbeans.modules.sql.framework.model.SQLInputObject;
066: import org.netbeans.modules.sql.framework.model.SQLJoinView;
067: import org.netbeans.modules.sql.framework.model.SQLLiteral;
068: import org.netbeans.modules.sql.framework.model.SQLModelObjectFactory;
069: import org.netbeans.modules.sql.framework.model.SQLObject;
070: import org.netbeans.modules.sql.framework.model.SQLObjectFactory;
071: import org.netbeans.modules.sql.framework.model.SQLPredicate;
072: import org.netbeans.modules.sql.framework.model.SourceColumn;
073: import org.netbeans.modules.sql.framework.model.SourceTable;
074: import org.netbeans.modules.sql.framework.model.TargetColumn;
075: import org.netbeans.modules.sql.framework.model.TargetTable;
076: import org.netbeans.modules.sql.framework.model.VisibleSQLLiteral;
077: import org.netbeans.modules.sql.framework.model.VisibleSQLPredicate;
078: import org.netbeans.modules.sql.framework.model.utils.SQLObjectUtil;
079: import org.netbeans.modules.sql.framework.ui.event.SQLDataEvent;
080: import org.netbeans.modules.sql.framework.ui.event.SQLLinkEvent;
081: import org.netbeans.modules.sql.framework.ui.model.CollabSQLUIModel;
082: import net.java.hulp.i18n.Logger;
083: import com.sun.sql.framework.exception.BaseException;
084: import org.netbeans.modules.etl.logger.Localizer;
085: import org.netbeans.modules.etl.logger.LogUtil;
086: import org.netbeans.modules.sql.framework.model.DBTable;
087:
088: /**
089: * Concrete implementation of SQLBuilderModel for use in representing SQL object models.
090: *
091: * @author Ritesh Adval
092: */
093: public class CollabSQLUIModelImpl extends AbstractSQLModel implements
094: CollabSQLUIModel {
095:
096: private static final String LOG_CATEGORY = CollabSQLUIModelImpl.class
097: .getName();
098: private static transient final Logger mLogger = LogUtil
099: .getLogger(CollabSQLUIModelImpl.class.getName());
100: private static transient final Localizer mLoc = Localizer.get();
101: protected boolean isReloaded = false;
102: protected boolean restoring = false;
103: protected SQLDefinition sqlDefinition;
104:
105: public CollabSQLUIModelImpl() {
106: super ();
107: }
108:
109: // New
110: public CollabSQLUIModelImpl(String collaborationName) { // throws BaseException {
111: this ();
112: this .sqlDefinition = SQLModelObjectFactory.getInstance()
113: .createSQLDefinition(collaborationName);
114: sqlDefinition.addSQLObjectListener(this );
115: this .isReloaded = false;
116:
117: }
118:
119: public void addObject(SQLObject sqlObject) throws BaseException {
120: super .addObject(sqlObject);
121: addObjectIgnoreUndo(sqlObject);
122: }
123:
124: public void addObjectIgnoreUndo(SQLObject sqlObject)
125: throws BaseException {
126: if (sqlObject.getObjectType() == SQLConstants.TARGET_DBMODEL) {
127: addTargetTableRuntimeArg((SQLDBModel) sqlObject);
128: }
129:
130: addSQLObject(sqlObject);
131: if (sqlObject.getObjectType() == SQLConstants.VISIBLE_PREDICATE) {
132: createVisiblePredicateRefObj((VisibleSQLPredicate) sqlObject);
133: }
134: // first time when an source table is added we want to handle auto join
135: addObjectInGraph(sqlObject, true);
136: }
137:
138: /**
139: * Adds a SourceTableImpl instance using the given DBTable instance as a template, if
140: * it does not already exist.
141: *
142: * @param srcTable DBTable to serve as template for the new SourceTableImpl instance.
143: * @return new SourceTableImpl instance
144: * @throws BaseException if error occurs during creation
145: */
146: public SQLObject addSourceTable(DBTable srcTable, Point loc)
147: throws BaseException {
148: SourceTable impl = (SourceTable) sqlDefinition
149: .createObject(SQLConstants.STR_SOURCE_TABLE);
150: impl.copyFrom(srcTable);
151:
152: if (loc != null) {
153: impl.getGUIInfo().setAttribute(GUIInfo.ATTR_X,
154: new Integer(loc.x));
155: impl.getGUIInfo().setAttribute(GUIInfo.ATTR_Y,
156: new Integer(loc.y));
157: }
158:
159: addObject(impl);
160: return impl;
161: }
162:
163: public void addSQLObject(SQLObject sqlObject) throws BaseException {
164: sqlDefinition.addObject(sqlObject);
165: isDirty = true;
166: }
167:
168: /**
169: * Adds a TargetTableImpl instance using the given DBTable instance as a template, if
170: * it does not already exist.
171: *
172: * @param targetTable DBTable to serve as template for the new TargetTableImpl
173: * instance.
174: * @return SourceTableImpl representing the contents of the given template object; may
175: * be a pre-existing object.
176: * @throws BaseException if error occurs during creation
177: */
178: public SQLObject addTargetTable(DBTable targetTable, Point loc)
179: throws BaseException {
180: TargetTable impl = (TargetTable) sqlDefinition
181: .createObject(SQLConstants.STR_TARGET_TABLE);
182: impl.copyFrom(targetTable);
183:
184: if (loc != null) {
185: impl.getGUIInfo().setAttribute(GUIInfo.ATTR_X,
186: new Integer(loc.x));
187: impl.getGUIInfo().setAttribute(GUIInfo.ATTR_Y,
188: new Integer(loc.y));
189: }
190:
191: addObject(impl);
192:
193: addTargetTableRuntimeArg(impl);
194:
195: return impl;
196: }
197:
198: public SQLCanvasObject createObject(String className)
199: throws BaseException {
200: SQLObject sqlObj = SQLObjectFactory.createSQLObject(className);
201: return (SQLCanvasObject) sqlObj;
202: }
203:
204: /**
205: * Indicates whether the table represented by the given DBTable already exists in this
206: * model
207: *
208: * @param table DBTable whose existence is to be tested
209: * @return true if table (source or target) exists in the model, false otherwise
210: */
211: public boolean exists(DBTable table) {
212: List existingTables = Collections.EMPTY_LIST;
213: boolean doesExist = false;
214:
215: if (table != null) {
216: if (table instanceof SourceTable) {
217: existingTables = getSQLDefinition().getSourceTables();
218: } else if (table instanceof TargetTable) {
219: existingTables = getSQLDefinition().getTargetTables();
220: }
221:
222: Iterator it = existingTables.iterator();
223: while (it.hasNext()) {
224: DBTable existing = (DBTable) it.next();
225: if (existing.toString().equals(table.toString())) {
226: doesExist = true;
227: break;
228: }
229: }
230: }
231:
232: return doesExist;
233: }
234:
235: public SQLJoinView getJoinView(SourceTable sTable) {
236: Collection joinViews = this .getSQLDefinition()
237: .getObjectsOfType(SQLConstants.JOIN_VIEW);
238: Iterator it = joinViews.iterator();
239:
240: while (it.hasNext()) {
241: SQLJoinView joinView = (SQLJoinView) it.next();
242: if (joinView.containsSourceTable(sTable)) {
243: return joinView;
244: }
245: }
246:
247: return null;
248: }
249:
250: public RuntimeDatabaseModel getRuntimeDbModel() {
251: return sqlDefinition.getRuntimeDbModel();
252: }
253:
254: public SQLDefinition getSQLDefinition() {
255: return this .sqlDefinition;
256: }
257:
258: public boolean isDirty() {
259: return isDirty;
260: }
261:
262: public boolean isReloaded() {
263: return this .isReloaded;
264: }
265:
266: // reload
267: public void reLoad(String sqlDefinitionXml) throws BaseException {
268: // clear the listener
269: if (this .sqlDefinition != null) {
270: this .sqlDefinition.removeSQLObjectListener(this );
271: }
272:
273: this .sqlDefinition = SQLModelObjectFactory.getInstance()
274: .createSQLDefinition();
275: // register this as listener after this only parse it
276: sqlDefinition.addSQLObjectListener(this );
277: // then parse it
278: sqlDefinition.parseXML(XmlUtil.loadXMLFile(new StringReader(
279: sqlDefinitionXml)));
280: this .isReloaded = true;
281:
282: // when reloaded clear the listener list
283: listeners.clear();
284: }
285:
286: public void removeDanglingColumnReference(SourceColumn column)
287: throws BaseException {
288: removeDanglingColumnRefFromSourceTables(column);
289: removeDanglingColumnRefFromTargetTables(column);
290: }
291:
292: public void removeObject(SQLObject sqlObject) throws BaseException {
293: super .removeObject(sqlObject);
294: removeObjectIgnoreUndo(sqlObject);
295: }
296:
297: public void removeObjectIgnoreUndo(SQLObject sqlObject)
298: throws BaseException {
299: if (sqlObject.getObjectType() == SQLConstants.TARGET_TABLE) {
300: removeTargetTableRuntimeArg((TargetTable) sqlObject);
301: }
302:
303: sqlDefinition.removeObject(sqlObject);
304:
305: // delete dangling references
306: removeDanglingReferences(sqlObject);
307:
308: if (sqlObject instanceof SQLCanvasObject) {
309: SQLDataEvent evt = new SQLDataEvent(this ,
310: (SQLCanvasObject) sqlObject);
311: fireSQLDataDeletionEvent(evt);
312: isDirty = true;
313: }
314: }
315:
316: public void restoreLinks() {
317: // link all tables
318: List list = sqlDefinition.getTargetTables();
319: Iterator it = list.iterator();
320: while (it.hasNext()) {
321: SQLConnectableObject sqlExObj = (SQLConnectableObject) it
322: .next();
323: restoreLinks(sqlExObj);
324: }
325:
326: // restore link of runtimeoutput
327: RuntimeDatabaseModel runtimeModel = sqlDefinition
328: .getRuntimeDbModel();
329: if (runtimeModel != null) {
330: RuntimeOutput runtimeOutput = runtimeModel
331: .getRuntimeOutput();
332: if (runtimeOutput != null) {
333: restoreLinks(runtimeOutput);
334: }
335: }
336:
337: // now link other objects
338: Collection objectC = sqlDefinition.getAllObjects();
339: it = objectC.iterator();
340: while (it.hasNext()) {
341: SQLObject sqlObj = (SQLObject) it.next();
342: if (sqlObj instanceof SQLConnectableObject) {
343: restoreLinks((SQLConnectableObject) sqlObj);
344: }
345: }
346: isDirty = false;
347: }
348:
349: public void restoreObjects() throws BaseException {
350: Collection col = sqlDefinition.getAllObjects();
351: Iterator it = col.iterator();
352:
353: while (it.hasNext()) {
354: SQLObject sqlObj = (SQLObject) it.next();
355: try {
356: // reload time we do not want to handle auto join
357: addObjectInGraph(sqlObj, false);
358: } catch (BaseException e) {
359: mLogger
360: .errorNoloc(
361: mLoc
362: .t(
363: "PRSR142: Error caught while restoring object ({0})",
364: sqlObj.getDisplayName()),
365: e);
366: throw e;
367: }
368: }
369: isDirty = false;
370: }
371:
372: /**
373: * Rebuilds view model based on object pool and SQLDefinition hierarchy.
374: */
375: public synchronized void restoreUIState() throws BaseException {
376: try {
377: restoring = true;
378: restoreObjects();
379: restoreLinks();
380: } finally {
381: restoring = false;
382: }
383: }
384:
385: public void setDirty(boolean dirty) {
386: this .isDirty = dirty;
387: }
388:
389: public void setReloaded(boolean reloaded) {
390: this .isReloaded = reloaded;
391: }
392:
393: public void setSQLDefinition(SQLDefinition sqlDefinition) {
394: this .sqlDefinition = sqlDefinition;
395: }
396:
397: /**
398: * set it to true if a java operator is used in the model
399: *
400: * @param javaOp true if there is a java operator
401: */
402: void setContainsJavaOperators(boolean containsjavaOp) {
403: this .sqlDefinition.setContainsJavaOperators(containsjavaOp);
404: }
405:
406: protected void addObjectInGraph(SQLObject sqlObject,
407: boolean handleAutojoin) throws BaseException {
408: if (sqlObject instanceof SQLCanvasObject) {
409: SQLDataEvent evt = new SQLDataEvent(this ,
410: (SQLCanvasObject) sqlObject);
411: fireSQLDataCreationEvent(evt);
412: isDirty = true;
413: } else if (sqlObject.getObjectType() == SQLConstants.SOURCE_DBMODEL
414: || sqlObject.getObjectType() == SQLConstants.TARGET_DBMODEL
415: || sqlObject.getObjectType() == SQLConstants.RUNTIME_DBMODEL) {
416: createTablesInGraph((SQLDBModel) sqlObject);
417: }
418: }
419:
420: protected void addTargetTableRuntimeArg(TargetTable targetTable) {
421: RuntimeDatabaseModel runDbModel = this .getRuntimeDbModel();
422: RuntimeOutput rOutput = null;
423: if (runDbModel != null) {
424: rOutput = runDbModel.getRuntimeOutput();
425: }
426:
427: // If runtime output is null then it is not created in graph (it is added in
428: // graph only via TablePanel) so do not create target table runtime args, they
429: // will be added from TablePanel.
430: if (rOutput == null) {
431: return;
432: }
433:
434: // add Count_<Target_Table_Name> runtime output argument
435: String argName = SQLObjectUtil
436: .getTargetTableCountRuntimeOutput(targetTable);
437: DBColumn column = rOutput.getColumn(argName);
438: if (column == null) {
439: TargetColumn tColumn = SQLModelObjectFactory.getInstance()
440: .createTargetColumn(argName, Types.NUMERIC, 0, 0,
441: true);
442:
443: rOutput.addColumn(tColumn);
444:
445: // fire update event
446: SQLDataEvent evt = new SQLDataEvent(this , rOutput, tColumn);
447: fireChildObjectCreatedEvent(evt);
448: }
449: }
450:
451: protected SQLCanvasObject getTopSQLCanvasObject(SQLObject sqlObj) {
452: if (sqlObj instanceof SQLCanvasObject) {
453: return (SQLCanvasObject) sqlObj;
454: }
455:
456: Object parentObj = sqlObj.getParentObject();
457: while (parentObj != null && parentObj instanceof SQLObject
458: && !(parentObj instanceof SQLCanvasObject)) {
459: parentObj = ((SQLObject) parentObj).getParentObject();
460: }
461:
462: if (parentObj instanceof SQLCanvasObject) {
463: return (SQLCanvasObject) parentObj;
464: }
465:
466: return null;
467: }
468:
469: protected void restoreLinks(SQLConnectableObject sqlExObj) {
470: if (sqlExObj instanceof SQLFilter) {
471: return;
472: }
473:
474: Map inputMap = sqlExObj.getInputObjectMap();
475: Iterator it = inputMap.keySet().iterator();
476:
477: while (it.hasNext()) {
478: String argName = (String) it.next();
479: SQLInputObject inputObj = (SQLInputObject) inputMap
480: .get(argName);
481: if (inputObj == null) {
482: continue;
483: }
484:
485: SQLObject srcObj = inputObj.getSQLObject();
486: String srcFieldName = null;
487:
488: if (srcObj == null) {
489: continue;
490: }
491:
492: // TODO: Temporary check for instance of SQLLiteralImpl(but allow
493: // VisibleSQLLiteral)
494: // we need to fix this with Source and Target Column as SQLCanvasObject
495: // and no need to get top canvas object.
496: // if an input object is SQLCanvasObject just create SQLLinkEvent and
497: // link it. no need to pass srcFieldName and argName
498:
499: if (!(srcObj instanceof VisibleSQLLiteral)
500: && srcObj instanceof SQLLiteral) {
501: continue;
502: }
503:
504: srcFieldName = srcObj.getDisplayName();
505:
506: srcObj = getTopSQLCanvasObject(srcObj);
507: if (srcObj instanceof SQLCanvasObject) {
508:
509: SQLLinkEvent evt = new SQLLinkEvent(this ,
510: (SQLCanvasObject) srcObj, sqlExObj,
511: srcFieldName, argName);
512: fireSQLLinkCreationEvent(evt);
513:
514: if (srcObj instanceof SQLConnectableObject) {
515: restoreLinks((SQLConnectableObject) srcObj);
516: }
517: }
518: }
519:
520: // now restore child sql object links
521: List children = sqlExObj.getChildSQLObjects();
522: it = children.iterator();
523: while (it.hasNext()) {
524: SQLObject childObj = (SQLObject) it.next();
525: if (childObj instanceof SQLConnectableObject) {
526: restoreLinks((SQLConnectableObject) childObj);
527: }
528: }
529: }
530:
531: private void addTargetTableRuntimeArg(SQLDBModel targetDbModel) {
532: Iterator it = targetDbModel.getTables().iterator();
533: while (it.hasNext()) {
534: TargetTable tt = (TargetTable) it.next();
535: addTargetTableRuntimeArg(tt);
536: }
537: }
538:
539: private void createTablesInGraph(SQLDBModel dbModel)
540: throws BaseException {
541: Iterator it = dbModel.getTables().iterator();
542:
543: while (it.hasNext()) {
544: try {
545: addObjectInGraph((SQLDBTable) it.next(), false);
546: } catch (BaseException e) {
547: mLogger
548: .errorNoloc(
549: mLoc
550: .t(
551: "PRSR143: Error while adding table to canvas. ({0})",
552: LOG_CATEGORY), e);
553: throw e;
554: }
555: }
556: }
557:
558: private void removeDanglingColumnReference(SourceTable table)
559: throws BaseException {
560: List colList = table.getColumnList();
561: Iterator it = colList.iterator();
562:
563: while (it.hasNext()) {
564: SourceColumn column = (SourceColumn) it.next();
565: removeDanglingColumnReference(column);
566: }
567: }
568:
569: private void removeDanglingColumnRefFromSourceTables(
570: SourceColumn column) throws BaseException {
571: List sTables = sqlDefinition.getSourceTables();
572: Iterator it = sTables.iterator();
573:
574: while (it.hasNext()) {
575: SourceTable sTable = (SourceTable) it.next();
576: // remove from extraction condition
577: SQLCondition cond = sTable.getExtractionCondition();
578: if (cond != null) {
579: cond.removeDanglingColumnRef(column);
580: }
581: }
582: }
583:
584: private void removeDanglingColumnRefFromTargetTables(
585: SourceColumn column) throws BaseException {
586: List sTables = sqlDefinition.getTargetTables();
587: Iterator it = sTables.iterator();
588:
589: while (it.hasNext()) {
590: TargetTable sTable = (TargetTable) it.next();
591: SQLCondition cond = sTable.getJoinCondition();
592: if (cond != null) {
593: cond.removeDanglingColumnRef(column);
594: }
595:
596: SQLCondition fcond = sTable.getFilterCondition();
597: if (fcond != null) {
598: fcond.removeDanglingColumnRef(column);
599: }
600: }
601: }
602:
603: private void removeDanglingReferences(SQLObject sqlObject)
604: throws BaseException {
605: int objType = sqlObject.getObjectType();
606: switch (objType) {
607: case SQLConstants.VISIBLE_PREDICATE:
608: removeVisiblePredicateRefObj((VisibleSQLPredicate) sqlObject);
609: break;
610: case SQLConstants.SOURCE_TABLE:
611: case SQLConstants.RUNTIME_INPUT:
612: removeDanglingColumnReference((SourceTable) sqlObject);
613: break;
614:
615: case SQLConstants.JOIN_VIEW:
616: SQLJoinView joinView = (SQLJoinView) sqlObject;
617: Iterator it = joinView.getSourceTables().iterator();
618: while (it.hasNext()) {
619: SQLObject sTable = (SQLObject) it.next();
620: removeDanglingReferences(sTable);
621: }
622: break;
623: }
624: }
625:
626: private void removeTargetTableRuntimeArg(TargetTable targetTable) {
627: // remove Count_<Target_Table_Name> runtime output argument
628: String argName = SQLObjectUtil
629: .getTargetTableCountRuntimeOutput(targetTable);
630:
631: RuntimeDatabaseModel runDbModel = this .getRuntimeDbModel();
632: RuntimeOutput rOutput = null;
633: if (runDbModel != null) {
634: rOutput = runDbModel.getRuntimeOutput();
635: }
636: if (rOutput == null) {
637: return;
638: }
639:
640: DBColumn column = rOutput.getColumn(argName);
641: if (column != null) {
642: ((SQLDBTable) rOutput).deleteColumn(argName);
643:
644: // fire update event
645: SQLDataEvent evt = new SQLDataEvent(this , rOutput,
646: (SQLObject) column);
647: fireChildObjectDeletedEvent(evt);
648: }
649: }
650:
651: private void removeVisiblePredicateRefObj(
652: VisibleSQLPredicate predicate) throws BaseException {
653: String newOperator = predicate.getOperatorType();
654: // FIXME: this check is very weak and may fail if string changes
655: // migrate this change
656: if (newOperator.equalsIgnoreCase("IS")
657: || newOperator.equalsIgnoreCase("IS NOT")) {
658: SQLLiteral nullLiteral = (SQLLiteral) predicate
659: .getSQLObject(SQLPredicate.RIGHT);
660: if (nullLiteral != null) {
661: this.removeObject(nullLiteral);
662: }
663: }
664: }
665: }
|