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.ArrayList;
044: import java.util.Iterator;
045: import java.util.LinkedHashMap;
046: import java.util.List;
047: import java.util.Map;
048:
049: import org.netbeans.modules.sql.framework.common.utils.TagParserUtility;
050: import org.netbeans.modules.sql.framework.model.ColumnRef;
051: import org.netbeans.modules.sql.framework.model.SQLConnectableObject;
052: import org.netbeans.modules.sql.framework.model.SQLConstants;
053: import org.netbeans.modules.sql.framework.model.SQLInputObject;
054: import org.netbeans.modules.sql.framework.model.SQLObject;
055: import org.netbeans.modules.sql.framework.model.visitors.SQLVisitor;
056: import net.java.hulp.i18n.Logger;
057: import com.sun.sql.framework.exception.BaseException;
058: import org.netbeans.modules.etl.logger.Localizer;
059: import org.netbeans.modules.etl.logger.LogUtil;
060:
061: /**
062: * Base class implementation of SQLConnectableObject; inherits behavior from
063: * AbstractSQLObject. Subclasses should override addInput and other methods as required for
064: * specialization.
065: *
066: * @author Jonathan Giron
067: * @version $Revision$
068: */
069: public abstract class SQLConnectableObjectImpl extends
070: AbstractSQLObject implements SQLConnectableObject {
071:
072: /* Log4J category string */
073: private static final String LOG_CATEGORY = SQLConnectableObjectImpl.class
074: .getName();
075: private static transient final Logger mLogger = LogUtil
076: .getLogger(SQLConnectableObjectImpl.class.getName());
077: private static transient final Localizer mLoc = Localizer.get();
078: /** Map of SQLInputObjects */
079: protected Map inputMap;
080:
081: /** Creates a new instance of AbstractSQLExpressionObject */
082: public SQLConnectableObjectImpl() {
083: super ();
084: inputMap = new LinkedHashMap(10);
085: }
086:
087: /**
088: * @throws com.sun.sql.framework.exception.BaseException
089: * @see SQLConnectableObject#addInput
090: */
091: public void addInput(String argName, SQLObject newInput)
092: throws BaseException {
093: if (argName == null || newInput == null) {
094: throw new BaseException("Input arguments not specified");
095: }
096:
097: int newType = newInput.getObjectType();
098: String objType = TagParserUtility.getDisplayStringFor(newType);
099:
100: if (isInputCompatible(argName, newInput) == SQLConstants.TYPE_CHECK_INCOMPATIBLE) {
101: throw new BaseException("Input type " + objType
102: + " is incompatible with input argument '"
103: + argName + "' of "
104: + TagParserUtility.getDisplayStringFor(this .type)
105: + " '" + this .getDisplayName() + "'.");
106: }
107:
108: if (!isInputValid(argName, newInput)) {
109: throw new BaseException("Cannot link " + objType + " '"
110: + newInput.getDisplayName() + "' as input to '"
111: + argName + "' in "
112: + TagParserUtility.getDisplayStringFor(this .type)
113: + " '" + this .getDisplayName() + "'");
114: }
115:
116: SQLInputObject inputObject = (SQLInputObject) inputMap
117: .get(argName);
118: if (inputObject != null) {
119: inputObject.setSQLObject(newInput);
120: } else {
121: throw new BaseException("Input with argName '" + argName
122: + "' does not exist.");
123: }
124: }
125:
126: /**
127: * Overrides default implementation to compute hashcode based on any associated
128: * SQLInputObjects as well as values of non-transient member variables.
129: *
130: * @param o Object to compare for equality
131: * @return hashcode for this instance
132: */
133: public boolean equals(Object o) {
134: if (o == null) {
135: return false;
136: } else if (o == this ) {
137: return true;
138: }
139:
140: boolean response = super .equals(o);
141:
142: if (o instanceof SQLConnectableObjectImpl) {
143: SQLConnectableObjectImpl impl = (SQLConnectableObjectImpl) o;
144:
145: // This convoluted logic is here because inputMap.equals(impl.inputMap)
146: // apparently delegates to the Object.equals() method. Go figure.
147: response &= (inputMap != null) && (impl.inputMap != null) ? (inputMap
148: .entrySet().equals(impl.inputMap.entrySet()))
149: : (inputMap == null) && (impl.inputMap == null);
150: } else {
151: response = false;
152: }
153:
154: return response;
155: }
156:
157: /**
158: * Gets list of child SQLObjects
159: *
160: * @return List of child SQLObject instances
161: */
162: public List getChildSQLObjects() {
163: return new ArrayList();
164: }
165:
166: /**
167: * @see SQLConnectableObject#getInput
168: */
169: public SQLInputObject getInput(String argName) {
170: return (SQLInputObject) inputMap.get(argName);
171: }
172:
173: /**
174: * @see SQLConnectableObject#getInputObjectMap
175: */
176: public Map getInputObjectMap() {
177: return inputMap;
178: }
179:
180: /**
181: * Provides default implementation of interface method signature. Returns an empty
182: * array list. Override this method in subclasses.
183: *
184: * @return ArrayList of SQLTypeObjects
185: * @throws com.sun.sql.framework.exception.BaseException
186: * @see SQLConnectableObject#getPossibleTypes
187: */
188: public ArrayList getPossibleTypes() throws BaseException {
189: ArrayList list = new ArrayList();
190: return (list);
191: }
192:
193: public List getSourceColumnsUsed() {
194: List list = new ArrayList();
195: return getColumnsUsed(this , SQLConstants.SOURCE_COLUMN, list);
196: }
197:
198: /**
199: * @see SQLConnectableObject#getSQLObject
200: */
201: public SQLObject getSQLObject(String argName) {
202: SQLInputObject input = getInput(argName);
203: return (input != null) ? input.getSQLObject() : null;
204: }
205:
206: /**
207: * @see SQLConnectableObject#getSQLObjectMap
208: */
209: public Map getSQLObjectMap() {
210: Map objMap = new LinkedHashMap(10);
211: Iterator iter = inputMap.entrySet().iterator();
212:
213: while (iter.hasNext()) {
214: Map.Entry entry = (Map.Entry) iter.next();
215: String argName = (String) entry.getKey();
216: SQLInputObject obj = (SQLInputObject) entry.getValue();
217:
218: if (argName != null && obj != null
219: && obj.getSQLObject() != null) {
220: objMap.put(argName, obj.getSQLObject());
221: }
222: }
223:
224: return objMap;
225: }
226:
227: public List getTargetColumnsUsed() {
228: List list = new ArrayList();
229: return getColumnsUsed(this , SQLConstants.TARGET_COLUMN, list);
230: }
231:
232: /**
233: * Overrides default implementation to compute hashcode based on any associated
234: * attributes as well as values of non-transient member variables.
235: *
236: * @return hashcode for this instance
237: */
238: public int hashCode() {
239: int hashCode = super .hashCode();
240: hashCode += (inputMap != null) ? inputMap.hashCode() : 0;
241:
242: return hashCode;
243: }
244:
245: public boolean hasSourceColumn() {
246: return hasColumnOfType(this , SQLConstants.SOURCE_COLUMN);
247: }
248:
249: public boolean hasTargetColumn() {
250: return hasColumnOfType(this , SQLConstants.TARGET_COLUMN);
251: }
252:
253: /**
254: * @see SQLConnectableObject
255: */
256: public int isInputCompatible(String argName, SQLObject input) {
257: return SQLConstants.TYPE_CHECK_COMPATIBLE;
258: }
259:
260: public boolean isInputStatic(String argName) {
261: return false;
262: }
263:
264: /**
265: * @see SQLConnectableObject#isInputValid
266: */
267: public boolean isInputValid(String argName, SQLObject input) {
268: return true;
269: }
270:
271: /**
272: * @param sqlObj
273: * @throws com.sun.sql.framework.exception.BaseException
274: * @see SQLConnectableObject#removeInputByArgName
275: */
276: public SQLObject removeInputByArgName(String argName,
277: SQLObject sqlObj) throws BaseException {
278: if (argName == null) {
279: throw new BaseException(
280: "Cannot delete input for null argument");
281: }
282:
283: SQLInputObject inputObject = (SQLInputObject) inputMap
284: .get(argName);
285: if (inputObject == null) {
286: throw new BaseException(
287: "Cannot delete non-existent input for argument "
288: + argName);
289: }
290:
291: SQLObject victim = inputObject.getSQLObject();
292: inputObject.setSQLObject(null);
293: return victim;
294: }
295:
296: public void reset() {
297: super .reset();
298: Iterator it = inputMap.keySet().iterator();
299: while (it.hasNext()) {
300: String name = (String) it.next();
301: SQLInputObject inputObj = (SQLInputObject) inputMap
302: .get(name);
303: //inputObj.setSQLObject(null);
304: inputObj.getSQLObject().reset();
305: }
306: }
307:
308: /**
309: * Overrides parent implementation to append XML elements for any input objects
310: * associated with this expression.
311: *
312: * @param prefix String to append to each new line of the XML representation
313: * @return XML representation of this SQLObject instance
314: */
315: public String toXMLString(String prefix) throws BaseException {
316: StringBuilder buf = new StringBuilder();
317: if (prefix == null) {
318: prefix = "";
319: }
320:
321: buf.append(prefix).append(getHeader());
322: buf.append(super .toXMLAttributeTags(prefix));
323: buf.append(TagParserUtility.toXMLInputTag(prefix + "\t",
324: inputMap));
325: buf.append(prefix).append(getFooter());
326:
327: return buf.toString();
328: }
329:
330: public abstract void visit(SQLVisitor visitor);
331:
332: public void copyFromSource(SQLObject source) {
333: super .copyFromSource(source);
334: SQLConnectableObject expObj = (SQLConnectableObject) source;
335:
336: Map inputObjMap = expObj.getInputObjectMap();
337: Iterator it = inputObjMap.keySet().iterator();
338:
339: while (it.hasNext()) {
340: String name = (String) it.next();
341: SQLInputObject inputObj = (SQLInputObject) inputObjMap
342: .get(name);
343: SQLObject obj = inputObj.getSQLObject();
344: if (obj != null) {
345: try {
346: SQLObject copiedObj = (SQLObject) obj
347: .cloneSQLObject();
348: SQLInputObject inputObject = (SQLInputObject) inputMap
349: .get(name);
350: if (inputObject != null) {
351: inputObject.setSQLObject(copiedObj);
352: }
353: } catch (CloneNotSupportedException ex) {
354: mLogger.errorNoloc(mLoc.t(
355: "PRSR111: Failed to cloned input map{0}",
356: LOG_CATEGORY), ex);
357: }
358: }
359: }
360:
361: }
362:
363: protected List getColumnsUsed(SQLConnectableObject exp,
364: int colType, List list) {
365: if (exp != null) {
366: Map inputObjMap = exp.getInputObjectMap();
367: Iterator it = inputObjMap.keySet().iterator();
368:
369: while (it.hasNext()) {
370: String name = (String) it.next();
371: SQLInputObject inputObj = (SQLInputObject) inputObjMap
372: .get(name);
373: SQLObject obj = inputObj.getSQLObject();
374: if (obj != null) {
375: try {
376: if (obj.getObjectType() == SQLConstants.COLUMN_REF) {
377: obj = ((ColumnRef) obj).getColumn();
378: if (obj.getObjectType() == colType) {
379: list.add(obj);
380: }
381: } else {
382: if (obj instanceof SQLConnectableObject) {
383: getColumnsUsed(
384: (SQLConnectableObject) obj,
385: colType, list);
386: }
387: }
388:
389: } catch (Exception ex) {
390: mLogger
391: .errorNoloc(
392: mLoc
393: .t(
394: "PRSR112: Finding expression contains column refs{0}",
395: LOG_CATEGORY),
396: ex);
397: }
398: }
399: }
400: }
401: return list;
402: }
403:
404: protected boolean hasColumnOfType(SQLConnectableObject exp,
405: int colType) {
406: boolean ret = false;
407:
408: if (exp != null) {
409: Map inputObjMap = exp.getInputObjectMap();
410: Iterator it = inputObjMap.keySet().iterator();
411:
412: while (it.hasNext()) {
413: String name = (String) it.next();
414: SQLInputObject inputObj = (SQLInputObject) inputObjMap
415: .get(name);
416: SQLObject obj = inputObj.getSQLObject();
417: if (obj != null) {
418: try {
419: if (obj.getObjectType() == SQLConstants.COLUMN_REF) {
420: obj = ((ColumnRef) obj).getColumn();
421: if (obj.getObjectType() == colType) {
422: ret = true;
423: break;
424: }
425: } else {
426: if (obj instanceof SQLConnectableObject) {
427: if (hasColumnOfType(
428: (SQLConnectableObject) obj,
429: colType)) {
430: ret = true;
431: break;
432: }
433: }
434: }
435:
436: } catch (Exception ex) {
437: mLogger
438: .errorNoloc(
439: mLoc
440: .t(
441: "PRSR113: Finding expression contains column refs{0}",
442: LOG_CATEGORY),
443: ex);
444: }
445: }
446: }
447: }
448: return ret;
449: }
450: }
|