1 | package de.uka.ipd.sdq.pcmsolver.handler; |
2 | |
3 | import java.util.List; |
4 | |
5 | import org.apache.log4j.Logger; |
6 | import org.eclipse.emf.common.util.EList; |
7 | |
8 | import de.uka.ipd.sdq.context.computed_allocation.ComputedAllocationContext; |
9 | import de.uka.ipd.sdq.context.computed_allocation.ComputedAllocationFactory; |
10 | import de.uka.ipd.sdq.context.computed_usage.ComputedUsageContext; |
11 | import de.uka.ipd.sdq.context.computed_usage.ComputedUsageFactory; |
12 | import de.uka.ipd.sdq.context.computed_usage.ExternalCallOutput; |
13 | import de.uka.ipd.sdq.context.computed_usage.Input; |
14 | import de.uka.ipd.sdq.pcm.core.CoreFactory; |
15 | import de.uka.ipd.sdq.pcm.core.PCMRandomVariable; |
16 | import de.uka.ipd.sdq.pcm.parameter.VariableUsage; |
17 | import de.uka.ipd.sdq.pcm.qosannotations.QoSAnnotations; |
18 | import de.uka.ipd.sdq.pcm.qosannotations.SpecifiedQoSAnnotation; |
19 | import de.uka.ipd.sdq.pcm.qosannotations.qos_performance.SpecifiedExecutionTime; |
20 | import de.uka.ipd.sdq.pcm.repository.Interface; |
21 | import de.uka.ipd.sdq.pcm.repository.OperationRequiredRole; |
22 | import de.uka.ipd.sdq.pcm.repository.Role; |
23 | import de.uka.ipd.sdq.pcm.repository.Signature; |
24 | import de.uka.ipd.sdq.pcm.resourceenvironment.ProcessingResourceSpecification; |
25 | import de.uka.ipd.sdq.pcm.resourceenvironment.ResourceContainer; |
26 | import de.uka.ipd.sdq.pcm.resourceenvironment.ResourceenvironmentFactory; |
27 | import de.uka.ipd.sdq.pcm.resourceenvironment.SchedulingPolicy; |
28 | import de.uka.ipd.sdq.pcm.resourcetype.ProcessingResourceType; |
29 | import de.uka.ipd.sdq.pcm.resourcetype.ResourcetypeFactory; |
30 | import de.uka.ipd.sdq.pcm.seff.ExternalCallAction; |
31 | import de.uka.ipd.sdq.pcm.seff.InternalAction; |
32 | import de.uka.ipd.sdq.pcm.seff.ResourceDemandingBehaviour; |
33 | import de.uka.ipd.sdq.pcm.seff.SeffFactory; |
34 | import de.uka.ipd.sdq.pcm.seff.ServiceEffectSpecification; |
35 | import de.uka.ipd.sdq.pcm.seff.seff_performance.ParametricResourceDemand; |
36 | import de.uka.ipd.sdq.pcm.seff.seff_performance.Seff_performanceFactory; |
37 | import de.uka.ipd.sdq.pcmsolver.transformations.ContextWrapper; |
38 | import de.uka.ipd.sdq.pcmsolver.visitors.SeffVisitor; |
39 | import de.uka.ipd.sdq.pcmsolver.visitors.VariableUsageHelper; |
40 | |
41 | public class ExternalCallActionHandler { |
42 | |
43 | private SeffVisitor visitor; |
44 | |
45 | private ComputedUsageFactory compUsageFactory = ComputedUsageFactory.eINSTANCE; |
46 | |
47 | private ComputedAllocationFactory compAllocationFactory = ComputedAllocationFactory.eINSTANCE; |
48 | |
49 | private SeffFactory seffFactory = SeffFactory.eINSTANCE; |
50 | |
51 | private Seff_performanceFactory performanceFactory = Seff_performanceFactory.eINSTANCE; |
52 | |
53 | private static Logger logger = Logger.getLogger(ExternalCallActionHandler.class.getName()); |
54 | |
55 | public ExternalCallActionHandler(SeffVisitor seffVisitor){ |
56 | visitor=seffVisitor; |
57 | } |
58 | |
59 | /** |
60 | * @param call |
61 | */ |
62 | public void handle(ExternalCallAction call) { |
63 | |
64 | Signature serviceToBeCalled = call.getCalledService_ExternalService(); |
65 | ServiceEffectSpecification seff = visitor.getContextWrapper().getNextSEFF(call); |
66 | |
67 | if (seff == null){ |
68 | logger.debug("I found no SEFF for service "+serviceToBeCalled.getEntityName() + " called by External Call "+ call.getId() + " thus I assume a System External Call"); |
69 | String timeSpecification = getTimeSpecification(serviceToBeCalled); |
70 | createInternalAction(timeSpecification, call); |
71 | } else { |
72 | //logger.debug("Found Assembly Connector"); |
73 | |
74 | /* FIXME: This method has to clone the ContextWrapper twice. |
75 | * This should be avoidable, but it is totally unclear when the ContextWrapper is modified |
76 | * For example, some constructors modify the passed ContextWrapper |
77 | * */ |
78 | ContextWrapper oldContextWrapper = (ContextWrapper)visitor.getContextWrapper().clone(); |
79 | List<ContextWrapper> contextWrapperList = visitor.getContextWrapper().getContextWrapperFor(call); |
80 | SeffVisitor seffVisitor = null; |
81 | for (ContextWrapper contextWrapper : contextWrapperList) { |
82 | seffVisitor = visitSEFF(seff, contextWrapper); |
83 | } |
84 | // because AllocationContexts do not have Parameters, the parameters of the output will be the same for all component instances. |
85 | // Note that this would be not true anymore if 1:n connectors are introduced on the system level. Then, |
86 | // another parameter handling mechanism has to be used here. |
87 | if (seffVisitor != null){ |
88 | visitor.setContextWrapper((ContextWrapper)oldContextWrapper.clone()); |
89 | storeOutputParametersToUsageContext(call, seffVisitor); |
90 | } else { |
91 | throw new RuntimeException("Internal Error: No ContextWrapper could be created for ExternalCall "+call.getEntityName()+ " "+ call.getId()); |
92 | } |
93 | |
94 | visitor.setContextWrapper(oldContextWrapper); |
95 | } |
96 | } |
97 | |
98 | /** |
99 | * Default, but can be overwritten by subclasses to call other SEFF visitors |
100 | * @param seff |
101 | * @param contextWrapper |
102 | * @return |
103 | */ |
104 | SeffVisitor visitSEFF(ServiceEffectSpecification seff, |
105 | ContextWrapper contextWrapper) { |
106 | SeffVisitor seffVisitor = new SeffVisitor(contextWrapper); |
107 | seffVisitor.doSwitch(seff); |
108 | return seffVisitor; |
109 | } |
110 | |
111 | private void createInternalAction(String timeSpecification, ExternalCallAction call) { |
112 | PCMRandomVariable rv= CoreFactory.eINSTANCE.createPCMRandomVariable(); |
113 | rv.setSpecification(timeSpecification); |
114 | |
115 | ParametricResourceDemand demand = performanceFactory.createParametricResourceDemand(); |
116 | |
117 | demand.setSpecification_ParametericResourceDemand(rv); |
118 | demand.setRequiredResource_ParametricResourceDemand(getProcessingResourceType()); |
119 | |
120 | InternalAction action = seffFactory.createInternalAction(); |
121 | action.getResourceDemand_Action().add(demand); |
122 | |
123 | // Add new internal action into control flow after external action |
124 | action.setSuccessor_AbstractAction(call.getSuccessor_AbstractAction()); |
125 | action.setPredecessor_AbstractAction(call); |
126 | |
127 | ResourceDemandingBehaviour rdb = (ResourceDemandingBehaviour)call.eContainer(); |
128 | rdb.getSteps_Behaviour().add(action); |
129 | } |
130 | |
131 | private ProcessingResourceType getProcessingResourceType() { |
132 | EList<ResourceContainer> resConList = visitor.getContextWrapper().getPcmInstance().getResourceEnvironment().getResourceContainer_ResourceEnvironment(); |
133 | for (ResourceContainer resCon : resConList){ |
134 | if (resCon.getEntityName().equals("SystemExternalResourceContainer")){ |
135 | return resCon.getActiveResourceSpecifications_ResourceContainer().get(0).getActiveResourceType_ActiveResourceSpecification(); |
136 | } |
137 | } |
138 | return createNewProcessingResourceType(); |
139 | } |
140 | |
141 | private ProcessingResourceType createNewProcessingResourceType() { |
142 | ProcessingResourceType resType = ResourcetypeFactory.eINSTANCE.createProcessingResourceType(); |
143 | resType.setEntityName("SystemExternalResource"); |
144 | visitor.getContextWrapper().getPcmInstance().getResourceRepository().getAvailableResourceTypes_ResourceRepository().add(resType); |
145 | |
146 | ProcessingResourceSpecification res = ResourceenvironmentFactory.eINSTANCE.createProcessingResourceSpecification(); |
147 | res.setActiveResourceType_ActiveResourceSpecification(resType); |
148 | |
149 | PCMRandomVariable rv = CoreFactory.eINSTANCE.createPCMRandomVariable(); |
150 | rv.setSpecification("1.0"); |
151 | |
152 | res.setProcessingRate_ProcessingResourceSpecification(rv); |
153 | res.setSchedulingPolicy(SchedulingPolicy.PROCESSOR_SHARING); |
154 | |
155 | ResourceContainer resCon = ResourceenvironmentFactory.eINSTANCE.createResourceContainer(); |
156 | resCon.setEntityName("SystemExternalResourceContainer"); |
157 | resCon.getActiveResourceSpecifications_ResourceContainer().add(res); |
158 | visitor.getContextWrapper().getPcmInstance().getResourceEnvironment().getResourceContainer_ResourceEnvironment().add(resCon); |
159 | |
160 | return resType; |
161 | } |
162 | |
163 | private String getTimeSpecification(Signature serviceToBeCalled) { |
164 | Interface requiredInterface = (Interface) serviceToBeCalled.eContainer(); |
165 | String reqName = requiredInterface.getEntityName(); |
166 | |
167 | EList<QoSAnnotations> annList = visitor.getContextWrapper().getPcmInstance().getSystem().getQosAnnotations_System(); |
168 | for (QoSAnnotations ann : annList){ |
169 | EList<SpecifiedQoSAnnotation> timeList = ann.getSpecifiedQoSAnnotations_QoSAnnotations(); |
170 | for (SpecifiedQoSAnnotation annotation : timeList){ |
171 | if(!(annotation instanceof SpecifiedExecutionTime)){ |
172 | continue; |
173 | } |
174 | SpecifiedExecutionTime time = (SpecifiedExecutionTime)annotation; |
175 | Role role = time.getRole_SpecifiedQoSAnnotation(); |
176 | |
177 | // TODO: I had to change RequiredRole to OperationRequiredRole for the code to compile. |
178 | // Check if this still works! FB, 13-06-2010 |
179 | if (role instanceof OperationRequiredRole){ |
180 | OperationRequiredRole reqRole = (OperationRequiredRole)role; |
181 | String reqIntName = reqRole.getRequiredInterface__OperationRequiredRole().getEntityName(); |
182 | if (reqName.equals(reqIntName)){ |
183 | String serviceName = time.getSignature_SpecifiedQoSAnnation().getEntityName(); |
184 | if (serviceToBeCalled.getEntityName().equals(serviceName)){ |
185 | return time.getSpecification_SpecifiedExecutionTime().getSpecification(); |
186 | } |
187 | } |
188 | } |
189 | |
190 | } |
191 | } |
192 | logger.warn("No time specification was found for external call "+serviceToBeCalled.getEntityName()+". I'm assuming a demand of 0."); |
193 | return "0"; |
194 | } |
195 | |
196 | /** |
197 | * FIXME: This modifies the visitor.getContextWrapper() because a modifying constructor is called! |
198 | * @param call |
199 | * @param nextVisitor |
200 | */ |
201 | private void storeOutputParametersToUsageContext(ExternalCallAction call, SeffVisitor nextVisitor) { |
202 | String returnName = call.getCalledService_ExternalService().getEntityName() + ".RETURN"; |
203 | |
204 | ExternalCallOutput eco = compUsageFactory.createExternalCallOutput(); |
205 | eco.setExternalCallAction_ExternalCallOutput(call); |
206 | visitor.getContextWrapper().getCompUsgCtx().getExternalCallOutput_ComputedUsageContext().add(eco); |
207 | |
208 | if (nextVisitor.getContextWrapper().getCompUsgCtx() |
209 | .getOutput_ComputedUsageContext() != null) { |
210 | EList<VariableUsage> outputParamsProducedByExtCall = nextVisitor |
211 | .getContextWrapper().getCompUsgCtx() |
212 | .getOutput_ComputedUsageContext() |
213 | .getParameterCharacterisations_Output(); |
214 | |
215 | ComputedUsageContext dummyContext = compUsageFactory |
216 | .createComputedUsageContext(); |
217 | Input input = compUsageFactory.createInput(); |
218 | for (VariableUsage vu : outputParamsProducedByExtCall) { |
219 | VariableUsageHelper.copyVariableUsageToInput(input, vu); |
220 | } |
221 | dummyContext.setInput_ComputedUsageContext(input); |
222 | |
223 | ComputedAllocationContext dummyAllContext = compAllocationFactory |
224 | .createComputedAllocationContext(); |
225 | |
226 | ContextWrapper dummyWrapper = ContextWrapper.getContextWrapperFor(call, |
227 | dummyContext, dummyAllContext, visitor.getContextWrapper()).get(0); |
228 | |
229 | EList<VariableUsage> outputParamsDeclaredInSeff = call |
230 | .getReturnVariableUsage__CallReturnAction(); |
231 | for (VariableUsage vu : outputParamsDeclaredInSeff) { |
232 | VariableUsageHelper |
233 | .copySolvedVariableUsageToExternalCallOutput( |
234 | dummyWrapper, eco, vu); |
235 | } |
236 | } |
237 | } |
238 | } |