Skip to content

Commit

Permalink
added generated server
Browse files Browse the repository at this point in the history
  • Loading branch information
martin-kuba committed Jan 26, 2023
1 parent d792736 commit 9d62c13
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 6 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ This project demonstrates the following features:
* a multimodule Maven project
* parent project [chat-service-parent](pom.xml) and multiple modules:
* module [chat-server](chat-server/pom.xml) - executable server
* module [chat-client-java-lib](chat-client-java-lib/pom.xml) - Java library generated by OpenAPI Generator
* module [chat-client-java-lib](chat-client-java-lib/pom.xml) - Java client library generated by OpenAPI Generator "java"
* module [chat-client-java](chat-client-java/pom.xml) - executable client using the library
* module [chat-server-generated](chat-server-generated/pom.xml) - executable server generated by OpenAPI Generator "spring"
* module aggregation, where a command executed in the parent project gets executed also in all modules
* module inheritance, where the parent project inherits from `org.springframework.boot:spring-boot-starter-parent`
and each module inherits from the parent
Expand Down
120 changes: 120 additions & 0 deletions chat-server-generated/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cz.muni.chat</groupId>
<artifactId>chat-service-parent</artifactId>
<version>0.0.0-SNAPSHOT</version>
</parent>

<artifactId>chat-server-generated</artifactId>
<packaging>jar</packaging>
<name>Generated server</name>
<description>Server generated by OpenAPI Generator</description>

<build>
<defaultGoal>spring-boot:run</defaultGoal>
<!-- name of executable JAR file -->
<finalName>chat_server_generated</finalName>

<plugins>
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>6.2.1</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/../openapi.yaml</inputSpec>
<generatorName>spring</generatorName>
<apiPackage>cz.muni.chat.generated.server.api</apiPackage>
<modelPackage>cz.muni.chat.generated.server.model</modelPackage>
<!-- https://openapi-generator.tech/docs/generators/spring -->
<configOptions>
<basePackage>cz.muni.chat.generated.server</basePackage>
<configPackage>cz.muni.chat.generated.server.config</configPackage>
<useSpringBoot3>true</useSpringBoot3>
<useTags>true</useTags>
<delegatePattern>true</delegatePattern>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
<!-- create executable jar -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
<!-- run integration tests in "mvn verify" phase -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
</plugin>
</plugins>
</build>


<properties>
<jackson-databind-nullable-version>0.2.4</jackson-databind-nullable-version>
<swagger-jakarta-version>2.2.7</swagger-jakarta-version>
<javax-validation-api-version>2.0.1.Final</javax-validation-api-version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-models-jakarta</artifactId>
<version>${swagger-jakarta-version}</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations-jakarta</artifactId>
<version>${swagger-jakarta-version}</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>${jackson-databind-nullable-version}</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>${javax-validation-api-version}</version>
</dependency>

<!-- for pagination from JPA without actually using JPA -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package cz.muni.chat.generated.server.api;

import cz.muni.chat.generated.server.model.BackgroundColorEnum;
import cz.muni.chat.generated.server.model.ChatMessage;
import cz.muni.chat.generated.server.model.NewChatMessageRequest;
import cz.muni.chat.generated.server.model.NewChatMessageRequest.TextColorEnum;
import cz.muni.chat.generated.server.model.PageChatMessage;
import cz.muni.chat.generated.server.model.PageableObject;
import cz.muni.chat.generated.server.model.SortObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import java.time.OffsetDateTime;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;

/**
* Implementation of API methods for generated controller.
*/
@Component
public class ChatImpl implements ChatApiDelegate {

private static final Logger log = LoggerFactory.getLogger(ChatImpl.class);

@Override
public ResponseEntity<List<ChatMessage>> getAllMessages() {
log.debug("getAllMessages()");
return new ResponseEntity<>(messages, HttpStatus.OK);
}

@Override
public ResponseEntity<ChatMessage> getMessage(String id) {
log.debug("getMessage({})", id);
ChatMessage chatMessage = messages.stream().filter(x -> x.getId().equals(id)).findFirst().orElse(null);
return new ResponseEntity<>(chatMessage, chatMessage != null ? HttpStatus.OK : HttpStatus.NOT_FOUND);
}

@Override
public ResponseEntity<ChatMessage> createMessage(NewChatMessageRequest r, String author, String userAgent) {
log.debug("createMessage({},{},{})", r, author, userAgent);
String text = r.getText();
BackgroundColorEnum backgroundColor = r.getBackgroundColor();
TextColorEnum textColor = r.getTextColor();
ChatMessage chatMessage = new ChatMessage()
.id(UUID.randomUUID().toString())
.timestamp(OffsetDateTime.now())
.author(author)
.text(text)
.textColor(textColor.getValue())
.backgroundColor(backgroundColor);
messages.add(0, chatMessage);
return new ResponseEntity<>(chatMessage, HttpStatus.CREATED);
}

@Override
public ResponseEntity<PageChatMessage> paged(Integer page, Integer size, List<String> sort) {
log.debug("paged(page={}, size={}, sort={})", page, size, sort);
PageRequest p = PageRequest.of(page, size);
List<ChatMessage> chatMessages = messages.stream().skip(p.getOffset()).limit(p.getPageSize()).toList();
Page<ChatMessage> m = new PageImpl<>(chatMessages, p, messages.size());

// copy to generated models :-(
SortObject s = new SortObject()
.sorted(p.getSort().isSorted())
.unsorted(p.getSort().isUnsorted())
.empty(p.getSort().isEmpty())
;
PageableObject pageableObject = new PageableObject()
.paged(p.isPaged())
.unpaged(p.isUnpaged())
.pageNumber(p.getPageNumber())
.pageSize(p.getPageSize())
.sort(s)
.offset(p.getOffset())
;
PageChatMessage pageChatMessage = new PageChatMessage()
.content(chatMessages)
.pageable(pageableObject)
.last(m.isLast())
.first(m.isFirst())
.empty(m.isEmpty())
.totalPages(m.getTotalPages())
.totalElements(m.getTotalElements())
.number(m.getNumber())
.numberOfElements(m.getNumberOfElements())
.size(m.getSize())
.sort(s)
;
return new ResponseEntity<>(pageChatMessage, HttpStatus.OK);
}

private final List<ChatMessage> messages = new CopyOnWriteArrayList<>();


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
logging.level.root=info
logging.level.cz.muni=debug
server.port=8080
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package cz.muni.chat.generated.server;

import com.fasterxml.jackson.databind.ObjectMapper;
import cz.muni.chat.generated.server.model.BackgroundColorEnum;
import cz.muni.chat.generated.server.model.ChatMessage;
import cz.muni.chat.generated.server.model.NewChatMessageRequest;
import cz.muni.chat.generated.server.model.NewChatMessageRequest.TextColorEnum;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import java.util.ArrayList;
import java.util.List;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
public class GeneratedServerIT {

private static final Logger log = LoggerFactory.getLogger(GeneratedServerIT.class);

@Autowired
private MockMvc mockMvc;

@Autowired
ObjectMapper objectMapper;

@Test
void testMessageIds() throws Exception {
log.debug("Integration Test - testMessageIds");
//create more messages
List<ChatMessage> msgs = new ArrayList<>();
for(int i = 1; i<=2; i++) {
String author = "Joe";
String text = "message " + i;
TextColorEnum textColor = TextColorEnum.BLACK;
BackgroundColorEnum backgroundColor = BackgroundColorEnum.WHITE;
NewChatMessageRequest n = new NewChatMessageRequest();
n.setText(text);
n.setTextColor(textColor);
n.setBackgroundColor(backgroundColor);
String reponse = mockMvc.perform(post("/api/messages?author=" + author)
.header("User-Agent", "007")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(n))
)
.andExpect(status().isCreated())
.andExpect(jsonPath("$.text").value(text))
.andExpect(jsonPath("$.author").value(author))
.andExpect(jsonPath("$.textColor").value(textColor.getValue()))
.andExpect(jsonPath("$.backgroundColor").value(backgroundColor.getValue()))
.andReturn().getResponse().getContentAsString();
log.debug("response = {}", reponse);
ChatMessage chatMessage = objectMapper.readValue(reponse, ChatMessage.class);
log.debug("msg = {}", chatMessage);
msgs.add(chatMessage);
}

// get each message by calling URL and compare its content
for (ChatMessage msg : msgs) {
// read each message by calling the RestController
String response = mockMvc.perform(get("/api/message/{id}",msg.getId()).contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString();
log.debug("response: {}", response);
ChatMessage chatMessage = objectMapper.readValue(response, ChatMessage.class);
assertThat("id", chatMessage.getId(), is(equalTo(msg.getId())));
assertThat("text", chatMessage.getText(), is(equalTo(msg.getText())));
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
spring.main.banner-mode=off
logging.pattern.console=%clr(%d{HH:mm:ss}) %clr(%-5p) %clr(%logger{22}) %clr(%m){faint}%n
logging.level.root=warn
logging.level.org.springframework=warn
# change to logging.level.cz.muni=debug to see log of tests execution
logging.level.cz.muni=warn
14 changes: 14 additions & 0 deletions chat-server-generated/src/test/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!-- disables annoying log at the start of tests -->
<configuration>
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<root level="warn">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,9 @@ void testMessageIds() throws Exception {
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString();
log.debug("response: {}", response);
JsonNode tree = objectMapper.readTree(response);
String idFromJSON = tree.get("id").asText();
String textFromJSON = tree.get("text").asText();
assertThat("id", idFromJSON, is(equalTo(storedMessage.id())));
assertThat("text", textFromJSON, is(equalTo(storedMessage.text())));
ChatMessage chatMessage = objectMapper.readValue(response, ChatMessage.class);
assertThat("id", chatMessage.id(), is(equalTo(storedMessage.id())));
assertThat("text", chatMessage.text(), is(equalTo(storedMessage.text())));
}
}

Expand Down
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<module>chat-server</module>
<module>chat-client-java-lib</module>
<module>chat-client-java</module>
<module>chat-server-generated</module>
</modules>

<!-- properties are inherited into children projects -->
Expand Down

0 comments on commit 9d62c13

Please sign in to comment.