This is an automated email from the ASF dual-hosted git repository. ningjiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/servicecomb-pack.git
commit d40844cef020a9aab65f513469350394fe2eafd7 Author: Lei Zhang <[email protected]> AuthorDate: Wed Aug 7 15:38:49 2019 +0800 SCB-1411 Implement transaction query list and detail page --- alpha/alpha-ui/pom.xml | 7 + .../servicecomb/pack/alpha/ui/IndexController.java | 4 +- .../pack/alpha/ui/TransactionController.java | 161 +++++++++++++++------ .../pack/alpha/ui/UIAutoConfiguration.java | 6 + .../pack/alpha/ui/vo/DataTablesRequestDTO.java | 9 ++ .../pack/alpha/ui/vo/DataTablesResponseDTO.java | 16 +- .../servicecomb/pack/alpha/ui/vo/EventDTO.java | 16 ++ .../main/resources/static/js/alpha-transaction.js | 8 +- .../main/resources/templates/fragments/header.html | 4 +- .../src/main/resources/templates/search.html | 4 +- 10 files changed, 172 insertions(+), 63 deletions(-) diff --git a/alpha/alpha-ui/pom.xml b/alpha/alpha-ui/pom.xml index 7458dc2..85457f2 100644 --- a/alpha/alpha-ui/pom.xml +++ b/alpha/alpha-ui/pom.xml @@ -47,6 +47,13 @@ </dependencyManagement> <dependencies> + + <!-- servicecomb pack --> + <dependency> + <groupId>org.apache.servicecomb.pack</groupId> + <artifactId>alpha-core</artifactId> + </dependency> + <!-- webjars --> <dependency> <groupId>org.webjars</groupId> diff --git a/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/IndexController.java b/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/IndexController.java index d293711..21daa9d 100644 --- a/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/IndexController.java +++ b/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/IndexController.java @@ -43,8 +43,8 @@ public class IndexController implements ErrorController { } @GetMapping("/ui/search") - public String searchIndex(ModelMap map, @RequestParam(name = "q") String q) { - map.put("q", q); + public String searchIndex(ModelMap map, @RequestParam(name = "globalTxId") String globalTxId) { + map.put("globalTxId", globalTxId); return "search"; } diff --git a/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/TransactionController.java b/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/TransactionController.java index 79be53c..10ab5a3 100644 --- a/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/TransactionController.java +++ b/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/TransactionController.java @@ -20,50 +20,71 @@ package org.apache.servicecomb.pack.alpha.ui; import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.UUID; -import javax.websocket.server.PathParam; +import javax.servlet.http.HttpServletRequest; +import org.apache.servicecomb.pack.alpha.core.fsm.repository.model.GlobalTransaction; +import org.apache.servicecomb.pack.alpha.core.fsm.repository.model.PagingGlobalTransactions; import org.apache.servicecomb.pack.alpha.ui.vo.DataTablesRequestDTO; import org.apache.servicecomb.pack.alpha.ui.vo.DataTablesResponseDTO; import org.apache.servicecomb.pack.alpha.ui.vo.EventDTO; import org.apache.servicecomb.pack.alpha.ui.vo.SubTransactionDTO; import org.apache.servicecomb.pack.alpha.ui.vo.TransactionRowDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.context.WebServerInitializedEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; @Controller -public class TransactionController { +public class TransactionController implements ApplicationListener<WebServerInitializedEvent> { + + @Autowired + RestTemplate restTemplate; + + int serverPort; @PostMapping("/ui/transaction/sagalist") @ResponseBody - public DataTablesResponseDTO sagaList(@ModelAttribute DataTablesRequestDTO dataTablesRequestDTO) { + public DataTablesResponseDTO sagaList(@ModelAttribute DataTablesRequestDTO dataTablesRequestDTO, + HttpServletRequest request) { + UriComponents uriComponents = UriComponentsBuilder + .fromUriString("http://localhost:" + serverPort + "/alpha/api/v1/transaction") + .queryParam("page", dataTablesRequestDTO.getStart()/dataTablesRequestDTO.getLength()) + .queryParam("size", dataTablesRequestDTO.getLength()) + .build(); List<TransactionRowDTO> data = new ArrayList<>(); - for (int i = 0; i < dataTablesRequestDTO.getLength()-2; i++) { - data.add(TransactionRowDTO.builder().serviceName("Booking").instanceId("booking-1") - .globalTxId("xxxx-xxx-xxx").state("COMMITTED").beginTime(new Date()).endTime(new Date()) - .subTxSize(3).durationTime(109).build()); - } - for (int i = 0; i < 1; i++) { - data.add(TransactionRowDTO.builder().serviceName("Booking").instanceId("booking-1") - .globalTxId("xxxx-xxx-xxx").state("SUSPENDED").beginTime(new Date()).endTime(new Date()) - .subTxSize(3).durationTime(109).build()); - } - for (int i = 0; i < 1; i++) { - data.add(TransactionRowDTO.builder().serviceName("Booking").instanceId("booking-1") - .globalTxId("xxxx-xxx-xxx").state("COMPENSATED").beginTime(new Date()).endTime(new Date()) - .subTxSize(3).durationTime(109).build()); - } + ResponseEntity<PagingGlobalTransactions> entity = restTemplate + .getForEntity(uriComponents.toUriString(), PagingGlobalTransactions.class); + PagingGlobalTransactions pagingGlobalTransactions = entity.getBody(); + pagingGlobalTransactions.getGlobalTransactions().forEach(globalTransaction -> { + data.add(TransactionRowDTO.builder() + .serviceName(globalTransaction.getServiceName()) + .instanceId(globalTransaction.getInstanceId()) + .globalTxId(globalTransaction.getGlobalTxId()) + .state(globalTransaction.getState()) + .beginTime(globalTransaction.getBeginTime()) + .endTime(globalTransaction.getEndTime()) + .subTxSize(globalTransaction.getSubTxSize()) + .durationTime(globalTransaction.getDurationTime()) + .build()); + }); return DataTablesResponseDTO.builder() .draw(dataTablesRequestDTO.getDraw()) - .recordsTotal(100) - .recordsFiltered(100) + .recordsTotal(pagingGlobalTransactions.getTotal()) + .recordsFiltered(pagingGlobalTransactions.getTotal()) .data(data) .build(); } + // TODO The state machine is not yet supported @PostMapping("/ui/transaction/tcclist") @ResponseBody public DataTablesResponseDTO tccList(@ModelAttribute DataTablesRequestDTO dataTablesRequestDTO) { @@ -78,11 +99,22 @@ public class TransactionController { @PostMapping("/ui/transaction/search") @ResponseBody - public DataTablesResponseDTO searchList(@ModelAttribute DataTablesRequestDTO dataTablesRequestDTO) { + public DataTablesResponseDTO searchList( + @ModelAttribute DataTablesRequestDTO dataTablesRequestDTO) { List<TransactionRowDTO> data = new ArrayList<>(); - data.add(TransactionRowDTO.builder().serviceName("Booking").instanceId("booking-1") - .globalTxId("xxxx-xxx-xxx").state("SUSPENDED").beginTime(new Date()).endTime(new Date()) - .subTxSize(3).durationTime(109).build()); + GlobalTransaction globalTransaction = findGlobalTransactionByGlobalTxId(dataTablesRequestDTO.getQuery()); + if (globalTransaction != null) { + data.add(TransactionRowDTO.builder() + .serviceName(globalTransaction.getServiceName()) + .instanceId(globalTransaction.getInstanceId()) + .globalTxId(globalTransaction.getGlobalTxId()) + .state(globalTransaction.getState()) + .beginTime(globalTransaction.getBeginTime()) + .endTime(globalTransaction.getEndTime()) + .subTxSize(globalTransaction.getSubTxSize()) + .durationTime(globalTransaction.getDurationTime()) + .build()); + } return DataTablesResponseDTO.builder() .draw(dataTablesRequestDTO.getDraw()) .recordsTotal(1) @@ -92,33 +124,66 @@ public class TransactionController { } @GetMapping("/ui/transaction/{globalTxId}") - public String searchList(ModelMap map, @PathParam("globalTxId") String globalTxId) { + public String getGlobalTransaction(ModelMap map, @PathVariable("globalTxId") String globalTxId) { List<EventDTO> events = new ArrayList<>(); List<SubTransactionDTO> subTransactions = new ArrayList<>(); + GlobalTransaction globalTransaction = findGlobalTransactionByGlobalTxId(globalTxId); + globalTransaction.getEvents().forEach(event -> { + EventDTO eventDTO = EventDTO.builder() + // Common Event properties + .type(event.get("type").toString()) + .serviceName(event.get("serviceName").toString()) + .instanceId(event.get("instanceId").toString()) + .globalTxId(event.get("globalTxId").toString()) + .parentTxId(event.get("parentTxId").toString()) + .localTxId(event.get("localTxId").toString()) + .createTime(new Date(Long.valueOf(event.get("createTime").toString()))) + .build(); + if(eventDTO.getType().equals("TxStartedEvent")){ + // TxStartedEvent properties + if(event.containsKey("compensationMethod")){ + eventDTO.setCompensationMethod(event.get("compensationMethod").toString()); + } + if(event.containsKey("retries")){ + eventDTO.setRetries(Long.valueOf(event.get("retries").toString())); + } + if(event.containsKey("timeout")){ + eventDTO.setTimeout(Long.valueOf(event.get("timeout").toString())); + } + } + if(eventDTO.getType().equals("TxAbortedEvent")){ + // TxAbortedEvent properties + if(event.containsKey("payloads")){ + eventDTO.setException(event.get("payloads").toString()); + } + } + events.add(eventDTO); + }); - globalTxId = UUID.randomUUID().toString(); - String localTxId_1 = UUID.randomUUID().toString(); - String localTxId_2 = UUID.randomUUID().toString(); - String localTxId_3 = UUID.randomUUID().toString(); - events.add(EventDTO.builder().type("SagaStartedEvent").serviceName("Booking").globalTxId(globalTxId).instanceId("booking-1").createTime(new Date()).localTxId(globalTxId).parentTxId(globalTxId).timeout(60000).build()); - events.add(EventDTO.builder().type("TxStartedEvent").serviceName("Car").globalTxId(globalTxId).instanceId("car-1").createTime(new Date()).localTxId(localTxId_1).parentTxId(globalTxId).retries(3).compensationMethod("org.servicecomb.sample.car.CarService.cannelOrder()").build()); - events.add(EventDTO.builder().type("TxEndedEvent").serviceName("Car").globalTxId(globalTxId).instanceId("car-1").createTime(new Date()).localTxId(localTxId_1).parentTxId(globalTxId).build()); - events.add(EventDTO.builder().type("TxStartedEvent").serviceName("Hotel").globalTxId(globalTxId).instanceId("hotel-1").createTime(new Date()).localTxId(localTxId_2).parentTxId(globalTxId).retries(3).compensationMethod("org.servicecomb.sample.hotel.HotelService.cannelOrder()").build()); - events.add(EventDTO.builder().type("TxEndedEvent").serviceName("Hotel").globalTxId(globalTxId).instanceId("hotel-1").createTime(new Date()).localTxId(localTxId_2).parentTxId(globalTxId).build()); - events.add(EventDTO.builder().type("TxStartedEvent").serviceName("Flight").globalTxId(globalTxId).instanceId("flight-1").createTime(new Date()).localTxId(localTxId_3).parentTxId(globalTxId).retries(2).compensationMethod("org.servicecomb.sample.flight.FlightService.cannelOrder()").build()); - events.add(EventDTO.builder().type("TxEndedEvent").serviceName("Flight").globalTxId(globalTxId).instanceId("flight-1").createTime(new Date()).localTxId(localTxId_3).parentTxId(globalTxId).build()); - events.add(EventDTO.builder().type("TxAbortedEvent").serviceName("Flight").globalTxId(globalTxId).instanceId("flight-1").createTime(new Date()).localTxId(localTxId_3).parentTxId(globalTxId).exception("java.lang.NullPointerException\n" - + "at TestCompile.work(TestCompile.java:25)\n" - + "at TestCompile.main(TestCompile.java:17)").build()); - events.add(EventDTO.builder().type("SagaEndedEvent").serviceName("Booking").globalTxId(globalTxId).instanceId("booking-1").createTime(new Date()).localTxId(globalTxId).parentTxId(globalTxId).build()); - - subTransactions.add(SubTransactionDTO.builder().parentTxId(globalTxId).localTxId(localTxId_1).beginTime(new Date()).endTime(new Date()).durationTime(10).state("COMMITTED").build()); - subTransactions.add(SubTransactionDTO.builder().parentTxId(globalTxId).localTxId(localTxId_2).beginTime(new Date()).endTime(new Date()).durationTime(10).state("COMMITTED").build()); - subTransactions.add(SubTransactionDTO.builder().parentTxId(globalTxId).localTxId(localTxId_3).beginTime(new Date()).endTime(new Date()).durationTime(10).state("COMMITTED").build()); - map.put("events",events); - map.put("globalTxId",globalTxId); - map.put("subTransactions",subTransactions); + globalTransaction.getSubTransactions().forEach( sub -> { + subTransactions.add( + SubTransactionDTO.builder().parentTxId(globalTxId).localTxId(sub.getLocalTxId()) + .beginTime(sub.getBeginTime()).endTime(sub.getEndTime()) + .durationTime(sub.getDurationTime()).state(sub.getState().name()).build()); + }); + map.put("events", events); + map.put("globalTxId", globalTransaction.getGlobalTxId()); + map.put("subTransactions", subTransactions); return "transaction_details"; } + private GlobalTransaction findGlobalTransactionByGlobalTxId(String globalTxId){ + UriComponents uriComponents = UriComponentsBuilder + .fromUriString("http://localhost:" + serverPort + "/alpha/api/v1/transaction/"+globalTxId) + .build(); + ResponseEntity<GlobalTransaction> entity = restTemplate + .getForEntity(uriComponents.toUriString(), GlobalTransaction.class); + GlobalTransaction globalTransaction = entity.getBody(); + return globalTransaction; + } + + @Override + public void onApplicationEvent(WebServerInitializedEvent webServerInitializedEvent) { + serverPort = webServerInitializedEvent.getWebServer().getPort(); + } } diff --git a/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/UIAutoConfiguration.java b/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/UIAutoConfiguration.java index b385762..38d0166 100644 --- a/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/UIAutoConfiguration.java +++ b/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/UIAutoConfiguration.java @@ -18,12 +18,18 @@ package org.apache.servicecomb.pack.alpha.ui; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.web.client.RestTemplate; @Configuration @ConditionalOnProperty(value = {"alpha.feature.akka.enabled"}) @Import({IndexController.class,TransactionController.class}) public class UIAutoConfiguration { + @Bean + public RestTemplate restTemplate(){ + return new RestTemplate(); + } } diff --git a/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/vo/DataTablesRequestDTO.java b/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/vo/DataTablesRequestDTO.java index 5f7c7d9..0048f57 100644 --- a/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/vo/DataTablesRequestDTO.java +++ b/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/vo/DataTablesRequestDTO.java @@ -27,6 +27,7 @@ public class DataTablesRequestDTO { private List<HashMap<String, String>> order; private int start; private int length; + private String query; public int getDraw() { return draw; @@ -67,4 +68,12 @@ public class DataTablesRequestDTO { public void setLength(int length) { this.length = length; } + + public String getQuery() { + return query; + } + + public void setQuery(String query) { + this.query = query; + } } diff --git a/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/vo/DataTablesResponseDTO.java b/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/vo/DataTablesResponseDTO.java index 85d5629..7978fba 100644 --- a/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/vo/DataTablesResponseDTO.java +++ b/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/vo/DataTablesResponseDTO.java @@ -22,19 +22,19 @@ import java.util.List; public class DataTablesResponseDTO { private int draw; - private int recordsTotal; - private int recordsFiltered; + private long recordsTotal; + private long recordsFiltered; private List<TransactionRowDTO> data = new ArrayList<>(); public int getDraw() { return draw; } - public int getRecordsTotal() { + public long getRecordsTotal() { return recordsTotal; } - public int getRecordsFiltered() { + public long getRecordsFiltered() { return recordsFiltered; } @@ -49,8 +49,8 @@ public class DataTablesResponseDTO { public static final class Builder { private int draw; - private int recordsTotal; - private int recordsFiltered; + private long recordsTotal; + private long recordsFiltered; private List<TransactionRowDTO> data = new ArrayList<>(); private Builder() { @@ -61,12 +61,12 @@ public class DataTablesResponseDTO { return this; } - public Builder recordsTotal(int recordsTotal) { + public Builder recordsTotal(long recordsTotal) { this.recordsTotal = recordsTotal; return this; } - public Builder recordsFiltered(int recordsFiltered) { + public Builder recordsFiltered(long recordsFiltered) { this.recordsFiltered = recordsFiltered; return this; } diff --git a/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/vo/EventDTO.java b/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/vo/EventDTO.java index fb5738f..e3bfd65 100644 --- a/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/vo/EventDTO.java +++ b/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/vo/EventDTO.java @@ -76,6 +76,22 @@ public class EventDTO { return exception; } + public void setTimeout(long timeout) { + this.timeout = timeout; + } + + public void setRetries(long retries) { + this.retries = retries; + } + + public void setCompensationMethod(String compensationMethod) { + this.compensationMethod = compensationMethod; + } + + public void setException(String exception) { + this.exception = exception; + } + public static Builder builder() { return new Builder(); } diff --git a/alpha/alpha-ui/src/main/resources/static/js/alpha-transaction.js b/alpha/alpha-ui/src/main/resources/static/js/alpha-transaction.js index fb8ef44..47cbbaa 100644 --- a/alpha/alpha-ui/src/main/resources/static/js/alpha-transaction.js +++ b/alpha/alpha-ui/src/main/resources/static/js/alpha-transaction.js @@ -24,6 +24,12 @@ $(document).ready(function () { column.searchValue = column.search.value; delete(column.search); } + + // set query parameters + var queryValue = $('#transaction_config').attr('query'); + if (typeof queryValue !== typeof undefined && queryValue !== false) { + data.query = queryValue; + } } var transaction_table = $('#dataTable').DataTable({ @@ -83,7 +89,7 @@ $(document).ready(function () { $('#dataTable tbody').on("click","tr", function(_event){ var data = transaction_table.row( this ).data(); - window.location = "/ui/transaction/"+data.globalTxId + window.location.href = "/ui/transaction/"+data.globalTxId }); // table toolbar add state select & custom layout diff --git a/alpha/alpha-ui/src/main/resources/templates/fragments/header.html b/alpha/alpha-ui/src/main/resources/templates/fragments/header.html index 4604926..fc430a4 100644 --- a/alpha/alpha-ui/src/main/resources/templates/fragments/header.html +++ b/alpha/alpha-ui/src/main/resources/templates/fragments/header.html @@ -26,7 +26,7 @@ <!-- Topbar Search --> <form class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search" action="/ui/search"> <div class="input-group"> - <input type="text" name="q" class="form-control bg-light border-0 small" placeholder="Search for Global Transaction ID ..." aria-label="Search" aria-describedby="basic-addon2"> + <input type="text" name="globalTxId" class="form-control bg-light border-0 small" placeholder="Search for Global Transaction ID ..." aria-label="Search" aria-describedby="basic-addon2"> <div class="input-group-append"> <button class="btn btn-primary" type="button"> <i class="fas fa-search fa-sm"></i> @@ -47,7 +47,7 @@ <div class="dropdown-menu dropdown-menu-right p-3 shadow animated--grow-in" aria-labelledby="searchDropdown"> <form class="form-inline mr-auto w-100 navbar-search" action="/ui/search"> <div class="input-group"> - <input type="text" name="q" class="form-control bg-light border-0 small" placeholder="Search for Global Transaction ID ..." aria-label="Search" aria-describedby="basic-addon2"> + <input type="text" name="globalTxId" class="form-control bg-light border-0 small" placeholder="Search for Global Transaction ID ..." aria-label="Search" aria-describedby="basic-addon2"> <div class="input-group-append"> <button class="btn btn-primary" type="button"> <i class="fas fa-search fa-sm"></i> diff --git a/alpha/alpha-ui/src/main/resources/templates/search.html b/alpha/alpha-ui/src/main/resources/templates/search.html index 6a85394..8b9f805 100644 --- a/alpha/alpha-ui/src/main/resources/templates/search.html +++ b/alpha/alpha-ui/src/main/resources/templates/search.html @@ -24,9 +24,9 @@ <body> <div layout:fragment="content" class="container-fluid"> <!-- Page Heading --> - <h1 class="h3 mb-4 text-gray-800" th:text="'Search [' + ${q} + '] Result'">Search Result Transaction </h1> + <h1 class="h3 mb-4 text-gray-800" th:text="'Search [' + ${globalTxId} + '] Result'">Search Result Transaction </h1> <!-- Transaction Table --> - <div id="transaction_config" ajax="/ui/transaction/search"> + <div id="transaction_config" ajax="/ui/transaction/search" th:query="${globalTxId}"> <div th:replace="fragments/transaction_table :: transaction_table"></div> </div> </div>
