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.Map;
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.components.portletregistry.PortletRegistry;
29  import org.apache.jetspeed.layout.PortletActionSecurityBehavior;
30  import org.apache.jetspeed.om.page.Fragment;
31  import org.apache.jetspeed.om.page.Page;
32  import org.apache.jetspeed.page.PageManager;
33  import org.apache.jetspeed.request.RequestContext;
34  
35  
36  /***
37   * Add Portlet portlet placement action
38   * 
39   * AJAX Parameters: 
40   *    id = portlet full name (pa::portletName) to be added
41   *    page = (implied in the URL)
42   * Optional Parameters:  
43   *    row = the new row to move to
44   *    col = the new column to move to
45   *    
46   * @author <a>David Gurney </a>
47   * @author <a href="mailto:taylor@apache.org">David Sean Taylor </a>
48   * @version $Id: $
49   */
50  public class AddPortletAction 
51      extends MovePortletAction 
52      implements AjaxAction, AjaxBuilder, Constants
53  {
54      protected Log log = LogFactory.getLog(AddPortletAction.class);
55      protected GetPortletsAction getPortletsAction = null;
56      protected boolean allowDuplicatePortlets = true;
57  
58      public AddPortletAction( String template, String errorTemplate, PortletRegistry registry, GetPortletsAction getPortletsAction )
59          throws AJAXException
60      {
61          this( template, errorTemplate, registry, null, null, getPortletsAction, true );
62      }
63  
64      public AddPortletAction( String template, 
65                               String errorTemplate, 
66                               PortletRegistry registry,
67                               PageManager pageManager,
68                               PortletActionSecurityBehavior securityBehavior,
69                               GetPortletsAction getPortletsAction )
70          throws AJAXException
71      {
72          this( template, errorTemplate, registry, pageManager, securityBehavior, getPortletsAction, true );
73      }
74  
75      public AddPortletAction( String template, 
76                               String errorTemplate,
77                               PortletRegistry registry,
78                               PageManager pageManager,
79                               PortletActionSecurityBehavior securityBehavior,
80                               GetPortletsAction getPortletsAction,
81                               boolean allowDuplicatePortlets )
82          throws AJAXException
83      {
84          super( template, errorTemplate, registry, pageManager, securityBehavior );
85          this.getPortletsAction = getPortletsAction;
86          this.allowDuplicatePortlets = allowDuplicatePortlets;
87      }
88      
89      protected boolean runAction( RequestContext requestContext, Map resultMap, boolean batch ) throws AJAXException
90      {
91          boolean success = true;
92          String status = "success";
93          try
94          {
95              resultMap.put( ACTION, "add" );
96              // Get the necessary parameters off of the request
97              String portletId = getActionParameter( requestContext, PORTLETID );
98              if (portletId == null) 
99              { 
100                 throw new RuntimeException( "portlet id not provided" ); 
101             }
102             resultMap.put( PORTLETID, portletId );
103             
104             // Verify that the specified portlet id is valid and accessible
105             // If the portletid is not valid an exception will be thrown
106             verifyPortletId( requestContext, portletId );
107             
108             if( allowDuplicatePortlets == false )
109             {
110             	// Check to see if this portlet has already been added to the page
111             	checkForDuplicatePortlet( requestContext, resultMap, portletId );
112             }
113             
114             String layoutId = getActionParameter( requestContext, LAYOUTID );
115             
116             if ( false == checkAccess( requestContext, JetspeedActions.EDIT ) )
117             {
118             	NestedFragmentContext addToFragmentContext = null;
119             	if ( layoutId != null && layoutId.length() > 0 )
120             	{
121             		Page page = requestContext.getPage();
122             		Fragment fragment = page.getFragmentById( layoutId );
123             		if ( fragment == null )
124             		{
125             			success = false;
126             			resultMap.put( REASON, "Specified layout fragment not found: " + layoutId );
127             			return success;
128             		}
129             	
130             		try
131             		{
132             			addToFragmentContext = new NestedFragmentContext( fragment, page, getPortletRegistry() );
133             		}
134             		catch ( Exception ex )
135             		{
136             			log.error( "Failure to construct nested context for fragment " + layoutId, ex );
137             			success = false;
138             			resultMap.put( REASON, "Cannot construct nested context for specified layout fragment" );
139             			return success;
140             		}
141             	}
142             	
143                 if ( ! createNewPageOnEdit( requestContext ) )
144                 {
145                     success = false;
146                     resultMap.put( REASON, "Insufficient access to edit page" );
147                     return success;
148                 }
149                 status = "refresh";
150 
151                 if ( addToFragmentContext != null )
152                 {
153                 	Page newPage = requestContext.getPage();
154 
155                 	// using NestedFragmentContext, find portlet id for copy of target portlet in the new page 
156                 	Fragment newFragment = null;
157                 	try
158                 	{
159                 		newFragment = addToFragmentContext.getFragmentOnNewPage( newPage, getPortletRegistry() );
160                 	}
161                 	catch ( Exception ex )
162                 	{
163                 		log.error( "Failure to locate copy of fragment " + layoutId, ex );
164                 		success = false;
165                 		resultMap.put( REASON, "Failed to find new fragment for specified layout id: " + layoutId );
166                 		return success;
167                 	}
168                 	layoutId = newFragment.getId();
169                 }
170             }
171             
172             Page page = requestContext.getPage();
173             
174             Fragment fragment = pageManager.newFragment();
175             fragment.setType( Fragment.PORTLET );
176             fragment.setName( portletId );
177             
178             Fragment placeInLayoutFragment = null;
179             if ( layoutId != null && layoutId.length() > 0 )
180             {
181                 placeInLayoutFragment = page.getFragmentById( layoutId );
182                 if ( placeInLayoutFragment == null )
183                 {
184                     throw new Exception( "layout id not found: " + layoutId );
185                 }
186             }
187             else
188             {
189                 placeInLayoutFragment = page.getRootFragment();
190             }
191 
192             success = placeFragment( requestContext,
193                                      batch,
194                                      resultMap,
195                                      fragment,
196                                      placeInLayoutFragment ) ;
197             
198             resultMap.put( PORTLETENTITY, fragment.getId() );
199             if ( success )
200             {
201             	resultMap.put( STATUS, status );
202             }
203         } 
204         catch ( Exception e )
205         {
206             // Log the exception
207             log.error("exception while adding a portlet", e);
208             resultMap.put(REASON, e.toString());
209 
210             // Return a failure indicator
211             success = false;
212         }
213 
214         return success;
215     }
216     
217     protected void verifyPortletId(RequestContext requestContext, String portletId) throws Exception
218     {
219     	// Get the list of valid portlets from the getPortletAction
220     	List portletList = getPortletsAction.retrievePortlets(requestContext, null);
221     	if(portletList != null) {
222     		for(int i = 0; i < portletList.size(); i++) {
223     			PortletInfo portletInfo = (PortletInfo)portletList.get(i);
224     			if(portletInfo != null) {
225     				if(portletInfo.getName().equalsIgnoreCase(portletId)) {
226     					// A match was found there is no need to continue
227     					return;
228     				}
229     			}
230     		}
231     	}
232     	// If we got here, then no match was found
233     	throw new Exception(portletId + " is not a valid portlet or not allowed for this user");
234     }
235     
236     protected void checkForDuplicatePortlet(RequestContext requestContext, Map resultMap, String portletId)
237     throws AJAXException
238     {
239     	// Look at each portlet currently on the page
240     	Page page = requestContext.getPage();
241     	
242     	boolean duplicateFound = isDuplicateFragment(page.getRootFragment(), portletId);
243     	
244     	// Throw an exception if a duplicate is found
245     	if(duplicateFound == true) {
246     		throw new AJAXException(portletId + " is already on the page, duplicates are not allowed");
247     	}
248     }
249 
250     protected boolean isDuplicateFragment(Fragment fragment, String portletId) {
251     	if(fragment != null) {
252 	    	// Get the name of this fragment
253 	    	String fragmentName = fragment.getName();
254 	    	if(fragmentName.equals(portletId)) {
255 	    		// Duplicate was found
256 	    		return true;
257 	    	} else {
258 	    		// Process the child fragments if found
259 	    		List childFragments = fragment.getFragments();
260 	    		if(childFragments != null) {
261 	    			for(int i = 0; i < childFragments.size(); i++) {
262 	    				// Recursively call this method again to process the child fragments
263 	    				if(isDuplicateFragment((Fragment)childFragments.get(i),portletId) == true) {
264 	    					// No need to continue to loop if a duplicate was found
265 	    					return true;
266 	    				}
267 	    			}
268 	    		}
269 	    	}
270     	}
271     	// We will only get here if no duplicates were found
272     	return false;
273     }
274 }