Source Code Cross Referenced for TypeRel.java in  » Database-ORM » MMBase » org » mmbase » module » corebuilders » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database ORM » MMBase » org.mmbase.module.corebuilders 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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.module.corebuilders;
011:
012:        import java.util.*;
013:
014:        import org.mmbase.bridge.Field;
015:        import org.mmbase.util.*;
016:        import org.mmbase.module.core.*;
017:        import org.mmbase.core.CoreField;
018:        import org.mmbase.core.event.Event;
019:        import org.mmbase.core.event.NodeEvent;
020:        import org.mmbase.core.util.Fields;
021:        import org.mmbase.cache.*;
022:        import org.mmbase.storage.search.implementation.BasicRelationStep;
023:        import org.mmbase.storage.search.RelationStep;
024:
025:        import org.mmbase.util.logging.Logger;
026:        import org.mmbase.util.logging.Logging;
027:
028:        /**
029:         * TypeRel defines the allowed relations between two object types. Every relations also specifies a
030:         * 'role', which is a reference to the RelDef table.
031:         *
032:         * Relations do principally have a 'source' and a 'destination' object type, but most functions of
033:         * this class do ignore this distinction.
034:         *
035:         * TypeRel is a 'core' MMBase builder. You can get a reference to it via the MMBase instance.
036:         *
037:         * @author Daniel Ockeloen
038:         * @author Pierre van Rooden
039:         * @author Michiel Meeuwissen
040:         * @version $Id: TypeRel.java,v 1.78 2008/02/20 17:12:28 michiel Exp $
041:         * @see RelDef
042:         * @see InsRel
043:         * @see org.mmbase.module.core.MMBase
044:         */
045:        public class TypeRel extends MMObjectBuilder {
046:
047:            private static final Logger log = Logging
048:                    .getLoggerInstance(TypeRel.class);
049:
050:            /**
051:             * Constant for {@link #contains}: return only typerels that exactly match.
052:             */
053:            public static final int STRICT = 0;
054:
055:            /**
056:             * Constant for {@link #contains}: return typerels where source/destination match with a
057:             * builder or its descendants
058:             */
059:            public static final int INCLUDE_DESCENDANTS = 1;
060:
061:            /**
062:             * Constant for {@link #contains}: return typerels where source/destination match with a
063:             * builder or its parents
064:             */
065:            public static final int INCLUDE_PARENTS = 2;
066:
067:            /**
068:             * Constant for {@link #contains}: return typerels where source/destination match with a
069:             * builder, its descendants, or its parents
070:             */
071:            public static final int INCLUDE_PARENTS_AND_DESCENDANTS = 3;
072:
073:            /**
074:             * TypeRel should contain only a limited amount of nodes, so we can simply cache them all, and
075:             * avoid all further querying.
076:             */
077:            protected TypeRelSet typeRelNodes; // for searching destinations
078:
079:            protected TypeRelSet parentTypeRelNodes; // for caching typerels for 'parent'
080:
081:            // builders
082:
083:            public InverseTypeRelSet inverseTypeRelNodes; // for searching sources
084:
085:            public boolean init() {
086:                if (oType != -1)
087:                    return true;
088:                super .init();
089:                // during init not yet all builder are available so inhertiance is not
090:                // yet possible
091:                // This means that calls to getAllowedRelations do not consider
092:                // inheritance during initializion of MMBase.
093:                // This occurs e.g. in one of the Community-builders.
094:                readCache(false);
095:                return true;
096:            }
097:
098:            /**
099:             * The TypeRel cache contains all TypeRels MMObjectNodes. Called after init by MMBase, and when
100:             * something changes.
101:             * @since MMBase-1.6.2
102:             */
103:            public void readCache() {
104:                readCache(true);
105:            }
106:
107:            /**
108:             * @since MMBase-1.6.2
109:             */
110:            private void readCache(boolean buildersInitialized) {
111:                log.debug("Reading in typerels");
112:                typeRelNodes = new TypeRelSet();
113:                parentTypeRelNodes = new TypeRelSet();
114:                inverseTypeRelNodes = new InverseTypeRelSet();
115:
116:                TypeDef typeDef = mmb.getTypeDef();
117:                typeDef.init();
118:                // Find all typerel nodes
119:                List<MMObjectNode> alltypes = getNodes();
120:                for (MMObjectNode typerel : alltypes) {
121:                    addCacheEntry(typerel, buildersInitialized);
122:                }
123:                log.debug("Done reading typerel cache "
124:                        + (buildersInitialized ? "(considered inheritance)"
125:                                : "") + ": " + typeRelNodes);
126:            }
127:
128:            /**
129:             * Addes one typerel cache entries, plus inherited relations (if builder are initialized)
130:             * @return A Set with the added entries, which can be used for logging or so, or can be
131:             * disregarded
132:             * @since MMBase-1.6.2
133:             */
134:            protected TypeRelSet addCacheEntry(MMObjectNode typeRel,
135:                    boolean buildersInitialized) {
136:
137:                TypeRelSet added = new TypeRelSet(); // store temporary, which will enable nice logging of what happened
138:
139:                // Start to add the actual definition, this is then afterwards again,
140:                // except if one of the builders could not be found
141:                added.add(typeRel);
142:
143:                RelDef reldef = mmb.getRelDef();
144:
145:                MMObjectNode reldefNode = reldef.getNode(typeRel
146:                        .getIntValue("rnumber"));
147:                if (reldefNode == null) {
148:                    throw new RuntimeException(
149:                            "Could not find reldef-node for rnumber= "
150:                                    + typeRel.getIntValue("rnumber"));
151:                }
152:
153:                boolean bidirectional = (!InsRel.usesdir)
154:                        || (reldefNode.getIntValue("dir") > 1);
155:
156:                inheritance: if (buildersInitialized) { // handle inheritance, which is
157:                    // not possible during
158:                    // initialization of MMBase.
159:
160:                    TypeDef typeDef = mmb.getTypeDef();
161:
162:                    String sourceBuilderName = typeDef.getValue(typeRel
163:                            .getIntValue("snumber"));
164:                    MMObjectBuilder sourceBuilder = sourceBuilderName != null ? mmb
165:                            .getBuilder(sourceBuilderName)
166:                            : null;
167:
168:                    String destinationBuilderName = typeDef.getValue(typeRel
169:                            .getIntValue("dnumber"));
170:                    MMObjectBuilder destinationBuilder = destinationBuilderName != null ? mmb
171:                            .getBuilder(destinationBuilderName)
172:                            : null;
173:
174:                    if (sourceBuilder == null) {
175:                        if (destinationBuilder == null) {
176:                            log
177:                                    .warn("Both source and destination of "
178:                                            + typeRel
179:                                            + " are not active builders. Cannot follow descendants.");
180:                        } else {
181:                            log
182:                                    .warn("The source of relation type "
183:                                            + typeRel
184:                                            + " is not an active builder. Cannot follow descendants.");
185:                        }
186:                        break inheritance;
187:                    }
188:
189:                    if (destinationBuilder == null) {
190:                        log
191:                                .warn("The destination of relation type "
192:                                        + typeRel
193:                                        + " is not an active builder. Cannot follow descendants.");
194:                        break inheritance;
195:                    }
196:
197:                    int rnumber = typeRel.getIntValue("rnumber");
198:
199:                    List<MMObjectBuilder> sources = sourceBuilder
200:                            .getDescendants();
201:                    sources.add(sourceBuilder);
202:
203:                    List<MMObjectBuilder> destinations = destinationBuilder
204:                            .getDescendants();
205:                    destinations.add(destinationBuilder);
206:
207:                    Iterator<MMObjectBuilder> i = sources.iterator();
208:                    while (i.hasNext()) {
209:                        MMObjectBuilder s = i.next();
210:                        Iterator<MMObjectBuilder> j = destinations.iterator();
211:                        while (j.hasNext()) {
212:                            MMObjectBuilder d = j.next();
213:                            MMObjectNode vnode = new VirtualTypeRelNode(s
214:                                    .getNumber(), d.getNumber(), rnumber);
215:                            added.add(vnode);
216:                        }
217:                    }
218:
219:                    // seek all parents and store typerels for them
220:                    // this cache is used by contains(INCLUDE_PARENTS /
221:                    // INCLUDE_PARENTS_AND_DESCENDANTS));
222:                    MMObjectBuilder sourceParent = sourceBuilder;
223:                    while (sourceParent != null) {
224:                        MMObjectBuilder destinationParent = destinationBuilder;
225:                        while (destinationParent != null) {
226:                            MMObjectNode vnode = new VirtualTypeRelNode(
227:                                    sourceParent.getNumber(), destinationParent
228:                                            .getNumber(), rnumber);
229:                            parentTypeRelNodes.add(vnode);
230:                            destinationParent = destinationParent
231:                                    .getParentBuilder();
232:                        }
233:                        sourceParent = sourceParent.getParentBuilder();
234:                    }
235:                    added.add(typeRel); // replaces the ones added in the 'inheritance'
236:                    // loop (so now not any more Virtual)
237:                }
238:                Iterator<MMObjectNode> i = added.iterator();
239:                while (i.hasNext()) {
240:                    MMObjectNode node = i.next();
241:                    if (!node.isVirtual()) {
242:                        // make sure 'real' nodes replace virtual nodes. (real and virtual nodes are equal, so will not be added to set otherwise)
243:                        // This is especially essential whey you use STRICT in contains
244:                        typeRelNodes.remove(node);
245:                        if (bidirectional)
246:                            inverseTypeRelNodes.remove(node);
247:                    }
248:                    typeRelNodes.add(node);
249:                    if (bidirectional)
250:                        inverseTypeRelNodes.add(node);
251:                }
252:                if (log.isDebugEnabled()) {
253:                    log.debug("Added to typerelcache: " + added);
254:                }
255:                return added;
256:            }
257:
258:            /**
259:             * Insert a new object (content provided) in the cloud, including an entry for the object alias
260:             * (if provided). This method indirectly calls {@link #preCommit}. If the typerel node
261:             * specified already exists (i.e. same snumber, dnumber,a nd rnumber fielfds), the typerel
262:             * creation fails and returns -1.
263:             * @param owner The administrator creating the node
264:             * @param node The object to insert. The object need be of the same type as the current builder.
265:             * @return An <code>int</code> value which is the new object's unique number, -1 if the insert
266:             * failed.
267:             */
268:            public int insert(String owner, MMObjectNode node) {
269:                int snumber = node.getIntValue("snumber");
270:                int dnumber = node.getIntValue("dnumber");
271:                int rnumber = node.getIntValue("rnumber");
272:                if (contains(snumber, dnumber, rnumber, STRICT)) {
273:                    log.error("The typerel with snumber=" + snumber
274:                            + ", dnumber=" + dnumber + ", rnumber=" + rnumber
275:                            + " already exists");
276:                    throw new RuntimeException("The typerel with snumber="
277:                            + snumber + ", dnumber=" + dnumber + ", rnumber="
278:                            + rnumber + " already exists");
279:                }
280:                int res = super .insert(owner, node);
281:                return res;
282:            }
283:
284:            /**
285:             * Remove a node from the cloud.
286:             * @param node The node to remove.
287:             */
288:            public void removeNode(MMObjectNode node) {
289:                super .removeNode(node);
290:            }
291:
292:            /**
293:             * Retrieves all relations which are 'allowed' for a specified node, that is, where the node is
294:             * either allowed to be the source, or to be the destination (but where the corresponing
295:             * relation definition is bidirectional). The allowed relations are determined by the type of
296:             * the node
297:             * @param node The node to retrieve the allowed relations of.
298:             * @return An <code>Enumeration</code> of nodes containing the typerel relation data
299:             */
300:            public Enumeration<MMObjectNode> getAllowedRelations(
301:                    MMObjectNode node) {
302:                return getAllowedRelations(node.getBuilder().getNumber());
303:            }
304:
305:            public Enumeration<MMObjectNode> getAllowedRelations(int otype) {
306:                Set<MMObjectNode> res = getAllowedRelations(otype, 0, 0,
307:                        RelationStep.DIRECTIONS_BOTH);
308:                return Collections.enumeration(res);
309:            }
310:
311:            /**
312:             * Retrieves all relations which are 'allowed' between two specified nodes. No distinction
313:             * between source / destination.
314:             * @param node1 The first objectnode
315:             * @param node2 The second objectnode
316:             * @return An <code>Enumeration</code> of nodes containing the typerel relation data
317:             */
318:            public Enumeration<MMObjectNode> getAllowedRelations(
319:                    MMObjectNode node1, MMObjectNode node2) {
320:                return getAllowedRelations(node1.getOType(), node2.getOType());
321:            }
322:
323:            /**
324:             * An enumeration of all allowed relations between two builders. No distinction is made between
325:             * source and destination.
326:             *
327:             */
328:            public Enumeration<MMObjectNode> getAllowedRelations(int builder1,
329:                    int builder2) {
330:                Set<MMObjectNode> res = getAllowedRelations(builder1, builder2,
331:                        0, RelationStep.DIRECTIONS_BOTH);
332:                return Collections.enumeration(res);
333:            }
334:
335:            /**
336:             * A Set of all allowed relations of a certain role between two builders. No distinction between
337:             * source and destination.
338:             *
339:             * @since MMBase-1.6.2
340:             */
341:            public Set<MMObjectNode> getAllowedRelations(int builder1,
342:                    int builder2, int role) {
343:                return getAllowedRelations(builder1, builder2, role,
344:                        RelationStep.DIRECTIONS_BOTH);
345:            }
346:
347:            /**
348:             * A Set of all allowed relations of a certain role between two builders. Distinction is made between
349:             * source and destination depending on passed directionality.
350:             *
351:             * @since MMBase-1.6.2
352:             */
353:            public Set<MMObjectNode> getAllowedRelations(int builder1,
354:                    int builder2, int role, int directionality) {
355:                Set<MMObjectNode> res = new HashSet<MMObjectNode>();
356:                if (directionality != RelationStep.DIRECTIONS_SOURCE) {
357:                    res.addAll(typeRelNodes.getBySourceDestinationRole(
358:                            builder1, builder2, role));
359:                }
360:                if (directionality != RelationStep.DIRECTIONS_DESTINATION
361:                        && (directionality != RelationStep.DIRECTIONS_EITHER || res
362:                                .isEmpty())) {
363:                    res.addAll(inverseTypeRelNodes.getByDestinationSourceRole(
364:                            builder2, builder1, role));
365:                }
366:                return res;
367:            }
368:
369:            /**
370:             * Retrieves all relations which are 'allowed' between two specified nodes.
371:             * @param snum The first objectnode type (the source)
372:             * @param dnum The second objectnode type (the destination)
373:             * @return An <code>Enumeration</code> of nodes containing the reldef (not typerel!) sname
374:             * field
375:             */
376:            protected Vector<String> getAllowedRelationsNames(int snum, int dnum) {
377:                Vector<String> results = new Vector<String>();
378:                for (Enumeration<MMObjectNode> e = getAllowedRelations(snum,
379:                        dnum); e.hasMoreElements();) {
380:                    MMObjectNode node = e.nextElement();
381:                    int rnumber = node.getIntValue("rnumber");
382:                    MMObjectNode snode = mmb.getRelDef().getNode(rnumber);
383:                    results.addElement(snode.getStringValue("sname"));
384:                }
385:                return results;
386:            }
387:
388:            /**
389:             * Retrieves the identifying number of the relation definition that is 'allowed' between two
390:             * specified node types. The results are dependent on there being only one type of relation
391:             * between two node types (not enforced, thus unpredictable). Makes use of a typeRelNodes.
392:             * @param snum The first objectnode type (the source)
393:             * @param dnum The second objectnode type (the destination)
394:             * @return the number of the found relation, or -1 if either no relation was found, or more than
395:             * one was found.
396:             */
397:            public int getAllowedRelationType(int snum, int dnum) {
398:                Set<MMObjectNode> set = new HashSet<MMObjectNode>(typeRelNodes
399:                        .getBySourceDestination(snum, dnum));
400:                set.addAll(inverseTypeRelNodes.getByDestinationSource(dnum,
401:                        snum));
402:
403:                if (set.size() != 1) {
404:                    return -1;
405:                } else {
406:                    MMObjectNode n = set.iterator().next();
407:                    return n.getIntValue("rnumber");
408:                }
409:            }
410:
411:            /**
412:             * Returns the display string for this node It returns a commbination of objecttypes and
413:             * rolename : "source->destination (role)".
414:             * @param node Node from which to retrieve the data
415:             * @return A <code>String</code> describing the content of the node
416:             */
417:            public String getGUIIndicator(MMObjectNode node) {
418:                try {
419:                    String source = mmb.getTypeDef().getValue(
420:                            node.getIntValue("snumber"));
421:                    String destination = mmb.getTypeDef().getValue(
422:                            node.getIntValue("dnumber"));
423:                    MMObjectNode role = mmb.getRelDef().getNode(
424:                            node.getIntValue("rnumber"));
425:                    return source + "->" + destination + " ("
426:                            + (role != null ? role.getGUIIndicator() : "???")
427:                            + ")";
428:                } catch (Exception e) {
429:                    log.warn(e);
430:                }
431:                return null;
432:            }
433:
434:            /**
435:             * Returns the display string for a specified field. Returns, for snumber and dnumber, the name
436:             * of the objecttype they represent, and for rnumber the display (GUI) string for the indicated
437:             * relation definition.
438:             * @param field The name of the field to retrieve
439:             * @param node Node from which to retrieve the data
440:             * @return A <code>String</code> describing the content of the field
441:             */
442:            public String getGUIIndicator(String field, MMObjectNode node) {
443:                try {
444:                    if (field.equals("snumber")) {
445:                        return mmb.getTypeDef().getValue(
446:                                node.getIntValue("snumber"));
447:                    } else if (field.equals("dnumber")) {
448:                        return mmb.getTypeDef().getValue(
449:                                node.getIntValue("dnumber"));
450:                    } else if (field.equals("rnumber")) {
451:                        MMObjectNode reldef = mmb.getRelDef().getNode(
452:                                node.getIntValue("rnumber"));
453:                        return (reldef != null ? reldef.getGUIIndicator()
454:                                : "???");
455:                    }
456:                } catch (Exception e) {
457:                }
458:                return null;
459:            }
460:
461:            /**
462:             * Processes the BUILDER-typerel-ALLOWEDRELATIONSNAMES in the LIST command, and (possibly)
463:             * returns a Vector containing requested data (based on the content of TYPE and NODE, which can
464:             * be retrieved through tagger).
465:             * @javadoc parameters
466:             */
467:            public Vector<String> getList(PageInfo sp, StringTagger tagger,
468:                    StringTokenizer tok) {
469:                if (tok.hasMoreTokens()) {
470:                    String cmd = tok.nextToken(); //Retrieving command.
471:                    if (cmd.equals("ALLOWEDRELATIONSNAMES")) {
472:                        try {
473:                            String tmp = tagger.Value("TYPE");
474:                            int number1 = mmb.getTypeDef().getIntValue(tmp);
475:                            tmp = tagger.Value("NODE");
476:                            int number2 = Integer.parseInt(tmp);
477:                            MMObjectNode node = getNode(number2);
478:                            return getAllowedRelationsNames(number1, node
479:                                    .getOType());
480:                        } catch (Exception e) {
481:                            log.error(e);
482:                        }
483:                    }
484:                }
485:                return null;
486:            }
487:
488:            /**
489:             * Tests if a specific relation type is defined.
490:             * <p>
491:             * Note that this routine returns false both when a snumber/dnumber are swapped, and when a
492:             * typecombo does not exist - it is not possible to derive whether one or the other has
493:             * occurred.
494:             * </p>
495:             * @deprecated use {@link #contains}instead
496:             * @param n1 The source type number.
497:             * @param n2 The destination type number.
498:             * @param r The relation definition (role) number, or -1 if the role does not matter
499:             * @return <code>true</code> when the relation exists, false otherwise.
500:             *
501:             */
502:            public boolean reldefCorrect(int n1, int n2, int r) {
503:                return contains(n1, n2, r);
504:            }
505:
506:            /**
507:             * Tests if a specific relation type is defined. The method also returns true if the typerel
508:             * occurs as a virtual (derived) node.
509:             * <p>
510:             * Note that this routine returns false both when a snumber/dnumber are swapped, and when a
511:             * typecombo does not exist - it is not possible to derive whether one or the other has
512:             * occurred.
513:             * <p>
514:             *
515:             * @param n1 The source type number.
516:             * @param n2 The destination type number.
517:             * @param r The relation definition (role) number, or -1 if the role does not matter
518:             * @return <code>true</code> when the relation exists, false otherwise.
519:             *
520:             * @since MMBase-1.6.2
521:             */
522:            public boolean contains(int n1, int n2, int r) {
523:                return contains(n1, n2, r, INCLUDE_DESCENDANTS);
524:            }
525:
526:            /**
527:             * Tests if a specific relation type is defined.
528:             * <p>
529:             * Note that this routine returns false both when a snumber/dnumber are swapped, and when a
530:             * typecombo does not exist - it is not possible to derive whether one or the other has
531:             * occurred.
532:             * <p>
533:             *
534:             * @param n1 The source type number.
535:             * @param n2 The destination type number.
536:             * @param r The relation definition (role) number, or -1 if the role does not matter r can only
537:             * be -1 if virtual is <code>true</code>
538:             * @param restriction if {@link #STRICT}, contains only returns true if the typerel occurs
539:             * as-is in the database. if {@link #INCLUDE_DESCENDANTS}, contains returns true if the typerel
540:             * occurs as a virtual (derived) node, where source or destination may also be descendants of
541:             * the specified type. if {@link #INCLUDE_PARENTS}, contains returns true if the typerel occurs
542:             * as a virtual (derived) node, where source or destination may also be parents of the specified
543:             * type. if {@link #INCLUDE_PARENTS_AND_DESCENDANTS}, contains returns true if the typerel
544:             * occurs as a virtual (derived) node, where source or destination may also be descendants or
545:             * parents of the specified type.
546:             * @return <code>true</code> when the relation exists, false otherwise.
547:             *
548:             * @since MMBase-1.6.2
549:             */
550:            public boolean contains(int n1, int n2, int r, int restriction) {
551:                switch (restriction) {
552:                case INCLUDE_DESCENDANTS:
553:                    return typeRelNodes.contains(new VirtualTypeRelNode(n1, n2,
554:                            r));
555:                case INCLUDE_PARENTS:
556:                    return parentTypeRelNodes.contains(new VirtualTypeRelNode(
557:                            n1, n2, r));
558:                case INCLUDE_PARENTS_AND_DESCENDANTS:
559:                    return typeRelNodes.contains(new VirtualTypeRelNode(n1, n2,
560:                            r))
561:                            || parentTypeRelNodes
562:                                    .contains(new VirtualTypeRelNode(n1, n2, r));
563:                case STRICT:
564:                    SortedSet<MMObjectNode> existingNodes = typeRelNodes
565:                            .getBySourceDestinationRole(n1, n2, r);
566:                    return (existingNodes.size() > 0 && !existingNodes.first()
567:                            .isVirtual());
568:                default:
569:                    log.error("Unknown restriction " + restriction);
570:                    return false;
571:                }
572:            }
573:
574:            /**
575:             * Watch for changes on relation types and adjust our memory table accordingly
576:             * @todo Should update artCache en relDefCorrectCache as wel
577:             */
578:            /*
579:             * (non-Javadoc)
580:             * @see org.mmbase.module.core.MMObjectBuilder#notify(org.mmbase.core.event.NodeEvent)
581:             */
582:            public void notify(NodeEvent event) {
583:                if (log.isDebugEnabled()) {
584:                    log.debug("Changed " + event.getMachine() + " "
585:                            + event.getNodeNumber() + " "
586:                            + event.getBuilderName() + " "
587:                            + NodeEvent.newTypeToOldType(event.getType()));
588:                }
589:                if (tableName.equals(event.getBuilderName())) {
590:                    if (event.getType() == Event.TYPE_NEW) {
591:                        Set<MMObjectNode> newTypeRels = addCacheEntry(
592:                                getNode(event.getNodeNumber()), true);
593:                        log.service("Added to typerelcache: " + newTypeRels);
594:                    } else {
595:                        //something else changed in a typerel node? reread the complete typeRelNodes Set
596:                        readCache();
597:                    }
598:                    // also, clear all query-caches, because result may change by this. See MMB-348
599:                    for (Cache qc : CacheManager.getMap().values()) {
600:                        if (qc instanceof  QueryResultCache) {
601:                            qc.clear();
602:                        }
603:                    }
604:                }
605:                super .notify(event);
606:            }
607:
608:            /**
609:             * Optimize as relation step by considering restrictions of TypeRel. TypeRel defines which type
610:             * of relations may be created, ergo can exist.
611:             *
612:             * @since MMBase-1.7
613:             */
614:            public boolean optimizeRelationStep(BasicRelationStep relationStep,
615:                    int sourceType, int destinationType, int roleInt,
616:                    int searchDir) {
617:                // Determine in what direction(s) this relation can be followed:
618:
619:                // Check directionality is requested and supported.
620:                if (searchDir != RelationStep.DIRECTIONS_ALL && InsRel.usesdir) {
621:                    relationStep.setCheckedDirectionality(true);
622:                }
623:
624:                // this is a bit confusing, can the simple cases like explicit 'source'
625:                // or 'destination' not be handled first?
626:
627:                boolean sourceToDestination = searchDir != RelationStep.DIRECTIONS_SOURCE
628:                        && contains(sourceType, destinationType, roleInt,
629:                                INCLUDE_PARENTS_AND_DESCENDANTS);
630:                boolean destinationToSource = searchDir != RelationStep.DIRECTIONS_DESTINATION
631:                        && contains(destinationType, sourceType, roleInt,
632:                                INCLUDE_PARENTS_AND_DESCENDANTS);
633:
634:                if (destinationToSource && sourceToDestination
635:                        && (searchDir == RelationStep.DIRECTIONS_EITHER)) {
636:                    // support old
637:                    destinationToSource = false;
638:                }
639:
640:                if (destinationToSource) {
641:                    // there is a typed relation from destination to src
642:                    if (sourceToDestination) {
643:                        // there is ALSO a typed relation from src to destination - make
644:                        // a more complex query
645:                        relationStep
646:                                .setDirectionality(RelationStep.DIRECTIONS_BOTH);
647:                    } else {
648:                        // there is ONLY a typed relation from destination to src -
649:                        // optimized query
650:                        relationStep
651:                                .setDirectionality(RelationStep.DIRECTIONS_SOURCE);
652:                    }
653:                } else {
654:                    if (sourceToDestination) {
655:                        // there is no typed relation from destination to src (assume a
656:                        // relation between src and destination) - optimized query
657:                        relationStep
658:                                .setDirectionality(RelationStep.DIRECTIONS_DESTINATION);
659:                    } else {
660:                        // no results possible, do something any way
661:                        if (searchDir == RelationStep.DIRECTIONS_SOURCE) {
662:                            // explicitely asked for source, it would be silly to try destination now
663:                            relationStep
664:                                    .setDirectionality(RelationStep.DIRECTIONS_SOURCE);
665:                        } else {
666:                            // the 'normal' way
667:                            relationStep
668:                                    .setDirectionality(RelationStep.DIRECTIONS_DESTINATION);
669:                        }
670:                        return false;
671:                    }
672:                }
673:                return true;
674:            }
675:
676:            /**
677:             * Implements equals for a typerel node. Two nodes are equal if the snumber and dnumber fields
678:             * are the same, and the rnumber fields are the same, or one of these is '-1' (don't care).
679:             * @since MMBase-1.6.2
680:             */
681:            public boolean equals(MMObjectNode o1, MMObjectNode o2) {
682:                if (o2.getBuilder() instanceof  TypeRel) {
683:                    int r1 = o1.getIntValue("rnumber");
684:                    int r2 = o2.getIntValue("rnumber");
685:                    return o1.getIntValue("snumber") == o2
686:                            .getIntValue("snumber")
687:                            && o1.getIntValue("dnumber") == o2
688:                                    .getIntValue("dnumber")
689:                            && (r1 == -1 || r2 == -1 || r1 == r2);
690:                }
691:                return false;
692:            }
693:
694:            /**
695:             * Implements for MMObjectNode
696:             * @since MMBase-1.6.2
697:             */
698:            public int hashCode(MMObjectNode o) {
699:                int result = 0;
700:                result = HashCodeUtil
701:                        .hashCode(result, o.getIntValue("snumber"));
702:                result = HashCodeUtil
703:                        .hashCode(result, o.getIntValue("dnumber"));
704:                result = HashCodeUtil
705:                        .hashCode(result, o.getIntValue("rnumber"));
706:                return result;
707:            }
708:
709:            public String toString(MMObjectNode n) {
710:                try {
711:                    int snumber = n.getIntValue("snumber");
712:                    int dnumber = n.getIntValue("dnumber");
713:                    int rnumber = n.getIntValue("rnumber");
714:
715:                    String sourceName = mmb.getTypeDef().getValue(snumber);
716:                    String destName = mmb.getTypeDef().getValue(dnumber);
717:
718:                    if (sourceName == null)
719:                        sourceName = "unknown builder '" + snumber + "'";
720:                    if (destName == null)
721:                        destName = "unknown builder '" + dnumber + "'";
722:
723:                    // unfilled should only happen during creation of the node.
724:                    String source = snumber > -1 ? sourceName : "[unfilled]";
725:                    String destination = dnumber > -1 ? destName : "[unfilled]";
726:                    MMObjectNode role = rnumber > -1 ? mmb.getRelDef().getNode(
727:                            rnumber) : null;
728:                    return source
729:                            + "->"
730:                            + destination
731:                            + " ("
732:                            + (role != null ? role.getStringValue("sname")
733:                                    : "???") + ") "
734:                            + (isVirtual() ? "(virtual)" : "");
735:                } catch (Exception e) {
736:                    log.warn(e);
737:                }
738:                return "typerel-node";
739:            }
740:
741:            /**
742:             * Of course, virtual typerel nodes need a virtual typerel builder. Well 'of course', the reason
743:             * is not quite obvious to me, it has to do with the bridge/temporarynodemanager which sometimes
744:             * needs to know it.
745:             *
746:             * @since MMBase-1.6.2
747:             */
748:            static class VirtualTypeRel extends TypeRel {
749:                static VirtualTypeRel virtualTypeRel = null;
750:
751:                VirtualTypeRel(TypeRel t) {
752:                    mmb = t.getMMBase();
753:                    CoreField field = Fields.createField("snumber",
754:                            Field.TYPE_NODE, Field.TYPE_UNKNOWN,
755:                            Field.STATE_VIRTUAL, null);
756:                    field.finish();
757:                    addField(field);
758:                    field = Fields.createField("dnumber", Field.TYPE_NODE,
759:                            Field.TYPE_UNKNOWN, Field.STATE_VIRTUAL, null);
760:                    field.finish();
761:                    addField(field);
762:                    field = Fields.createField("rnumber", Field.TYPE_NODE,
763:                            Field.TYPE_UNKNOWN, Field.STATE_VIRTUAL, null);
764:                    field.finish();
765:                    addField(field);
766:                    tableName = "virtual_typerel";
767:                    virtual = true;
768:                }
769:
770:                static VirtualTypeRel getVirtualTypeRel(TypeRel t) {
771:                    if (virtualTypeRel == null)
772:                        virtualTypeRel = new VirtualTypeRel(t);
773:                    return virtualTypeRel;
774:                }
775:            }
776:
777:            /**
778:             * A TypeRelSet is a Set of typerel nodes. The TypeRel builder maintains such a Set of all
779:             * typerel nodes for quick reference. TypeRelSets are also instantiated when doing queries on
780:             * TypeRel like getAllowedRelations(MMObjectBuilder) etc.
781:             *
782:             * @since MMBase-1.6.2
783:             */
784:            protected class TypeRelSet extends TreeSet<MMObjectNode> {
785:                protected TypeRelSet() {
786:                    super (new Comparator<MMObjectNode>() {
787:                        // sorted by source, destination, role
788:                        public int compare(MMObjectNode n1, MMObjectNode n2) {
789:                            int i1 = n1.getIntValue("snumber");
790:                            int i2 = n2.getIntValue("snumber");
791:                            if (i1 != i2)
792:                                return i1 - i2;
793:
794:                            i1 = n1.getIntValue("dnumber");
795:                            i2 = n2.getIntValue("dnumber");
796:                            if (i1 != i2)
797:                                return i1 - i2;
798:
799:                            i1 = n1.getIntValue("rnumber");
800:                            i2 = n2.getIntValue("rnumber");
801:                            if (i1 > 0 && i2 > 0 && i1 != i2)
802:                                return i1 - i2;
803:
804:                            return 0;
805:                        }
806:                    });
807:                }
808:
809:                // make sure only MMObjectNode's are added
810:                public boolean add(MMObjectNode node) {
811:                    return super .add(node);
812:                }
813:
814:                // find some subsets:
815:                SortedSet<MMObjectNode> getBySource(MMObjectBuilder source) {
816:                    return getBySourceDestinationRole(source.getNumber(), 0, 0);
817:                }
818:
819:                SortedSet<MMObjectNode> getBySource(int source) {
820:                    return getBySourceDestinationRole(source, 0, 0);
821:                }
822:
823:                SortedSet<MMObjectNode> getBySourceDestination(
824:                        MMObjectBuilder source, MMObjectBuilder destination) {
825:                    return getBySourceDestinationRole(source.getNumber(),
826:                            destination.getNumber(), 0);
827:                }
828:
829:                SortedSet<MMObjectNode> getBySourceDestination(int source,
830:                        int destination) {
831:                    return getBySourceDestinationRole(source, destination, 0);
832:                }
833:
834:                SortedSet<MMObjectNode> getBySourceDestinationRole(int source,
835:                        int destination, int role) {
836:                    // determine minimum value - corrects in case '-1' (common MMBase value for N.A.) is passed
837:                    int roleMin = role <= 0 ? 0 : role;
838:                    int destinationMin = destination <= 0 ? 0 : destination;
839:                    int sourceMin = source <= 0 ? 0 : source;
840:
841:                    // determine maximum value
842:                    int roleMax = role <= 0 ? 0 : role + 1; // i.e. source, destination, role
843:                    int destinationMax = role <= 0 ? destination + 1
844:                            : destination; // i.e. source, destination, 0
845:                    int sourceMax = (destination <= 0 && role <= 0) ? (source <= 0 ? 0
846:                            : source + 1)
847:                            : source; // i.e. source, 0, 0
848:
849:                    VirtualTypeRelNode fromTypeRelNode = new VirtualTypeRelNode(
850:                            sourceMin, destinationMin, roleMin);
851:                    VirtualTypeRelNode toTypeRelNode = new VirtualTypeRelNode(
852:                            sourceMax, destinationMax, roleMax);
853:
854:                    SortedSet<MMObjectNode> allowed = subSet(fromTypeRelNode,
855:                            toTypeRelNode);
856:                    return Collections.unmodifiableSortedSet(allowed);
857:                }
858:
859:            }
860:
861:            /**
862:             * An InverseTypeRelSet is a Set of typerel nodes. The TypeRel builder maintains such a Set of
863:             * all typerel nodes for quick reference.
864:             *
865:             * @since MMBase-1.6.2
866:             */
867:            protected class InverseTypeRelSet extends TreeSet<MMObjectNode> {
868:
869:                protected InverseTypeRelSet() {
870:                    super (new Comparator<MMObjectNode>() {
871:                        // sorted by destination, source, role
872:                        public int compare(MMObjectNode n1, MMObjectNode n2) {
873:                            int i1 = n1.getIntValue("dnumber");
874:                            int i2 = n2.getIntValue("dnumber");
875:                            if (i1 != i2)
876:                                return i1 - i2;
877:
878:                            i1 = n1.getIntValue("snumber");
879:                            i2 = n2.getIntValue("snumber");
880:                            if (i1 != i2)
881:                                return i1 - i2;
882:
883:                            i1 = n1.getIntValue("rnumber");
884:                            i2 = n2.getIntValue("rnumber");
885:                            if (i1 != -1 && i2 != -1 && i1 != i2)
886:                                return i1 - i2;
887:                            return 0;
888:                        }
889:                    });
890:                }
891:
892:                // make sure only MMObjectNode's are added
893:                public boolean add(MMObjectNode object) {
894:                    return super .add(object);
895:                }
896:
897:                SortedSet<MMObjectNode> getByDestination(
898:                        MMObjectBuilder destination) {
899:                    return getByDestinationSourceRole(0, destination
900:                            .getNumber(), 0);
901:                }
902:
903:                SortedSet<MMObjectNode> getByDestination(int destination) {
904:                    return getByDestinationSourceRole(0, destination, 0);
905:                }
906:
907:                SortedSet<MMObjectNode> getByDestinationSource(
908:                        MMObjectBuilder source, MMObjectBuilder destination) {
909:                    return getByDestinationSourceRole(source.getNumber(),
910:                            destination.getNumber(), 0);
911:                }
912:
913:                SortedSet<MMObjectNode> getByDestinationSource(int source,
914:                        int destination) {
915:                    return getByDestinationSourceRole(source, destination, 0);
916:                }
917:
918:                SortedSet<MMObjectNode> getByDestinationSourceRole(int source,
919:                        int destination, int role) {
920:                    // determine minimum value - corrects in case '-1' (common MMBase value for N.A.) is passed
921:                    int roleMin = role <= 0 ? 0 : role;
922:                    int sourceMin = source <= 0 ? 0 : source;
923:                    int destinationMin = destination <= 0 ? 0 : destination;
924:
925:                    // determine maximum value
926:                    int roleMax = role <= 0 ? 0 : role + 1; // i.e. source, destination, role
927:                    int sourceMax = role <= 0 ? (source <= 0 ? 0 : source + 1)
928:                            : source; // i.e. source, destination, 0
929:                    int destinationMax = (source <= 0 && role <= 0) ? destination + 1
930:                            : destination; // i.e. 0, destination, 0
931:
932:                    return Collections.unmodifiableSortedSet(subSet(
933:                            new VirtualTypeRelNode(sourceMin, destinationMin,
934:                                    roleMin), new VirtualTypeRelNode(sourceMax,
935:                                    destinationMax, roleMax)));
936:                }
937:
938:            }
939:
940:            /**
941:             * A VirtualTypeRelNode is a MMObjectNode which is added to the typerelset with extensions of
942:             * the actual builders specified. So these entries are not in the database.
943:             *
944:             * @since MMBase-1.6.2
945:             */
946:            protected class VirtualTypeRelNode extends VirtualNode {
947:
948:                VirtualTypeRelNode(int snumber, int dnumber) { // only for use in lookups
949:                    // We don't use this-constructor because some jvm get confused then
950:                    super (VirtualTypeRel.getVirtualTypeRel(TypeRel.this ));
951:                    setValue("snumber", snumber);
952:                    setValue("dnumber", dnumber);
953:                    setValue("rnumber", -1);
954:                }
955:
956:                VirtualTypeRelNode(int snumber) { // only for use in lookups
957:                    // We don't use this-constructor because some jvm get confused then
958:                    super (VirtualTypeRel.getVirtualTypeRel(TypeRel.this ));
959:                    setValue("snumber", snumber);
960:                    setValue("dnumber", -1);
961:                    setValue("rnumber", -1);
962:                }
963:
964:                VirtualTypeRelNode(int snumber, int dnumber, int rnumber) {
965:                    super (VirtualTypeRel.getVirtualTypeRel(TypeRel.this ));
966:                    setValue("snumber", snumber);
967:                    setValue("dnumber", dnumber);
968:                    setValue("rnumber", rnumber);
969:                    values = Collections.unmodifiableMap(values); // make sure it is not changed any more!
970:                }
971:            }
972:
973:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.