title: Grails: Getting the controller to do some parallel data processing and rendering the results iteratively
body: <p>I'm trying to get the controller to call a service method that does some data processing, then render the results, and then do it over and over again till no more data processing is required. The problem is that the controller keeps processing data without rendering the inbetween results. He just keeps on calling the index method (where both calculations and rendering methods are being called) without rendering anything.</p>
  
  <p>This is the index function:</p>
  
  <pre><code>def index() {
     def systemStatus = null
  
     ExecutorService executor = Executors.newSingleThreadExecutor()
  
     Future future = executor.submit(new Callable(){
        public Object call() throws Exception {
           println("calculations thread is: " + Thread.currentThread().id)
           def temp = systemStatusService.calculateSystemStatus()
           return temp
         }
     })
  
     systemStatus = future.get()
     executor.shutdown()
  
     Thread.currentThread().sleep((long)5000)
     if(systemStatus["additionalInfo"]["stillGotWorkToDo"]){
        renderSystemStatus(systemStatus)
        index()
     }
     else{
        render("No data to render!!")
     }
  }
  </code></pre>
  
  <p>I want to call the index() method again after the rendering has been done.</p>
  
  <p>I have tried using the executorService to parallely process data and do the redndering, but if i put the render function in the executor service i get an error.</p>
  
  <p>The methods look like this:</p>
  
  <p>calculateSystemStatus method in a separate service:</p>
  
  <pre><code>class SystemStatusService {
      def queueManagementService
  
      def calculateSystemStatus(){
          def stillGotWorkToDo = true
  
          def trackState = queueManagementService.getTrackState("taxi", Taxi.getAll()*.name)
          trackState &lt;&lt; queueManagementService.getTrackState("turnaround", Turnaround.getAll()*.name)
  
          stillGotWorkToDo = queueManagementService.manageMoveRequests()
  
          def obstructingTaxi = null
          def boardedTaxi = null
          def allocatedTaxiZone = null
          def turnaround = null
  
          def pendingMoveRequests = queueManagementService.getPendingMoveRequests()
          pendingMoveRequests.each{
              allocatedTaxiZone = queueManagementService.getZone(it.allocatedTaxi.position, it.allocatedTaxi.rail)
              it.currentTaxiZone = allocatedTaxiZone
  
              if(it.targetType == "taxi"){
                  obstructingTaxi = queueManagementService.findObstructingTaxi(it.allocatedTaxi.name, it.id)
                  it.obstructingTaxi = obstructingTaxi
              }
              else{
                  turnaround = Turnaround.findByName(it.targetName)
                  if(turnaround){
                      boardedTaxi = turnaround.boardedTaxi
                      it.boardedTaxi = boardedTaxi
                  }
              }
          }
  
          obstructingTaxi = null
          boardedTaxi = null
          allocatedTaxiZone = null
          turnaround = null
  
          def executingMoveRequests = queueManagementService.getExecutingMoveRequests()
          executingMoveRequests.each{
              allocatedTaxiZone = queueManagementService.getZone(it.allocatedTaxi.position, it.allocatedTaxi.rail)
              it.currentTaxiZone = allocatedTaxiZone
  
              if(it.targetType == "taxi"){
                  obstructingTaxi = queueManagementService.findObstructingTaxi(it.allocatedTaxi.name, it.id)
                  it.obstructingTaxi = obstructingTaxi
              }
              else{
                  turnaround = Turnaround.findByName(it.targetName)
                  if(turnaround){
                      boardedTaxi = turnaround.boardedTaxi
                      it.boardedTaxi = boardedTaxi
                  }
              }
          }
  
          def additionalInfo = [:]
          additionalInfo["stillGotWorkToDo"] = stillGotWorkToDo
          additionalInfo["pending"] = pendingMoveRequests
          additionalInfo["executing"] = executingMoveRequests
  
          return [trackState: trackState, additionalInfo: additionalInfo]
      }
  }
  </code></pre>
  
  <p>The render method:</p>
  
  <pre><code>def renderSystemStatus(def systemStatus){
      def trackState = systemStatus["trackState"]
      def pending = systemStatus["additionalInfo"]["pending"]
      def executing = systemStatus["additionalInfo"]["executing"]
      def obstructingTaxi = null
      def boardedTaxi = null
      def allocatedTaxiZone = null
  
      render("Track state: &lt;br/&gt;")
       trackState.each(){
           render("$it.key $it.value&lt;br/&gt;")
       }
  
       render("&lt;br/&gt;Pending move requests: &lt;br/&gt;")
       pending.each(){
           if(!it.isAttached()){
               it.attach()
           }
  
           if(it.targetType == "taxi"){
               allocatedTaxiZone = it.currentTaxiZone
               if(it.obstructingTaxi){
                   obstructingTaxi = it.obstructingTaxi
                   render("$it.allocatedTaxi.name on (current taxi zone: $allocatedTaxiZone.name, rail slot $it.allocatedTaxi.rail.slot) -&gt; $it.destinationZone.name ($it.destination, rail slot: $it.destinationZone.rail.slot) --------- ['$it.targetName' going to $it.microDestination] obstructed by ${obstructingTaxi.name} &lt;br/&gt;")
               }
               else{
                   render("$it.allocatedTaxi.name on (current taxi zone: $allocatedTaxiZone.name, rail slot $it.allocatedTaxi.rail.slot) -&gt; $it.destinationZone.name ($it.destination, rail slot: $it.destinationZone.rail.slot) --------- ['$it.targetName' going to $it.microDestination] &lt;br/&gt;")
               }
           }
           else{
               allocatedTaxiZone = it.currentTaxiZone
               if(it.boardedTaxi){
                   boardedTaxi = it.boardedTaxi
                   render("$it.allocatedTaxi.name on (current taxi zone: $allocatedTaxiZone.name, rail slot $it.allocatedTaxi.rail.slot) -&gt; $it.destinationZone.name ($it.destination, rail slot: $it.destinationZone.rail.slot) --------- ['$it.targetName' going to $it.microDestination], boarding taxi: ${boardedTaxi.name} &lt;br/&gt;")
               }
               else{
                   render("$it.allocatedTaxi.name on (current taxi zone: $allocatedTaxiZone.name, rail slot $it.allocatedTaxi.rail.slot) -&gt; $it.destinationZone.name ($it.destination, rail slot: $it.destinationZone.rail.slot) --------- ['$it.targetName' going to $it.microDestination] &lt;br/&gt;")
               }
           }
       }
  
       render("&lt;br/&gt; Executing move requests:  &lt;br/&gt;")
       executing.each(){
           if(!it.isAttached()){
               it.attach()
           }
  
           if(it.targetType == "taxi"){
               allocatedTaxiZone = it.currentTaxiZone
               if(it.obstructingTaxi){
                   obstructingTaxi = it.obstructingTaxi
                   render("$it.allocatedTaxi.name on (current taxi zone: $allocatedTaxiZone.name, rail slot $it.allocatedTaxi.rail.slot) -&gt; $it.destinationZone.name ($it.destination, rail slot: $it.destinationZone.rail.slot) --------- ['$it.targetName' going to $it.microDestination] obstructed by ${obstructingTaxi.name} &lt;br/&gt;")
               }
               else{
                   render("$it.allocatedTaxi.name on (current taxi zone: $allocatedTaxiZone.name, rail slot $it.allocatedTaxi.rail.slot) -&gt; $it.destinationZone.name ($it.destination, rail slot: $it.destinationZone.rail.slot) --------- ['$it.targetName' going to $it.microDestination] &lt;br/&gt;")
               }
           }
           else{
               allocatedTaxiZone = it.currentTaxiZone
               if(it.boardedTaxi){
                   boardedTaxi = it.boardedTaxi
                   render("$it.allocatedTaxi.name on (current taxi zone: $allocatedTaxiZone.name, rail slot $it.allocatedTaxi.rail.slot) -&gt; $it.destinationZone.name ($it.destination, rail slot: $it.destinationZone.rail.slot) --------- ['$it.targetName' going to $it.microDestination], boarding taxi: ${boardedTaxi.name} &lt;br/&gt;")
               }
               else{
                   render("$it.allocatedTaxi.name on (current taxi zone: $allocatedTaxiZone.name, rail slot $it.allocatedTaxi.rail.slot) -&gt; $it.destinationZone.name ($it.destination, rail slot: $it.destinationZone.rail.slot) --------- ['$it.targetName' going to $it.microDestination] &lt;br/&gt;")
               }
           }
       }
  }
  </code></pre>
  
  <p>How can i achieve to get the desired actions? First calculate, then render, if needed, again, and so forth.</p>