View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.orchestra.flow.config;
20  
21  import java.io.Serializable;
22  import java.util.ArrayList;
23  import java.util.HashMap;
24  import java.util.List;
25  import java.util.Map;
26  
27  import javax.faces.context.FacesContext;
28  
29  import org.apache.myfaces.orchestra.lib.OrchestraException;
30  
31  /**
32   * Contains static metadata information about a callable flow.
33   */
34  public class FlowAccept implements Serializable
35  {
36      // For serialization. IMPORTANT; update this when changing the
37      // binary format of this class (eg adding fields).
38      private static final long serialVersionUID = 2L;
39  
40      private String service;
41      private String commitWhen = "commit";
42      private String cancelWhen = "cancel";
43      private String restartWhen = "restart";
44      private List<FlowParamAccept> params = new ArrayList<FlowParamAccept>(4);
45      private List<FlowReturnSend> returns = new ArrayList<FlowReturnSend>(4);
46  
47      /**
48       * Constructor.
49       */
50      public FlowAccept()
51      {
52      }
53  
54      /**
55       * Check that all the properties of this object have valid values, ie
56       * whether the configuration specified by the user is valid.
57       * <p>
58       * Throws an OrchestraException if a mandatory parameter is missing.
59       * <p>
60       * The service property is mandatory; it is always necessary to specify
61       * what logical service (function) this callable flow implements.
62       * <p>
63       * There must be at least one input parameter to this flow. There are
64       * so few sensible flows that take no input parameters at all that is
65       * is just not supported; it almost certainly means the user has made
66       * a configuration error.
67       * <p>
68       * There must be at least one output parameter from this flow. A
69       * sensible flow that returns no values to its caller is so rare that
70       * this is just not supported; it almost certainly means the user has
71       * made a configuration error.
72       */
73      public void validate()
74      {
75          if (service == null)
76          {
77              throw new OrchestraException("service is null");
78          }
79  
80          if (params.isEmpty())
81          {
82              throw new OrchestraException("params is empty");
83          }
84  
85          if (returns.isEmpty())
86          {
87              throw new OrchestraException("returns is empty");
88          }
89  
90          for(FlowParamAccept p: params)
91          {
92              p.validate();
93          }
94  
95          for(FlowReturnSend p : returns)
96          {
97              p.validate();
98          }
99      }
100 
101     /**
102      * Process all the configured "return param" expressions, fetching the data
103      * from the committed flow into a temporary map.
104      * <p>
105      * The data in this map is then expected to be passed back to the caller by
106      * executing the "return param" expressions of the matching FlowCall object. 
107      */
108     public Map<String, Object> readReturnParams(FacesContext facesContext)
109     {
110         Map<String, Object> data = new HashMap<String, Object>();
111         for(FlowReturnSend param : returns)
112         {
113             String paramName = param.getName();
114             Object paramValue = param.getSrcValue(facesContext);
115             data.put(paramName, paramValue);
116         }
117         return data;
118     }
119 
120     /**
121      * Process all the configured "accept param" expressions, fetching the data
122      * from a map and writing it into beans that are in conversations held by
123      * this flow's conversation context.
124      * <p>
125      * The map is expected to have been populated by executing the "send param"
126      * expressions of the matching FlowCall object. 
127      */
128     public void writeAcceptParams(FacesContext facesContext, Map<String, Object> data)
129     {
130         for(FlowParamAccept param : params)
131         {
132             String paramName = param.getName();
133 
134             Object paramValue;
135             if (data.containsKey(paramName))
136             {
137                 // use caller-provided value
138                 paramValue = data.get(paramName);
139             }
140             else
141             {
142                 // use default value
143                 String dflt = param.getDflt();
144                 if (dflt == null)
145                 {
146                     throw new OrchestraException("Missing parameter:" + paramName);
147                 }
148                 paramValue = param.getDfltValue(facesContext);
149             }
150 
151             param.setDstValue(facesContext, paramValue);
152         }
153     }
154 
155     /**
156      * Return the logical function that this flow implements.
157      * <p>
158      * This is a free-form text string, but it is recommended that the contents
159      * look like a fully-qualified java interface name. A called flow is really
160      * like invoking a service implementation object via a "service interface"
161      * that has only one method.  
162      */
163     public String getService()
164     {
165         return service;
166     }
167 
168     /** For use only during object initialization. */
169     public void setService(String service)
170     {
171         this.service = service;
172     }
173 
174     /**
175      * Return the JSF navigation outcome string that will trigger a "commit" of
176      * this flow.
177      * <p>
178      * When a flow is "committed", the return data specified for the flow is copied
179      * back to the caller, all conversations and contexts for the flow are deleted
180      * and navigation back to the original calling flow occurs.
181      * <p>
182      * This value defaults to "commit", which is usually a good choice. However
183      * it can be overridden if desired.
184      */
185     public String getCommitWhen()
186     {
187         return commitWhen;
188     }
189 
190     /** For use only during object initialization. */
191     public void setCommitWhen(String outcome)
192     {
193         this.commitWhen = outcome;
194     }
195 
196     /**
197      * Return the JSF navigation outcome string that will trigger a "cancel" of
198      * this flow.
199      * <p>
200      * When a flow is "cancelled", all conversations and contexts for the flow
201      * are deleted and navigation back to the original calling flow occurs. No
202      * data is "returned" to the caller.
203      * <p>
204      * This value defaults to "cancel", which is usually a good choice. However
205      * it can be overridden if desired.
206      */
207     public String getCancelWhen()
208     {
209         return cancelWhen;
210     }
211 
212     /** For use only during object initialization. */
213     public void setCancelWhen(String outcome)
214     {
215         this.cancelWhen = outcome;
216     }
217 
218     /**
219      * Return the JSF navigation outcome string that will trigger a "restart"
220      * of this flow.
221      * <p>
222      * Restarting a flow causes navigation to occur to the entry page for the
223      * flow again. 
224      * <p>
225      * This value defaults to "restart", which is usually a good choice. However
226      * it can be overridden if desired.
227      */
228     public String getRestartWhen()
229     {
230         return restartWhen;
231     }
232 
233     /** For use only during object initialization. */
234     public void setRestartWhen(String outcome)
235     {
236         this.restartWhen = outcome;
237     }
238 
239     /**
240      * Return list of FlowParamAccept objects which defines what input
241      * parameters this callable flow accepts.
242      */
243     public List<FlowParamAccept> getParams()
244     {
245         return params;
246     }
247 
248     /** For use only during object initialization. */
249     public void addParam(FlowParamAccept param)
250     {
251         this.params.add(param);
252     }
253 
254     /**
255      * Return list of FlowReturnSend objects which defines what output
256      * parameters this callable flow returns to the caller on commit.
257      */
258     public List<FlowReturnSend> getReturns()
259     {
260         return returns;
261     }
262 
263     /** For use only during object initialization. */
264     public void addReturn(FlowReturnSend returnParam)
265     {
266         this.returns.add(returnParam);
267     }
268 
269     /**
270      * Custom string format to improve log messages.
271      */
272     @Override
273     public String toString()
274     {
275         return "flowAccept: service=" + service;
276     }
277 }