View Javadoc

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.List;
20  import java.util.ArrayList;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.apache.jetspeed.components.portletregistry.PortletRegistry;
25  import org.apache.jetspeed.layout.PortletPlacementException;
26  import org.apache.jetspeed.om.page.Fragment;
27  import org.apache.jetspeed.om.page.Page;
28  /***
29   * NestedFragmentContext
30   * 
31   * This object captures the nested position of a fragment
32   * within a page. Given a target fragment and a page,
33   * the target fragment col/row within its parent is
34   * recorded, followed by the target fragment's parent
35   * col/row within its parent, etc.
36   * 
37   * The purpose of this object is to support the
38   * create-new-page-on-edit feature. For example, when
39   * a fragment is moved, causing the creation of a new
40   * page, the information captured by this object 
41   * allows the copy of the fragment in the new page to
42   * be located.
43   * 
44   * @author <a>Steve Milek</a>
45   * @author <a href="mailto:smilek@apache.org">Steve Milek</a>
46   * @version $Id: $
47   */
48  public class NestedFragmentContext
49  {
50      protected static final Log log = LogFactory.getLog( NestedFragmentContext.class );
51      protected static final String eol = System.getProperty( "line.separator" );
52  	
53  	private Fragment targetFragment;
54  	private Fragment rootFragment;
55  	private Page page;
56  	private List fragmentLevels;
57  	
58  	public NestedFragmentContext( Fragment targetFragment, Page page, PortletRegistry registry )
59  	    throws PortletPlacementException
60  	{
61  		this.targetFragment = targetFragment;
62  		this.page = page;
63  		this.rootFragment = page.getRootFragment();
64  		init( registry );
65  	}
66  	
67  	protected void init( PortletRegistry registry )
68  	    throws PortletPlacementException
69  	{
70  		List nestedFragmentLevels = new ArrayList();
71  		Fragment nextTarget = targetFragment;
72  		Fragment nextParent = null;
73  		do
74  		{
75  			nextParent = NestedFragmentContext.getParentFragmentById( nextTarget.getId(), rootFragment );
76  			if ( nextParent != null )
77  			{
78  				NestedFragmentLevel level = new NestedFragmentLevel( nextTarget, nextParent, registry );
79  				nestedFragmentLevels.add( level );
80  				
81  				nextTarget = nextParent;
82  			}
83  			else
84  			{
85  				if ( ! nextTarget.getId().equals( rootFragment.getId() ) )
86  				{
87  					throw new PortletPlacementException( "Cannot determine complete nested structure for fragment " + targetFragment.getId() );
88  				}
89  				nextTarget = null;
90  			}
91  		}
92  		while ( nextTarget != null );
93  		this.fragmentLevels = nestedFragmentLevels;
94  	}
95  	
96  	public Fragment getFragmentOnNewPage( Page newPage, PortletRegistry registry )
97  	    throws PortletPlacementException
98  	{
99  		Fragment newPageRootFragment = newPage.getRootFragment();
100 		
101 		int depth = fragmentLevels.size();
102 		
103 		Fragment nextFragment = newPageRootFragment;
104 		for ( int i = depth -1; i >= 0 ; i-- )
105 		{
106 			NestedFragmentLevel level = (NestedFragmentLevel)fragmentLevels.get(i);
107 			PortletPlacementContextImpl placement = new PortletPlacementContextImpl( newPage, registry, nextFragment );
108 			try
109 			{
110 				nextFragment = placement.getFragmentAtOldCoordinate( new CoordinateImpl( level.getChildCol(), level.getChildRow() ) );
111 			
112 			}
113 			catch ( PortletPlacementException ppex )
114 			{
115 				log.error( "getFragmentOnNewPage failure to locate fragment on new page (index=" + i + ") :" + eol + this.toString() + ( placement != null ? ( eol + placement.dumpFragments(null) ) : "" ) + eol, ppex );
116 				throw ppex;
117 			}
118 		    catch ( RuntimeException ex )
119 			{
120 				log.error( "getFragmentOnNewPage failure to locate fragment on new page (index=" + i + ") :" + eol + this.toString() + ( placement != null ? ( eol + placement.dumpFragments(null) ) : "" ) + eol, ex );
121 				throw ex;
122 			}	
123 		    if ( nextFragment == null )
124 			{
125 				throw new PortletPlacementException( "Cannot locate copy of fragment " + targetFragment.getId() + " in the new page structure :" + eol + this.toString() + ( placement != null ? ( eol + placement.dumpFragments(null) ) : "" ));
126 			}
127 		}
128 		return nextFragment;
129 	}
130 	
131 	public String toString()
132 	{
133 		StringBuffer out = new StringBuffer();
134 		int depth = fragmentLevels.size();
135 		int ldepth = 0;
136 		for ( int i = depth -1; i >= 0 ; i-- )
137 		{
138 			NestedFragmentLevel level = (NestedFragmentLevel)fragmentLevels.get(i);
139 			if ( ldepth > 0 )
140 			{
141 				out.append( eol );
142 				for ( int j = 0 ; j < ldepth ; j++ )
143 					out.append( "   " );
144 			}
145 			ldepth++;
146 			out.append( level.toString() );
147 		}
148 		return out.toString();
149 	}
150 	
151 	class NestedFragmentLevel
152 	{
153 		private int childRow;
154 		private int childCol;
155 		private Fragment child;
156 		private Fragment parent;
157 		
158 		NestedFragmentLevel( Fragment child, Fragment parent, PortletRegistry registry )
159 		    throws PortletPlacementException
160 		{
161 			this.child = child;
162 			this.parent = parent;
163 			PortletPlacementContextImpl placement = new PortletPlacementContextImpl( page, registry, parent );
164             this.childRow = placement.getFragmentRow( child );
165             this.childCol = placement.getFragmentCol( child );
166 		}
167 		
168 		protected int getChildRow()
169 		{
170 			return this.childRow;
171 		}
172 		protected int getChildCol()
173 		{
174 			return this.childCol;
175 		}
176 		protected Fragment getChild()
177 		{
178 			return this.child;
179 		}
180 		protected Fragment getParent()
181 		{
182 			return this.parent;
183 		}
184 		public String toString()
185 		{
186 			return child.getType() + " col=" + childCol + " row=" + childRow  + " id=" + child.getId() + " parent-id=" + parent.getId() ;
187 		}
188 	}
189 	
190 	public static Fragment getParentFragmentById( String id, Fragment parent )
191     {   
192         // find fragment by id, tracking fragment parent
193         if ( id == null )
194         {
195         	return null;
196         }
197 		
198 		Fragment matchedParent = null;
199         if( parent != null ) 
200         {
201             // process the children
202             List children = parent.getFragments();
203             for( int i = 0, cSize = children.size() ; i < cSize ; i++) 
204             {
205                 Fragment childFrag = (Fragment)children.get( i );
206                 if ( childFrag != null ) 
207                 {
208                     if ( id.equals( childFrag.getId() ) )
209                     {
210                         matchedParent = parent;
211                         break;
212                     }
213                     else
214                     {
215                         matchedParent = NestedFragmentContext.getParentFragmentById( id, childFrag );
216                         if ( matchedParent != null )
217                         {
218                             break;
219                         }
220                     }
221                 }
222             }
223         }
224         return matchedParent;
225     }
226 }