KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > bridge > implementation > BasicCloud


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10
11 package org.mmbase.bridge.implementation;
12 import java.util.*;
13 import java.io.*;
14 import org.mmbase.bridge.*;
15 import org.mmbase.bridge.util.Queries;
16 import org.mmbase.cache.*;
17 import org.mmbase.module.core.*;
18 import org.mmbase.module.corebuilders.*;
19
20 import org.mmbase.security.*;
21 import org.mmbase.storage.search.*;
22 import org.mmbase.util.*;
23 import org.mmbase.util.functions.*;
24 import org.mmbase.util.logging.*;
25
26 /**
27  * Basic implementation of Cloud. It wraps a.o. the core's ClusterBuilder and Typedef functionalities.
28  *
29  * @author Rob Vermeulen
30  * @author Pierre van Rooden
31  * @author Michiel Meeuwissen
32  * @version $Id: BasicCloud.java,v 1.161.2.2 2006/12/02 17:44:32 nklasens Exp $
33  */

34 public class BasicCloud implements Cloud, Cloneable JavaDoc, Comparable JavaDoc, SizeMeasurable, Serializable {
35
36     private static final long serialVersionUID = 1;
37
38     private static final Logger log = Logging.getLoggerInstance(BasicCloud.class);
39
40     // lastRequestId
41
// used to generate a temporary ID number
42
// The Id starts at - 2 and is decremented each time a new id is asked
43
// until Integer.MIN_VALUE is reached (after which counting starts again at -2).
44
private static int lastRequestId = Integer.MIN_VALUE;
45
46     // link to cloud context
47
private CloudContext cloudContext = null;
48
49     // name of the cloud
50
protected String JavaDoc name = null;
51
52     // account of the current user (unique)
53
// This is a unique number, unrelated to the user context
54
// It is meant to uniquely identify this session to MMBase
55
// It is NOT used for authorisation!
56
protected String JavaDoc account = null;
57
58     // description
59
// note: in future, this is dependend on language settings!
60
protected String JavaDoc description = null;
61
62     // all transactions started by this cloud object (with createTransaction)
63
protected Map transactions = new HashMap();
64
65     // node managers cache
66
protected Map nodeManagerCache = new HashMap();
67
68     MMBaseCop mmbaseCop = null;
69
70     protected UserContext userContext = null;
71
72     private HashMap properties = new HashMap();
73
74     private Locale locale;
75
76     public int getByteSize() {
77         return getByteSize(new SizeOf());
78     }
79
80     public int getByteSize(SizeOf sizeof) {
81         return sizeof.sizeof(transactions) + sizeof.sizeof(nodeManagerCache);
82     }
83
84     /**
85      * basic constructor for descendant clouds (i.e. Transaction)
86      * @param cloudName name of cloud
87      * @param cloud parent cloud
88      */

89     BasicCloud(String JavaDoc cloudName, BasicCloud cloud) {
90         cloudContext = cloud.cloudContext;
91         locale = cloud.locale;
92         name = cloudName;
93         description = cloud.description;
94         mmbaseCop = cloud.mmbaseCop;
95
96         userContext = cloud.userContext;
97         account = cloud.account;
98     }
99
100     /**
101      * @param name name of cloud
102      * @param authenticationType authentication type
103      * @param loginInfo Map with login credentials
104      * @param cloudContext cloudContext of cloud
105      * @throws NotFoundException If MMBase not yet started, or shutting down.
106      * @throws BridgeException No security could be obtained.
107      * @throws SecurityException Could not perform login
108      */

109     BasicCloud(String JavaDoc name, String JavaDoc authenticationType, Map loginInfo, CloudContext cloudContext) {
110         // get the cloudcontext and mmbase root...
111
this.cloudContext = (BasicCloudContext) cloudContext;
112         init();
113         userContext = mmbaseCop.getAuthentication().login(authenticationType, loginInfo, null);
114         if (userContext == null) {
115             log.debug("Login failed");
116             throw new java.lang.SecurityException JavaDoc("Login invalid (login-module: " + authenticationType + ")");
117         }
118         // end authentication...
119

120         if (userContext.getAuthenticationType() == null) {
121             log.warn("Security implementation did not set 'authentication type' in the user object.");
122         }
123
124         // normally, we want the cloud to read it's context from an xml file.
125
// the current system does not support multiple clouds yet,
126
// so as a temporary hack we set default values
127
this.name = name;
128         description = name;
129     }
130
131     /**
132      * @param name name of cloud
133      * @param authenticationType authentication type
134      * @param loginInfo Map with login credentials
135      * @param cloudContext cloudContext of cloud
136      * @throws NotFoundException If MMBase not yet started, or shutting down.
137      * @throws BridgeException No security could be obtained.
138      * @throws SecurityException Could not perform login
139      */

140     BasicCloud(String JavaDoc name, UserContext user, CloudContext cloudContext) {
141         // get the cloudcontext and mmbase root...
142
this.cloudContext = cloudContext;
143         init();
144         userContext = user;
145         if (userContext == null) {
146             throw new java.lang.SecurityException JavaDoc("Login invalid: did not supply user object");
147         }
148
149         if (userContext.getAuthenticationType() == null) {
150             log.warn("Security implementation did not set 'authentication type' in the user object.");
151         }
152
153         this.name = name;
154         description = name;
155     }
156
157     private final void init() {
158         MMBase mmb = BasicCloudContext.mmb;
159
160         if (! mmb.getState()) {
161             throw new NotFoundException("MMBase not yet, or not successfully initialized (check mmbase log)");
162         }
163
164         if (mmb.isShutdown()) {
165             throw new NotFoundException("MMBase is shutting down.");
166         }
167
168         log.debug("Doing authentication");
169         mmbaseCop = mmb.getMMBaseCop();
170
171         if (mmbaseCop == null) {
172             throw new BridgeException("Couldn't find the MMBaseCop. Perhaps your MMBase did not start up correctly; check application server and mmbase logs ");
173         }
174         log.debug("Setting up cloud object");
175         locale = mmb.getLocale();
176
177         // generate an unique id for this instance...
178
account = "U" + uniqueId();
179     }
180
181     // Makes a node or Relation object based on an MMObjectNode
182
BasicNode makeNode(MMObjectNode node, String JavaDoc nodeNumber) {
183         int nodenr = node.getNumber();
184         MMObjectBuilder parent = node.getBuilder();
185         if (nodenr == -1) {
186             int nodeid = Integer.parseInt(nodeNumber);
187             if (parent instanceof TypeDef) {
188                 return new BasicNodeManager(node, this, nodeid);
189             } else if (parent instanceof RelDef || parent instanceof TypeRel) {
190                 return new BasicRelationManager(node, this, nodeid);
191             } else if (parent instanceof InsRel) {
192                 return new BasicRelation(node, this, nodeid);
193             } else {
194                 return new BasicNode(node, this, nodeid);
195             }
196         } else {
197             this.verify(Operation.READ, nodenr);
198             if (parent instanceof TypeDef) {
199                 return new BasicNodeManager(node, this);
200             } else if (parent instanceof RelDef || parent instanceof TypeRel) {
201                 return new BasicRelationManager(node, this);
202             } else if (parent instanceof InsRel) {
203                 return new BasicRelation(node, this);
204             } else {
205                 return new BasicNode(node, this);
206             }
207         }
208     }
209
210     public Node getNode(String JavaDoc nodeNumber) throws NotFoundException {
211         MMObjectNode node;
212         try {
213             node = BasicCloudContext.tmpObjectManager.getNode(account, nodeNumber);
214         } catch (RuntimeException JavaDoc e) {
215             throw new NotFoundException("Something went wrong while getting node with number '" + nodeNumber + "': " + e.getMessage() + " by cloud with account " + account, e);
216         }
217         if (node == null) {
218             throw new NotFoundException("Node with number '" + nodeNumber + "' does not exist.");
219         } else {
220             return makeNode(node, nodeNumber);
221         }
222     }
223
224     public final Node getNode(int nodeNumber) throws NotFoundException {
225         return getNode("" + nodeNumber);
226     }
227
228     public final Node getNodeByAlias(String JavaDoc aliasname) throws NotFoundException {
229         return getNode(aliasname);
230     }
231
232     public final Relation getRelation(int nodeNumber) throws NotFoundException {
233         return getRelation("" + nodeNumber);
234     }
235
236     public final Relation getRelation(String JavaDoc nodeNumber) throws NotFoundException {
237         return (Relation)getNode(nodeNumber);
238     }
239
240     public boolean hasNode(int nodeNumber) {
241         return hasNode("" + nodeNumber, false);
242     }
243
244     public boolean hasNode(String JavaDoc nodeNumber) {
245         return nodeNumber != null && hasNode(nodeNumber, false);
246     }
247
248     // check if anode exists.
249
// if isrelation is true, the method returns false if the node is not a relation
250
private boolean hasNode(String JavaDoc nodeNumber, boolean isrelation) {
251         MMObjectNode node;
252         try {
253             node = BasicCloudContext.tmpObjectManager.getNode(account, nodeNumber);
254         } catch (Throwable JavaDoc e) {
255             return false; // error - node inaccessible or does not exist
256
}
257         if (node == null) {
258             return false; // node does not exist
259
} else {
260             if (isrelation && !(node.getBuilder() instanceof InsRel)) {
261                 return false;
262             }
263             return true;
264         }
265     }
266
267     public boolean hasRelation(int nodeNumber) {
268         return hasNode("" + nodeNumber, true);
269     }
270
271     public boolean hasRelation(String JavaDoc nodeNumber) {
272         return hasNode(nodeNumber, true);
273     }
274
275     public NodeManagerList getNodeManagers() {
276         List nodeManagers = new ArrayList();
277         for (Iterator builders = BasicCloudContext.mmb.getBuilders().iterator(); builders.hasNext();) {
278             MMObjectBuilder bul = (MMObjectBuilder)builders.next();
279             if (!bul.isVirtual() && check(Operation.READ, bul.getNumber())) {
280                 nodeManagers.add(bul.getTableName());
281             }
282         }
283         return new BasicNodeManagerList(nodeManagers, this);
284     }
285
286     /**
287      * @since MMBase-1.8
288      */

289     BasicNodeManager getBasicNodeManager(MMObjectBuilder bul) throws NotFoundException {
290         String JavaDoc nodeManagerName = bul.getTableName();
291         // cache quicker, and you don't get 2000 nodetypes when you do a search....
292
BasicNodeManager nodeManager = (BasicNodeManager)nodeManagerCache.get(nodeManagerName);
293         if (nodeManager == null) {
294             // not found in cache
295
nodeManager = new BasicNodeManager(bul, this);
296             nodeManagerCache.put(nodeManagerName, nodeManager);
297         } else if (nodeManager.getMMObjectBuilder() != bul) {
298             // cache differs
299
nodeManagerCache.remove(nodeManagerName);
300             nodeManager = new BasicNodeManager(bul, this);
301             nodeManagerCache.put(nodeManagerName, nodeManager);
302         }
303         return nodeManager;
304     }
305
306     BasicNodeManager getBasicNodeManager(String JavaDoc nodeManagerName) throws NotFoundException {
307         MMObjectBuilder bul = BasicCloudContext.mmb.getMMObject(nodeManagerName);
308         // always look if builder exists, since otherwise
309
if (bul == null) {
310             throw new NotFoundException("Node manager with name '" + nodeManagerName + "' does not exist.");
311         }
312         return getBasicNodeManager(bul);
313
314     }
315
316     public final NodeManager getNodeManager(String JavaDoc nodeManagerName) throws NotFoundException {
317         return getBasicNodeManager(nodeManagerName);
318     }
319
320     public boolean hasNodeManager(String JavaDoc nodeManagerName) {
321         return BasicCloudContext.mmb.getMMObject(nodeManagerName) != null;
322     }
323
324     /**
325      * Retrieves a node manager
326      * @param nodeManagerId ID of the NodeManager to retrieve
327      * @return the requested <code>NodeManager</code> if the manager exists, <code>null</code> otherwise
328      * @throws NotFoundException node manager not found
329      */

330     public NodeManager getNodeManager(int nodeManagerId) throws NotFoundException {
331         TypeDef typedef = BasicCloudContext.mmb.getTypeDef();
332         return getNodeManager(typedef.getValue(nodeManagerId));
333     }
334
335     /**
336      * Retrieves a RelationManager.
337      * Note that you can retrieve a manager with source and destination reversed.
338      * @param sourceManagerId number of the NodeManager of the source node
339      * @param destinationManagerId number of the NodeManager of the destination node
340      * @param roleId number of the role
341      * @return the requested RelationManager
342      */

343     RelationManager getRelationManager(int sourceManagerId, int destinationManagerId, int roleId) {
344         Set set = BasicCloudContext.mmb.getTypeRel().getAllowedRelations(sourceManagerId, destinationManagerId, roleId);
345         if (set.size() > 0) {
346             Iterator i = set.iterator();
347             MMObjectNode typeRel = (MMObjectNode) i.next();
348             if (set.size() > 1 && (sourceManagerId != -1 || destinationManagerId != -1)) {
349                 int quality =
350                     (typeRel.getIntValue("snumber") == sourceManagerId ? 1 : 0) +
351                     (typeRel.getIntValue("dnumber") == destinationManagerId ? 1 : 0);
352
353                 while(i.hasNext()) {
354                     MMObjectNode candidate = (MMObjectNode) i.next();
355                     int candidateQuality =
356                         (candidate.getIntValue("snumber") == sourceManagerId ? 1 : 0) +
357                         (candidate.getIntValue("dnumber") == destinationManagerId ? 1 : 0);
358                     if (candidateQuality > quality) {
359                         typeRel = candidate;
360                         quality = candidateQuality;
361                     }
362                 }
363             }
364
365             return new BasicRelationManager(typeRel, this);
366         } else {
367             log.error("Relation " + sourceManagerId + "/" + destinationManagerId + "/" + roleId + " does not exist", new Exception JavaDoc());
368             return null; // calling method throws exception
369
}
370     }
371
372     public RelationManager getRelationManager(int number) throws NotFoundException {
373         MMObjectNode n = BasicCloudContext.mmb.getTypeDef().getNode(number);
374         if (n == null) {
375             throw new NotFoundException("Relation manager with number " + number + " does not exist.");
376         }
377         if ((n.getBuilder() instanceof RelDef) || (n.getBuilder() instanceof TypeRel)) {
378             return new BasicRelationManager(n, this);
379         } else {
380             throw new NotFoundException("Node with number " + number + " is not a relation manager.");
381         }
382     }
383
384     public RelationManagerList getRelationManagers() {
385         List v = BasicCloudContext.mmb.getTypeRel().getNodes();
386         return new BasicRelationManagerList(v, this);
387     }
388
389     public RelationManager getRelationManager(String JavaDoc sourceManagerName, String JavaDoc destinationManagerName, String JavaDoc roleName) throws NotFoundException {
390         int r = BasicCloudContext.mmb.getRelDef().getNumberByName(roleName);
391         if (r == -1) {
392             throw new NotFoundException("Role '" + roleName + "' does not exist.");
393         }
394         // other settings of the cloud...
395
TypeDef typedef = BasicCloudContext.mmb.getTypeDef();
396
397         int n1 = typedef.getIntValue(sourceManagerName);
398         if (n1 == -1) {
399             throw new NotFoundException("Source type '" + sourceManagerName + "' does not exist.");
400         }
401         int n2 = typedef.getIntValue(destinationManagerName);
402         if (n2 == -1) {
403             throw new NotFoundException("Destination type '" + destinationManagerName + "' does not exist.");
404         }
405         RelationManager rm = getRelationManager(n1, n2, r);
406         if (rm == null) {
407             throw new NotFoundException("Relation manager from '" + sourceManagerName + "' to '" + destinationManagerName + "' as '" + roleName + "' does not exist.");
408         } else {
409             return rm;
410         }
411     }
412
413     public RelationManager getRelationManager(NodeManager source, NodeManager destination, String JavaDoc roleName) throws NotFoundException {
414         int r = BasicCloudContext.mmb.getRelDef().getNumberByName(roleName);
415         if (r == -1) {
416             throw new NotFoundException("Role '" + roleName + "' does not exist.");
417         }
418         RelationManager rm = getRelationManager(source.getNumber(), destination.getNumber(), r);
419         if (rm == null) {
420             throw new NotFoundException("Relation manager from '" + source + "' to '" + destination + "' as '" + roleName + "' does not exist.");
421         } else {
422             return rm;
423         }
424
425     }
426
427     public boolean hasRelationManager(String JavaDoc sourceManagerName, String JavaDoc destinationManagerName, String JavaDoc roleName) {
428         int r = BasicCloudContext.mmb.getRelDef().getNumberByName(roleName);
429         if (r == -1) return false;
430         TypeDef typedef = BasicCloudContext.mmb.getTypeDef();
431         int n1 = typedef.getIntValue(sourceManagerName);
432         if (n1 == -1) return false;
433         int n2 = typedef.getIntValue(destinationManagerName);
434         if (n2 == -1) return false;
435
436         return BasicCloudContext.mmb.getTypeRel().contains(n1, n2, r);
437         // return getRelationManager(n1, n2, r) != null;
438
}
439
440     public boolean hasRole(String JavaDoc roleName) {
441         return BasicCloudContext.mmb.getRelDef().getNumberByName(roleName) != -1;
442     }
443
444     public boolean hasRelationManager(NodeManager source, NodeManager destination, String JavaDoc roleName) {
445         int r = BasicCloudContext.mmb.getRelDef().getNumberByName(roleName);
446         if (r == -1) return false;
447         return BasicCloudContext.mmb.getTypeRel().contains(source.getNumber(), destination.getNumber(), r);
448         // return getRelationManager(source.getNumber(), destination.getNumber(), r) != null;
449
}
450
451     public RelationManager getRelationManager(String JavaDoc roleName) throws NotFoundException {
452         int r = BasicCloudContext.mmb.getRelDef().getNumberByName(roleName);
453         if (r == -1) {
454             throw new NotFoundException("Role '" + roleName + "' does not exist.");
455         }
456         return getRelationManager(r);
457     }
458
459     public RelationManagerList getRelationManagers(String JavaDoc sourceManagerName, String JavaDoc destinationManagerName, String JavaDoc roleName) throws NotFoundException {
460         NodeManager n1 = null;
461         if (sourceManagerName != null)
462             n1 = getNodeManager(sourceManagerName);
463         NodeManager n2 = null;
464         if (destinationManagerName != null)
465             n2 = getNodeManager(destinationManagerName);
466         return getRelationManagers(n1, n2, roleName);
467     }
468
469     public RelationManagerList getRelationManagers(NodeManager sourceManager, NodeManager destinationManager, String JavaDoc roleName) throws NotFoundException {
470         if (sourceManager != null) {
471             return sourceManager.getAllowedRelations(destinationManager, roleName, null);
472         } else if (destinationManager != null) {
473             return destinationManager.getAllowedRelations(sourceManager, roleName, null);
474         } else if (roleName != null) {
475             int r = BasicCloudContext.mmb.getRelDef().getNumberByName(roleName);
476             if (r == -1) {
477                 throw new NotFoundException("Role '" + roleName + "' does not exist.");
478             }
479             Vector v = BasicCloudContext.mmb.getTypeRel().searchVector("rnumber==" + r);
480             return new BasicRelationManagerList(v, this);
481         } else {
482             return getRelationManagers();
483         }
484     }
485
486     public boolean hasRelationManager(String JavaDoc roleName) {
487         return BasicCloudContext.mmb.getRelDef().getNumberByName(roleName) != -1;
488     }
489
490     /**
491      * Create unique temporary node number.
492      * The Id starts at - 2 and is decremented each time a new id is asked
493      * until Integer.MINVALUE is reached (after which counting starts again at -2).
494      * @todo This may be a temporary solution. It may be desirable to immediately reserve a
495      * number at the database layer, so resolving (by the transaction) will not be needed.
496      * However, this needs some changes in the TemporaryNodeManager and the classes that make use of this.
497      *
498      * @return the temporary id as an integer
499      */

500     static synchronized int uniqueId() {
501         if (lastRequestId > Integer.MIN_VALUE) {
502             lastRequestId--;
503         } else {
504             lastRequestId = -2;
505         }
506         return lastRequestId;
507     }
508
509     /**
510      * Test if a node id is a temporay id.
511      * @param id the id (node numebr) to test
512      * @return true if the id is a temporary id
513      * @since MMBase-1.5
514      */

515     static boolean isTemporaryId(int id) {
516         return id < -1;
517     }
518
519     public Transaction createTransaction() {
520         return createTransaction(null, false);
521     }
522
523     public Transaction createTransaction(String JavaDoc name) throws AlreadyExistsException {
524         return createTransaction(name, false);
525     }
526
527     public Transaction createTransaction(String JavaDoc name, boolean overwrite) throws AlreadyExistsException {
528         if (name == null) {
529             name = "Tran" + uniqueId();
530         } else {
531             Transaction oldtransaction = (Transaction)transactions.get(name);
532             if (oldtransaction != null) {
533                 if (overwrite) {
534                     oldtransaction.cancel();
535                 } else {
536                     throw new AlreadyExistsException("Transaction with name " + name + "already exists.");
537                 }
538             }
539         }
540         Transaction transaction = new BasicTransaction(name, this);
541         transactions.put(name, transaction);
542         return transaction;
543     }
544
545     public Transaction getTransaction(String JavaDoc name) {
546         Transaction tran = (Transaction)transactions.get(name);
547         if (tran == null) {
548             tran = createTransaction(name, false);
549         } else {
550         }
551         return tran;
552     }
553
554     public CloudContext getCloudContext() {
555         return cloudContext;
556     }
557
558     public String JavaDoc getName() {
559         return name;
560     }
561
562     public String JavaDoc getDescription() {
563         return description;
564     }
565
566     public UserContext getUser() {
567         return userContext;
568     }
569
570     /**
571      * Retrieves the current user accountname (unique)
572      * @return the account name
573      */

574     String JavaDoc getAccount() {
575         return account;
576     }
577
578     /**
579     * Checks access rights.
580     * @param operation the operation to check (READ, WRITE, CREATE, OWN)
581     * @param nodeID the node on which to check the operation
582     * @return <code>true</code> if access is granted, <code>false</code> otherwise
583     */

584     boolean check(Operation operation, int nodeID) {
585         return mmbaseCop != null && mmbaseCop.getAuthorization().check(userContext, nodeID, operation);
586     }
587
588     /**
589     * Asserts access rights. throws an exception if an operation is not allowed.
590     * @param operation the operation to check (READ, WRITE, CREATE, OWN)
591     * @param nodeID the node on which to check the operation
592     */

593     void verify(Operation operation, int nodeID) {
594         while (mmbaseCop == null) {
595             synchronized(this) {
596                 if (mmbaseCop == null) {
597                     throw new org.mmbase.security.SecurityException("No MMBaseCop"); // mmbase cop can be null if deserialization not yet ready.
598
}
599             }
600         }
601         mmbaseCop.getAuthorization().verify(userContext, nodeID, operation);
602     }
603
604     /**
605     * Checks access rights.
606     * @param operation the operation to check (CREATE, CHANGE_RELATION)
607     * @param nodeID the node on which to check the operation
608     * @param srcNodeID the source node for this relation
609     * @param dstNodeID the destination node for this relation
610     * @return <code>true</code> if access is granted, <code>false</code> otherwise
611     */

612     boolean check(Operation operation, int nodeID, int srcNodeID, int dstNodeID) {
613         return mmbaseCop != null && mmbaseCop.getAuthorization().check(userContext, nodeID, srcNodeID, dstNodeID, operation);
614     }
615
616     /**
617     * Asserts access rights. throws an exception if an operation is not allowed.
618     * @param operation the operation to check (CREATE, CHANGE_RELATION)
619     * @param nodeID the node on which to check the operation
620     * @param srcNodeID the source node for this relation
621     * @param dstNodeID the destination node for this relation
622     */

623     void verify(Operation operation, int nodeID, int srcNodeID, int dstNodeID) {
624         mmbaseCop.getAuthorization().verify(userContext, nodeID, srcNodeID, dstNodeID, operation);
625     }
626
627     // javadoc inherited
628
public NodeList getList(Query query) {
629         log.debug("get List");
630         NodeList result;
631         if (query.isAggregating()) { // should this perhaps be a seperate method? --> Then also 'isAggregating' not needed any more
632
result = getResultNodeList(query);
633         } else {
634             result = getSecureList(query);
635         }
636         if (query instanceof NodeQuery) {
637             NodeQuery nq = (NodeQuery) query;
638             String JavaDoc pref = nq.getNodeStep().getAlias();
639             if (pref == null) pref = nq.getNodeStep().getTableName();
640             result.setProperty(NodeList.NODESTEP_PROPERTY, pref);
641         }
642         return result;
643     }
644
645     /*
646     // javadoc inherited
647     public NodeList getList(NodeQuery query) {
648         return getSecureNodes(query);
649     }
650     */

651
652
653     /**
654      * Aggregating query result.
655      * @param query query to execute
656      * @return list of nodes
657      * @since MMBase-1.7
658      */

659     protected NodeList getResultNodeList(Query query) {
660         log.debug("Resultnode list");
661         try {
662
663             boolean checked = setSecurityConstraint(query);
664
665             if (! checked) {
666                 log.warn("Query " + query + " could not be completely modified by security: Aggregated result might be wrong");
667             }
668             Cache cache = AggregatedResultCache.getCache();
669
670             List resultList = (List) cache.get(query);
671             if (resultList == null) {
672                 ResultBuilder resultBuilder = new ResultBuilder(BasicCloudContext.mmb, query);
673                 resultList = BasicCloudContext.mmb.getSearchQueryHandler().getNodes(query, resultBuilder);
674                 cache.put(query, resultList);
675             }
676             query.markUsed();
677             NodeManager tempNodeManager = new VirtualNodeManager(query, this);
678             NodeList resultNodeList = new BasicNodeList(resultList, tempNodeManager);
679             resultNodeList.setProperty(NodeList.QUERY_PROPERTY, query);
680             return resultNodeList;
681         } catch (SearchQueryException sqe) {
682             throw new BridgeException(sqe);
683         }
684     }
685
686     /**
687      * Result with all Cluster - MMObjectNodes, with cache. Security is not considered here (the
688      * query is executed thoughtlessly). The security check is done in getSecureNodes, which calls
689      * this one.
690      * @param query query to execute
691      * @return list of cluster nodes
692      * @since MMBase-1.7
693      */

694     protected List getClusterNodes(Query query) {
695
696         // start multilevel cache
697
Cache multilevelCache = MultilevelCache.getCache();
698
699         ClusterBuilder clusterBuilder = BasicCloudContext.mmb.getClusterBuilder();
700         // check multilevel cache if needed
701
List resultList = null;
702         if (query.getCachePolicy().checkPolicy(query)) {
703             resultList = (List)multilevelCache.get(query);
704         }
705         // if unavailable, obtain from database
706
if (resultList == null) {
707             log.debug("result list is null, getting from database");
708             try {
709                 resultList = clusterBuilder.getClusterNodes(query);
710             } catch (SearchQueryException sqe) {
711                 throw new BridgeException(query.toString() + ":" + sqe.getMessage(), sqe);
712             }
713             if (query.getCachePolicy().checkPolicy(query)) {
714                 multilevelCache.put(query, resultList);
715             }
716         }
717
718         query.markUsed();
719
720         return resultList;
721     }
722
723     /**
724      * @param query add security constaint to this query
725      * @return is query secure
726      * @since MMBase-1.7
727      */

728     boolean setSecurityConstraint(Query query) {
729         if (mmbaseCop == null) return false;
730         Authorization auth = mmbaseCop.getAuthorization();
731         if (query instanceof BasicQuery) { // query should alway be 'BasicQuery' but if not, for some on-fore-seen reason..
732
BasicQuery bquery = (BasicQuery) query;
733             if (bquery.isSecure()) { // already set, and secure
734
return true;
735             } else {
736                 if (bquery.queryCheck == null) { // not set already, do it now.
737
Authorization.QueryCheck check = auth.check(userContext, query, Operation.READ);
738                     if (log.isDebugEnabled()) {
739                         log.debug("FOUND security check " + check + " FOR " + query);
740                     }
741                     bquery.setSecurityConstraint(check);
742                 }
743                 return bquery.isSecure();
744             }
745         } else {
746             // should not happen
747
if (query != null) {
748                 log.warn("Don't know how to set a security constraint on a " + query.getClass().getName());
749             } else {
750                 log.warn("Don't know how to set a security constraint on NULL");
751             }
752         }
753         return false;
754     }
755
756     public StringList getPossibleContexts() {
757         return new BasicStringList(mmbaseCop.getAuthorization().getPossibleContexts(getUser()));
758     }
759
760     void checkNodes(BasicNodeList resultNodeList, Query query) {
761         Authorization auth = mmbaseCop.getAuthorization();
762         resultNodeList.autoConvert = false; // make sure no conversion to Node happen, until we are ready.
763

764         if (log.isDebugEnabled()) {
765             log.trace(resultNodeList);
766         }
767
768         log.debug("Starting read-check");
769         // resultNodeList is now a BasicNodeList; read restriction should only be applied now
770
// assumed it though, that it contain _only_ MMObjectNodes..
771

772         // get authorization for this call only
773

774         List steps = query.getSteps();
775         Step nodeStep = null;
776         if (query instanceof NodeQuery) {
777             nodeStep = ((NodeQuery) query).getNodeStep();
778         }
779         log.debug("Creating iterator");
780         ListIterator li = resultNodeList.listIterator();
781         while (li.hasNext()) {
782             log.debug("next");
783             Object JavaDoc o = li.next();
784             if (log.isDebugEnabled()) {
785                 log.debug(o.getClass().getName());
786             }
787             MMObjectNode node = (MMObjectNode)o;
788             boolean mayRead = true;
789             for (int j = 0; mayRead && (j < steps.size()); ++j) {
790                 Step step = (Step) steps.get(j);
791                 int nodenr;
792                 if (step.equals(nodeStep)) {
793                     nodenr = node.getIntValue("number");
794                 } else {
795                     String JavaDoc pref = step.getAlias();
796                     if (pref == null) {
797                         pref = step.getTableName();
798                     }
799                     nodenr = node.getIntValue(pref + ".number");
800                 }
801                 if (nodenr != -1) {
802                     mayRead = auth.check(userContext, nodenr, Operation.READ);
803                 }
804             }
805
806             if (!mayRead) {
807                 li.remove();
808             }
809         }
810         resultNodeList.autoConvert = true;
811
812
813     }
814
815
816     /**
817      * Result with Cluster Nodes (checked security)
818      * @param query query to execute
819      * @return lisr of cluster nodes
820      * @since MMBase-1.7
821      */

822     protected NodeList getSecureList(Query query) {
823
824         boolean checked = setSecurityConstraint(query);
825
826         List resultList = getClusterNodes(query);
827
828         if (log.isDebugEnabled()) {
829             log.debug("Creating NodeList of size " + resultList.size());
830         }
831
832         // create resultNodeList
833
NodeManager tempNodeManager = new VirtualNodeManager(query, this);
834
835         BasicNodeList resultNodeList = new BasicNodeList(resultList, tempNodeManager);
836         resultNodeList.setProperty(NodeList.QUERY_PROPERTY, query);
837
838         if (! checked) {
839             checkNodes(resultNodeList, query);
840         }
841
842         return resultNodeList;
843     }
844
845     //javadoc inherited
846
public NodeList getList(
847         String JavaDoc startNodes,
848         String JavaDoc nodePath,
849         String JavaDoc fields,
850         String JavaDoc constraints,
851         String JavaDoc orderby,
852         String JavaDoc directions,
853         String JavaDoc searchDir,
854         boolean distinct) {
855
856         if ((nodePath==null) || nodePath.equals("")) throw new BridgeException("Node path cannot be empty - list at least one nodemanager.");
857         Query query = Queries.createQuery(this, startNodes, nodePath, fields, constraints, orderby, directions, searchDir, distinct);
858         return getList(query);
859     }
860
861
862     public void setLocale(Locale l) {
863         if (l == null) {
864             locale = new Locale(BasicCloudContext.mmb.getLanguage(), "");
865         } else {
866             locale = l;
867         }
868     }
869     public Locale getLocale() {
870         return locale;
871     }
872
873     public boolean mayRead(int nodeNumber) {
874         return mayRead(nodeNumber + "");
875     }
876
877     public boolean mayRead(String JavaDoc nodeNumber) {
878         MMObjectNode node;
879         try {
880             node = BasicCloudContext.tmpObjectManager.getNode(account, nodeNumber);
881         } catch (RuntimeException JavaDoc e) {
882             throw new NotFoundException("Something went wrong while getting node with number '" + nodeNumber + "': " + e.getMessage(), e);
883         }
884         if (node == null) {
885             throw new NotFoundException("Node with number '" + nodeNumber + "' does not exist.");
886         } else {
887             int nodenr = node.getNumber();
888             if (nodenr == -1) {
889                 return true; // temporary node
890
} else {
891                 return check(Operation.READ, node.getNumber()); // check read access
892
}
893         }
894     }
895
896     // javadoc inherited
897
public Query createQuery() {
898         return new BasicQuery(this);
899     }
900
901     public NodeQuery createNodeQuery() {
902         return new BasicNodeQuery(this);
903     }
904
905
906     public Query createAggregatedQuery() {
907         return new BasicQuery(this, true);
908     }
909
910
911
912
913     /**
914      * Based on multi-level query. Returns however 'normal' nodes based on the last step. This is a
915      * protected function, which is used in the implemetnedion of getRelatedNodes, getRelations of
916      * NodeManager
917      *
918      * Before it executes the query, the fields of the query are checked. All and only fields of the
919      * 'last' NodeManager and the relation should be queried. If fields are present already, but
920      * not like this, an exception is thrown. If not fields are present, the rights fields are added
921      * first (if the query is still unused, otherwise trhows Exception).
922      * @param query query to execute
923      * @return list of normal nodes
924      *
925      * @throws BridgeException If wrong fields in query or could not be added.
926      *
927      * @since MMBase-1.7
928      */

929     protected NodeList getLastStepList(Query query) {
930         return null;
931     }
932
933
934     /**
935      * Compares this cloud to the passed object.
936      * Returns 0 if they are equal, -1 if the object passed is a Cloud and larger than this cloud,
937      * and +1 if the object passed is a Cloud and smaller than this cloud.
938      * @todo There is no specific order in which clouds are ordered at this moment.
939      * Currently, all clouds within one CloudContext are treated as being equal.
940      * @param o the object to compare it with
941      * @return compare number
942      */

943     public int compareTo(Object JavaDoc o) {
944         int h1 = ((Cloud)o).getCloudContext().hashCode();
945         int h2 = cloudContext.hashCode();
946
947         // mm: why not simply return h2 - h1?
948

949         if (h1 > h2) {
950             return -1;
951         } else if (h1 < h2) {
952             return 1;
953         } else {
954             return 0;
955         }
956     }
957
958     /**
959      * Compares this cloud to the passed object, and returns true if they are equal.
960      * @todo Add checks for multiple clouds in the same cloudcontext
961      * Currently, all clouds within one CloudContext are treated as being equal.
962      * @param o the object to compare it with
963      * @return is equal
964      */

965     public boolean equals(Object JavaDoc o) {
966         // XXX: Currently, all clouds (i.e. transactions/user clouds) within a CloudContext
967
// are treated as the 'same' cloud. This may change in future implementations
968
if (o instanceof Cloud) {
969             Cloud oc = (Cloud) o;
970             return cloudContext.equals(oc.getCloudContext()) && userContext.equals(oc.getUser());
971         } else {
972             return false;
973         }
974     }
975
976     public Object JavaDoc getProperty(Object JavaDoc key) {
977         return properties.get(key);
978     }
979
980     public void setProperty(Object JavaDoc key, Object JavaDoc value) {
981         properties.put(key, value);
982     }
983
984     public Map getProperties() {
985         return Collections.unmodifiableMap(properties);
986     }
987
988     public Collection getFunctions(String JavaDoc setName) {
989         FunctionSet set = FunctionSets.getFunctionSet(setName);
990         if (set == null) {
991             throw new NotFoundException("Functionset with name " + setName + "does not exist.");
992         }
993         // get functions
994
return set.getFunctions();
995     }
996
997     public Function getFunction(String JavaDoc setName, String JavaDoc functionName) {
998         FunctionSet set = FunctionSets.getFunctionSet(setName);
999         if (set == null) {
1000            throw new NotFoundException("Functionset with name '" + setName + "' does not exist.");
1001        }
1002        Function fun = set.getFunction(functionName);
1003        if (fun == null) {
1004            throw new NotFoundException("Function with name '" + functionName + "' does not exist in function set with name '"+ setName + "'.");
1005        }
1006        return fun;
1007    }
1008
1009    public NodeList createNodeList() {
1010        return new BasicNodeList(Collections.EMPTY_LIST, this);
1011    }
1012
1013    public RelationList createRelationList() {
1014        return new BasicRelationList(Collections.EMPTY_LIST, this);
1015    }
1016
1017    public NodeManagerList createNodeManagerList() {
1018        return new BasicNodeManagerList(Collections.EMPTY_LIST, this);
1019    }
1020
1021    public RelationManagerList createRelationManagerList() {
1022        return new BasicRelationManagerList(Collections.EMPTY_LIST, this);
1023    }
1024
1025    /**
1026     * Checks wether the current transaction contains the given node.
1027     */

1028    boolean contains(MMObjectNode node) {
1029        return false;
1030    }
1031
1032    /**
1033     * Ignored by basic cloud. See {@link BasicTransaction#add(String)}.
1034     */

1035    void add(String JavaDoc currentObjectContext) {
1036    }
1037
1038    /**
1039     * Ignored by basic cloud. See {@link BasicTransaction#remove(String)}.
1040     */

1041    void remove(String JavaDoc currentObjectContext) {
1042    }
1043
1044    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException JavaDoc {
1045        name = in.readUTF();
1046        userContext = (UserContext)in.readObject();
1047        cloudContext = LocalContext.getCloudContext();
1048        description = name;
1049        properties = (HashMap) in.readObject();
1050        locale = (Locale) in.readObject();
1051        org.mmbase.util.ThreadPools.jobsExecutor.execute(new BasicCloudStarter());
1052        transactions = new HashMap();
1053        nodeManagerCache = new HashMap();
1054    }
1055
1056
1057    private void writeObject(ObjectOutputStream out) throws IOException {
1058        out.writeUTF(name);
1059        out.writeObject(userContext);
1060        HashMap props = new HashMap();
1061        Iterator i = properties.entrySet().iterator();
1062        while(i.hasNext()) {
1063            Map.Entry entry = (Map.Entry) i.next();
1064            Object JavaDoc key = entry.getKey();
1065            Object JavaDoc value = entry.getValue();
1066            if ((key instanceof Serializable) && (value instanceof Serializable)) {
1067                props.put(key, value);
1068            }
1069        }
1070        out.writeObject(props);
1071        out.writeObject(locale);
1072        log.service("Serialized cloud " + BasicCloud.this + " of " + BasicCloud.this.getUser());
1073    }
1074
1075    class BasicCloudStarter implements Runnable JavaDoc {
1076        public void run() {
1077            synchronized(BasicCloud.this) {
1078                LocalContext.getCloudContext().assertUp();
1079                BasicCloud.this.init();
1080                if (BasicCloud.this.userContext == null) {
1081                    throw new java.lang.SecurityException JavaDoc("Login invalid: did not supply user object");
1082                }
1083                if (BasicCloud.this.userContext.getAuthenticationType() == null) {
1084                    log.warn("Security implementation did not set 'authentication type' in the user object.");
1085                }
1086                log.service("Deserialized " + BasicCloud.this);
1087            }
1088        }
1089    }
1090
1091    public String JavaDoc toString() {
1092        return "BasicCloud '" + getName() + "' of " + getUser().getIdentifier() + " @" + Integer.toHexString(hashCode());
1093    }
1094}
1095
Popular Tags