| 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 | } |