1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.modules.actions.controllers;
18
19
20 import org.apache.jetspeed.om.registry.PortletEntry;
21 import org.apache.jetspeed.om.profile.IdentityElement;
22 import org.apache.jetspeed.om.profile.Entry;
23 import org.apache.jetspeed.om.profile.psml.PsmlControl;
24 import org.apache.jetspeed.om.profile.MetaInfo;
25 import org.apache.jetspeed.om.profile.Layout;
26 import org.apache.jetspeed.om.profile.Parameter;
27 import org.apache.jetspeed.om.profile.Portlets;
28 import org.apache.jetspeed.om.profile.Reference;
29 import org.apache.jetspeed.om.profile.psml.PsmlParameter;
30 import org.apache.jetspeed.om.profile.psml.PsmlLayout;
31 import org.apache.jetspeed.portal.Portlet;
32 import org.apache.jetspeed.portal.PortletSet;
33 import org.apache.jetspeed.portal.PortletController;
34 import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
35 import org.apache.jetspeed.services.logging.JetspeedLogger;
36 import org.apache.jetspeed.services.rundata.JetspeedRunData;
37 import org.apache.jetspeed.services.Registry;
38 import org.apache.jetspeed.services.statemanager.SessionState;
39 import org.apache.jetspeed.services.PsmlManager;
40
41
42 import org.apache.turbine.modules.ActionLoader;
43 import org.apache.turbine.services.localization.Localization;
44 import org.apache.turbine.util.RunData;
45
46
47 import org.apache.velocity.context.Context;
48
49
50 import java.util.ArrayList;
51 import java.util.Collections;
52 import java.util.Vector;
53 import java.util.List;
54 import java.util.Enumeration;
55 import java.util.Iterator;
56 import java.util.Map;
57 import java.util.HashMap;
58 import java.util.StringTokenizer;
59
60 /***
61 * This action builds a context suitable for controllers handling
62 * grid positioned layout using PortletSet.Constraints
63 *
64 * @author <a href="mailto:raphael@apache.org">Raphaël Luta</a>
65 * @author <a href="mailto:paulsp@apache.org">Paul Spencer</a>
66 * @version $Id: MultiColumnControllerAction.java,v 1.30 2004/02/23 02:49:58 jford Exp $
67 */
68 public class MultiColumnControllerAction extends VelocityControllerAction
69 {
70
71 private static final String REFERENCES_REMOVED = "references-removed";
72
73 /***
74 * Static initialization of the logger for this class
75 */
76 private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(MultiColumnControllerAction.class.getName());
77
78 /***
79 * Subclasses must override this method to provide default behavior
80 * for the portlet action
81 */
82 protected void buildNormalContext(PortletController controller,
83 Context context,
84 RunData rundata)
85 {
86 try
87 {
88
89 String cols = controller.getConfig().getInitParameter("cols");
90 int colNum = 0;
91 int rowNum = 0;
92 try
93 {
94 colNum = Integer.parseInt(cols);
95 }
96 catch (Exception e)
97 {
98
99 colNum = 3;
100 }
101 context.put("colNum", String.valueOf(colNum));
102
103
104 String sizes = controller.getConfig().getInitParameter("sizes");
105 context.put("sizes", getCellSizes(sizes));
106
107
108 String columnClasses = controller.getConfig().getInitParameter("col_classes");
109 context.put("col_classes", getCellClasses(columnClasses));
110
111 PortletSet set = controller.getPortlets();
112
113 Enumeration en = set.getPortlets();
114 int row = 0;
115 int col = 0;
116 while (en.hasMoreElements())
117 {
118 Portlet p = (Portlet) en.nextElement();
119
120 PortletSet.Constraints
121 constraints = p.getPortletConfig().getConstraints();
122
123 if ((constraints != null)
124 && (constraints.getColumn() != null)
125 && (constraints.getRow() != null))
126 {
127 col = constraints.getColumn().intValue();
128 if (col > colNum)
129 {
130 constraints.setColumn(new Integer(col % colNum));
131 }
132
133 row = constraints.getRow().intValue();
134 if (row > rowNum)
135 {
136 rowNum = row;
137 }
138 }
139 }
140 row = (int) Math.ceil(set.size() / colNum);
141 if (row > rowNum)
142 {
143 rowNum = row;
144 }
145
146 if ( logger.isDebugEnabled() ) {
147 logger.debug("Controller calculated setSize " + set.size() + " row " + row + " colNum: " + colNum + " rowNum: " + rowNum);
148 }
149
150 List[] table = new List[colNum];
151 List filler = Collections.nCopies(rowNum + 1, null);
152 for (int i = 0; i < colNum; i++)
153 {
154 table[i] = new ArrayList();
155 table[i].addAll(filler);
156 }
157
158 List work = new ArrayList();
159
160
161
162 for (int i = 0; i < set.size(); i++)
163 {
164 Portlet p = set.getPortletAt(i);
165
166 PortletSet.Constraints
167 constraints = p.getPortletConfig().getConstraints();
168
169 if ((constraints != null)
170 && (constraints.getColumn() != null)
171 && (constraints.getRow() != null)
172 && (constraints.getColumn().intValue() < colNum))
173 {
174 row = constraints.getRow().intValue();
175 col = constraints.getColumn().intValue();
176 table[col].set(row, p);
177 }
178 else
179 {
180 work.add(p);
181 }
182 }
183
184
185 Iterator i = work.iterator();
186 for (row = 0; row < rowNum; row++)
187 {
188 for (col = 0; i.hasNext() && (col < colNum); col++)
189 {
190 if (table[col].get(row) == null)
191 {
192 table[col].set(row, i.next());
193 }
194 }
195 }
196
197
198 for (int j = 0; j < table.length; j++)
199 {
200 i = table[j].iterator();
201 while (i.hasNext())
202 {
203 Object obj = i.next();
204 if (obj == null)
205 {
206 i.remove();
207 }
208 }
209 }
210
211 if (logger.isDebugEnabled())
212 {
213 dumpColumns(table);
214 }
215
216 context.put("portlets", table);
217 }
218 catch (Exception e)
219 {
220 logger.error("Exception", e);
221 }
222 }
223
224 /***
225 * Subclasses must override this method to provide default behavior
226 * for the portlet action
227 */
228 protected void buildCustomizeContext(PortletController controller,
229 Context context,
230 RunData rundata)
231 {
232 JetspeedRunData jdata = (JetspeedRunData) rundata;
233
234
235 SessionState customizationState = jdata.getPageSessionState();
236
237 super.buildCustomizeContext(controller, context, rundata);
238
239 List[] columns = null;
240
241
242 String cols = controller.getConfig().getInitParameter("cols");
243 int colNum = 0;
244 try
245 {
246 colNum = Integer.parseInt(cols);
247 }
248 catch (Exception e)
249 {
250
251 colNum = 3;
252 }
253 context.put("colNum", String.valueOf(colNum));
254
255
256 String sizes = controller.getConfig().getInitParameter("sizes");
257 context.put("sizes", getCellSizes(sizes));
258
259
260 String columnClasses = controller.getConfig().getInitParameter("col_classes");
261 context.put("col_classes", getCellClasses(columnClasses));
262
263 columns = (List[]) customizationState.getAttribute("customize-columns");
264 PortletSet customizedSet = (PortletSet) jdata.getCustomized();
265 Portlets set = jdata.getCustomizedProfile()
266 .getDocument()
267 .getPortletsById(customizedSet.getID());
268
269 if ( logger.isDebugEnabled() ) {
270 logger.debug("MultiCol: columns " + columns + " set " + set);
271 }
272
273 if ((columns != null) && (columns.length == colNum))
274 {
275 int eCount = 0;
276 for (int i = 0; i < columns.length; i++)
277 {
278 eCount += columns[i].size();
279 }
280
281 if ( logger.isDebugEnabled() ) {
282 logger.debug("MultiCol: eCount " + eCount + " setCount" + set.getEntryCount() + set.getPortletsCount());
283 }
284 if (eCount != set.getEntryCount() + set.getPortletsCount())
285 {
286 if ( logger.isDebugEnabled() ) {
287 logger.debug("MultiCol: rebuilding columns ");
288 }
289 columns = buildColumns(set, colNum);
290 }
291
292 }
293 else
294 {
295 if ( logger.isDebugEnabled() ) {
296 logger.debug("MultiCol: rebuilding columns ");
297 }
298 columns = buildColumns(set, colNum);
299 }
300
301 customizationState.setAttribute("customize-columns", columns);
302 context.put("portlets", columns);
303
304 Map titles = new HashMap();
305 for (int col = 0; col < columns.length; col++)
306 {
307 for (int row = 0; row < columns[col].size(); row++)
308 {
309 IdentityElement identityElement = (IdentityElement) columns[col].get(row);
310 MetaInfo metaInfo = identityElement.getMetaInfo();
311 if ((metaInfo != null) && (metaInfo.getTitle() != null))
312 {
313 titles.put(identityElement.getId(), metaInfo.getTitle());
314 continue;
315 }
316
317 if (identityElement instanceof Entry)
318 {
319 Entry entry = (Entry) identityElement;
320 PortletEntry pentry = (PortletEntry) Registry.getEntry(Registry.PORTLET, entry.getParent());
321 if ((pentry != null) && (pentry.getTitle() != null))
322 {
323 titles.put(entry.getId(), pentry.getTitle());
324 continue;
325 }
326
327 titles.put(entry.getId(), entry.getParent());
328 continue;
329 }
330
331 if (identityElement instanceof Reference)
332 {
333 titles.put(identityElement.getId(), Localization.getString(rundata, "CUSTOMIZER_REF_DEFAULTTITLE"));
334 continue;
335 }
336
337
338 titles.put(identityElement.getId(), Localization.getString(rundata, "CUSTOMIZER_NOTITLESET"));
339 }
340 }
341
342 context.put("titles", titles);
343 context.put("action", "controllers.MultiColumnControllerAction");
344 }
345
346 /***
347 * Cancel the current customizations. If this was the last customization
348 * on the stack, then return the user to the home page.
349 */
350 public void doCancel(RunData data, Context context)
351 {
352
353 ((JetspeedRunData) data).setCustomized(null);
354
355
356 if (((JetspeedRunData) data).getCustomized() == null)
357 {
358 try
359 {
360 ActionLoader.getInstance().exec(data, "controls.EndCustomize");
361 }
362 catch (Exception e)
363 {
364 logger.error("Unable to load action controls.EndCustomize ", e);
365 }
366 }
367 }
368
369 public void doSave(RunData data, Context context)
370 {
371
372 SessionState customizationState = ((JetspeedRunData) data).getPageSessionState();
373
374
375 List[] columns = (List[]) customizationState.getAttribute("customize-columns");
376 for (int col = 0; col < columns.length; col++)
377 {
378 for (int row = 0; row < columns[col].size(); row++)
379 {
380 setPosition((IdentityElement) columns[col].get(row), col, row);
381 }
382 }
383
384
385 ((JetspeedRunData) data).setCustomized(null);
386
387
388 if (((JetspeedRunData) data).getCustomized() == null)
389 {
390
391 try
392 {
393 ((JetspeedRunData) data).getCustomizedProfile().store();
394
395
396
397 String referencesRemoved = (String) customizationState.getAttribute(REFERENCES_REMOVED);
398 if (referencesRemoved != null && referencesRemoved.equals("true"))
399 {
400 PsmlManager.refresh(((JetspeedRunData) data).getCustomizedProfile());
401 }
402 }
403 catch (Exception e)
404 {
405 logger.error("Unable to save profile ", e);
406 }
407
408 try
409 {
410 ActionLoader.getInstance().exec(data, "controls.EndCustomize");
411 }
412 catch (Exception e)
413 {
414 logger.error("Unable to load action controls.EndCustomize ", e);
415 }
416 }
417 }
418
419 public void doDelete(RunData data, Context context)
420 {
421 JetspeedRunData jdata = (JetspeedRunData) data;
422
423
424 SessionState customizationState = jdata.getPageSessionState();
425
426 PortletSet customizedSet = (PortletSet) jdata.getCustomized();
427
428 customizationState.setAttribute(REFERENCES_REMOVED, "false");
429
430 int col = data.getParameters().getInt("col", -1);
431 int row = data.getParameters().getInt("row", -1);
432 List[] columns = (List[]) customizationState.getAttribute("customize-columns");
433 if (columns == null)
434 {
435 return;
436 }
437
438 if ((col > -1) && (row > -1))
439 {
440 try
441 {
442 IdentityElement identityElement = (IdentityElement) columns[col].get(row);
443 columns[col].remove(row);
444
445 Portlets portlets = jdata.getCustomizedProfile()
446 .getDocument()
447 .getPortletsById(customizedSet.getID());
448
449 if (portlets != null)
450 {
451 if (identityElement instanceof Entry)
452 {
453 for (int i = 0; i < portlets.getEntryCount(); i++)
454 {
455 if (portlets.getEntry(i) == identityElement)
456 {
457 portlets.removeEntry(i);
458 }
459 }
460 }
461 else if (identityElement instanceof Reference)
462 {
463 for (int i = 0; i < portlets.getReferenceCount(); i++)
464 {
465 if (portlets.getReference(i) == identityElement)
466 {
467 customizationState.setAttribute(REFERENCES_REMOVED, "true");
468 portlets.removeReference(i);
469 }
470 }
471 }
472 }
473 }
474 catch (Exception e)
475 {
476
477 logger.error("MultiColumnControllerAction: Probably got wrong coordinates", e);
478 }
479 }
480 }
481
482 public void doLeft(RunData data, Context context)
483 {
484
485 SessionState customizationState = ((JetspeedRunData) data).getPageSessionState();
486
487 List[] columns = (List[]) customizationState.getAttribute("customize-columns");
488 int col = data.getParameters().getInt("col", -1);
489 int row = data.getParameters().getInt("row", -1);
490 if (columns == null)
491 {
492 return;
493 }
494
495 if ((col > 0) && (row > -1))
496 {
497 move(columns, col, row, col - 1, row);
498 }
499 }
500
501 public void doRight(RunData data, Context context)
502 {
503
504 SessionState customizationState = ((JetspeedRunData) data).getPageSessionState();
505
506 List[] columns = (List[]) customizationState.getAttribute("customize-columns");
507 int col = data.getParameters().getInt("col", -1);
508 int row = data.getParameters().getInt("row", -1);
509 if (columns == null)
510 {
511 return;
512 }
513
514 if ((col > -1) && (row > -1) && (col < columns.length - 1))
515 {
516 move(columns, col, row, col + 1, row);
517 }
518 }
519
520 public void doUp(RunData data, Context context)
521 {
522
523 SessionState customizationState = ((JetspeedRunData) data).getPageSessionState();
524
525 List[] columns = (List[]) customizationState.getAttribute("customize-columns");
526 int col = data.getParameters().getInt("col", -1);
527 int row = data.getParameters().getInt("row", -1);
528 if (columns == null)
529 {
530 return;
531 }
532
533 if ((col > -1) && (row > 0))
534 {
535 move(columns, col, row, col, row - 1);
536 }
537 }
538
539 public void doDown(RunData data, Context context)
540 {
541
542 SessionState customizationState = ((JetspeedRunData) data).getPageSessionState();
543
544 List[] columns = (List[]) customizationState.getAttribute("customize-columns");
545 int col = data.getParameters().getInt("col", -1);
546 int row = data.getParameters().getInt("row", -1);
547 if (columns == null)
548 {
549 return;
550 }
551
552 if ((col > -1) && (row > -1) && (row < columns[col].size() - 1))
553 {
554 move(columns, col, row, col, row + 1);
555 }
556 }
557
558 public void doControl(RunData data, Context context)
559 {
560 JetspeedRunData jdata = (JetspeedRunData) data;
561
562 String controlName = data.getParameters().getString("control");
563 String id = data.getParameters().getString("js_peid");
564
565 try
566 {
567 Entry entry = jdata.getCustomizedProfile().getDocument().getEntryById(id);
568
569 if (entry != null)
570 {
571 if (controlName != null && controlName.trim().length() > 0)
572 {
573 PsmlControl control = new PsmlControl();
574 control.setName(controlName);
575 if (control != null)
576 {
577 entry.setControl(control);
578 }
579 }
580 else
581 {
582 entry.setControl(null);
583 }
584 }
585 }
586 catch (Exception e)
587 {
588 logger.error("Exception", e);
589 }
590 }
591
592 protected static void setPosition(IdentityElement identityElement, int col, int row)
593 {
594 boolean colFound = false;
595 boolean rowFound = false;
596
597 if (identityElement != null)
598 {
599 Layout layout = identityElement.getLayout();
600
601 if (layout == null)
602 {
603 layout = new PsmlLayout();
604 identityElement.setLayout(layout);
605 }
606
607 for (int i = 0; i < layout.getParameterCount(); i++)
608 {
609 Parameter p = layout.getParameter(i);
610
611 if (p.getName().equals("column"))
612 {
613 p.setValue(String.valueOf(col));
614 colFound = true;
615 }
616 else if (p.getName().equals("row"))
617 {
618 p.setValue(String.valueOf(row));
619 rowFound = true;
620 }
621 }
622
623 if (!colFound)
624 {
625 Parameter p = new PsmlParameter();
626 p.setName("column");
627 p.setValue(String.valueOf(col));
628 layout.addParameter(p);
629 }
630
631 if (!rowFound)
632 {
633 Parameter p = new PsmlParameter();
634 p.setName("row");
635 p.setValue(String.valueOf(row));
636 layout.addParameter(p);
637 }
638 }
639 }
640
641 protected static void move(List[] cols, int oCol, int oRow, int nCol, int nRow)
642 {
643 Object obj = null;
644
645 if ((oCol < cols.length) && (oRow < cols[oCol].size()))
646 {
647 obj = cols[oCol].get(oRow);
648 if (obj != null)
649 {
650 cols[oCol].remove(oRow);
651 }
652 }
653
654 if (obj != null)
655 {
656 if (nCol < cols.length)
657 {
658 if (nRow < cols[nCol].size())
659 {
660 cols[nCol].add(nRow, obj);
661 }
662 else
663 {
664 cols[nCol].add(obj);
665 }
666 }
667 }
668 }
669
670 protected static List[] buildColumns(Portlets set, int colNum)
671 {
672
673 Iterator iterator = set.getEntriesIterator();
674 int row = 0;
675 int col = 0;
676 int rowNum = 0;
677 while (iterator.hasNext())
678 {
679 IdentityElement identityElement = (IdentityElement) iterator.next();
680
681 Layout layout = identityElement.getLayout();
682
683 if (layout != null)
684 {
685 for (int p = 0; p < layout.getParameterCount(); p++)
686 {
687 Parameter prop = layout.getParameter(p);
688
689 try
690 {
691 if (prop.getName().equals("row"))
692 {
693 row = Integer.parseInt(prop.getValue());
694 if (row > rowNum)
695 {
696 rowNum = row;
697 }
698 }
699 else if (prop.getName().equals("column"))
700 {
701 col = Integer.parseInt(prop.getValue());
702 if (col > colNum)
703 {
704 prop.setValue(String.valueOf(col % colNum));
705 }
706 }
707 }
708 catch (Exception e)
709 {
710
711 }
712 }
713 }
714 }
715
716 int sCount = set.getEntryCount() + set.getPortletsCount();
717 row = (sCount / colNum) + 1;
718 if (row > rowNum)
719 {
720 rowNum = row;
721 }
722
723 if ( logger.isDebugEnabled() ) {
724 logger.debug("Controller customize colNum: " + colNum + " rowNum: " + rowNum);
725 }
726
727 List[] table = new List[colNum];
728 List filler = Collections.nCopies(rowNum + 1, null);
729 for (int i = 0; i < colNum; i++)
730 {
731 table[i] = new ArrayList();
732 table[i].addAll(filler);
733 }
734
735 List work = new ArrayList();
736
737
738
739 for (int i = 0; i < set.getEntryCount(); i++)
740 {
741 addElement(set.getEntry(i), table, work, colNum);
742 }
743
744
745 for (int i = 0; i < set.getReferenceCount(); i++)
746 {
747 addElement(set.getReference(i), table, work, colNum);
748 }
749
750
751 Iterator i = work.iterator();
752 for (row = 0; row < rowNum; row++)
753 {
754 for (col = 0; i.hasNext() && (col < colNum); col++)
755 {
756 if (table[col].get(row) == null)
757 {
758 if ( logger.isDebugEnabled() ) {
759 logger.debug("Set portlet at col " + col + " row " + row);
760 }
761 table[col].set(row, i.next());
762 }
763 }
764 }
765
766
767 for (int j = 0; j < table.length; j++)
768 {
769 if ( logger.isDebugEnabled() ) {
770 logger.debug("Column " + j);
771 }
772 i = table[j].iterator();
773 while (i.hasNext())
774 {
775 Object obj = i.next();
776 if ( logger.isDebugEnabled() ) {
777 logger.debug("Element " + obj);
778 }
779 if (obj == null)
780 {
781 i.remove();
782 }
783
784 }
785 }
786
787 return table;
788 }
789
790 /*** Parses the size config info and returns a list of
791 * size values for the current set
792 *
793 * @param sizeList java.lang.String a comma separated string a values
794 * @return a List of values
795 */
796 protected static List getCellSizes(String sizeList)
797 {
798 List list = new Vector();
799
800 if (sizeList != null)
801 {
802 StringTokenizer st = new StringTokenizer(sizeList, ",");
803 while (st.hasMoreTokens())
804 {
805 list.add(st.nextToken());
806 }
807 }
808
809 return list;
810 }
811
812 protected static List getCellClasses(String classlist)
813 {
814 List list = new Vector();
815
816 if (classlist != null)
817 {
818 StringTokenizer st = new StringTokenizer(classlist, ",");
819 while (st.hasMoreTokens())
820 {
821 list.add(st.nextToken());
822 }
823 }
824
825 return list;
826 }
827
828 /***
829 * Add an element to the "table" or "work" objects. If the element is
830 * unconstrained, and the position is within the number of columns, then
831 * the element is added to "table". Othewise the element is added to "work"
832 *
833 * @param element to add
834 * @param table of positioned elements
835 * @param work list of un-positioned elements
836 * @param columnCount Number of colum
837 */
838 protected static void addElement(IdentityElement element, List[] table, List work, int columnCount)
839 {
840 Layout layout = element.getLayout();
841 int row = -1;
842 int col = -1;
843
844 if (layout != null)
845 {
846 try
847 {
848 for (int p = 0; p < layout.getParameterCount(); p++)
849 {
850 Parameter prop = layout.getParameter(p);
851
852 if (prop.getName().equals("row"))
853 {
854 row = Integer.parseInt(prop.getValue());
855 }
856 else if (prop.getName().equals("column"))
857 {
858 col = Integer.parseInt(prop.getValue());
859 }
860 }
861 }
862 catch (Exception e)
863 {
864
865 }
866 }
867
868 if ( logger.isDebugEnabled() ) {
869 logger.debug("Constraints col " + col + " row " + row);
870 }
871 if ((row >= 0) && (col >= 0) && (col < columnCount))
872 {
873 table[col].set(row, element);
874 }
875 else
876 {
877 if (layout != null)
878 {
879
880
881
882
883
884 element.setLayout(null);
885 layout = null;
886 }
887 work.add(element);
888 }
889
890 }
891
892 protected void dumpColumns(List[] cols)
893 {
894 for (int i = 0; i < cols.length; i++)
895 {
896 logger.debug("Column " + i);
897 for (int j = 0; j < cols[i].size(); j++)
898 {
899 logger.debug("Row " + j + " object: " + cols[i].get(j));
900 }
901 }
902 }
903 }