Coverage report

  %line %branch
org.apache.jetspeed.layout.impl.PortletPlacementContextImpl
0% 
0% 

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

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.