001: /***************************************************************
002: * This file is part of the [fleXive](R) project.
003: *
004: * Copyright (c) 1999-2008
005: * UCS - unique computing solutions gmbh (http://www.ucs.at)
006: * All rights reserved
007: *
008: * The [fleXive](R) project is free software; you can redistribute
009: * it and/or modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation;
011: * either version 2 of the License, or (at your option) any
012: * later version.
013: *
014: * The GNU General Public License can be found at
015: * http://www.gnu.org/copyleft/gpl.html.
016: * A copy is found in the textfile GPL.txt and important notices to the
017: * license from the author are found in LICENSE.txt distributed with
018: * these libraries.
019: *
020: * This library is distributed in the hope that it will be useful,
021: * but WITHOUT ANY WARRANTY; without even the implied warranty of
022: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023: * GNU General Public License for more details.
024: *
025: * For further information about UCS - unique computing solutions gmbh,
026: * please see the company website: http://www.ucs.at
027: *
028: * For further information about [fleXive](R), please see the
029: * project website: http://www.flexive.org
030: *
031: *
032: * This copyright notice MUST APPEAR in all copies of the file!
033: ***************************************************************/package com.flexive.shared.scripting.groovy;
034:
035: import com.flexive.shared.CacheAdmin;
036: import com.flexive.shared.exceptions.FxInvalidParameterException;
037: import com.flexive.shared.exceptions.FxInvalidStateException;
038: import com.flexive.shared.search.query.*;
039: import com.flexive.shared.structure.FxEnvironment;
040: import groovy.lang.Closure;
041: import groovy.util.BuilderSupport;
042: import org.codehaus.groovy.runtime.InvokerHelper;
043:
044: import java.util.Arrays;
045: import java.util.HashMap;
046: import java.util.List;
047: import java.util.Map;
048:
049: /**
050: * An (experimental) groovy builder for search queries.<br/>
051: * Example:<br/>
052: * <pre>
053: new GroovyQueryBuilder().select(["@pk", "caption", "*"]) {
054: eq("caption", "bla")
055: not_empty("filename")
056: or {
057: gt("id", 0)
058: lt("id", 100)
059: }
060: lt("created_at", new Date())
061: }.sqlQuery
062: * </pre>
063: *
064: * @author Daniel Lichtenberger (daniel.lichtenberger@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
065: * @version $Rev: 181 $
066: */
067: public class GroovyQueryBuilder extends BuilderSupport {
068: private final FxEnvironment environment = CacheAdmin
069: .getEnvironment();
070: private QueryRootNode root = new QueryRootNode(
071: QueryRootNode.Type.CONTENTSEARCH);
072:
073: public GroovyQueryBuilder() {
074: }
075:
076: /**
077: * Use an external query builder as the target builder.
078: *
079: * @param builder a sql query builder to be used for creating the query
080: */
081: public GroovyQueryBuilder(SqlQueryBuilder builder) {
082: root.setQueryBuilder(builder);
083: }
084:
085: public Object builder(Closure closure) {
086: System.out.println(closure);
087: return root;
088: }
089:
090: /** {@inheritDoc} */
091: @Override
092: protected Object doInvokeMethod(String methodName, Object name,
093: Object args) {
094: List list = InvokerHelper.asList(args);
095: if (list.size() >= 2) {
096: Object object1 = list.get(0);
097: Object object2 = list.get(1);
098: if (!(object1 instanceof Closure || object1 instanceof Map)
099: && !(object2 instanceof Closure || object2 instanceof Map)) {
100: // object1=property, object2=value
101: Map<String, Object> attributes = new HashMap<String, Object>();
102: attributes.put("property", object1);
103: if (list.size() > 2) {
104: // pass parameters as list
105: object2 = list.subList(1, list.size());
106: }
107: attributes.put("value", object2);
108: return super .doInvokeMethod(methodName, name,
109: attributes);
110: }
111: }
112: return super .doInvokeMethod(methodName, name, args);
113: }
114:
115: /** {@inheritDoc} */
116: @Override
117: protected void setParent(Object parent, Object child) {
118: if (parent != child) {
119: root.addChild((QueryNode) parent, (QueryNode) child);
120: }
121: }
122:
123: /** {@inheritDoc} */
124: @Override
125: protected Object createNode(Object name) {
126: if ("and".equals(name) || "or".equals(name)) {
127: QueryOperatorNode node;
128: if (root == null) {
129: root = new QueryRootNode(
130: QueryRootNode.Type.CONTENTSEARCH);
131: node = root;
132: } else {
133: node = new QueryOperatorNode(root.getNewId());
134: }
135: node
136: .setOperator("and".equals(name) ? QueryOperatorNode.Operator.AND
137: : QueryOperatorNode.Operator.OR);
138: return node;
139: } else {
140: final PropertyValueComparator comparator;
141: try {
142: comparator = PropertyValueComparator
143: .valueOf(((String) name).toUpperCase());
144: } catch (IllegalArgumentException e) {
145: throw new FxInvalidParameterException("COMPARATOR",
146: "ex.fxQueryBuilder.comparator.unknown", name,
147: Arrays.asList(PropertyValueComparator.values()))
148: .asRuntimeException();
149: }
150: PropertyValueNode node = new PropertyValueNode(root
151: .getNewId(), null);
152: node.setComparator(comparator);
153: return node;
154: }
155: }
156:
157: /** {@inheritDoc} */
158: @Override
159: protected Object createNode(Object name, Object value) {
160:
161: if ("select".equals(name)) {
162: if (!(value instanceof List)) {
163: throw new FxInvalidParameterException("VALUE",
164: "ex.fxQueryBuilder.select.column")
165: .asRuntimeException();
166: }
167: List columns = (List) value;
168: if (!columns.isEmpty()) {
169: if (root.getQueryBuilder() == null) {
170: root.setQueryBuilder(new SqlQueryBuilder());
171: }
172: root.getQueryBuilder().setIncludeBasicSelects(false);
173: // add column as specified in the columns attribute
174: for (Object column : columns) {
175: root.getQueryBuilder().select(column.toString());
176: }
177: }
178: return root;
179: } else if ("filterBriefcase".equals(name)) {
180: if (!(value instanceof Number)) {
181: throw new FxInvalidParameterException("VALUE",
182: "ex.fxQueryBuilder.filterBriefcase.number")
183: .asRuntimeException();
184: }
185: root.getQueryBuilder().filterBriefcase(
186: ((Number) value).longValue());
187: return root;
188: } else {
189: final QueryNode node = (QueryNode) createNode(name);
190: if (!(node instanceof PropertyValueNode)) {
191: return root;
192: }
193: // name = comparator, value = [property name, value]
194: final PropertyValueNode propertyNode = (PropertyValueNode) node;
195: /*if (value instanceof List) {
196: List args = (List) value;
197: propertyNode.setProperty(environment.getProperty((String) args.get(0)));
198: if (propertyNode.getComparator().isNeedsInput()) {
199: if (args.size() < 2) {
200: throw new FxInvalidStateException("ex.fxQueryBuilder.node.value", propertyNode.getComparator()).asRuntimeException();
201: }
202: propertyNode.setValue(getFxValue(args.get(1)));
203: }
204: } else */if (propertyNode.getComparator().isNeedsInput()) {
205: // operator needs input, but only property name supplied
206: throw new FxInvalidParameterException("VALUE",
207: "ex.fxQueryBuilder.node.value", propertyNode
208: .getComparator()).asRuntimeException();
209: } else {
210: // comparator doesn't need input, property name supplied as scalar
211: propertyNode.setProperty(environment
212: .getProperty((String) value));
213: }
214: return node;
215: }
216: }
217:
218: /** {@inheritDoc} */
219: @Override
220: protected Object createNode(Object name, Map attributes) {
221: final Object node = createNode(name);
222: if (node instanceof PropertyValueNode) {
223: // name = comparator, attributes = {column, value}
224: final PropertyValueNode propertyNode = (PropertyValueNode) node;
225: if (attributes.get("property") == null) {
226: throw new FxInvalidStateException(
227: "ex.fxQueryBuilder.node.column", propertyNode
228: .getComparator()).asRuntimeException();
229: }
230: if (propertyNode.getComparator().isNeedsInput()
231: && attributes.get("value") == null) {
232: throw new FxInvalidStateException(
233: "ex.fxQueryBuilder.node.value", propertyNode
234: .getComparator()).asRuntimeException();
235: }
236: String propertyName = (String) attributes.get("property");
237: propertyNode.setProperty(environment
238: .getProperty(propertyName));
239: propertyNode.setValue(propertyNode.getProperty()
240: .getEmptyValue());
241: Object value = attributes.get("value");
242: //noinspection unchecked
243: propertyNode.getValue().setDefaultTranslation(value);
244: return propertyNode;
245: } else {
246: throw new UnsupportedOperationException(
247: "createNode(Object, Map) not implemented for "
248: + name);
249: }
250: }
251:
252: /** {@inheritDoc} */
253: @Override
254: protected Object createNode(Object name, Map attributes,
255: Object value) {
256: throw new UnsupportedOperationException(
257: "createNode(Object, Map, Object) not implemented yet");
258: }
259: }
|