001: package org.andromda.metafacades.uml14;
002:
003: import java.util.ArrayList;
004: import java.util.Collection;
005: import java.util.Collections;
006: import java.util.Iterator;
007: import java.util.LinkedHashMap;
008: import java.util.LinkedHashSet;
009: import java.util.List;
010: import java.util.Map;
011:
012: import org.andromda.metafacades.uml.EventFacade;
013: import org.andromda.metafacades.uml.FrontEndActionState;
014: import org.andromda.metafacades.uml.FrontEndActivityGraph;
015: import org.andromda.metafacades.uml.FrontEndController;
016: import org.andromda.metafacades.uml.FrontEndEvent;
017: import org.andromda.metafacades.uml.FrontEndFinalState;
018: import org.andromda.metafacades.uml.FrontEndForward;
019: import org.andromda.metafacades.uml.FrontEndParameter;
020: import org.andromda.metafacades.uml.FrontEndUseCase;
021: import org.andromda.metafacades.uml.FrontEndView;
022: import org.andromda.metafacades.uml.ModelElementFacade;
023: import org.andromda.metafacades.uml.OperationFacade;
024: import org.andromda.metafacades.uml.ParameterFacade;
025: import org.andromda.metafacades.uml.PseudostateFacade;
026: import org.andromda.metafacades.uml.StateVertexFacade;
027: import org.andromda.metafacades.uml.TransitionFacade;
028: import org.andromda.metafacades.uml.UseCaseFacade;
029: import org.apache.commons.collections.CollectionUtils;
030: import org.apache.commons.collections.Predicate;
031: import org.apache.commons.lang.StringUtils;
032:
033: /**
034: * MetafacadeLogic implementation for org.andromda.metafacades.uml.FrontEndAction.
035: *
036: * @see org.andromda.metafacades.uml.FrontEndAction
037: */
038: public class FrontEndActionLogicImpl extends FrontEndActionLogic {
039: public FrontEndActionLogicImpl(Object metaObject, String context) {
040: super (metaObject, context);
041: }
042:
043: /**
044: * @see org.andromda.metafacades.uml.FrontEndAction#getInput()
045: */
046: protected java.lang.Object handleGetInput() {
047: Object input = null;
048: final ModelElementFacade source = this .getSource();
049: if (source instanceof PseudostateFacade) {
050: final PseudostateFacade pseudostate = (PseudostateFacade) source;
051: if (pseudostate.isInitialState()) {
052: input = source;
053: }
054: } else {
055: if (source instanceof FrontEndView) {
056: input = source;
057: }
058: }
059: return input;
060: }
061:
062: /**
063: * @see org.andromda.metafacades.uml.FrontEndAction#getParameters()
064: */
065: protected java.util.List handleGetParameters() {
066: final EventFacade trigger = this .getTrigger();
067: return trigger == null ? Collections.EMPTY_LIST
068: : new ArrayList(trigger.getParameters());
069: }
070:
071: /**
072: * @see org.andromda.metafacades.uml.FrontEndAction#findParameter(java.lang.String)
073: */
074: protected ParameterFacade handleFindParameter(final String name) {
075: return (ParameterFacade) CollectionUtils.find(this
076: .getParameters(), new Predicate() {
077: public boolean evaluate(Object object) {
078: final ParameterFacade parameter = (ParameterFacade) object;
079: return StringUtils.trimToEmpty(parameter.getName())
080: .equals(name);
081: }
082: });
083: }
084:
085: /**
086: * @see org.andromda.metafacades.uml.FrontEndAction#getDeferredOperations()
087: */
088: protected java.util.List handleGetDeferredOperations() {
089: final Collection deferredOperations = new LinkedHashSet();
090: final FrontEndController controller = this .getController();
091: if (controller != null) {
092: final List actionStates = this .getActionStates();
093: for (int ctr = 0; ctr < actionStates.size(); ctr++) {
094: final FrontEndActionState actionState = (FrontEndActionState) actionStates
095: .get(ctr);
096: deferredOperations.addAll(actionState
097: .getControllerCalls());
098: }
099:
100: final List transitions = this .getDecisionTransitions();
101: for (int ctr = 0; ctr < transitions.size(); ctr++) {
102: final FrontEndForward forward = (FrontEndForward) transitions
103: .get(ctr);
104: final FrontEndEvent trigger = forward
105: .getDecisionTrigger();
106: if (trigger != null) {
107: deferredOperations.add(trigger.getControllerCall());
108: }
109: }
110: }
111: return new ArrayList(deferredOperations);
112: }
113:
114: /**
115: * @see org.andromda.metafacades.uml.FrontEndAction#getDecisionTransitions()
116: */
117: protected List handleGetDecisionTransitions() {
118: if (decisionTransitions == null) {
119: initializeCollections();
120: }
121: return new ArrayList(decisionTransitions);
122: }
123:
124: /**
125: * @see org.andromda.metafacades.uml.FrontEndAction#getTargetViews()
126: */
127: protected List handleGetTargetViews() {
128: final Collection targetViews = new LinkedHashSet();
129: final Collection forwards = this .getActionForwards();
130: for (final Iterator iterator = forwards.iterator(); iterator
131: .hasNext();) {
132: final FrontEndForward forward = (FrontEndForward) iterator
133: .next();
134: if (forward.isEnteringView()) {
135: targetViews.add(forward.getTarget());
136: }
137: }
138: return new ArrayList(targetViews);
139: }
140:
141: /**
142: * All action states that make up this action, this includes all possible action states traversed
143: * after a decision point too.
144: */
145: private Collection actionStates = null;
146:
147: /**
148: * All transitions leading into either a page or final state that originated from a call to this action.
149: */
150: private Map actionForwards = null;
151:
152: /**
153: * All transitions leading into a decision point that originated from a call to this action.
154: */
155: private Collection decisionTransitions = null;
156:
157: /**
158: * All transitions that can be traversed when calling this action.
159: */
160: private Collection transitions = null;
161:
162: /**
163: * Initializes all action states, action forwards, decision transitions and transitions in one shot, so that they
164: * can be queried more effiencently later on.
165: */
166: private void initializeCollections() {
167: this .actionStates = new LinkedHashSet();
168: this .actionForwards = new LinkedHashMap();
169: this .decisionTransitions = new LinkedHashSet();
170: this .transitions = new LinkedHashSet();
171: this .collectTransitions((TransitionFacade) this .THIS(),
172: transitions);
173: }
174:
175: /**
176: * Recursively collects all action states, action forwards, decision transitions and transitions.
177: *
178: * @param transition the current transition that is being processed
179: * @param processedTransitions the set of transitions already processed
180: */
181: private void collectTransitions(TransitionFacade transition,
182: Collection processedTransitions) {
183: if (processedTransitions.contains(transition)) {
184: return;
185: }
186: processedTransitions.add(transition);
187: final StateVertexFacade target = transition.getTarget();
188: if (target instanceof FrontEndView
189: || target instanceof FrontEndFinalState) {
190: if (!this .actionForwards
191: .containsKey(transition.getTarget())) {
192: this .actionForwards.put(transition.getTarget(),
193: transition);
194: }
195: } else if (target instanceof PseudostateFacade
196: && ((PseudostateFacade) target).isDecisionPoint()) {
197: this .decisionTransitions.add(transition);
198: final Collection outcomes = target.getOutgoing();
199: for (final Iterator iterator = outcomes.iterator(); iterator
200: .hasNext();) {
201: final TransitionFacade outcome = (TransitionFacade) iterator
202: .next();
203: collectTransitions(outcome, processedTransitions);
204: }
205: } else if (target instanceof FrontEndActionState) {
206: this .actionStates.add(target);
207: final FrontEndForward forward = ((FrontEndActionState) target)
208: .getForward();
209: if (forward != null) {
210: collectTransitions(forward, processedTransitions);
211: }
212: } else // all the rest is ignored but outgoing transitions are further processed
213: {
214: final Collection outcomes = target.getOutgoing();
215: for (final Iterator iterator = outcomes.iterator(); iterator
216: .hasNext();) {
217: final TransitionFacade outcome = (TransitionFacade) iterator
218: .next();
219: collectTransitions(outcome, processedTransitions);
220: }
221: }
222: }
223:
224: /**
225: * @see org.andromda.metafacades.uml.FrontEndAction#getActionStates()
226: */
227: protected List handleGetActionStates() {
228: if (this .actionStates == null) {
229: this .initializeCollections();
230: }
231: return new ArrayList(this .actionStates);
232: }
233:
234: /**
235: * @see org.andromda.metafacades.uml.FrontEndAction#getTransitions()
236: */
237: protected List handleGetTransitions() {
238: if (this .transitions == null) {
239: this .initializeCollections();
240: }
241: return new ArrayList(this .transitions);
242: }
243:
244: /**
245: * @see org.andromda.metafacades.uml.FrontEndAction#getActionForwards()
246: */
247: protected List handleGetActionForwards() {
248: if (this .actionForwards == null) {
249: this .initializeCollections();
250: }
251: return new ArrayList(this .actionForwards.values());
252: }
253:
254: /**
255: * @see org.andromda.metafacades.uml.FrontEndAction#getController()
256: */
257: protected Object handleGetController() {
258: final FrontEndActivityGraph graph = this
259: .getFrontEndActivityGraph();
260: return graph == null ? null : graph.getController();
261: }
262:
263: /**
264: * Overridden because actions (transitions) are not directly contained in a UML namespace.
265: *
266: * @see org.andromda.metafacades.uml.ModelElementFacade#getPackageName()
267: */
268: public String handleGetPackageName() {
269: String packageName = null;
270:
271: final UseCaseFacade useCase = this .getUseCase();
272: if (useCase != null) {
273: packageName = useCase.getPackageName();
274: }
275: return packageName;
276: }
277:
278: /**
279: * @see org.andromda.metafacades.uml.FrontEndAction#isUseCaseStart()
280: */
281: protected boolean handleIsUseCaseStart() {
282: final StateVertexFacade source = getSource();
283: return source instanceof PseudostateFacade
284: && ((PseudostateFacade) source).isInitialState();
285: }
286:
287: /**
288: * @see org.andromda.metafacades.uml.FrontEndAction#getFormFields()
289: */
290: protected List handleGetFormFields() {
291: final Map formFieldMap = new LinkedHashMap();
292:
293: // - For an action that starts the use case, we need to detect all usecases forwarding to the one
294: // belonging to this action if there are any parameters in those transitions we need to have
295: // them included in this action's form
296: if (this .isUseCaseStart()) {
297: final FrontEndUseCase useCase = this .getUseCase();
298: if (useCase != null) {
299: final Collection finalStates = useCase
300: .getReferencingFinalStates();
301: for (final Iterator finalStateIterator = finalStates
302: .iterator(); finalStateIterator.hasNext();) {
303: final Object finalStateObject = finalStateIterator
304: .next();
305:
306: // we need to test for the type because a non struts-use-case final state might accidently
307: // we linking to this use-case (for example: the user temporarily wants to disable code generation
308: // for a specific use-case and is not removing the final-state to use-case link(s))
309: if (finalStateObject instanceof FrontEndFinalState) {
310: final FrontEndFinalState finalState = (FrontEndFinalState) finalStateObject;
311: final Collection parameters = finalState
312: .getInterUseCaseParameters();
313: for (final Iterator parameterIterator = parameters
314: .iterator(); parameterIterator
315: .hasNext();) {
316: final ParameterFacade parameter = (ParameterFacade) parameterIterator
317: .next();
318: formFieldMap.put(parameter.getName(),
319: parameter);
320: }
321: }
322: }
323: }
324: }
325:
326: // if any action encountered by the execution of the complete action-graph path emits a forward
327: // containing one or more parameters they need to be included as a form field too
328: final Collection actionStates = this .getActionStates();
329: for (final Iterator iterator = actionStates.iterator(); iterator
330: .hasNext();) {
331: final FrontEndActionState actionState = (FrontEndActionState) iterator
332: .next();
333: final FrontEndForward forward = actionState.getForward();
334: if (forward != null) {
335: final Collection forwardParameters = forward
336: .getForwardParameters();
337: for (final Iterator parameterIterator = forwardParameters
338: .iterator(); parameterIterator.hasNext();) {
339: final ModelElementFacade forwardParameter = (ModelElementFacade) parameterIterator
340: .next();
341: formFieldMap.put(forwardParameter.getName(),
342: forwardParameter);
343: }
344: }
345: }
346:
347: // add page variables for all pages/final-states targetted
348: // also add the fields of the target page's actions (for preloading)
349: final Collection forwards = this .getActionForwards();
350: for (final Iterator iterator = forwards.iterator(); iterator
351: .hasNext();) {
352: final FrontEndForward forward = (FrontEndForward) iterator
353: .next();
354: final StateVertexFacade target = forward.getTarget();
355: if (target instanceof FrontEndView) {
356: final FrontEndView view = (FrontEndView) target;
357: final Collection viewVariables = view.getVariables();
358: for (final Iterator pageVariableIterator = viewVariables
359: .iterator(); pageVariableIterator.hasNext();) {
360: final ModelElementFacade facade = (ModelElementFacade) pageVariableIterator
361: .next();
362: formFieldMap.put(facade.getName(), facade);
363: }
364: final Collection allActionParameters = view
365: .getAllFormFields();
366: for (final Iterator actionParameterIterator = allActionParameters
367: .iterator(); actionParameterIterator.hasNext();) {
368: // - don't allow existing parameters that are tables be overwritten (since they take
369: // precedence
370: final Object parameter = actionParameterIterator
371: .next();
372: if (parameter instanceof FrontEndParameter) {
373: FrontEndParameter variable = (FrontEndParameter) parameter;
374: final String name = variable.getName();
375: final Object existingParameter = formFieldMap
376: .get(name);
377: if (existingParameter instanceof FrontEndParameter) {
378: final FrontEndParameter existingVariable = (FrontEndParameter) existingParameter;
379: if (existingVariable != null) {
380: if (existingVariable.isTable()) {
381: variable = existingVariable;
382: }
383: }
384: }
385: formFieldMap.put(name, variable);
386: }
387: }
388: } else if (target instanceof FrontEndFinalState) {
389: // only add these if there is no parameter recorded yet with the same name
390: final Collection forwardParameters = forward
391: .getForwardParameters();
392: for (final Iterator parameterIterator = forwardParameters
393: .iterator(); parameterIterator.hasNext();) {
394: final ModelElementFacade facade = (ModelElementFacade) parameterIterator
395: .next();
396: if (!formFieldMap.containsKey(facade.getName())) {
397: formFieldMap.put(facade.getName(), facade);
398: }
399: }
400: }
401: }
402:
403: // we do the action parameters in the end because they are allowed to overwrite existing properties
404: final Collection actionParameters = this .getParameters();
405: for (final Iterator parameterIterator = actionParameters
406: .iterator(); parameterIterator.hasNext();) {
407: final Object parameter = parameterIterator.next();
408: if (parameter instanceof FrontEndParameter) {
409: final FrontEndParameter variable = (FrontEndParameter) parameter;
410: formFieldMap.put(variable.getName(), variable);
411: }
412: }
413:
414: // - if we don't have any fields defined on this action and there are no action forwards,
415: // take the parameters from the deferred operations (since we would want to stay on the same view)
416: if (formFieldMap.isEmpty()
417: && this .getActionForwards().isEmpty()) {
418: for (final Iterator iterator = this .getDeferredOperations()
419: .iterator(); iterator.hasNext();) {
420: final OperationFacade operation = (OperationFacade) iterator
421: .next();
422: for (final Iterator parameterIterator = operation
423: .getArguments().iterator(); parameterIterator
424: .hasNext();) {
425: final ParameterFacade parameter = (ParameterFacade) parameterIterator
426: .next();
427: formFieldMap.put(parameter.getName(), parameter);
428: }
429: }
430: }
431: return new ArrayList(formFieldMap.values());
432: }
433: }
|