001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010:
011: package org.mmbase.bridge.implementation;
012:
013: import java.util.*;
014: import org.mmbase.bridge.util.Queries;
015: import org.mmbase.cache.CachePolicy;
016: import org.mmbase.module.core.*;
017: import org.mmbase.module.corebuilders.*;
018: import org.mmbase.storage.search.*;
019: import org.mmbase.storage.search.implementation.*;
020: import org.mmbase.bridge.*;
021: import org.mmbase.util.logging.*;
022: import org.mmbase.security.Authorization;
023:
024: /**
025: * 'Basic' implementation of bridge Query. Wraps a 'BasicSearchQuery' from core.
026: *
027: * This implementation is actually ussuable with other implementations of bridge too, because it has the public constructor:
028: * {@link #BasicQuery(Cloud, BasicSearchQuery)}.
029: *
030: * @author Michiel Meeuwissen
031: * @version $Id: BasicQuery.java,v 1.71 2008/02/27 11:48:44 michiel Exp $
032: * @since MMBase-1.7
033: * @see org.mmbase.storage.search.implementation.BasicSearchQuery
034: */
035: public class BasicQuery implements Query {
036:
037: private static final Logger log = Logging
038: .getLoggerInstance(BasicQuery.class);
039:
040: /**
041: * Whether this Query was used already. If it is used, it may not be changed any more.
042: */
043: protected boolean used = false;
044:
045: /**
046: * Whether this Query is aggregating.
047: * @todo this member is in BasicSearchQuery too (but private).
048: */
049: protected boolean aggregating = false; // ugly ugly, this member is in BasicSearchQuery too (but private).
050:
051: /**
052: * The QueryCheck object associated with this Query, or null if no such object was determined yet.
053: */
054: protected Authorization.QueryCheck queryCheck = null;
055:
056: /**
057: * If a the contraint was made 'secure', in insecureConstraint the original Constraint is
058: * stored. This object is null if either the queryCheck object is not yet determined, or the
059: * orignal query did not have constraints.
060: */
061: protected Constraint insecureConstraint = null;
062:
063: private HashMap<String, Integer> aliasSequences = new HashMap<String, Integer>(); // must be HashMap because cloneable
064: // to make unique table aliases. This is similar impl. as in core. Why should it be at all....
065:
066: /**
067: * The core query which is 'wrapped'
068: */
069: protected BasicSearchQuery query;
070:
071: /**
072: * reference to the cloud.
073: */
074: protected Cloud cloud;
075:
076: /**
077: * The implicitely added 'extra' fields. These are removed if the query becomes 'distinct'. So,
078: * you can e.g. not do element= on a distinct query result.
079: */
080: protected List<StepField> implicitFields = new ArrayList<StepField>();
081:
082: /**
083: * The explicitely added 'extra' fields. Because you explicitely added those, they will not be removed if the query becomes 'distinct'.
084: */
085: protected List<StepField> explicitFields = new ArrayList<StepField>();
086:
087: BasicQuery(Cloud c) {
088: query = new BasicSearchQuery();
089: cloud = c;
090: }
091:
092: BasicQuery(Cloud c, boolean aggregating) {
093: query = new BasicSearchQuery(aggregating);
094: this .aggregating = aggregating;
095: cloud = c;
096: }
097:
098: public BasicQuery(Cloud c, BasicSearchQuery q) { // public for org.mmbase.bridge.util
099: query = q;
100: cloud = c;
101: this .aggregating = q.isAggregating();
102: }
103:
104: public BasicSearchQuery getQuery() {
105: return query;
106: }
107:
108: protected void createNewQuery() {
109: query = new BasicSearchQuery();
110: }
111:
112: // SearchQuery impl:
113:
114: public List<Step> getSteps() {
115: return query.getSteps();
116: }
117:
118: public List<StepField> getFields() {
119: return query.getFields();
120: }
121:
122: public Constraint getConstraint() {
123: return query.getConstraint();
124: }
125:
126: // bridge.Query impl
127: public Constraint getCleanConstraint() {
128: if (queryCheck != null) {
129: return insecureConstraint;
130: } else {
131: return query.getConstraint();
132: }
133: }
134:
135: // more SearchQuery impl
136: public int getMaxNumber() {
137: return query.getMaxNumber();
138: }
139:
140: public int getOffset() {
141: return query.getOffset();
142: }
143:
144: public List<SortOrder> getSortOrders() {
145: return query.getSortOrders();
146: }
147:
148: public boolean isDistinct() {
149: return query.isDistinct();
150: }
151:
152: // bridge.Query impl.:
153:
154: public boolean isAggregating() {
155: return aggregating;
156: }
157:
158: public CachePolicy getCachePolicy() {
159: return query.getCachePolicy();
160: }
161:
162: public void setCachePolicy(CachePolicy policy) {
163: query.setCachePolicy(policy);
164: }
165:
166: /**
167: * @since MMBase-1.7.1
168: */
169: protected void removeSecurityConstraintFromClone(
170: BasicSearchQuery clone) {
171: if (log.isDebugEnabled()) {
172: log.debug("Removing " + queryCheck + " FROM " + clone);
173: }
174: if (queryCheck != null) {
175: Constraint secureConstraint = queryCheck.getConstraint();
176: if (secureConstraint != null) {
177: Constraint constraint = clone.getConstraint();
178: // remove it from clone (by modifying the 'cloned' constraint)
179: if (secureConstraint.equals(constraint)) {
180: clone.setConstraint(null);
181: } else { // must be part of the composite constraint
182: BasicCompositeConstraint compConstraint = (BasicCompositeConstraint) constraint;
183: compConstraint.removeChild(secureConstraint); // remove it
184: if (compConstraint.getChilds().size() == 0) { // no need to let it then
185: clone.setConstraint(null);
186: }
187: if (compConstraint.getChilds().size() == 1) { // no need to let it composite then
188: Constraint newConstraint = compConstraint
189: .getChilds().get(0);
190: clone.setConstraint(newConstraint);
191: }
192: }
193: }
194: }
195:
196: }
197:
198: @Override
199: public Object clone() { // also works for descendants (NodeQuery)
200: try {
201: BasicQuery clone = (BasicQuery) super .clone();
202: clone.query = (BasicSearchQuery) query.clone();
203: clone.aliasSequences = (HashMap<String, Integer>) aliasSequences
204: .clone();
205: removeSecurityConstraintFromClone(clone.query);
206: clone.insecureConstraint = null;
207: clone.queryCheck = null;
208: clone.used = false;
209: return clone;
210: } catch (CloneNotSupportedException e) {
211: // cannot happen
212: throw new InternalError(e.toString());
213: }
214: }
215:
216: public Query aggregatingClone() {
217: BasicSearchQuery bsq = new BasicSearchQuery(query,
218: BasicSearchQuery.COPY_AGGREGATING);
219: removeSecurityConstraintFromClone(bsq);
220: BasicQuery clone = new BasicQuery(cloud, bsq);
221: clone.used = false;
222: clone.aggregating = true;
223: return clone;
224: }
225:
226: public Query cloneWithoutFields() {
227: BasicSearchQuery bsq = new BasicSearchQuery(query,
228: BasicSearchQuery.COPY_WITHOUTFIELDS);
229: removeSecurityConstraintFromClone(bsq);
230: BasicQuery clone = new BasicQuery(cloud, bsq);
231: clone.used = false;
232: clone.aggregating = false;
233: return clone;
234: }
235:
236: /**
237: * Creates a unique alias for this Query based on a given base String
238: */
239: protected String createAlias(String name) {
240: if (used)
241: throw new BridgeException("Query was used already");
242: Integer seq = aliasSequences.get(name);
243: if (seq == null) {
244: seq = Integer.valueOf(0);
245: } else {
246: seq = Integer.valueOf(seq.intValue() + 1);
247: }
248: aliasSequences.put(name, seq);
249: return glueAlias(name, seq);
250: }
251:
252: /**
253: * Glues a string and integer together to a new string.
254: */
255: protected String glueAlias(String aliasBase, Integer seq) {
256: if (seq == null)
257: return aliasBase;
258: int s = seq.intValue();
259: if (s == 0) {
260: return aliasBase;
261: } else {
262: return aliasBase + s;
263: }
264: }
265:
266: public Step addStep(NodeManager nm) {
267: if (used)
268: throw new BridgeException("Query was used already");
269:
270: removeSecurityConstraint(); // if present
271: MMObjectBuilder builder = MMBase.getMMBase().getBuilder(
272: nm.getName());
273: if (builder == null)
274: throw new BridgeException("No builder with name "
275: + nm.getName() + " (perhaps " + nm
276: + " is virtual?)");
277: BasicStep step = query.addStep(builder);
278: setAlias(step, ""); // "": generate alias
279: if (!aggregating) {
280: addFieldImplicit(step, nm.getField("number"));
281: }
282:
283: return step;
284: }
285:
286: public void setAlias(Step step, String alias) {
287: String currentAlias = step.getAlias();
288: String aliasBase = step.getTableName();
289:
290: // check if it was the lastely 'automaticly' create alias, in which case we free the sequence number again
291: // (also to fix #6547)
292:
293: Integer currentSeq = aliasSequences.get(aliasBase);
294: if (currentSeq != null
295: && glueAlias(aliasBase, currentSeq)
296: .equals(currentAlias)) {
297: if (currentSeq.intValue() == 0) {
298: aliasSequences.put(aliasBase, null);
299: } else {
300: aliasSequences.put(aliasBase, Integer
301: .valueOf(currentSeq.intValue() - 1));
302: }
303: }
304: if ("".equals(alias)) {
305: alias = createAlias(aliasBase);
306: }
307:
308: BasicStep basicStep = (BasicStep) step;
309: basicStep.setAlias(alias);
310: }
311:
312: protected BasicRelationStep addRelationStep(InsRel insrel,
313: NodeManager otherNodeManager, int direction) {
314: MMObjectBuilder otherBuilder = ((BasicNodeManager) otherNodeManager).builder;
315: BasicRelationStep relationStep = query.addRelationStep(insrel,
316: otherBuilder);
317: relationStep.setDirectionality(direction);
318: relationStep.setAlias(createAlias(relationStep.getTableName()));
319: NodeManager relationManager = otherNodeManager.getCloud()
320: .getNodeManager(relationStep.getTableName());
321: BasicStep next = (BasicStep) relationStep.getNext();
322: next.setAlias(createAlias(next.getTableName()));
323: if (!aggregating) {
324: // the number fields must always be queried, otherwise the original node cannot be found back (e.g. <mm:node element=)
325: addFieldImplicit(relationStep, relationManager
326: .getField("number")); // query relation node
327: addFieldImplicit(next, otherNodeManager.getField("number")); // and next node
328: // distinct?
329: }
330: return relationStep;
331: }
332:
333: public RelationStep addRelationStep(NodeManager otherNodeManager) {
334: return addRelationStep(otherNodeManager, null, "BOTH");
335: }
336:
337: public RelationStep addRelationStep(NodeManager otherNodeManager,
338: String role, String direction) {
339: if ("".equals(role))
340: role = null;
341: return addRelationStep(otherNodeManager, role, direction, true);
342: }
343:
344: protected RelationStep addRelationStep(
345: NodeManager otherNodeManager, String role,
346: String direction, boolean warnOnImpossibleStep) {
347: if (used)
348: throw new BridgeException("Query was used already");
349:
350: // a bit silly that two lookups are needed
351: int relationDir = Queries.getRelationStepDirection(direction);
352:
353: TypeRel typeRel = BasicCloudContext.mmb.getTypeRel();
354: if (role == null) {
355: InsRel insrel = BasicCloudContext.mmb.getInsRel();
356: BasicRelationStep step = addRelationStep(insrel,
357: otherNodeManager, relationDir);
358: if (!typeRel.optimizeRelationStep(step, cloud
359: .getNodeManager(step.getPrevious().getTableName())
360: .getNumber(), otherNodeManager.getNumber(), -1,
361: relationDir)) {
362: if (relationDir != RelationStep.DIRECTIONS_SOURCE
363: && relationDir != RelationStep.DIRECTIONS_DESTINATION
364: && warnOnImpossibleStep) {
365: log
366: .warn("Added an impossible relation step ("
367: + step
368: + " to "
369: + otherNodeManager
370: + ") to the query. The query-result will always be empty now (so you could as well not execute it).");
371: log.warn(Logging.applicationStacktrace());
372: }
373: }
374: return step;
375: } else {
376: RelDef relDef = BasicCloudContext.mmb.getRelDef();
377: int r = relDef.getNumberByName(role);
378: if (r == -1) {
379: throw new NotFoundException("Role '" + role
380: + "' does not exist.");
381: }
382: MMObjectNode relDefNode = relDef.getNode(r);
383: InsRel insrel = ((RelDef) relDefNode.getBuilder())
384: .getBuilder(relDefNode.getNumber());
385: BasicRelationStep step = addRelationStep(insrel,
386: otherNodeManager, relationDir);
387: step.setRole(Integer.valueOf(r));
388: if (!cloud.hasNodeManager(role)) {
389: step.setAlias(createAlias(role));
390: }
391: if (!typeRel.optimizeRelationStep(step, cloud
392: .getNodeManager(step.getPrevious().getTableName())
393: .getNumber(), otherNodeManager.getNumber(), r,
394: relationDir)) {
395: if (relationDir != RelationStep.DIRECTIONS_SOURCE
396: && relationDir != RelationStep.DIRECTIONS_DESTINATION
397: && warnOnImpossibleStep) {
398: // not fully specified, and nothing found, warn about that.
399: log
400: .warn("Added an impossible relation step ("
401: + step
402: + " to "
403: + otherNodeManager
404: + ") to the query. The query-result will always be empty now (so you could as well not execute it). ");
405: log.warn(Logging.applicationStacktrace());
406: }
407: }
408: return step;
409: }
410: }
411:
412: public void removeFields() {
413: query.removeFields();
414: explicitFields.clear();
415: Iterator<StepField> i = implicitFields.iterator();
416: while (i.hasNext()) {
417: BasicStepField sf = (BasicStepField) i.next();
418: Step addedStep = sf.getStep();
419: query.addField(addedStep, sf.getField());
420: }
421:
422: }
423:
424: public StepField addField(Step step, Field field) {
425: if (used)
426: throw new BridgeException("Query was used already");
427: org.mmbase.core.CoreField cf = ((BasicField) field).coreField; /// XXX Casting is wrong
428: BasicStepField sf = new BasicStepField(step, cf);
429: if (!implicitFields.remove(sf)) {// it's explicitly added now
430: if (cf.inStorage()) {
431: sf = query.addField(step, cf);
432: } else {
433: log
434: .debug("Not adding the field "
435: + field
436: + " because it is not in storage (this is a virtual field)");
437: }
438: }
439: explicitFields.add(sf);
440: return sf;
441: }
442:
443: public StepField addField(String fieldIdentifier) {
444: // code copied from createStepField, should be centralized
445: if (used)
446: throw new BridgeException("Query was used already");
447: int dot = fieldIdentifier.indexOf('.');
448: if (dot <= 0)
449: throw new BridgeException(
450: "No step alias found in field identifier '"
451: + fieldIdentifier
452: + "'. Expected a dot in it.");
453: String stepAlias = fieldIdentifier.substring(0, dot);
454: String fieldName = fieldIdentifier.substring(dot + 1);
455: Step step = getStep(stepAlias);
456: if (step == null)
457: throw new NotFoundException("No step with alias '"
458: + stepAlias + "' found in " + getSteps());
459: NodeManager nm = cloud.getNodeManager(step.getTableName());
460: Field field = nm.getField(fieldName);
461: return addField(step, field);
462: }
463:
464: /**
465: * Fields which are added 'implicity' should be added by this function.
466: */
467: protected void addFieldImplicit(Step step, Field field) {
468: if (used)
469: throw new BridgeException("Query was used already");
470: if (!query.isDistinct()) {
471: org.mmbase.core.CoreField coreField = ((BasicField) field).coreField; /// XXX Casting is wrong
472: StepField sf = query.addFieldUnlessPresent(step, coreField);
473: if (!implicitFields.contains(sf)) {
474: implicitFields.add(sf);
475: }
476: }
477: }
478:
479: public StepField createStepField(Step step, Field field) {
480: if (field == null)
481: throw new BridgeException("Field is null");
482: return new BasicStepField(step, ((BasicField) field).coreField); /// XXX Casting is wrong
483: }
484:
485: public StepField createStepField(Step step, String fieldName) {
486: return createStepField(step, cloud.getNodeManager(
487: step.getTableName()).getField(fieldName));
488: }
489:
490: public Step getStep(String stepAlias) {
491: return Queries.searchStep(getSteps(), stepAlias);
492: }
493:
494: public StepField createStepField(String fieldIdentifier) {
495: // code copied from addField, should be centralized
496: int dot = fieldIdentifier.indexOf('.');
497: if (dot <= 0)
498: throw new BridgeException(
499: "No step alias found in field identifier '"
500: + fieldIdentifier
501: + "'. Expected a dot in it.");
502: String stepAlias = fieldIdentifier.substring(0, dot);
503: String fieldName = fieldIdentifier.substring(dot + 1);
504: Step step = getStep(stepAlias);
505: if (step == null)
506: throw new NotFoundException("No step with alias '"
507: + stepAlias + "' found in " + getSteps());
508: NodeManager nm = cloud.getNodeManager(step.getTableName());
509: Field field = nm.getField(fieldName);
510: return createStepField(step, field);
511: }
512:
513: public AggregatedField addAggregatedField(Step step, Field field,
514: int aggregationType) {
515: if (used)
516: throw new BridgeException("Query was used already");
517: BasicAggregatedField aggregatedField = query
518: .addAggregatedField(step,
519: ((BasicField) field).coreField, aggregationType); /// XXX Casting is wrong
520: // aggregatedField.setAlias(field.getName());
521:
522: if (this instanceof NodeQuery) { // UGLY!
523: NodeQuery nodeQuery = (NodeQuery) this ;
524: ((BasicStep) step).setAlias(nodeQuery.getNodeManager()
525: .getName());
526: // Step needs alias, because otherwise clusterbuilder chokes.
527: // And node-manager.getList is illogical, because a aggregated result is certainly not a 'real' node.
528: }
529:
530: // TODO, think of something better. --> a good way to present aggregated results.
531:
532: return aggregatedField;
533: }
534:
535: public Query setDistinct(boolean distinct) {
536: if (used)
537: throw new BridgeException("Query was used already");
538: query.setDistinct(distinct);
539: if (distinct) { // in that case, make sure only the 'explicitely' added fields remain.
540: query.removeFields();
541: implicitFields.clear();
542: Iterator<StepField> i = explicitFields.iterator();
543: while (i.hasNext()) {
544: BasicStepField sf = (BasicStepField) i.next();
545: query.addField(sf.getStep(), sf.getField());
546: }
547: }
548: return this ;
549: }
550:
551: public Query setMaxNumber(int maxNumber) {
552: if (used)
553: throw new BridgeException("Query was used already");
554: query.setMaxNumber(maxNumber);
555: return this ;
556: }
557:
558: public Query setOffset(int offset) {
559: if (used)
560: throw new BridgeException("Query was used already");
561: query.setOffset(offset);
562: return this ;
563:
564: }
565:
566: public LegacyConstraint createConstraint(String s) {
567: return new BasicLegacyConstraint(s);
568: }
569:
570: public FieldNullConstraint createConstraint(StepField f) {
571: return new BasicFieldNullConstraint(f);
572: }
573:
574: public FieldValueConstraint createConstraint(StepField f, Object v) {
575: return createConstraint(f, FieldCompareConstraint.EQUAL, v);
576: }
577:
578: public FieldValueConstraint createConstraint(StepField f, int op,
579: Object v, int part) {
580: BasicFieldValueConstraint c = new BasicFieldValueDateConstraint(
581: f, v, part);
582: c.setOperator(op);
583: return c;
584: }
585:
586: public FieldValueConstraint createConstraint(StepField f, int op,
587: Object v) {
588: if (v instanceof Node)
589: v = Integer.valueOf(((Node) v).getNumber());
590: BasicFieldValueConstraint c = new BasicFieldValueConstraint(f,
591: v);
592: c.setOperator(op);
593: return c;
594: }
595:
596: public CompareFieldsConstraint createConstraint(StepField f,
597: int op, StepField v) {
598: BasicCompareFieldsConstraint c = new BasicCompareFieldsConstraint(
599: f, v);
600: c.setOperator(op);
601: return c;
602: }
603:
604: public FieldValueBetweenConstraint createConstraint(StepField f,
605: Object o1, Object o2) {
606: return new BasicFieldValueBetweenConstraint(f, o1, o2);
607: }
608:
609: public FieldValueInConstraint createConstraint(StepField f,
610: SortedSet<? extends Object> v) {
611: if (v.size() == 0) { // make sure the query becomes empty!
612: Step step = f.getStep();
613: StepField nf = createStepField(step, "number");
614: BasicFieldValueInConstraint c = new BasicFieldValueInConstraint(
615: nf);
616: c.addValue(Integer.valueOf(-1));
617: return c;
618: } else {
619: BasicFieldValueInConstraint c = new BasicFieldValueInConstraint(
620: f);
621: for (Object o : v) {
622: c.addValue(o);
623: }
624: return c;
625: }
626: }
627:
628: public Constraint setInverse(Constraint c, boolean i) {
629: ((BasicConstraint) c).setInverse(i);
630: return c;
631: }
632:
633: public FieldConstraint setCaseSensitive(FieldConstraint c, boolean s) {
634: ((BasicFieldConstraint) c).setCaseSensitive(s);
635: return c;
636:
637: }
638:
639: public CompositeConstraint createConstraint(Constraint c1,
640: int operator, Constraint c2) {
641: if ((!used)
642: && c1 instanceof BasicCompositeConstraint
643: && ((CompositeConstraint) c1).getLogicalOperator() == operator) {
644: if (c2 != null)
645: ((BasicCompositeConstraint) c1).addChild(c2);
646: return (CompositeConstraint) c1;
647: } else {
648: BasicCompositeConstraint c = new BasicCompositeConstraint(
649: operator);
650: if (c1 != null)
651: c.addChild(c1);
652: if (c2 != null)
653: c.addChild(c2);
654: return c;
655: }
656: }
657:
658: public void setConstraint(Constraint c) {
659: if (used)
660: throw new BridgeException("Query was used already");
661: query.setConstraint(c);
662: }
663:
664: public SortOrder addSortOrder(StepField f, int direction) {
665: return addSortOrder(f, direction, false);
666: }
667:
668: public SortOrder addSortOrder(StepField f, int direction,
669: boolean caseSensitive) {
670: return addSortOrder(f, direction, caseSensitive, -1);
671: }
672:
673: public SortOrder addSortOrder(StepField f, int direction,
674: boolean caseSensitive, int part) {
675: if (used)
676: throw new BridgeException("Query was used already");
677: if (f == null)
678: throw new BridgeException(
679: "Cannot add sortorder on 'null' step field");
680: BasicSortOrder o = query.addSortOrder(f);
681: o.setDirection(direction);
682: o.setCaseSensitive(caseSensitive);
683: if (o instanceof BasicDateSortOrder) {
684: ((BasicDateSortOrder) o).setPart(part);
685: }
686: return o;
687: }
688:
689: /**
690: * @since MMBase-1.7.1
691: */
692: public void addNode(Step s, int nodeNumber) {
693: if (used)
694: throw new BridgeException("Query was used already");
695: BasicStep step = (BasicStep) s;
696: if (step == null)
697: throw new IllegalArgumentException("Step may not be null");
698: step.addNode(nodeNumber);
699: return;
700: }
701:
702: public void addNode(Step s, Node node) {
703: addNode(s, node.getNumber());
704: }
705:
706: public boolean isUsed() {
707: return used;
708: }
709:
710: public boolean markUsed() {
711: boolean wasUsed = used;
712: if (queryCheck == null) { // if called manually
713: /// XXXX CASTING HERE. Is this really necessary!
714: // apply security constraints first, if not yet done, because the query gets unmodifiable from now on.
715: //((BasicCloud) cloud).setSecurityConstraint(this);
716: }
717: used = true;
718: return wasUsed;
719: }
720:
721: boolean isSecure() {
722: return queryCheck != null && queryCheck.isChecked();
723: }
724:
725: /**
726: * Applies a security-constraint to this Query. Such a constraint can be removed easily (needed
727: * before cloning a query and so on).
728: * @see #removeSecurityConstraint
729: */
730: void setSecurityConstraint(Authorization.QueryCheck c) {
731: if (queryCheck != null) {
732: throw new BridgeException(
733: "Already a security constraints set");
734: }
735: if (insecureConstraint != null) {
736: throw new BridgeException(
737: "Already a insecure constraint defined");
738: }
739: if (c == null) {
740: throw new BridgeException("QueryCheck may not be null");
741: }
742: if (log.isDebugEnabled()) {
743: log.debug("Setting security check " + c + " TO " + this );
744: }
745: queryCheck = c;
746:
747: insecureConstraint = query.getConstraint(); // current constraint
748: Constraint secureConstraint = queryCheck.getConstraint();
749: if (secureConstraint != null) {
750: if (insecureConstraint != null) {
751: BasicCompositeConstraint compConstraint = new BasicCompositeConstraint(
752: CompositeConstraint.LOGICAL_AND);
753: compConstraint.addChild(insecureConstraint);
754: compConstraint.addChild(secureConstraint);
755: query.setConstraint(compConstraint);
756: } else {
757: query.setConstraint(secureConstraint);
758: }
759: }
760: }
761:
762: /**
763: * Remove a previously set security constraint (if set one)
764: * @see #setSecurityConstraint
765: */
766: void removeSecurityConstraint() {
767: if (log.isDebugEnabled()) {
768: log.debug("Removing " + queryCheck + " FROM " + this );
769: }
770: if (queryCheck != null) {
771: query.setConstraint(insecureConstraint);
772: insecureConstraint = null;
773: }
774: queryCheck = null;
775:
776: }
777:
778: public Cloud getCloud() {
779: return cloud;
780: }
781:
782: public NodeList getList() {
783: return cloud.getList(this );
784: }
785:
786: @Override
787: public boolean equals(Object obj) {
788: return query.equals(obj);
789: }
790:
791: // javadoc is inherited
792: @Override
793: public int hashCode() {
794: return query.hashCode();
795: }
796:
797: @Override
798: public String toString() {
799: return query.toString() + (used ? "(used)" : "") + "INSECURE: "
800: + insecureConstraint + " QUERYCHECK: " + queryCheck;
801:
802: }
803:
804: public String toSql() {
805: try {
806: return MMBase.getMMBase().getSearchQueryHandler()
807: .createSqlString(query);
808: } catch (org.mmbase.storage.search.SearchQueryException sqe) {
809: return sqe.getMessage() + ": " + toString();
810: } catch (Exception ise) {
811: return ise.getMessage() + ": " + toString();
812: }
813:
814: }
815:
816: }
|