4740 |
05 Feb 09 |
nicklas |
1 |
/** |
4740 |
05 Feb 09 |
nicklas |
$Id$ |
4740 |
05 Feb 09 |
nicklas |
3 |
|
4740 |
05 Feb 09 |
nicklas |
Copyright (C) 2008 Nicklas Nordborg |
4740 |
05 Feb 09 |
nicklas |
5 |
|
4740 |
05 Feb 09 |
nicklas |
This file is part of BASE - BioArray Software Environment. |
4740 |
05 Feb 09 |
nicklas |
Available at http://base.thep.lu.se/ |
4740 |
05 Feb 09 |
nicklas |
8 |
|
4740 |
05 Feb 09 |
nicklas |
BASE is free software; you can redistribute it and/or |
4740 |
05 Feb 09 |
nicklas |
modify it under the terms of the GNU General Public License |
4740 |
05 Feb 09 |
nicklas |
as published by the Free Software Foundation; either version 3 |
4740 |
05 Feb 09 |
nicklas |
of the License, or (at your option) any later version. |
4740 |
05 Feb 09 |
nicklas |
13 |
|
4740 |
05 Feb 09 |
nicklas |
BASE is distributed in the hope that it will be useful, |
4740 |
05 Feb 09 |
nicklas |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
4740 |
05 Feb 09 |
nicklas |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4740 |
05 Feb 09 |
nicklas |
GNU General Public License for more details. |
4740 |
05 Feb 09 |
nicklas |
18 |
|
4740 |
05 Feb 09 |
nicklas |
You should have received a copy of the GNU General Public License |
4740 |
05 Feb 09 |
nicklas |
along with BASE. If not, see <http://www.gnu.org/licenses/>. |
4740 |
05 Feb 09 |
nicklas |
21 |
*/ |
4740 |
05 Feb 09 |
nicklas |
22 |
package net.sf.basedb.util.overview.node; |
4740 |
05 Feb 09 |
nicklas |
23 |
|
4740 |
05 Feb 09 |
nicklas |
24 |
import net.sf.basedb.core.BasicItem; |
4740 |
05 Feb 09 |
nicklas |
25 |
import net.sf.basedb.core.DbControl; |
4740 |
05 Feb 09 |
nicklas |
26 |
import net.sf.basedb.util.overview.Node; |
4740 |
05 Feb 09 |
nicklas |
27 |
import net.sf.basedb.util.overview.OverviewContext; |
4766 |
17 Feb 09 |
nicklas |
28 |
import net.sf.basedb.util.overview.cache.DirectionalCacheKey; |
4740 |
05 Feb 09 |
nicklas |
29 |
import net.sf.basedb.util.overview.cache.NodeCache; |
4740 |
05 Feb 09 |
nicklas |
30 |
import net.sf.basedb.util.overview.validator.NodeValidator; |
4740 |
05 Feb 09 |
nicklas |
31 |
|
4740 |
05 Feb 09 |
nicklas |
32 |
/** |
4740 |
05 Feb 09 |
nicklas |
A node factory is responsible for creating item-type nodes. |
4740 |
05 Feb 09 |
nicklas |
The primary function of a node factory is to interface with |
4740 |
05 Feb 09 |
nicklas |
a {@link NodeValidator} to actually decide if a node should |
4740 |
05 Feb 09 |
nicklas |
be created or not for a given item (which may be missing or |
4740 |
05 Feb 09 |
nicklas |
the current user may be denied access). |
4740 |
05 Feb 09 |
nicklas |
<p> |
4740 |
05 Feb 09 |
nicklas |
Another function is to interface with the current |
4740 |
05 Feb 09 |
nicklas |
{@link OverviewContext} and it's optional {@link NodeCache} |
4740 |
05 Feb 09 |
nicklas |
so that we don't have to use resources for re-loading a deep |
4740 |
05 Feb 09 |
nicklas |
sub-tree starting with an item that has already been loaded |
4740 |
05 Feb 09 |
nicklas |
in another branch of the tree. |
4740 |
05 Feb 09 |
nicklas |
44 |
|
4740 |
05 Feb 09 |
nicklas |
@author Nicklas |
4740 |
05 Feb 09 |
nicklas |
@version 2.10 |
4740 |
05 Feb 09 |
nicklas |
@base.modified $Date$ |
4740 |
05 Feb 09 |
nicklas |
48 |
*/ |
4740 |
05 Feb 09 |
nicklas |
49 |
public class NodeFactory<I extends BasicItem> |
4740 |
05 Feb 09 |
nicklas |
50 |
{ |
6444 |
09 Apr 14 |
nicklas |
51 |
private static final org.slf4j.Logger log = |
6444 |
09 Apr 14 |
nicklas |
52 |
org.slf4j.LoggerFactory.getLogger(NodeFactory.class); |
4740 |
05 Feb 09 |
nicklas |
53 |
private static final boolean debug = log.isDebugEnabled(); |
4740 |
05 Feb 09 |
nicklas |
54 |
|
4740 |
05 Feb 09 |
nicklas |
55 |
private DbControl dc; |
4740 |
05 Feb 09 |
nicklas |
56 |
private OverviewContext context; |
4740 |
05 Feb 09 |
nicklas |
57 |
private NodeValidator<? super I> validator; |
4740 |
05 Feb 09 |
nicklas |
58 |
private NodeNameGenerator<? super I> nameGenerator; |
4740 |
05 Feb 09 |
nicklas |
59 |
|
4740 |
05 Feb 09 |
nicklas |
60 |
/** |
4740 |
05 Feb 09 |
nicklas |
Create a node factory. If a validator is specified it will be |
4740 |
05 Feb 09 |
nicklas |
used to determine if a node should be created or not. Without |
4740 |
05 Feb 09 |
nicklas |
a validator nodes are not created for missing items, only for |
4740 |
05 Feb 09 |
nicklas |
existing item (including if access is denied) |
4740 |
05 Feb 09 |
nicklas |
65 |
|
4740 |
05 Feb 09 |
nicklas |
@param dc A DbControl to use if database access is needed |
4740 |
05 Feb 09 |
nicklas |
@param context The current overview context |
4740 |
05 Feb 09 |
nicklas |
@param validator An optional validator |
4740 |
05 Feb 09 |
nicklas |
@param nameGenerator A name generator to use for node name and title |
4740 |
05 Feb 09 |
nicklas |
generation |
4740 |
05 Feb 09 |
nicklas |
71 |
*/ |
4740 |
05 Feb 09 |
nicklas |
72 |
public NodeFactory(DbControl dc, OverviewContext context, |
4740 |
05 Feb 09 |
nicklas |
73 |
NodeValidator<? super I> validator, NodeNameGenerator<? super I> nameGenerator) |
4740 |
05 Feb 09 |
nicklas |
74 |
{ |
4740 |
05 Feb 09 |
nicklas |
75 |
this.dc = dc; |
4740 |
05 Feb 09 |
nicklas |
76 |
this.context = context; |
4740 |
05 Feb 09 |
nicklas |
77 |
this.validator = validator; |
4740 |
05 Feb 09 |
nicklas |
78 |
this.nameGenerator = nameGenerator; |
4740 |
05 Feb 09 |
nicklas |
79 |
} |
4740 |
05 Feb 09 |
nicklas |
80 |
|
4740 |
05 Feb 09 |
nicklas |
81 |
/** |
4740 |
05 Feb 09 |
nicklas |
Get the node validator that is used by this factory. |
4740 |
05 Feb 09 |
nicklas |
@return A node validator or null if no validator is used |
4740 |
05 Feb 09 |
nicklas |
84 |
*/ |
4740 |
05 Feb 09 |
nicklas |
85 |
public NodeValidator<? super I> getNodeValidator() |
4740 |
05 Feb 09 |
nicklas |
86 |
{ |
4740 |
05 Feb 09 |
nicklas |
87 |
return validator; |
4740 |
05 Feb 09 |
nicklas |
88 |
} |
4740 |
05 Feb 09 |
nicklas |
89 |
|
4740 |
05 Feb 09 |
nicklas |
90 |
/** |
4740 |
05 Feb 09 |
nicklas |
Create a node representing a missing item. A node is only created |
4740 |
05 Feb 09 |
nicklas |
if a validator is present and it's {@link |
4740 |
05 Feb 09 |
nicklas |
NodeValidator#preMissingItem(DbControl, OverviewContext, Node)} |
4740 |
05 Feb 09 |
nicklas |
method returns TRUE. |
4740 |
05 Feb 09 |
nicklas |
95 |
|
4740 |
05 Feb 09 |
nicklas |
@param parentNode The parent node |
4740 |
05 Feb 09 |
nicklas |
@return The new node, or null if no node was created |
4740 |
05 Feb 09 |
nicklas |
98 |
*/ |
4740 |
05 Feb 09 |
nicklas |
99 |
public Node createMissingNode(Node parentNode) |
4740 |
05 Feb 09 |
nicklas |
100 |
{ |
4740 |
05 Feb 09 |
nicklas |
101 |
Node node = null; |
4740 |
05 Feb 09 |
nicklas |
102 |
if (validator != null && validator.preMissingItem(dc, context, parentNode)) |
4740 |
05 Feb 09 |
nicklas |
103 |
{ |
4740 |
05 Feb 09 |
nicklas |
104 |
String nodeName = nameGenerator.getMissingNodeName(parentNode); |
4740 |
05 Feb 09 |
nicklas |
105 |
String nodeTitle = nameGenerator.getMissingNodeTitle(parentNode); |
4740 |
05 Feb 09 |
nicklas |
106 |
node = createNode(null, nodeName, nodeTitle, null, parentNode, ChildNodeDirection.NONE); |
4740 |
05 Feb 09 |
nicklas |
107 |
validator.postMissingItem(dc, context, node, parentNode); |
4740 |
05 Feb 09 |
nicklas |
108 |
} |
4740 |
05 Feb 09 |
nicklas |
109 |
return node; |
4740 |
05 Feb 09 |
nicklas |
110 |
} |
4740 |
05 Feb 09 |
nicklas |
111 |
|
4740 |
05 Feb 09 |
nicklas |
112 |
/** |
4740 |
05 Feb 09 |
nicklas |
Create a node representing an item that the logged in user is denied to |
4740 |
05 Feb 09 |
nicklas |
access. A node is created if no validator is present or if the |
4740 |
05 Feb 09 |
nicklas |
validator's {@link |
4740 |
05 Feb 09 |
nicklas |
NodeValidator#preDeniedItem(DbControl, OverviewContext, Node)} |
4740 |
05 Feb 09 |
nicklas |
method returns TRUE. |
4740 |
05 Feb 09 |
nicklas |
118 |
|
4740 |
05 Feb 09 |
nicklas |
@param parentNode The parent node |
4740 |
05 Feb 09 |
nicklas |
@return The new node, or null if no node was created |
4740 |
05 Feb 09 |
nicklas |
121 |
*/ |
4740 |
05 Feb 09 |
nicklas |
122 |
public Node createDeniedNode(Node parentNode) |
4740 |
05 Feb 09 |
nicklas |
123 |
{ |
4740 |
05 Feb 09 |
nicklas |
124 |
Node node = null; |
4740 |
05 Feb 09 |
nicklas |
125 |
if (validator == null || validator.preDeniedItem(dc, context, parentNode)) |
4740 |
05 Feb 09 |
nicklas |
126 |
{ |
4740 |
05 Feb 09 |
nicklas |
127 |
String nodeName = nameGenerator.getDeniedNodeName(parentNode); |
4740 |
05 Feb 09 |
nicklas |
128 |
String nodeTitle = nameGenerator.getDeniedNodeTitle(parentNode); |
4740 |
05 Feb 09 |
nicklas |
129 |
node = createNode(null, nodeName, nodeTitle, null, parentNode, ChildNodeDirection.NONE); |
4740 |
05 Feb 09 |
nicklas |
130 |
if (validator != null) validator.postDeniedItem(dc, context, node, parentNode); |
4740 |
05 Feb 09 |
nicklas |
131 |
} |
4740 |
05 Feb 09 |
nicklas |
132 |
return node; |
4740 |
05 Feb 09 |
nicklas |
133 |
} |
4740 |
05 Feb 09 |
nicklas |
134 |
|
4740 |
05 Feb 09 |
nicklas |
135 |
/** |
4740 |
05 Feb 09 |
nicklas |
Create a node representing an existing item. A node is created if no |
4740 |
05 Feb 09 |
nicklas |
validator is present or if the validator's {@link |
4740 |
05 Feb 09 |
nicklas |
NodeValidator#preValidate(DbControl, OverviewContext, Object, Node)} |
4740 |
05 Feb 09 |
nicklas |
method returns TRUE. |
4740 |
05 Feb 09 |
nicklas |
140 |
|
4740 |
05 Feb 09 |
nicklas |
@param item The item to attach to the node |
4740 |
05 Feb 09 |
nicklas |
@param cacheKey An optional cache key |
4740 |
05 Feb 09 |
nicklas |
@param parentNode The parent node |
4740 |
05 Feb 09 |
nicklas |
@param direction The direction to use when loading the node's children |
4740 |
05 Feb 09 |
nicklas |
@return The new node, or null if no node was created |
4740 |
05 Feb 09 |
nicklas |
146 |
*/ |
4740 |
05 Feb 09 |
nicklas |
147 |
public Node createNode(I item, Object cacheKey, Node parentNode, ChildNodeDirection direction) |
4740 |
05 Feb 09 |
nicklas |
148 |
{ |
4740 |
05 Feb 09 |
nicklas |
149 |
Node node = null; |
4740 |
05 Feb 09 |
nicklas |
150 |
if (validator == null || validator.preValidate(dc, context, item, parentNode)) |
4740 |
05 Feb 09 |
nicklas |
151 |
{ |
4740 |
05 Feb 09 |
nicklas |
152 |
String nodeName = nameGenerator.getNodeName(item, parentNode); |
4740 |
05 Feb 09 |
nicklas |
153 |
String nodeTitle = nameGenerator.getNodeTitle(item, parentNode); |
4740 |
05 Feb 09 |
nicklas |
154 |
node = createNode(item, nodeName, nodeTitle, cacheKey, parentNode, direction); |
4740 |
05 Feb 09 |
nicklas |
155 |
if (validator != null) validator.postValidate(dc, context, node, parentNode); |
4740 |
05 Feb 09 |
nicklas |
156 |
} |
4740 |
05 Feb 09 |
nicklas |
157 |
return node; |
4740 |
05 Feb 09 |
nicklas |
158 |
} |
4740 |
05 Feb 09 |
nicklas |
159 |
|
4740 |
05 Feb 09 |
nicklas |
160 |
private Node createNode(I item, String name, String title, Object cacheKey, Node parentNode, ChildNodeDirection direction) |
4740 |
05 Feb 09 |
nicklas |
161 |
{ |
4740 |
05 Feb 09 |
nicklas |
162 |
Node node = null; |
4740 |
05 Feb 09 |
nicklas |
163 |
if (cacheKey != null) |
4740 |
05 Feb 09 |
nicklas |
164 |
{ |
4766 |
17 Feb 09 |
nicklas |
165 |
node = cloneCachedNode(cacheKey, parentNode, direction); |
4740 |
05 Feb 09 |
nicklas |
166 |
} |
4740 |
05 Feb 09 |
nicklas |
167 |
if (node == null) |
4740 |
05 Feb 09 |
nicklas |
168 |
{ |
4740 |
05 Feb 09 |
nicklas |
169 |
node = new Node(name, title, parentNode, item, direction); |
4766 |
17 Feb 09 |
nicklas |
170 |
if (cacheKey != null) cacheNewNode(cacheKey, node, direction); |
4740 |
05 Feb 09 |
nicklas |
171 |
} |
4740 |
05 Feb 09 |
nicklas |
172 |
return node; |
4740 |
05 Feb 09 |
nicklas |
173 |
} |
4740 |
05 Feb 09 |
nicklas |
174 |
|
4740 |
05 Feb 09 |
nicklas |
175 |
/** |
4740 |
05 Feb 09 |
nicklas |
Clones a cached node if the current context supports |
4740 |
05 Feb 09 |
nicklas |
caching and another node with the given cache key |
4768 |
18 Feb 09 |
nicklas |
already exists. This method wraps the given cacheKey |
4768 |
18 Feb 09 |
nicklas |
with a {@link DirectionalCacheKey} since the loading |
4768 |
18 Feb 09 |
nicklas |
direction will affect the children of a node. |
4740 |
05 Feb 09 |
nicklas |
181 |
|
4740 |
05 Feb 09 |
nicklas |
@param cacheKey The cache key to use for node lookup |
4740 |
05 Feb 09 |
nicklas |
@param parentNode The node that should be the parent of the |
4740 |
05 Feb 09 |
nicklas |
cloned node |
4766 |
17 Feb 09 |
nicklas |
@param direction The direction we are loading child nodes in |
4740 |
05 Feb 09 |
nicklas |
@return The new (cloned) node, or null if no cached node was found |
4740 |
05 Feb 09 |
nicklas |
@see OverviewContext#getNodeCache() |
4740 |
05 Feb 09 |
nicklas |
188 |
*/ |
4766 |
17 Feb 09 |
nicklas |
189 |
protected Node cloneCachedNode(Object cacheKey, Node parentNode, ChildNodeDirection direction) |
4740 |
05 Feb 09 |
nicklas |
190 |
{ |
4740 |
05 Feb 09 |
nicklas |
191 |
NodeCache<Object> cache = context.getNodeCache(); |
4740 |
05 Feb 09 |
nicklas |
192 |
if (cache == null) return null; |
4766 |
17 Feb 09 |
nicklas |
193 |
Node node = cache.getNode(new DirectionalCacheKey(cacheKey, direction)); |
4740 |
05 Feb 09 |
nicklas |
194 |
if (node != null) |
4740 |
05 Feb 09 |
nicklas |
195 |
{ |
4740 |
05 Feb 09 |
nicklas |
196 |
if (debug) log.debug("Cloning node: " + node + "; parent=" + parentNode); |
4740 |
05 Feb 09 |
nicklas |
197 |
node = node.deepCopy(parentNode); |
4740 |
05 Feb 09 |
nicklas |
198 |
} |
4740 |
05 Feb 09 |
nicklas |
199 |
return node; |
4740 |
05 Feb 09 |
nicklas |
200 |
} |
4740 |
05 Feb 09 |
nicklas |
201 |
|
4740 |
05 Feb 09 |
nicklas |
202 |
/** |
4740 |
05 Feb 09 |
nicklas |
Store a node in the node cache if the current overview context |
4740 |
05 Feb 09 |
nicklas |
supports caching. |
4740 |
05 Feb 09 |
nicklas |
205 |
|
4740 |
05 Feb 09 |
nicklas |
@param cacheKey The cache key |
4740 |
05 Feb 09 |
nicklas |
@param node The node to store |
4766 |
17 Feb 09 |
nicklas |
@param direction The direction we are loading child nodes in |
4740 |
05 Feb 09 |
nicklas |
@see OverviewContext#getNodeCache() |
4740 |
05 Feb 09 |
nicklas |
210 |
*/ |
4766 |
17 Feb 09 |
nicklas |
211 |
protected void cacheNewNode(Object cacheKey, Node node, ChildNodeDirection direction) |
4740 |
05 Feb 09 |
nicklas |
212 |
{ |
4740 |
05 Feb 09 |
nicklas |
213 |
NodeCache<Object> cache = context.getNodeCache(); |
4740 |
05 Feb 09 |
nicklas |
214 |
if (cache == null) return; |
4766 |
17 Feb 09 |
nicklas |
215 |
cache.putNode(new DirectionalCacheKey(cacheKey, direction), node); |
4740 |
05 Feb 09 |
nicklas |
216 |
} |
4740 |
05 Feb 09 |
nicklas |
217 |
|
4740 |
05 Feb 09 |
nicklas |
218 |
public void postValidateFolder(Node folderNode, Node parentNode) |
4740 |
05 Feb 09 |
nicklas |
219 |
{ |
4740 |
05 Feb 09 |
nicklas |
220 |
if (validator != null) |
4740 |
05 Feb 09 |
nicklas |
221 |
{ |
4740 |
05 Feb 09 |
nicklas |
222 |
validator.postValidateFolder(dc, context, folderNode, parentNode); |
4740 |
05 Feb 09 |
nicklas |
223 |
} |
4740 |
05 Feb 09 |
nicklas |
224 |
} |
4740 |
05 Feb 09 |
nicklas |
225 |
} |