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.model.impl;
042:
043: import java.util.Iterator;
044: import java.util.List;
045:
046: import org.netbeans.modules.sql.framework.common.utils.TagParserUtility;
047: import org.netbeans.modules.sql.framework.codegen.SQLOperatorFactory;
048: import org.netbeans.modules.sql.framework.model.SQLConstants;
049: import org.netbeans.modules.sql.framework.model.SQLInputObject;
050: import org.netbeans.modules.sql.framework.model.SQLLiteral;
051: import org.netbeans.modules.sql.framework.model.SQLObject;
052: import org.netbeans.modules.sql.framework.model.SQLOperator;
053: import org.netbeans.modules.sql.framework.model.SQLOperatorArg;
054: import org.netbeans.modules.sql.framework.model.SQLOperatorDefinition;
055: import org.netbeans.modules.sql.framework.model.SQLPredicate;
056: import org.netbeans.modules.sql.framework.model.utils.GeneratorUtil;
057: import org.netbeans.modules.sql.framework.model.utils.OperatorUtil;
058: import org.netbeans.modules.sql.framework.model.visitors.SQLVisitor;
059: import org.netbeans.modules.sql.framework.ui.graph.IOperatorField;
060: import org.netbeans.modules.sql.framework.ui.graph.IOperatorXmlInfo;
061: import org.w3c.dom.Element;
062: import org.w3c.dom.NodeList;
063:
064: import com.sun.sql.framework.exception.BaseException;
065: import com.sun.sql.framework.utils.Attribute;
066:
067: /**
068: * Represents boolean conditional expressions for join, case, etc.,
069: *
070: * @author Ritesh Adval, Sudhi Seshachala
071: * @version $Revision$
072: */
073: public class SQLPredicateImpl extends SQLConnectableObjectImpl
074: implements SQLPredicate {
075:
076: /** Reference to left-most predicate, if any (for composite predicates) */
077: protected SQLPredicate leftMost = null;
078:
079: protected SQLOperatorDefinition operatorDefinition;
080:
081: protected IOperatorXmlInfo operatorXmlInfo;
082:
083: /** Parent of this predicate (can be null or another predicate) */
084: protected SQLPredicate root = null;
085:
086: /** Creates a new instance of SQLPredicate */
087: public SQLPredicateImpl() {
088: super ();
089: type = SQLConstants.PREDICATE;
090: }
091:
092: public SQLPredicateImpl(SQLPredicate src) throws BaseException {
093: this ();
094: if (src == null) {
095: throw new IllegalArgumentException(
096: "can not create SQLPredicate using copy constructor, src is null");
097: }
098:
099: copyFrom(src);
100: }
101:
102: /**
103: * @see org.netbeans.modules.sql.framework.model.SQLConnectableObject#addInput
104: */
105: public void addInput(String argName, SQLObject newInput)
106: throws BaseException {
107: if (argName == null || newInput == null) {
108: throw new BaseException("Input arguments not specified");
109: }
110:
111: int newType = newInput.getObjectType();
112: String objType = TagParserUtility.getDisplayStringFor(newType);
113:
114: if (isInputCompatible(argName, newInput) == SQLConstants.TYPE_CHECK_INCOMPATIBLE) {
115: throw new BaseException("Input type " + objType
116: + " is incompatible with input argument '"
117: + argName + "'.");
118: }
119:
120: if (isInputValid(argName, newInput)) {
121: switch (newType) {
122: case SQLConstants.PREDICATE:
123: case SQLConstants.VISIBLE_PREDICATE:
124: ((SQLPredicate) newInput).setRoot(this );
125: // Fall through to next group.
126:
127: case SQLConstants.GENERIC_OPERATOR:
128: case SQLConstants.CUSTOM_OPERATOR:
129: case SQLConstants.LITERAL:
130: case SQLConstants.VISIBLE_LITERAL:
131: case SQLConstants.CASE:
132: case SQLConstants.SOURCE_COLUMN:
133: case SQLConstants.TARGET_COLUMN:
134: case SQLConstants.CAST_OPERATOR:
135: case SQLConstants.DATE_DIFF_OPERATOR:
136: case SQLConstants.DATE_ADD_OPERATOR:
137: case SQLConstants.COLUMN_REF:
138: SQLInputObject inputObject = (SQLInputObject) this .inputMap
139: .get(argName);
140: if (inputObject != null) {
141: inputObject.setSQLObject(newInput);
142: } else {
143: throw new BaseException("Input with argName '"
144: + argName + "' does not exist.");
145: }
146:
147: break;
148:
149: default:
150: throw new BaseException("Cannot link "
151: + objType
152: + " '"
153: + newInput.getDisplayName()
154: + "' as input to '"
155: + argName
156: + "' in "
157: + TagParserUtility
158: .getDisplayStringFor(this .type) + " '"
159: + this .getDisplayName() + "'");
160: }
161: } else {
162: throw new BaseException("Cannot link " + objType + " '"
163: + newInput.getDisplayName() + "' as input to '"
164: + argName + "' in "
165: + TagParserUtility.getDisplayStringFor(this .type)
166: + " '" + this .getDisplayName() + "'");
167: }
168: }
169:
170: public Object clone() throws CloneNotSupportedException {
171: try {
172: SQLPredicateImpl predicate = new SQLPredicateImpl(this );
173: return predicate;
174: } catch (BaseException ex) {
175: throw new CloneNotSupportedException(
176: "can not create clone of " + this .getOperatorType());
177: }
178: }
179:
180: public void copyFrom(SQLPredicate src) throws BaseException {
181: // Must establish input objects via OperatorXmlInfo before we can call
182: // super.copyFromSource() to populate them with cloned SQLObject inputs.
183: this .operatorDefinition = src.getOperatorDefinition();
184: this .setOperatorXmlInfo(src.getOperatorXmlInfo());
185:
186: super .copyFromSource(src);
187:
188: // we do not clone root as it must be set outside to build this tree
189: if (src.getRoot() != null) {
190: this .root = src.getRoot();
191: }
192: }
193:
194: /**
195: * @see java.lang.Object#equals
196: */
197: public boolean equals(Object refObj) {
198: // TODO: Need to refactor class and Interface hierarchy, such that we should be
199: // using Interface more then actual implemetation classes in referring classes.
200: if (!(refObj instanceof SQLPredicateImpl)) {
201: return false;
202: }
203:
204: SQLPredicateImpl predicate = (SQLPredicateImpl) refObj;
205:
206: // check if predicate has same operator
207: String myOp = getOperatorType();
208: String refOp = predicate.getOperatorType();
209: boolean response = (myOp != null) ? (myOp.equals(refOp))
210: : (refOp == null);
211:
212: SQLPredicate this Pred = this .getLeftMostPredicate();
213: SQLPredicate refPred = predicate.getLeftMostPredicate();
214:
215: if ((this Pred != this ) && (refPred != predicate)) {
216: response &= (this Pred != null) ? (this Pred.equals(refPred))
217: : (refPred == null);
218: }
219:
220: return response && super .equals(refObj);
221: }
222:
223: public Object getArgumentValue(String argName) throws BaseException {
224: return this .getSQLObject(argName);
225: }
226:
227: public String getCustomOperatorName() {
228: return this .displayName;
229: }
230:
231: public String getDisplayName() {
232: String dName = super .getDisplayName();
233: if (dName == null) {
234: return this .getOperatorType();
235: }
236:
237: return dName;
238: }
239:
240: /**
241: * @see org.netbeans.modules.sql.framework.model.SQLOperator#getOperatorDefinition()
242: */
243: public SQLOperatorDefinition getOperatorDefinition() {
244: return operatorDefinition;
245: }
246:
247: /**
248: * @see org.netbeans.modules.sql.framework.model.SQLGenericOperator#getOperatorType(java.lang.String)
249: */
250: public String getOperatorType() {
251: if (operatorDefinition != null) {
252: return operatorDefinition.getOperatorName();
253: }
254:
255: Attribute attr = getAttribute(SQLOperator.ATTR_SCRIPTREF);
256: return (attr != null) ? attr.getAttributeValue().toString()
257: : null;
258: }
259:
260: /**
261: * @see org.netbeans.modules.sql.framework.model.SQLOperator#getOperatorXmlInfo()
262: */
263: public IOperatorXmlInfo getOperatorXmlInfo() {
264: return operatorXmlInfo;
265: }
266:
267: /**
268: * method getRoot gets the root SQLPredicate.
269: *
270: * @return SQLPredicate of the root.
271: */
272: public SQLPredicate getRoot() {
273: return (this .root);
274: }
275:
276: /**
277: * @see java.lang.Object#hashCode
278: */
279: public int hashCode() {
280: int myHash = super .hashCode();
281: myHash += (getOperatorType() != null) ? getOperatorType()
282: .hashCode() : 0;
283:
284: // Avoid infinite recursion if this predicate (erroneously) references
285: // itself.
286: Object left = this .getLeftMostPredicate();
287: if (left != null && this != left) {
288: myHash += left.hashCode();
289: }
290: return myHash;
291: }
292:
293: public boolean isCustomOperator() {
294: return false;
295: }
296:
297: /**
298: * @see org.netbeans.modules.sql.framework.model.SQLConnectableObject
299: */
300: public int isInputCompatible(String argName, SQLObject input) {
301: String operator = this .getOperatorType();
302: // if operator is not AND or OR and we are trying to add another
303: // predicate which is not AND or OR (which may be one of < , > etc)
304: // then it is not compatible
305: // ex - to disallow link a < to a < predicate
306: if (!isGroupPredicate(operator)
307: && (input instanceof SQLPredicate)) {
308: // if input is a predicate then disallow
309: return SQLConstants.TYPE_CHECK_INCOMPATIBLE;
310:
311: } else if (isGroupPredicate(operator)
312: && !(input instanceof SQLPredicate)) {
313: // if this is a group predicate then we should not allow non comparison
314: // inputs
315: return SQLConstants.TYPE_CHECK_INCOMPATIBLE;
316: }
317:
318: return SQLConstants.TYPE_CHECK_COMPATIBLE;
319: }
320:
321: /**
322: * @see org.netbeans.modules.sql.framework.model.SQLConnectableObject#isInputStatic(java.lang.String)
323: */
324: public boolean isInputStatic(String argName) {
325: IOperatorXmlInfo xmlInfo = getOperatorXmlInfo();
326: if (xmlInfo != null && argName != null) {
327: IOperatorField field = xmlInfo.getInputField(argName);
328: if (field != null) {
329: return field.isStatic();
330: }
331: }
332: return false;
333: }
334:
335: /**
336: * @see org.netbeans.modules.sql.framework.model.SQLConnectableObject#isInputValid
337: */
338: public boolean isInputValid(String argName, SQLObject input) {
339: if (input == null) {
340: return false;
341: }
342:
343: switch (input.getObjectType()) {
344: case SQLConstants.PREDICATE:
345: case SQLConstants.VISIBLE_PREDICATE:
346: case SQLConstants.GENERIC_OPERATOR:
347: case SQLConstants.CUSTOM_OPERATOR:
348: case SQLConstants.CAST_OPERATOR:
349: case SQLConstants.DATE_DIFF_OPERATOR:
350: case SQLConstants.DATE_ADD_OPERATOR:
351: case SQLConstants.VISIBLE_LITERAL:
352: case SQLConstants.CASE:
353: case SQLConstants.SOURCE_COLUMN:
354: case SQLConstants.TARGET_COLUMN:
355: case SQLConstants.LITERAL:
356: case SQLConstants.COLUMN_REF:
357: return true;
358:
359: default:
360: return false;
361: }
362: }
363:
364: /**
365: * check if open and close parenthesis should be used
366: *
367: * @return bool
368: */
369: public boolean isShowParenthesis() {
370: Boolean paran = (Boolean) getAttributeObject(ATTR_PARENTHESIS);
371:
372: if (paran != null) {
373: return paran.booleanValue();
374: }
375:
376: return true;
377: }
378:
379: /**
380: * Parses the given XML element to populate content of this instance.
381: *
382: * @param xmlElement Element to be parsed
383: * @exception BaseException thropwn while parsing
384: */
385: public void parseXML(Element xmlElement) throws BaseException {
386: parseCommonFields(xmlElement);
387: NodeList inputArgList = xmlElement
388: .getElementsByTagName(SQLObject.TAG_INPUT);
389: TagParserUtility.parseInputTagList(this , inputArgList);
390: }
391:
392: /**
393: * @see org.netbeans.modules.sql.framework.model.SQLConnectableObject#removeInputByArgName
394: */
395: public SQLObject removeInputByArgName(String argName,
396: SQLObject sqlObj) throws BaseException {
397: // make sure root predicate is null out for input
398: if (sqlObj instanceof SQLPredicate) {
399: ((SQLPredicate) sqlObj).setRoot(null);
400: }
401:
402: return super .removeInputByArgName(argName, sqlObj);
403: }
404:
405: /**
406: * @see org.netbeans.modules.sql.framework.model.impl.AbstractSQLObject#secondPassParse
407: */
408: public void secondPassParse(Element element) throws BaseException {
409: TagParserUtility.parseInputTag(this , element);
410: }
411:
412: public void setArgument(String argName, Object val)
413: throws BaseException {
414: if (val instanceof String) {
415: String strVal = (String) val;
416: int argJdbc = this .operatorDefinition
417: .getArgJdbcSQLType(argName);
418: SQLLiteral literal = new SQLLiteralImpl(strVal, strVal,
419: argJdbc);
420: this .addInput(argName, literal);
421: } else if (val instanceof SQLObject) {
422: this .addInput(argName, (SQLObject) val);
423: } else {
424: throw new BaseException("Can not set argument, object "
425: + val + "is not a valid SQLObject");
426: }
427:
428: }
429:
430: public void setArguments(List opArgs) throws BaseException {
431: if (operatorDefinition == null) {
432: throw new BaseException("Operator Definition is null.");
433: }
434:
435: if (opArgs != null) {
436: // now add inputs from the argument list
437: Iterator it = opArgs.iterator();
438: int argIdx = 0;
439: while (it.hasNext()) {
440: SQLObject argValue = (SQLObject) it.next();
441: SQLOperatorArg operatorArg = operatorDefinition
442: .getOperatorArg(argIdx);
443: String argName = operatorArg.getArgName();
444: setArgument(argName, argValue);
445: argIdx++;
446: }
447: }
448:
449: }
450:
451: public void setCustomOperator(boolean userFx) {
452: throw new UnsupportedOperationException(
453: "Not a user specific function");
454: }
455:
456: public void setCustomOperatorName(String userFxName) {
457: throw new UnsupportedOperationException(
458: "Not a user specific function");
459: }
460:
461: public void setDbSpecificOperator(String dbSpName)
462: throws BaseException {
463: // first try all lower case
464: String cdbSpName = dbSpName.toLowerCase();
465: operatorDefinition = SQLOperatorFactory.getDefault()
466: .getDbSpecficOperatorDefinition(dbSpName);
467: if (operatorDefinition == null) {
468: // now try upper case
469: cdbSpName = dbSpName.toUpperCase();
470: operatorDefinition = SQLOperatorFactory.getDefault()
471: .getDbSpecficOperatorDefinition(cdbSpName);
472: // if it is still null then throw exception
473: if (operatorDefinition == null) {
474: throw new BaseException(dbSpName
475: + " is not a recognized operator.");
476: }
477: }
478:
479: // set IOperatorXmlInfo
480: IOperatorXmlInfo operatorXml = OperatorUtil
481: .findOperatorXmlInfo(operatorDefinition
482: .getOperatorName());
483: if (operatorXml != null) {
484: this .setOperatorXmlInfo(operatorXml);
485: } else {
486: throw new BaseException(
487: "Cannot locate definition for operator "
488: + operatorDefinition.getOperatorName());
489: }
490: }
491:
492: /**
493: * @see org.netbeans.modules.sql.framework.model.SQLGenericOperator#setOperatorType(java.lang.String)
494: */
495: public void setOperatorType(String opName) throws BaseException {
496: IOperatorXmlInfo operatorXml = OperatorUtil
497: .findOperatorXmlInfo(opName);
498: if (operatorXml != null) {
499: this .setOperatorXmlInfo(operatorXml);
500: } else {
501: throw new BaseException(
502: "Cannot locate definition for operator " + opName);
503: }
504: }
505:
506: /**
507: * @see org.netbeans.modules.sql.framework.model.SQLOperator#setOperatorXmlInfo(org.netbeans.modules.sql.framework.ui.graph.IOperatorXmlInfo)
508: */
509: public void setOperatorXmlInfo(IOperatorXmlInfo opInfo)
510: throws BaseException {
511: this .operatorXmlInfo = opInfo;
512: String aType = opInfo.getName();
513: setAttribute(SQLOperator.ATTR_SCRIPTREF, aType);
514: operatorDefinition = SQLOperatorFactory.getDefault()
515: .getSQLOperatorDefinition(aType);
516: if (operatorDefinition == null) {
517: throw new BaseException(aType
518: + " is not a recognized operator.");
519: }
520:
521: int argCount = operatorDefinition.getArgCount();
522: init(argCount);
523: }
524:
525: /**
526: * method setRoot sets the root SQLPredicate.
527: *
528: * @param pred is the SQLPredicate of the new root.
529: */
530: public void setRoot(SQLPredicate pred) {
531: this .root = pred;
532: }
533:
534: /**
535: * set to true if parenthesis needs to be appended
536: *
537: * @param show bool
538: */
539: public void setShowParenthesis(boolean show) {
540: setAttribute(ATTR_PARENTHESIS, new Boolean(show));
541: }
542:
543: public String toString() {
544: String str = super .toString();
545:
546: try {
547: GeneratorUtil eval = GeneratorUtil.getInstance();
548: eval.setTableAliasUsed(true);
549: str = eval.getEvaluatedString(this );
550: eval.setTableAliasUsed(false);
551: } catch (BaseException ignore) {
552: // ignore
553: }
554: return str;
555: }
556:
557: public void visit(SQLVisitor visitor) {
558: visitor.visit(this );
559: }
560:
561: /**
562: * Gets leftmost predicate, if any, in composite predicate hierarchy of which this
563: * instance is a part.
564: *
565: * @return leftmost SQLPredicate instance
566: */
567: protected SQLPredicate getLeftMostPredicate() {
568: SQLPredicate ret = getLeftMostPredicate(this );
569: if (ret == null) {
570: return (this );
571: }
572: return (ret);
573: }
574:
575: /**
576: * Gets leftmost predicate of either (1) this instance or (2) the given predicate
577: * instance.
578: *
579: * @param pred SQLPredicate which may be searched for its leftmost predicate if this
580: * instance has no leftmost predicate.
581: * @return leftmost predicate of either this instance or pred
582: */
583: protected SQLPredicate getLeftMostPredicate(SQLPredicate pred) {
584: SQLPredicate newReturnPred = null;
585:
586: if (pred == null) {
587: return null;
588: }
589:
590: SQLInputObject inObj = getInput(LEFT);
591: SQLObject leftObj = null;
592:
593: if (inObj != null) {
594: leftObj = inObj.getSQLObject();
595: }
596:
597: if (leftObj != null && (leftObj instanceof SQLPredicate)) {
598: SQLObject sqlObj = null;
599: if (pred.getInput(LEFT) != null) {
600: sqlObj = pred.getInput(LEFT).getSQLObject();
601: }
602:
603: if (sqlObj instanceof SQLPredicate) {
604: newReturnPred = this
605: .getLeftMostPredicate((SQLPredicate) sqlObj);
606: }
607:
608: // if there are no left most predicate then see if pred has left as predicate
609: if (newReturnPred == null) {
610: SQLInputObject inObj1 = pred.getInput(LEFT);
611: if (inObj1 != null) {
612: sqlObj = inObj1.getSQLObject();
613: if (sqlObj instanceof SQLPredicate) {
614: return (SQLPredicate) sqlObj;
615: }
616: }
617: } else {
618: return (newReturnPred);
619: }
620: }
621: return null;
622: }
623:
624: protected void parseCommonFields(Element xmlElement)
625: throws BaseException {
626: super .parseXML(xmlElement);
627: String opName = (String) getAttributeObject(SQLOperator.ATTR_SCRIPTREF);
628: IOperatorXmlInfo operatorXml = OperatorUtil
629: .findOperatorXmlInfo(opName);
630: if (operatorXml != null) {
631: this .setOperatorXmlInfo(operatorXml);
632: } else {
633: throw new BaseException(
634: "Cannot locate definition for operator " + opName);
635: }
636: }
637:
638: private void init(int argCount) {
639: for (int i = 0; i < argCount; i++) {
640: SQLOperatorArg operatorArg = operatorDefinition
641: .getOperatorArg(i);
642: String argName = operatorArg.getArgName();
643: IOperatorField field = null;
644: if (operatorXmlInfo != null) {
645: field = operatorXmlInfo.getInputField(argName);
646: }
647:
648: SQLInputObject inputObject = new SQLInputObjectImpl(
649: argName, (field != null ? field.getDisplayName()
650: : argName), null);
651: this .inputMap.put(argName, inputObject);
652: }
653: }
654:
655: // a group predicate is AND or OR which groups two comparison predicates
656: private boolean isGroupPredicate(String op) {
657: if (op != null
658: && (op.equalsIgnoreCase("AND")
659: || op.equalsIgnoreCase("OR") || op
660: .equalsIgnoreCase("NOT"))) {
661: return true;
662: }
663: return false;
664: }
665: }
|