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.Map;
20  import java.util.Iterator;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.apache.jetspeed.JetspeedActions;
25  import org.apache.jetspeed.ajax.AJAXException;
26  import org.apache.jetspeed.ajax.AjaxAction;
27  import org.apache.jetspeed.ajax.AjaxBuilder;
28  import org.apache.jetspeed.layout.Coordinate;
29  import org.apache.jetspeed.layout.PortletActionSecurityBehavior;
30  import org.apache.jetspeed.layout.PortletPlacementException;
31  import org.apache.jetspeed.layout.PortletPlacementContext;
32  import org.apache.jetspeed.om.page.Fragment;
33  import org.apache.jetspeed.om.page.Page;
34  import org.apache.jetspeed.page.PageManager;
35  import org.apache.jetspeed.page.document.NodeException;
36  import org.apache.jetspeed.request.RequestContext;
37  
38  /***
39   * Move Portlet portlet placement action
40   *
41   * AJAX Parameters: 
42   *    id = the fragment id of the portlet to move
43   *    page = (implied in the URL)
44   * Additional Absolute Parameters:  
45   *    row = the new row to move to
46   *    col = the new column to move to
47   * Additional Relative Parameters: (move left, right, up, down)
48   *    none
49   *    
50   * @author <a>David Gurney</a>
51   * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
52   * @version $Id: $
53   */
54  public class MovePortletAction 
55      extends BasePortletAction 
56      implements AjaxAction, AjaxBuilder, Constants
57  {
58      protected static final Log log = LogFactory.getLog(MovePortletAction.class);
59      private int iMoveType = -1;
60      private String sMoveType = null;
61  
62      public MovePortletAction(String template, 
63              String errorTemplate, 
64              String sMoveType)
65      throws AJAXException    
66      {
67          this(template, errorTemplate, sMoveType, null, null);
68      }
69      
70      public MovePortletAction(String template, 
71                               String errorTemplate, 
72                               PageManager pageManager,
73                               PortletActionSecurityBehavior securityBehavior)
74      throws AJAXException
75      {
76          this( template, errorTemplate, "moveabs", pageManager, securityBehavior );
77      }
78  
79      public MovePortletAction(String template, 
80                               String errorTemplate, 
81                               String sMoveType,
82                               PageManager pageManager,
83                               PortletActionSecurityBehavior securityBehavior)
84      throws AJAXException
85      {
86          super(template, errorTemplate, pageManager, securityBehavior);
87          setMoveType(sMoveType);
88      }
89  
90      // Convert the move type into an integer
91      public void setMoveType(String p_sMoveType) throws AJAXException
92      {
93          sMoveType = p_sMoveType;
94  
95          if (p_sMoveType.equalsIgnoreCase("moveabs"))
96          {
97              iMoveType = ABS;
98          } 
99          else if (p_sMoveType.equalsIgnoreCase("moveup"))
100         {
101             iMoveType = UP;
102         } 
103         else if (p_sMoveType.equalsIgnoreCase("movedown"))
104         {
105             iMoveType = DOWN;
106         } 
107         else if (p_sMoveType.equalsIgnoreCase("moveleft"))
108         {
109             iMoveType = LEFT;
110         } 
111         else if (p_sMoveType.equalsIgnoreCase("moveright"))
112         {
113             iMoveType = RIGHT;
114         }
115         else if (p_sMoveType.equalsIgnoreCase("move"))
116         {
117             iMoveType = CARTESIAN;
118         }
119         else
120         {
121             throw new AJAXException("invalid move type of:" + p_sMoveType);
122         }
123     }
124 
125     public boolean runBatch(RequestContext requestContext, Map resultMap) throws AJAXException
126     {
127         return runAction(requestContext, resultMap, true);
128     }    
129     
130     public boolean run(RequestContext requestContext, Map resultMap)
131             throws AJAXException
132     {
133         return runAction(requestContext, resultMap, false);
134     }
135     
136     protected boolean runAction( RequestContext requestContext, Map resultMap, boolean batch )  throws AJAXException
137     {
138         boolean success = true;
139         String status = "success";
140         try
141         {
142             resultMap.put(ACTION, sMoveType);
143             // Get the necessary parameters off of the request
144             String moveFragmentId = getActionParameter(requestContext, FRAGMENTID);
145             String layoutId = getActionParameter(requestContext, LAYOUTID);
146             if ( moveFragmentId == null ) 
147             {
148                 throw new Exception( FRAGMENTID + " not provided; must specify portlet or layout id" ); 
149             }
150             resultMap.put(FRAGMENTID, moveFragmentId);
151             
152             Fragment currentLayoutFragment = null;
153             Fragment moveToLayoutFragment = null;
154             // when layoutId is null we use old behavior, ignoring everything to do with multiple layout fragments
155             if ( layoutId != null && layoutId.length() > 0 && iMoveType != CARTESIAN )
156             {
157                 Page page = requestContext.getPage();
158                 currentLayoutFragment = page.getFragmentById( layoutId );
159                 if ( currentLayoutFragment == null )
160                 {
161                     throw new Exception("layout id not found: " + layoutId );
162                 }
163                 else
164                 {
165                     // determine if layoutId parameter refers to the current or the move target layout fragment
166                     moveToLayoutFragment = currentLayoutFragment;
167                     Iterator layoutChildIter = moveToLayoutFragment.getFragments().iterator();
168                     while ( layoutChildIter.hasNext() )
169                     {
170                         Fragment childFrag = (Fragment)layoutChildIter.next();
171                         if ( childFrag != null )
172                         {
173                             if ( moveFragmentId.equals( childFrag.getId() ) )
174                             {
175                                 moveToLayoutFragment = null;
176                                 break;
177                             }
178                         }
179                     }
180                     if ( moveToLayoutFragment != null )
181                     {
182                         // figure out the current layout fragment - must know to be able to find the portlet
183                         //    fragment by row/col when a new page is created
184                         Fragment root = requestContext.getPage().getRootFragment();
185                         currentLayoutFragment = getParentFragmentById(moveFragmentId, root);
186                     }
187                 }
188                 if ( currentLayoutFragment == null )
189                 {
190                     // report error
191                     throw new Exception("parent layout id not found for portlet id:" + moveFragmentId );
192                 }
193             }
194             
195             if (false == checkAccess(requestContext, JetspeedActions.EDIT))
196             {
197                 Page page = requestContext.getPage();
198                 Fragment fragment = page.getFragmentById(moveFragmentId);
199                 if (fragment == null)
200                 {
201                     success = false;
202                     resultMap.put(REASON, "Fragment not found");
203                     return success;
204                 }
205                 
206                 // remember current row/column of porlet fragment
207                 int column = fragment.getLayoutColumn();
208                 int row = fragment.getLayoutRow();
209                 
210                 // rememeber current row/column of parent layout fragment and move-to layout fragment
211                 int layoutColumn = -1, layoutRow = -1;
212                 int moveToLayoutColumn = -1, moveToLayoutRow = -1;
213                 if ( currentLayoutFragment != null )
214                 {
215                     layoutColumn = currentLayoutFragment.getLayoutColumn();
216                     layoutRow = currentLayoutFragment.getLayoutRow();
217                     if ( moveToLayoutFragment != null )
218                     {
219                         moveToLayoutColumn = moveToLayoutFragment.getLayoutColumn();
220                         moveToLayoutRow = moveToLayoutFragment.getLayoutRow();
221                     }
222                 }
223                 
224                 if (!createNewPageOnEdit(requestContext))
225                 {
226                     success = false;
227                     resultMap.put(REASON, "Insufficient access to edit page");
228                     return success;
229                 }
230                 status = "refresh";
231                 
232                 // translate old portlet id to new portlet id
233                 Fragment newFragment = getFragmentIdFromLocation(row, column, requestContext.getPage());
234                 if (newFragment == null)
235                 {
236                     success = false;
237                     resultMap.put( REASON, "Failed to find new fragment for portlet id: " + moveFragmentId );
238                     return success;                    
239                 }
240                 moveFragmentId = newFragment.getId();
241                 
242                 if ( currentLayoutFragment != null )
243                 {
244                     newFragment = getFragmentIdFromLocation(layoutRow, layoutColumn, requestContext.getPage());
245                     if (newFragment == null)
246                     {
247                         success = false;
248                         resultMap.put( REASON, "Failed to find new parent layout fragment id: " + currentLayoutFragment.getId() + " for portlet id: " + moveFragmentId );
249                         return success;
250                     }
251                     currentLayoutFragment = newFragment;
252                     if ( moveToLayoutFragment != null )
253                     {
254                         newFragment = getFragmentIdFromLocation(moveToLayoutRow, moveToLayoutColumn, requestContext.getPage());
255                         if (newFragment == null)
256                         {
257                             success = false;
258                             resultMap.put( REASON, "Failed to find new move-to layout fragment id: " + moveToLayoutFragment.getId() + " for portlet id: " + moveFragmentId );
259                             return success;
260                         }
261                         moveToLayoutFragment = newFragment;
262                     }
263                 }
264             }
265             
266             if ( moveToLayoutFragment != null )
267             {
268                 success = moveFragment( requestContext,
269                                         pageManager,
270                                         batch,
271                                         resultMap,
272                                         moveFragmentId,
273                                         moveToLayoutFragment,
274                                         currentLayoutFragment ) ;
275             }
276             else
277             {
278                 PortletPlacementContext placement = null;
279                 if ( currentLayoutFragment != null )
280                     placement = new PortletPlacementContextImpl(requestContext, currentLayoutFragment, 1);
281                 else
282                 {
283                     placement = new PortletPlacementContextImpl(requestContext);
284                 }
285                 Fragment fragment = placement.getFragmentById(moveFragmentId);
286                 if (fragment == null)
287                 {
288                     success = false;
289                     resultMap.put(REASON, "Failed to find fragment for portlet id: " + moveFragmentId );
290                     return success;
291                 }
292                 Coordinate returnCoordinate = null;
293                 float oldX = 0f, oldY = 0f, oldZ = 0f, oldWidth = 0f, oldHeight = 0f;
294                 float x = -1f, y = -1f, z = -1f, width = -1f, height = -1f;
295                 boolean absHeightChanged = false;
296                 
297                 String posExtended = getActionParameter(requestContext, DESKTOP_EXTENDED);
298                 if ( posExtended != null )
299                 {
300                     Map fragmentProperties = fragment.getProperties();
301                     if ( fragmentProperties == null )
302                     {
303                         success = false;
304                         resultMap.put(REASON, "Failed to acquire fragment properties map for portlet id: " + moveFragmentId );
305                         return success;
306                     }
307                     String oldDeskExt = (String)fragmentProperties.get( DESKTOP_EXTENDED );
308                     resultMap.put( OLD_DESKTOP_EXTENDED, ( (oldDeskExt != null) ? oldDeskExt : "" ) );
309                     fragmentProperties.put( DESKTOP_EXTENDED, posExtended );
310                 }
311                 
312                 // Only required for moveabs
313                 if (iMoveType == ABS)
314                 {
315                     Coordinate a_oCoordinate = getCoordinateFromParams(requestContext);
316                     returnCoordinate = placement.moveAbsolute(fragment, a_oCoordinate);
317                     String sHeight = getActionParameter(requestContext, HEIGHT);
318                     if ( sHeight != null && sHeight.length() > 0 )
319                     {
320                         oldHeight = fragment.getLayoutHeight();
321                         height = Float.parseFloat(sHeight);
322                         fragment.setLayoutHeight(height);
323                         absHeightChanged = true;
324                     }
325                 } 
326                 else if (iMoveType == LEFT)
327                 {
328                     returnCoordinate = placement.moveLeft(fragment);
329                 } 
330                 else if (iMoveType == RIGHT)
331                 {
332                     returnCoordinate = placement.moveRight(fragment);
333                 } 
334                 else if (iMoveType == UP)
335                 {
336                     returnCoordinate = placement.moveUp(fragment);
337                 } 
338                 else if (iMoveType == DOWN)
339                 {
340                     returnCoordinate = placement.moveDown(fragment);
341                 }
342                 else if (iMoveType == CARTESIAN)
343                 {
344                     String sx = getActionParameter(requestContext, X);
345                     String sy = getActionParameter(requestContext, Y);
346                     String sz = getActionParameter(requestContext, Z);
347                     String sWidth = getActionParameter(requestContext, WIDTH);
348                     String sHeight = getActionParameter(requestContext, HEIGHT);
349                     if (sx != null)
350                     {
351                         oldX = fragment.getLayoutX();
352                         x = Float.parseFloat(sx); 
353                         fragment.setLayoutX(x);
354                     }
355                     if (sy != null)
356                     {
357                         oldY = fragment.getLayoutY();                    
358                         y = Float.parseFloat(sy); 
359                         fragment.setLayoutY(y);
360                     }                
361                     if (sz != null)
362                     {
363                         oldZ = fragment.getLayoutZ();                    
364                         z = Float.parseFloat(sz); 
365                         fragment.setLayoutZ(z);
366                     }                
367                     if (sWidth != null)
368                     {
369                         oldWidth = fragment.getLayoutWidth();                    
370                         width = Float.parseFloat(sWidth); 
371                         fragment.setLayoutWidth(width);
372                     }
373                     if (sHeight != null)
374                     {
375                         oldHeight = fragment.getLayoutHeight();                    
376                         height = Float.parseFloat(sHeight); 
377                         fragment.setLayoutHeight(height);
378                     }
379                 }
380                 // synchronize back to the page layout root fragment
381                 Page page = placement.syncPageFragments();
382             
383                 if (pageManager != null && !batch)
384                 {
385                     pageManager.updatePage(page);
386                 }
387                 
388                 if (iMoveType == CARTESIAN)
389                 {
390                     putCartesianResult(resultMap, x, oldX, X, OLD_X);
391                     putCartesianResult(resultMap, y, oldY, Y, OLD_Y);                
392                     putCartesianResult(resultMap, z, oldZ, Z, OLD_Z);
393                     putCartesianResult(resultMap, width, oldWidth, WIDTH, OLD_WIDTH);
394                     putCartesianResult(resultMap, height, oldHeight, HEIGHT, OLD_HEIGHT);
395                 }
396                 else
397                 {
398                     // Need to determine what the old col and row were
399                     resultMap.put(OLDCOL, String.valueOf(returnCoordinate
400                             .getOldCol()));
401                     resultMap.put(OLDROW, String.valueOf(returnCoordinate
402                             .getOldRow()));
403                     // Need to determine what the new col and row were
404                     resultMap.put(NEWCOL, String.valueOf(returnCoordinate
405                             .getNewCol()));
406                     resultMap.put(NEWROW, String.valueOf(returnCoordinate
407                             .getNewRow()));
408                     if ( absHeightChanged )
409                     {
410                         putCartesianResult(resultMap, height, oldHeight, HEIGHT, OLD_HEIGHT);
411                     }
412                 }
413             }
414             resultMap.put(STATUS, status);
415             resultMap.put(FRAGMENTID, moveFragmentId);
416         } 
417         catch (Exception e)
418         {
419             // Log the exception
420             log.error("exception while moving a portlet", e);
421             resultMap.put(REASON, e.toString());
422             // Return a failure indicator
423             success = false;
424         }
425 
426         return success;
427     }
428 
429     protected boolean moveFragment( RequestContext requestContext,
430                                     PageManager pageManager,
431                                     boolean batch,
432                                     Map resultMap,
433                                     String moveFragmentId,
434                                     Fragment moveToLayoutFragment,
435                                     Fragment removeFromLayoutFragment )
436         throws PortletPlacementException, NodeException
437     {
438         boolean success = true;
439         Fragment placeFragment = null;
440         if ( removeFromLayoutFragment != null )
441         {
442             PortletPlacementContext placement = new PortletPlacementContextImpl( requestContext, removeFromLayoutFragment, 1 );
443         
444             placeFragment = placement.getFragmentById( moveFragmentId );
445             if ( placeFragment == null )
446             {
447                 success = false;
448                 resultMap.put( REASON, "Failed to find fragment to move to another layout for fragment id: " + moveFragmentId );
449                 return success;
450             }
451             placement.remove( placeFragment );
452             Page page = placement.syncPageFragments();
453             page.removeFragmentById( moveFragmentId );
454         }
455         if ( placeFragment != null )
456         {
457             return placeFragment( requestContext,
458                                   pageManager,
459                                   batch,
460                                   resultMap,
461                                   placeFragment,
462                                   moveToLayoutFragment );
463         }
464         return success;
465     }
466 
467     protected boolean placeFragment( RequestContext requestContext,
468                                      PageManager pageManager,
469                                      boolean batch,
470                                      Map resultMap,
471                                      Fragment placeFragment,
472                                      Fragment placeInLayoutFragment )
473         throws PortletPlacementException, NodeException
474     {
475         boolean success = true;
476         if ( placeFragment == null )
477         {
478             success = false;
479             return success;
480         }
481 
482         // desktop extended
483         String posExtended = getActionParameter(requestContext, DESKTOP_EXTENDED);
484         if ( posExtended != null )
485         {
486             Map fragmentProperties = placeFragment.getProperties();
487             if ( fragmentProperties == null )
488             {
489                 success = false;
490                 resultMap.put(REASON, "Failed to acquire fragment properties map for fragment id: " + placeFragment.getId() );
491                 return success;
492             }
493             String oldDeskExt = (String)fragmentProperties.get( DESKTOP_EXTENDED );
494             resultMap.put( OLD_DESKTOP_EXTENDED, ( (oldDeskExt != null) ? oldDeskExt : "" ) );
495             fragmentProperties.put( DESKTOP_EXTENDED, posExtended );
496         }
497                 
498         // add fragment
499         PortletPlacementContext placement = new PortletPlacementContextImpl( requestContext, placeInLayoutFragment, 1 );
500         Coordinate returnCoordinate = placement.add( placeFragment, getCoordinateFromParams( requestContext ) );
501         Page page = placement.syncPageFragments();
502 
503         placeInLayoutFragment.getFragments().add( placeFragment );
504         if ( pageManager != null && ! batch )
505         {
506             pageManager.updatePage( page );
507         }
508 
509         // Need to determine what the old col and row were
510         resultMap.put( OLDCOL, String.valueOf( returnCoordinate.getOldCol() ) );
511         resultMap.put( OLDROW, String.valueOf( returnCoordinate.getOldRow() ) );
512         // Need to determine what the new col and row were
513         resultMap.put( NEWCOL, String.valueOf( returnCoordinate.getNewCol() ) );
514         resultMap.put( NEWROW, String.valueOf( returnCoordinate.getNewRow() ) );
515 
516         return success;
517     }
518     
519     protected Coordinate getCoordinateFromParams(RequestContext requestContext)
520     {
521         String a_sCol = getActionParameter( requestContext, COL );
522         String a_sRow = getActionParameter( requestContext, ROW );
523 
524         int a_iCol = 0;
525         int a_iRow = 0;
526 
527         // Convert the col and row into integers
528         if ( a_sCol != null )
529         {
530             a_iCol = Integer.parseInt( a_sCol );
531         }
532         if ( a_sRow != null )
533         {
534             a_iRow = Integer.parseInt( a_sRow );
535         }
536 
537         Coordinate a_oCoordinate = new CoordinateImpl( 0, 0, a_iCol, a_iRow );
538         return a_oCoordinate;
539     }
540 
541     protected void putCartesianResult(Map resultMap, float value, float oldValue, String name, String oldName)
542     {    
543         if (value != -1F)
544         {
545             resultMap.put(oldName, new Float(oldValue));
546             resultMap.put(name, new Float(value));
547         }
548     }
549 }