001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.layout.impl;
018:
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.ArrayList;
023: import java.util.Set;
024: import java.util.Map;
025: import java.util.Collections;
026: import java.util.Comparator;
027:
028: import org.apache.commons.logging.Log;
029: import org.apache.commons.logging.LogFactory;
030: import org.apache.jetspeed.components.portletregistry.PortletRegistry;
031: import org.apache.jetspeed.layout.Coordinate;
032: import org.apache.jetspeed.layout.PortletPlacementException;
033: import org.apache.jetspeed.layout.PortletPlacementContext;
034: import org.apache.jetspeed.om.page.Fragment;
035: import org.apache.jetspeed.om.page.Page;
036: import org.apache.pluto.om.common.Parameter;
037: import org.apache.pluto.om.common.ParameterSet;
038: import org.apache.pluto.om.portlet.PortletDefinition;
039:
040: /**
041: * Portal Placement Context
042: *
043: * The purpose of the object is to provide an API that
044: * can be used to move a portlet fragment on the page.
045: * This includes moving, adding, removing and getting
046: * information about portlets that are on the page and
047: * portlets that are available to be added to the page.
048: *
049: * This object represents the fragment contents of a
050: * single layout fragment (i.e. nested depth cannot
051: * be captured by this object).
052: *
053: * An important note about this object:
054: * This object is really only intended to be used to do
055: * a single operation such as "moveabs" or "add". After
056: * performing the operation, the hashmap data structures
057: * are not correct and should not be used for subsequent
058: * operations. The reason they are incorrect is that when
059: * a fragment is moved, the coordinate of fragments below
060: * it are now different. These could be updated, but it
061: * really doesn't serve a purpose since this is a short
062: * lived object.
063: *
064: * @author <a>David Gurney</a>
065: * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
066: * @author <a href="mailto:smilek@apache.org">Steve Milek</a>
067: * @version $Id: $
068: */
069: public class PortletPlacementContextImpl implements
070: PortletPlacementContext {
071: private static Log log = LogFactory
072: .getLog(PortletPlacementContextImpl.class);
073: protected static final String eol = System
074: .getProperty("line.separator");
075:
076: // Columns are reference by index, the rows are held
077: // in the columnsList as shown below:
078: //
079: // [0] [1] [2]
080: // ArrayList ArrayList ArrayList
081: // Row0Frag Row0Frag Row0Frag
082: // Row1Frag Row1Frag Row1Frag
083: // Row2Frag Row2Frag Row2Frag
084: // ...
085: //
086: protected ArrayList[] columnsList = null;
087:
088: // Used as a convience when looking up a particular fragment
089: //
090: // key is Fragment id (String), value is a Coordinate object
091: protected Map fragmentCoordinateMap = new HashMap();
092:
093: // Used as a convience when looking up a particular fragment by id
094: //
095: // key is the Fragment id (String), value is the Fragment
096: protected Map fragmentMap = new HashMap();
097:
098: // Number of columns
099: protected int numberOfColumns = -1;
100:
101: protected Page page;
102: private PortletRegistry registry;
103: protected Fragment layoutContainerFragment;
104:
105: public PortletPlacementContextImpl(Page page,
106: PortletRegistry registry) throws PortletPlacementException {
107: this (page, registry, null);
108: }
109:
110: public PortletPlacementContextImpl(Page page,
111: PortletRegistry registry, Fragment container)
112: throws PortletPlacementException {
113: if (page == null)
114: throw new NullPointerException(
115: "PortletPlacementContext cannot be instantiated with a null Page argument");
116: if (registry == null)
117: throw new NullPointerException(
118: "PortletPlacementContext cannot be instantiated with a null PortletRegistry argument");
119:
120: this .page = page;
121: this .registry = registry;
122:
123: init(container);
124: }
125:
126: protected void init(Fragment container)
127: throws PortletPlacementException {
128: if (container == null) {
129: container = page.getRootFragment();
130: if (container == null)
131: throw new PortletPlacementException(
132: "PortletPlacementContext cannot acquire root layout fragment from page");
133: }
134: if (!"layout".equals(container.getType())) {
135: throw new PortletPlacementException(
136: "PortletPlacementContext specified container fragment ("
137: + container.getId()
138: + ") is not a layout fragment, but is type: "
139: + container.getType());
140: }
141: this .layoutContainerFragment = container;
142:
143: int columnCount = PortletPlacementContextImpl
144: .getColumnCountAndSizes(container, registry, null);
145: if (columnCount <= 0) {
146: throw new PortletPlacementException(
147: "PortletPlacementContext cannot detemine number of columns in layout fragment ("
148: + container.getId() + ")");
149: }
150: this .numberOfColumns = columnCount;
151:
152: initProcessLayoutContainerFragment();
153:
154: //debugFragments( "init" );
155: }
156:
157: private void initProcessLayoutContainerFragment()
158: throws PortletPlacementException {
159: List fragChildren = this .layoutContainerFragment.getFragments();
160: int fragChildCount = fragChildren.size();
161:
162: int columnCount = this .numberOfColumns;
163:
164: // sort the fragments in the same manner as /portal and /desktop rendering
165: FragmentLinkedListEntry[][] colLinkedLists = new FragmentLinkedListEntry[columnCount][fragChildCount];
166: FragmentLinkedListInfo[] colLinkedListsInfo = new FragmentLinkedListInfo[columnCount];
167: for (int colIndex = 0; colIndex < columnCount; colIndex++) {
168: colLinkedListsInfo[colIndex] = new FragmentLinkedListInfo();
169: }
170: for (int fragChildIndex = 0; fragChildIndex < fragChildCount; fragChildIndex++) {
171: Fragment fragment = (Fragment) fragChildren
172: .get(fragChildIndex);
173: if (fragment != null) {
174: int col = getColumnFromFragment(fragment);
175:
176: FragmentLinkedListEntry[] ll = colLinkedLists[col];
177: FragmentLinkedListInfo llInfo = colLinkedListsInfo[col];
178:
179: Integer rowObj = getRowFromFragment(fragment);
180: int row;
181: if (rowObj != null)
182: row = rowObj.intValue();
183: else
184: row = llInfo.getHigh() + 1; // fragment with unspecified row property is assigned
185: // the value of current fragment in the highest row + 1
186: // - this is one of the reasons we are not using sort here
187:
188: FragmentLinkedListEntry fragLLentry = new FragmentLinkedListEntry(
189: fragChildIndex, row);
190: int llLen = llInfo.useNextAvailableIndex();
191: ll[llLen] = fragLLentry;
192: if (llLen == 0) {
193: llInfo.setHead(0);
194: llInfo.setTail(0);
195: llInfo.setHigh(row);
196: } else {
197: if (row > llInfo.getHigh()) {
198: ll[llInfo.getTail()].setNextEntry(llLen);
199: llInfo.setHigh(row);
200: llInfo.setTail(llLen);
201: } else {
202: int llEntryIndex = llInfo.getHead();
203: int llPrevEntryIndex = -1;
204: while (ll[llEntryIndex].getRow() < row) {
205: llPrevEntryIndex = llEntryIndex;
206: llEntryIndex = ll[llEntryIndex]
207: .getNextEntry();
208: }
209: if (ll[llEntryIndex].getRow() == row) { // a subsequent fragment (in the document) with a row value equal to that
210: // of a previous fragment is inserted before the previous fragment
211: // - this is one of the reasons we are not using sort here
212: int incrementedRow = row + 1;
213: ll[llEntryIndex].setRow(incrementedRow);
214: if (llInfo.getTail() == llEntryIndex)
215: llInfo.setHigh(incrementedRow);
216: }
217: fragLLentry.setNextEntry(llEntryIndex);
218: if (llPrevEntryIndex == -1)
219: llInfo.setHead(llLen);
220: else
221: ll[llPrevEntryIndex].setNextEntry(llLen);
222: }
223: }
224: }
225: }
226:
227: ArrayList[] columnFragments = new ArrayList[columnCount];
228: for (int colIndex = 0; colIndex < columnCount; colIndex++) {
229: ArrayList fragmentsInColumn = new ArrayList();
230: columnFragments[colIndex] = fragmentsInColumn;
231:
232: FragmentLinkedListEntry[] ll = colLinkedLists[colIndex];
233: FragmentLinkedListInfo llInfo = colLinkedListsInfo[colIndex];
234:
235: int rowIndex = 0;
236: int nextEntryIndex = llInfo.getHead();
237: while (nextEntryIndex != -1) {
238: FragmentLinkedListEntry fragLLentry = ll[nextEntryIndex];
239: Fragment fragment = (Fragment) fragChildren
240: .get(fragLLentry.getFragmentIndex());
241:
242: fragmentsInColumn.add(fragment);
243: CoordinateImpl coordinate = new CoordinateImpl(
244: colIndex, rowIndex);
245: this .fragmentCoordinateMap.put(fragment.getId(),
246: coordinate);
247: this .fragmentMap.put(fragment.getId(), fragment);
248:
249: nextEntryIndex = fragLLentry.getNextEntry();
250: rowIndex++;
251: }
252: }
253: this .columnsList = columnFragments;
254: }
255:
256: private int getColumnFromFragment(Fragment fragment) {
257: // get column value in the same manner as /portal and /desktop rendering
258:
259: // get column from properties to distinguish between null and -1 (fragment.getLayoutColumn() is -1 when column is not specified)
260: String colStr = (String) fragment.getProperties().get("column");
261: int columnCount = this .numberOfColumns;
262: int col = columnCount - 1;
263: if (colStr != null) {
264: try {
265: col = Integer.parseInt(colStr);
266: if (col < 0)
267: col = 0;
268: else if (col >= columnCount)
269: col = columnCount - 1;
270: } catch (NumberFormatException ex) {
271: col = columnCount - 1;
272: }
273: }
274: return col;
275: }
276:
277: private Integer getRowFromFragment(Fragment fragment) {
278: // get row value in the same manner as /portal and /desktop rendering
279:
280: // get row from properties to distinguish between null and -1 (fragment.getLayoutRow() is -1 when row is not specified)
281: String rowStr = (String) fragment.getProperties().get("row");
282: if (rowStr != null) {
283: try {
284: int row = Integer.parseInt(rowStr);
285: if (row < 0)
286: row = 0;
287: return new Integer(row);
288: } catch (NumberFormatException ex) {
289: }
290: }
291: return null;
292: }
293:
294: private int normalizeColumnIndex(int col,
295: ArrayList[] columnFragments, int defaultForUnspecifiedCol) {
296: int columnCount = this .numberOfColumns;
297: if (col >= columnCount)
298: col = (columnCount - 1);
299: else if (col < 0 && defaultForUnspecifiedCol >= 0
300: && defaultForUnspecifiedCol < columnCount)
301: col = defaultForUnspecifiedCol;
302: else if (col < 0)
303: col = 0;
304: return col;
305: }
306:
307: class FragmentLinkedListInfo {
308: private int head = -1;
309: private int tail = -1;
310: private int high = -1;
311: private int availableNextIndex = 0;
312:
313: FragmentLinkedListInfo() {
314: }
315:
316: public int getHead() {
317: return head;
318: }
319:
320: public void setHead(int newOne) {
321: this .head = newOne;
322: }
323:
324: public int getTail() {
325: return tail;
326: }
327:
328: public void setTail(int newOne) {
329: this .tail = newOne;
330: }
331:
332: public int getHigh() {
333: return high;
334: }
335:
336: public void setHigh(int newOne) {
337: this .high = newOne;
338: }
339:
340: public int useNextAvailableIndex() {
341: return this .availableNextIndex++;
342: }
343: }
344:
345: class FragmentLinkedListEntry {
346: private int fragmentIndex;
347: private int row;
348: private int nextEntry = -1;
349:
350: FragmentLinkedListEntry(int fragmentIndex, int row) {
351: this .fragmentIndex = fragmentIndex;
352: this .row = row;
353: }
354:
355: public int getFragmentIndex() {
356: return this .fragmentIndex;
357: }
358:
359: public int getRow() {
360: return this .row;
361: }
362:
363: public void setRow(int newOne) {
364: this .row = newOne;
365: }
366:
367: public int getNextEntry() {
368: return this .nextEntry;
369: }
370:
371: public void setNextEntry(int newOne) {
372: this .nextEntry = newOne;
373: }
374: }
375:
376: public String dumpFragments(String debug) {
377: StringBuffer out = new StringBuffer();
378: out.append("PortletPlacementContext - ");
379: if (debug != null)
380: out.append(debug).append(" - ");
381: out
382: .append("container: ")
383: .append(
384: this .layoutContainerFragment == null ? "<null>"
385: : (this .layoutContainerFragment.getId()
386: + " / " + this .layoutContainerFragment
387: .getType())).append(
388: " column-count=").append(this .numberOfColumns)
389: .append(eol);
390: for (int ix = 0; ix < this .columnsList.length; ix++) {
391: ArrayList column = this .columnsList[ix];
392: out.append(" column ").append(ix).append(eol);
393: Iterator frags = column.iterator();
394: while (frags.hasNext()) {
395: Fragment f = (Fragment) frags.next();
396: out.append(" frag ").append(
397: f == null ? "<null>" : (f.getId() + " / " + f
398: .getType())).append(eol);
399: }
400: }
401: return out.toString();
402: }
403:
404: public Fragment debugFragments(String debug) {
405: log.info(dumpFragments(debug));
406: return layoutContainerFragment;
407: }
408:
409: /**
410: * Takes the internal portlet placement state and stores back
411: * out to fragment state
412: *
413: * @return the managed page layout with updated fragment state.
414: */
415: public Page syncPageFragments() {
416: syncFragments(true, -1);
417: //debugFragments( "syncPage" );
418: return this .page;
419: }
420:
421: protected int getLatestColumn(Coordinate coordinate) {
422: int col = -1;
423: if (coordinate != null) {
424: col = coordinate.getNewCol();
425: if (col == -1)
426: col = coordinate.getOldCol();
427: }
428: return col;
429: }
430:
431: protected int getLatestRow(Coordinate coordinate) {
432: int row = -1;
433: if (coordinate != null) {
434: row = coordinate.getNewRow();
435: if (row == -1)
436: row = coordinate.getOldRow();
437: }
438: return row;
439: }
440:
441: protected void syncFragments(boolean updateFragmentObjects,
442: int onlyForColumnIndex) {
443: for (int colIndex = 0; colIndex < this .columnsList.length; colIndex++) {
444: if (onlyForColumnIndex == -1
445: || onlyForColumnIndex == colIndex) {
446: ArrayList column = this .columnsList[colIndex];
447: int colRowCount = column.size();
448: for (int rowIndex = 0; rowIndex < colRowCount; rowIndex++) {
449: Fragment fragment = (Fragment) column.get(rowIndex);
450: Coordinate coordinate = (Coordinate) this .fragmentCoordinateMap
451: .get(fragment.getId());
452: boolean needsReplacementCoordinate = false;
453:
454: if (getLatestColumn(coordinate) != colIndex
455: || getLatestRow(coordinate) != rowIndex)
456: needsReplacementCoordinate = true;
457:
458: if (needsReplacementCoordinate) {
459: Coordinate replacementCoordinate = new CoordinateImpl(
460: coordinate.getOldCol(), coordinate
461: .getOldRow(), colIndex,
462: rowIndex);
463: this .fragmentCoordinateMap
464: .put(fragment.getId(),
465: replacementCoordinate);
466: }
467: if (updateFragmentObjects) {
468: fragment.setLayoutColumn(colIndex);
469: fragment.setLayoutRow(rowIndex);
470: }
471: }
472: }
473: }
474: }
475:
476: public int getFragmentRow(Fragment fragment) {
477: if (fragment == null)
478: return -1;
479: Coordinate coordinate = (Coordinate) this .fragmentCoordinateMap
480: .get(fragment.getId());
481:
482: if (coordinate == null)
483: return -1;
484: if (coordinate.getNewRow() >= 0)
485: return coordinate.getNewRow();
486: return coordinate.getOldRow();
487: }
488:
489: public int getFragmentCol(Fragment fragment) {
490: if (fragment == null)
491: return -1;
492: Coordinate coordinate = (Coordinate) this .fragmentCoordinateMap
493: .get(fragment.getId());
494:
495: if (coordinate == null)
496: return -1;
497: if (coordinate.getNewCol() >= 0)
498: return coordinate.getNewCol();
499: return coordinate.getOldCol();
500: }
501:
502: public Fragment getFragment(String fragmentId)
503: throws PortletPlacementException {
504: return (Fragment) this .fragmentMap.get(fragmentId);
505: }
506:
507: public Fragment getFragmentAtOldCoordinate(Coordinate coordinate)
508: throws PortletPlacementException {
509: return getFragmentAtCoordinate(coordinate, true, false);
510: }
511:
512: public Fragment getFragmentAtNewCoordinate(Coordinate coordinate)
513: throws PortletPlacementException {
514: return getFragmentAtCoordinate(coordinate, false, false);
515: }
516:
517: protected Fragment getFragmentAtCoordinate(Coordinate coordinate,
518: boolean useOldCoordinateValues, boolean suppressExceptions)
519: throws PortletPlacementException {
520: int col = -1;
521: int row = -1;
522: if (useOldCoordinateValues) {
523: col = coordinate.getOldCol();
524: row = coordinate.getOldRow();
525: } else {
526: col = coordinate.getNewCol();
527: row = coordinate.getNewRow();
528: }
529:
530: // Do some sanity checking about the request
531: if (col < 0 || col >= this .numberOfColumns) {
532: if (suppressExceptions)
533: return null;
534: throw new PortletPlacementException("Requested column ("
535: + col + ") is out of bounds (column-count="
536: + this .numberOfColumns + ")");
537: }
538:
539: // Get the array list associated with the column
540: ArrayList columnArray = this .columnsList[col];
541: if (row < 0 || row >= columnArray.size()) {
542: if (suppressExceptions)
543: return null;
544: throw new PortletPlacementException("Requested row (" + row
545: + ") is out of bounds (col[" + col + "].row-count="
546: + columnArray.size() + ")");
547: }
548:
549: return (Fragment) columnArray.get(row);
550: }
551:
552: public Fragment getFragmentById(String fragmentId)
553: throws PortletPlacementException {
554: return (Fragment) this .fragmentMap.get(fragmentId);
555: }
556:
557: public int getNumberColumns() throws PortletPlacementException {
558: return this .numberOfColumns;
559: }
560:
561: public int getNumberRows(int col) throws PortletPlacementException {
562: // Sanity check the column
563: if (col < 0 || col >= this .numberOfColumns) {
564: throw new PortletPlacementException("Requested column ("
565: + col + ") is out of bounds (column-count="
566: + this .numberOfColumns + ")");
567: }
568: return this .columnsList[col].size();
569: }
570:
571: public Coordinate add(Fragment fragment, Coordinate coordinate)
572: throws PortletPlacementException {
573: return moveAbsolute(fragment, coordinate, true);
574: }
575:
576: public Coordinate moveAbsolute(Fragment fragment,
577: Coordinate newCoordinate) throws PortletPlacementException {
578: return moveAbsolute(fragment, newCoordinate, false);
579: }
580:
581: public Coordinate moveAbsolute(Fragment fragment,
582: Coordinate newCoordinate, boolean okToAddFragment)
583: throws PortletPlacementException {
584: if (fragment == null)
585: throw new NullPointerException(
586: "PortletPlacementContext moveAbsolute() cannot accept a null Fragment argument");
587:
588: Coordinate currentCoordinate = (Coordinate) this .fragmentCoordinateMap
589: .get(fragment.getId());
590: int currentCol = getLatestColumn(currentCoordinate);
591: int currentRow = getLatestRow(currentCoordinate);
592:
593: int newCol = normalizeColumnIndex(
594: getLatestColumn(newCoordinate), this .columnsList,
595: currentCol);
596: int newRow = getLatestRow(newCoordinate);
597:
598: if (currentCoordinate == null) {
599: if (!okToAddFragment)
600: throw new NullPointerException(
601: "PortletPlacementContext moveAbsolute() cannot add fragment ("
602: + fragment.getId()
603: + ") unless the okToAddFragment argument is set to true");
604:
605: // add fragment
606: ArrayList newColumn = this .columnsList[newCol];
607: if (newRow < 0 || newRow >= newColumn.size())
608: newRow = newColumn.size();
609: newColumn.add(newRow, fragment);
610:
611: CoordinateImpl coordinate = new CoordinateImpl(newCol,
612: newRow);
613: this .fragmentCoordinateMap
614: .put(fragment.getId(), coordinate);
615: this .fragmentMap.put(fragment.getId(), fragment);
616: syncFragments(false, newCol);
617: } else {
618: boolean columnChanged = (currentCol != newCol);
619: boolean rowChanged = (currentRow != newRow);
620:
621: if (columnChanged || rowChanged) {
622: verifyFragmentAtExpectedCoordinate(currentCol,
623: currentRow, fragment, "moveAbsolute()");
624:
625: ArrayList currentColumn = this .columnsList[currentCol];
626: currentColumn.remove(currentRow);
627:
628: ArrayList newColumn = currentColumn;
629: if (columnChanged)
630: newColumn = this .columnsList[newCol];
631:
632: if (newRow < 0 || newRow >= newColumn.size())
633: newColumn.add(fragment);
634: else
635: newColumn.add(newRow, fragment);
636:
637: this .fragmentMap.put(fragment.getId(), fragment);
638:
639: syncFragments(false, currentCol);
640: if (columnChanged)
641: syncFragments(false, newCol);
642: }
643: }
644: return (Coordinate) this .fragmentCoordinateMap.get(fragment
645: .getId());
646: }
647:
648: protected Coordinate moveDirection(Fragment fragment, int deltaCol,
649: int deltaRow) throws PortletPlacementException {
650: if (fragment == null)
651: throw new NullPointerException(
652: "PortletPlacementContext moveDirection() cannot accept a null Fragment argument");
653:
654: if (deltaCol != 0 || deltaRow != 0) {
655: Coordinate currentCoordinate = (Coordinate) this .fragmentCoordinateMap
656: .get(fragment.getId());
657: if (currentCoordinate == null)
658: throw new NullPointerException(
659: "PortletPlacementContext moveDirection() cannot locate target fragment ("
660: + fragment.getId() + ")");
661:
662: int currentCol = getLatestColumn(currentCoordinate);
663: int currentRow = getLatestRow(currentCoordinate);
664:
665: verifyFragmentAtExpectedCoordinate(currentCol, currentRow,
666: fragment, "moveDirection()");
667:
668: int newCol = currentCol + deltaCol;
669: int newRow = currentRow + deltaRow;
670: if (newCol >= 0 && newCol < this .numberOfColumns) {
671: ArrayList currentColumn = this .columnsList[currentCol];
672: ArrayList newColumn = currentColumn;
673: if (newCol != currentCol)
674: newColumn = this .columnsList[newCol];
675:
676: currentColumn.remove(currentRow);
677:
678: if (newRow < 0 || newRow >= newColumn.size())
679: newColumn.add(fragment);
680: else
681: newColumn.add(newRow, fragment);
682:
683: this .fragmentMap.put(fragment.getId(), fragment);
684:
685: syncFragments(false, currentCol);
686: if (newCol != currentCol)
687: syncFragments(false, newCol);
688: }
689: }
690: return (Coordinate) this .fragmentCoordinateMap.get(fragment
691: .getId());
692: }
693:
694: public Coordinate moveDown(Fragment fragment)
695: throws PortletPlacementException {
696: return moveDirection(fragment, 0, 1);
697: }
698:
699: public Coordinate moveUp(Fragment fragment)
700: throws PortletPlacementException {
701: return moveDirection(fragment, 0, -1);
702: }
703:
704: public Coordinate moveLeft(Fragment fragment)
705: throws PortletPlacementException {
706: return moveDirection(fragment, -1, 0);
707: }
708:
709: public Coordinate moveRight(Fragment fragment)
710: throws PortletPlacementException {
711: return moveDirection(fragment, 1, 0);
712: }
713:
714: public Coordinate remove(Fragment fragment)
715: throws PortletPlacementException {
716: if (fragment == null)
717: throw new NullPointerException(
718: "PortletPlacementContext remove() cannot accept a null Fragment argument");
719:
720: Coordinate currentCoordinate = (Coordinate) this .fragmentCoordinateMap
721: .get(fragment.getId());
722: if (currentCoordinate == null)
723: throw new NullPointerException(
724: "PortletPlacementContext remove() cannot locate target fragment ("
725: + fragment.getId() + ")");
726:
727: int currentCol = getLatestColumn(currentCoordinate);
728: int currentRow = getLatestRow(currentCoordinate);
729:
730: verifyFragmentAtExpectedCoordinate(currentCol, currentRow,
731: fragment, "moveDirection()");
732:
733: ArrayList currentColumn = this .columnsList[currentCol];
734:
735: currentColumn.remove(currentRow);
736:
737: this .fragmentCoordinateMap.remove(fragment.getId());
738: this .fragmentMap.remove(fragment.getId());
739:
740: syncFragments(false, currentCol);
741:
742: return currentCoordinate;
743: }
744:
745: protected Fragment verifyFragmentAtExpectedCoordinate(int colIndex,
746: int rowIndex, Fragment fragment, String sourceDesc)
747: throws PortletPlacementException {
748: CoordinateImpl coordinate = new CoordinateImpl(colIndex,
749: rowIndex);
750:
751: boolean suppressExceptions = (fragment != null);
752: Fragment foundFragment = getFragmentAtCoordinate(coordinate,
753: true, suppressExceptions);
754:
755: if (fragment != null) {
756: if (foundFragment == null
757: || foundFragment.getId() != fragment.getId()) {
758: sourceDesc = (sourceDesc == null ? "getFragmentAtExpectedCoordinate"
759: : sourceDesc);
760:
761: ArrayList column = null;
762: int colFragCount = -1;
763: if (colIndex >= 0 && colIndex < this .numberOfColumns) {
764: column = this .columnsList[colIndex];
765: colFragCount = column.size();
766: }
767: StringBuffer out = new StringBuffer();
768: out.append("PortletPlacementContext ").append(
769: sourceDesc).append(
770: " has encountered unexpected results");
771: out
772: .append(
773: " using the current instance state to locate fragment ")
774: .append(fragment.getId()).append(" (");
775: if (foundFragment == null)
776: out.append("no fragment");
777: else
778: out.append("different fragment");
779: out.append(" in row ").append(rowIndex).append(
780: " of column ").append(colIndex);
781: if (column == null) {
782: out
783: .append(
784: " - column is out of bounds, column-count=")
785: .append(this .numberOfColumns);
786: } else {
787: out.append(" - ");
788: if (rowIndex < 0 || rowIndex >= colFragCount)
789: out.append("row is out of bounds, ");
790: out.append("row-count=").append(colFragCount);
791: }
792: out.append(")");
793: throw new PortletPlacementException(out.toString());
794: }
795: }
796: return fragment;
797: }
798:
799: static public int getColumnCountAndSizes(Fragment layoutFragment,
800: PortletRegistry registry, Map fragSizes) {
801: return PortletPlacementContextImpl.getColumnCountAndSizes(
802: layoutFragment, registry, fragSizes, false);
803: }
804:
805: static public int getColumnCountAndSizes(Fragment layoutFragment,
806: PortletRegistry registry, Map fragSizes,
807: boolean suppressErrorLogging) {
808: if (layoutFragment == null)
809: throw new NullPointerException(
810: "getColumnCountAndSizes cannot accept a null Fragment argument");
811: if (registry == null)
812: throw new NullPointerException(
813: "getColumnCountAndSizes cannot accept a null PortletRegistry argument");
814:
815: int columnCount = -1;
816: if (!"layout".equals(layoutFragment.getType())) {
817: if (!suppressErrorLogging)
818: log
819: .error("getColumnCountAndSizes not a layout fragment - "
820: + layoutFragment.getId()
821: + " type="
822: + layoutFragment.getType());
823: } else { // get layout fragment sizes
824: String sizesVal = layoutFragment.getProperty("sizes");
825: String layoutName = layoutFragment.getName();
826: layoutName = ((layoutName != null && layoutName.length() > 0) ? layoutName
827: : (String) null);
828: ParameterSet paramSet = null;
829: PortletDefinition portletDef = null;
830: if (sizesVal == null || sizesVal.length() == 0) {
831: if (layoutName != null) {
832: // logic below is copied from org.apache.jetspeed.portlets.MultiColumnPortlet
833: portletDef = registry
834: .getPortletDefinitionByUniqueName(layoutName);
835: if (portletDef != null) {
836: paramSet = portletDef.getInitParameterSet();
837: if (paramSet != null) {
838: Parameter sizesParam = paramSet
839: .get("sizes");
840: sizesVal = (sizesParam == null) ? null
841: : sizesParam.getValue();
842: }
843: }
844: }
845: }
846: if (sizesVal != null && sizesVal.length() > 0) {
847: if (fragSizes != null)
848: fragSizes.put(layoutFragment.getId(), sizesVal);
849:
850: int sepPos = -1, startPos = 0, sizesLen = sizesVal
851: .length();
852: columnCount = 0;
853: do {
854: sepPos = sizesVal.indexOf(',', startPos);
855: if (sepPos != -1) {
856: if (sepPos > startPos)
857: columnCount++;
858: startPos = sepPos + 1;
859: } else if (startPos < sizesLen) {
860: columnCount++;
861: }
862: } while (startPos < sizesLen && sepPos != -1);
863: if (!suppressErrorLogging && columnCount <= 0)
864: log
865: .error("getColumnCountAndSizes invalid columnCount - "
866: + layoutFragment.getId()
867: + " / "
868: + layoutName
869: + " count="
870: + columnCount
871: + " sizes="
872: + sizesVal);
873: } else if (paramSet == null) {
874: if (!suppressErrorLogging) {
875: if (layoutName == null)
876: log
877: .error("getColumnCountAndSizes null sizes, null layoutName - "
878: + layoutFragment.getId());
879: else if (portletDef == null)
880: log
881: .error("getColumnCountAndSizes null sizes, null PortletDefinition - "
882: + layoutFragment.getId()
883: + " / " + layoutName);
884: else
885: log
886: .error("getColumnCountAndSizes null sizes, null ParameterSet - "
887: + layoutFragment.getId()
888: + " / " + layoutName);
889: }
890: } else {
891: Parameter colsParam = paramSet.get("columns");
892: String colsParamVal = (colsParam == null) ? null
893: : colsParam.getValue();
894: if (colsParamVal != null && colsParamVal.length() > 0) {
895: try {
896: columnCount = Integer.parseInt(colsParamVal);
897: } catch (NumberFormatException ex) {
898: }
899: if (columnCount < 1) {
900: columnCount = 2;
901: }
902: switch (columnCount) {
903: case 1:
904: sizesVal = "100%";
905: break;
906: case 2:
907: sizesVal = "50%,50%";
908: break;
909: case 3:
910: sizesVal = "34%,33%,33%";
911: break;
912: case 4:
913: sizesVal = "25%,25%,25%,25%";
914: break;
915: default: {
916: sizesVal = "50%,50%";
917: columnCount = 2;
918: break;
919: }
920: }
921: if (fragSizes != null)
922: fragSizes.put(layoutFragment.getId(), sizesVal);
923: //log.info( "getColumnCountAndSizes " + layoutFragment.getId() + " count=" + columnCount + " defaulted-sizes=" + sizesParamVal );
924: } else {
925: if (!suppressErrorLogging)
926: log
927: .error("getColumnCountAndSizes null sizes, columns not defined in ParameterSet - "
928: + layoutFragment.getId()
929: + " / " + layoutName);
930: }
931: }
932: }
933: return columnCount;
934: }
935: }
|