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.portals.bridges.frameworks;
    18
    19  import java.io.IOException;
    20  import java.io.Serializable;
    21  import java.lang.reflect.Method;
    22  import java.util.Iterator;
    23  import java.util.Map;
    24  import java.util.ResourceBundle;
    25  import java.util.StringTokenizer;
    26
    27  import javax.portlet.ActionRequest;
    28  import javax.portlet.ActionResponse;
    29  import javax.portlet.PortletConfig;
    30  import javax.portlet.PortletContext;
    31  import javax.portlet.PortletException;
    32  import javax.portlet.PortletMode;
    33  import javax.portlet.PortletModeException;
    34  import javax.portlet.PortletPreferences;
    35  import javax.portlet.PortletRequest;
    36  import javax.portlet.PortletRequestDispatcher;
    37  import javax.portlet.PortletResponse;
    38  import javax.portlet.PortletSession;
    39  import javax.portlet.ReadOnlyException;
    40  import javax.portlet.RenderRequest;
    41  import javax.portlet.RenderResponse;
    42  import javax.portlet.WindowState;
    43  import javax.portlet.WindowStateException;
    44
    45  import org.apache.commons.beanutils.BeanUtils;
    46
    47  import org.apache.portals.bridges.frameworks.model.ModelBean;
    48  import org.apache.portals.bridges.frameworks.model.PortletApplicationModel;
    49  import org.apache.portals.bridges.frameworks.spring.PortletApplicationModelImpl;
    50  import org.apache.portals.bridges.velocity.GenericVelocityPortlet;
    51
    52  /***
    53   * SpringVelocityPortlet
    54   *
    55   * @author <a href="mailto:taylor@apache.org">David Sean Taylor </a>
    56   * @version $Id: GenericFrameworkPortlet.java,v 1.1 2004/11/04 18:09:33 taylor
    57   *          Exp $
    58   */
    59  public class GenericFrameworkPortlet extends GenericVelocityPortlet
    60  {
    61
    62      /***
    63       * Init Parameter: default spring configuration property
    64       */
    65      private static final String INITPARAM_SPRING_CONFIG = "spring-configuration";
    66
    67      /***
    68       * Init Parameter: default velocity configuration property
    69       */
    70      private static final String INITPARAM_VALIDATOR_CONFIG = "validator-configuration";
    71
    72      private static final String PREFS_SUFFIX = ".prefs";
    73
    74      private static final String SESSION_ERROR_MESSAGES = "portals.bridges.framework.errors";
    75
    76      /***
    77       * Action signature for calling velocity portlet actions
    78       */
    79      private static final Class[] VELOCITY_PORTLET_ACTION_SIGNATURE =
    80      { ActionRequest.class, ActionResponse.class, Object.class};
    81
    82      private static PortletApplicationModel model = null;
    83
    84      private static Object semaphore = new Object();
    85
    86      public GenericFrameworkPortlet()
    87      {
    88      }
    89
    90      public void setExternalSupport(Map map)
    91      {
    92          model.setExternalSupport(map);
    93      }
    94
    95      public void init(PortletConfig config) throws PortletException
    96      {
    97          super.init(config);
    98          String springConfig = this.getInitParameter(INITPARAM_SPRING_CONFIG);
    99          if (springConfig == null) { throw new PortletException("Spring Configuration file not specified"); }
    100
    101         String validatorConfig = this.getInitParameter(INITPARAM_VALIDATOR_CONFIG);
    102
    103         synchronized (semaphore)
    104         {
    105             if (null == model)
    106             {
    107                 model = new PortletApplicationModelImpl(springConfig, validatorConfig);
    108                 model.init(config);
    109             }
    110         }
    111     }
    112
    113     /***
    114      * Invoke the velocity portlet pipeline: (1) determine the logical view (2)
    115      * restore state from Form to Bean (3) validate the bean -- or -- (2)
    116      * restore state from Form to Prefs
    117      *
    118      * (4) execute the velocity action (5) forward to another view
    119      *
    120      */
    121     public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException
    122     {
    123         // (1) Determine the current view
    124         String view = determineLogicalView(request);
    125
    126         Object bean = null;
    127         ModelBean mb = model.getModelBean(view);
    128
    129         if (mb.getBeanType() == ModelBean.PREFS_MAP)
    130         {
    131             // (2) restore state from Form to Prefs
    132             bean = formToPrefs(request, view, mb);
    133         }
    134         else
    135         {
    136             // (2) restore state from Form to Bean
    137             bean = formToBean(request, view, mb);
    138         }
    139
    140         String forward = null;
    141
    142         // (3) validate the bean
    143         ResourceBundle bundle = this.getPortletConfig().getResourceBundle(request.getLocale());
    144         Map errors = model.validate(bean, view, bundle);
    145         if (errors.isEmpty())
    146         {
    147             request.getPortletSession().removeAttribute(SESSION_ERROR_MESSAGES, PortletSession.PORTLET_SCOPE);
    148
    149             // (4) execute the velocity action
    150             String action = request.getParameter(FrameworkConstants.BRIDGES_ACTION);
    151             if (null == action)
    152             {
    153                 if (mb.getBeanType() == ModelBean.PREFS_MAP)
    154                 {
    155                     // store prefs
    156                     storePreferences(request, (Map) bean);
    157                 }
    158
    159                 forward = model.getForward(view, ForwardConstants.SUCCESS);
    160             }
    161             else
    162             {
    163                 // call the specified action in the post params
    164                 String actionForward = invokeVelocityPortletAction(action, request, response, bean);
    165                 forward = model.getForward(actionForward);
    166             }
    167         }
    168         else
    169         {
    170             // failed validation
    171             request.getPortletSession().setAttribute(SESSION_ERROR_MESSAGES, errors, PortletSession.PORTLET_SCOPE);
    172             forward = model.getForward(view, ForwardConstants.FAILURE);
    173         }
    174
    175         clearBeanFromSession(request, mb);
    176
    177         // (5) forward to another view
    178         forwardToView(request, response, forward);
    179
    180     }
    181
    182     protected void forwardToView(ActionRequest request, ActionResponse response, String forward)
    183     {
    184         if (forward == null) { return; } // stay on same page
    185
    186         String logicalView = null;
    187         PortletMode newMode = null;
    188         StringTokenizer tokenizer = new StringTokenizer(forward, ForwardConstants.DELIMITER);
    189         while (tokenizer.hasMoreTokens())
    190         {
    191             String token = tokenizer.nextToken();
    192             if (token.startsWith(ForwardConstants.MODE_PREFIX))
    193             {
    194                 newMode = setPortletMode(response, token.substring(ForwardConstants.MODE_PREFIX.length()));
    195             }
    196             else if (token.startsWith(ForwardConstants.STATE_PREFIX))
    197             {
    198                 setWindowState(response, token.substring(ForwardConstants.STATE_PREFIX.length()));
    199             }
    200             else
    201             {
    202                 logicalView = token;
    203             }
    204         }
    205         if (logicalView != null)
    206         {
    207             setLogicalView(request, response, logicalView, newMode);
    208         }
    209
    210     }
    211
    212     private void setWindowState(ActionResponse response, String forward)
    213     {
    214         try
    215         {
    216             if (forward.equals(ForwardConstants.MAXIMIZED))
    217             {
    218                 response.setWindowState(WindowState.MAXIMIZED);
    219             }
    220             else if (forward.equals(ForwardConstants.MINIMIZED))
    221             {
    222                 response.setWindowState(WindowState.MINIMIZED);
    223             }
    224             else if (forward.equals(ForwardConstants.NORMAL))
    225             {
    226                 response.setWindowState(WindowState.NORMAL);
    227             }
    228         }
    229         catch (WindowStateException e)
    230         {
    231         }
    232     }
    233
    234     private PortletMode setPortletMode(ActionResponse response, String forward)
    235     {
    236         PortletMode mode = null;
    237         try
    238         {
    239             if (forward.equals(ForwardConstants.VIEW))
    240             {
    241                 response.setPortletMode(PortletMode.VIEW);
    242                 mode = PortletMode.VIEW;
    243             }
    244             else if (forward.equals(ForwardConstants.EDIT))
    245             {
    246                 response.setPortletMode(PortletMode.EDIT);
    247                 mode = PortletMode.EDIT;
    248             }
    249             else if (forward.equals(ForwardConstants.HELP))
    250             {
    251                 response.setPortletMode(PortletMode.HELP);
    252                 mode = PortletMode.HELP;
    253             }
    254         }
    255         catch (PortletModeException e)
    256         {
    257         }
    258         return mode;
    259     }
    260
    261     protected void storePreferences(PortletRequest request, Map bean) throws IOException, PortletException
    262     {
    263         String key = "none";
    264
    265         try
    266         {
    267             PortletPreferences prefs = request.getPreferences();
    268             Iterator it = bean.entrySet().iterator();
    269             while (it.hasNext())
    270             {
    271                 Map.Entry entry = (Map.Entry) it.next();
    272                 key = (String) entry.getKey();
    273                 if (!prefs.isReadOnly(key))
    274                 {
    275                     prefs.setValue(key, (String) entry.getValue());
    276                 }
    277             }
    278             prefs.store();
    279         }
    280         catch (ReadOnlyException roe)
    281         {
    282             throw new PortletException("Failed to set preference " + key + ", value is readonly");
    283         }
    284
    285     }
    286
    287     /***
    288      * Get the current logical view based on velocity.view request parameter If
    289      * the request parameter is not found, fall back to init param
    290      *
    291      * @param request
    292      * @return the current view
    293      * @throws PortletException
    294      */
    295     protected String determineLogicalView(PortletRequest request) throws PortletException
    296     {
    297         String view = null;
    298         PortletSession session = request.getPortletSession();
    299         if (request.getPortletMode().equals(PortletMode.VIEW))
    300         {
    301             view  = request.getParameter(FrameworkConstants.VIEW_VIEW_MODE);
    302             if (view == null)
    303             {
    304                 view = (String)session.getAttribute(FrameworkConstants.VIEW_VIEW_MODE);
    305                 //view = request.getParameter(FrameworkConstants.VIEW_VIEW_MODE);
    306                 if (view == null)
    307                 {
    308                     view = this.getDefaultViewPage();
    309                 }
    310             }
    311         }
    312         else if (request.getPortletMode().equals(PortletMode.EDIT))
    313         {
    314             view  = request.getParameter(FrameworkConstants.VIEW_EDIT_MODE);
    315             if (view == null)
    316             {
    317                 view = (String)session.getAttribute(FrameworkConstants.VIEW_EDIT_MODE);
    318                 //view = request.getParameter(FrameworkConstants.VIEW_EDIT_MODE);
    319                 if (view == null)
    320                 {
    321                     view = this.getDefaultEditPage();
    322                 }
    323             }
    324         }
    325         else if (request.getPortletMode().equals(PortletMode.HELP))
    326         {
    327             view  = request.getParameter(FrameworkConstants.VIEW_HELP_MODE);
    328             if (view == null)
    329             {
    330                 view = (String)session.getAttribute(FrameworkConstants.VIEW_HELP_MODE);
    331                 //view = request.getParameter(FrameworkConstants.VIEW_HELP_MODE);
    332                 if (view == null)
    333                 {
    334                     view = this.getDefaultHelpPage();
    335                 }
    336             }
    337         }
    338         if (null == view)
    339         {
    340             throw new PortletException(
    341                 "Portlet error: cant find view resource for portlet: "
    342                         + this.getPortletName());
    343         }
    344         return view;
    345     }
    346
    347     protected void setLogicalView(PortletRequest request, PortletResponse response, String view, PortletMode newMode)
    348     {
    349         PortletSession session = request.getPortletSession();
    350         if (request.getPortletMode().equals(PortletMode.VIEW))
    351         {
    352             session.setAttribute(FrameworkConstants.VIEW_VIEW_MODE, view);
    353         }
    354         else if (request.getPortletMode().equals(PortletMode.EDIT))
    355         {
    356             session.setAttribute(FrameworkConstants.VIEW_EDIT_MODE, view);
    357         }
    358         else if (request.getPortletMode().equals(PortletMode.HELP))
    359         {
    360             session.setAttribute(FrameworkConstants.VIEW_HELP_MODE, view);
    361         }
    362     }
    363
    364     protected Object formToBean(ActionRequest request, String view, ModelBean mb) throws PortletException
    365     {
    366
    367         // try to get the bean from the session first
    368         Object bean = getBeanFromSession(request, mb);
    369         if (bean == null)
    370         {
    371             bean = model.createBean(mb);
    372             if (bean == null) { throw new PortletException("Portlet Action error in creating bean for view: " + view); }
    373             putBeanInSession(request, mb, bean);
    374         }
    375
    376         Map params = request.getParameterMap();
    377         try
    378         {
    379             BeanUtils.populate(bean, params);
    380         }
    381         catch (Exception e)
    382         {
    383             throw new PortletException("Portlet Action error in  populating bean: " + mb.getBeanName(), e);
    384         }
    385         return bean;
    386     }
    387
    388     protected Object formToPrefs(ActionRequest request, String view, ModelBean mb) throws PortletException
    389     {
    390         Map params = request.getParameterMap();
    391         Map bean = (Map) request.getPortletSession().getAttribute(view + PREFS_SUFFIX);
    392         if (bean == null)
    393         {
    394             PortletPreferences prefs = request.getPreferences();
    395
    396             bean = model.createPrefsBean(mb, prefs.getMap());
    397
    398             request.getPortletSession().setAttribute(view + PREFS_SUFFIX, bean);
    399         }
    400
    401         try
    402         {
    403             Iterator it = params.entrySet().iterator();
    404             while (it.hasNext())
    405             {
    406                 Map.Entry entry = (Map.Entry) it.next();
    407                 Object value = entry.getValue();
    408                 String key = (String) entry.getKey();
    409                 if (null == bean.get(key))
    410                 {
    411                     continue;
    412                 }
    413                 if (value instanceof String)
    414                 {
    415                     bean.put(key, value);
    416                 }
    417                 else if (value instanceof String[])
    418                 {
    419                     bean.put(key, ((String[]) value)[0]);
    420                 }
    421             }
    422         }
    423         catch (Exception e)
    424         {
    425             throw new PortletException("Portlet Action error in  populating bean: ", e);
    426         }
    427         return bean;
    428     }
    429
    430     /***
    431      * Invokes a specific Velocity Portlet Action All portlet actions must have
    432      * the signature:
    433      *
    434      * String methodName(ActionRequest request, ActionResponse response)
    435      *
    436      * @param methodName
    437      */
    438     protected String invokeVelocityPortletAction(String methodName, ActionRequest request, ActionResponse response,
    439             Object bean) throws PortletException
    440     {
    441         try
    442         {
    443             Method method = this.getClass().getMethod(methodName, VELOCITY_PORTLET_ACTION_SIGNATURE);
    444             Object[] parameters =
    445             { request, response, bean};
    446             String result = (String) method.invoke(this, parameters);
    447             return result;
    448         }
    449         catch (Exception e)
    450         {
    451             throw new PortletException("Failed to invoke portlet action: " + methodName, e);
    452         }
    453     }
    454
    455     public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException
    456     {
    457         doRender(request, response);
    458     }
    459
    460     public void doHelp(RenderRequest request, RenderResponse response) throws PortletException, IOException
    461     {
    462         doRender(request, response);
    463     }
    464
    465     public void doEdit(RenderRequest request, RenderResponse response) throws PortletException, IOException
    466     {
    467         doRender(request, response);
    468     }
    469
    470     protected void doRender(RenderRequest request, RenderResponse response) throws PortletException, IOException
    471     {
    472         String view = determineLogicalView(request);
    473         if (view == null) { throw new PortletException("Logical View not found: " + view); }
    474
    475         String template = model.getTemplate(view);
    476         if (template == null) { throw new PortletException("Template not found for Logical View: " + view); }
    477
    478         ModelBean mb = model.getModelBean(view);
    479         switch (mb.getBeanType())
    480         {
    481         case ModelBean.PREFS_MAP:
    482             preferencesToContext(request, view, mb);
    483             break;
    484         case ModelBean.POJO:
    485             beanToContext(request, view, mb);
    486             break;
    487         }
    488         putRequestVariable(request, FrameworkConstants.FORWARD_TOOL, new Forwarder(model, request, response));
    489         Map errors = (Map) request.getPortletSession().getAttribute(SESSION_ERROR_MESSAGES,
    490                 PortletSession.PORTLET_SCOPE);
    491         if (errors != null)
    492         {
    493             putRequestVariable(request, "ERRORS", errors);
    494         }
    495         request.setAttribute(FrameworkConstants.MODEL_TOOL, model);
    496
    497         PortletContext context = getPortletContext();
    498         PortletRequestDispatcher rd = context.getRequestDispatcher(template);
    499         rd.include(request, response);
    500     }
    501
    502     private void beanToContext(RenderRequest request, String view, ModelBean mb)
    503     {
    504         Object bean;
    505
    506         String key = null;
    507         if (mb.getLookupKey() != null)
    508         {
    509             key = (String) request.getAttribute(mb.getLookupKey());
    510         }
    511
    512         if (key != null)
    513         {
    514             bean = model.lookupBean(mb, key);
    515             if (bean != null)
    516                 putBeanInSession(request, mb, bean);
    517         }
    518         else
    519         {
    520             bean = getBeanFromSession(request, mb);
    521         }
    522         if (bean == null)
    523         {
    524             bean = model.createBean(mb);
    525             if (bean == null) { return; }
    526             putBeanInSession(request, mb, bean);
    527         }
    528         putRequestVariable(request, mb.getBeanName(), bean);
    529     }
    530
    531     private void preferencesToContext(RenderRequest request, String view, ModelBean mb)
    532     {
    533         Map bean = (Map) request.getPortletSession().getAttribute(view + PREFS_SUFFIX);
    534         if (bean == null)
    535         {
    536             PortletPreferences prefs = request.getPreferences();
    537             bean = model.createPrefsBean(mb, prefs.getMap());
    538             putBeanInSession(request, mb, bean);
    539         }
    540         putRequestVariable(request, FrameworkConstants.PREFS_VARIABLE, bean);
    541     }
    542
    543     private Object getBeanFromSession(PortletRequest request, ModelBean mb)
    544     {
    545         return request.getPortletSession().getAttribute(makeModelBeanKey(mb));
    546     }
    547
    548     private void clearBeanFromSession(PortletRequest request, ModelBean mb)
    549     {
    550         request.getPortletSession().removeAttribute(makeModelBeanKey(mb));
    551     }
    552
    553     public void startNewRecord(PortletRequest request, String view)
    554     {
    555         ModelBean mb = model.getModelBean(view);
    556         if (mb != null)
    557             clearBeanFromSession(request, mb);
    558     }
    559
    560     private void putBeanInSession(PortletRequest request, ModelBean mb, Object bean)
    561     {
    562         if (bean instanceof Serializable)
    563         {
    564             request.getPortletSession().setAttribute(makeModelBeanKey(mb), bean);
    565         }
    566     }
    567
    568     private String makeModelBeanKey(ModelBean mb)
    569     {
    570         return "ModelBean:" + mb.getBeanName();
    571     }
    572
    573     /***
    574      * Specific for Velocity
    575      *
    576      * @param name
    577      * @param value
    578      */
    579     protected void putRequestVariable(RenderRequest request, String name, Object value)
    580     {
    581         request.setAttribute(name, value);
    582     }
    583
    584 }