Announcement Announcement Module
Collapse
No announcement yet.
Evaluating variable to a Spring bean reference Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Evaluating variable to a Spring bean reference

    I'm running Spring 3.0 GA and Webflow 2.0.8... I have spring EL in the classpath along with ongl...

    I have a strategy used for reading data from a file. I have several instances of these strategies defined as spring beans.

    I have several <a href=".."/> tags in a jsp file that passes a parameter into webflow that identifies the bean id of one of these strategy instances. The webflow xml references the variable and makes a call to the read method.

    Here is the html code:

    Code:
    <tr>
        <td><a href="${flowExecutionUrl}&_eventId=viewAuditMessages&reader=vaLogInboundReader&listingName=View Messages" title="View">View</a></td>
    </tr>
    Here is the flow code:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <flow xmlns="http://www.springframework.org/schema/webflow"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://www.springframework.org/schema/webflow
    		http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
    
     	<!-- If not specified, the start state is the first state specified. -->
    	<view-state id="viewAuditManager" view="audit/auditManager">
    		<transition on="viewAuditMessages" to="viewAuditMessagesSubflow"/>
    	</view-state>
    		
    	<subflow-state id="viewAuditMessagesSubflow" subflow="viewAuditMessages">
    		<input name="reader" value="requestParameters.reader"/>
    		<input name="listingName"  value="requestParameters.listingName"/>
    	</subflow-state>
    		
    </flow>
    Here is the viewAuditMessages subflow:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <flow xmlns="http://www.springframework.org/schema/webflow"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://www.springframework.org/schema/webflow
    		http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
    
    	<var name="pageModel" class="gov.va.med.datasharing.th.model.PageModel"/>
    
    	<input name="reader" />
    	<input name="listingName" />
    		
     	<!-- If not specified, the start state is the first state specified. -->
    	<view-state id="viewInboundAuditMessages" model="pageModel" view="file/viewMessages">
    		<!-- Put listing name and messages on request scope for jsp access -->
    		<on-render>
    			<set name="flowScope.messages" value="#{reader}.read()"/>
    			<set name="requestScope.messages" value="flowScope.messages"/>
    		</on-render>
    		<transition on="newPage" to="viewInboundAuditMessages"/>
    	</view-state>
    		
    </flow>
    Note above the reference #{reader}.read()


    This exception occurs:

    Code:
    org.springframework.webflow.execution.ActionExecutionException: Exception thrown executing [AnnotatedAction@13bd737 targetAction = [SetAction@18c6634 name = flowScope.messages, value = #{reader}.read(), type = [null]], attributes = map[[empty]]] in state 'viewInboundAuditMessages' of flow 'viewAuditMessages' -- action execution attributes were 'map[[empty]]'
    	at org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:60)
    	at org.springframework.webflow.engine.ActionList.execute(ActionList.java:155)
    	at org.springframework.webflow.engine.ViewState.render(ViewState.java:280)
    	at org.springframework.webflow.engine.ViewState.refresh(ViewState.java:241)
    	at org.springframework.webflow.engine.ViewState.resume(ViewState.java:219)
    	at org.springframework.webflow.engine.Flow.resume(Flow.java:545)
    	at org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:259)
    	at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:163)
    	at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:183)
    	at org.springframework.webflow.mvc.servlet.FlowController.handleRequest(FlowController.java:174)
    	at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:771)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:716)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:647)
    	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:552)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    	at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
    	at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
    	at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
    	at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:175)
    	at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3498)
    	at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
    	at weblogic.security.service.SecurityManager.runAs(Unknown Source)
    	at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2180)
    	at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2086)
    	at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1406)
    	at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
    	at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)
    Caused by: org.springframework.binding.expression.EvaluationException: An OgnlException occurred getting the value for expression '#{reader}.read()' on context [class org.springframework.webflow.engine.impl.RequestControlContextImpl]
    	at org.springframework.binding.expression.ognl.OgnlExpression.getValue(OgnlExpression.java:92)
    	at org.springframework.webflow.action.SetAction.doExecute(SetAction.java:75)
    	at org.springframework.webflow.action.AbstractAction.execute(AbstractAction.java:188)
    	at org.springframework.webflow.execution.AnnotatedAction.execute(AnnotatedAction.java:145)
    	at org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:51)
    	... 28 more
    Caused by: ognl.MethodFailedException: Method "read" failed for object {vaLogInboundReader=null} [java.lang.NoSuchMethodException: read()]
    	at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:837)
    	at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:61)
    	at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:860)
    	at ognl.ASTMethod.getValueBody(ASTMethod.java:73)
    	at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170)
    	at ognl.SimpleNode.getValue(SimpleNode.java:210)
    	at ognl.ASTChain.getValueBody(ASTChain.java:109)
    	at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170)
    	at ognl.SimpleNode.getValue(SimpleNode.java:210)
    	at ognl.Ognl.getValue(Ognl.java:333)
    	at org.springframework.binding.expression.ognl.OgnlExpression.getValue(OgnlExpression.java:85)
    	... 32 more
    Caused by: java.lang.NoSuchMethodException: read()
    	at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:824)
    	... 42 more
    vaLogInboundReader is the value of reader. I think the issue is that EL is evaluating it as a string literal instead of the bean id reference. Is there a way in EL to specify reader so that it is interpreted as a Spring bean Id reference? Is there a way to explicitly do a 'applicationContext.getBean() in Spring EL? Or must I write a java class to do a lookup and call it in the webflow?

  • #2
    Let me make sure I understand what you're doing. Your "reader" attribute is actually the name of a Spring bean you want to resolve at runtime?

    I don't think SWF can do this on its own. However, it's easy enough to add a Resolver object as a utility Spring bean to help you out. Here's my implementation, which can be set as a singleton Spring bean for purposes like yours, or can be safely serialized, and thus composed with flow and view-scoped beans if you need that functionality:

    Code:
    /**
     * Resolves a Spring bean based upon the given String
     */
    public class BeanResolver implements Serializable {
      
      public Object resolve(String name) {
        ApplicationContext context = 
            RequestContextHolder.getRequestContext().getActiveFlow().getApplicationContext();
        return context.getBean(name);
      }
    }

    Comment


    • #3
      yes, that is what I am trying to do. I just thought there would be a built in way to do it.

      To my surprise though I'm having another problem. I changed the webflow code to:

      Code:
      	<view-state id="viewInboundAuditMessages" model="pageModel" view="file/viewMessages">
      		<!-- Put listing name and messages on request scope for jsp access -->
      		<on-render>
      			<set name="readerBean" value="beanResolver.resolve(reader)"/>
      			<set name="flowScope.messages" value="readerBean.read()"/>
      			<set name="requestScope.messages" value="flowScope.messages"/>
      		<evaluate expression="System.out.println($listingName)"/>
      		</on-render>
      		<transition on="newPage" to="viewInboundAuditMessages"/>
      	</view-state>
      The resolver appears to work; but there is some problem in EL... Is it legal to call a java method and assign the result to a variable in EL?

      Here is the exception:

      Code:
      org.springframework.webflow.execution.ActionExecutionException: Exception thrown executing [AnnotatedAction@42f484 targetAction = [SetAction@11b7f38 name = readerBean, value = beanResolver.resolve(reader), type = [null]], attributes = map[[empty]]] in state 'viewInboundAuditMessages' of flow 'viewAuditMessages' -- action execution attributes were 'map[[empty]]'
      	at org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:60)
      	at org.springframework.webflow.engine.ActionList.execute(ActionList.java:155)
      	at org.springframework.webflow.engine.ViewState.render(ViewState.java:280)
      	at org.springframework.webflow.engine.ViewState.refresh(ViewState.java:241)
      	at org.springframework.webflow.engine.ViewState.resume(ViewState.java:219)
      	at org.springframework.webflow.engine.Flow.resume(Flow.java:545)
      	at org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:259)
      	at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:163)
      	at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:183)
      	at org.springframework.webflow.mvc.servlet.FlowController.handleRequest(FlowController.java:174)
      	at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
      	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:771)
      	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:716)
      	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:647)
      	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:552)
      	at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
      	at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
      	at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
      	at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
      	at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
      	at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:175)
      	at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3498)
      	at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
      	at weblogic.security.service.SecurityManager.runAs(Unknown Source)
      	at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2180)
      	at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2086)
      	at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1406)
      	at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
      	at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)
      Caused by: org.springframework.binding.expression.PropertyNotFoundException: Property not found
      	at org.springframework.binding.expression.ognl.OgnlExpression.setValue(OgnlExpression.java:105)
      	at org.springframework.webflow.action.SetAction.doExecute(SetAction.java:76)
      	at org.springframework.webflow.action.AbstractAction.execute(AbstractAction.java:188)
      	at org.springframework.webflow.execution.AnnotatedAction.execute(AnnotatedAction.java:145)
      	at org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:51)
      	... 28 more
      Caused by: ognl.NoSuchPropertyException: org.springframework.webflow.engine.impl.RequestControlContextImpl.readerBean
      	at ognl.ObjectPropertyAccessor.setProperty(ObjectPropertyAccessor.java:132)
      	at org.springframework.webflow.expression.WebFlowOgnlExpressionParser$RequestContextPropertyAccessor.setProperty(WebFlowOgnlExpressionParser.java:144)
      	at ognl.OgnlRuntime.setProperty(OgnlRuntime.java:1670)
      	at ognl.ASTProperty.setValueBody(ASTProperty.java:101)
      	at ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:177)
      	at ognl.SimpleNode.setValue(SimpleNode.java:246)
      	at ognl.Ognl.setValue(Ognl.java:476)
      	at org.springframework.binding.expression.ognl.OgnlExpression.setValue(OgnlExpression.java:103)
      	... 32 more
      The reader contained the correct value, the getBean method succeeds and returns the proper instance; but yet this error occurs...

      Comment


      • #4
        I changed the code as follows and this works;

        OK, there is something I don't understand about assigning variables in webflow... Seems like it should have worked...


        Code:
        	<view-state id="viewInboundAuditMessages" model="pageModel" view="file/viewMessages">
        		<!-- Put listing name and messages on request scope for jsp access -->
        		<on-render>
        			<evaluate expression="beanResolver.resolve(reader)" result="viewScope.readerBean" />
        			<set name="flowScope.messages" value="viewScope.readerBean.read()"/>
        			<set name="requestScope.messages" value="flowScope.messages"/>
        		</on-render>
        		<transition on="newPage" to="viewInboundAuditMessages"/>
        	</view-state>

        Comment


        • #5
          As far as assignment goes, I think the problem is here:

          Code:
          <set name="readerBean" value="beanResolver.resolve(reader)"/>
          You're not providing any scope for this, so it doesn't know where you want to save this (flowScope? flash? view? etc). If you change it to specify the scope (viewScope.readerBean) then you're fine. Likewise, if you're trying to set a field of an already existing attribute, it can find it in whichever scope it's in and call the setter.

          As for your two following set actions, the scope is required in the "name" attribute, since you're setting new attributes in these scopes. However, you typically don't need to use the scope within the value attribute unless you have the same attribute name in multiple scopes. In your case, it might be necessary since you're saving messages in flow and requestScope.
          Last edited by InverseFalcon; Mar 8th, 2010, 03:57 PM.

          Comment


          • #6
            The problem with this is that I really don't want the reader strategies to be serializable. There is no need for them to go to the client... I simply want to assign a variable that would stay on the server, then reference it in another expression that makes the method call. This should all happen on the server...

            Comment


            • #7
              I'm a little confused by this. The only way something is going to get to the client is if you send it yourself, either explicitly on the page, in the header, or something like that. My understanding is requestScope is server-side attribute storage, but limited in lifetime to a single request. If you don't write a requestScoped attribute to your page, it's not going to transfer to your client.

              SWF's serialization requirements for its various scopes (flow, flash, view) are to support serialization of the state snapshot to better support browser back button usage. Serialized snapshots are kept server side; they are never sent to the client.

              If I've misunderstood your concern, please clarify.

              Comment


              • #8
                Sorry for the confusion. I misstated the concern over the client; however, it makes no sense to make this strategy class serializable since it does not keep state that the application cares about. I modified the code accordingly to eliminate the issues.

                Code:
                	<view-state id="viewInboundAuditMessages" model="pageModel" view="file/viewMessages">
                		<!-- Put listing name and messages on request scope for jsp access -->
                		<on-render>
                			<set name="requestScope.viewAuditLinks" value="'true'" />
                			<set name="flowScope.messages" value="beanResolver.resolve(readerName).read()"/>
                			<set name="requestScope.messages" value="flowScope.messages"/>
                		</on-render>
                		<transition on="newPage" to="viewInboundAuditMessages"/>
                	</view-state>
                Thanks for you assistance!

                Comment


                • #9
                  Sure thing. I'm still a bit confused about why you need to save the messages in flowScope. Can't you get by with requestScoped messages?

                  Comment


                  • #10
                    That was an old artifact that I was able to remove.

                    Thanks for you assistance!

                    Comment

                    Working...
                    X