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: package org.mmbase.bridge.implementation;
011:
012: import java.util.*;
013:
014: import org.mmbase.bridge.*;
015: import org.mmbase.storage.search.*;
016: import org.mmbase.storage.search.implementation.*;
017:
018: /**
019: * 'Basic' implementation of bridge NodeQuery. Wraps a Query with all and only fields of one
020: * Step. If there is only one step, this can wrap NodeSearchQuery of core.
021: *
022: * Often, queries with more steps are sensible nodequeries, because sorting (e.g. posrel.pos) or
023: * filtering can be done on those steps (e.g. publishtimes).
024: *
025: * Nodes of this type can be used as an argument to function which do return 'real' nodes (so not clusternodes).
026: *
027: * @todo perhaps it would be nice to have the possibllity to query also two complete steps (also one of the neigbouring 'relation' steps).
028: * this would give nice efficient implementations of things like mm:relatednode (of mm:listrelations)
029: *
030: * @todo This kind of functionality should perhaps be present in NodeSearchQuery itself because you can then use it 'under' the bridge too.
031: *
032: * @author Michiel Meeuwissen
033: * @version $Id: BasicNodeQuery.java,v 1.33 2007/02/11 20:42:32 nklasens Exp $
034: * @since MMBase-1.7
035: * @see org.mmbase.storage.search.implementation.NodeSearchQuery
036: */
037: public class BasicNodeQuery extends BasicQuery implements NodeQuery {
038:
039: protected Step step = null;
040:
041: BasicNodeQuery(Cloud c) {
042: super (c);
043: }
044:
045: /**
046: * node query.
047: */
048: BasicNodeQuery(BasicNodeManager nodeManager) {
049: super (nodeManager.cloud);
050: query = new NodeSearchQuery(nodeManager.getMMObjectBuilder());
051: this .step = getSteps().get(0); // the only step
052: }
053:
054: BasicNodeQuery(BasicNodeManager nodeManager, NodeSearchQuery q) {
055: super (nodeManager.cloud);
056: query = q;
057: this .step = getSteps().get(0); // the only step
058: }
059:
060: /**
061: * Makes a multi-step node-query, based on a normal query. As a default, all fields of last steps are added (if at least there are steps already)
062: *
063: */
064: BasicNodeQuery(Cloud cloud, SearchQuery q) {
065: super (cloud);
066: query = new BasicSearchQuery(q);
067: List<Step> steps = query.getSteps();
068: if (steps.size() > 0) {
069: setNodeStep((steps.get(steps.size() - 1)));
070: }
071: }
072:
073: public NodeManager getNodeManager() {
074: if (step == null)
075: return null;
076: if (step instanceof RelationStep) {
077: RelationStep rs = (RelationStep) step;
078: int role = -1;
079: Integer roleValue = rs.getRole();
080: if (roleValue != null) {
081: role = roleValue.intValue();
082: }
083: String roleName = role > 0 ? cloud.getNode(role)
084: .getStringValue("sname") : null;
085: NodeManager previous = cloud.getNodeManager(rs
086: .getPrevious().getTableName());
087: NodeManager next = cloud.getNodeManager(rs.getNext()
088: .getTableName());
089: if (cloud.hasRelationManager(previous, next, roleName)) {
090: return cloud.getRelationManager(previous, next,
091: roleName);
092: } else {
093: if (roleName == null) {
094: return cloud.getNodeManager("insrel"); // not a relation manager, no role known
095: } else {
096: return cloud.getRelationManager(roleName);
097: }
098: }
099: } else {
100: return cloud.getNodeManager(step.getTableName());
101: }
102: }
103:
104: public Step getNodeStep() {
105: return step;
106: }
107:
108: // overridden from BasicQuery (a node query does not have '.' in its field names)
109: @Override
110: public StepField createStepField(String fieldName) {
111: if (fieldName.indexOf('.') == -1) {
112: BasicStepField stepField = (BasicStepField) getStepField(getNodeManager()
113: .getField(fieldName));
114: // stepField.setAlias(fieldName);
115: if (stepField == null)
116: throw new NotFoundException("No field '" + fieldName
117: + "' found in " + getSteps());
118: return stepField;
119: } else {
120: // It does contain dot? Perhaps one of the other steps.
121: return super .createStepField(fieldName);
122: }
123: }
124:
125: public StepField getStepField(Field field) {
126: if (query instanceof NodeSearchQuery) {
127: BasicStepField stepField = ((NodeSearchQuery) query)
128: .getField(((BasicField) field).coreField);
129: return stepField;
130: } else {
131: Iterator<StepField> fields = query.getFields().iterator();
132: while (fields.hasNext()) {
133: StepField stepField = fields.next();
134: if (stepField.getStep().equals(step)) {
135: if (stepField.getFieldName()
136: .equals(field.getName())) {
137: return stepField;
138: }
139: }
140:
141: }
142: }
143: //throw new NotFoundException("Could not find field '" + field + "' in " + this);
144: return null; // hmm.
145: }
146:
147: @Override
148: public void removeFields() {
149: explicitFields.clear();
150: setNodeStep(step);
151: }
152:
153: public List<StepField> getExtraFields() {
154: return Collections.unmodifiableList(explicitFields);
155: }
156:
157: /**
158: * Adds all fields of the gives collection, unless it is a field of the 'step' itself
159: */
160: protected void addFields(Collection<StepField> c) {
161: Iterator<StepField> i = c.iterator();
162: while (i.hasNext()) {
163: BasicStepField sf = (BasicStepField) i.next();
164: Step addedStep = sf.getStep();
165: if (addedStep.equals(step))
166: continue; // these are among the node-fields already
167: query.addField(addedStep, sf.getField());
168: }
169: }
170:
171: // overrides setDistinct of super, because it should consider 'step' Fields.
172: @Override
173: public Query setDistinct(boolean distinct) {
174: if (used)
175: throw new BridgeException("Query was used already");
176: query.setDistinct(distinct);
177: if (distinct) { // in that case, make sure only the 'explicitely' added fields remain.
178: query.removeFields();
179: query.addFields(step);
180: implicitFields.clear();
181: addFields(explicitFields);
182: }
183: return this ;
184: }
185:
186: public Step setNodeStep(Step step) {
187: assert query.getSteps().contains(step);
188: if (this .step == null && step == null)
189: return null;
190: if (this .step != null && this .step.equals(step))
191: return this .step; // already this step.
192: // Make sure the query _starts_ with the Node-fields.
193: // otherwise BasicQueryHandler.getNodes could do it wrong...
194: query.removeFields();
195: query.addFields(step);
196: addFields(explicitFields);
197: Step prevStep = this .step;
198: this .step = step;
199: if (!isDistinct()) {
200: addFields(implicitFields);
201: }
202: return prevStep;
203: }
204:
205: @Override
206: public Query cloneWithoutFields() {
207: BasicSearchQuery bsq = new BasicSearchQuery(query,
208: BasicSearchQuery.COPY_WITHOUTFIELDS);
209: if (queryCheck != null) {
210: removeSecurityConstraintFromClone(bsq);
211: }
212: BasicNodeQuery clone = new BasicNodeQuery(cloud, bsq);
213: clone.used = false;
214: clone.aggregating = false;
215: return clone;
216: }
217:
218: @Override
219: public NodeList getList() {
220: return getNodeManager().getList(this);
221: }
222:
223: }
|