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 org.mmbase.security.*;
014: import org.mmbase.bridge.*;
015: import org.mmbase.module.core.*;
016: import org.mmbase.util.logging.*;
017:
018: /**
019: * @javadoc
020: *
021: * @author Rob Vermeulen
022: * @author Pierre van Rooden
023: * @version $Id: BasicRelation.java,v 1.43 2007/02/10 15:47:42 nklasens Exp $
024: */
025: public class BasicRelation extends BasicNode implements Relation {
026: private static final Logger log = Logging
027: .getLoggerInstance(BasicRelation.class);
028:
029: private RelationManager relationManager = null;
030: protected int snum;
031: protected int dnum;
032:
033: private static final int UNSET = -999;
034:
035: private int sourceNodeType = UNSET;
036: private int destinationNodeType = UNSET;
037:
038: protected boolean relationChanged = false; // Indicates a change in snum or dnum
039:
040: /**
041: * @javadoc
042: */
043: BasicRelation(MMObjectNode node, BasicCloud cloud) {
044: super (node, cloud);
045: }
046:
047: /**
048: * @javadoc
049: */
050: BasicRelation(MMObjectNode node, BasicRelationManager nodeManager) {
051: super (node, nodeManager);
052: }
053:
054: /**
055: * @javadoc
056: */
057: BasicRelation(MMObjectNode node, BasicCloud cloud, int id) {
058: super (node, cloud, id);
059: }
060:
061: @Override
062: public final boolean isRelation() {
063: return true;
064: }
065:
066: @Override
067: public Relation toRelation() {
068: return this ;
069: }
070:
071: /**
072: * Initializes the node.
073: * Determines nodemanager and cloud (depending on information available),
074: * Sets references to MMBase modules and initializes state in case of a transaction.
075: */
076: @Override
077: protected void init() {
078: super .init();
079: if (nodeManager instanceof RelationManager) {
080: relationManager = (RelationManager) nodeManager;
081: }
082: snum = getIntValue("snumber");
083: dnum = getIntValue("dnumber");
084:
085: }
086:
087: public Node getSource() {
088: // Note that this will not return an accurate value when the field is
089: // edited during a transaction.
090: return nodeManager.getCloud().getNode(snum);
091: }
092:
093: public Node getDestination() {
094: // Note that this will not return an accurate value when the field is
095: // edited during a transaction.
096: return nodeManager.getCloud().getNode(dnum);
097: }
098:
099: public void setSource(Node node) {
100: if (node.getCloud() != cloud) {
101: throw new BridgeException(
102: "Source and relation are not in the same transaction or from different clouds.");
103: }
104: relationChanged = true;
105: int source = node.getIntValue("number");
106: if (source == -1) {
107: // set a temporary field, transactionmanager resolves this
108: getNode().setValue("_snumber",
109: node.getValue(MMObjectBuilder.TMP_FIELD_NUMBER));
110: } else {
111: getNode().setValue("snumber", source);
112: }
113: snum = node.getNumber();
114: sourceNodeType = node.getIntValue("otype");
115: }
116:
117: public void setDestination(Node node) {
118: if (node.getCloud() != cloud) {
119: throw new BridgeException(
120: "Destination and relation are not in the same transaction or from different clouds.");
121: }
122: relationChanged = true;
123: int dest = node.getIntValue("number");
124: if (dest == -1) {
125: // set a temporary field, transactionmanager resolves this
126: getNode().setValue("_dnumber",
127: node.getValue(MMObjectBuilder.TMP_FIELD_NUMBER));
128: } else {
129: getNode().setValue("dnumber", dest);
130: }
131: dnum = node.getNumber();
132: destinationNodeType = node.getIntValue("otype");
133: }
134:
135: public RelationManager getRelationManager() {
136: if (relationManager == null) {
137: int stypenum = BasicCloudContext.mmb.getTypeRel()
138: .getNodeType(snum);
139: int dtypenum = BasicCloudContext.mmb.getTypeRel()
140: .getNodeType(dnum);
141: if (log.isDebugEnabled()) {
142: log.debug(stypenum + ", " + dtypenum + ", "
143: + getNode().getIntValue("rnumber"));
144: }
145:
146: relationManager = cloud.getRelationManager(stypenum,
147: dtypenum, getNode().getIntValue("rnumber"));
148: }
149: return relationManager;
150: }
151:
152: /**
153: *
154: * @javadoc
155: */
156: void checkValid() {
157: if (log.isDebugEnabled()) {
158: log.debug("s: " + snum + " d: " + dnum + " st: "
159: + sourceNodeType + " dt: " + destinationNodeType);
160: }
161: //int snumber = snumtype.getNumber();
162: //int dnumber = dnumtype.getNumber();
163:
164: if (sourceNodeType == UNSET) {
165: sourceNodeType = -1;
166: if (snum != -1)
167: sourceNodeType = BasicCloudContext.mmb.getTypeDef()
168: .getNodeType(snum);
169: }
170: if (destinationNodeType == UNSET) {
171: destinationNodeType = -1;
172: if (dnum != -1)
173: destinationNodeType = BasicCloudContext.mmb
174: .getTypeDef().getNodeType(dnum);
175: }
176:
177: int rnumber = getNode().getIntValue("rnumber");
178: if (!BasicCloudContext.mmb.getTypeRel().contains(
179: sourceNodeType, destinationNodeType, rnumber)) {
180: if (!BasicCloudContext.mmb.getTypeRel().contains(
181: destinationNodeType, sourceNodeType, rnumber)) {
182: if (!cloud.hasNode(sourceNodeType)) {
183: throw new BridgeException(
184: "Source type of relation "
185: + this
186: + ": "
187: + sourceNodeType
188: + " does not point to a valid node.");
189: }
190: if (!cloud.hasNode(destinationNodeType)) {
191: throw new BridgeException(
192: "Destination type of relation "
193: + this
194: + ": "
195: + destinationNodeType
196: + " does not point to a valid node.");
197: }
198: if (!cloud.hasNode(rnumber)) {
199: throw new BridgeException("Rnumber of relation "
200: + this + ": " + rnumber
201: + " does not point to a valid node.");
202: }
203: throw new BridgeException(
204: "Source and/or Destination node are not of the correct type, or relation not allowed ("
205: + cloud.getNode(sourceNodeType)
206: .getValue("name")
207: + " ("
208: + snum
209: + "),"
210: + cloud.getNode(destinationNodeType)
211: .getValue("name")
212: + " ("
213: + dnum
214: + "),"
215: + cloud.getNode(rnumber).getValue(
216: "sname") + ")");
217: }
218: }
219:
220: }
221:
222: @Override
223: public void setValueWithoutProcess(String fieldName, Object value) {
224: checkWrite();
225: if ("rnumber".equals(fieldName)) {
226: throw new BridgeException("Not allowed to change field '"
227: + fieldName + "'.");
228: } else if ("snumber".equals(fieldName)
229: || "dnumber".equals(fieldName)) {
230: relationChanged = true;
231: }
232: super .setValueWithoutProcess(fieldName, value);
233: }
234:
235: @Override
236: public void commit() {
237: // Check types of source and destination
238: // Normally, this check would be run in the core.
239: // However, the current system mdoes not throw an exception when a wrong
240: // node is created, we want to do this so for them moment
241: // we perform this check here.
242: // Note that we do not realign the node since InsRel does it for us,
243: // but we DO update snum and dnum.
244: //
245: // XXX:This check should ultimately be removed, once we have an agreement
246: // on throwing the exception in the core
247:
248: checkValid();
249: if (!(BasicCloud.isTemporaryId(snum) || BasicCloud
250: .isTemporaryId(dnum))) {
251: if (isNew()) {
252: cloud
253: .verify(Operation.CREATE, BasicCloudContext.mmb
254: .getTypeDef().getIntValue(
255: getNodeManager().getName()),
256: snum, dnum);
257: relationChanged = false;
258: } else {
259: if (relationChanged) {
260: cloud.verify(Operation.CHANGE_RELATION, noderef
261: .getNumber(), snum, dnum);
262: relationChanged = false;
263: }
264: }
265: }
266: super .commit();
267: if (!(cloud instanceof Transaction)) {
268: snum = getNode().getIntValue("snumber");
269: dnum = getNode().getIntValue("dnumber");
270: }
271: }
272:
273: }
|