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.HashMap;
20  import java.util.Iterator;
21  import java.util.Map;
22  
23  import javax.portlet.PortletMode;
24  import javax.portlet.WindowState;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.jetspeed.JetspeedActions;
29  import org.apache.jetspeed.PortalReservedParameters;
30  import org.apache.jetspeed.ajax.AJAXException;
31  import org.apache.jetspeed.ajax.AjaxAction;
32  import org.apache.jetspeed.ajax.AjaxBuilder;
33  import org.apache.jetspeed.container.state.MutableNavigationalState;
34  import org.apache.jetspeed.container.window.PortletWindowAccessor;
35  import org.apache.jetspeed.decoration.PageActionAccess;
36  import org.apache.jetspeed.layout.PortletActionSecurityBehavior;
37  import org.apache.jetspeed.om.page.ContentFragment;
38  import org.apache.jetspeed.om.page.ContentPage;
39  import org.apache.jetspeed.page.PageManager;
40  import org.apache.jetspeed.request.RequestContext;
41  import org.apache.pluto.om.window.PortletWindow;
42  
43  /***
44   * Changes the window state or portlet mode for a given portlet window
45   *
46   * AJAX Parameters: 
47   *    id = the fragment id of the portlet to move
48   *    page = (implied in the URL)
49   *    state = the new window state
50   *    mode = the new portlet mode
51   *    
52   * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
53   * @version $Id: $
54   */
55  public class ChangePortletAction 
56      extends BasePortletAction 
57      implements AjaxAction, AjaxBuilder, Constants
58  {
59      protected static final Log log = LogFactory.getLog(ChangePortletAction.class);
60      protected String action;
61      protected Map validWindowStates = new HashMap();
62      protected Map validPortletModes = new HashMap();
63      protected PortletWindowAccessor windowAccessor;
64      
65      public ChangePortletAction(String template, 
66              String errorTemplate, 
67              String action,
68              PortletWindowAccessor windowAccessor)            
69      throws AJAXException    
70      {
71          this(template, errorTemplate, action, null, windowAccessor, null);
72      }
73      
74      public ChangePortletAction(String template, 
75                               String errorTemplate, 
76                               String action,
77                               PageManager pageManager,
78                               PortletWindowAccessor windowAccessor,                             
79                               PortletActionSecurityBehavior securityBehavior)
80      throws AJAXException
81      {
82          super(template, errorTemplate, pageManager, securityBehavior);
83          this.action = action;
84          this.windowAccessor = windowAccessor;
85          
86          // Build the maps of allowed (internal) modes and states
87          Iterator modes = JetspeedActions.getStandardPortletModes().iterator();        
88          while (modes.hasNext())
89          {
90              String mode = modes.next().toString();
91              this.validPortletModes.put(mode, mode);
92          }
93          modes = JetspeedActions.getExtendedPortletModes().iterator();
94          while (modes.hasNext())
95          {
96              String mode = modes.next().toString();
97              this.validPortletModes.put(mode, mode);
98          }
99          Iterator states = JetspeedActions.getStandardWindowStates().iterator();        
100         while (states.hasNext())
101         {
102             String state = states.next().toString();
103             this.validWindowStates.put(state, state);
104         }        
105         states = JetspeedActions.getExtendedWindowStates().iterator();        
106         while (states.hasNext())
107         {
108             String state = states.next().toString();
109             this.validWindowStates.put(state, state);
110         }        
111     }
112 
113     public boolean runBatch(RequestContext requestContext, Map resultMap) throws AJAXException
114     {
115         return runAction(requestContext, resultMap, true);
116     }    
117     
118     public boolean run(RequestContext requestContext, Map resultMap)
119             throws AJAXException
120     {
121         return runAction(requestContext, resultMap, false);
122     }
123     
124     public boolean runAction(RequestContext requestContext, Map resultMap, boolean batch)
125     {
126         boolean success = true;
127         String status = "success";
128         try
129         {
130             resultMap.put(ACTION, action);
131             // Get the necessary parameters off of the request
132             String fragmentId = getActionParameter(requestContext, FRAGMENTID);
133             if (fragmentId == null) 
134             { 
135                 throw new Exception("fragment id not provided"); 
136             }
137             resultMap.put(FRAGMENTID, fragmentId);
138             
139             ContentPage page = requestContext.getPage();            
140             ContentFragment fragment = page.getContentFragmentById(fragmentId);
141             
142             if ( fragment == null )
143             {
144             	throw new Exception( "fragment specified by id cannot be found" );
145             }
146             String requestedState = getActionParameter(requestContext, WINDOW_STATE);
147             String requestedMode = getActionParameter(requestContext, PORTLET_MODE);    
148             if ( "layout".equals( fragment.getType() ) )
149             {
150             	if ( ! fragment.getId().equals( page.getRootFragment().getId() ) )
151             	{
152             		throw new Exception( "for layout fragments, change action applies to only to the root layout fragment (i.e. it does not apply to nested layout fragments)" );
153             	}
154             	PageActionAccess pageActionAccess = (PageActionAccess)requestContext.getAttribute( PortalReservedParameters.PAGE_EDIT_ACCESS_ATTRIBUTE );
155             	if ( pageActionAccess == null )
156             	{
157             		throw new Exception( "cannot change action for root layout fragment due to null PageActionAccess object" );
158             	}
159             	//pageActionAccess.
160             	PortletWindow window = windowAccessor.getPortletWindow(fragment);
161             	PortletMode currentMode = requestContext.getPortalURL().getNavigationalState().getMode( window );
162             	WindowState currentState = requestContext.getPortalURL().getNavigationalState().getState( window );
163             	
164             	boolean requestedModeAlreadySet = false;
165             	if ( requestedMode == null )
166             		requestedModeAlreadySet = true;
167             	else
168             	{
169             		if ( requestedMode.equals( PortletMode.EDIT.toString() ) )
170             		{
171             			if( pageActionAccess.isEditing() )
172             				requestedModeAlreadySet = true;
173             			else
174             			{
175             				if ( pageActionAccess.isEditAllowed())
176             				{
177             					pageActionAccess.setEditing( true );
178             					resultMap.put(STATUS, status);
179             					resultMap.put(OLD_PORTLET_MODE, currentMode.toString());
180             					resultMap.put(PORTLET_MODE, requestedMode);
181             				}
182             				else
183             				{
184             					throw new Exception( "permissions do no allow page edit" );
185             				}
186             			}
187             		}
188             		else if ( requestedMode.equals( PortletMode.VIEW.toString() ) )
189             		{
190             			pageActionAccess.setEditing( false );
191             			//if ( currentMode.equals( PortletMode.HELP ) )
192             			resultMap.put(STATUS, status);
193             			resultMap.put(OLD_PORTLET_MODE, currentMode.toString());
194             			resultMap.put(PORTLET_MODE, requestedMode);
195             		}
196             		else
197             		{
198             			requestedModeAlreadySet = true;
199             		}
200             	}
201             	if ( requestedModeAlreadySet )
202             	{
203            			resultMap.put(STATUS, status);
204            			resultMap.put(OLD_PORTLET_MODE, currentMode.toString());
205            			resultMap.put(PORTLET_MODE, currentMode.toString());
206            		}
207             }
208             else
209             {
210 	            if (requestedState == null && requestedMode == null) 
211 	            { 
212 	                throw new Exception("portlet window state or mode not provided"); 
213 	            }           
214 	            if (requestedState != null && !isValidWindowState(requestedState))
215 	            {
216 	                throw new Exception("portlet window state " + requestedState + " is not supported");
217 	            }
218 	            if (requestedMode != null && !isValidPortletMode(requestedMode))
219 	            {
220 	                throw new Exception("portlet mode " + requestedMode + " is not supported");
221 	            }
222 	
223 	            
224 	            String oldState = fragment.getState();
225 	            String oldMode = fragment.getMode();
226 	            
227 	            // Now Change the transient navigational state
228 	            MutableNavigationalState navState = (MutableNavigationalState)requestContext.getPortalURL().getNavigationalState();
229 	            PortletWindow portletWindow = windowAccessor.getPortletWindow(fragment);
230 	            if (portletWindow != null)
231 	            {
232 	                oldState = navState.getState(portletWindow).toString();
233 	                oldMode =  navState.getMode(portletWindow).toString();
234 	                if (requestedState != null)
235 	                {
236 	                    navState.setState(portletWindow, new WindowState(requestedState));
237 	                }
238 	                if (requestedMode != null)
239 	                {
240 	                    navState.setMode(portletWindow, new PortletMode(requestedMode));
241 	                }
242 	                navState.sync(requestContext);                                
243 	            }
244 	            
245 	
246 	            if (checkAccess(requestContext, JetspeedActions.EDIT))
247 	            {
248 	                if (requestedState != null)
249 	                    fragment.setState(requestedState);
250 	                if (requestedMode != null)
251 	                    fragment.setMode(requestedMode);
252 	                
253 	                if (pageManager != null && !batch)
254 	                {
255 	                    pageManager.updatePage(page);
256 	                }
257 	            }
258 	            
259 	            //requestContext.getPortalURL().getNavigationalState().
260 	            resultMap.put(STATUS, status);
261 	            
262 	            if (requestedState != null)
263 	            {
264 	                resultMap.put(OLD_WINDOW_STATE, oldState);
265 	                resultMap.put(WINDOW_STATE, requestedState);
266 	            }
267 	
268 	            if (requestedMode != null)
269 	            {
270 	                resultMap.put(OLD_PORTLET_MODE, oldMode);
271 	                resultMap.put(PORTLET_MODE, requestedMode);
272 	            }
273             }
274         } 
275         catch (Exception e)
276         {
277             // Log the exception
278             log.error("exception while changing portlet/page action", e);
279             resultMap.put(REASON, e.toString());
280             // Return a failure indicator
281             success = false;
282         }
283 
284         return success;
285     }
286     
287     // TODO: The validWindowStates and validPortletModes maps only contain 
288     //       internal (portal level) valid modes and states.
289     //       *if* a pa defines a custom mode/state with a different name but
290     //       mapped onto a internal (portal) mode/state 
291     //       *then* first the real internal mode/state needs to be retrieved from the 
292     //       targetted portlet its application:
293     //       o.a.j.om.common.portlet.PortletApplication.getMappedMode(customMode) and
294     //       o.a.j.om.common.portlet.PortletApplication.getMappedState(customState)        
295     
296     protected boolean isValidWindowState(String windowState)
297     {
298         return this.validWindowStates.containsKey(windowState);
299     }
300     protected boolean isValidPortletMode(String portletMode)
301     {
302         return this.validPortletModes.containsKey(portletMode);
303     }
304     
305 }