1
2
3
4
5
6
7
8
9
10 package com.sri.emo.controller;
11
12 import com.jcorporate.expresso.core.controller.*;
13 import com.jcorporate.expresso.core.db.DBException;
14 import com.jcorporate.expresso.core.db.exception.DBRecordNotFoundException;
15 import com.jcorporate.expresso.core.dbobj.MultiDBObject;
16 import com.jcorporate.expresso.core.misc.RecordPaginator;
17 import com.jcorporate.expresso.core.misc.StringUtil;
18 import com.jcorporate.expresso.core.registry.RequestRegistry;
19 import com.jcorporate.expresso.core.security.SuperUser;
20 import com.jcorporate.expresso.core.security.User;
21 import com.jcorporate.expresso.kernel.util.FastStringBuffer;
22 import com.jcorporate.expresso.services.dbobj.*;
23 import com.sri.common.controller.StateHandler;
24 import com.sri.common.taglib.InputTag;
25 import com.sri.emo.EmoSchema;
26 import com.sri.emo.controller.nodefilter.DoFilterNodes;
27 import com.sri.emo.controller.nodefilter.NodeFilter;
28 import com.sri.emo.dbobj.*;
29 import com.sri.emo.dbobj.selectiontree.TreeDeletionSelector;
30
31 import java.util.*;
32
33 /***
34 * Handle Node manipulation.
35 *
36 * @author larry hamel
37 */
38 public class NodeAction extends NodeController {
39 /***
40 *
41 */
42 private static final long serialVersionUID = 1L;
43
44
45 /***
46 * Constant for access to state "List Nodes"
47 */
48 public static final String LIST_NODE = "listNodes";
49
50 /***
51 * Constant for access to state "Prompt Edit Picklist For Nodes"
52 */
53 public static final String PROMPT_PICKLIST_NODE = "promptPickListNodes";
54
55 /***
56 * Constant for access to state "Save Picklist for nodes"
57 */
58 public static final String DO_PICKLIST_NODE = "doPickListNodes";
59
60 /***
61 * Constant for access to state "Prompt Edit Attribute"
62 */
63 public static final String PROMPT_EDIT_ATTRIB = "promptEditAttrib";
64
65 /***
66 * Constant for access to state "Save Node Attributes"
67 */
68 public static final String DO_EDIT_ATTRIB = "doEditAttrib";
69
70 /***
71 * Constant for access to state "Delete Node"
72 */
73 public static final String DO_DELETE_NODE = "doDeleteNode";
74
75 /***
76 * Constant for access to state "Prompt Delete Node"
77 */
78 public static final String PROMPT_DELETE_NODE = "promptDeleteNode";
79
80 /***
81 * Constant for access to state "Prompt Delete A Node Tree"
82 */
83 public static final String PROMPT_DELETE_NODE_TREE = "promptDeleteNodeTree";
84
85 public static final String DO_EDIT_MORE_ATTRIB = "doEditMoreAttrib";
86
87 public static final String DO_ATTRIB_PICK = "doAttribPick";
88
89 public static final String DO_DELETE_ONE_ATTRIB = "doDeleteAttrib";
90
91 /***
92 * Constant for access to state "Prompt Clone Node"
93 */
94 public static final String PROMPT_CLONE_NODE = "promptCloneNode";
95
96 /***
97 * Constant for access to state "Prompt Clone Node and its Parts"
98 */
99 public static final String PROMPT_CLONE_TREE = "promptCloneTree";
100
101 /***
102 * Constant for access to state "Clone a Tree Of Nodes"
103 */
104 public static final String DO_CLONE_TREE = "doCloneTree";
105
106 /***
107 * Constant for access to state "Clone a Single Node"
108 */
109 public static final String DO_CLONE_NODE = "doCloneNode";
110
111 public static final String DO_ORPHAN_CLONE_NODE = "doOrphanCloneNode";
112
113 public static final String ADD_GROUP = "addGroup";
114
115 public static final String INDEX = "index";
116
117 public static final String PROMPT_EDIT_PERMS = "promptEditPerms";
118
119 public static final String REMOVE_GROUP = "removeGroup";
120
121 public static final String PROMPT_ADD_ATTRIB = "promptAddAttrib";
122
123 public static final String PROMPT_ATTRIB_PICK = "promptAttribPick";
124
125 public static final String PROMPT_EDIT_ONE_ATTRIB = "promptEditOneAttrib";
126
127 public static final String DO_EDIT_ONE_ATTRIB = "doEditOneAttrib";
128
129 public static final String LIST_ALL_TYPES = "listAllTypes";
130
131 /***
132 * Constant for access to state "View Node as Tree"
133 */
134 public static final String VIEW_TREE = "viewTree";
135
136 /***
137 * Constant for access to state "View Single Attribute"
138 */
139 public static final String VIEW_SINGLE_ATTRIBUTE = "viewSingleAttribute";
140
141 /***
142 * checkbox name
143 */
144 public static final String PICK_LIST_ITEM = "PICK_LIST_ITEM";
145
146 public static final String ARE_MULTIPLE_ITEMS = "ARE_MULTIPLE_ITEMS";
147
148 public static final String TYPE_TRANS = "allTypes";
149
150 public static final String PERMS_BLOCK = "PERMS_BLOCK";
151
152 /***
153 * setup code for list of node types to omit from a tree listing; use "|" to
154 * delimit items in one string.
155 */
156 public static final String OMIT_TYPES = "OMIT_TYPES";
157
158 /***
159 * sorting columns for lists
160 */
161 public static final String TITLE_SORT = "TITLE_SORT";
162
163 public static final String DESCENDING_FLAG = "_DESC";
164
165 public static final String ASCENDING_FLAG = "_ASC";
166
167 public static final String TITLE_SORT_DESC = TITLE_SORT + DESCENDING_FLAG;
168
169 public static final String GROUP_SORT = "GROUP_SORT";
170
171 public static final String GROUP_SORT_DESC = GROUP_SORT + DESCENDING_FLAG;
172
173 public static final String OWNER_SORT = "OWNER_SORT";
174
175 public static final String OWNER_SORT_DESC = OWNER_SORT + DESCENDING_FLAG;
176
177 public static final String KEYWORD_SORT = "KEYWORD_SORT";
178
179 public static final String KEYWORD_SORT_DESC = KEYWORD_SORT
180 + DESCENDING_FLAG;
181
182 public static final String[][] ALL_SORTS = {
183
184
185 {TITLE_SORT, Node.NODE_TITLE},
186 {TITLE_SORT_DESC, Node.NODE_TITLE + " DESC"},
187 {GROUP_SORT, Node.GROUP_OF_OWNER},
188 {GROUP_SORT_DESC, Node.GROUP_OF_OWNER + " DESC"},
189 {OWNER_SORT, Node.NODE_OWNER},
190 {OWNER_SORT_DESC, Node.NODE_OWNER + " DESC"},
191 {KEYWORD_SORT, Node.NODE_COMMENT},
192 {KEYWORD_SORT_DESC, Node.NODE_COMMENT + " DESC"},};
193
194 /***
195 * flavors for cloning
196 */
197 public static final String SIBLING_MARKER = "sibling";
198
199 public static final String RELATION_TARGET = "relationTarget"; /***
200 public static final String FILTER_SESSION_KEY = "filtered";
201 public static final String SORT_PARAM = "sort";
202
203 // * names used to indicate that ascending arrows are in order
204 // */
205
206
207
208
209
210
211
212
213
214
215
216 public NodeAction() {
217 super(EmoSchema.class);
218 addState(new State(LIST_NODE, "List Nodes"));
219 addState(new State(PROMPT_PICKLIST_NODE, "List nodes for selection"));
220 addState(new State(DO_PICKLIST_NODE, "Submit nodes to be related"));
221
222 State s = new State(PROMPT_EDIT_ATTRIB, "Prompt to edit attribute");
223 s.addRequiredParameter(Node.NODE_ID);
224 s.addRequiredParameter(Attribute.ATTRIBUTE_TYPE);
225 addState(s);
226
227 s = new State(PROMPT_ATTRIB_PICK,
228 "Prompt to edit attribute that has picklist");
229 s.addRequiredParameter(Node.NODE_ID);
230 s.addRequiredParameter(Attribute.ATTRIBUTE_TYPE);
231 addState(s);
232
233 s = new State(DO_ATTRIB_PICK, "Submit attribute that has picklist");
234 s.addRequiredParameter(Node.NODE_ID);
235 s.addRequiredParameter(Attribute.ATTRIBUTE_TYPE);
236 addState(s);
237
238 s = new State(DO_DELETE_ONE_ATTRIB, "Delete attribute");
239 s.addRequiredParameter(Attribute.ATTRIBUTE_ID);
240 addState(s);
241
242 s = new State(PROMPT_EDIT_ONE_ATTRIB, "Prompt to edit ONE attribute");
243 s.addRequiredParameter(Attribute.ATTRIBUTE_ID);
244 addState(s);
245
246 s = new State(DO_EDIT_ONE_ATTRIB, "Submit edit ONE attribute");
247 s.addRequiredParameter(Attribute.ATTRIBUTE_ID);
248 addState(s);
249
250 s = new State(PROMPT_ADD_ATTRIB, "Prompt to add ONE attribute");
251 s.addRequiredParameter(Node.NODE_ID);
252 s.addRequiredParameter(Attribute.ATTRIBUTE_TYPE);
253 addState(s);
254
255 s = new State(PROMPT_EDIT_ONE_ATTRIB, "Prompt to edit ONE attribute");
256 s.addRequiredParameter(Attribute.ATTRIBUTE_ID);
257 addState(s);
258
259 addState(new State(DO_EDIT_ATTRIB, "Submit attribute edits"));
260 addState(new State(DO_DELETE_NODE, "Delete Node"));
261 addState(new State(PROMPT_DELETE_NODE, "Prompt to delete node"));
262 addState(new State(PROMPT_DELETE_NODE_TREE,
263 "Prompt to delete node tree"));
264 addState(new State(DO_EDIT_MORE_ATTRIB,
265 "Submit attribute edits and return to edit more attributes"));
266
267 addState(new State(PROMPT_CLONE_NODE, "Prompt to clone node"));
268 addState(new State(DO_CLONE_NODE, "Submit to clone node"));
269 addState(new State(DO_ORPHAN_CLONE_NODE, "Submit to orphan clone node"));
270 addState(new State(PROMPT_CLONE_TREE, "Prompt clone tree"));
271 addState(new State(DO_CLONE_TREE, "Do clone tree"));
272
273 addState(new State(INDEX, "Index of all node types (auto generated)"));
274 addState(new State(PROMPT_EDIT_PERMS,
275 "Prompt editting of permission groups for this node"));
276 addState(new State(REMOVE_GROUP,
277 "Remove permission groups for this node"));
278 addState(new State(ADD_GROUP, "Add permission groups for this node"));
279 addState(new State(LIST_ALL_TYPES, "List of lists; all node types"));
280
281 s = new State(VIEW_TREE, "Tree view");
282 s.addRequiredParameter(Node.NODE_ID);
283 addState(s);
284
285 s = new State(AddNodeAction.VIEW_NODE, "View");
286 s.addRequiredParameter(Node.NODE_ID);
287 addState(s);
288
289 s = new State(VIEW_SINGLE_ATTRIBUTE, "View Single Attribute");
290 s.addRequiredParameter(Attribute.ATTRIBUTE_ID);
291 addState(s);
292
293
294 s = this.addStateHandler(DoFilterNodes.STATE_NAME, DoFilterNodes.STATE_DESCRIPTION, DoFilterNodes.class);
295
296 setInitialState(LIST_ALL_TYPES);
297 }
298
299 /***
300 * Returns the title of this controller
301 *
302 * @return java.lang.String
303 */
304 public String getTitle() {
305 return "NodeAction Controller";
306 }
307
308 /***
309 * Lists the nodes for a particular type.
310 *
311 * @param request ExpressoRequest
312 * @param response ExpressoResponse
313 * @throws ControllerException
314 */
315 protected void runListNodesState(final ExpressoRequest request,
316 final ExpressoResponse response) throws ControllerException {
317 try {
318
319 Node querynode = new Node(request);
320
321
322 isValidAndPopulated(querynode, new String[0], null, request, response);
323
324 if (querynode.getNodeType().length() == 0) {
325
326 NodeType atype = new NodeType(RequestRegistry.getUser());
327 List list = atype.searchAndRetrieveList();
328
329 if (list.size() == 0) {
330 throw new ControllerException(
331 "Cannot find any node types for listing");
332 } else {
333 NodeType chosen = (NodeType) list.get(0);
334 getLogger()
335 .warn(
336 "in runListNodesState, no node type is set for fetching list of nodes; using first item in list, which is: "
337 + chosen.getEntityName());
338 querynode.setNodeType(chosen.getEntityName());
339 }
340 }
341
342 NodeType type = querynode.getEntity();
343
344 if ((type != null) && type.hasCustomHandler()) {
345 type.getCustomHandler().list(querynode, this,
346 (ControllerRequest) request,
347 (ControllerResponse) response);
348 } else {
349 list(querynode, request, response);
350 }
351 } catch (DBException dbe) {
352 throw new ControllerException(dbe);
353 }
354 }
355
356 /***
357 * List all nodes of type indicated by samplenode.
358 *
359 * @param samplenode has given type, but may NOT have an ID--it is just a sample
360 * @param request The ExpressoRequest object.
361 * @param response The ExpressoResponse object.
362 * @throws ControllerException upon error.
363 * @throws DBException upon database related error.
364 */
365 public void list(Node samplenode, ExpressoRequest request,
366 ExpressoResponse response) throws ControllerException, DBException {
367 String categoryName = request.getParameter(NodeType.DISPLAY_TITLE);
368
369 if (categoryName == null) {
370 categoryName = NodeType.getDisplayName(samplenode.getNodeType());
371 }
372
373 response.add(new Output(NodeType.DISPLAY_TITLE, categoryName));
374
375 String sortparam = request.getParameter(SORT_PARAM);
376
377 if (sortparam == null) {
378 sortparam = TITLE_SORT;
379 }
380
381 Block blockList = new Block("Nodes");
382 response.addBlock(blockList);
383
384 List list = null;
385 RecordPaginator paginator = new RecordPaginator();
386 paginator.setCountRecords(true);
387 paginator.setPageNumber((ControllerRequest) request);
388
389
390 NodeFilter filter = getFilter(request);
391 filter.addInputs(response);
392 if (!filter.isFiltered()) {
393 list = paginator.searchAndRetrieve(samplenode, getSort(sortparam));
394 } else {
395 MultiDBObject joinObject = filter.getMulti(samplenode);
396
397
398 setPageLimit(joinObject);
399
400
401 List multiList = paginator.searchAndRetrieve(joinObject, getSort(sortparam));
402
403
404 list = new ArrayList(multiList.size());
405 for (Iterator iterator = multiList.iterator(); iterator.hasNext();) {
406 MultiDBObject multiDBObject = (MultiDBObject) iterator.next();
407 Node anode = (Node) multiDBObject.getDBObject(Node.NODE_TABLE);
408 list.add(anode);
409 }
410 }
411
412 int numItems = list.size();
413
414 for (int k = 0; k < numItems; k++) {
415 Node node = (Node) list.get(k);
416
417
418 Block rowBlock = new Block("NodeItem");
419 blockList.add(rowBlock);
420
421
422
423 Output output = new Output(Node.NODE_TITLE,
424 str(node.getNodeTitle()));
425 rowBlock.add(output);
426 output = new Output(Node.NODE_ID, str(node.getNodeId()));
427 rowBlock.add(output);
428
429 String annotation = node.getNodeAnnotation();
430
431 if (!StringUtil.isBlankOrNull(annotation)) {
432 output = new Output(Node.NODE_ANNOTATION, str(annotation));
433 rowBlock.add(output);
434 }
435
436 output = new Output(Node.NODE_COMMENT, strTrunc(node
437 .getNodeComment(), MAX_CHARS_OUTPUT));
438 rowBlock.add(output);
439
440
441 List groups = node.getWriteGroups();
442 FastStringBuffer buf = FastStringBuffer.getInstance();
443
444 try {
445 boolean firsttime = true;
446
447 for (Iterator iter = groups.iterator(); iter.hasNext();) {
448 if (!firsttime) {
449 buf.append(", ");
450 }
451
452 String grp = (String) iter.next();
453 UserGroup group = new UserGroup();
454 group.setDBName(request.getDataContext());
455 group.setField(UserGroup.GROUP_NAME_FIELD, grp);
456
457 if (!group.find()) {
458 throw new DBException("cannot find group: " + grp);
459 }
460
461 buf.append(group.getGroupDescription());
462 firsttime = false;
463 }
464
465 output = new Output(EDIT_GROUP_DISPLAY, str(buf.toString()));
466 } finally {
467 buf.release();
468 buf = null;
469 }
470
471 rowBlock.add(output);
472
473 String owner = node.getNodeOwner();
474 output = new Output(Node.NODE_OWNER, str(owner));
475 rowBlock.add(output);
476
477
478 Transition editTransition = new Transition("", AddNodeAction.class,
479 AddNodeAction.VIEW_NODE);
480 editTransition.addParam(Node.NODE_ID, node.getNodeId());
481 checkEmbedded(request, editTransition);
482 rowBlock.add(editTransition);
483
484 if (node.canRequesterWrite()) {
485
486 Transition deleteTransition = new Transition(
487 PROMPT_DELETE_NODE, this);
488 deleteTransition.addParam(Node.NODE_ID, node.getNodeId());
489 checkEmbedded(request, deleteTransition);
490
491 rowBlock.add(deleteTransition);
492
493
494
495 Transition editPerms = new Transition(PROMPT_EDIT_PERMS, this);
496 editPerms.addParam(Node.NODE_ID, node.getNodeId());
497 checkEmbedded(request, editPerms);
498
499 rowBlock.add(editPerms);
500
501 }
502 }
503
504 if (samplenode.canRequesterAdd()) {
505
506
507 Transition addTransition = new Transition("Add "
508 + NodeType.getDisplayName(samplenode.getNodeType()),
509 AddNodeAction.class, AddNodeAction.PROMPT_EDIT_NODE);
510 addTransition.addParam(Node.NODE_TYPE, samplenode.getNodeType());
511 addTransition.addParam(NodeType.DISPLAY_TITLE, NodeType
512 .getDisplayName(samplenode.getNodeType()));
513 checkEmbedded(request, addTransition);
514
515 response.add(addTransition);
516
517 Transition importTrans = new Transition("Import",
518 AddNodeAction.class, AddNodeAction.PROMPT_IMPORT_NODE);
519 checkEmbedded(request, importTrans);
520
521 response.add(importTrans);
522 }
523
524 addSortTransitions(sortparam, request, response);
525
526
527 Block paginationBlock = generatePageTransitions(request, paginator, 10);
528 if (paginationBlock != null) {
529
530 if (isEmbeddedMode(request)) {
531 for (Enumeration transitionIterator = paginationBlock.getTransitions().elements(); transitionIterator.hasMoreElements();)
532 {
533 Transition eachPageTransition = (Transition) transitionIterator.nextElement();
534 addEmbeddedParameter(eachPageTransition);
535 }
536 }
537 response.add(paginationBlock);
538 }
539
540 response.add(new Output("pageCount", Integer.toString(paginator.getPageCount())));
541
542 }
543
544 /***
545 * add a parameter to any transition if we are embedded
546 */
547 public static void checkEmbedded(ExpressoRequest request, Transition addTransition) {
548 if (isEmbeddedMode(request)) {
549 addEmbeddedParameter(addTransition);
550 }
551 }
552
553 /***
554 * @return filter constructed from session + request info or null if no filtering
555 */
556 private NodeFilter getFilter(ExpressoRequest request) {
557 return new NodeFilter(request);
558 }
559
560 private void setPageLimit(MultiDBObject joinObject) throws DBException {
561 DBObjLimit dl = new DBObjLimit(SuperUser.INSTANCE);
562 dl.setDataContext(joinObject.getDataContext());
563 dl.setField("DBObjectName", Node.class.getName());
564 Integer pageLim = null;
565 if (dl.find()) {
566 pageLim = new Integer(dl.getField("PageLimit"));
567 } else {
568 pageLim = new Integer(50);
569 }
570 joinObject.setAttribute("pageLimit", pageLim);
571 }
572
573 /***
574 * Generates the page transitions.
575 *
576 * @param request expresso request.
577 * @param rp the record paginator.
578 * @param pageLimit the maximum number of page links to display at a time. (10, for
579 * example, is a good number).
580 * @return a block with the appropriate page transitions
581 * @throws ControllerException
582 */
583 protected Block generatePageTransitions(final ExpressoRequest request,
584 final RecordPaginator rp, int pageLimit) throws ControllerException {
585
586 Block returnBlock = null;
587
588 if (!rp.isCountRecords()) {
589 throw new java.lang.IllegalArgumentException(
590 "You must have countRecords set "
591 + "to true for pagination to work");
592 }
593
594 int endPage = rp.getPageCount();
595 if (endPage > 1) {
596
597 returnBlock = new Block();
598 returnBlock.setName("pageJumpBlock");
599
600 int curPage = rp.getPageNumber();
601
602 int startPage;
603 int index = 1;
604 if (curPage >= 10) {
605 startPage = curPage - (curPage % 10);
606 } else {
607 startPage = curPage - (curPage % 10) + 1;
608 }
609 if (endPage >= (startPage + 10)) {
610 endPage = curPage + (10 - (curPage % 10));
611 }
612
613 Class controllerClass = this.getClass();
614 Map allParameters = request.getAllParameters();
615 allParameters.remove(Controller.CONTROLLER_PARAM_KEY);
616 String state = (String) allParameters.get(Controller.STATE_PARAM_KEY);
617 allParameters.remove(Controller.STATE_PARAM_KEY);
618
619 if (curPage != 1) {
620 Transition t = new Transition();
621 t.setParams(allParameters);
622 t.setState(state);
623 t.setControllerObject(controllerClass);
624 t.addParam("page", Integer.toString(curPage - 1));
625 t.setLabel("< Prev");
626 t.setName(Integer.toString(index));
627 index++;
628 returnBlock.add(t);
629 }
630
631 for (int i = startPage; i <= endPage; i++) {
632 Transition t = new Transition();
633 t.setParams(allParameters);
634 t.setControllerObject(controllerClass);
635 t.addParam("page", Integer.toString(i));
636 t.setLabel(Integer.toString(i));
637 t.setState(state);
638 if (curPage == i) {
639 t.setAttribute("currentPage", "true");
640 Output o = new Output();
641 o.setName("CurrentPage");
642 o.setContent(Integer.toString(curPage));
643 returnBlock.add(o);
644 }
645 t.setName(Integer.toString(index));
646 index++;
647
648 returnBlock.add(t);
649 }
650
651 if (curPage < endPage) {
652 Transition t = new Transition();
653 t.setParams(allParameters);
654 t.setControllerObject(controllerClass);
655 t.addParam("page", Integer.toString(curPage + 1));
656 t.setState(state);
657 t.setLabel("Next >");
658 t.setName(Integer.toString(index));
659 index++;
660 returnBlock.add(t);
661 }
662
663 }
664
665 return returnBlock;
666 }
667
668 /***
669 * @param request The ExpressoRequest object.
670 * @param response The ExpressoResponse object.
671 * @throws ControllerException upon error.
672 * @throws DBException upon database related error.
673 */
674
675 private void addSortTransitions(String sortparam, ExpressoRequest request,
676 ExpressoResponse response) throws ControllerException, DBException {
677 String reverseSort = getReverseSortParam(sortparam);
678
679 String nodeType = request.getParameter(Node.NODE_TYPE);
680
681 if (!NodeType.isValidType(nodeType)) {
682 nodeType = getFirstNodeTypeInDB();
683 }
684
685 String specialDisplayNodeType = request
686 .getParameter(NodeType.NODE_TYPE_NAME);
687
688 Transition trans = null;
689
690 for (int i = 0; i < ALL_SORTS.length; i++) {
691 String oneSortKey = ALL_SORTS[i][0];
692
693
694 if (oneSortKey.equals(sortparam)) {
695
696
697 if (sortparam.endsWith(DESCENDING_FLAG)) {
698
699 trans = new Transition(reverseSort + ASCENDING_FLAG, "",
700 getClass(), LIST_NODE);
701 trans.addParam(SORT_PARAM, reverseSort);
702 trans.addParam(Node.NODE_TYPE, nodeType);
703 checkEmbedded(request, trans);
704
705 response.add(trans);
706
707
708 response.add(new Output(reverseSort, "true"));
709 } else {
710
711
712 trans = new Transition(reverseSort, "", getClass(),
713 LIST_NODE);
714 trans.addParam(SORT_PARAM, reverseSort);
715 trans.addParam(Node.NODE_TYPE, nodeType);
716 response.add(trans);
717 checkEmbedded(request, trans);
718
719
720 response.add(new Output(sortparam, "true"));
721 }
722
723 } else if (!reverseSort.equals(oneSortKey)) {
724
725 if ((i % 2) == 0) {
726 trans = new Transition(oneSortKey, "", getClass(),
727 LIST_NODE);
728 trans.addParam(SORT_PARAM, oneSortKey);
729 trans.addParam(Node.NODE_TYPE, nodeType);
730 checkEmbedded(request, trans);
731 response.add(trans);
732 }
733 }
734
735
736 if ((specialDisplayNodeType != null) && (trans != null)) {
737 trans.addParam(NodeType.NODE_TYPE_NAME, specialDisplayNodeType);
738 }
739 }
740 }
741
742 /***
743 * Return node type (in string form) of first node type in database.
744 *
745 * @return java.lang.String
746 * @throws DBException upon database related error.
747 */
748 private String getFirstNodeTypeInDB() throws DBException {
749 NodeType atype = new NodeType(RequestRegistry.getUser());
750 List list = atype.searchAndRetrieveList();
751 String result = "";
752
753 if (!list.isEmpty()) {
754 atype = (NodeType) list.get(0);
755 result = atype.getEntityName();
756 }
757
758 return result;
759 }
760
761 /***
762 * @param sort java.lang.String
763 * @return key which indicates reverse sort on same column
764 */
765 private String getReverseSortParam(String sort) {
766 String result = ALL_SORTS[1][0];
767
768 if (sort == null) {
769 if (getLogger().isDebugEnabled()) {
770 getLogger().debug("Sort == null");
771 }
772 } else {
773 for (int i = 0; i < ALL_SORTS.length; i++) {
774 String[] oneSort = ALL_SORTS[i];
775
776 if (oneSort[0].equals(sort)) {
777
778
779 if ((i % 2) == 0) {
780 result = ALL_SORTS[i + 1][0];
781 } else {
782 result = ALL_SORTS[i - 1][0];
783 }
784
785 break;
786 }
787 }
788 }
789
790 return result;
791 }
792
793 /***
794 * @param sort java.lang.String
795 * @return actual db sort string for use in list query
796 */
797 private String getSort(String sort) {
798 String result = ALL_SORTS[0][1];
799
800 if (sort == null) {
801 if (getLogger().isDebugEnabled()) {
802 getLogger().debug("Sort == null");
803 }
804 } else {
805 for (int i = 0; i < ALL_SORTS.length; i++) {
806 String[] oneSort = ALL_SORTS[i];
807
808 if (oneSort[0].equals(sort)) {
809 result = oneSort[1];
810
811 if (!result.startsWith(Node.NODE_TITLE)) {
812
813 result += ("|" + Node.NODE_TITLE);
814 }
815
816 break;
817 }
818 }
819 }
820
821 return result;
822 }
823
824 /***
825 * Display list with checkboxes and submit, in order to add relation to some
826 * other node.
827 *
828 * @param request The ExpressoRequest object.
829 * @param response The ExpressoResponse object.
830 * @throws ControllerException upon error.
831 */
832 protected void runPromptPickListNodesState(final ExpressoRequest request,
833 final ExpressoResponse response) throws ControllerException {
834 String type = request.getParameter(Node.NODE_TYPE);
835 String targetId = request.getParameter(Node.NODE_ID);
836 String relation = request.getParameter(Relation.RELATION_TYPE);
837
838 if ((type == null) || (targetId == null) || (relation == null)
839 || (type.length() == 0) || (targetId.length() == 0)
840 || (relation.length() == 0)) {
841 throw new ControllerException(
842 "type, targetId and relation are required parameters");
843 }
844
845 try {
846 Node target = new Node(request, targetId);
847 target.retrieve();
848
849
850 response.add(new Output(NodeType.DISPLAY_TITLE, NodeType
851 .getDisplayName(type)));
852 response.add(new Output(RelationType.RELATION_TYPE_DISPLAY_NAME,
853 RelationType.getRelTypeDisplayName(relation)));
854
855 response.add(new Output(Node.NODE_TITLE, target.getNodeTitle()));
856
857 Transition nodetrans = new Transition("", AddNodeAction.class,
858 AddNodeAction.VIEW_NODE);
859 nodetrans.addParam(Node.NODE_ID, targetId);
860 checkEmbedded(request, nodetrans);
861 response.add(nodetrans);
862
863 Input targetIdHidden = new Input(Node.NODE_ID);
864 targetIdHidden.setType(InputTag.TYPE_HIDDEN);
865 targetIdHidden.setDefaultValue(targetId);
866 response.add(targetIdHidden);
867
868 Input relationHidden = new Input(Relation.RELATION_TYPE);
869 relationHidden.setType(InputTag.TYPE_HIDDEN);
870 relationHidden.setDefaultValue(relation);
871 response.add(relationHidden);
872
873 Input typeHidden = new Input(Node.NODE_TYPE);
874 typeHidden.setType(InputTag.TYPE_HIDDEN);
875 typeHidden.setDefaultValue(type);
876 response.add(typeHidden);
877
878 Block selectedBlock = new Block(ROW_BLOCK);
879 response.addBlock(selectedBlock);
880
881 Block unselBlock = new Block(SIBLING_MARKER);
882 response.addBlock(unselBlock);
883
884 Hashtable reflexNodes = getReflexiveNodeHash(relation, target, type);
885 Node querynode = new Node(RequestRegistry.getUser());
886 querynode.setDBName(request.getDataContext());
887
888
889
890 if (!type.equals(NodeType.ANY_OBJECT)) {
891 querynode.setField(Node.NODE_TYPE, type);
892 querynode.setCustomWhereClause(Node.NODE_TYPE + " = '" + type
893 + "'");
894 }
895
896 querynode.setFieldsToRetrieve(Node.NODE_ID + "|" + Node.NODE_TITLE
897 + "|" + Node.NODE_ANNOTATION);
898
899 ArrayList allPossibleNodeList = querynode
900 .searchAndRetrieveList(Node.NODE_TITLE);
901
902
903 Node srcnode = new Node(request, targetId);
904 List multilist = srcnode.getRawRelated(relation, type);
905 Hashtable alreadySelectedHash = new Hashtable(multilist.size());
906
907
908 for (int i = 0; i < multilist.size(); i++) {
909 MultiDBObject aMultiObject = (MultiDBObject) multilist.get(i);
910 String destId = aMultiObject.getField(Node.NODE_JOIN,
911 Node.NODE_ID);
912 alreadySelectedHash.put(destId, aMultiObject);
913
914 Relation rel = (Relation) aMultiObject
915 .getDBObject(Node.RELATION_JOIN);
916
917
918 Node aNode = (Node) aMultiObject.getDBObject(Node.NODE_JOIN);
919
920 Block rowBlock = new Block(ROW);
921 selectedBlock.add(rowBlock);
922 rowBlock.add(getCheckbox(PICK_LIST_ITEM, "", rel.getDestId(),
923 true));
924
925 Transition trans = AddNodeAction.getViewTrans(rel.getDestId());
926 trans.setLabel(aNode.getNodeTitle());
927 checkEmbedded(request, trans);
928 rowBlock.add(trans);
929
930
931
932 Block decblock = new Block(AddNodeAction.DEC_REL_ORDER);
933 rowBlock.add(decblock);
934
935 Block incblock = new Block(AddNodeAction.INC_REL_ORDER);
936 rowBlock.add(incblock);
937
938 if (multilist.size() > 1) {
939 if (rel.getOrderInt() > 1) {
940 trans = new Transition("", AddNodeAction.class,
941 AddNodeAction.DEC_REL_ORDER);
942 trans.setName(AddNodeAction.DEC_REL_ORDER
943 + rel.getKey());
944 trans.addParam(Relation.RELATION_SRC, rel.getSrcId());
945 trans.addParam(Relation.RELATION_TYPE, rel
946 .getRelationTypeName());
947 trans.addParam(Relation.RELATION_DEST, rel.getDestId());
948 trans.setAttribute(Relation.RELATION_ORDER, rel
949 .getOrder());
950 checkEmbedded(request, trans);
951
952 decblock.add(trans);
953 }
954
955 if (rel.getOrderInt() < multilist.size()) {
956 trans = new Transition("", AddNodeAction.class,
957 AddNodeAction.INC_REL_ORDER);
958 trans.setName(AddNodeAction.INC_REL_ORDER
959 + rel.getKey());
960 trans.addParam(Relation.RELATION_SRC, rel.getSrcId());
961 trans.addParam(Relation.RELATION_TYPE, rel
962 .getRelationTypeName());
963 trans.addParam(Relation.RELATION_DEST, rel.getDestId());
964 trans.setAttribute(Relation.RELATION_ORDER, rel
965 .getOrder());
966 checkEmbedded(request, trans);
967 incblock.add(trans);
968 }
969 }
970 }
971
972 for (Iterator iterator = allPossibleNodeList.iterator(); iterator
973 .hasNext();) {
974 Node node = (Node) iterator.next();
975 String aNodeId = node.getNodeId();
976
977 if (alreadySelectedHash.get(aNodeId) != null) {
978 continue;
979 }
980
981
982 if (aNodeId.equals(targetId)) {
983 continue;
984 }
985
986 if (reflexNodes.get(aNodeId) != null) {
987 continue;
988
989 }
990
991
992 Block rowBlock = new Block(ROW);
993 unselBlock.add(rowBlock);
994
995
996
997
998 rowBlock.add(getCheckbox(PICK_LIST_ITEM, "", aNodeId, false));
999
1000
1001 Transition trans = AddNodeAction.getViewTrans(aNodeId);
1002 trans.setLabel(node.getNodeTitle());
1003 checkEmbedded(request, trans);
1004
1005 rowBlock.add(trans);
1006
1007
1008
1009 rowBlock.add(new Output(Node.NODE_ANNOTATION, str(node
1010 .getNodeAnnotation())));
1011 }
1012
1013
1014 Transition submit = new Transition(DO_PICKLIST_NODE, this);
1015 submit.setLabel("Save");
1016 checkEmbedded(request, submit);
1017 response.add(submit);
1018
1019 if (querynode.canRequesterAdd()) {
1020 addPrivilegedLinks(type, targetId, relation, request, response);
1021 }
1022 } catch (DBException dbe) {
1023 throw new ControllerException(dbe);
1024 }
1025 }
1026
1027 private void addPrivilegedLinks(String type, String targetId,
1028 String relation, ExpressoRequest request, ExpressoResponse response)
1029 throws DBException, ControllerException {
1030
1031
1032 Transition addTransition = new Transition("Add New "
1033 + NodeType.getDisplayName(type), AddNodeAction.class,
1034 AddNodeAction.PROMPT_EDIT_NODE);
1035 addTransition.addParam(Node.NODE_TYPE, type);
1036
1037
1038 addTransition.addParam(RELATION_TARGET, targetId);
1039 addTransition.addParam(Relation.RELATION_TYPE, relation);
1040 checkEmbedded(request, addTransition);
1041
1042 response.add(addTransition);
1043 }
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058 private Hashtable getReflexiveNodeHash(String relation, Node target,
1059 String type) throws DBException {
1060 RelationType relType = new RelationType();
1061 relType.setRelType(relation);
1062 relType.retrieve();
1063
1064 Hashtable reflexNodes = null;
1065
1066 if (relType.isReflexive()) {
1067 reflexNodes = new Hashtable(target.getRelatedNodesHash(relType
1068 .getInverseRelType().getRelTypeName(), type, null));
1069
1070
1071
1072
1073 } else {
1074 reflexNodes = new Hashtable();
1075 }
1076
1077 return reflexNodes;
1078 }
1079
1080 protected void runDoPickListNodesState(
1081 final ServletControllerRequest request,
1082 final ExpressoResponse response) throws ControllerException,
1083 DBException {
1084
1085 String targetId = request.getParameter(Node.NODE_ID);
1086 String relationType = request.getParameter(Relation.RELATION_TYPE);
1087 String nodeType = request.getParameter(Node.NODE_TYPE);
1088
1089 if ((targetId == null) || (relationType == null)
1090 || (targetId.length() == 0) || (relationType.length() == 0)
1091 || (nodeType == null) || (nodeType.length() == 0)) {
1092 throw new ControllerException(
1093 "targetId, nodeType and relationType are required parameters");
1094 }
1095
1096 Node node = new Node(request, request.getParameter(Node.NODE_ID));
1097 node.retrieve();
1098
1099
1100 Hashtable reflexNodes = getReflexiveNodeHash(relationType, node,
1101 nodeType);
1102 String[] checkValues = getParamValues(
1103 (ServletControllerRequest) request, PICK_LIST_ITEM);
1104
1105
1106 if ((checkValues != null) && (checkValues.length > 1)) {
1107
1108 String parentType = node.getNodeType();
1109 Part part = PartsFactory
1110 .getPart(parentType, nodeType, relationType);
1111
1112 if (part == null) {
1113 getLogger().error(
1114 "cannot find part for parent/nodetype/relation: "
1115 + parentType + "/" + nodeType + "/"
1116 + relationType);
1117 } else if (!part.areMultipleAttributesAllowed()) {
1118 response
1119 .addError("Only 1 item is allowed. Please choose just one.");
1120 response.setFormCache();
1121
1122 Transition trans = new Transition("x", "", NodeAction.class,
1123 NodeAction.PROMPT_PICKLIST_NODE);
1124 Map parameters = request.getAllParameters();
1125 parameters.remove(CONTROLLER_PARAM_KEY);
1126 parameters.remove(STATE_PARAM_KEY);
1127 trans.setParams(parameters);
1128 checkEmbedded(request, trans);
1129 trans.executeTransition(request, response);
1130
1131 return;
1132 }
1133 }
1134
1135
1136
1137
1138 for (int k = 0; (checkValues != null) && (k < checkValues.length); k++) {
1139 String nodeId = checkValues[k];
1140
1141
1142 if (reflexNodes.get(nodeId) != null) {
1143 response
1144 .addError("Cannot add a relation that already has a reciprocal relation for: "
1145 + ((Node) reflexNodes.get(nodeId))
1146 .getNodeTitle());
1147 response.setFormCache();
1148
1149 Transition trans = new Transition("", NodeAction.class,
1150 NodeAction.PROMPT_PICKLIST_NODE);
1151 Map parameters = request.getAllParameters();
1152 parameters.remove(CONTROLLER_PARAM_KEY);
1153 parameters.remove(STATE_PARAM_KEY);
1154 trans.setParams(parameters);
1155 checkEmbedded(request, trans);
1156 trans.executeTransition(request, response);
1157
1158 return;
1159 }
1160
1161 }
1162
1163
1164 node.updateNodeRelations(nodeType, relationType, checkValues);
1165
1166 Transition trans = new Transition("", AddNodeAction.class,
1167 AddNodeAction.VIEW_NODE);
1168 trans.addParam(Node.NODE_ID, targetId);
1169
1170
1171 boolean sentRedirect = redirectToSender(request, "Update Saved");
1172
1173 if (sentRedirect) {
1174 return;
1175 }
1176
1177 trans.redirectTransition(request, response);
1178 }
1179
1180 /***
1181 * Optional submit button for adding attributes AND getting chance to add
1182 * more.
1183 *
1184 * @param request The ExpressoRequest object.
1185 * @param response The ExpressoResponse object.
1186 * @throws ControllerException upon error.
1187 */
1188 protected void runDoEditMoreAttribState(ExpressoRequest request,
1189 ExpressoResponse response) throws ControllerException {
1190 saveAllAttribs(request);
1191
1192 try {
1193
1194 Transition trans = new Transition(PROMPT_EDIT_ATTRIB, this);
1195 String nodeId = request.getParameter(Node.NODE_ID);
1196 trans.addParam(Node.NODE_ID, nodeId);
1197
1198 String attribType = request.getParameter(Attribute.ATTRIBUTE_TYPE);
1199 trans.addParam(Attribute.ATTRIBUTE_TYPE, attribType);
1200 checkEmbedded(request, trans);
1201 trans.redirectTransition(request, response);
1202 } catch (Exception dbe) {
1203 throw new ControllerException(dbe);
1204 }
1205 }
1206
1207 /***
1208 * Attribute info comes in as sets. A set includes the attribute value,
1209 * comment, and either <p/> 1) id (if existing) or
1210 * </p>
1211 * <p/>
1212 * 2) type (if new)
1213 * </p>
1214 * <p/>
1215 * We can pick any one of the set, like the value item, then save all the
1216 * items in the set with that set number (the number is the suffix of the
1217 * param name)
1218 * </p>
1219 *
1220 * @param request The ExpressoRequest object.
1221 * @param response The ExpressoResponse object.
1222 * @throws ControllerException upon error.
1223 * @throws NonHandleableException upon transition error.
1224 */
1225 protected void runDoEditAttribState(final ServletControllerRequest request,
1226 final ExpressoResponse response) throws ControllerException,
1227 NonHandleableException {
1228 try {
1229 saveAttribs(request);
1230 Transition trans = AddNodeAction.getViewTrans(request
1231 .getParameter(Node.NODE_ID));
1232
1233 if (redirectToSender(request, "Update Saved")) {
1234 return;
1235 }
1236 trans.redirectTransition(request, response);
1237 } catch (DBException dbe) {
1238 ErrorCollection errors = new ErrorCollection();
1239 errors.addError(dbe.getMessage());
1240 response.setFormCache();
1241 response.saveErrors(errors);
1242
1243 try {
1244 transition(LIST_NODE, request, response);
1245 } catch (NonHandleableException nhe) {
1246 throw new ControllerException(nhe);
1247 }
1248 }
1249 }
1250
1251 private void saveAttribs(ExpressoRequest request) throws DBException,
1252 ControllerException {
1253
1254 String attribId = request.getParameter(Attribute.ATTRIBUTE_ID);
1255
1256 if ((attribId != null) && (attribId.length() > 0)) {
1257
1258 Attribute attribute = new Attribute(attribId);
1259 attribute.retrieve();
1260
1261 String value = request.getParameter(Attribute.ATTRIBUTE_VALUE);
1262 String comment = request.getParameter(Attribute.ATTRIBUTE_COMMENT);
1263 if (comment != null) {
1264 comment = comment.trim();
1265 }
1266 attribute.setAttributeValue(value);
1267 attribute.setAttributeComment(comment);
1268 attribute.update(true);
1269
1270
1271 Node node = attribute.getParentNode();
1272 node.touch();
1273
1274 request.setParameter(Node.NODE_ID, node.getNodeId());
1275 request.setParameter(Attribute.ATTRIBUTE_TYPE, attribute
1276 .getAttribType());
1277 } else {
1278
1279 saveAllAttribs(request);
1280 }
1281 }
1282
1283 /***
1284 * Saves the picklist attributes.
1285 *
1286 * @param request ServletControllerRequest the servlet controller request
1287 * (servlet environment only)
1288 * @param response ExpressoResponse the controller response
1289 * @throws ControllerException upon error.
1290 * @throws NonHandleableException upon fatal error.
1291 */
1292 protected void runDoAttribPickState(final ServletControllerRequest request,
1293 final ExpressoResponse response) throws ControllerException,
1294 NonHandleableException {
1295 try {
1296 String attribId = request.getParameter(Attribute.ATTRIBUTE_ID);
1297 String value = request.getParameter(Attribute.ATTRIBUTE_VALUE);
1298 String comment = request.getParameter(Attribute.ATTRIBUTE_COMMENT);
1299
1300 if ((attribId != null) && (attribId.length() > 0)) {
1301
1302 Attribute attribute = new Attribute(attribId);
1303 attribute.retrieve();
1304
1305 attribute.setAttributeValue(value);
1306 attribute.setAttributeComment(comment);
1307 attribute.update(true);
1308
1309
1310 attribute.getParentNode().touch();
1311 } else {
1312
1313
1314 String nodeId = request.getParameter(Node.NODE_ID);
1315 String attribType = request
1316 .getParameter(Attribute.ATTRIBUTE_TYPE);
1317
1318
1319 if ((nodeId == null) || (nodeId.length() == 0)
1320 || (attribType == null) || (attribType.length() == 0)) {
1321 throw new ControllerException(
1322 "nodeId and attrib_type are required parameters");
1323 }
1324
1325
1326
1327 if ((value.length() == 0) && (comment.length() == 0)) {
1328 throw new ControllerException(
1329 "found no value or comment to save");
1330 }
1331
1332
1333
1334 Node node = new Node(request, nodeId);
1335
1336 if (!node.find()) {
1337 throw new ControllerException("cannot find node with id: "
1338 + nodeId);
1339 }
1340
1341 Attribute attribute = new Attribute();
1342 attribute.setField(Attribute.ATTRIBUTE_TYPE, attribType);
1343 attribute.setField(Attribute.NODE_ID, nodeId);
1344 attribute.setField(Attribute.NODE_TYPE, node.getNodeType());
1345 attribute.setField(Attribute.ATTRIBUTE_VALUE, value);
1346 attribute.setField(Attribute.ATTRIBUTE_COMMENT, comment);
1347 attribute.add();
1348
1349 node.touch();
1350 }
1351
1352
1353 Transition trans = AddNodeAction.getViewTrans(request
1354 .getParameter(Node.NODE_ID));
1355
1356 if (redirectToSender(request, "Update Saved")) {
1357 return;
1358 }
1359
1360 trans.redirectTransition(request, response);
1361 } catch (DBException dbe) {
1362 ErrorCollection errors = new ErrorCollection();
1363 errors.addError(dbe.getMessage());
1364 response.setFormCache();
1365 response.saveErrors(errors);
1366
1367 try {
1368 transition(LIST_NODE, request, response);
1369 } catch (NonHandleableException nhe) {
1370 throw new ControllerException(nhe);
1371 }
1372 }
1373 }
1374
1375 protected void runDoDeleteAttribState(ExpressoRequest request,
1376 ExpressoResponse response) throws ControllerException {
1377 try {
1378
1379
1380
1381
1382
1383 String attribId = request.getParameter(Attribute.ATTRIBUTE_ID);
1384 request.removeParameter(Attribute.ATTRIBUTE_ID);
1385 saveAttribs(request);
1386
1387
1388 Attribute attrib = new Attribute(attribId);
1389 attrib.retrieve();
1390 Node node = attrib.getParentNode();
1391 attrib.delete();
1392
1393
1394
1395 if (node.getAttributes(attrib.getAttribType()).length > 0) {
1396 Transition trans = new Transition(PROMPT_EDIT_ATTRIB, this);
1397 trans
1398 .addParam(Attribute.ATTRIBUTE_TYPE, attrib
1399 .getAttribType());
1400 trans.addParam(Node.NODE_ID, node.getNodeId());
1401 checkEmbedded(request, trans);
1402 trans.redirectTransition(request, response);
1403 } else {
1404
1405 Transition trans = AddNodeAction.getViewTrans(node.getNodeId());
1406 checkEmbedded(request, trans);
1407 trans.redirectTransition(request, response);
1408 }
1409 } catch (DBException dbe) {
1410 ErrorCollection errors = new ErrorCollection();
1411 errors.addError(dbe.getMessage());
1412 response.setFormCache();
1413 response.saveErrors(errors);
1414
1415 try {
1416 transition(LIST_NODE, request, response);
1417 } catch (NonHandleableException nhe) {
1418 throw new ControllerException(nhe);
1419 }
1420 }
1421 }
1422
1423 private void saveAllAttribs(ExpressoRequest request)
1424 throws ControllerException {
1425 Set keys = new TreeSet(request.getAllParameters().keySet());
1426 for (Iterator iterator = keys.iterator(); iterator.hasNext();) {
1427 String paramName = (String) iterator.next();
1428
1429
1430
1431 if (paramName.startsWith(Attribute.ATTRIBUTE_VALUE_PREFIX)) {
1432 int startChar = Attribute.ATTRIBUTE_VALUE_PREFIX.length();
1433 int setNum = Integer.parseInt(paramName.substring(startChar));
1434 saveAttribute(request, setNum);
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449 }
1450 }
1451 }
1452
1453 /***
1454 * Prompts for editing a node attribute.
1455 *
1456 * @param request ExpressoRequest
1457 * @param response ExpressoResponse
1458 * @throws ControllerException
1459 */
1460 protected void runPromptEditAttribState(final ExpressoRequest request,
1461 final ExpressoResponse response) throws ControllerException {
1462 String nodeId = request.getParameter(Node.NODE_ID);
1463 String attribName = request.getParameter(Attribute.ATTRIBUTE_TYPE);
1464
1465 try {
1466 String attribDisplayName = null;
1467 Part part = null;
1468
1469 Node node = new Node(request, nodeId);
1470
1471 if (!node.find()) {
1472 response
1473 .addError("Cannot find an item with ID="
1474 + nodeId
1475 + ". You may have used an obsolete link, "
1476 + "where the item has been deleted. Please navigate to and use a fresh list of items.");
1477
1478 Transition trans = new Transition("", NodeAction.class,
1479 NodeAction.INDEX);
1480 checkEmbedded(request, trans);
1481 trans.executeTransition(request, response);
1482
1483 return;
1484 }
1485
1486 part = PartsFactory.getAttribPart(node.getNodeType(), attribName);
1487 attribDisplayName = part.getPartLabel();
1488 response.add(new Output(Node.NODE_TITLE, node.getNodeTitle()));
1489 response.add(new Output(Attribute.ATTRIBUTE_DISPLAY_NAME,
1490 attribDisplayName));
1491
1492 Attribute[] attribs = node.getAttributes(part.getPartType());
1493 Attribute representativeAttribute = getRepAttribute(attribs, node,
1494 attribName);
1495
1496 if (representativeAttribute.hasCustomHandler()) {
1497 IPartHandler handler = representativeAttribute
1498 .getCustomHandler();
1499
1500 try {
1501 Transition trans = handler.getEditTransition(request
1502 .getAllParameters());
1503 if (trans != null) {
1504 if (isEmbeddedMode(request)) {
1505 addEmbeddedParameter(trans);
1506 addReturnToSenderParameter(request, response, trans);
1507 }
1508 trans.executeTransition(request, response, false);
1509 return;
1510 }
1511 } catch (Exception e) {
1512 throw new ControllerException(e);
1513 }
1514 }
1515
1516
1517 if (part.hasPicklist()) {
1518 Transition trans = new Transition(PROMPT_ATTRIB_PICK, this);
1519 trans.addParam(Node.NODE_ID, nodeId);
1520 trans.addParam(Attribute.ATTRIBUTE_TYPE, attribName);
1521 if (isEmbeddedMode(request)) {
1522 addEmbeddedParameter(trans);
1523 addReturnToSenderParameter(request, response, trans);
1524 }
1525 trans.executeTransition(request, response);
1526
1527 return;
1528 }
1529
1530 if (!part.areMultipleAttributesAllowed()) {
1531 response.add(new Output(Part.CARDINALITY,
1532 " (only single attribute allowed) "));
1533 }
1534
1535
1536 Transition addTrans = new Transition(PROMPT_ADD_ATTRIB, this);
1537 Map parameters = request.getAllParameters();
1538 parameters.remove(CONTROLLER_PARAM_KEY);
1539 parameters.remove(STATE_PARAM_KEY);
1540 addTrans.setParams(parameters);
1541 if (isEmbeddedMode(request)) {
1542 addReturnToSenderParameter(request, response, addTrans);
1543 addEmbeddedParameter(addTrans);
1544 }
1545
1546 if (attribs.length == 0) {
1547
1548 addTrans.executeTransition(request, response);
1549 return;
1550 } else if (part.areMultipleAttributesAllowed()) {
1551
1552
1553 response.add(addTrans);
1554 if (attribs.length > 1) {
1555 response.add(new Output(Part.PART_NUM, "Y"));
1556 }
1557 }
1558
1559 response.add(getAttributeInputBlock(attribs, part, request, false));
1560
1561 response.add(AddNodeAction.getViewTrans(nodeId));
1562
1563
1564 Transition trans = new Transition("", getClass(), DO_EDIT_ATTRIB);
1565 trans.addParam(Node.NODE_ID, nodeId);
1566 trans.addParam(Attribute.ATTRIBUTE_TYPE, attribName);
1567 if (isEmbeddedMode(request)) {
1568 addEmbeddedParameter(trans);
1569 addReturnToSenderParameter(request, response, trans);
1570 }
1571 response.add(trans);
1572 } catch (Exception e) {
1573 throw new ControllerException(e);
1574 }
1575 }
1576
1577 public static Attribute getRepAttribute(final List attribs,
1578 final Node node, final String attribName) throws DBException {
1579 Attribute representativeAttribute = null;
1580 if (attribs.size() > 0) {
1581 representativeAttribute = (Attribute) attribs.get(0);
1582 } else {
1583 representativeAttribute = new Attribute(node);
1584 representativeAttribute.setAttributeType(attribName);
1585 }
1586 return representativeAttribute;
1587 }
1588
1589 public Attribute getRepAttribute(final Attribute[] attribs,
1590 final Node node, final String attribName) throws DBException {
1591 Attribute representativeAttribute = null;
1592 if (attribs.length > 0) {
1593 representativeAttribute = attribs[0];
1594 } else {
1595 representativeAttribute = new Attribute(node);
1596 representativeAttribute.setAttributeType(attribName);
1597 }
1598 return representativeAttribute;
1599 }
1600
1601 /***
1602 * Prompts for editing a picklist attribute.
1603 *
1604 * @param request ExpressoRequest the ExpressoRequest object.
1605 * @param response ExpressoResponse the ExpressoResponse object.
1606 * @throws ControllerException upon error.
1607 */
1608 protected void runPromptAttribPickState(final ExpressoRequest request,
1609 final ExpressoResponse response) throws ControllerException {
1610 String nodeId = request.getParameter(Node.NODE_ID);
1611 String attribName = request.getParameter(Attribute.ATTRIBUTE_TYPE);
1612
1613 try {
1614
1615 Node node = new Node(request, nodeId);
1616
1617 if (!node.find()) {
1618 response
1619 .addError("Cannot find an item with ID="
1620 + nodeId
1621 + ". You may have used an obsolete link, "
1622 + "where the item has been deleted. Please navigate to and use a fresh list of items.");
1623
1624 Transition trans = new Transition("", NodeAction.class,
1625 NodeAction.INDEX);
1626 checkEmbedded(request, trans);
1627 trans.executeTransition(request, response);
1628
1629 return;
1630 }
1631
1632 Part part = PartsFactory.getAttribPart(node.getNodeType(),
1633 attribName);
1634
1635 String attribDisplayName = part.getPartLabel();
1636 response.add(new Output(Node.NODE_TITLE, node.getNodeTitle()));
1637 response.add(new Output(Attribute.ATTRIBUTE_DISPLAY_NAME,
1638 attribDisplayName));
1639
1640 Attribute[] attribs = node.getAttributes(part.getPartType());
1641 Attribute representativeAttribute = getRepAttribute(attribs, node,
1642 attribName);
1643
1644
1645 if (representativeAttribute.hasCustomHandler()) {
1646 try {
1647 Transition trans = representativeAttribute
1648 .getEditTrans(request.getAllParameters());
1649 if (trans != null) {
1650 checkEmbedded(request, trans);
1651 trans.executeTransition(request, response, false);
1652 return;
1653 }
1654 } catch (Exception e) {
1655 throw new ControllerException(e);
1656 }
1657 }
1658
1659 if (!part.hasPicklist()) {
1660 throw new ControllerException(
1661 "unexpected that this attribute does not have picklist: "
1662 + part.getPartType() + " for nodeId: " + nodeId);
1663 }
1664
1665 Block blk = addPicklist(part, request, response, nodeId);
1666 response.add(blk);
1667
1668 Transition addTrans = new Transition("Save", NodeAction.class,
1669 DO_ATTRIB_PICK);
1670 addTrans.addParam(Node.NODE_ID, nodeId);
1671 addTrans.addParam(Attribute.ATTRIBUTE_TYPE, attribName);
1672 if (isEmbeddedMode(request)) {
1673 addEmbeddedParameter(addTrans);
1674 addReturnToSenderParameter(request, response, addTrans);
1675 }
1676
1677 String attribId = blk.getAttribute(Attribute.ATTRIBUTE_ID);
1678 if ((attribId != null) && (attribId.length() > 0)) {
1679 addTrans.addParam(Attribute.ATTRIBUTE_ID, attribId);
1680 }
1681
1682 response.add(addTrans);
1683 } catch (Exception e) {
1684 throw new ControllerException(e);
1685 }
1686 }
1687
1688 /***
1689 * Prompts for adding an attribute.
1690 *
1691 * @param request ExpressoRequest The <tt>ExpressoRequest</tt> object.
1692 * @param response ExpressoResponse The <tt>ExpressoResponse</tt> object.
1693 * @throws ControllerException upon error.
1694 */
1695 protected void runPromptAddAttribState(
1696 final ServletControllerRequest request,
1697 final ExpressoResponse response) throws ControllerException {
1698 String nodeId = request.getParameter(Node.NODE_ID);
1699 String attribName = request.getParameter(Attribute.ATTRIBUTE_TYPE);
1700
1701 try {
1702 String attribDisplayName = null;
1703 Part part = null;
1704
1705 Node node = new Node(request, nodeId);
1706
1707 if (!node.find()) {
1708 response
1709 .addError("Cannot find an item with ID="
1710 + nodeId
1711 + ". You may have used an obsolete link, "
1712 + "where the item has been deleted. Please navigate to and "
1713 + "use a fresh list of items.");
1714
1715 if (this.redirectToSender(request, null)) {
1716 return;
1717 }
1718
1719 Transition trans = new Transition("", NodeAction.class,
1720 NodeAction.INDEX);
1721 trans.executeTransition(request, response);
1722
1723 return;
1724 }
1725
1726 part = PartsFactory.getAttribPart(node.getNodeType(), attribName);
1727 attribDisplayName = part.getPartLabel();
1728 response.add(new Output(Node.NODE_TITLE, node.getNodeTitle()));
1729 response.add(new Output(Attribute.ATTRIBUTE_DISPLAY_NAME,
1730 attribDisplayName));
1731
1732 Attribute[] attribs = node.getAttributes(part.getPartType());
1733 Attribute representative = getRepAttribute(attribs, node,
1734 attribName);
1735
1736 if (representative.hasCustomHandler()) {
1737 try {
1738 Transition trans = representative.getEditTrans(request
1739 .getAllParameters());
1740 if (trans != null) {
1741 if (isEmbeddedMode(request)) {
1742 addEmbeddedParameter(trans);
1743 propagateReturnToSenderParameter(request, response,
1744 trans);
1745 }
1746 trans.executeTransition(request, response, false);
1747 return;
1748 }
1749 } catch (Exception e) {
1750 throw new ControllerException(e);
1751 }
1752 }
1753
1754
1755 int num_empty_attribs = 5;
1756
1757 if (!part.areMultipleAttributesAllowed()) {
1758 num_empty_attribs = 1;
1759 response.add(new Output(Part.CARDINALITY,
1760 " (only single attribute allowed) "));
1761 }
1762
1763 Block rowBlock = new Block(ROW_BLOCK);
1764 response.add(rowBlock);
1765
1766 for (int i = 0; i < num_empty_attribs; i++) {
1767
1768 Block row = new Block(ROW);
1769 rowBlock.add(row);
1770
1771 Input valueInput = getTextArea(getValueParamName(i), null, part
1772 .numDisplayLines(), TEXTAREA_NUM_COLS);
1773 row.add(valueInput);
1774
1775 Input commentInput = getTextArea(getCommentParamName(i), null,
1776 part.numDisplayLines(), TEXTAREA_NUM_COLS);
1777 row.add(commentInput);
1778 }
1779
1780 Transition addTrans = new Transition("Add", NodeAction.class,
1781 DO_EDIT_ATTRIB);
1782 addTrans.addParam(Node.NODE_ID, nodeId);
1783 addTrans.addParam(Attribute.ATTRIBUTE_TYPE, attribName);
1784 if (isEmbeddedMode(request)) {
1785 propagateReturnToSenderParameter(request, response, addTrans);
1786 addEmbeddedParameter(addTrans);
1787 }
1788 response.add(addTrans);
1789
1790
1791 response.add(AddNodeAction.getViewTrans(node.getNodeId()));
1792 } catch (Exception e) {
1793 throw new ControllerException(e);
1794 }
1795 }
1796
1797 /***
1798 * Edits a single attribute.
1799 *
1800 * @param request ExpressoRequest
1801 * @param response ExpressoResponse
1802 * @throws ControllerException
1803 */
1804 protected void runPromptEditOneAttribState(final ExpressoRequest request,
1805 final ExpressoResponse response) throws ControllerException {
1806 String attribId = request.getParameter(Attribute.ATTRIBUTE_ID);
1807
1808 try {
1809 Attribute attrib = new Attribute(attribId);
1810 attrib.retrieve();
1811
1812 Node node = attrib.getParentNode();
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825 Part part = PartsFactory.getAttribPart(node.getNodeType(), attrib
1826 .getAttribType());
1827
1828 if (attrib.hasCustomHandler()) {
1829 try {
1830 Transition trans = attrib.getEditTrans(request
1831 .getAllParameters());
1832 checkEmbedded(request, trans);
1833 if (trans != null) {
1834 trans.executeTransition(request, response, false);
1835 return;
1836 }
1837 } catch (Exception e) {
1838 throw new ControllerException(e);
1839 }
1840 }
1841
1842 String attribDisplayName = part.getPartLabel();
1843 response.add(new Output(Node.NODE_TITLE, node.getNodeTitle()));
1844 response.add(new Output(Attribute.ATTRIBUTE_DISPLAY_NAME,
1845 attribDisplayName));
1846
1847 Input in = new Input(Attribute.ATTRIBUTE_VALUE);
1848 in.setDefaultValue(attrib.getAttribValueRaw());
1849 response.add(in);
1850 in = new Input(Attribute.ATTRIBUTE_COMMENT);
1851 in.setDefaultValue(attrib.getAttribCommentRaw().trim());
1852 response.add(in);
1853
1854 Transition trans = new Transition("Save", NodeAction.class,
1855 DO_EDIT_ATTRIB);
1856 trans.addParam(Attribute.ATTRIBUTE_ID, attribId);
1857 checkEmbedded(request, trans);
1858 response.add(trans);
1859
1860
1861 response.add(AddNodeAction.getViewTrans(node.getNodeId()));
1862
1863
1864 trans = new Transition(DO_DELETE_ONE_ATTRIB, this);
1865 trans.addParam(Attribute.ATTRIBUTE_ID, attribId);
1866 checkEmbedded(request, trans);
1867 response.add(trans);
1868 } catch (Exception e) {
1869 throw new ControllerException(e);
1870 }
1871 }
1872
1873 public static Node getNode(ExpressoRequest request, String nodeId)
1874 throws DBException {
1875 Node node = new Node(request, nodeId);
1876 node.retrieve();
1877
1878 return node;
1879 }
1880
1881 /***
1882 * Write changes in attribute to DB. An erased attribute means that we
1883 * should *delete* the item from the DB.
1884 *
1885 * @param request The ExpressoRequest Object
1886 * @param setNum integer
1887 * @return Attribute
1888 * @throws ControllerException upon error.
1889 */
1890 protected Attribute saveAttribute(ExpressoRequest request, int setNum)
1891 throws ControllerException {
1892 try {
1893 String id = request.getParameter(getIdParamName(setNum));
1894
1895
1896 String value = request.getParameter(getValueParamName(setNum));
1897 String comment = request.getParameter(getCommentParamName(setNum));
1898
1899
1900 String nodeId = request.getParameter(Node.NODE_ID);
1901 String attribType = request.getParameter(Attribute.ATTRIBUTE_TYPE);
1902
1903 boolean isNew = (id == null) || (id.length() == 0)
1904 || id.equals(Attribute.ATTRIBUTE_ID_UNKNOWN);
1905
1906
1907
1908 if ((value.length() == 0) && (comment.length() == 0)) {
1909 return null;
1910 }
1911
1912
1913 if ((nodeId == null) || (nodeId.length() == 0)
1914 || (attribType == null) || (attribType.length() == 0)) {
1915 throw new ControllerException(
1916 "nodeId and attrib_type are required parameters");
1917 }
1918
1919
1920 Node node = new Node(request, nodeId);
1921
1922 if (!node.find()) {
1923 throw new ControllerException("cannot find node with id: "
1924 + nodeId);
1925 }
1926
1927 if (isNew) {
1928 return node.addAttribute(attribType, value, comment);
1929 } else {
1930 try {
1931 return node.updateAttribute(id, value, comment);
1932 } catch (DBRecordNotFoundException ex) {
1933 getLogger().warn(ex.getMessage());
1934 return node.addAttribute(attribType, value, comment);
1935 }
1936 }
1937
1938 } catch (DBException dbe) {
1939 throw new ControllerException(dbe);
1940 }
1941 }
1942
1943 /***
1944 * Utility to create an input block for a given attribute part. <p/> this
1945 * method is complicated by fact that we must associate sets of items
1946 * together as inputs; we'll get back just a pile of parameters from the
1947 * HTML page POST, so we need a way to prefix param names such that they can
1948 * be grouped together later.
1949 * </p>
1950 *
1951 * @param attribs The attributes for the part.
1952 * @param part The part itself. later.
1953 * @param request The ExpressoRequest object
1954 * @return populated Block
1955 * @throws ControllerException upon error.
1956 */
1957 protected Block getAttributeInputBlock(final Attribute[] attribs,
1958 final Part part, final ExpressoRequest request, boolean readOnly)
1959 throws ControllerException {
1960 Block typeBlock = new Block(ROW_BLOCK);
1961
1962 try {
1963
1964
1965
1966
1967
1968 int itemNum = 0;
1969
1970 for (int i = 0; i < attribs.length; i++) {
1971 Attribute attribute = attribs[i];
1972 String attribId = attribute.getAttribId();
1973
1974
1975 Block rowBlock = new Block(ROW);
1976 typeBlock.add(rowBlock);
1977
1978 Block aDeleteBlock = new Block(DO_DELETE_ONE_ATTRIB);
1979 rowBlock.add(aDeleteBlock);
1980 if (!readOnly) {
1981 Transition trans = new Transition(DO_DELETE_ONE_ATTRIB,
1982 this);
1983 trans.setName(DO_DELETE_ONE_ATTRIB + i);
1984
1985
1986
1987 trans.addParam(Attribute.ATTRIBUTE_ID, attribId);
1988 checkEmbedded(request, trans);
1989 aDeleteBlock.add(trans);
1990 }
1991 Input valueInput = new Input(getValueParamName(itemNum));
1992 if (readOnly) {
1993 valueInput.setAttribute(Input.ATTRIBUTE_READONLY,
1994 "readonly");
1995 }
1996 rowBlock.add(valueInput);
1997
1998 if (!part.hasPicklist()) {
1999 valueInput.setMaxLength(4000);
2000 valueInput.setType(InputTag.TYPE_TEXTAREA);
2001 valueInput.setLines(part.numDisplayLines());
2002 valueInput.setDisplayLength(TEXTAREA_NUM_COLS);
2003
2004
2005 valueInput.setDefaultValue(attribute.getAttribValueRaw());
2006 }
2007
2008
2009
2010
2011 Input commentInput = getTextArea(getCommentParamName(itemNum),
2012 attribute.getAttribCommentRaw(),
2013 part.numDisplayLines(), TEXTAREA_NUM_COLS);
2014
2015 if (readOnly) {
2016 commentInput.setAttribute(Input.ATTRIBUTE_READONLY,
2017 "readonly");
2018 }
2019
2020 rowBlock.add(commentInput);
2021
2022
2023 Input hiddenId = new Input(getIdParamName(itemNum));
2024 rowBlock.add(hiddenId);
2025 hiddenId.setType(InputTag.TYPE_HIDDEN);
2026 hiddenId.setDefaultValue(attribId);
2027
2028 itemNum++;
2029
2030 if (!readOnly) {
2031
2032
2033 Block decblock = new Block(AddNodeAction.DEC_ATTRIB_ORDER);
2034 rowBlock.add(decblock);
2035
2036 Block incblock = new Block(AddNodeAction.INC_ATTRIB_ORDER);
2037 rowBlock.add(incblock);
2038
2039 if (attribs.length > 1) {
2040 if (attribute.getOrderInt() > 1) {
2041 final Transition trans = new Transition("",
2042 AddNodeAction.class,
2043 AddNodeAction.DEC_ATTRIB_ORDER);
2044 trans.setName(AddNodeAction.DEC_ATTRIB_ORDER
2045 + attribute.getAttribId());
2046 trans.addParam(Attribute.ATTRIBUTE_ID, attribute
2047 .getAttribId());
2048 checkEmbedded(request, trans);
2049 decblock.add(trans);
2050 }
2051
2052 if (attribute.getOrderInt() < attribs.length) {
2053 final Transition trans = new Transition("",
2054 AddNodeAction.class,
2055 AddNodeAction.INC_ATTRIB_ORDER);
2056 trans.setName(AddNodeAction.INC_ATTRIB_ORDER
2057 + attribute.getAttribId());
2058 trans.addParam(Attribute.ATTRIBUTE_ID, attribute
2059 .getAttribId());
2060 checkEmbedded(request, trans);
2061 incblock.add(trans);
2062 }
2063 }
2064 }
2065 }
2066 } catch (Exception dbe) {
2067 throw new ControllerException(dbe);
2068 }
2069
2070 return typeBlock;
2071 }
2072
2073 public static Block addPicklist(Part part, ExpressoRequest request,
2074 ExpressoResponse response, String nodeId) throws Exception {
2075 Block rowBlock = new Block(ROW_BLOCK);
2076
2077
2078 Input valueInput = new Input(Attribute.ATTRIBUTE_VALUE);
2079 rowBlock.add(valueInput);
2080 valueInput.setType(InputTag.TYPE_DROPDOWN);
2081
2082
2083 String selected = "";
2084 String comment = "";
2085
2086
2087 Node node = new Node(request, nodeId);
2088 Attribute[] attribs = node.getAttributes(part.getPartType());
2089 boolean hasAttrib = attribs.length > 0;
2090
2091 if (hasAttrib) {
2092 Attribute attribute = attribs[0];
2093 selected = attribute.getAttribValue();
2094
2095 if (selected == null) {
2096 selected = "";
2097 }
2098
2099 comment = attribute.getAttribComment();
2100
2101 if (comment == null) {
2102 comment = "";
2103 }
2104
2105 rowBlock.setAttribute(Attribute.ATTRIBUTE_ID, attribute
2106 .getAttribId());
2107 }
2108
2109 String[][] picklistArray = null;
2110
2111 try {
2112 picklistArray = part.getPicklistArray(request);
2113 } catch (Exception e) {
2114 throw new DBException(e);
2115 }
2116
2117 boolean foundSelected = false;
2118 String defaultSelected = "";
2119 if (picklistArray.length > 0 && picklistArray[0].length > 0) {
2120 defaultSelected = picklistArray[0][0];
2121
2122
2123 } else {
2124 response.addError("Picklist is empty!");
2125 }
2126
2127 for (int i = 0; i < picklistArray.length; i++) {
2128 valueInput.addValidValue(picklistArray[i][0], picklistArray[i][1]);
2129
2130 if (selected.equals(picklistArray[i][0])) {
2131 foundSelected = true;
2132 valueInput.setDefaultValue(picklistArray[i][0]);
2133 }
2134
2135
2136 if (PickList.NOT_SPECIFIED_DISPLAY.equals(picklistArray[i][0])) {
2137 defaultSelected = PickList.NOT_SPECIFIED_DISPLAY;
2138 }
2139 }
2140
2141
2142 if (!foundSelected) {
2143 valueInput.setDefaultValue(defaultSelected);
2144 }
2145
2146
2147 List picklist = null;
2148 picklist = part.getPicklist(request);
2149
2150
2151
2152 if ((picklist.size() > 0)
2153 && ((PickList) picklist.get(0)).canRequesterWrite()) {
2154 Transition promptEditPicklist = new Transition("",
2155 PicklistAction.class, PicklistAction.PROMPT_LIST);
2156 rowBlock.add(promptEditPicklist);
2157 promptEditPicklist.addParam(PickList.NODE_TYPE, part
2158 .getParentType());
2159 promptEditPicklist.addParam(PickList.ATTRIBUTE_TYPE, part
2160 .getPartType());
2161 checkEmbedded(request, promptEditPicklist);
2162 promptEditPicklist.addParam(Node.NODE_ID, nodeId);
2163 }
2164 Input commentInput = getTextArea(Attribute.ATTRIBUTE_COMMENT, comment);
2165 rowBlock.add(commentInput);
2166
2167 return rowBlock;
2168 }
2169
2170 /***
2171 * Utility to create an output block for a given shared node part.
2172 *
2173 * @param srcNodeId The source node.
2174 * @param srcType The source node type.
2175 * @param request The ExpressoRequest object
2176 * @param part the Part we're rendering to the block.
2177 * @param nodeTitle Unused
2178 * @param canEdit true if the node can be edited.
2179 * @return populated block.
2180 * @throws ControllerException upon error.
2181 * @throws DBException upon database error.
2182 */
2183 protected Block getSharedNodeBlock(String srcNodeId, String srcType,
2184 ExpressoRequest request, Part part, String nodeTitle,
2185 boolean canEdit) throws ControllerException, DBException {
2186 if (part.isOwnedAttribute()) {
2187 throw new ControllerException("cannot handle attribute node here");
2188 }
2189
2190 Block typeBlock = new Block("part");
2191 typeBlock.add(new Output(Part.PART_DISPLAY_NAME, part.getPartLabel()));
2192
2193
2194
2195 typeBlock
2196 .add(new Output(Relation.RELATION_TYPE, part.getNodeRelation()));
2197
2198
2199
2200
2201 if (srcType.equals(part.getPartType())) {
2202 typeBlock.add(new Output(Part.PART_HELP_STRING, part
2203 .getNodeRelation()));
2204 } else {
2205 typeBlock
2206 .add(new Output(Part.PART_HELP_STRING, part.getPartType()));
2207 }
2208
2209 try {
2210 Node srcnode = new Node(request, srcNodeId);
2211 Node[] related = srcnode.getRelatedNodes(part.getNodeRelation(),
2212 part.getPartType());
2213
2214
2215
2216
2217 for (int i = 0; i < related.length; i++) {
2218 Node node = related[i];
2219
2220
2221 Block rowBlock = new Block(ROW_BLOCK);
2222 typeBlock.add(rowBlock);
2223
2224 String blockNodeId = node.getNodeId();
2225
2226
2227 rowBlock.add(new Output(Node.NODE_TITLE, node.getNodeTitle()));
2228 rowBlock.add(new Output(Node.NODE_ANNOTATION, strTrunc(node
2229 .getNodeAnnotation(), MAX_CHARS_OUTPUT)));
2230
2231
2232
2233 rowBlock.add(new Output(Relation.RELATION_ANNOTATION, str("")));
2234 rowBlock.add(new Output(Node.NODE_COMMENT, strTrunc(node
2235 .getNodeComment(), MAX_CHARS_OUTPUT)));
2236
2237
2238 Transition editTransition = new Transition(
2239 AddNodeAction.VIEW_NODE, "View", AddNodeAction.class,
2240 AddNodeAction.VIEW_NODE);
2241 checkEmbedded(request, editTransition);
2242 editTransition.addParam(Node.NODE_ID, blockNodeId);
2243 rowBlock.add(editTransition);
2244 }
2245 } catch (DBException e) {
2246 throw new ControllerException(e);
2247 }
2248
2249 if (canEdit) {
2250 Transition associateTrans = new Transition(PROMPT_PICKLIST_NODE,
2251 this);
2252 associateTrans.setLabel("Edit");
2253 associateTrans.addParam(Node.NODE_TYPE, part.getPartType());
2254
2255
2256 associateTrans.addParam(Node.NODE_ID, srcNodeId);
2257 associateTrans.addParam(Relation.RELATION_TYPE, part
2258 .getNodeRelation());
2259 checkEmbedded(request, associateTrans);
2260 typeBlock.add(associateTrans);
2261 }
2262
2263 return typeBlock;
2264 }
2265
2266 /***
2267 * Add number suffix from to Attribute.ATTRIBUTE_COMMENT_PREFIX.
2268 *
2269 * @param setNum The number to add.
2270 * @return String.
2271 */
2272 private static String getCommentParamName(int setNum) {
2273 return Attribute.ATTRIBUTE_COMMENT_PREFIX + setNum;
2274 }
2275
2276 /***
2277 * Add number suffix from to Attribute.ATTRIBUTE_ID_PREFIX.
2278 *
2279 * @param setNum The number to add.
2280 * @return java.lang.String.
2281 */
2282 private static String getIdParamName(int setNum) {
2283 return Attribute.ATTRIBUTE_ID_PREFIX + setNum;
2284 }
2285
2286 /***
2287 * Ddd number suffix from to Attribute.ATTRIBUTE_VALUE_PREFIX.
2288 *
2289 * @param setNum The number suffix
2290 * @return java.lang.String.
2291 */
2292 private static String getValueParamName(int setNum) {
2293 return Attribute.ATTRIBUTE_VALUE_PREFIX + setNum;
2294 }
2295
2296 /***
2297 * Find all properly-typed nodes related to this source node, with relation
2298 * of given type.
2299 *
2300 * @param srcNodeId
2301 * source node id
2302 * @param relation
2303 * the relationship type
2304 * @param nodeType
2305 * nodes of this type (only) will be returned
2306 * @param orderList
2307 * (returned param) list to receive ordered list of
2308 * MultiDBObjects; pass in null if you don't want this list added
2309 * @return hash with key = node Id, value = node
2310 * @throws DBException
2311 * upon error.
2312 */
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335 /***
2336 * Prompt to confirm delete.
2337 *
2338 * @param request The ExpressoRequest object.
2339 * @param response The ExpressoResponse object.
2340 * @throws ControllerException upon error.
2341 */
2342 protected void runPromptDeleteNodeState(final ExpressoRequest request,
2343 final ExpressoResponse response) throws ControllerException {
2344 try {
2345 Node existing = getNode(request);
2346 String titleStr = existing.getNodeTitle();
2347
2348 response.add(new Output(Node.NODE_TITLE, titleStr));
2349
2350
2351 Transition submitTransition = new Transition(DO_DELETE_NODE, this);
2352 submitTransition.setLabel("Delete");
2353 submitTransition.addParam(Node.NODE_ID, existing.getNodeId());
2354 response.add(submitTransition);
2355
2356 Transition treeTransition = new Transition(PROMPT_DELETE_NODE_TREE,
2357 this);
2358 treeTransition.setLabel("Delete tree...");
2359 treeTransition.addParam(Node.NODE_ID, existing.getNodeId());
2360 checkEmbedded(request, treeTransition);
2361 response.add(treeTransition);
2362 } catch (DBException dbe) {
2363 ErrorCollection errors = new ErrorCollection();
2364 errors.addError(dbe.getMessage());
2365 response.setFormCache();
2366 response.saveErrors(errors);
2367
2368 try {
2369 transition(LIST_NODE, request, response);
2370 } catch (NonHandleableException nhe) {
2371 throw new ControllerException(nhe);
2372 }
2373 }
2374 }
2375
2376 public static Node getNode(final ExpressoRequest request)
2377 throws ControllerException, DBException {
2378 String nodeId = request.getParameter(Node.NODE_ID);
2379
2380 if ((nodeId == null) || (nodeId.length() == 0)) {
2381 throw new ControllerException("nodeId is a required parameter");
2382 }
2383
2384 return getNode(request, nodeId);
2385 }
2386
2387 /***
2388 * show lists of contained nodes that will be deleted (with checkmarks for
2389 * opt-out) and list of contained nodes that will not because they are
2390 * contained 'externally' to this tree. <p/> algorithm is complex: we can
2391 * determine internal/external links easily enough when given a hash of all
2392 * nodes in tree: any links to tree-external node makes a node undeletable.
2393 * But for all the nodes considered 'internal' on the first pass, some of
2394 * their containers might be declared undeletable. Then we need additional
2395 * passes to make sure the nodes established as undeletable in pass N-1 also
2396 * 'preserves' any nodes it contains. <p/> In other words, a branch is
2397 * deleted only if its root is not external, and vice-versa.
2398 */
2399 protected void runPromptDeleteNodeTreeState(final ExpressoRequest request,
2400 final ExpressoResponse response) throws ControllerException {
2401 try {
2402
2403
2404
2405
2406 Node existing = getNode(request);
2407
2408 response.add(new Output(Node.NODE_TITLE, existing.getNodeTitle()));
2409
2410
2411 Transition submitTransition = new Transition(DO_DELETE_NODE, this);
2412 submitTransition.setLabel("Delete");
2413 submitTransition.addParam(Node.NODE_ID, existing.getNodeId());
2414 checkEmbedded(request, submitTransition);
2415 response.add(submitTransition);
2416
2417
2418 HashMap allNodeHash = new HashMap();
2419 existing.setAttribute(Node.INDENT, new Integer(1));
2420
2421
2422
2423
2424
2425 existing.getNodesInStronglyRelatedTree(request, allNodeHash);
2426
2427
2428
2429 Set saveSet = new HashSet(allNodeHash.values().size());
2430 Set toDeleteSet = new HashSet();
2431 TreeDeletionSelector selector = new TreeDeletionSelector(
2432 allNodeHash);
2433 selector.determineDeletionTree(existing, saveSet, toDeleteSet);
2434
2435
2436 List toDelete = new ArrayList(toDeleteSet);
2437 List notdel = new ArrayList(saveSet);
2438
2439
2440 Block noDelBlock = new Block(PERMS_BLOCK);
2441 response.add(noDelBlock);
2442 Collections.sort(notdel, new IndentComparator());
2443
2444 for (Iterator iterator = notdel.iterator(); iterator.hasNext();) {
2445 Node anode = (Node) iterator.next();
2446 String blkname = "";
2447 Integer indent = (Integer) anode.getAttribute(Node.INDENT);
2448
2449 if (indent != null) {
2450 blkname = StringUtil.repeatString(
2451 " ", indent
2452 .intValue());
2453 }
2454
2455 Block rowblk = new Block(blkname);
2456 noDelBlock.add(rowblk);
2457
2458
2459
2460 Transition trans = AddNodeAction
2461 .getViewTrans(anode.getNodeId());
2462 trans.setLabel(anode.getNodeTitle());
2463 checkEmbedded(request, trans);
2464 rowblk.add(trans);
2465
2466 rowblk.add(new Output(Node.NODE_TYPE, anode.getEntity()
2467 .getDisplayName()));
2468 }
2469
2470
2471 Collections.sort(toDelete, new IndentComparator());
2472
2473 Block deleteBlock = new Block(ROW_BLOCK);
2474 response.add(deleteBlock);
2475
2476 for (Iterator iterator = toDelete.iterator(); iterator.hasNext();) {
2477 Node anode = (Node) iterator.next();
2478 String blkname = "";
2479 Integer indent = (Integer) anode.getAttribute(Node.INDENT);
2480
2481 if (indent != null) {
2482 blkname = StringUtil.repeatString(
2483 " ", indent
2484 .intValue());
2485 }
2486
2487 Block rowblk = new Block(blkname);
2488 deleteBlock.add(rowblk);
2489
2490
2491
2492 Transition trans = AddNodeAction
2493 .getViewTrans(anode.getNodeId());
2494 trans.setLabel(anode.getNodeTitle());
2495 checkEmbedded(request, trans);
2496 rowblk.add(trans);
2497
2498 rowblk.add(new Output(Node.NODE_TYPE, anode.getEntity()
2499 .getDisplayName()));
2500
2501 Input in = new Input(SIBLING_MARKER);
2502 in.setType(InputTag.TYPE_CHECKBOX);
2503 in.addValidValue(anode.getNodeId(), "");
2504 in.setDefaultValue(anode.getNodeId());
2505 rowblk.add(in);
2506 in.setAttribute(Input.SELECTED, "true");
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516 allNodeHash = null;
2517 selector = null;
2518 saveSet = null;
2519 toDeleteSet = null;
2520 toDelete = null;
2521 notdel = null;
2522 System.gc();
2523 }
2524 } catch (Exception dbe) {
2525 throw new ControllerException(dbe);
2526 }
2527 }
2528
2529 /***
2530 * Performs the deletion of the node after prompt state.
2531 *
2532 * @param request ServletControllerRequest the servlet controller request.
2533 * @param response ExpressoResponse
2534 * @throws ControllerException
2535 */
2536 protected void runDoDeleteNodeState(final ServletControllerRequest request,
2537 final ExpressoResponse response) throws ControllerException {
2538 try {
2539 Node existing = getNode(request);
2540
2541
2542 final boolean isTreeDelete = request
2543 .getParameter(PROMPT_DELETE_NODE_TREE) != null;
2544
2545
2546
2547
2548
2549
2550 if (isTreeDelete) {
2551 Transition trans = new Transition(PROMPT_DELETE_NODE_TREE, this);
2552 trans.addParam(Node.NODE_ID, existing.getNodeId());
2553 checkEmbedded(request, trans);
2554 trans.redirectTransition(request, response);
2555
2556 return;
2557 }
2558
2559
2560 Transition trans = null;
2561
2562
2563 NodeType entity = existing.getEntity();
2564
2565 if (entity.hasCustomHandler()) {
2566 INodeHandler handler = entity.getCustomHandler();
2567 trans = handler.getListTransition(request);
2568 } else {
2569 trans = getListTransition(existing.getNodeType());
2570 }
2571
2572 assert trans != null : "Transition should not be null by this point";
2573 checkEmbedded(request, trans);
2574
2575 existing.delete(true);
2576
2577
2578
2579 String[] delIds = getParamValues(
2580 (ServletControllerRequest) request, SIBLING_MARKER);
2581
2582 for (int i = 0; (delIds != null) && (i < delIds.length); i++) {
2583 String id = delIds[i];
2584 getNode(request, id).delete();
2585 }
2586
2587 trans.redirectTransition(request, response);
2588 } catch (Exception dbe) {
2589 throw new ControllerException(dbe);
2590 }
2591 }
2592
2593 /***
2594 * @param type node type of desired list; null is ok--will default to first
2595 * list (design patterns)
2596 * @return Transition.
2597 */
2598 public static Transition getListTransition(String type) {
2599 Transition trans = new Transition("", NodeAction.class, LIST_NODE);
2600 trans.addParam(Node.NODE_TYPE, type);
2601 return trans;
2602 }
2603
2604 /***
2605 * Prompts for cloning the node.
2606 *
2607 * @param request ExpressoRequest
2608 * @param response ExpressoResponse
2609 * @throws ControllerException
2610 */
2611 protected void runPromptCloneNodeState(ExpressoRequest request,
2612 ExpressoResponse response) throws ControllerException {
2613 String nodeId = request.getParameter(Node.NODE_ID);
2614
2615 if ((nodeId == null) || (nodeId.length() == 0)) {
2616 throw new ControllerException("nodeId is a required parameter");
2617 }
2618
2619 try {
2620 Node existing = new Node(request, nodeId);
2621 existing.retrieve();
2622
2623 addAttribIO(nodeId, response, existing);
2624
2625
2626 Transition submitTransition = new Transition(DO_CLONE_NODE, this);
2627 submitTransition.setLabel("Duplicate an Independent");
2628 checkEmbedded(request, submitTransition);
2629 response.add(submitTransition);
2630
2631 Transition siblingTrans = new Transition(SIBLING_MARKER, "",
2632 getClass(), DO_CLONE_NODE);
2633 siblingTrans.addParam(SIBLING_MARKER, "true");
2634 siblingTrans.setLabel("Duplicate Within Container");
2635 checkEmbedded(request, siblingTrans);
2636 response.add(siblingTrans);
2637
2638 Transition treeTrans = new Transition(PROMPT_CLONE_TREE, "",
2639 getClass(), PROMPT_CLONE_TREE);
2640 treeTrans.setLabel("Duplicate Entire Tree Beneath");
2641 checkEmbedded(request, treeTrans);
2642 response.add(treeTrans);
2643 } catch (DBException dbe) {
2644 ErrorCollection errors = new ErrorCollection();
2645 errors.addError(dbe.getMessage());
2646 response.setFormCache();
2647 response.saveErrors(errors);
2648
2649 try {
2650 transition(LIST_NODE, request, response);
2651 } catch (NonHandleableException nhe) {
2652 throw new ControllerException(nhe);
2653 }
2654 }
2655 }
2656
2657 private void addAttribIO(String nodeId, ExpressoResponse response,
2658 Node existing) throws ControllerException, DBException {
2659 Input hiddenId = new Input(Node.NODE_ID);
2660 hiddenId.setType(InputTag.TYPE_HIDDEN);
2661 hiddenId.setDefaultValue(nodeId);
2662 response.add(hiddenId);
2663
2664 Input titleInput = new Input(Node.NODE_TITLE);
2665 titleInput.setType(InputTag.TYPE_TEXT);
2666 titleInput.setDefaultValue("Copy of " + existing.getNodeTitle());
2667 response.add(titleInput);
2668
2669
2670 Input input = new Input(TITLE_SORT);
2671 input.setType(InputTag.TYPE_TEXT);
2672 input.setDefaultValue("copy");
2673 response.add(input);
2674
2675 Output output = new Output(Node.NODE_TITLE, existing.getNodeTitle());
2676 response.add(output);
2677 }
2678
2679 /***
2680 * Prompts for cloning an entire tree of nodes.
2681 *
2682 * @param request ExpressoRequest
2683 * @param response ExpressoResponse
2684 * @throws ControllerException
2685 */
2686 protected void runPromptCloneTreeState(final ExpressoRequest request,
2687 final ExpressoResponse response) throws ControllerException {
2688 String nodeId = request.getParameter(Node.NODE_ID);
2689
2690 if ((nodeId == null) || (nodeId.length() == 0)) {
2691 throw new ControllerException("nodeId is a required parameter");
2692 }
2693
2694 try {
2695 Node existing = new Node(request, nodeId);
2696 existing.retrieve();
2697
2698 Input hiddenId = new Input(Node.NODE_ID);
2699 hiddenId.setType(InputTag.TYPE_HIDDEN);
2700 hiddenId.setDefaultValue(nodeId);
2701 response.add(hiddenId);
2702
2703 Input titleInput = new Input(Node.NODE_TITLE);
2704 titleInput.setType(InputTag.TYPE_TEXT);
2705 titleInput.setDefaultValue("Copy of " + existing.getNodeTitle());
2706 response.add(titleInput);
2707
2708 Output output = new Output(Node.NODE_TITLE, existing.getNodeTitle());
2709 response.add(output);
2710
2711
2712
2713
2714 Transition treeTrans = new Transition(DO_CLONE_TREE, "",
2715 getClass(), DO_CLONE_TREE);
2716 treeTrans.addParam(Node.NODE_ID, nodeId);
2717 treeTrans.setLabel("Duplicate Entire Tree Beneath");
2718 checkEmbedded(request, treeTrans);
2719 response.add(treeTrans);
2720 } catch (DBException dbe) {
2721 ErrorCollection errors = new ErrorCollection();
2722 errors.addError(dbe.getMessage());
2723 response.setFormCache();
2724 response.saveErrors(errors);
2725
2726 try {
2727 transition(LIST_NODE, request, response);
2728 } catch (NonHandleableException nhe) {
2729 throw new ControllerException(nhe);
2730 }
2731 }
2732 }
2733
2734 /***
2735 * Clone either orphan or sibling. If this is the ORPHAN clone, where
2736 * "owning" relations are not copied, creating an orphan object
2737 * has links to the shared relations "below" it in the "part
2738 * of" relation hierarchy, but not links to similar relations
2739 * "above" this object. in contrast, sibling clones also
2740 * duplicated the 'container' relations
2741 *
2742 * @param request The ExpressoRequest object.
2743 * @param response The ExpressoResponse object.
2744 * @throws ControllerException upon error.
2745 */
2746 protected void runDoCloneNodeState(ExpressoRequest request,
2747 ExpressoResponse response) throws ControllerException, DBException {
2748 String nodeId = request.getParameter(Node.NODE_ID);
2749
2750 if (nodeId == null) {
2751 throw new ControllerException("nodeId is a required parameter");
2752 }
2753
2754 String title = request.getParameter(Node.NODE_TITLE);
2755
2756 if (title == null) {
2757 throw new ControllerException("title is a required parameter");
2758 }
2759
2760 ErrorCollection ec = new ErrorCollection();
2761
2762 Node origNode = new Node(nodeId);
2763 origNode.retrieve();
2764
2765 NodeCloner nodeCloner = new NodeCloner(origNode, title);
2766 Node clone = null;
2767
2768
2769 String sibling = request.getParameter(SIBLING_MARKER);
2770 if (sibling == null) {
2771 clone = nodeCloner.cloneAsOrphan(ec);
2772 } else {
2773 clone = nodeCloner.cloneAsSibling(ec);
2774 }
2775
2776 if (ec.size() > 0) {
2777 response.saveErrors(ec);
2778 Transition trans = new Transition(PROMPT_CLONE_NODE, this);
2779 trans.addParam(Node.NODE_ID, nodeId);
2780 checkEmbedded(request, trans);
2781 trans.executeTransition(request, response);
2782
2783 return;
2784 }
2785
2786 assert clone != null : "Cloned node should have been either clone or there should have been errors";
2787
2788
2789 Transition trans = new Transition("", "", AddNodeAction.class,
2790 AddNodeAction.VIEW_NODE);
2791 trans.addParam(Node.NODE_ID, clone.getNodeId());
2792 checkEmbedded(request, trans);
2793 trans.redirectTransition(request, response);
2794 }
2795
2796 /***
2797 * Clone either orphan or sibling. if this is the ORPHAN clone, where
2798 * "owning" relations are not copied, creating an orphan object
2799 * has links to the shared relations "below" it in the "part
2800 * of" relation hierarchy, but not links to similar relations
2801 * "above" this object. in contrast, sibling clones also
2802 * duplicated the 'container' relations
2803 *
2804 * @param request The ExpressoRequest object.
2805 * @param response The ExpressoResponse object.
2806 * @throws ControllerException upon error.
2807 */
2808 protected void runDoCloneTreeState(ExpressoRequest request,
2809 ExpressoResponse response) throws ControllerException {
2810 String nodeId = request.getParameter(Node.NODE_ID);
2811
2812 if (nodeId == null) {
2813 throw new ControllerException("nodeId is a required parameter");
2814 }
2815
2816 String title = request.getParameter(Node.NODE_TITLE);
2817
2818 if (title == null) {
2819 throw new ControllerException("title is a required parameter");
2820 }
2821
2822 try {
2823 Node origNode = new Node(request, nodeId);
2824 origNode.retrieve();
2825
2826
2827 Node titleSearch = new Node(request);
2828 titleSearch.setNodeTitle(title);
2829
2830 if (titleSearch.find()) {
2831 response.addError("Duplicate title not allowed. Please choose"
2832 + " something different.");
2833
2834 Transition trans = new Transition(PROMPT_CLONE_NODE, this);
2835 trans.addParam(Node.NODE_ID, nodeId);
2836 checkEmbedded(request, trans);
2837 trans.executeTransition(request, response);
2838
2839 return;
2840 }
2841
2842
2843
2844 HashMap map = new HashMap();
2845
2846 Node clone = origNode.cloneTree(title, map);
2847
2848
2849 Transition trans = new Transition("", "", AddNodeAction.class,
2850 AddNodeAction.VIEW_NODE);
2851 trans.addParam(Node.NODE_ID, clone.getNodeId());
2852 checkEmbedded(request, trans);
2853 trans.redirectTransition(request, response);
2854 } catch (Exception dbe) {
2855 throw new ControllerException(dbe);
2856 }
2857 }
2858
2859 /***
2860 * Generate an index of all nodes--just use shortcuts from (auto) footer.
2861 *
2862 * @param request The ExpressoRequest object.
2863 * @param response The ExpressoResponse object.
2864 * @throws ControllerException upon error.
2865 */
2866 protected void runIndexState(final ExpressoRequest request,
2867 final ExpressoResponse response) throws ControllerException {
2868 }
2869
2870 /***
2871 * Edit permission groups for this node.
2872 *
2873 * @param request The ExpressoRequest object.
2874 * @param response The ExpressoResponse object.
2875 * @throws ControllerException upon error.
2876 */
2877 protected void runPromptEditPermsState(final ExpressoRequest request,
2878 final ExpressoResponse response) throws ControllerException {
2879 String nodeId = request.getParameter(Node.NODE_ID);
2880
2881 if (nodeId == null) {
2882 throw new ControllerException("nodeId is a required parameter");
2883 }
2884
2885 try {
2886 Node origNode = getNode(request);
2887 response.add(new Output(Node.NODE_TITLE, origNode.getNodeTitle()));
2888
2889 Transition trans = new Transition(AddNodeAction.VIEW_NODE, "",
2890 AddNodeAction.class, AddNodeAction.VIEW_NODE);
2891 trans.addParam(Node.NODE_ID, origNode.getNodeId());
2892 checkEmbedded(request, trans);
2893
2894 response.add(trans);
2895
2896 List groupsOfUsersMembership = RequestRegistry.getUser()
2897 .getGroupsList();
2898
2899 List groupsForListing;
2900 if (request.getUserInfo().isAdmin()) {
2901
2902 List allgrps = UserGroup.getAllGroups();
2903 groupsForListing = new ArrayList(allgrps.size());
2904 for (Iterator iterator = allgrps.iterator(); iterator.hasNext();) {
2905 UserGroup group = (UserGroup) iterator.next();
2906 groupsForListing.add(group.getGroupName());
2907 }
2908 } else {
2909 groupsForListing = new ArrayList(groupsOfUsersMembership);
2910 }
2911
2912 groupsForListing.remove(UserGroup.ALL_USERS_GROUP);
2913
2914
2915 groupsForListing.remove(UserGroup.UNKNOWN_USERS_GROUP);
2916 groupsForListing.remove(UserGroup.NOT_REG_USERS_GROUP);
2917
2918
2919 List nodeGroups = origNode.getGroups();
2920
2921 if (nodeGroups.size() > 0) {
2922 Block permblock = new Block(NodeAction.PERMS_BLOCK);
2923 response.add(permblock);
2924
2925 int i = 0;
2926
2927 for (Iterator iterator = nodeGroups.iterator(); iterator
2928 .hasNext();) {
2929 RowGroupPerms groupperms = (RowGroupPerms) iterator.next();
2930
2931 if (groupperms.canGroupWrite()) {
2932 Block rowBlock = new Block(ROW_BLOCK);
2933 permblock.add(rowBlock);
2934
2935
2936 groupsForListing.remove(groupperms.group());
2937
2938
2939 UserGroup usergroup = new UserGroup();
2940 usergroup.setRequestingUser(SuperUser.INSTANCE);
2941
2942
2943
2944
2945
2946 usergroup.setGroupName(groupperms.group());
2947 usergroup.retrieve();
2948
2949 rowBlock.add(new Output(UserGroup.GROUP_NAME_FIELD,
2950 usergroup.getGroupDescription()));
2951
2952 trans = new Transition(REMOVE_GROUP + i++, "Remove",
2953 getClass(), REMOVE_GROUP);
2954 trans.addParam(Node.NODE_ID, origNode.getNodeId());
2955 checkEmbedded(request, trans);
2956 trans.addParam(UserGroup.GROUP_NAME_FIELD, groupperms
2957 .group());
2958 rowBlock.add(trans);
2959 }
2960 }
2961 }
2962
2963 if (groupsForListing.size() > 0) {
2964
2965 Block permblock = new Block(NodeAction.ADD_GROUP);
2966 response.add(permblock);
2967
2968 int i = 0;
2969
2970 for (Iterator iterator = groupsForListing.iterator(); iterator
2971 .hasNext();) {
2972 String groupname = (String) iterator.next();
2973
2974 Block rowBlock = new Block(ROW_BLOCK);
2975 permblock.add(rowBlock);
2976
2977
2978 UserGroup usergroup = new UserGroup();
2979 usergroup.setRequestingUser(User.getAdmin(request
2980 .getDataContext()));
2981
2982 usergroup.setGroupName(groupname);
2983 usergroup.retrieve();
2984
2985 rowBlock.add(new Output(UserGroup.GROUP_NAME_FIELD,
2986 usergroup.getGroupDescription()));
2987
2988 trans = new Transition(ADD_GROUP + i++, "Add", getClass(),
2989 ADD_GROUP);
2990 trans.addParam(Node.NODE_ID, origNode.getNodeId());
2991 trans.addParam(UserGroup.GROUP_NAME_FIELD, groupname);
2992 checkEmbedded(request, trans);
2993 rowBlock.add(trans);
2994 }
2995 }
2996 } catch (Exception dbe) {
2997 throw new ControllerException(dbe);
2998 }
2999 }
3000
3001 /***
3002 * Edit permission groups for this node.
3003 *
3004 * @param request The ExpressoRequest object.
3005 * @param response The ExpressoResponse object.
3006 * @throws ControllerException upon error.
3007 */
3008 protected void runRemoveGroupState(final ExpressoRequest request,
3009 final ExpressoResponse response) throws ControllerException {
3010 String nodeId = request.getParameter(Node.NODE_ID);
3011
3012 if (nodeId == null) {
3013 throw new ControllerException("nodeId is a required parameter");
3014 }
3015
3016 String group = request.getParameter(UserGroup.GROUP_NAME_FIELD);
3017
3018 if (group == null) {
3019 throw new ControllerException("group name is a required parameter");
3020 }
3021
3022 try {
3023 Node origNode = new Node(request, nodeId);
3024 origNode.retrieve();
3025
3026 Transition trans = NodeAction.getListTransition(origNode
3027 .getNodeType());
3028 checkEmbedded(request, trans);
3029
3030 List list = origNode.getGroups();
3031
3032 if (list.size() == 1) {
3033 response.addError("Cannot remove last group");
3034 trans.executeTransition(request, response);
3035
3036 return;
3037 }
3038
3039 origNode.removeGroup(group);
3040
3041 NodeType type = origNode.getEntity();
3042
3043 if (type.hasCustomHandler()) {
3044 INodeHandler handler = type.getCustomHandler();
3045 trans = handler.getListTransition((ControllerRequest) request);
3046 checkEmbedded(request, trans);
3047 }
3048
3049 trans.redirectTransition(request, response);
3050 } catch (Exception dbe) {
3051 throw new ControllerException(dbe);
3052 }
3053 }
3054
3055 /***
3056 * Edit permission groups for this node.
3057 *
3058 * @param request The ExpressoRequest object.
3059 * @param response The ExpressoResponse object.
3060 * @throws ControllerException upon error.
3061 */
3062 protected void runAddGroupState(final ExpressoRequest request,
3063 final ExpressoResponse response) throws ControllerException {
3064 String nodeId = request.getParameter(Node.NODE_ID);
3065
3066 if (nodeId == null) {
3067 throw new ControllerException("nodeId is a required parameter");
3068 }
3069
3070 String group = request.getParameter(UserGroup.GROUP_NAME_FIELD);
3071
3072 if (group == null) {
3073 throw new ControllerException("group name is a required parameter");
3074 }
3075
3076 try {
3077 Node origNode = new Node(request, nodeId);
3078 origNode.retrieve();
3079
3080 origNode.addGroupPerm(group, RowPermissions.DEFAULT_PERMISSIONS);
3081
3082 Transition trans = NodeAction.getListTransition(origNode
3083 .getNodeType());
3084
3085 NodeType type = origNode.getEntity();
3086
3087 if (type.hasCustomHandler()) {
3088 INodeHandler handler = type.getCustomHandler();
3089 trans = handler.getListTransition((ControllerRequest) request);
3090 }
3091
3092 assert trans != null;
3093
3094 checkEmbedded(request, trans);
3095
3096 trans.redirectTransition(request, response);
3097 } catch (Exception dbe) {
3098 throw new ControllerException(dbe);
3099 }
3100 }
3101
3102 /***
3103 * List of lists.
3104 *
3105 * @param request The ExpressoRequest object.
3106 * @param response The ExpressoResponse object.
3107 * @throws ControllerException upon error.
3108 */
3109 protected void runListAllTypesState(final ExpressoRequest request,
3110 final ExpressoResponse response) throws ControllerException {
3111 try {
3112 Block allblock = new Block(ROW_BLOCK);
3113 response.add(allblock);
3114
3115 User requestor = request.getUserInfo();
3116 boolean canEditModel = requestor.isAdmin()
3117 || requestor
3118 .isMember(Setup
3119 .getValueRequired(PartAction.MODEL_EDIT_GROUP_DEFAULT_SETUP_CODE));
3120
3121 TreeSet types = PartsFactory.getEntities();
3122
3123 for (Iterator iterator = types.iterator(); iterator.hasNext();) {
3124 NodeType type = (NodeType) iterator.next();
3125
3126 Block row = new Block(ROW);
3127 allblock.add(row);
3128
3129 Output output = new Output(NodeType.NODE_TYPE_ID, type.getId());
3130 row.add(output);
3131
3132 output = new Output(NodeType.DISPLAY_TITLE, type
3133 .getDisplayName());
3134 row.add(output);
3135
3136 output = new Output(NodeType.NODE_TYPE_DESCRIP, type
3137 .getEntityDescription());
3138 row.add(output);
3139
3140 Transition trans = NodeAction.getListTransition(type
3141 .getEntityName());
3142 checkEmbedded(request, trans);
3143
3144 row.add(trans);
3145
3146 if (canEditModel) {
3147 trans = new Transition("edit", PartAction.class,
3148 PartAction.PROMPT_EDIT_ENTITY);
3149 trans.addParam(NodeType.NODE_TYPE_ID, type.getId());
3150 checkEmbedded(request, trans);
3151 row.add(trans);
3152
3153 trans = new Transition("delete", PartAction.class,
3154 PartAction.PROMPT_DELETE_ENTITY);
3155 trans.addParam(NodeType.NODE_TYPE_ID, type.getId());
3156 row.add(trans);
3157 checkEmbedded(request, trans);
3158 row.add(getPermsTrans(type));
3159 }
3160 }
3161
3162 if (canEditModel) {
3163 Transition trans = new Transition("add", PartAction.class,
3164 PartAction.PROMPT_ADD_ENTITY);
3165 checkEmbedded(request, trans);
3166 response.add(trans);
3167
3168 trans = new Transition("import from XML", PartAction.class,
3169 PartAction.PROMPT_IMPORT_ENTITY);
3170 checkEmbedded(request, trans);
3171 response.add(trans);
3172 }
3173 } catch (Exception dbe) {
3174 throw new ControllerException(dbe);
3175 }
3176 }
3177
3178 public static Transition getDeleteTrans(final String nodeId) {
3179 Transition deleteTransition = new Transition("Delete",
3180 NodeAction.class, NodeAction.PROMPT_DELETE_NODE);
3181 deleteTransition.addParam(Node.NODE_ID, nodeId);
3182
3183 return deleteTransition;
3184 }
3185
3186 /***
3187 * Views a single attribute in its entirety. Useful for when somebody does
3188 * not have permission to update an attribute, but the attribute label is
3189 * truncates (such as in treeview)
3190 *
3191 * @param request ExpressoRequest the ExpressoRequest object.
3192 * @param response ExpressoResponse the ExpressoResponse object.
3193 * @throws ControllerException upon controller framework related error.
3194 * @throws DBException upon database access related error.
3195 */
3196 protected void runViewSingleAttributeState(final ExpressoRequest request,
3197 final ExpressoResponse response) throws ControllerException,
3198 DBException {
3199 String id = request.getParameter(Attribute.ATTRIBUTE_ID);
3200 Attribute attrib = new Attribute();
3201 attrib.setAttributeId(id);
3202 attrib.retrieve();
3203
3204 Node node = attrib.getParentNode();
3205
3206
3207
3208
3209 request.getSession().setAttribute("ReadOnlyRequest", Boolean.TRUE);
3210
3211 try {
3212 Part part = attrib.getPart();
3213 response.add(new Output(Attribute.ATTRIBUTE_DISPLAY_NAME, part
3214 .getPartLabel()));
3215
3216 Transition viewTrans = AddNodeAction.getViewTrans(node.getNodeId());
3217 viewTrans.setLabel(node.getNodeTitle());
3218 response.add(viewTrans);
3219
3220 String value = attrib.getAttribValue();
3221 if (part.hasPicklist()) {
3222 value = attrib.getField(Attribute.ATTRIBUTE_PICKLIST_DISPLAY);
3223 }
3224 response.add(new Output(Attribute.ATTRIBUTE_VALUE, value));
3225
3226 response.add(new Output(Attribute.ATTRIBUTE_COMMENT, attrib
3227 .getAttribComment()));
3228 } catch (Exception e) {
3229 throw new ControllerException(e);
3230 }
3231
3232 }
3233
3234 /***
3235 * synonym for method in AddNodeAction
3236 *
3237 * @param request ExpressoRequest
3238 * @param response ExpressoResponse
3239 * @throws ControllerException
3240 * @throws DBException
3241 */
3242 protected void runViewNodeState(final ExpressoRequest request,
3243 final ExpressoResponse response) throws ControllerException,
3244 DBException, NonHandleableException {
3245 AddNodeAction.getViewTrans(request.getParameter(Node.NODE_ID))
3246 .executeTransition(request, response);
3247 }
3248
3249 /***
3250 * Executes the view tree command.
3251 *
3252 * @param request ExpressoRequest
3253 * @param response ExpressoResponse
3254 * @throws ControllerException
3255 * @throws DBException
3256 */
3257 protected void runViewTreeState(final ExpressoRequest request,
3258 final ExpressoResponse response) throws ControllerException,
3259 DBException, NonHandleableException {
3260
3261 Node existing = getNode(request);
3262 StateHandler handler = new ViewNodeAsTree(existing);
3263 handler.handleRequest(request, response);
3264
3265 Transition reflexiveTransition = new Transition("", this.getClass(),
3266 NodeAction.VIEW_TREE);
3267 reflexiveTransition.addParam(Node.NODE_ID, request
3268 .getParameter(Node.NODE_ID));
3269 checkEmbedded(request, reflexiveTransition);
3270
3271
3272 try {
3273 Transition expandAll = (Transition) reflexiveTransition.clone();
3274 expandAll.addParam(ViewNodeAsTree.PARAM_EXPAND_ALL, "Y");
3275 expandAll.setLabel("Expand All");
3276 expandAll.setName("ExpandAll");
3277 checkEmbedded(request, expandAll);
3278 response.add(expandAll);
3279
3280 Transition collapseAll = (Transition) reflexiveTransition.clone();
3281 collapseAll.addParam(ViewNodeAsTree.PARAM_COLLAPSE_ALL, "Y");
3282 collapseAll.setLabel("Collapse All");
3283 collapseAll.setName("CollapseAll");
3284 checkEmbedded(request, collapseAll);
3285 response.add(collapseAll);
3286
3287
3288 Transition flat = AddNodeAction.getViewTrans(request
3289 .getParameter(Node.NODE_ID));
3290 checkEmbedded(request, flat);
3291 response.add(flat);
3292 } catch (CloneNotSupportedException ex) {
3293 throw new ControllerException("Error cloning Transitions.", ex);
3294 }
3295 }
3296
3297 }