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.HashMap;
045: import java.util.Iterator;
046: import java.util.List;
047: import java.util.ListIterator;
048: import java.util.Map;
049:
050: import org.netbeans.modules.sql.framework.common.utils.TagParserUtility;
051: import org.netbeans.modules.sql.framework.model.SQLCondition;
052: import org.netbeans.modules.sql.framework.model.SQLDefinition;
053: import org.netbeans.modules.sql.framework.model.SQLGroupBy;
054: import org.netbeans.modules.sql.framework.model.SQLModelObjectFactory;
055: import org.netbeans.modules.sql.framework.model.SQLObject;
056: import org.netbeans.modules.sql.framework.model.SourceColumn;
057: import org.netbeans.modules.sql.framework.model.TargetColumn;
058: import org.netbeans.modules.sql.framework.model.TargetTable;
059: import org.netbeans.modules.sql.framework.model.utils.SQLObjectUtil;
060: import org.netbeans.modules.sql.framework.model.visitors.SQLGroupByValidationVisitor;
061: import org.w3c.dom.Element;
062: import org.w3c.dom.Node;
063: import org.w3c.dom.NodeList;
064:
065: import com.sun.sql.framework.exception.BaseException;
066: import com.sun.sql.framework.utils.StringUtil;
067:
068: /**
069: * @author Ritesh Adval
070: */
071: public class SQLGroupByImpl extends AbstractSQLObject implements
072: SQLGroupBy, Cloneable {
073:
074: /**
075: * Attribute name used in XML representation of column sequence.
076: */
077: public static final String ATTR_SEQUENCE = "sequence";
078:
079: /**
080: * Name used for root element of the XML representation for this class.
081: */
082: public static final String ELEMENT_TAG = "groupBy";
083:
084: /** having condition tag */
085: public static final String HAVING_CONDITION = "havingCondition";
086:
087: private List colSequence = new ArrayList();
088: private Map columns = new HashMap();
089: private SQLCondition havingCondition;
090:
091: /**
092: * Creates a new default instance of SQLGroupByImpl.
093: */
094: public SQLGroupByImpl() {
095: super ();
096:
097: havingCondition = SQLModelObjectFactory.getInstance()
098: .createSQLCondition(HAVING_CONDITION);
099: setHavingCondition(havingCondition);
100: }
101:
102: /**
103: * Creates a new instance of SQLGroupByImpl
104: *
105: * @param myColumnList List of columns associated with this group-by instance
106: * @param parent parent object of this group-by instance
107: */
108: public SQLGroupByImpl(List myColumnList, Object parent) {
109: this ();
110:
111: setColumns(myColumnList);
112: setParentObject(parent);
113: }
114:
115: public SQLGroupByImpl(SQLGroupBy source) {
116: this ();
117: copyFrom(source);
118: }
119:
120: public void copyFrom(SQLGroupBy source) {
121: super .copyFromSource((SQLObject) source);
122: setColumns(source.getColumns());
123: setParentObject(source.getParentObject());
124: setHavingCondition(source.getHavingCondition());
125: }
126:
127: /**
128: * Indicates whether if given object is equal to this one.
129: *
130: * @param obj Object against which to compare this
131: * @return true if obj equals this; false otherwise.
132: */
133: public boolean equals(Object obj) {
134: if (this == obj) {
135: return true;
136: } else if (!(obj instanceof SQLGroupBy)) {
137: return false;
138: } else if (obj == null) {
139: return false;
140: }
141:
142: SQLGroupBy src = (SQLGroupBy) obj;
143: boolean response = super .equals(obj);
144:
145: if (!response) {
146: return response;
147: }
148:
149: response &= src.getColumns().equals(this .getColumns());
150:
151: return response;
152: }
153:
154: /**
155: * @see org.netbeans.modules.sql.framework.model.SQLGroupBy#getColumns
156: */
157: public List getColumns() {
158: List colList = new ArrayList(columns.values().size());
159:
160: Iterator iter = colSequence.iterator();
161: while (iter.hasNext()) {
162: String key = (String) iter.next();
163: colList.add(columns.get(key));
164: }
165:
166: return colList;
167: }
168:
169: public SQLCondition getHavingCondition() {
170: return havingCondition;
171: }
172:
173: /**
174: * @see org.netbeans.modules.sql.framework.model.SQLGroupBy#getParent
175: */
176: public Object getParentObject() {
177: return parentObject;
178: }
179:
180: /**
181: * Overrides default implementation to compute hashcode based on any associated
182: * attributes as well as values of non-transient member variables.
183: *
184: * @return hashcode for this instance
185: */
186: public int hashCode() {
187: int hCode = super .hashCode();
188:
189: hCode += this .getColumns().hashCode();
190: return hCode;
191: }
192:
193: public boolean isValid() {
194: TargetTable targetTable = (TargetTable) this .getParentObject();
195: SQLGroupByValidationVisitor groupByVisitor = new SQLGroupByValidationVisitor(
196: null, getColumns());
197: groupByVisitor.visit(targetTable.getColumns().values());
198: if (groupByVisitor.getValidationInfoList().size() > 0) {
199: return false;
200: } else {
201: return true;
202: }
203: }
204:
205: /**
206: * Parses the XML content, if any, represented by the given DOM element.
207: *
208: * @param groupByElement DOM element to be parsed for orderBy content
209: * @exception BaseException thrown while parsing XML, or if orderByElement is null
210: */
211: public void parseXML(Element groupByElement) throws BaseException {
212: String seqList = groupByElement.getAttribute(ATTR_SEQUENCE);
213: if (seqList == null || seqList.trim().length() == 0) {
214: throw new BaseException(
215: "Invalid or missing sequence attribute.");
216: }
217: colSequence = StringUtil.createStringListFrom(seqList);
218:
219: NodeList childNodeList = groupByElement.getChildNodes();
220: if (childNodeList != null && childNodeList.getLength() != 0) {
221: for (int i = 0; i < childNodeList.getLength(); i++) {
222: if (childNodeList.item(i).getNodeType() == Node.ELEMENT_NODE) {
223: Element childElement = (Element) childNodeList
224: .item(i);
225: String tagName = childElement.getTagName();
226:
227: if (TagParserUtility.TAG_OBJECTREF.equals(tagName)) {
228: secondPassParse(childElement);
229: } else if (SQLCondition.TAG_CONDITION
230: .equals(tagName)) {
231: String conditionName = childElement
232: .getAttribute(SQLCondition.DISPLAY_NAME);
233: if (conditionName != null
234: && conditionName
235: .equals(HAVING_CONDITION)) {
236: SQLCondition cond1 = SQLModelObjectFactory
237: .getInstance().createSQLCondition(
238: HAVING_CONDITION);
239: cond1.setParent(this );
240: cond1.parseXML(childElement);
241: this .setHavingCondition(cond1);
242: }
243: }
244: }
245: }
246: }
247: }
248:
249: /**
250: * @see org.netbeans.modules.sql.framework.model.SQLOrderBy#removeExpression
251: */
252: public void removeColumn(SQLObject obj) {
253: if (obj != null) {
254: String objId = obj.getId();
255: if (!StringUtil.isNullString(objId)) {
256: colSequence.remove(objId);
257: columns.remove(objId);
258: }
259: }
260: }
261:
262: /**
263: * Parses elements which require a second pass to resolve their values.
264: *
265: * @param element DOM element containing XML marshalled version of this SQLObject
266: * instance
267: * @throws BaseException if element is null or error occurs during parsing
268: */
269: public void secondPassParse(Element element) throws BaseException {
270: SQLDefinition definition = SQLObjectUtil
271: .getAncestralSQLDefinition((SQLObject) parentObject);
272:
273: SQLObject obj = TagParserUtility.parseXMLObjectRefTag(
274: definition, element);
275:
276: // If obj is null it may not be parsed yet so do a second parse...
277: // it registers this TargetColumn instance to be parsed a second time
278: // to resolve the value reference
279: if (obj == null) {
280: definition.addSecondPassSQLObject(this , element);
281: } else {
282: columns.put(obj.getId(), obj);
283: }
284: }
285:
286: /**
287: * Sets collection of columns associated with this instance.
288: *
289: * @param newColumnList list of columns involved in this group by
290: */
291: public void setColumns(List newColumnList) {
292: columns.clear();
293: colSequence.clear();
294:
295: Iterator iter = newColumnList.iterator();
296: while (iter.hasNext()) {
297: SQLObject repObj = (SQLObject) iter.next();
298: colSequence.add(repObj.getId());
299: columns.put(repObj.getId(), repObj);
300: }
301: }
302:
303: public void setHavingCondition(SQLCondition having) {
304: this .havingCondition = having;
305: if (this .havingCondition != null) {
306: this .havingCondition.setParent(this );
307: this .havingCondition.setDisplayName(HAVING_CONDITION);
308: }
309: }
310:
311: /**
312: * @see org.netbeans.modules.sql.framework.model.SQLGroupBy#setParent
313: */
314: public void setParentObject(Object obj) {
315: parentObject = obj;
316: }
317:
318: public String toString() {
319: StringBuilder strBuf = new StringBuilder(40);
320: Iterator it = this .getColumns().iterator();
321: while (it.hasNext()) {
322: Object colObj = it.next();
323: if (colObj instanceof SourceColumn) {
324: SourceColumn column = (SourceColumn) colObj;
325: strBuf.append(column.getName());
326: } else if (colObj instanceof TargetColumn) {
327: TargetColumn column = (TargetColumn) colObj;
328: strBuf.append(column.getName());
329: SQLObject obj = column.getValue();
330: strBuf.append("->(");
331: if (obj != null) {
332: strBuf.append(obj.toString());
333: }
334: strBuf.append(")");
335: }
336:
337: if (it.hasNext()) {
338: strBuf.append(",");
339: }
340: }
341: return strBuf.toString();
342: }
343:
344: /**
345: * @see org.netbeans.modules.sql.framework.model.SQLGroupBy#toXMLString(String)
346: */
347: public String toXMLString(String prefix) throws BaseException {
348: StringBuilder xml = new StringBuilder(500);
349: final String indent = prefix + "\t";
350:
351: if (columns == null || columns.isEmpty()) {
352: return "";
353: }
354:
355: xml.append(prefix).append("<").append(ELEMENT_TAG).append(" ");
356: xml.append(ATTR_SEQUENCE).append("=\"");
357:
358: removeDanglingExpressionIds();
359: xml.append(StringUtil.createDelimitedStringFrom(colSequence));
360: xml.append("\">\n");
361:
362: Iterator iter = columns.values().iterator();
363: while (iter.hasNext()) {
364: SQLObject expr = (SQLObject) iter.next();
365: try {
366: String refXml = TagParserUtility.toXMLObjectRefTag(
367: expr, indent);
368: xml.append(refXml);
369: } catch (BaseException e) {
370: // TODO log this exception
371: }
372: }
373:
374: if (havingCondition != null) {
375: xml.append(havingCondition.toXMLString(prefix + indent));
376: }
377:
378: xml.append(prefix).append("</").append(ELEMENT_TAG).append(
379: ">\n");
380: return xml.toString();
381: }
382:
383: private void removeDanglingExpressionIds() {
384: ListIterator iter = colSequence.listIterator();
385: while (iter.hasNext()) {
386: String anId = (String) iter.next();
387: if (!columns.containsKey(anId)) {
388: iter.remove();
389: }
390: }
391: }
392:
393: public Object clone() throws CloneNotSupportedException {
394: return new SQLGroupByImpl(this);
395: }
396: }
|