diff --git a/build.gradle.kts b/build.gradle.kts index 81a9ed1..cdbf01d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,6 +4,7 @@ plugins { id("com.github.johnrengelman.shadow") version "7.1.2" id("java") id("application") + id("org.jetbrains.kotlin.jvm") version "1.6.10" } group = "spp.example" diff --git a/src/main/java/spp/example/operate/WebappOperator.java b/src/main/java/spp/example/operate/WebappOperator.java deleted file mode 100644 index 48975cb..0000000 --- a/src/main/java/spp/example/operate/WebappOperator.java +++ /dev/null @@ -1,117 +0,0 @@ -package spp.example.operate; - -import com.github.javafaker.Faker; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.UriComponentsBuilder; -import spp.example.webapp.Booter; -import spp.example.webapp.model.User; - -import java.net.URI; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; - -public class WebappOperator { - - private static final RestTemplate restTemplate = new RestTemplate(); - private static final Faker faker = Faker.instance(); - - private static List> genNames = new CopyOnWriteArrayList<>(); - private static int minUserId = Integer.MAX_VALUE; - private static int maxUserId = Integer.MIN_VALUE; - - public static void main(String[] args) { - //start webapp - Booter.main(args); - - Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> { - String firstName = faker.name().firstName(); - String lastName = faker.name().lastName(); - genNames.add(new ImmutablePair(firstName, lastName)); - try { - URI uri = UriComponentsBuilder - .fromHttpUrl("http://localhost:9999/users") - .queryParam("firstName", firstName) - .queryParam("lastName", lastName) - .build() - .toUri(); - restTemplate.exchange(uri, HttpMethod.POST, null, User.class); - } catch (Exception ignore) { - } - }, 0, ThreadLocalRandom.current().nextInt(2500 * 5), TimeUnit.MILLISECONDS); - - genNames.add(new ImmutablePair(faker.name().firstName(), faker.name().lastName())); - Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> { - try { - Pair genName; - if (ThreadLocalRandom.current().nextInt(10) > 8) { - genName = genNames.remove(ThreadLocalRandom.current().nextInt(genNames.size())); - } else { - genName = new ImmutablePair(faker.name().firstName(), faker.name().lastName()); - } - URI uri = UriComponentsBuilder - .fromHttpUrl("http://localhost:9999/users") - .queryParam("firstName", genName.getLeft()) - .queryParam("lastName", genName.getRight()) - .build() - .toUri(); - restTemplate.exchange(uri, HttpMethod.DELETE, null, User.class); - } catch (Exception ignore) { - } - }, 0, ThreadLocalRandom.current().nextInt(1500 * 5), TimeUnit.MILLISECONDS); - - Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> { - ResponseEntity userEntities = restTemplate.getForEntity("http://localhost:9999/users", User[].class); - Arrays.stream(userEntities.getBody()).forEach(user -> { - if (user.getId() < minUserId) { - minUserId = (int) user.getId(); - } - if (user.getId() > maxUserId) { - maxUserId = (int) user.getId(); - } - }); - }, 0, ThreadLocalRandom.current().nextInt(3500 * 5), TimeUnit.MILLISECONDS); - - Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> { - if (minUserId < maxUserId && maxUserId > 0) { - int userId = ThreadLocalRandom.current().nextInt(minUserId, maxUserId); - if (ThreadLocalRandom.current().nextBoolean()) { - userId *= 2; - } - try { - restTemplate.getForEntity("http://localhost:9999/users/" + userId, User.class); - } catch (RestClientException ignore) { - } - } - }, 0, ThreadLocalRandom.current().nextInt(3500 * 5), TimeUnit.MILLISECONDS); - - Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> { - try { - restTemplate.getForEntity("http://localhost:9999/throws-exception", User.class); - } catch (RestClientException ignore) { - } - }, 0, ThreadLocalRandom.current().nextInt(6500 * 5), TimeUnit.MILLISECONDS); - - Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> { - try { - restTemplate.getForEntity("http://localhost:9999/primitive-local-vars", User.class); - } catch (RestClientException ignore) { - } - }, 0, 1, TimeUnit.SECONDS); - - Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> { - try { - restTemplate.getForEntity("http://localhost:9999/changing-primitive-local-vars", User.class); - } catch (RestClientException ignore) { - } - }, 0, 2, TimeUnit.SECONDS); - } -} diff --git a/src/main/java/spp/example/webapp/Booter.java b/src/main/java/spp/example/webapp/Booter.java deleted file mode 100644 index d735c20..0000000 --- a/src/main/java/spp/example/webapp/Booter.java +++ /dev/null @@ -1,12 +0,0 @@ -package spp.example.webapp; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Booter { - - public static void main(String[] args) { - SpringApplication.run(Booter.class, args); - } -} diff --git a/src/main/java/spp/example/webapp/configuration/UserStorageConfiguration.java b/src/main/java/spp/example/webapp/configuration/UserStorageConfiguration.java deleted file mode 100644 index 757dc59..0000000 --- a/src/main/java/spp/example/webapp/configuration/UserStorageConfiguration.java +++ /dev/null @@ -1,45 +0,0 @@ -package spp.example.webapp.configuration; - -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; -import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; -import spp.example.webapp.model.User; - -import javax.sql.DataSource; - -@Configuration -@EnableJpaRepositories( - basePackages = "spp.example.webapp.repository", - entityManagerFactoryRef = "cardEntityManagerFactory" -) -public class UserStorageConfiguration { - - @Bean - @Primary - @ConfigurationProperties("app.datasource.card") - public DataSourceProperties cardDataSourceProperties() { - return new DataSourceProperties(); - } - - @Bean - @ConfigurationProperties("app.datasource.card.configuration") - public DataSource cardDataSource() { - return cardDataSourceProperties() - .initializeDataSourceBuilder() - .build(); - } - - @Bean(name = "cardEntityManagerFactory") - public LocalContainerEntityManagerFactoryBean cardEntityManagerFactory( - EntityManagerFactoryBuilder builder) { - return builder - .dataSource(cardDataSource()) - .packages(User.class) - .build(); - } -} diff --git a/src/main/java/spp/example/webapp/controller/LiveInstrumentController.java b/src/main/java/spp/example/webapp/controller/LiveInstrumentController.java deleted file mode 100644 index bce898d..0000000 --- a/src/main/java/spp/example/webapp/controller/LiveInstrumentController.java +++ /dev/null @@ -1,41 +0,0 @@ -package spp.example.webapp.controller; - -import org.apache.commons.lang3.RandomStringUtils; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; - -import java.util.concurrent.ThreadLocalRandom; - -@RestController -public class LiveInstrumentController { - - @RequestMapping(value = "/primitive-local-vars", method = RequestMethod.GET) - public ResponseEntity primitiveLocalVariables() { - int i = 1; - char c = 'h'; - String s = "hi"; - float f = 1.0f; - long max = Long.MAX_VALUE; - byte b = -2; - short sh = Short.MIN_VALUE; - double d = 00.23d; - boolean bool = true; - return ResponseEntity.ok().build(); - } - - @RequestMapping(value = "/changing-primitive-local-vars", method = RequestMethod.GET) - public ResponseEntity changingPrimitiveLocalVariables() { - int i = ThreadLocalRandom.current().nextInt(); - char c = (char) (ThreadLocalRandom.current().nextInt(26) + 'a'); - String s = RandomStringUtils.randomAlphanumeric(15); - float f = ThreadLocalRandom.current().nextFloat(); - long max = ThreadLocalRandom.current().nextLong(); - byte b = (byte) ThreadLocalRandom.current().nextInt(Byte.MAX_VALUE); - short sh = (short) ThreadLocalRandom.current().nextInt(Short.MAX_VALUE); - double d = ThreadLocalRandom.current().nextDouble(); - boolean bool = ThreadLocalRandom.current().nextBoolean(); - return ResponseEntity.ok().build(); - } -} diff --git a/src/main/java/spp/example/webapp/controller/WebappController.java b/src/main/java/spp/example/webapp/controller/WebappController.java deleted file mode 100644 index f230562..0000000 --- a/src/main/java/spp/example/webapp/controller/WebappController.java +++ /dev/null @@ -1,92 +0,0 @@ -package spp.example.webapp.controller; - -import org.apache.skywalking.apm.toolkit.trace.Trace; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import spp.example.webapp.model.User; -import spp.example.webapp.service.UserService; - -@RestController -public class WebappController { - - private static final Logger log = LoggerFactory.getLogger(WebappController.class); - - private final UserService userService; - - public WebappController(UserService userService) { - this.userService = userService; - } - - @RequestMapping(value = "/users", method = RequestMethod.GET) - public ResponseEntity> userList() { - log.info("Getting user list"); - return ResponseEntity.ok(userService.getUsers()); - } - - @RequestMapping(value = "/users/{id}", method = RequestMethod.GET) - public ResponseEntity getUser(@PathVariable long id) { - log.info("Getting user by id: {}", id); - return ResponseEntity.of(userService.getUser(id)); - } - - @RequestMapping(value = "/users", method = RequestMethod.POST) - public ResponseEntity createUser(@RequestParam String firstName, @RequestParam String lastName) { - log.info("Creating user: {} {}", firstName, lastName); - User newUser = new User(); - newUser.setFirstname(firstName); - newUser.setLastname(lastName); - - if (userService.getUserByFirstAndLastName(firstName, lastName).isPresent()) { - return ResponseEntity.status(HttpStatus.CONFLICT).build(); - } else { - return ResponseEntity.ok(userService.createUser(newUser)); - } - } - - @RequestMapping(value = "/users", method = RequestMethod.DELETE) - public void deleteUser(@RequestParam String firstName, @RequestParam String lastName) { - log.info("Deleting user: {} {}", firstName, lastName); - User user = new User(); - user.setFirstname(firstName); - user.setLastname(lastName); - - if (userService.getUserByFirstAndLastName(firstName, lastName).isPresent()) { - userService.deleteUser(user); - } else { - log.warn("Missing user: {} {}", user.getFirstname(), user.getLastname()); - } - } - - @RequestMapping(value = "/throws-exception", method = RequestMethod.GET) - public void throwsException() { - log.error("Throwing exception"); - try { - caughtException(); - } catch (Exception ex) { - log.error("Threw error", ex); - } - - sometimesUncaughtException(); - uncaughtException(); - } - - @Trace - private void sometimesUncaughtException() { - if (Math.random() > 0.5) { - throw new RuntimeException("Something bad happened"); - } - } - - @Trace - private void caughtException() { - "test".substring(10); - } - - @Trace - private void uncaughtException() { - throw new RuntimeException("Something bad happened"); - } -} diff --git a/src/main/java/spp/example/webapp/edge/SingleThread.java b/src/main/java/spp/example/webapp/edge/SingleThread.java deleted file mode 100644 index a255da7..0000000 --- a/src/main/java/spp/example/webapp/edge/SingleThread.java +++ /dev/null @@ -1,39 +0,0 @@ -package spp.example.webapp.edge; - -import org.springframework.stereotype.Component; - -import javax.annotation.PostConstruct; -import java.io.OutputStream; -import java.io.PrintStream; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -@Component -public class SingleThread implements Runnable { - - private final PrintStream nullStream = new PrintStream(new OutputStream() { - public void write(int b) { - } - }); - - @PostConstruct - public void init() { - ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); - executorService.scheduleAtFixedRate(this, 0, 1, TimeUnit.SECONDS); - } - - @Override - public void run() { - int i = 1; - char c = 'h'; - String s = "hi"; - float f = 1.0f; - long max = Long.MAX_VALUE; - byte b = -2; - short sh = Short.MIN_VALUE; - double d = 00.23d; - boolean bool = true; - nullStream.print(i + c + s + f + max + b + sh + d + bool); - } -} diff --git a/src/main/java/spp/example/webapp/edge/TwoMbObject.java b/src/main/java/spp/example/webapp/edge/TwoMbObject.java deleted file mode 100644 index 30615eb..0000000 --- a/src/main/java/spp/example/webapp/edge/TwoMbObject.java +++ /dev/null @@ -1,33 +0,0 @@ -package spp.example.webapp.edge; - -import org.springframework.stereotype.Component; - -import javax.annotation.PostConstruct; -import java.io.OutputStream; -import java.io.PrintStream; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -@Component -public class TwoMbObject implements Runnable { - - private final PrintStream nullStream = new PrintStream(new OutputStream() { - public void write(int b) { - } - }); - - private final byte[] TWO_MB_ARR = new byte[1024 * 1024 * 2]; - - @PostConstruct - public void init() { - ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); - executorService.scheduleAtFixedRate(this, 0, 1, TimeUnit.SECONDS); - } - - @Override - public void run() { - nullStream.println(TWO_MB_ARR); - nullStream.print("nothing"); - } -} diff --git a/src/main/java/spp/example/webapp/model/User.java b/src/main/java/spp/example/webapp/model/User.java deleted file mode 100644 index 5e09262..0000000 --- a/src/main/java/spp/example/webapp/model/User.java +++ /dev/null @@ -1,44 +0,0 @@ -package spp.example.webapp.model; - -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import java.io.Serializable; - -@Entity -public class User implements Serializable { - - @Id - @GeneratedValue - private long id = -1; - private String firstname; - private String lastname; - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - public String getFirstname() { - return firstname; - } - - public void setFirstname(String firstname) { - this.firstname = firstname; - } - - public String getLastname() { - return lastname; - } - - public void setLastname(String lastname) { - this.lastname = lastname; - } - - public String toString() { - return String.format("[#UserObject] Id: %s", id); - } -} diff --git a/src/main/java/spp/example/webapp/repository/UserStorage.java b/src/main/java/spp/example/webapp/repository/UserStorage.java deleted file mode 100644 index 2730c05..0000000 --- a/src/main/java/spp/example/webapp/repository/UserStorage.java +++ /dev/null @@ -1,15 +0,0 @@ -package spp.example.webapp.repository; - -import org.springframework.data.repository.CrudRepository; -import spp.example.webapp.model.User; - -import java.util.List; -import java.util.Optional; - -public interface UserStorage extends CrudRepository { - List findByFirstname(String firstName); - - List findByLastname(String firstName); - - Optional findByFirstnameAndLastname(String firstName, String lastName); -} \ No newline at end of file diff --git a/src/main/java/spp/example/webapp/service/UserService.java b/src/main/java/spp/example/webapp/service/UserService.java deleted file mode 100644 index 88ceec9..0000000 --- a/src/main/java/spp/example/webapp/service/UserService.java +++ /dev/null @@ -1,18 +0,0 @@ -package spp.example.webapp.service; - -import spp.example.webapp.model.User; - -import java.util.Optional; - -public interface UserService { - - Iterable getUsers(); - - Optional getUser(long userId); - - User createUser(User user); - - void deleteUser(User user); - - Optional getUserByFirstAndLastName(String firstName, String lastName); -} diff --git a/src/main/java/spp/example/webapp/service/UserServiceImpl.java b/src/main/java/spp/example/webapp/service/UserServiceImpl.java deleted file mode 100644 index ad004ba..0000000 --- a/src/main/java/spp/example/webapp/service/UserServiceImpl.java +++ /dev/null @@ -1,82 +0,0 @@ -package spp.example.webapp.service; - -import lombok.SneakyThrows; -import org.apache.skywalking.apm.toolkit.trace.Trace; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; -import spp.example.webapp.model.User; -import spp.example.webapp.repository.UserStorage; - -import java.util.Optional; -import java.util.concurrent.ThreadLocalRandom; - -@Service -public class UserServiceImpl implements UserService { - - private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class); - - private final UserStorage userStorage; - - public UserServiceImpl(UserStorage userStorage) { - this.userStorage = userStorage; - } - - @Trace - @Override - @SneakyThrows - public Iterable getUsers() { - Thread.sleep(ThreadLocalRandom.current().nextInt(250)); //pretend work - log.info("Getting all users"); - return userStorage.findAll(); - } - - @Trace - @Override - @SneakyThrows - public Optional getUser(long userId) { - Thread.sleep(ThreadLocalRandom.current().nextInt(250)); //pretend work - Optional user = userStorage.findById(userId); - if (user.isPresent()) { - log.info("Found user: {}", user); - } else { - log.warn("Could not find user: {}", userId); - } - return user; - } - - @Trace - @Override - @SneakyThrows - public User createUser(User user) { - Thread.sleep(ThreadLocalRandom.current().nextInt(250)); //pretend work - log.info("Saving user: {} {}", user.getFirstname(), user.getLastname()); - User createdUser = userStorage.save(user); - log.info("Created user: {}", createdUser); - return createdUser; - } - - @Trace - @Override - @SneakyThrows - public void deleteUser(User user) { - Thread.sleep(ThreadLocalRandom.current().nextInt(250)); //pretend work - userStorage.delete(user); - log.info("Deleted user: {} {}", user.getFirstname(), user.getLastname()); - } - - @Trace - @Override - @SneakyThrows - public Optional getUserByFirstAndLastName(String firstName, String lastName) { - Thread.sleep(ThreadLocalRandom.current().nextInt(250)); //pretend work - log.info("Getting user by first and last name"); - Optional user = userStorage.findByFirstnameAndLastname(firstName, lastName); - if (user.isPresent()) { - log.info("Found user: {}", user); - } else { - log.warn("Could not find user: {} {}", firstName, lastName); - } - return user; - } -} diff --git a/src/main/kotlin/example/operate/WebappOperator.kt b/src/main/kotlin/example/operate/WebappOperator.kt new file mode 100644 index 0000000..f2d2cb3 --- /dev/null +++ b/src/main/kotlin/example/operate/WebappOperator.kt @@ -0,0 +1,101 @@ +package example.operate + +import com.github.javafaker.Faker +import example.webapp.Booter +import example.webapp.model.User +import org.apache.commons.lang3.tuple.ImmutablePair +import org.apache.commons.lang3.tuple.Pair +import org.springframework.http.HttpMethod +import org.springframework.web.client.RestClientException +import org.springframework.web.client.RestTemplate +import org.springframework.web.util.UriComponentsBuilder +import java.util.* +import java.util.concurrent.* + +object WebappOperator { + private val restTemplate = RestTemplate() + private val faker = Faker.instance() + private val genNames: MutableList> = CopyOnWriteArrayList() + private var minUserId = Int.MAX_VALUE + private var maxUserId = Int.MIN_VALUE + @JvmStatic + fun main(args: Array) { + //start webapp + Booter.main(args) + Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate({ + val firstName = faker.name().firstName() + val lastName = faker.name().lastName() + genNames.add(ImmutablePair.of(firstName, lastName)) + try { + val uri = UriComponentsBuilder + .fromHttpUrl("http://localhost:9999/users") + .queryParam("firstName", firstName) + .queryParam("lastName", lastName) + .build() + .toUri() + restTemplate.exchange(uri, HttpMethod.POST, null, User::class.java) + } catch (ignore: Exception) { + } + }, 0, ThreadLocalRandom.current().nextInt(2500 * 5).toLong(), TimeUnit.MILLISECONDS) + genNames.add(ImmutablePair.of(faker.name().firstName(), faker.name().lastName())) + Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate({ + try { + val genName: Pair + if (ThreadLocalRandom.current().nextInt(10) > 8) { + genName = genNames.removeAt(ThreadLocalRandom.current().nextInt(genNames.size)) + } else { + genName = ImmutablePair.of(faker.name().firstName(), faker.name().lastName()) + } + val uri = UriComponentsBuilder + .fromHttpUrl("http://localhost:9999/users") + .queryParam("firstName", genName.left) + .queryParam("lastName", genName.right) + .build() + .toUri() + restTemplate.exchange(uri, HttpMethod.DELETE, null, User::class.java) + } catch (ignore: Exception) { + } + }, 0, ThreadLocalRandom.current().nextInt(1500 * 5).toLong(), TimeUnit.MILLISECONDS) + Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate({ + val userEntities = restTemplate.getForEntity("http://localhost:9999/users", Array::class.java) + Arrays.stream(userEntities.body).forEach { user: User -> + if (user.id < minUserId) { + minUserId = user.id.toInt() + } + if (user.id > maxUserId) { + maxUserId = user.id.toInt() + } + } + }, 0, ThreadLocalRandom.current().nextInt(3500 * 5).toLong(), TimeUnit.MILLISECONDS) + Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate({ + if (minUserId < maxUserId && maxUserId > 0) { + var userId = ThreadLocalRandom.current().nextInt(minUserId, maxUserId) + if (ThreadLocalRandom.current().nextBoolean()) { + userId *= 2 + } + try { + restTemplate.getForEntity("http://localhost:9999/users/$userId", User::class.java) + } catch (ignore: RestClientException) { + } + } + }, 0, ThreadLocalRandom.current().nextInt(3500 * 5).toLong(), TimeUnit.MILLISECONDS) + Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate({ + try { + restTemplate.getForEntity("http://localhost:9999/throws-exception", User::class.java) + } catch (ignore: RestClientException) { + } + }, 0, ThreadLocalRandom.current().nextInt(6500 * 5).toLong(), TimeUnit.MILLISECONDS) + Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate({ + try { + restTemplate.getForEntity("http://localhost:9999/primitive-local-vars", User::class.java) + } catch (ignore: RestClientException) { + } + }, 0, 1, TimeUnit.SECONDS) + Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate({ + try { + restTemplate.getForEntity("http://localhost:9999/changing-primitive-local-vars", User::class.java) + } catch (ignore: RestClientException) { + } + }, 0, 2, TimeUnit.SECONDS) + } +} \ No newline at end of file diff --git a/src/main/kotlin/example/webapp/Booter.kt b/src/main/kotlin/example/webapp/Booter.kt new file mode 100644 index 0000000..9051461 --- /dev/null +++ b/src/main/kotlin/example/webapp/Booter.kt @@ -0,0 +1,12 @@ +package example.webapp + +import org.springframework.boot.SpringApplication +import org.springframework.boot.autoconfigure.SpringBootApplication + +@SpringBootApplication +object Booter { + @JvmStatic + fun main(args: Array) { + SpringApplication.run(Booter::class.java, *args) + } +} \ No newline at end of file diff --git a/src/main/kotlin/example/webapp/configuration/UserStorageConfiguration.kt b/src/main/kotlin/example/webapp/configuration/UserStorageConfiguration.kt new file mode 100644 index 0000000..8ad381e --- /dev/null +++ b/src/main/kotlin/example/webapp/configuration/UserStorageConfiguration.kt @@ -0,0 +1,44 @@ +package example.webapp.configuration + +import example.webapp.model.User +import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties +import org.springframework.boot.context.properties.ConfigurationProperties +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Primary +import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean +import javax.sql.DataSource + +@Configuration +@EnableJpaRepositories( + basePackages = ["spp.example.webapp.repository"], + entityManagerFactoryRef = "cardEntityManagerFactory" +) +class UserStorageConfiguration { + @Bean + @Primary + @ConfigurationProperties("app.datasource.card") + fun cardDataSourceProperties(): DataSourceProperties { + return DataSourceProperties() + } + + @Bean + @ConfigurationProperties("app.datasource.card.configuration") + fun cardDataSource(): DataSource { + return cardDataSourceProperties() + .initializeDataSourceBuilder() + .build() + } + + @Bean(name = ["cardEntityManagerFactory"]) + fun cardEntityManagerFactory( + builder: EntityManagerFactoryBuilder + ): LocalContainerEntityManagerFactoryBean { + return builder + .dataSource(cardDataSource()) + .packages(User::class.java) + .build() + } +} \ No newline at end of file diff --git a/src/main/kotlin/example/webapp/controller/LiveInstrumentController.kt b/src/main/kotlin/example/webapp/controller/LiveInstrumentController.kt new file mode 100644 index 0000000..1b607ca --- /dev/null +++ b/src/main/kotlin/example/webapp/controller/LiveInstrumentController.kt @@ -0,0 +1,39 @@ +package example.webapp.controller + +import org.apache.commons.lang3.RandomStringUtils +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestMethod +import org.springframework.web.bind.annotation.RestController +import java.util.concurrent.ThreadLocalRandom + +@RestController +class LiveInstrumentController { + @RequestMapping(value = ["/primitive-local-vars"], method = [RequestMethod.GET]) + fun primitiveLocalVariables(): ResponseEntity<*> { + val i = 1 + val c = 'h' + val s = "hi" + val f = 1.0f + val max = Long.MAX_VALUE + val b: Byte = -2 + val sh = Short.MIN_VALUE + val d = 00.23 + val bool = true + return ResponseEntity.ok().build() + } + + @RequestMapping(value = ["/changing-primitive-local-vars"], method = [RequestMethod.GET]) + fun changingPrimitiveLocalVariables(): ResponseEntity<*> { + val i = ThreadLocalRandom.current().nextInt() + val c = (ThreadLocalRandom.current().nextInt(26) + 'a'.code).toChar() + val s = RandomStringUtils.randomAlphanumeric(15) + val f = ThreadLocalRandom.current().nextFloat() + val max = ThreadLocalRandom.current().nextLong() + val b = ThreadLocalRandom.current().nextInt(Byte.MAX_VALUE.toInt()).toByte() + val sh = ThreadLocalRandom.current().nextInt(Short.MAX_VALUE.toInt()).toShort() + val d = ThreadLocalRandom.current().nextDouble() + val bool = ThreadLocalRandom.current().nextBoolean() + return ResponseEntity.ok().build() + } +} \ No newline at end of file diff --git a/src/main/kotlin/example/webapp/controller/WebappController.kt b/src/main/kotlin/example/webapp/controller/WebappController.kt new file mode 100644 index 0000000..ef1a045 --- /dev/null +++ b/src/main/kotlin/example/webapp/controller/WebappController.kt @@ -0,0 +1,84 @@ +package example.webapp.controller + +import example.webapp.controller.WebappController +import example.webapp.model.User +import example.webapp.service.UserService +import org.apache.skywalking.apm.toolkit.trace.Trace +import org.slf4j.LoggerFactory +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* + +@RestController +class WebappController(private val userService: UserService) { + @RequestMapping(value = ["/users"], method = [RequestMethod.GET]) + fun userList(): ResponseEntity?> { + log.info("Getting user list") + return ResponseEntity.ok(userService.users) + } + + @RequestMapping(value = ["/users/{id}"], method = [RequestMethod.GET]) + fun getUser(@PathVariable id: Long): ResponseEntity { + log.info("Getting user by id: {}", id) + return ResponseEntity.of(userService.getUser(id)) + } + + @RequestMapping(value = ["/users"], method = [RequestMethod.POST]) + fun createUser(@RequestParam firstName: String?, @RequestParam lastName: String?): ResponseEntity { + log.info("Creating user: {} {}", firstName, lastName) + val newUser = User() + newUser.firstname = firstName + newUser.lastname = lastName + return if (userService.getUserByFirstAndLastName(firstName, lastName)!!.isPresent) { + ResponseEntity.status(HttpStatus.CONFLICT).build() + } else { + ResponseEntity.ok(userService.createUser(newUser)) + } + } + + @RequestMapping(value = ["/users"], method = [RequestMethod.DELETE]) + fun deleteUser(@RequestParam firstName: String?, @RequestParam lastName: String?) { + log.info("Deleting user: {} {}", firstName, lastName) + val user = User() + user.firstname = firstName + user.lastname = lastName + if (userService.getUserByFirstAndLastName(firstName, lastName)!!.isPresent) { + userService.deleteUser(user) + } else { + log.warn("Missing user: {} {}", user.firstname, user.lastname) + } + } + + @RequestMapping(value = ["/throws-exception"], method = [RequestMethod.GET]) + fun throwsException() { + log.error("Throwing exception") + try { + caughtException() + } catch (ex: Exception) { + log.error("Threw error", ex) + } + sometimesUncaughtException() + uncaughtException() + } + + @Trace + private fun sometimesUncaughtException() { + if (Math.random() > 0.5) { + throw RuntimeException("Something bad happened") + } + } + + @Trace + private fun caughtException() { + "test".substring(10) + } + + @Trace + private fun uncaughtException() { + throw RuntimeException("Something bad happened") + } + + companion object { + private val log = LoggerFactory.getLogger(WebappController::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/example/webapp/edge/SingleThread.kt b/src/main/kotlin/example/webapp/edge/SingleThread.kt new file mode 100644 index 0000000..e28c38e --- /dev/null +++ b/src/main/kotlin/example/webapp/edge/SingleThread.kt @@ -0,0 +1,33 @@ +package example.webapp.edge + +import org.springframework.stereotype.Component +import java.io.OutputStream +import java.io.PrintStream +import java.util.concurrent.* +import javax.annotation.PostConstruct + +@Component +class SingleThread : Runnable { + private val nullStream = PrintStream(object : OutputStream() { + override fun write(b: Int) {} + }) + + @PostConstruct + fun init() { + val executorService = Executors.newSingleThreadScheduledExecutor() + executorService.scheduleAtFixedRate(this, 0, 1, TimeUnit.SECONDS) + } + + override fun run() { + val i = 1 + val c = 'h' + val s = "hi" + val f = 1.0f + val max = Long.MAX_VALUE + val b: Byte = -2 + val sh = Short.MIN_VALUE + val d = 00.23 + val bool = true + nullStream.print(i + c.code + s + f + max + b + sh + d + bool) + } +} \ No newline at end of file diff --git a/src/main/kotlin/example/webapp/edge/TwoMbObject.kt b/src/main/kotlin/example/webapp/edge/TwoMbObject.kt new file mode 100644 index 0000000..cf42070 --- /dev/null +++ b/src/main/kotlin/example/webapp/edge/TwoMbObject.kt @@ -0,0 +1,26 @@ +package example.webapp.edge + +import org.springframework.stereotype.Component +import java.io.OutputStream +import java.io.PrintStream +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit +import javax.annotation.PostConstruct + +@Component +class TwoMbObject : Runnable { + private val nullStream = PrintStream(object : OutputStream() { + override fun write(b: Int) {} + }) + private val TWO_MB_ARR = ByteArray(1024 * 1024 * 2) + @PostConstruct + fun init() { + val executorService = Executors.newSingleThreadScheduledExecutor() + executorService.scheduleAtFixedRate(this, 0, 1, TimeUnit.SECONDS) + } + + override fun run() { + nullStream.println(TWO_MB_ARR) + nullStream.print("nothing") + } +} \ No newline at end of file diff --git a/src/main/kotlin/example/webapp/model/User.kt b/src/main/kotlin/example/webapp/model/User.kt new file mode 100644 index 0000000..4ecd80f --- /dev/null +++ b/src/main/kotlin/example/webapp/model/User.kt @@ -0,0 +1,18 @@ +package example.webapp.model + +import java.io.Serializable +import javax.persistence.Entity +import javax.persistence.GeneratedValue +import javax.persistence.Id + +@Entity +class User : Serializable { + @Id + @GeneratedValue + var id: Long = -1 + var firstname: String? = null + var lastname: String? = null + override fun toString(): String { + return String.format("[#UserObject] Id: %s", id) + } +} \ No newline at end of file diff --git a/src/main/kotlin/example/webapp/repository/UserStorage.kt b/src/main/kotlin/example/webapp/repository/UserStorage.kt new file mode 100644 index 0000000..340fd2c --- /dev/null +++ b/src/main/kotlin/example/webapp/repository/UserStorage.kt @@ -0,0 +1,11 @@ +package example.webapp.repository + +import example.webapp.model.User +import org.springframework.data.repository.CrudRepository +import java.util.* + +interface UserStorage : CrudRepository { + fun findByFirstname(firstName: String?): List? + fun findByLastname(firstName: String?): List? + fun findByFirstnameAndLastname(firstName: String?, lastName: String?): Optional? +} \ No newline at end of file diff --git a/src/main/kotlin/example/webapp/service/UserService.kt b/src/main/kotlin/example/webapp/service/UserService.kt new file mode 100644 index 0000000..992ddb4 --- /dev/null +++ b/src/main/kotlin/example/webapp/service/UserService.kt @@ -0,0 +1,12 @@ +package example.webapp.service + +import example.webapp.model.User +import java.util.* + +interface UserService { + val users: Iterable + fun getUser(userId: Long): Optional + fun createUser(user: User): User + fun deleteUser(user: User) + fun getUserByFirstAndLastName(firstName: String?, lastName: String?): Optional? +} \ No newline at end of file diff --git a/src/main/kotlin/example/webapp/service/UserServiceImpl.kt b/src/main/kotlin/example/webapp/service/UserServiceImpl.kt new file mode 100644 index 0000000..a7c0b86 --- /dev/null +++ b/src/main/kotlin/example/webapp/service/UserServiceImpl.kt @@ -0,0 +1,73 @@ +package example.webapp.service + +import example.webapp.model.User +import example.webapp.repository.UserStorage +import example.webapp.service.UserServiceImpl +import lombok.SneakyThrows +import org.apache.skywalking.apm.toolkit.trace.Trace +import org.slf4j.LoggerFactory +import org.springframework.stereotype.Service +import java.util.* +import java.util.concurrent.ThreadLocalRandom + +@Service +class UserServiceImpl(private val userStorage: UserStorage) : UserService { + //pretend work + @get:SneakyThrows + @get:Trace + override val users: Iterable + get() { + Thread.sleep(ThreadLocalRandom.current().nextInt(250).toLong()) //pretend work + log.info("Getting all users") + return userStorage.findAll() + } + + @Trace + @SneakyThrows + override fun getUser(userId: Long): Optional { + Thread.sleep(ThreadLocalRandom.current().nextInt(250).toLong()) //pretend work + val user = userStorage.findById(userId) + if (user.isPresent) { + log.info("Found user: {}", user) + } else { + log.warn("Could not find user: {}", userId) + } + return user + } + + @Trace + @SneakyThrows + override fun createUser(user: User): User { + Thread.sleep(ThreadLocalRandom.current().nextInt(250).toLong()) //pretend work + log.info("Saving user: {} {}", user.firstname, user.lastname) + val createdUser = userStorage.save(user) + log.info("Created user: {}", createdUser) + return createdUser + } + + @Trace + @SneakyThrows + override fun deleteUser(user: User) { + Thread.sleep(ThreadLocalRandom.current().nextInt(250).toLong()) //pretend work + userStorage.delete(user) + log.info("Deleted user: {} {}", user.firstname, user.lastname) + } + + @Trace + @SneakyThrows + override fun getUserByFirstAndLastName(firstName: String?, lastName: String?): Optional? { + Thread.sleep(ThreadLocalRandom.current().nextInt(250).toLong()) //pretend work + log.info("Getting user by first and last name") + val user = userStorage.findByFirstnameAndLastname(firstName, lastName) + if (user!!.isPresent) { + log.info("Found user: {}", user) + } else { + log.warn("Could not find user: {} {}", firstName, lastName) + } + return user + } + + companion object { + private val log = LoggerFactory.getLogger(UserServiceImpl::class.java) + } +} \ No newline at end of file