68 Commits
11.2 ... 11.3

Author SHA1 Message Date
57a08c3246 Resolved merge conflict in xmlFormatter.html 2023-05-30 15:56:03 +02:00
5a331d9815 Fixed merge conflicts 2023-05-30 15:49:50 +02:00
e9221e2393 Release 11.3 2023-05-30 15:42:09 +02:00
7318708bd2 Disabled persistency in Redis (#214)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #214
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-30 15:27:15 +02:00
66b20f8256 Added tests for JSON Formatter (#212)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #212
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-30 13:17:10 +02:00
b6e6277074 Cleared unused listeners, and optimize uianimation code (#213)
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #213
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-30 13:15:47 +02:00
fb128070dc Removed broken code 2023-05-26 14:12:11 +02:00
d0c19e19df Merged bema/ref/tools_urls to master 2023-05-26 14:11:20 +02:00
c41c3f5abc Merged widlam/refactor/issue#201 to master 2023-05-26 14:04:34 +02:00
9b18a9f42d Simplified history 2023-05-26 13:55:48 +02:00
a8d93fc2a5 Made more elegant solution to tools URLs 2023-05-26 11:57:00 +02:00
6058169818 Solved #180 and one other bug (#210)
I found and fixed bug: When in URL query was put without # at the end the page would start reloading indefinitely

Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #210
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-26 11:39:57 +02:00
d336f5d18e Fixed bug with category not bein remembered 2023-05-26 10:44:54 +02:00
45fab20cc4 Merge branch 'master' of gitea.release11.com:R11/release11-tools into widlam/refactor/issue#201 2023-05-25 14:59:43 +02:00
b733e1e344 Fixed history problem, and improve mock services frontend 2023-05-25 14:49:16 +02:00
97042faaa3 Tools can be selected through URL (solves #161) (#207)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #207
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-24 14:40:07 +02:00
8815f657e0 Clean frontend code 2023-05-24 11:08:15 +02:00
ecafb17f05 revert f9b426bb30
revert Every tool can now be accessed from URL
2023-05-24 11:06:50 +02:00
f9b426bb30 Every tool can now be accessed from URL 2023-05-24 10:33:00 +02:00
02c10b8354 Fixed not working JSON arrays (#206)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #206
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-23 13:48:22 +02:00
5b69fd1de0 Every service meant to be public work now on port 80 (#205)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #205
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-23 08:59:09 +02:00
2aaf993f7a Started to removing changing UUID and many messages system 2023-05-23 08:38:28 +02:00
d5e33381a2 Refactor of History module (#184)
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #184
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-19 13:10:45 +02:00
d231a7476b Fixed timezone (#193)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #193
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-19 13:09:01 +02:00
369256baf2 tests with variable URL (#200)
Co-authored-by: augustyd <kainytsugua.kerad@gmail.com>
Reviewed-on: #200
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-committed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-05-18 13:38:38 +02:00
e697a783ae Solved #195 and cleaned up code (#196)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #196
Reviewed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-05-18 13:36:51 +02:00
1930cde695 Postman tests (#194)
Co-authored-by: augustyd <kainytsugua.kerad@gmail.com>
Reviewed-on: #194
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-committed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-05-17 14:08:16 +02:00
bcbfd34feb Moved scripts from .html files to seperate js .files (#191)
Let's hope everything works as before or better.

Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #191
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-16 09:59:04 +02:00
2d97e39dbe Fixed 404 when no lastPage was stored (solves #189)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #190
2023-05-12 15:03:46 +02:00
c89623c3a8 Dependencies in libXML now have specified versions
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #187
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-12 14:13:47 +02:00
dc3df79fc1 Moved frontend of REST Mock to frontend container (solves #168)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #186
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-12 10:06:19 +02:00
34038a2ce9 Tools java backend now uses interfaces for engine classes (solves #167) (#179)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #179
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-11 15:23:54 +02:00
d8504ee8f8 Changed timezone (solves #164 and #181)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #183
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-11 11:20:36 +02:00
6a1c6aac46 Last opened page is now stored (solves #166) (#178)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #178
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-09 15:12:57 +02:00
7fd6fd3788 Fixed incorrect Content-Type (#174) (#175)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #175
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-09 11:15:26 +02:00
41d3b90fd8 Removed version number from Mock Service (done #172) (#173)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #173
Reviewed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-05-09 10:21:37 +02:00
c55942c24a Added syntax highlighting for XML Tools (#156)
Syntax highlight now should work on all tools apart from Mock Services.

Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #156
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-08 11:11:16 +02:00
21f5911b1c Added sample XSD schema (#163)
Due to some errors with namespaces and XSD schema simplified sample XML for that tool.

Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #163
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-08 10:13:10 +02:00
71bbe668f6 augustyd/enchancment/issue#98 (#155)
issue#98
save button when user creates new message and has unsaved data in old message

Co-authored-by: augustyd <kainytsugua.kerad@gmail.com>
Reviewed-on: #155
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-committed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-04-26 13:38:23 +02:00
4a04ac3b70 Added a email address to report a bugs (#154)
![image](/attachments/d3e81b26-ea63-4ed6-8ae6-b8945325be16)

Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #154
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-26 13:32:13 +02:00
b26840ffba Added new JSON field documentation (#153)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #153
2023-04-21 09:43:24 +02:00
1199e06bef Implemented message shown when no data type is returned. (#150)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #152
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-21 09:31:28 +02:00
1b7f6e6f70 Added META tags for SEO and SEM (#149)
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #149
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-21 08:54:21 +02:00
fe6585d509 Merge branch 'master' of gitea.release11.com:R11/release11-tools 2023-04-19 13:36:01 +02:00
093c8756b1 Added XSLTTemplate, functions that add it to transform area and documentation for that function (#144)
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #144
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-19 13:35:40 +02:00
2b8a9c3008 Implemented showing returned type (#112) (#148)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #148
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-19 13:33:39 +02:00
1f10a1d5b5 Resolved conflict 2023-04-19 13:31:58 +02:00
8a852b7a83 Fixed doubled category 2023-04-19 13:30:14 +02:00
38c1215889 Disabled caching for frontend (#146)
Disable caching for frontend

Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #146
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-19 13:27:52 +02:00
1fc1ab76ec Resolved another conflict 2023-04-19 13:27:49 +02:00
2f0541fe3d Resolved another conflict 2023-04-19 13:27:06 +02:00
5c39b7cfe0 Fixed error codes and added logging (#138)
fixed error codes (400 not 500) and added logging for json

Co-authored-by: augustyd <kainytsugua.kerad@gmail.com>
Reviewed-on: #138
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-committed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-04-19 13:26:13 +02:00
db055ef58b Resolved another conflict 2023-04-19 13:26:10 +02:00
420bfaccd9 Resolved merge conflict in xpath.html 2023-04-19 13:18:55 +02:00
3d41447581 Added numeric functions and some string 2023-04-19 13:05:36 +02:00
a773022f0d Added tooltips for XPath 2.0 (#134)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #134
2023-04-19 13:05:36 +02:00
afcd52815f Prepared templates for new XPath tooltips (#133)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #133
2023-04-19 13:05:36 +02:00
b72157377d Disabled caching for frontend (#146)
Disable caching for frontend

Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #146
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-19 10:28:04 +02:00
0946982ab6 Added missing functions (#143)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #143
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
Reviewed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-04-18 10:55:45 +02:00
8098aeacd9 Added new tooltips for XPath 3.0 and 3.1
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #139
Reviewed-by: Adam Bem <bema@noreply.example.com>
Reviewed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-18 10:05:44 +02:00
de94eca0ac Fixed error codes and added logging (#138)
fixed error codes (400 not 500) and added logging for json

Co-authored-by: augustyd <kainytsugua.kerad@gmail.com>
Reviewed-on: #138
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-committed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-04-14 10:42:47 +02:00
a7edf934f7 Merged critical XSLT fix 2023-04-12 10:01:27 +02:00
7c0d79612a Added numeric functions and some string 2023-04-12 10:01:10 +02:00
02f1977ff0 Added tooltips for XPath 2.0 (#134)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #134
2023-04-12 10:01:10 +02:00
1816302ba1 Prepared templates for new XPath tooltips (#133)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #133
2023-04-12 10:01:10 +02:00
00f3606da6 Added numeric functions and some string 2023-04-06 14:03:39 +02:00
f77a6f15c2 Added tooltips for XPath 2.0 (#134)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #134
2023-04-06 11:53:53 +02:00
0e9a87bfe7 Prepared templates for new XPath tooltips (#133)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #133
2023-03-29 08:49:43 +02:00
99 changed files with 12221 additions and 2574 deletions

View File

@@ -9,11 +9,11 @@ import Parser
app = Flask(__name__)
CORS(app)
cors = CORS(app, resource={
r"/*":{
"origins":"*"
}
})
# cors = CORS(app, resource={
# r"/*":{
# "origins":"*"
# }
# })
def process_xml(request: request, type: str) -> str:
"""Function to process

View File

@@ -1,3 +1,3 @@
lxml
flask
flask_cors
lxml==4.9.2
flask==2.3.2
flask_cors==3.0.10

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<version>2.7.11</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
@@ -18,9 +18,10 @@
<jedis.version>3.3.0</jedis.version>
<logback-redis-appender.version>1.1.6</logback-redis-appender.version>
<assertj.version>3.16.1</assertj.version>
<mapstruct.version>1.3.1.Final</mapstruct.version>
<mapstruct.version>1.5.5.Final</mapstruct.version>
<docker.image.prefix>Release11</docker.image.prefix>
<docker.image.name>${project.artifactId}</docker.image.name>
<lombok.version>1.18.26</lombok.version>
</properties>
<dependencies>
@@ -57,21 +58,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.cwbase</groupId>
<artifactId>logback-redis-appender</artifactId>
<version>${logback-redis-appender.version}</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.4.1</version>
</dependency>
</dependencies>
<build>
@@ -101,6 +87,11 @@
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</dependency>
</annotationProcessorPaths>
<compilerArgs>
<compilerArg>-Amapstruct.defaultComponentModel=spring</compilerArg>

View File

@@ -1,68 +0,0 @@
package com.r11.tools.config;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import redis.clients.jedis.JedisPool;
/**
* Class containing configuration for Redis db client
* @author Rafał Żukowicz
*/
@Configuration
@EnableRedisRepositories
@PropertySource("classpath:data-access.properties")
public class RedisConfig {
@Autowired
private Environment environment;
/**
* Bean of JedisPool - the Redis client. It stores requests in "the pool" and then fires them at Redis.
* It's considered super lightweight and fast client variant
* @return lightweight client of the Redis - the JedisPool
*/
@Bean
JedisPool jedisPool(){
final JedisPool pool = new JedisPool(environment.getProperty("redis.host"),
Integer.parseInt(environment.getProperty("redis.port")));
return pool;
}
/**
* Bean of a factory for connenction object.
* It's initialized with Redis db url property and is fed to other methods.
* @return the factory for RedisTemplates
*/
@Bean
JedisConnectionFactory jedisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration =
new RedisStandaloneConfiguration(Objects.requireNonNull(environment.getProperty("redis.host")),
Integer.parseInt(Objects.requireNonNull(environment.getProperty("redis.port"))));
return new JedisConnectionFactory(redisStandaloneConfiguration);
}
/**
* RedisTemplate is the tool to store and retrieve given type (object) of hash from the database.
* It's like you could store your Java object by just naming it inside database. You might thing about it
* as of DAO.
* @return RedisTemplate the redis dao.
*/
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
redisTemplate.setExposeConnection(true);
redisTemplate.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
return redisTemplate;
}
}

View File

@@ -0,0 +1,64 @@
package com.r11.tools.configuration;
import com.r11.tools.repository.MockedResponseRepository;
import com.r11.tools.repository.RequestHistoryRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import java.time.LocalDateTime;
/**
* Based on configuration deletes all outdated messages and history records from database.
*
* @author Mikołaj Widła
*/
@EnableScheduling
@EnableAsync
@Configuration
public class RetentionConfiguration {
private final MockedResponseRepository responseRepository;
private final RequestHistoryRepository historyRepository;
private final RetentionConfigurationProperties retentionProperties;
private final Logger log = LogManager.getRootLogger();
public RetentionConfiguration(MockedResponseRepository responseRepository,
RequestHistoryRepository historyRepository,
RetentionConfigurationProperties retentionProperties){
this.historyRepository = historyRepository;
this.responseRepository = responseRepository;
this.retentionProperties = retentionProperties;
}
@Scheduled(fixedDelayString = "#{${retention.retention-cooldown} * 60000 }")
@Async
public void deleteMessagesAndHistoryRecords(){
log.info("OUTDATED MESSAGES AND HISTORY RECORDS DELETED!");
responseRepository
.findAll()
.iterator()
.forEachRemaining( mockedMessage -> {
if (mockedMessage.getCreatedAt().plusMinutes(retentionProperties.getMinutesToDeleteMessage()).isBefore(LocalDateTime.now())){
responseRepository.delete(mockedMessage);
}
} );
historyRepository
.findAll()
.iterator()
.forEachRemaining(
historyRecord -> {
if (historyRecord.getDateTimeStamp().plusMinutes(retentionProperties.getMinutesToDeleteHistoryRecord()).isBefore(LocalDateTime.now())){
historyRepository.delete(historyRecord);
}
}
);
}
}

View File

@@ -0,0 +1,31 @@
package com.r11.tools.configuration;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.validation.constraints.Positive;
/**
* Store all properties needed to change a retention in {@link RetentionConfiguration}
*
* @author Mikołaj Widła
*/
@Configuration
@ConfigurationProperties(prefix = "retention")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class RetentionConfigurationProperties {
@Positive
private Integer minutesToDeleteMessage;
@Positive
private Integer minutesToDeleteHistoryRecord;
@Positive
private Integer retentionCooldown;
}

View File

@@ -0,0 +1,28 @@
package com.r11.tools.configuration;
import com.r11.tools.interceptor.IncomingMockRequestInterceptor;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Configuration for {@link IncomingMockRequestInterceptor}
*
* @author Mikołaj Widła
*/
@Configuration
@AllArgsConstructor
public class WebConfig implements WebMvcConfigurer{
private final IncomingMockRequestInterceptor requestInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor( requestInterceptor )
.addPathPatterns("/api/mock/r/**");
}
}

View File

@@ -1,56 +0,0 @@
package com.r11.tools.controller;
import com.r11.tools.model.EventRequestDto;
import com.r11.tools.service.EtrackService;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.UUID;
/**
* It's the REST api for {@link com.r11.tools.model.Event}
* @author Gabriel Modzelewski
*/
@RestController
@RequestMapping(path = "/api/event")
@AllArgsConstructor
public class EventController {
private final EtrackService service;
/**
* Returns the list of Events in given time bracket.
* The list of objects is received via {@link EventRequestDto}, which contains time brackets,
* as well as the key - uuid.
* @param event EventRequestDto object that contains data needed to query the database
* @return list of {@link com.r11.tools.model.Event}
*/
@PostMapping
public ResponseEntity filterHistory(@RequestBody EventRequestDto event){
return new ResponseEntity(service.getEventsByDateTimeAndBusinessKeys(event), HttpStatus.OK);
}
/**
* Returns the list of Events of last 24h from given date.
* @param uuid unique id of message list
* @param messageId unique id of message in message list
* @return list of {@link com.r11.tools.model.Event}
*/
@GetMapping(path = "/{uuid}/{messageId}")
public ResponseEntity getLastDay(@PathVariable UUID uuid,
@PathVariable Integer messageId){
LocalDateTime requestTime = LocalDateTime.now();
LocalDateTime dayBeforeRequest = requestTime.minusDays(1L);
EventRequestDto eventRequestDto = EventRequestDto.builder()
.clientUUID(uuid)
.mockedResponseId(messageId)
.localDateTimeFrom(dayBeforeRequest)
.localDateTimeTo(requestTime)
.build();
return new ResponseEntity(service.getEventsByDateTimeAndBusinessKeys(eventRequestDto), HttpStatus.OK);
}
}

View File

@@ -1,27 +0,0 @@
package com.r11.tools.controller;
import lombok.SneakyThrows;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* Class responsible for returning homepage html
* @author Gabriel Modzelewski
*/
@Controller
@RequestMapping("/")
public class MainController {
/**
* Default path to get the homepage
* @return the view of homepage
*/
@SneakyThrows
@GetMapping
public ModelAndView showHome(){
ModelAndView mov = new ModelAndView();
mov.setViewName("html/mock");
return mov;
}
}

View File

@@ -3,13 +3,14 @@ package com.r11.tools.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.r11.tools.model.MockedMessageDto;
import com.r11.tools.service.KlausService;
import com.r11.tools.utilis.BusinessKey;
import com.r11.tools.utilis.TrackingClient;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.http.*;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
@@ -18,17 +19,19 @@ import java.util.*;
/**
* Returns the homepage and provides the api for javascript async requests.
* @author Gabriel Modzelewski
* @author Mikołaj Widła
*/
@RestController
@RequestMapping(path = "/api/mock")
@AllArgsConstructor
@CrossOrigin(origins = "*")
public class MockController {
private final KlausService klausService;
private final Logger log = LogManager.getRootLogger();
@ExceptionHandler(Exception.class)
public void errorHandler(Exception ex){
log.error(ex.getStackTrace());
log.error(Arrays.toString(ex.getStackTrace()));
}
/**
@@ -48,106 +51,35 @@ public class MockController {
* Returns the full list of messages. It's used by javascript on the client side to initialize homepage
* with data from the database.
* @param uuidValue the key-uuid of given set of messages
* @return responds with 200 OK and list of {@link MockedMessageDto}
* @return responds with 200 OK and {@link MockedMessageDto}
*/
@GetMapping({"/", "/{uuidValue}"})
public List<MockedMessageDto> getListOfMessages(@PathVariable(required = false) String uuidValue){
public MockedMessageDto getMessage(@PathVariable(required = false) String uuidValue){
UUID clientUUID;
MockedMessageDto message ;
if(uuidValue == null || uuidValue.equals("")) clientUUID = UUID.randomUUID();
else clientUUID = UUID.fromString(uuidValue);
List<MockedMessageDto> messages = klausService.getAllMockedResponses(clientUUID);
if(messages.size() == 0) {
klausService.setMockedResponse(buildDefaultMessage(clientUUID));
messages = klausService.getAllMockedResponses(clientUUID);
}
Collections.sort(messages);
return messages;
}
message = klausService
.getMockedMessageByClientUUID(clientUUID)
.orElse( buildDefaultMessage(clientUUID) );
/**
* If provided UUID does not exist in database returns ResponseEntity with new generated UUID(if previous UUID is not provided),
* or old UUID(if previous UUID is provided). If provided UUID exists function returns provided UUID.
* @param givenUUIDValue the UUID client wants to check exsitance in database
* @param previousUUIDValue the previous UUID used by client(optional variable)
* @return ResponseEntity with UUID
*/
@RequestMapping(
method = RequestMethod.GET ,
path = {"/check/{givenUUIDValue}/{previousUUIDValue}",
"/check/{givenUUIDValue}"})
public ResponseEntity<String> checkUUID(
@PathVariable String givenUUIDValue
,@PathVariable(required = false) String previousUUIDValue ){
try{
UUID.fromString(givenUUIDValue);
} catch (IllegalArgumentException ex){
log.error("Wrong UUID value!");
if (previousUUIDValue == null || previousUUIDValue.equals("")){
UUID newUUID = UUID.randomUUID();
log.info("New UUID generated.");
return ResponseEntity.ok(newUUID.toString());
}
log.info("Previous UUID value restored.");
return ResponseEntity.ok(previousUUIDValue);
}
return ResponseEntity.ok(givenUUIDValue);
}
/**
* Accepts empty post request and creates new message in given set. The new message has default set of data,
* which is constructed in {@link #buildDefaultMessage(UUID, int)} method.
* @param uuidValue the key-uuid of given set of messages
* @return confirmation response with 200 OK
*/
@PostMapping("/{uuidValue}")
public ResponseEntity<String> addNewMessage(@PathVariable String uuidValue){
UUID clientUUID = UUID.fromString(uuidValue);
List<MockedMessageDto> messages = klausService.getAllMockedResponses(clientUUID);
MockedMessageDto nextMessage = buildDefaultMessage(clientUUID, findNextId(messages));
return klausService.setMockedResponse(nextMessage);
}
/**
* Deletes message of given id via client request
* @param uuidValue the key-uuid of given set of messages
* @param idValue unique id of given message
* @return after deletion the confirmation is send with status 200 OK
*/
@DeleteMapping("/{uuidValue}/{idValue}")
public ResponseEntity<String> removeMessage(@PathVariable String uuidValue,
@PathVariable String idValue){
UUID clientUUID = UUID.fromString(uuidValue);
int id = Integer.parseInt(idValue);
return klausService.deleteMockedResponse(clientUUID, id);
}
/**
* Recalls {@link #buildDefaultMessage(UUID)} for message construction and sets id of message
* @param uuid the key-uuid of given set of messages
* @param id unique id of given message
* @return message with default dataset and set id
*/
private static MockedMessageDto buildDefaultMessage(UUID uuid, int id){
MockedMessageDto message = buildDefaultMessage(uuid);
message.setMockedResponseId(id);
return message;
}
/**
* Constructs message with default set of data
* @param uuid the key-uuid of given set of messages
* @return message with default dataset
*/
private static MockedMessageDto buildDefaultMessage(UUID uuid){
private MockedMessageDto buildDefaultMessage(UUID uuid){
Map<String, String> headers = new HashMap<>();
headers.put("Keep-Alive", "timeout=60");
headers.put("Connection", "keep-alive");
headers.put("Date", LocalDateTime.now().toString());
return MockedMessageDto.builder()
MockedMessageDto mockedMessageDto = MockedMessageDto.builder()
.clientUUID(uuid)
.mockedResponseId(1)
.mediaType(MediaType.APPLICATION_XML_VALUE)
.contentType(MediaType.APPLICATION_XML_VALUE)
.messageBody("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<note>\n" +
" <to>Tove</to>\n" +
@@ -158,46 +90,24 @@ public class MockController {
.httpHeaders(headers)
.httpStatus(200)
.build();
klausService.setMockedResponse(mockedMessageDto);
return mockedMessageDto;
}
/**
* Finds the highest id in the list and returns it incremented by 1
* @param messages list of messages
* @return highest id incremented by 1
*/
public static int findNextId(List<MockedMessageDto> messages) {
int highestId = 0;
for (MockedMessageDto m : messages)
highestId = highestId > m.getMockedResponseId() ? highestId : m.getMockedResponseId();
return ++highestId;
}
/**
* It's one of the most important features - the bread and butter of the Mocked Service. It's link that allows
* to receive mocked response from the server and use it to mock!
* @param requestEntity Logs the data of request
* @param clientUUID the key-uuid of given set of messages
* @param mockedResponseId unique id of given message
* @return
*/
@GetMapping(value = "/r/{clientUUID}/{mockedResponseId}")
public ResponseEntity getMockedResponse(RequestEntity<String> requestEntity,
@PathVariable UUID clientUUID,
@PathVariable int mockedResponseId) {
TrackingClient.setBusinessKeys(Map.of(BusinessKey.INTERFACE_NAME, "getMockedResponse - request",
BusinessKey.CLIENT_UUID, String.valueOf(clientUUID),
BusinessKey.MESSAGE_ID, String.valueOf(mockedResponseId)));
// log.info(requestEntity.toString().replaceAll("\"", "\\\\\"").substring(1).replaceAll("\n",""));
TrackingClient.setBusinessKeys(Map.of(BusinessKey.INTERFACE_NAME, "getMockedResponse - response",
BusinessKey.CLIENT_UUID, String.valueOf(clientUUID),
BusinessKey.MESSAGE_ID, String.valueOf(mockedResponseId)));
MockedMessageDto mockedMessageDto = klausService.getMockedResponse(clientUUID, mockedResponseId);
@RequestMapping(value = "/r/{clientUUID}")
public ResponseEntity getMockedResponse(
@PathVariable UUID clientUUID) {
MockedMessageDto mockedMessageDto = klausService.getMockedResponse(clientUUID);
HttpHeaders httpHeaders = new HttpHeaders();
if (mockedMessageDto.getHttpHeaders() != null) mockedMessageDto.getHttpHeaders().forEach(httpHeaders::set);
httpHeaders.add("Content-Type", mockedMessageDto.getMediaType());
httpHeaders.add("Content-Type", mockedMessageDto.getContentType());
return new ResponseEntity<>(mockedMessageDto.getMessageBody(), httpHeaders,
Objects.requireNonNull(HttpStatus.valueOf(mockedMessageDto.getHttpStatus())));
}
}

View File

@@ -7,6 +7,7 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.ExceptionHandler;
@@ -15,6 +16,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
* @author Rafał Żukowicz
*/
@ControllerAdvice
@CrossOrigin(origins = "*")
public class MvcExceptionHandler {
/**

View File

@@ -0,0 +1,42 @@
package com.r11.tools.controller;
import com.r11.tools.mappers.RequestHistoryMapper;
import com.r11.tools.model.RequestHistory;
import com.r11.tools.model.RequestHistoryDTO;
import com.r11.tools.service.RequestHistoryService;
import lombok.AllArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
/**
* It's the REST api for {@link RequestHistory}
* @author Gabriel Modzelewski
* @author Mikołaj Widła
*/
@RestController
@RequestMapping(path = "/api/event")
@AllArgsConstructor
@CrossOrigin(origins = "*")
public class RequestHistoryController {
private final RequestHistoryService service;
private final RequestHistoryMapper mapper;
/**
* Returns the list of Events.
* @param uuid unique id of message list
* @return list of {@link RequestHistory}
*/
@GetMapping(path = "/{uuid}")
public ResponseEntity<List<RequestHistoryDTO>> getLastDay(@PathVariable String uuid){
List<RequestHistoryDTO> requestHistory = service.getHistoryRecordsByUUID(
uuid
).stream()
.map(mapper::requestHistoryToRequestHistoryDTO)
.collect(Collectors.toList());
return ResponseEntity.ok(requestHistory);
}
}

View File

@@ -0,0 +1,78 @@
package com.r11.tools.interceptor;
import com.r11.tools.model.RequestHistoryDTO;
import com.r11.tools.service.RequestHistoryService;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.util.ContentCachingRequestWrapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
/**
* Interceptor that gets needed data from HttpRequest, and saves it to history
* @author Mikołaj Widła
*/
@Component
@AllArgsConstructor
public class IncomingMockRequestInterceptor implements HandlerInterceptor {
private final RequestHistoryService historyService;
@Override
public boolean preHandle(HttpServletRequest httpRequest, HttpServletResponse response, Object handler){
Map<String,String> headers = getHeadersFromHttpRequest(httpRequest);
Map<String,String> pathVariable = getPathVariablesFromHttpRequest(httpRequest);
String requestBody = getRequestBodyFromHttpRequest(httpRequest);
RequestHistoryDTO historyDTO = RequestHistoryDTO.builder()
.httpMethod(HttpMethod.valueOf(httpRequest.getMethod()))
.headers( headers )
.clientUUID(UUID.fromString(pathVariable.get("clientUUID")))
.dateTimeStamp(LocalDateTime.now())
.requestBody(requestBody)
.build();
historyService.saveRequest(historyDTO);
return true;
}
private Map<String,String> getHeadersFromHttpRequest( HttpServletRequest httpRequest ){
Set<String> headersName = StreamSupport.stream(
Spliterators.spliteratorUnknownSize(
httpRequest.getHeaderNames().asIterator(),
Spliterator.ORDERED
), false
).collect(Collectors.toSet());
return headersName.stream()
.collect(Collectors.toMap(
value -> value,
httpRequest::getHeader
));
}
private Map<String,String> getPathVariablesFromHttpRequest( HttpServletRequest httpRequest ){
return (Map<String, String>) httpRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
}
private String getRequestBodyFromHttpRequest( HttpServletRequest httpRequest ){
HttpServletRequest wrappedRequest = new ContentCachingRequestWrapper(httpRequest);
try {
return StreamUtils.copyToString(wrappedRequest.getInputStream(), Charset.defaultCharset());
} catch (IOException e) {
return "";
}
}
}

View File

@@ -4,14 +4,23 @@ import com.r11.tools.model.MockedMessage;
import com.r11.tools.model.MockedMessageDto;
import org.mapstruct.*;
import java.util.Optional;
/**
* Creates key value for redis entry
* @author Rafał Źukowicz
*/
@Mapper
public interface MockedMessageMapper {
@Mapping( target = "compositePrimaryKey", expression = "java(mockedMessageDto.getClientUUID() + \"_\"" +
" + mockedMessageDto.getMockedResponseId())")
@Mapping( target = "createdAt" , expression = "java(java.time.LocalDateTime.now())")
MockedMessage mockedMessageDtoToMockedMessage(MockedMessageDto mockedMessageDto);
MockedMessageDto mockedMessageToMockedMessageDto(MockedMessage mockedMessage);
default Optional<MockedMessageDto> optionalMockedMessageToOptionalMockedMessageDTO(Optional<MockedMessage> optionalMockedMessage){
return optionalMockedMessage.map(this::mockedMessageToMockedMessageDto);
}
default Optional<MockedMessage> optionalMockedMessageDTOToOptionalMockedMessage(Optional<MockedMessageDto> optionalMockedMessageDto){
return optionalMockedMessageDto.map(this::mockedMessageDtoToMockedMessage);
}
}

View File

@@ -0,0 +1,23 @@
package com.r11.tools.mappers;
import com.r11.tools.model.RequestHistory;
import com.r11.tools.model.RequestHistoryDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
/**
* Map between DTO and Entity
*
* @author Mikołaj Widła
*
*/
@Mapper
public interface RequestHistoryMapper {
@Mapping(target = "clientUUID", expression = "java(requestHistoryDTO.getClientUUID().toString())")
RequestHistory requestHistoryDTOToRequestHistory(RequestHistoryDTO requestHistoryDTO);
@Mapping(target = "clientUUID", expression = "java(java.util.UUID.fromString(requestHistory.getClientUUID()))")
RequestHistoryDTO requestHistoryToRequestHistoryDTO(RequestHistory requestHistory);
}

View File

@@ -1,36 +0,0 @@
package com.r11.tools.model;
import java.time.LocalDateTime;
import lombok.*;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.lang.Nullable;
/**
* Pojo class for Event entity
* @author Rafał Żukowicz
*/
@Data
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Event implements Comparable<Event>{
@DateTimeFormat(pattern = "yyyy-MM-ddTHH:mm:ss")
private LocalDateTime dateTimeStamp;
@Nullable
private String interfaceName;
@Nullable
private String clientUUID;
@Nullable
private Integer messageId;
private String thread;
private String level;
@Nullable
private String message;
@Override
public int compareTo(Event o) {
return this.getDateTimeStamp().compareTo(o.getDateTimeStamp()) * -1;
}
}

View File

@@ -1,10 +1,6 @@
package com.r11.tools.model;
import com.r11.tools.model.constraints.HttpCode;
import java.io.Serializable;
import java.util.Map;
import java.util.UUID;
import javax.validation.constraints.Positive;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -13,6 +9,11 @@ import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.index.Indexed;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;
/**
* MockedMessage redis entity pojo
* @author Rafał Żukowicz
@@ -23,18 +24,14 @@ import org.springframework.data.redis.core.index.Indexed;
@NoArgsConstructor
@AllArgsConstructor
public class MockedMessage implements Serializable {
@Id
private String compositePrimaryKey;
@Indexed
@Id
private UUID clientUUID;
@Positive
private Integer mockedResponseId;
private String mediaType;
private String contentType;
private String messageBody;
private Map<String, String> httpHeaders;
@HttpCode
private Integer httpStatus;
private LocalDateTime createdAt;
}

View File

@@ -1,12 +1,11 @@
package com.r11.tools.model;
import com.r11.tools.model.constraints.HttpCode;
import lombok.*;
import java.io.Serializable;
import java.util.Map;
import java.util.UUID;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import lombok.*;
/**
* Alternative version of {@link MockedMessage} used in http body
@@ -18,19 +17,12 @@ import lombok.*;
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class MockedMessageDto implements Serializable, Comparable<MockedMessageDto> {
public class MockedMessageDto implements Serializable{
private UUID clientUUID;
@NotNull
@Positive
private Integer mockedResponseId;
private String mediaType;
private String contentType;
private String messageBody;
private Map<String, String> httpHeaders;
@HttpCode
private Integer httpStatus;
@Override
public int compareTo(MockedMessageDto message) {
return this.mockedResponseId > message.getMockedResponseId() ? 1 : -1;
}
}

View File

@@ -0,0 +1,42 @@
package com.r11.tools.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.index.Indexed;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpMethod;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Map;
/**
* Pojo class for Event entity
* @author Rafał Żukowicz
* @author Mikołaj Widła
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@RedisHash("mockHistory")
public class RequestHistory implements Comparable<RequestHistory>, Serializable {
@Id
private String id;
@DateTimeFormat(pattern = "yyyy-MM-ddTHH:mm:ss")
private LocalDateTime dateTimeStamp;
@Indexed
private String clientUUID;
private Map<String,String> headers;
private HttpMethod httpMethod;
private String requestBody;
@Override
public int compareTo(RequestHistory o) {
return this.getDateTimeStamp().compareTo(o.getDateTimeStamp()) * -1;
}
}

View File

@@ -1,28 +1,32 @@
package com.r11.tools.model;
import java.time.LocalDateTime;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpMethod;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;
/**
* Pojo for history query request. Contains information necessary to obtain {@link Event} list
* Pojo for history query request. Contains information necessary to obtain {@link RequestHistory} list
* @author Rafał Żukowicz
* @author Mikołaj Widła
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EventRequestDto {
public class RequestHistoryDTO {
private UUID clientUUID;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime localDateTimeFrom;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime localDateTimeTo;
private Integer mockedResponseId;
private LocalDateTime dateTimeStamp;
private Map<String,String> headers;
private HttpMethod httpMethod;
private String requestBody;
}

View File

@@ -1,20 +0,0 @@
package com.r11.tools.repository;
import com.r11.tools.model.Event;
import com.r11.tools.utilis.BusinessKey;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
/**
* Event entity dao interface
* @author Rafał Żukowicz
*/
@Repository
@Transactional
public interface EventRepository {
List<Event> findEvents(LocalDateTime localDateTimeFrom, LocalDateTime localDateTimeTo,
Map<BusinessKey, String> businessKeys);
}

View File

@@ -1,99 +0,0 @@
package com.r11.tools.repository;
import static com.r11.tools.utilis.RedisAppender.LOG_PREFIX;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.r11.tools.model.Event;
import com.r11.tools.utilis.BusinessKey;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Repository;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
/**
* Builds Event list based on logs created via {@link com.r11.tools.utilis.TrackingClient} and {@link com.r11.tools.utilis.RedisAppender}
* @author Rafał Żukowicz
*/
@Repository
@AllArgsConstructor
public class EventRepositoryImpl implements EventRepository {
private final JedisPool jedisPool;
private final ObjectMapper objectMapper;
/**
* Creates list of {@link Event} based on {@link com.r11.tools.model.EventRequestDto} data via searching logs
* @param localDateTimeFrom date from which logs are retrieved
* @param localDateTimeTo date to which logs are retrieved
* @param businessKeys set keys for redis values
* @return
*/
@Override
public List<Event> findEvents(LocalDateTime localDateTimeFrom, LocalDateTime localDateTimeTo,
Map<BusinessKey, String> businessKeys) {
List<String> eventStrings = findEventsBetweenDates(localDateTimeFrom.toLocalDate(), localDateTimeTo.toLocalDate());
if (businessKeys.size() > 0) {
eventStrings = businessKeysFilter(eventStrings, businessKeys);
}
List<Event> events = parseEvents(eventStrings);
if (localDateTimeFrom.toLocalTime() != LocalTime.MIN) {
events = events.stream().filter(event -> event.getDateTimeStamp().compareTo(localDateTimeFrom) >= 0)
.collect(Collectors.toList());
}
return events.stream().filter(event -> event.getDateTimeStamp().compareTo(localDateTimeTo) <= 0)
.collect(Collectors.toList());
}
/**
* Returns logs between given dates
* @param localDateFrom date from which logs are retrieved
* @param localDateTo date to which logs are retrieved
* @return
*/
private List<String> findEventsBetweenDates(LocalDate localDateFrom, LocalDate localDateTo) {
try (Jedis jedis = jedisPool.getResource()) {
return localDateFrom.datesUntil(localDateTo.plusDays(1)).map(day -> LOG_PREFIX + day.toString())
.map(key -> jedis.lrange(key, 0, -1)).flatMap(Collection::stream).collect(Collectors.toList());
}
}
/**
* Filters keys so only the ones queried are retirned
* @param events list of logs
* @param businessKeys set keys for redis values
* @return filtered list of logs
*/
private List<String> businessKeysFilter(List<String> events, Map<BusinessKey, String> businessKeys) {
for (Map.Entry<BusinessKey, String> entry : businessKeys.entrySet()) {
String stringPattern = entry.getKey().getReasonPhrase()+ "\"" + ":" + "\"" + entry.getValue() + "\"";
events = events.stream().filter(s -> s.contains(stringPattern)).collect(Collectors.toList());
}
return events;
}
/**
* Parses list of logs into list of {@link Event}
* @param eventStrings list of logs
* @return list of {@link Event}
*/
private List<Event> parseEvents(List<String> eventStrings) {
List<Event> events = new ArrayList<>();
for (String eventString : eventStrings) {
eventString = eventString.replaceAll("\\R", "");
try {
events.add(objectMapper.readValue(eventString, Event.class));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
return events;
}
}

View File

@@ -14,11 +14,11 @@ import org.springframework.transaction.annotation.Transactional;
*/
@Repository
@Transactional
public interface MockedResponseRepository extends CrudRepository<MockedMessage, String> {
public interface MockedResponseRepository extends CrudRepository<MockedMessage, UUID> {
/**
* Finds all messages by their uuid
* @param clientUUID the key-uuid of given set of messages
* @return Optional of list of {@link com.r11.tools.model.MockedMessage}
*/
Optional<List<MockedMessage>> findAllByClientUUID(UUID clientUUID);
Optional<MockedMessage> findAllByClientUUID(UUID clientUUID);
}

View File

@@ -0,0 +1,18 @@
package com.r11.tools.repository;
import com.r11.tools.model.RequestHistory;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* History Record entity dao interface
* @author Rafał Żukowicz
*/
@Repository
@Transactional
public interface RequestHistoryRepository extends CrudRepository<RequestHistory,String> {
List<RequestHistory> findAllByClientUUID(String clientUUID);
}

View File

@@ -1,20 +0,0 @@
package com.r11.tools.service;
import com.r11.tools.model.Event;
import com.r11.tools.model.EventRequestDto;
import java.util.List;
import org.springframework.stereotype.Service;
/**
* Spring service interface for {@link com.r11.tools.controller.EventController}
* @author Rafał Żukowicz
*/
@Service
public interface EtrackService {
/**
* Searches for {@link Event} objects between date brackets
* @param eventsDto object containing required data for request
* @return list of {@link Event}
*/
List<Event> getEventsByDateTimeAndBusinessKeys(EventRequestDto eventsDto);
}

View File

@@ -1,44 +0,0 @@
package com.r11.tools.service;
import com.r11.tools.model.Event;
import com.r11.tools.model.EventRequestDto;
import com.r11.tools.repository.EventRepository;
import com.r11.tools.utilis.BusinessKey;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Spring Service for {@link com.r11.tools.controller.EventController}. Contains logic required for quering
* the database for {@link Event} objects
* @author Rafał Żukowicz
*/
@Service
@AllArgsConstructor
public class EtrackServiceImpl implements EtrackService {
private final EventRepository eventRepository;
/**
* Adds {@link BusinessKey} to {@link EventRequestDto}
* in order to create query via{@link com.r11.tools.repository.EventRepositoryImpl}
* @param eventsDto object containing required data for request
* @return list of {@link Event}
*/
@Override
public List<Event> getEventsByDateTimeAndBusinessKeys(EventRequestDto eventsDto) {
Map<BusinessKey, String> businessKeys = new HashMap<>();
businessKeys.put(BusinessKey.CLIENT_UUID, eventsDto.getClientUUID().toString());
if (eventsDto.getMockedResponseId() != null){
businessKeys.put(BusinessKey.MESSAGE_ID, String.valueOf(eventsDto.getMockedResponseId()));
}
List<Event> events = eventRepository.findEvents(eventsDto.getLocalDateTimeFrom(), eventsDto.getLocalDateTimeTo(),
businessKeys);
Collections.sort(events);
return events;
}
}

View File

@@ -1,7 +1,8 @@
package com.r11.tools.service;
import com.r11.tools.model.MockedMessageDto;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
@@ -12,8 +13,7 @@ import org.springframework.stereotype.Service;
*/
@Service
public interface KlausService {
ResponseEntity<String> deleteMockedResponse(UUID clientUUID, int mockedResponseId);
List<MockedMessageDto> getAllMockedResponses(UUID clientUUID);
MockedMessageDto getMockedResponse(UUID clientUUID, int mockedResponseId);
Optional<MockedMessageDto> getMockedMessageByClientUUID(UUID clientUUID);
MockedMessageDto getMockedResponse(UUID clientUUID);
ResponseEntity<String> setMockedResponse(MockedMessageDto mockedMessageDto);
}

View File

@@ -1,6 +1,5 @@
package com.r11.tools.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.r11.tools.mappers.MockedMessageMapper;
import com.r11.tools.model.MockedMessage;
import com.r11.tools.model.MockedMessageDto;
@@ -13,16 +12,16 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* Service for {@link com.r11.tools.controller.MockController} and {@link com.r11.tools.controller.MockController}
* Allows for performing CRUD operations on {@link MockedMessageDto}
* @author Rafał Żukowicz
* @author Gabriel Modzelewski
* @author Mikołaj Widła
*/
@Service
@AllArgsConstructor
@@ -30,22 +29,7 @@ public class KlausServiceImpl implements KlausService {
private final MockedMessageMapper mockedMessageMapper;
private final Logger log = LogManager.getRootLogger();
private final MockedResponseRepository mockedResponseRepository;
private final ObjectMapper objectMapper;
/**
* Removes message of given id in given key-uuid set
* @param clientUUID the key-uuid of given set of messages
* @param mockedResponseId unique id of given message
* @return confirmation and status 200 OK
*/
@Override
public ResponseEntity<String> deleteMockedResponse(UUID clientUUID, int mockedResponseId) {
String key = clientUUID.toString() + "_" + mockedResponseId;
mockedResponseRepository.deleteById(key);
log.info("Message: "+mockedResponseId+" has been removed.");
return new ResponseEntity<>("MockedResponse has been removed successfully",
new HttpHeaders(), HttpStatus.ACCEPTED);
}
/**
* Returns all messages of given key-uuid
@@ -53,28 +37,23 @@ public class KlausServiceImpl implements KlausService {
* @return List of {@link MockedMessageDto}
*/
@Override
public List<MockedMessageDto> getAllMockedResponses(UUID clientUUID){
Optional<List<MockedMessage>> listOptional = mockedResponseRepository.findAllByClientUUID(clientUUID);
log.info("Messages for UUID: "+clientUUID+" has been fetched from DB.");
return listOptional.map(mockedMessages -> mockedMessages.stream()
.map(mockedMessageMapper::mockedMessageToMockedMessageDto)
.collect(Collectors.toList())).orElse(List.of());
public Optional<MockedMessageDto> getMockedMessageByClientUUID(UUID clientUUID){
Optional<MockedMessage> mockedMessageOptional = mockedResponseRepository.findAllByClientUUID(clientUUID);
log.info("Message for UUID: "+clientUUID+" has been fetched from DB.");
return mockedMessageMapper.optionalMockedMessageToOptionalMockedMessageDTO(mockedMessageOptional);
}
/**
* Returns {@link MockedMessageDto} of given id and key-uuid. If message doesn't then empty message is returned
* @param clientUUID the key-uuid of given set of messages
* @param mockedResponseId unique id of given message
* @return {@link MockedMessageDto} object
*/
@SneakyThrows
@Override
public MockedMessageDto getMockedResponse(UUID clientUUID, int mockedResponseId){
String key = clientUUID.toString() + "_" + mockedResponseId;
Optional<MockedMessage> optionalMockedMessage = mockedResponseRepository.findById(key);
public MockedMessageDto getMockedResponse(UUID clientUUID){
Optional<MockedMessage> optionalMockedMessage = mockedResponseRepository.findById(clientUUID);
MockedMessageDto mockedMessageDto = MockedMessageDto.builder()
.clientUUID(clientUUID)
.mockedResponseId(mockedResponseId)
.build();
if (optionalMockedMessage.isPresent()) {
mockedMessageDto = mockedMessageMapper.mockedMessageToMockedMessageDto(optionalMockedMessage.get());

View File

@@ -0,0 +1,23 @@
package com.r11.tools.service;
import com.r11.tools.controller.RequestHistoryController;
import com.r11.tools.model.RequestHistory;
import com.r11.tools.model.RequestHistoryDTO;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* Spring service interface for {@link RequestHistoryController}
* @author Rafał Żukowicz
*/
@Service
public interface RequestHistoryService {
/**
* Searches for {@link RequestHistory} objects between date brackets
* @param uuid user uuid
* @return list of {@link RequestHistory}
*/
List<RequestHistory> getHistoryRecordsByUUID(String uuid);
void saveRequest(RequestHistoryDTO requestDTO);
}

View File

@@ -0,0 +1,38 @@
package com.r11.tools.service;
import com.r11.tools.controller.RequestHistoryController;
import com.r11.tools.mappers.RequestHistoryMapper;
import com.r11.tools.model.RequestHistory;
import com.r11.tools.model.RequestHistoryDTO;
import com.r11.tools.repository.RequestHistoryRepository;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
/**
* Spring Service for {@link RequestHistoryController}. Contains logic required for quering
* the database for {@link RequestHistory} objects
* @author Rafał Żukowicz
* @author Mikołaj Widła
*/
@Service
@AllArgsConstructor
public class RequestHistoryServiceImpl implements RequestHistoryService {
private final RequestHistoryRepository repository;
private final RequestHistoryMapper requestMapper;
@Override
public List<RequestHistory> getHistoryRecordsByUUID(String uuid) {
List<RequestHistory> history = repository.findAllByClientUUID(uuid);
Collections.sort(history);
return history;
}
@Override
public void saveRequest(RequestHistoryDTO requestDTO) {
repository.save(requestMapper.requestHistoryDTOToRequestHistory(requestDTO));
}
}

View File

@@ -1,24 +0,0 @@
package com.r11.tools.utilis;
import lombok.AllArgsConstructor;
/**
* Enum of keys for redis database.
* @author Rafał Żukowicz
*/
@AllArgsConstructor
public enum BusinessKey {
INTERFACE_NAME("interfaceName"),
CLIENT_UUID("clientUUID"),
MESSAGE_ID("messageId");
private final String phrase;
/**
* Returns string value of given enum variant
* @return string value of enum
*/
public String getReasonPhrase() {
return this.phrase;
}
}

View File

@@ -1,235 +0,0 @@
package com.r11.tools.utilis;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Layout;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import com.cwbase.logback.AdditionalField;
import com.cwbase.logback.JSONEventLayout;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Iterator;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Protocol;
/**
* Class is used to insert logs directly to Redis. {@link com.release11.klaus.repository.EventRepositoryImpl} is using those logs.
* @author Rafał Żukowicz
* @author Gabriel Modzelewski
*/
public class RedisAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
JedisPool pool;
JSONEventLayout jsonlayout;
Layout<ILoggingEvent> layout;
String host = "localhost";
int port = Protocol.DEFAULT_PORT;
String key = null;
int timeout = Protocol.DEFAULT_TIMEOUT;
String password = null;
int database = Protocol.DEFAULT_DATABASE;
public static final String LOG_PREFIX = "logstash_";
public RedisAppender() {
jsonlayout = new JSONEventLayout();
}
/**
* Appends JedisPool by another log
* @param event object containing log info
*/
@Override
protected void append(ILoggingEvent event) {
Jedis client = pool.getResource();
try {
String json = layout == null ? jsonlayout.doLayout(event) : layout.doLayout(event);
key = LOG_PREFIX + LocalDate.now();
client.rpush(key, json);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (client != null) {
client.close();
}
}
}
@Deprecated
public String getSource() {
return jsonlayout.getSource();
}
@Deprecated
public void setSource(String source) {
jsonlayout.setSource(source);
}
@Deprecated
public String getSourceHost() {
return jsonlayout.getSourceHost();
}
@Deprecated
public void setSourceHost(String sourceHost) {
jsonlayout.setSourceHost(sourceHost);
}
@Deprecated
public String getSourcePath() {
return jsonlayout.getSourcePath();
}
@Deprecated
public void setSourcePath(String sourcePath) {
jsonlayout.setSourcePath(sourcePath);
}
@Deprecated
public String getTags() {
if (jsonlayout.getTags() != null) {
Iterator<String> i = jsonlayout.getTags().iterator();
StringBuilder sb = new StringBuilder();
while (i.hasNext()) {
sb.append(i.next());
if (i.hasNext()) {
sb.append(',');
}
}
return sb.toString();
}
return null;
}
@Deprecated
public void setTags(String tags) {
if (tags != null) {
String[] atags = tags.split(",");
jsonlayout.setTags(Arrays.asList(atags));
}
}
@Deprecated
public String getType() {
return jsonlayout.getType();
}
@Deprecated
public void setType(String type) {
jsonlayout.setType(type);
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getDatabase() {
return database;
}
public void setDatabase(int database) {
this.database = database;
}
@Deprecated
public void setMdc(boolean flag) {
jsonlayout.setProperties(flag);
}
@Deprecated
public boolean getMdc() {
return jsonlayout.getProperties();
}
@Deprecated
public void setLocation(boolean flag) {
jsonlayout.setLocationInfo(flag);
}
@Deprecated
public boolean getLocation() {
return jsonlayout.getLocationInfo();
}
@Deprecated
public void setCallerStackIndex(int index) {
jsonlayout.setCallerStackIdx(index);
}
@Deprecated
public int getCallerStackIndex() {
return jsonlayout.getCallerStackIdx();
}
@Deprecated
public void addAdditionalField(AdditionalField p) {
jsonlayout.addAdditionalField(p);
}
public Layout<ILoggingEvent> getLayout() {
return layout;
}
public void setLayout(Layout<ILoggingEvent> layout) {
this.layout = layout;
}
/**
* Starts new instance of JedisPool
*/
@Override
public void start() {
super.start();
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setTestOnBorrow(true);
pool = new JedisPool(config, host, port, timeout, password, database);
}
/**
* Stops and destroys JedisPool object
*/
@Override
public void stop() {
super.stop();
pool.destroy();
}
}

View File

@@ -1,24 +0,0 @@
package com.r11.tools.utilis;
import java.util.Map;
import org.slf4j.MDC;
/**
* This static class has one purpose and one purpose only. It logs data about incomming requests.
* The data from logs is received via {@link com.release11.klaus.repository.EventRepositoryImpl}
* @author Rafał Żukowski
*/
public final class TrackingClient {
/**
* Logs data inside the given map
* @param businessKeysMap map containing all the information about incomming request
*/
public static void setBusinessKeys(Map<BusinessKey, String> businessKeysMap){
for (Map.Entry<BusinessKey, String> entry : businessKeysMap.entrySet()) {
MDC.put(entry.getKey().getReasonPhrase(), entry.getValue());
}
}
}

View File

@@ -5,3 +5,12 @@ spring.mvc.view.suffix=.html
logging.level.root=INFO
logging.level.org.springframework.web=INFO
logging.level.com.release11=INFO
#database:
spring.redis.host=redis
spring.redis.port=6379
#retention
retention.minutes-to-delete-message=120
retention.minutes-to-delete-history-record=1440
retention.retention-cooldown=1440

View File

@@ -1,2 +0,0 @@
redis.host = redis
redis.port = 6379

View File

@@ -2,25 +2,8 @@
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<property name="HOME_LOG" value="/log/mockServices.log"/>
<!--https://github.com/kmtong/logback-redis-appender-->
<appender name="LOGSTASH" class="com.r11.tools.utilis.RedisAppender">
<host>redis</host>
<port>6379</port>
<key>logstash</key>
<layout class="ch.qos.logback.classic.PatternLayout">
<!--https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html-->
<Pattern>
{"dateTimeStamp" : "%d{yyyy-MM-dd}T%d{HH:mm:ss}", "eventId":"%X{eventId}", "interfaceName":"%X{interfaceName}", "clientUUID":"%X{clientUUID}", "messageId":"%X{messageId}", "thread":"%t","level":"%-5level", "message":"%msg"}%n
</Pattern>
</layout>
</appender>
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="LOGSTASH" />
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${HOME_LOG}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/mockServices.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
@@ -34,7 +17,6 @@
</appender>
<root level="DEBUG">
<appender-ref ref="ASYNC" />
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>

View File

@@ -1,541 +0,0 @@
var clientUUID = '';
var advancedDisplayed = false;
var json = {};
var jsonIndex = 0;
var lastId = 1;
var htable_row = 0;
var host = getDomain();
var dataModified = false;
const addMessageName = 'addMessage';
const loadMessageName = 'changeMessage';
const removeMessageName = 'removeMessage';
const C_UUID = 'mock-uuid';
const C_ID = 'last-displayed-id';
const C_ADV = 'advanced-mode';
const color_red = "#ff8f8f";
const color_grey = "#6b6b6b";
const setModified = function(){
setDataModified();
}
const setOrigin = function(){
setDataOrigin();
}
const getUpdate = function(){
updateData();
}
const dataRefresh = function(){
getData();
}
$('#btn-newtile').click(function(){callAddMessage()});
// $('#btn-addRow').click(function(){addRow()});
// $('#btn-save').click(getUpdate);
function getData(){
$.getJSON(host + '/api/mock/'+clientUUID, function(data) {
json = data;
checkUuid();
refreshData();
});
}
function checkUuid(){
if(clientUUID == null || clientUUID == undefined || clientUUID == ''){
clientUUID = json[0].clientUUID;
setCookie();
}
}
function getDomain(){
var url = window.location.href;
var arr = url.split("/");
var result = arr[0] + "//" + arr[2];
return result;
}
function httpStatusInvalid(){
value = $('#httpStatus').val();
return value == '';
}
function setDataModified(){
if(httpStatusInvalid()){
$('#btn-save').removeClass('active');
$('#btn-save').off();
document.getElementById("httpStatus").style.backgroundColor = color_red;
return;
}
dataModified = true;
$('#btn-save').addClass('active');
$('#btn-save').click(getUpdate);
document.getElementById("httpStatus").style.backgroundColor = null;
}
//Adding change listener to fields
$('.data-field').change(setModified);
function setDataOrigin(){
dataModified = false;
$('#btn-save').removeClass('active');
$('#btn-save').off();
}
const idToDisplay = function(){
let defaultId = json[0].mockedResponseId;
if(lastId == undefined || lastId == null) return defaultId;
for(let i=0; i<json.length; i++){
if(json[i].mockedResponseId == lastId){
return lastId;
}
}
if(jsonIndex <= json.length && jsonIndex > 0){
jsonIndex -= 1;
return json[jsonIndex].mockedResponseId;
}
return defaultId;
}
function refreshData(){
$("#uuid-input").val(clientUUID);
fillMessageList();
let id = idToDisplay();
loadMessage(id);
}
function setCookie(){
document.cookie = C_UUID + '=' +clientUUID;
document.cookie = C_ID + '=' + lastId;
document.cookie = C_ADV + '=' + advancedVisibility;
}
function loadCookies(){
clientUUID = getCookie(C_UUID);
lastId = getCookie(C_ID);
advancedDisplayed = getCookie(C_ADV) == 'true';
}
function getCookie(cname) {
var name = cname + '=';
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for(var i = 0; i <ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return '';
}
function callMethodByName(methodObject){
let name = methodObject.name;
let id = methodObject.id;
switch(name){
case addMessageName:
addMessage();
break;
case loadMessageName:
loadMessage(id);
break;
case removeMessageName:
removeMessage(id);
break;
}
}
function updateData(){
var updatedJson = generateJson();
const dataSaved = function () {
setDataOrigin();
refreshData();
savedModalDisplay();
}
$.ajax({
url: host + '/api/mock',
type: 'PUT',
data: JSON.stringify(updatedJson, null, 2),
contentType: "application/json",
}).done(dataSaved);
}
function callAddMessage(){
if(dataModified){
setMethodToCall(addMessageName, null);
dataLossModalDisplay();
}
else {
addMessage();
}
}
function addMessage(){
$.ajax({
url: host + '/api/mock/'+clientUUID,
type: 'POST',
}).done(dataRefresh);
}
function callRemoveMessage(id){
if(dataModified){
setMethodToCall(removeMessageName, id);
dataLossModalDisplay();
}
else {
removeMessage(id);
}
}
function removeMessage(id){
var jsonObject = findJsonById(id);
$.ajax({
url: host + '/api/mock/'+clientUUID + '/' + id,
type: 'DELETE',
}).done(dataRefresh);
}
function clearMock(){
fillStaticFields('','','','');
htable_row = 0;
$('#httpStatusValues').html('');
}
function initializeMock(index){
clearMock();
fillStaticFields(json[index].clientUUID
, json[index].mockedResponseId
, json[index].mediaType
, json[index].messageBody
, json[index].httpStatus);
fillHeaderTable(json[index].httpHeaders);
}
function fillStaticFields(uuid, id, mediaType, body, httpStatus){
let link = createLink(uuid,id);
let linkHtml = '<a class="hyperlink" target="_blank" href="'+link+'">'+link+'</a>';
$('#messageLink').html(linkHtml);
$('#httpStatus').val(httpStatus);
$('#uuid-input').val(uuid);
$('#typeSelector').val(mediaType);
$('#bodyEditor').val(body);
$('#mockedMessageId').html(id);
}
function changeEditionOfUUID(element){
var inputFieldId= "#uuid-input"
var inputFieldDiv = "#uuid-edit-field"
if(element.checked){
$(inputFieldId).removeAttr('disabled');
$(inputFieldDiv).removeClass('disabled');
} else{
$(inputFieldId).attr('disabled', true);
$(inputFieldDiv).addClass('disabled');
}
}
function copyUUIDToClipboard(){
navigator.clipboard.writeText( document.getElementById('uuid-input').value );
}
async function fetchUUIDCheck(givenUUID , strategy){
var newUUID = "UUID" ;
url = host + "/api/mock/check/";
switch(strategy){
case "new":{
await fetch(url + givenUUID+ "/", { method : "GET" })
.then ( response => response.text() )
.then ( data => {
newUUID = data;
} )
break;
}
case "restore":{
await fetch(url + givenUUID + "/" + clientUUID + "/" , { method: "GET" })
.then (response => response.text() )
.then (data => {
newUUID = data;
} )
break;
}
}
return newUUID ;
}
function checkUUIDChars(uuid) {
uuid.replace(/ /g,'')
const regex = new RegExp("^[A-z0-9-]+$");
if(regex.test(uuid) && uuid != ""){
return uuid ;
}
return "invalid";
}
function changeUUID(element){
const uuidStrategy = $('input[name="uuid-validation-type"]:checked').val();
const givenUUID = checkUUIDChars(element.value);
if( givenUUID == clientUUID ){
$("#uuid-input").attr("disabled", true);
uuidChangeModalDisplay("noChg");
return;
}
var newUUID = fetchUUIDCheck(givenUUID , uuidStrategy);
var changeMessage = uuidStrategy;
newUUID
.then( data => {
if (givenUUID == data) {
changeMessage = "success";
}
clientUUID = data;
$("#editable").attr("checked", false);
uuidChangeModalDisplay(changeMessage);
document.cookie = C_UUID + '=' + data ;
} )
loadCookies();
refreshData();
}
function createLink(uuid, id){
var link = host + '/api/mock/r/'+uuid+'/'+id;
return link;
}
function fillHeaderTable(headers){
var innerHTML = buildHeaderMapHtml(headers);
refreshHeaderTable(innerHTML);
}
function refreshHeaderTable(html){
$('#headerMapTable').html(html);
$('.table-map').change(function(){setDataModified()});
$('.btn-hashmap').click(function(){
$(this).closest('tr').remove();
setDataModified();
})
}
function buildHeaderMapHtml(headers){
var innerHTML = '';
for(var key in headers){
innerHTML += buildRowHtml(key, headers[key]);
}
return innerHTML;
}
function addRow(key, value){
var headerMap = $('#headerMapTable');
var headersMapHtml = headerMap.html();
headersMapHtml += buildRowHtml(key, value);
refreshHeaderTable(headersMapHtml);
}
const newRowInput = function(){
const hName = $('#headerKeyInput');
const hValue = $('#headerValueInput');
if(checkIfInputValid(hName.val()) && checkIfInputValid(hValue.val())){
addRow(hName.val(), hValue.val());
hName.val(null);
hValue.val(null);
setDataModified();
}
}
$('#btn-newRow').click(newRowInput);
function checkIfInputValid(input){
return !(input == '' || input == null || input == undefined);
}
function checkIfHeaderEssential(key){
if( key == "Connection" || key == "Keep-Alive" || key == "Date" ){
return true;
}
return false;
}
function buildRowHtml(key, value){
if(checkIfHeaderEssential(key)){
return '' +
'<tr>' +
'<td><input class="key data-field" value="' + key + '" readonly></td>' +
'<td><input class="data-field" value="' + value + '"></td>' +
'</tr>';
}
return '' +
'<tr>' +
'<td><input class="key data-field" value="' + key + '"></td>' +
'<td><input class="data-field" value="' + value + '"></td>' +
'<td><button class="modification-button btn-hashmap"><i class="icon-cancel"></i></button></td>' +
'</tr>';
}
function fillMessageList(){
$("#listItems").html('');
var innerHTML = '';
for(let i=0; i<json.length; i++){
innerHTML += generateMessageTileHtml(json[i].mockedResponseId, json[i].httpStatus, json[i].mediaType);
}
$("#listItems").append(innerHTML);
$('.tile').click(function(e) {
var element = $(this);
var button = element.find('.btn-tile').children().get(0);
if(!(button == e.target)){
callLoadMessage(parseInt($(this).attr('tileid')));
}
});
$('.btn-tile').click(function(){
//
callRemoveMessage($(this).closest('.tile').attr('tileId'));
})
}
function findJsonById(id){
return json[findJsonIndexById(id)];
}
function findJsonIndexById(id){
for(let i=0; i<json.length; i++)
if(id == json[i].mockedResponseId) return i;
}
function callLoadMessage(id){
if(dataModified) {
setMethodToCall(loadMessageName, id);
dataLossModalDisplay();
}
else {
loadMessage(id);
}
}
function loadMessage(id){
if(id == null || id == undefined){
return;
}
lastId = id;
setCookie();
setDataOrigin();
for(let i=0; i<json.length; i++){
if(id == json[i].mockedResponseId){
jsonIndex = i;
initializeMock(jsonIndex);
selectMessage(id);
return;
}
}
}
function selectMessage(id){
const tiles = $('.tile');
tiles.removeClass("active");
$('.tile[tileid="'+id+'"]').addClass("active");
initializeHistory();
refreshHeaderTable(innerHTML);
}
function generateMessageTileHtml(id, httpStatus, mediaType){
var innerHTML = '' +
'<div tileid="' + id + '" class="tile">' +
'<div class="content">' +
'<div class="display-space-between">' +
'<div class="centered-vertically">' +
'<p>Id: ' + id + '</p>' +
'<p>Status: ' + httpStatus + '</p>' +
'</div>' +
'<div>' +
'<button class="modification-button btn-tile"><i class="icon-cancel"></i></button>' +
'</div>' +
'</div>' +
'</div>' +
'</div>';
return innerHTML;
}
const onbuild = function(){
loadCookies();
getData();
if(advancedDisplayed) {
changeAdvancedVisibility();
}
}
$(document).ready(onbuild);
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function generateJson(){
var newJson =
{
clientUUID: json[jsonIndex].clientUUID,
mockedResponseId: json[jsonIndex].mockedResponseId,
mediaType: $('#typeSelector').val(),
messageBody: $('#bodyEditor').val(),
httpStatus: $('#httpStatus').val(),
httpHeaders: {},
};
newJson['httpHeaders'] = convertTableToJson();
json[jsonIndex] = newJson;
return newJson;
}
function convertTableToJson(){
const rows = $('#headerMapTable').children();
var obj = {};
var key;
for(let i=0; i<rows.length; i++){
key = rows.eq(i).children().eq(0).children().eq(0).val();
obj[key] = rows.eq(i).children().eq(1).children().eq(0).val();
}
return obj;
}

View File

@@ -1,58 +0,0 @@
var historyJson = {};
const maxIterations = 200;
function filterHistory(){
var dateFrom = new Date($('#historyFrom').val() + 'T' + $('#historyTimeFrom').val());
var dateTo = new Date($('#historyTo').val() + 'T' + $('#historyTimeTo').val());
loadHistory(dateFrom, dateTo);
}
const startSearch = function(){
filterHistory();
}
$('#btn-searchHistory').click(startSearch);
function loadHistory(dateFrom, dateTo){
var eventRequest = {
clientUUID : json[jsonIndex].clientUUID,
localDateTimeFrom : dateFrom,
localDateTimeTo : dateTo,
mockedResponseId : json[jsonIndex].mockedResponseId
};
$.ajax({
url: host + '/api/event',
type: 'POST',
data: JSON.stringify(eventRequest, null, 2),
contentType: "application/json"
}).done(function(data){
historyJson = data;
displayHistory();
});
}
function getLast24hHistoryData(){
$.getJSON(host + '/api/event/' + clientUUID + '/' + lastId, function(data){
historyJson = data;
displayHistory();
});
}
function historyToHtml(){
var innerHTML = '';
var iterations = historyJson.length <= maxIterations ? historyJson.length : maxIterations;
for(let i=0; i<iterations; i++){
let style = i%2==0 ? ' class="even"' : '';
innerHTML += '<tr' + style + '>' +
'<td>' + historyJson[i].dateTimeStamp + '</td>' +
'<td>' + historyJson[i].interfaceName + '</td>' +
'</tr>';
}
return innerHTML;
}
function displayHistory(){
$('#historyTable tbody').html(historyToHtml());
}

View File

@@ -1,141 +0,0 @@
var advancedVisibility = false;
var selectMenu = $("#selectMenuContent");
var advancedTab = $("#advanced");
var basicID = $("#basicItemData")
var advancedID = $("#advancedItemData");
var advancedUUIDOptions = $("#uuid-validation-strategy");
var focusedField = false;
function changeAdvancedVisibility(){
if(advancedVisibility){
selectMenu.removeClass('active');
advancedTab.removeClass('active');
advancedID.removeClass('active');
advancedUUIDOptions.removeClass('active');
basicID.addClass('active');
advancedVisibility = false;
}
else {
selectMenu.addClass('active');
advancedTab.addClass('active');
advancedID.addClass('active');
advancedUUIDOptions.addClass('active');
basicID.removeClass('active');
advancedVisibility = true;
}
setCookie();
}
const historyFilter = $('#history-filter');
const historyFilterSwitch = function(){
historyFilter.toggleClass('active');
}
$("#optional").click(changeAdvancedVisibility);
$('#historyTab').click(showHistory);
$('#btn-history-filter').click(historyFilterSwitch);
const tabitem = $('.tabitem');
function showHistory(){
$('#headersTab').click(showHeaders);
tabitem.removeClass('active');
$('.tabcontent').removeClass('active');
$('#history').addClass('active');
$('#historyTab').addClass('active');
$('#historyTab').off('click');
initializeHistory();
}
function initializeHistory(){
historyFilter.removeClass('active');
getLast24hHistoryData();
}
function showHeaders(){
$('#historyTab').click(showHistory);
tabitem.removeClass('active');
$('.tabcontent').removeClass('active');
$('#headers').addClass('active');
$('#headersTab').addClass('active');
$('#headersTab').off('click');
}
function focusInTip(element){
showTip(element);
focusedField = true;
}
function focusOutTip(element){
focusedField = false;
hidTip(element);
}
function hidTip(element){
if(focusedField) return;
$('#'+element).removeClass('active');
}
function showTip(element){
if(focusedField) return;
$('.tip').removeClass('active');
$('#'+element).addClass('active');
}
$('#messageLink').mouseover(function(){showTip('messageLinkTip')});
$('#messageLink').mouseleave(function(){hidTip('messageLinkTip')});
$('#httpStatus').mouseover(function(){showTip('httpStatusTip')});
$('#httpStatus').focusin(function(){focusInTip('httpStatusTip')});
$('#httpStatus').mouseleave(function(){hidTip('httpStatusTip')});
$('#httpStatus').focusout(function(){focusOutTip('httpStatusTip')});
$('#typeSelector').mouseover(function(){showTip('typeSelectorTip')});
$('#typeSelector').focusin(function(){focusInTip('typeSelectorTip')});
$('#typeSelector').mouseleave(function(){hidTip('typeSelectorTip')});
$('#typeSelector').focusout(function(){focusOutTip('typeSelectorTip')});
$('#bodyEditor').mouseover(function(){showTip('bodyEditorTip')});
$('#bodyEditor').focusin(function(){focusInTip('bodyEditorTip')});
$('#bodyEditor').mouseleave(function(){hidTip('bodyEditorTip')});
$('#bodyEditor').focusout(function(){focusOutTip('bodyEditorTip')});
$('#headersTab').mouseover(function(){showTip('headersTabTip')});
$('#headersTab').mouseleave(function(){hidTip('headersTabTip')});
$('#historyTab').mouseover(function(){showTip('historyTabTip')});
$('#historyTab').mouseleave(function(){hidTip('historyTabTip')});
$('#headerKeyInput').mouseover(function(){showTip('newHeaderTip')});
$('#headerKeyInput').focusin(function(){focusInTip('newHeaderTip')});
$('#headerKeyInput').mouseleave(function(){hidTip('newHeaderTip')});
$('#headerKeyInput').focusout(function(){focusOutTip('newHeaderTip')});
$('#headerValueInput').mouseover(function(){showTip('newHeaderTip')});
$('#headerValueInput').focusin(function(){focusInTip('newHeaderTip')});
$('#headerValueInput').mouseleave(function(){hidTip('newHeaderTip')});
$('#headerValueInput').focusout(function(){focusOutTip('newHeaderTip')});
$('#btnSave').mouseover(function(){showTip('btnSaveTip');});
$('#btnSave').focusin(function(){focusInTip('btnSaveTip')});
$('#btnSave').mouseleave(function(){hidTip('btnSaveTip')});
$('#btnSave').focusout(function(){focusOutTip('btnSaveTip')});
$('#new-tile').mouseover(function(){showTip('btn-newTileTip');});
$('#new-tile').mouseleave(function(){hidTip('btn-newTileTip')});
$('#new-tile').focusout(function(){focusOutTip('btn-newTileTip')});
$('#listItems').mouseover(function(){showTip('messagesTip');});
$('#listItems').mouseleave(function(){hidTip('messagesTip')});
$('#uuid-edit-field').mouseover(function(){ showTip('UUIDFieldTip') });
$('#uuid-edit-field').mouseleave(function(){ hidTip('UUIDFieldTip') });
$('#uuid-validation-strategy').mouseover(function(){ showTip('UUIDValidationStrategyTip') });
$('#uuid-validation-strategy').mouseleave(function(){ hidTip('UUIDValidationStrategyTip') });
$('#editableBlock').mouseover( function(){ showTip('UUIDEditionTip') } );
$('#editableBlock').mouseleave(function(){ hidTip('UUIDEditionTip') });

View File

@@ -8,6 +8,9 @@ import com.r11.tools.controller.XPathController;
import com.r11.tools.controller.XsdController;
import com.r11.tools.controller.XsltController;
import com.r11.tools.controller.internal.RestControllerRegistry;
import com.r11.tools.xml.Saxon;
import com.r11.tools.xml.Xalan;
import com.r11.tools.xml.XmlEngine;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import spark.Spark;
@@ -35,12 +38,15 @@ public class SparkApplication {
Gson jsongson = new GsonBuilder()
.disableHtmlEscaping()
.create();
XmlEngine saxon = new Saxon();
XmlEngine xalan = new Xalan();
RestControllerRegistry registry = new RestControllerRegistry();
registry.registerController(new ProcessorInfoController(logger));
registry.registerController(new XsdController(gson, logger));
registry.registerController(new XPathController(gson, logger));
registry.registerController(new XsltController(gson, logger));
registry.registerController(new ProcessorInfoController(logger, saxon, xalan));
registry.registerController(new XsdController(gson, logger, xalan));
registry.registerController(new XPathController(gson, logger, saxon, xalan));
registry.registerController(new XsltController(gson, logger, saxon, xalan));
registry.registerController(new JsonController(gson, jsongson, logger));
registry.register();

View File

@@ -1,8 +1,7 @@
package com.r11.tools.controller;
import com.google.gson.Gson;
import com.google.gson.*;
//import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.r11.tools.controller.internal.GlobalControllerManifest;
import com.r11.tools.controller.internal.HandlerType;
import com.r11.tools.controller.internal.RestController;
@@ -11,6 +10,9 @@ import spark.Request;
import spark.Response;
import org.apache.logging.log4j.Logger;
import java.util.List;
import java.util.Map;
@GlobalControllerManifest(path = "/json")
public class JsonController implements RestController {
@@ -32,9 +34,7 @@ public class JsonController implements RestController {
JsonObject responseJson = new JsonObject();
try {
JsonObject requestJson = this.gson.fromJson(request.body(), JsonObject.class);
response.status(200);
Object requestJson = this.gson.fromJson(request.body(), Object.class);
responseJson.addProperty("data", this.prettyGson.toJson(requestJson));
responseJson.addProperty("time", System.currentTimeMillis() - startProcess);
@@ -61,7 +61,7 @@ public class JsonController implements RestController {
JsonObject responseJson = new JsonObject();
try {
JsonObject requestJson = this.prettyGson.fromJson(request.body(), JsonObject.class);
Object requestJson = this.prettyGson.fromJson(request.body(), Object.class);
response.status(200);

View File

@@ -5,6 +5,7 @@ import com.r11.tools.controller.internal.HandlerType;
import com.r11.tools.controller.internal.RestController;
import com.r11.tools.controller.internal.ScopedControllerManifest;
import com.r11.tools.xml.Saxon;
import com.r11.tools.xml.XmlEngine;
import org.apache.logging.log4j.Logger;
import spark.Request;
import spark.Response;
@@ -13,9 +14,13 @@ import spark.Response;
public class ProcessorInfoController implements RestController {
private final Logger logger;
private final XmlEngine saxon;
private final XmlEngine xalan;
public ProcessorInfoController(Logger logger) {
public ProcessorInfoController(Logger logger, XmlEngine saxon, XmlEngine xalan) {
this.logger = logger;
this.saxon = saxon;
this.xalan = xalan;
}
/**
@@ -24,8 +29,8 @@ public class ProcessorInfoController implements RestController {
@ScopedControllerManifest(method = HandlerType.GET, path = "/procinfo")
public void processorInfo(Request request, Response response) {
try {
response.header("processor", "Saxon " + Saxon.getVersion() + " over s9api");
response.body(Saxon.getVersion());
response.header("processor", "Saxon " + saxon.getVersion() + " over s9api");
response.body(saxon.getVersion());
} catch (Exception ex) {
this.logger.error("Error on retrieving engine version. " + ex);
response.body(ex.getMessage());

View File

@@ -3,8 +3,7 @@ package com.r11.tools.controller;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.r11.tools.controller.internal.*;
import com.r11.tools.xml.Saxon;
import com.r11.tools.xml.Xalan;
import com.r11.tools.xml.XmlEngine;
import org.apache.logging.log4j.Logger;
import spark.Request;
import spark.Response;
@@ -15,9 +14,14 @@ public class XPathController implements RestController {
private final Gson gson;
private final Logger logger;
public XPathController(Gson gson, Logger logger) {
private final XmlEngine saxon;
private final XmlEngine xalan;
public XPathController(Gson gson, Logger logger, XmlEngine saxon, XmlEngine xalan) {
this.gson = gson;
this.logger = logger;
this.saxon = saxon;
this.xalan = xalan;
}
@ScopedControllerManifest(method = HandlerType.POST, path = "/xpath")
@@ -44,10 +48,6 @@ public class XPathController implements RestController {
String processor = requestJson.get("processor").getAsString();
String version = requestJson.get("version").getAsString();
String tmp = "";
long timeStart;
long duration;
if (processor == null) {
response.body("saxon, xalan");
return;
@@ -56,65 +56,77 @@ public class XPathController implements RestController {
JsonObject responseJson = new JsonObject();
switch (processor) {
case "saxon":
response.header("processor", "Saxon " + Saxon.getVersion() + " " + version + " over s9api");
timeStart = System.currentTimeMillis();
try {
tmp = Saxon.processXPath(data, query, version).getData().trim();
response.status(200);
responseJson.addProperty("result", tmp);
responseJson.addProperty("status", "OK");
} catch (Exception ex) {
this.logger.error("Error on processing XPath using Saxon. " + ex);
response.status(400);
responseJson.addProperty("result", ex.getMessage());
responseJson.addProperty("status", "ERR");
}
duration = System.currentTimeMillis() - timeStart;
this.logger.info("Request (XPath, Saxon) processed in " + duration + " ms.");
responseJson.addProperty("processor", "Saxon " + Saxon.getVersion() + " " + version + " over s9api");
responseJson.addProperty("time", duration);
response.body(this.gson.toJson(responseJson));
return;
processWithSaxon(response, data, query, version, responseJson);
break;
case "xalan":
response.header("processor", Xalan.getVersion());
timeStart = System.currentTimeMillis();
try {
XPathQueryResult xPathQueryResult = Xalan.processXPath(data, query);
response.status(200);
responseJson.addProperty("result", xPathQueryResult.getData().trim());
responseJson.addProperty("status", "OK");
responseJson.addProperty("type", xPathQueryResult.getType());
} catch (Exception ex) {
this.logger.error("Error on processing XPath using Xalan. " + ex);
response.status(400);
responseJson.addProperty("result", ex.getMessage());
responseJson.addProperty("status", "ERR");
}
duration = System.currentTimeMillis() - timeStart;
this.logger.info("Request (XPath, Xalan) processed in " + duration + " ms.");
responseJson.addProperty("processor", Xalan.getVersion());
responseJson.addProperty("time", duration);
response.body(this.gson.toJson(responseJson));
return;
processWithXalan(response, data, query, responseJson);
break;
default:
response.body("saxon, xalan");
}
}
private void processWithXalan(Response response, String data, String query, JsonObject responseJson) {
long timeStart;
long duration;
response.header("processor", xalan.getVersion());
timeStart = System.currentTimeMillis();
try {
XPathQueryResult xPathQueryResult = xalan.processXPath(data, query, "");
response.status(200);
responseJson.addProperty("result", xPathQueryResult.getData().trim());
responseJson.addProperty("status", "OK");
responseJson.addProperty("type", xPathQueryResult.getType());
} catch (Exception ex) {
this.logger.error("Error on processing XPath using Xalan. " + ex);
response.status(400);
responseJson.addProperty("result", ex.getMessage());
responseJson.addProperty("status", "ERR");
}
duration = System.currentTimeMillis() - timeStart;
this.logger.info("Request (XPath, Xalan) processed in " + duration + " ms.");
responseJson.addProperty("processor", xalan.getVersion());
responseJson.addProperty("time", duration);
response.body(this.gson.toJson(responseJson));
}
private void processWithSaxon(Response response, String data, String query, String version, JsonObject responseJson) {
long timeStart;
String tmp;
long duration;
response.header("processor", "Saxon " + saxon.getVersion() + " " + version + " over s9api");
timeStart = System.currentTimeMillis();
try {
tmp = saxon.processXPath(data, query, version).getData().trim();
response.status(200);
responseJson.addProperty("result", tmp);
responseJson.addProperty("status", "OK");
} catch (Exception ex) {
this.logger.error("Error on processing XPath using Saxon. " + ex);
response.status(400);
responseJson.addProperty("result", ex.getMessage());
responseJson.addProperty("status", "ERR");
}
duration = System.currentTimeMillis() - timeStart;
this.logger.info("Request (XPath, Saxon) processed in " + duration + " ms.");
responseJson.addProperty("processor", "Saxon " + saxon.getVersion() + " " + version + " over s9api");
responseJson.addProperty("time", duration);
response.body(this.gson.toJson(responseJson));
}
}

View File

@@ -7,6 +7,7 @@ import com.r11.tools.controller.internal.HandlerType;
import com.r11.tools.controller.internal.RestController;
import com.r11.tools.controller.internal.ScopedControllerManifest;
import com.r11.tools.xml.Xalan;
import com.r11.tools.xml.XmlEngine;
import org.apache.logging.log4j.Logger;
import spark.Request;
import spark.Response;
@@ -17,9 +18,12 @@ public class XsdController implements RestController {
private final Gson gson;
private final Logger logger;
public XsdController(Gson gson, Logger logger) {
private final XmlEngine xalan;
public XsdController(Gson gson, Logger logger, XmlEngine xalan) {
this.gson = gson;
this.logger = logger;
this.xalan = xalan;
}
@ScopedControllerManifest(method = HandlerType.POST, path = "/xsd")
@@ -44,14 +48,14 @@ public class XsdController implements RestController {
String data = requestJson.get("data").getAsString();
String xsd = requestJson.get("process").getAsString();
response.header("processor", Xalan.getVersion());
response.header("processor", xalan.getVersion());
long timeStart = System.currentTimeMillis();
String tmp;
JsonObject responseJson = new JsonObject();
try {
tmp = Xalan.validate(data, xsd).trim();
tmp = xalan.validate(data, xsd).trim();
response.status(200);
@@ -69,7 +73,7 @@ public class XsdController implements RestController {
long duration = System.currentTimeMillis() - timeStart;
this.logger.info("Request (XSD, Xalan) processed in " + duration + " ms.");
responseJson.addProperty("processor", Xalan.getVersion());
responseJson.addProperty("processor", xalan.getVersion());
responseJson.addProperty("time", duration);
response.body(this.gson.toJson(responseJson));

View File

@@ -8,6 +8,7 @@ import com.r11.tools.controller.internal.RestController;
import com.r11.tools.controller.internal.ScopedControllerManifest;
import com.r11.tools.xml.Saxon;
import com.r11.tools.xml.Xalan;
import com.r11.tools.xml.XmlEngine;
import org.apache.logging.log4j.Logger;
import spark.Request;
import spark.Response;
@@ -18,9 +19,14 @@ public class XsltController implements RestController {
private final Gson gson;
private final Logger logger;
public XsltController(Gson gson, Logger logger) {
private final XmlEngine saxon;
private final XmlEngine xalan;
public XsltController(Gson gson, Logger logger, XmlEngine saxon, XmlEngine xalan) {
this.gson = gson;
this.logger = logger;
this.saxon = saxon;
this.xalan = xalan;
}
@ScopedControllerManifest(method = HandlerType.POST, path = "/xslt")
@@ -51,69 +57,78 @@ public class XsltController implements RestController {
response.body("saxon, xalan");
return;
}
String tmp;
long timeStart;
long duration;
JsonObject responseJson = new JsonObject();
switch (processor) {
case "saxon":
timeStart = System.currentTimeMillis();
try {
tmp = Saxon.processXSLT(data, query);
response.status(200);
responseJson.addProperty("result", tmp);
responseJson.addProperty("status", "OK");
} catch (Exception ex) {
this.logger.error("Error on processing XSLT using Saxon. " + ex);
response.status(400);
responseJson.addProperty("result", ex.getMessage());
responseJson.addProperty("status", "ERR");
}
duration = System.currentTimeMillis() - timeStart;
this.logger.info("Request (XSLT, Saxon) processed in " + duration + " ms.");
responseJson.addProperty("processor", "Saxon " + Saxon.getVersion() + " " + version);
responseJson.addProperty("time", duration);
response.body(this.gson.toJson(responseJson));
processWithSaxon(response, data, query, version, responseJson);
return;
case "xalan":
timeStart = System.currentTimeMillis();
try {
tmp = Xalan.processXSLT(data, query);
response.status(200);
responseJson.addProperty("result", tmp);
responseJson.addProperty("status", "OK");
} catch (Exception ex) {
this.logger.error("Error on processing XSLT using Xalan. " + ex);
response.status(400);
responseJson.addProperty("result", ex.getMessage());
responseJson.addProperty("status", "ERR");
}
duration = System.currentTimeMillis() - timeStart;
this.logger.info("Request (XSLT, Xalan) processed in " + duration + " ms.");
responseJson.addProperty("processor", Xalan.getVersion());
responseJson.addProperty("time", duration);
response.body(this.gson.toJson(responseJson));
processWithXalan(response, data, query, responseJson);
return;
default:
response.body("saxon, xalan");
}
}
private void processWithXalan(Response response, String data, String query, JsonObject responseJson) {
long duration;
long timeStart;
String tmp;
timeStart = System.currentTimeMillis();
try {
tmp = xalan.processXSLT(data, query);
response.status(200);
responseJson.addProperty("result", tmp);
responseJson.addProperty("status", "OK");
} catch (Exception ex) {
this.logger.error("Error on processing XSLT using Xalan. " + ex);
response.status(400);
responseJson.addProperty("result", ex.getMessage());
responseJson.addProperty("status", "ERR");
}
duration = System.currentTimeMillis() - timeStart;
this.logger.info("Request (XSLT, Xalan) processed in " + duration + " ms.");
responseJson.addProperty("processor", xalan.getVersion());
responseJson.addProperty("time", duration);
response.body(this.gson.toJson(responseJson));
}
private void processWithSaxon(Response response, String data, String query, String version, JsonObject responseJson) {
long duration;
String tmp;
long timeStart;
timeStart = System.currentTimeMillis();
try {
tmp = saxon.processXSLT(data, query);
response.status(200);
responseJson.addProperty("result", tmp);
responseJson.addProperty("status", "OK");
} catch (Exception ex) {
this.logger.error("Error on processing XSLT using Saxon. " + ex);
response.status(400);
responseJson.addProperty("result", ex.getMessage());
responseJson.addProperty("status", "ERR");
}
duration = System.currentTimeMillis() - timeStart;
this.logger.info("Request (XSLT, Saxon) processed in " + duration + " ms.");
responseJson.addProperty("processor", "Saxon " + saxon.getVersion() + " " + version);
responseJson.addProperty("time", duration);
response.body(this.gson.toJson(responseJson));
}
}

View File

@@ -11,7 +11,7 @@ import java.io.StringWriter;
* Handler for Saxon engine
* @author Wojciech Czop
*/
public class Saxon {
public class Saxon implements XmlEngine{
/**
* Transforms string containing xml document via xslt
@@ -20,7 +20,7 @@ public class Saxon {
* @return transformed xml
* @throws SaxonApiException thrown on stylesheet or transformation errors
*/
public static String processXSLT(String data, String transform) throws SaxonApiException {
public String processXSLT(String data, String transform) throws SaxonApiException {
Processor processor = new Processor(false);
XsltCompiler compiler = processor.newXsltCompiler();
XsltExecutable stylesheet = compiler.compile(new StreamSource(new StringReader(transform)));
@@ -34,6 +34,11 @@ public class Saxon {
return sw.toString();
}
@Override
public String validate(String data, String xsd) {
throw new UnsupportedOperationException();
}
/**
* Process xpath and return either node or wrapped atomic value
* @param data xml to be querried
@@ -42,7 +47,7 @@ public class Saxon {
* @return string xml representation of the node
* @throws Exception thrown on node building errors or invalid xpath
*/
public static XPathQueryResult processXPath(String data, String query, String version) throws Exception {
public XPathQueryResult processXPath(String data, String query, String version) throws Exception {
Processor p = new Processor(false);
XPathCompiler compiler = p.newXPathCompiler();
DocumentBuilder builder = p.newDocumentBuilder();
@@ -70,7 +75,7 @@ public class Saxon {
* Returns version of the processor
* @return version of the processor
*/
public static String getVersion() {
public String getVersion() {
return new Processor(false).getSaxonProductVersion();
}
}

View File

@@ -24,7 +24,7 @@ import java.io.*;
* Handler for Xalan engine
* @author Wojciech Czop
*/
public class Xalan {
public class Xalan implements XmlEngine{
/**
* Transforms string containing xml document via xslt
@@ -33,7 +33,7 @@ public class Xalan {
* @return transformed xml
* @throws Exception thrown on stylesheet or transformation errors
*/
public static String processXSLT(String data, String transform) throws Exception{
public String processXSLT(String data, String transform) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new InputSource(new StringReader(data)));
@@ -51,7 +51,7 @@ public class Xalan {
return sw.toString();
}
private static boolean isTextNode(Node n) {
private boolean isTextNode(Node n) {
if (n == null)
return false;
short nodeType = n.getNodeType();
@@ -65,7 +65,7 @@ public class Xalan {
* @return xml processed using given xpath
* @throws Exception thrown on node building errors or invalid xpath
*/
public static XPathQueryResult processXPath(String data, String transform) throws Exception {
public XPathQueryResult processXPath(String data, String transform, String version) throws Exception {
// Set up a DOM tree to query.
InputSource in = new InputSource(new StringReader(data));
@@ -103,7 +103,7 @@ public class Xalan {
return new XPathQueryResult(resultString.toString(), "node");
} catch (TransformerException e) {
String returnData = XPathAPI.eval(doc, transform).toString();
return new XPathQueryResult(data, "string");
return new XPathQueryResult(returnData, "string");
}
}
@@ -112,7 +112,7 @@ public class Xalan {
* Returns version of the processor
* @return version of the processor
*/
public static String getVersion(){
public String getVersion(){
return org.apache.xalan.Version.getVersion();
}
@@ -123,7 +123,7 @@ public class Xalan {
* @return statement of validity
* @throws Exception thrown on invalid xsd schema or xml
*/
public static String validate(String data, String xsd) throws Exception{
public String validate(String data, String xsd) throws Exception {
Source dataSource = new StreamSource(new StringReader(data));
Source xsdSource = new StreamSource(new StringReader(xsd));
SchemaFactory schemaFactory = SchemaFactory

View File

@@ -0,0 +1,12 @@
package com.r11.tools.xml;
import com.r11.tools.controller.internal.XPathQueryResult;
public interface XmlEngine {
XPathQueryResult processXPath(String data, String query, String version) throws Exception;
String processXSLT(String data, String transform) throws Exception;
String validate(String data, String xsd) throws Exception;
public String getVersion();
}

View File

@@ -1,5 +1,8 @@
FROM nginx:stable-alpine
RUN apk add --no-cache tzdata
ENV TZ Europe/Warsaw
COPY ./tools/ /usr/share/nginx/html/tools/
COPY ./lawful/ /usr/share/nginx/html/lawful/
COPY ./assets/ /usr/share/nginx/html/assets/

View File

@@ -41,7 +41,7 @@ div#header {
grid-column: 1;
}
iframe#frame {
iframe#iframe {
flex-grow: 1;
background-color: #FFFFFF;
}

View File

@@ -6,6 +6,8 @@
@import url('r11tooltip.css');
@import url('r11modal.css');
@import url('r11flexbox.css');
@import url('r11popup.css');
@import url('../../highlight.css');
@font-face {
font-family: 'Material Icons';

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -69,4 +69,27 @@
.content p {
margin: 0;
padding: 0;
}
}
.refresh-button{
float: right;
border: none;
background-color: unset;
font-size: xx-large;
}
.refresh-button:hover{
animation-name: rotation;
animation-duration: 0.8s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
@keyframes rotation{
from{
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

View File

@@ -0,0 +1,83 @@
.popup-flex:not(.hiddable-container){
animation: blur 0.5s ease-in-out ;
animation-fill-mode: forwards;
}
.popup-flex{
display: flex;
align-items: center;
width: 100%;
height: 100%;
z-index: 50;
flex-direction: column;
gap: 2%;
position: fixed;
justify-content: center;
}
.popup-body{
min-width: 33%;
max-width: 60%;
max-height: 70%;
background-color: white;
box-shadow: 10px 10px 5px lightblue;
min-height: 45%;
border-radius: 1em;
text-align: center;
padding: 10px 15px 15px 15px;
color: black;
border: 1px #2A93B0 solid;
display: flex;
flex-direction: column;
position: fixed;
}
.popup-button-close-container{
text-align: right;
margin-right: 2%;
margin-top: 1%;
font-size: xx-large;
font-weight: bold;
position: sticky;
top:0
}
.hiddable-popup-option{
flex-grow: 1;
overflow: auto;
padding: 1.5%;
}
.popup-button-close{
background: padding-box;
border: 0;
}
.popup-button-close:hover{
color: #2A93B0;
}
.hiddable-container{
display:none;
}
.hidden-popup-type{
display: none;
}
#history-request-body{
text-align: justify;
}
@keyframes blur {
0% {
backdrop-filter: blur(0px);
}
50% {
backdrop-filter: blur(5px);
}
100% {
backdrop-filter: blur(10px);
}
}

View File

@@ -68,4 +68,29 @@
background-color: #3bc4f1;
text-align: left;
color: white;
}
.table-default td{
text-align: center;
}
#header-table tr td {
border: 1px black solid;
padding: 1.5%;
}
#header-table{
border-collapse: collapse;
width: 100%;
height: 100%;
}
.history-header-name{
min-width: 10vw;
}
#historyTable, td{
padding: 1%;
overflow-x: scroll;
}

View File

@@ -21,6 +21,7 @@ input {
border: 2px solid rgba(93, 99, 96, 0.705);
border-radius: 5px;
padding: 8px;
display: block;
}
@@ -62,10 +63,6 @@ body {
width: 90%;
}
.tool.extended .tool-context {
width: 75%;
}
.tool.extended .tool-extention {
width: 20%;
padding-top: 2%;

View File

@@ -1,6 +0,0 @@
$(document).ready( function() {
document.getElementById("rest-mock").href =
window.location.protocol + "//" + window.location.hostname + ":8097";
});

View File

@@ -1,6 +1,41 @@
const tools = new Map();
/**
* Get address of Mock Services
*
* @function
* @name getMockHost
* @kind function
* @returns {string}
*/
function getMockHost() {
return window.location.protocol + "//" + window.location.hostname + ":8097";
}
/**
* Function called after page is loaded
*
* @function
* @name init
* @kind function
* @returns {void}
*/
function init() {
changeActiveTools('xmlTool', 'XML');
tools.set("xpath", "tools/xpath.html");
tools.set("xsd", "tools/xsd.html");
tools.set("xslt", "tools/xslt.html");
tools.set("xmlform", "tools/xmlFormatter.html");
tools.set("jsonform", "tools/jsonFormatter.html");
tools.set("mock", "tools/mock.html");
changeActiveTools('XML');
var toolUrl = window.location.search.substring(1);
if (tools.has(toolUrl))
changeTool(toolUrl, false);
else
loadLastPage();
}
/**
@@ -12,26 +47,77 @@ function init() {
* @param {any} activeClass class of elements that have to be shown
* @param {any} activeCategoryButton class of category button that has to be active
*/
function changeActiveTools(activeClass, activeCategoryButton) {
let tools = document.getElementById("toolList").children
function changeActiveTools(activeCategoryButton) {
let toolList = document.getElementById("toolList").children;
let categoryToClass = new Map([["XML", "xmlTool"],
["JSON", "jsonTool"],
["REST", "restTool"]]);
for (i = 0; i < tools.length; i++) {
if (tools[i].classList.contains(activeClass)) {
tools[i].style.display = "block";
}
else {
tools[i].style.display = "none";
}
let activeClass = categoryToClass.get(activeCategoryButton.toUpperCase());
if(activeClass == null) return;
for (i = 0; i < toolList.length; i++) {
if (toolList[i].classList.contains(activeClass))
toolList[i].style.display = "block";
else
toolList[i].style.display = "none";
}
let categories = document.getElementById("menu").children
let categoryList = document.getElementById("menu").children;
for (i = 0; i < categories.length; i++) {
if (categories[i].innerText == activeCategoryButton) {
categories[i].classList.add("active")
}
else {
categories[i].classList.remove("active")
}
for (i = 0; i < categoryList.length; i++) {
if (categoryList[i].innerText == activeCategoryButton)
categoryList[i].classList.add("active");
else
categoryList[i].classList.remove("active");
}
}
/**
* This function changes active tool.
* Optional updateURL can be set to false to stop changing URL.
* This helps avoiding endless reload loop when loading page.
*
* @function
* @name changeTool
* @kind function
* @param {any} tool
* @param {boolean} updateURL?
* @returns {void}
*/
function changeTool(tool, updateURL = true) {
if (! tools.has(tool)) return;
const url = tools.get(tool);
if (updateURL) document.location.search = tool;
switch (tool) { // XML category is default.
case "jsonform":
changeActiveTools('JSON');
break;
case "mock":
changeActiveTools('REST');
break;
}
localStorage.setItem("lastPage", tool);
document.getElementById("iframe").src = url;
}
/**
* Function that loads last used tool and sets active category accordingly
*
* @function
* @name loadLastPage
* @kind function
* @returns {void}
*/
function loadLastPage() {
var lastPage = localStorage.getItem("lastPage");
if (lastPage == null) {
lastPage = "xpath";
}
changeTool(lastPage);
}

View File

@@ -1,72 +0,0 @@
function formatAndValidateJson(errorElement) {
const input = document.querySelector('#jsonBlock');
const processInfo = document.getElementById(errorElement);
const address = window.location.protocol + "//" + window.location.hostname + ":" + 8081 + "/json/formatting"
fetch(address, {
method: 'POST',
body: input.textContent
})
.then(async (response) => {
const promise = response.json();
if (!response.ok) {
throw Error(await promise);
}
return promise;
})
.then((data) => {
input.innerText = data.data;
processInfo.innerText = "";
hljs.highlightElement(input);
processInfo.innerHTML = "<b style='color: green'>Computed in </b> <span style='color: green'>" + data.time + "ms</span>";
})
.catch((error) => {
processInfo.innerHTML = "<b style='color: red'>" + error.data + "</b>";
console.error('Error:', error);
});
}
function minimizeJson(errorElement) {
const input = document.querySelector('#jsonBlock');
const processInfo = document.getElementById(errorElement);
const address = window.location.protocol + "//" + window.location.hostname + ":" + 8081 + "/json/minimize"
fetch(address, {
method: 'POST',
body: input.textContent
})
.then(async (response) => {
const promise = response.json();
if (!response.ok) {
throw Error(await promise);
}
return promise;
})
.then((data) => {
input.innerText = data.data;
processInfo.innerText = "";
hljs.highlightElement(input);
processInfo.innerHTML = "<b style='color: green'>Computed in </b> <span style='color: green'>" + data.time + "ms</span>";
})
.catch((error) => {
processInfo.innerHTML = "<b style='color: red'>" + error.data + "</b>";
console.error('Error:', error);
});
}
function clearJsonData() {
const input = document.querySelector('#jsonBlock');
input.textContent = "";
}
function insertDefaultJson() {
const input = document.querySelector('#jsonBlock');
input.textContent = "{\"enter\": \"your\", \"json\": \"here\"}";
hljs.highlightElement(input);
}

View File

@@ -0,0 +1,250 @@
const mergeHTMLPlugin = (function () {
'use strict';
var originalStream;
/**
* @param {string} value
* @returns {string}
*/
function escapeHTML(value) {
return value
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#x27;');
}
/* plugin itself */
/** @type {HLJSPlugin} */
const mergeHTMLPlugin = {
// preserve the original HTML token stream
"before:highlightElement": ({ el }) => {
originalStream = nodeStream(el);
},
// merge it afterwards with the highlighted token stream
"after:highlightElement": ({ el, result, text }) => {
if (!originalStream.length) {
return;
}
const resultNode = document.createElement('div');
resultNode.innerHTML = result.value;
result.value = mergeStreams(originalStream, nodeStream(resultNode), text);
el.innerHTML = result.value;
}
};
/**
* @param {Node} node
*/
function tag(node) {
return node.nodeName.toLowerCase();
}
/**
* @param {Node} node
*/
function nodeStream(node) {
/** @type Event[] */
const result = [];
(function _nodeStream(node, offset) {
for (let child = node.firstChild; child; child = child.nextSibling) {
if (child.nodeType === 3) {
offset += child.nodeValue.length;
} else if (child.nodeType === 1) {
result.push({
event: 'start',
offset: offset,
node: child
});
offset = _nodeStream(child, offset);
if (!tag(child).match(/br|hr|img|input/)) {
result.push({
event: 'stop',
offset: offset,
node: child
});
}
}
}
return offset;
})(node, 0);
return result;
}
/**
* @param {any} original - the original stream
* @param {any} highlighted - stream of the highlighted source
* @param {string} value - the original source itself
*/
function mergeStreams(original, highlighted, value) {
let processed = 0;
let result = '';
const nodeStack = [];
function selectStream() {
if (!original.length || !highlighted.length) {
return original.length ? original : highlighted;
}
if (original[0].offset !== highlighted[0].offset) {
return (original[0].offset < highlighted[0].offset) ? original : highlighted;
}
return highlighted[0].event === 'start' ? original : highlighted;
}
/**
* @param {Node} node
*/
function open(node) {
/** @param {Attr} attr */
function attributeString(attr) {
return ' ' + attr.nodeName + '="' + escapeHTML(attr.value) + '"';
}
// @ts-ignore
result += '<' + tag(node) + [].map.call(node.attributes, attributeString).join('')
+ '>';
}
/**
* @param {Node} node
*/
function close(node) {
result += '</' + tag(node) + '>';
}
/**
* @param {Event} event
*/
function render(event) {
(event.event === 'start' ? open : close)(event.node);
}
while (original.length || highlighted.length) {
let stream = selectStream();
result += escapeHTML(value.substring(processed, stream[0].offset));
processed = stream[0].offset;
if (stream === original) {
/*
On any opening or closing tag of the original markup we first close
the entire highlighted node stack, then render the original tag along
with all the following original tags at the same offset and then
reopen all the tags on the highlighted stack.
*/
nodeStack.reverse().forEach(close);
do {
render(stream.splice(0, 1)[0]);
stream = selectStream();
} while (stream === original && stream.length && stream[0].offset === processed);
nodeStack.reverse().forEach(open);
} else {
if (stream[0].event === 'start') {
nodeStack.push(stream[0].node);
} else {
nodeStack.pop();
}
render(stream.splice(0, 1)[0]);
}
}
return result + escapeHTML(value.substr(processed));
}
return mergeHTMLPlugin;
}());
function formatAndValidateJson(errorElement) {
const input = document.querySelector('#jsonBlock');
const processInfo = document.getElementById(errorElement);
const address = window.location.protocol + "//" + window.location.hostname + ":" + 8081 + "/json/formatting"
fetch(address, {
method: 'POST',
body: input.textContent
})
.then(async (response) => {
const promise = response.json();
if (!response.ok) {
throw Error(await promise);
}
return promise;
})
.then((data) => {
input.innerText = data.data;
processInfo.innerText = "";
hljs.highlightElement(input);
processInfo.innerHTML = "<b style='color: green'>Computed in </b> <span style='color: green'>" + data.time + "ms</span>";
})
.catch((error) => {
processInfo.innerHTML = "<b style='color: red'>" + error.data + "</b>";
console.error('Error:', error);
});
}
function minimizeJson(errorElement) {
const input = document.querySelector('#jsonBlock');
const processInfo = document.getElementById(errorElement);
const address = window.location.protocol + "//" + window.location.hostname + ":" + 8081 + "/json/minimize"
fetch(address, {
method: 'POST',
body: input.textContent
})
.then(async (response) => {
const promise = response.json();
if (!response.ok) {
throw Error(await promise);
}
return promise;
})
.then((data) => {
input.innerText = data.data;
processInfo.innerText = "";
hljs.highlightElement(input);
processInfo.innerHTML = "<b style='color: green'>Computed in </b> <span style='color: green'>" + data.time + "ms</span>";
})
.catch((error) => {
processInfo.innerHTML = "<b style='color: red'>" + error.data + "</b>";
console.error('Error:', error);
});
}
function clearJsonData() {
const input = document.querySelector('#jsonBlock');
input.textContent = "";
}
function insertDefaultJson() {
const input = document.querySelector('#jsonBlock');
input.textContent = "{\"enter\": \"your\", \"json\": \"here\"}";
hljs.highlightElement(input);
}
/**
* This function is executed after the page is loaded.
*
* @function
* @name init
* @kind function
*/
function init() {
// Make sure that only plain text is pasted
configurePastingInElement("jsonBlock");
hljs.addPlugin(mergeHTMLPlugin);
}

View File

@@ -0,0 +1,254 @@
var clientUUID = '';
var advancedDisplayed = false;
var json = {};
var jsonIndex = 0;
var host = window.location.protocol + "//" + window.location.hostname + "/mock";
const C_UUID = 'mock-uuid';
const C_ADV = 'advanced-mode';
const color_red = "#ff8f8f";
const color_grey = "#6b6b6b";
const setModified = function(){
setDataModified();
}
const getUpdate = function(){
updateData();
}
const dataRefresh = function(){
getData();
}
/*
Listeners segment
*/
$(document).on('change', '.data-field', setModified);
$('#btn-save').click(
() => {
disableSaveButton();
}
);
$('#btn-newRow').click(
()=> {
newRowInput();
setDataModified();
}
);
/*
Functions segment
*/
function disableSaveButton(){
$('#btn-save').removeClass('active');
$('#btn-save').off();
}
function createLink(uuid){
var link = host + '/api/mock/r/'+uuid;
return link;
}
function onLoad(){
loadCookies();
getData();
}
function getData(){
$.getJSON(host + '/api/mock/'+clientUUID, function(data) {
json = data;
loadFetchedMessage();
initializeUUID();
});
}
function loadCookies(){
clientUUID = getCookie(C_UUID);
advancedDisplayed = getCookie(C_ADV) == 'true';
}
function setCookie(){
document.cookie = C_UUID + '=' +clientUUID;
document.cookie = C_ADV + '=' + advancedVisibility;
}
function initializeUUID(){
if(clientUUID == null || clientUUID == undefined || clientUUID == ''){
clientUUID = json.clientUUID;
setCookie();
}
}
function httpStatusInvalid(){
value = $('#httpStatus').val();
return value == '';
}
function setDataModified(){
if(httpStatusInvalid()){
$('#btn-save').removeClass('active');
$('#btn-save').off();
document.getElementById("httpStatus").style.backgroundColor = color_red;
return;
}
$('#btn-save').addClass('active');
$('#btn-save').click(getUpdate);
document.getElementById("httpStatus").style.backgroundColor = null;
}
function getCookie(cname) {
var name = cname + '=';
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for(var i = 0; i <ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return '';
}
function updateData(){
var updatedJson = createRequestBody();
const dataSaved = function () {
loadFetchedMessage();
savedModalDisplay();
}
$.ajax({
url: host + '/api/mock',
type: 'PUT',
data: JSON.stringify(updatedJson, null, 2),
contentType: "application/json",
}).done(dataSaved);
disableSaveButton();
}
function loadFetchedMessage(){
fillStaticFields(
json.clientUUID,
json.contentType,
json.messageBody,
json.httpStatus);
fillHeaderTable(json.httpHeaders);
getHistoryData();
refreshHeaderTable(document.innerHTML);
}
function fillStaticFields(uuid, contentType, body, httpStatus){
let link = createLink(uuid);
let linkHtml = '<a class="hyperlink" target="_blank" href="'+link+'">'+link+'</a>';
$('#messageLink').html(linkHtml);
$('#httpStatus').val(httpStatus);
$('#typeSelector').val(contentType);
$('#bodyEditor').val(body);
}
function fillHeaderTable(headers){
var innerHTML = buildHeaderMapHtml(headers);
refreshHeaderTable(innerHTML);
}
function refreshHeaderTable(html){
$('#headerMapTable').html(html);
$('.btn-hashmap').click(function(){
setDataModified();
$(this).closest('tr').remove();
})
}
function buildHeaderMapHtml(headers){
var innerHTML = '';
for(var key in headers){
innerHTML += buildRowHtml(key, headers[key]);
}
return innerHTML;
}
function addRow(key, value){
var headerMap = $('#headerMapTable');
var headersMapHtml = headerMap.html();
headersMapHtml += buildRowHtml(key, value);
refreshHeaderTable(headersMapHtml);
}
function newRowInput(){
const hName = $('#headerKeyInput');
const hValue = $('#headerValueInput');
if(checkIfInputValid(hName.val()) && checkIfInputValid(hValue.val())){
addRow(hName.val(), hValue.val());
hName.val(null);
hValue.val(null);
}
}
function checkIfInputValid(input){
return !(input == '' || input == null || input == undefined);
}
function checkIfHeaderEssential(key){
if( key == "Connection" || key == "Keep-Alive" || key == "Date" ){
return true;
}
return false;
}
function buildRowHtml(key, value){
if(checkIfHeaderEssential(key)){
return '' +
'<tr>' +
'<td><input class="key data-field" value="' + key + '" readonly></td>' +
'<td><input class="data-field" value="' + value + '"></td>' +
'</tr>';
}
return '' +
'<tr>' +
'<td><input class="key data-field" value="' + key + '"></td>' +
'<td><input class="data-field" value="' + value + '"></td>' +
'<td><button class="modification-button btn-hashmap"><i class="icon-cancel"></i></button></td>' +
'</tr>';
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function createRequestBody(){
var newJson =
{
clientUUID: json.clientUUID,
contentType: $('#typeSelector').val(),
messageBody: $('#bodyEditor').val(),
httpStatus: $('#httpStatus').val(),
httpHeaders: {},
};
newJson['httpHeaders'] = convertTableToJson();
json = newJson;
return newJson;
}
function convertTableToJson(){
const rows = $('#headerMapTable').children();
var obj = {};
var key;
for(let i=0; i<rows.length; i++){
key = rows.eq(i).children().eq(0).children().eq(0).val();
obj[key] = rows.eq(i).children().eq(1).children().eq(0).val();
}
return obj;
}

View File

@@ -0,0 +1,49 @@
var historyJson = {};
const maxIterations = 200;
function getHistoryData(){
$.getJSON(host + '/api/event/' + clientUUID, function(data){
historyJson = data;
displayHistory();
});
}
function historyToHtml(){
var innerHTML = '';
var iterations = historyJson.length <= maxIterations ? historyJson.length : maxIterations;
for(let i=0; i<iterations; i++){
let style = i%2==0 ? ' class="even"' : '';
innerHTML += '<tr' + style + '>' +
'<td>' + parseTimeStamp(historyJson[i].dateTimeStamp) + '</td>' +
'<td>' + historyJson[i].httpMethod + '</td>' +
'<td>' + parseRequestBody(historyJson[i].requestBody, i) + '</td>' +
'<td> <button id="'+i+'" class="showHeaderButton" onClick="showHeadersHistory(this);"> Show headers </button> </td>' +
'</tr>';
}
return innerHTML;
}
function parseRequestBody(requestBody,i){
return requestBody.length == 0 ?
"No request body" :
'<button id="'+i+'" class="showRequestBodyButton" onClick="showRequestBody(this);"> Show request body </button>'
}
function parseTimeStamp(timeStamp){
return timeStamp.substring(0,19).replace('T',' ');
}
function parseHeaders(pos){
parsedJson = new Map();
headers = historyJson[pos].headers
Object.keys( headers ).forEach(
(jsonKey) => {
parsedJson.set( jsonKey , headers[jsonKey] );
}
)
return parsedJson;
}
function displayHistory(){
$('#historyTable tbody').html(historyToHtml());
}

View File

@@ -7,7 +7,6 @@ var methodToCall = {
const overlay = $('#overlay');
const savedModal = $('#modal-confirm');
const dataLossModal = $('#modal-query');
const uuidChangeModal = $('#modal-uuidChanged')
const dataLossModalYes = dataLossModal.children().eq(2).children().eq(0);
const dataLossModalNo = dataLossModal.children().eq(2).children().eq(1);
const allModals = $('.modal');
@@ -24,36 +23,10 @@ const dataLossModalDisplay = function(){
showModal(dataLossModal);
}
const uuidChangeModalDisplay = function(addidionalMessage){
switch(addidionalMessage){
case "success":{
$(".uuid-modal-body").removeClass("active");
$("#changeUUIDSuccess").addClass("active");
break;
}
case "new":{
$(".uuid-modal-body").removeClass("active");
$("#newUUID").addClass("active");
break;
}
case "restore":{
$(".uuid-modal-body").removeClass("active");
$("#restoredUUID").addClass("active");
break;
}
case "noChg":{
$(".uuid-modal-body").removeClass("active");
$("#noChgUUID").addClass("active");
break;
}
}
showModal(uuidChangeModal);
}
btnModalClose.click(closeModals);
overlay.click(closeModals);
dataLossModalNo.click(closeModals);
dataLossModalYes.click(dropChangesAndClose);
function setMethodToCall(name, id){
methodToCall.name = name;
@@ -74,16 +47,7 @@ function showModal(jmodal){
function hideModal(jmodal){
if(!modalDisplayed) return;
if ($(uuidChangeModal).hasClass('active')) window.location.reload();
overlay.removeClass('active');
jmodal.removeClass('active');
modalDisplayed = false;
}
btnModalClose.click(closeModals);
overlay.click(closeModals);
dataLossModalNo.click(closeModals);
dataLossModalYes.click(dropChangesAndClose);

View File

@@ -0,0 +1,34 @@
function switchPopups (neededPopupOption) {
$('.hiddable-popup-option').addClass('hidden-popup-type');
$('#'+neededPopupOption).removeClass('hidden-popup-type');
}
function showPopup(){
$('.popup-flex').removeClass('hiddable-container');
}
function hidePopup(){
$('.popup-flex').addClass('hiddable-container');
$('.hiddable-popup-option').addClass('hidden-popup-type');
}
/*
* Event listener that's close the popup when user clicks out of a popup.
*/
window.addEventListener(
'click' ,
(clickedElement) => {
if(!document.getElementById('popup-body').contains(clickedElement.target) && clickedElement.target.className == 'popup-flex' ) {
hidePopup();
}
}
);
$('.popup-button-close').click(
() => {
hidePopup();
$('.hiddable-popup-option').addClass('hidden-popup-type')
}
);

View File

@@ -0,0 +1,165 @@
var advancedVisibility = false;
var focusedField = false;
/*
Listeners
*/
$("#optional").click(changeAdvancedVisibility);
$('#historyTab').click(showHistory);
$('.tooltipped').on("mouseenter" , (event) => {showTip(event.currentTarget.id+'Tip')})
.on( "mouseleave", (event) => {hideTip(event.currentTarget.id+'Tip')});
/*
Functions
*/
function changeAdvancedVisibility(){
if(advancedVisibility){
$("#advanced").removeClass('active');
advancedVisibility = false;
}
else {
$('#advanced').addClass('active');
advancedVisibility = true;
}
setCookie();
}
const tabitem = $('.tabitem');
function showHistory(){
$('#headersTab').click(showHeaders);
tabitem.removeClass('active');
$('.tabcontent').removeClass('active');
$('#history').addClass('active');
$('#historyTab').addClass('active');
$('#historyTab').off('click');
getHistoryData();
}
function showHeaders(){
$('#historyTab').click(showHistory);
tabitem.removeClass('active');
$('.tabcontent').removeClass('active');
$('#headers').addClass('active');
$('#headersTab').addClass('active');
$('#headersTab').off('click');
}
function showHeadersHistory(record){
historyTable = '';
headers = parseHeaders(record.id)
headers.forEach(
(value,key) => {
historyTable +=
'<tr>' +
'<td class="history-header-name">'+ key + '</td>' +
'<td class="history-header-value">'+ value + '</td>' +
'</tr>'
}
);
document.getElementById('header-history-table-body').innerHTML = historyTable;
switchPopups('history-headers-table');
showPopup();
}
async function formatJSON(json) {
const backend = "java";
const address = window.location.protocol + "//" + window.location.hostname + "/" + backend + "/json/formatting";
var init = {
body: json,
method: "POST"
};
var request = new Request(address, init);
var result = await fetch(request).then(response => {
return response.text().then(function (text) {
var json = JSON.parse(text);
json.status = response.status;
return json;
});
});
return result;
}
async function formatXML(xml) {
const backend = "libxml";
const address = window.location.protocol + "//" + window.location.hostname + "/" + backend + "/prettify";
var data = {
data: xml,
process: "",
processor: "libxml",
version: "1.0"
}
var init = {
body: JSON.stringify(data),
method: "POST"
};
var request = new Request(address, init);
var result = await fetch(request).then(response => {
return response.text().then(function (text) {
return JSON.parse(text);
});
});
return result;
}
function showRequestBody(element){
var historyRequestBody = historyJson[element.id].requestBody;
const popupContent = document.getElementById('code-highlight-content')
document.getElementById('code-highlight-content').innerText = "Loading...";
switch(historyJson[element.id].headers["content-type"]){
case "application/json":{
formatJSON(historyRequestBody).then(function(result) {
if (result.status == "200") {
popupContent.innerText = result.data;
highlightSyntax('code-highlight-content');
}
else {
popupContent.innerText = historyRequestBody;
}
});
break;
}
case "application/xml": {
formatXML(historyRequestBody).then(function(result) {
if (result.status == "OK") {
popupContent.innerText = result.result;
highlightSyntax('code-highlight-content');
}
else {
popupContent.innerText = historyRequestBody;
}
});
break;
}
default:{
popupContent.innerText = historyRequestBody;
highlightSyntax('code-highlight-content');
}
}
switchPopups('history-request-body');
showPopup();
}
function refreshHistoryRecords(){
getHistoryData();
}
function hideTip(element){
$('#'+element).removeClass('active');
}
function showTip(element){
$('.tip').removeClass('active');
$('#'+element).addClass('active');
}

View File

@@ -65,28 +65,6 @@ function clearDataField() {
}
/**
* The `escapeHTML` function is used to escape special characters in an HTML element's innerHTML property.
* This is done to prevent these characters from being interpreted as HTML tags or attributes,
* which could potentially cause security vulnerabilities or unintended behavior.
*
* @function
* @name escapeHTML
* @kind function
* @param {any} element
* @returns {void}
*/
function escapeHTML(elementID) {
document.getElementById(elementID).innerHTML = document.getElementById(elementID).innerHTML
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
/**
* It fills the XML area with a sample XML.
*
@@ -98,7 +76,7 @@ function escapeHTML(elementID) {
*/
function fillDefaultXML(element) {
if (element.classList.contains("active")) {
const serverAddress = window.location.protocol + "//" + window.location.hostname + ":8086";
const serverAddress = window.location.protocol + "//" + window.location.hostname;
clearDefaultContent(document.getElementById("xmlArea"), "Insert XML here");
fetch(serverAddress + "/assets/samples/sampleXml.xml")
.then(response => response.text())
@@ -111,8 +89,18 @@ function fillDefaultXML(element) {
}
}
/**
* It fills the XSD area with a sample XSD and XML area with matching XML.
*
* @function
* @name fillDefaultXSD
* @kind function
* @param {any} element
* @returns {void}
*/
function fillDefaultXSD(){
const serverAddress = window.location.protocol + "//" + window.location.hostname + ":8086";
const serverAddress = window.location.protocol + "//" + window.location.hostname;
fetch(serverAddress + "/assets/samples/sampleXSD.xsd")
.then( response => response.text() )
.then( (XSDSchema) => {
@@ -138,7 +126,7 @@ function fillDefaultXSD(){
* @returns {void}
*/
function fillDefaultXSLT() {
const serverAddress = window.location.protocol + "//" + window.location.hostname + ":8086";
const serverAddress = window.location.protocol + "//" + window.location.hostname;
fetch(serverAddress + "/assets/samples/XSLTTemplate.xslt")
.then( response => response.text() )
.then( (XSTLTemplate) => {
@@ -289,9 +277,9 @@ function performRequest(endpoint, checkXML, checkTransform) {
var xmlData = document.getElementById(sourceId).innerText.trim();
var transformData = document.getElementById(transformId).innerText.trim();
var port = 8081;
var backend = "java";
if (getProcessor() == "libxml") {
port = 8082;
backend = "libxml";
}
var empty = false;
@@ -305,7 +293,7 @@ function performRequest(endpoint, checkXML, checkTransform) {
empty = true;
}
if (!empty) {
restRequest(port, endpoint, xmlData, transformData).then(function (result) {
restRequest(backend, endpoint, xmlData, transformData).then(function (result) {
document.getElementById("resultArea").innerText = result.result;
highlightSyntax("resultArea");
document.getElementById("procinfo").innerText = ' Computed using ' + result.processor;
@@ -345,7 +333,7 @@ function performFormatRequest(endpoint, checkXML, sourceId, targetId) {
const sourceElement = document.getElementById(sourceId);
const targetElement = document.getElementById(targetId);
const infoElement = document.getElementById("formatinfo");
const port = 8082;
const backend = "libxml";
var xmlData = sourceElement.innerText.trim();
var empty = false;
@@ -356,7 +344,7 @@ function performFormatRequest(endpoint, checkXML, sourceId, targetId) {
}
if (!empty) {
restRequest(port, endpoint, xmlData, "").then(function (result) {
restRequest(backend, endpoint, xmlData, "").then(function (result) {
if (result.status == "OK") {
targetElement.innerText = result.result.trim();
highlightSyntax(targetElement.id);
@@ -386,16 +374,15 @@ function performFormatRequest(endpoint, checkXML, sourceId, targetId) {
* @function
* @name restRequest
* @kind function
* @param {any} port of target service
* @param {any} backend target backend
* @param {any} endpoint of target service
* @param {any} xmlData XML that will be sent
* @param {any} transformData data used to transform given XML
* @returns {Promise<any>}
*/
async function restRequest(port, endpoint, xmlData, transformData) {
const escapeChar = "specialEscapeChar";
async function restRequest(backend, endpoint, xmlData, transformData) {
const addr = window.location.protocol + "//" + window.location.hostname + ":" + port + "/" + endpoint;
const addr = window.location.protocol + "//" + window.location.hostname + "/" + backend + "/" + endpoint;
if (defaultStrings.includes(xmlData)) {
xmlData = "<empty/>";

View File

@@ -0,0 +1,34 @@
/**
* This function is executed after the page is loaded.
*
* @function
* @name init
* @kind function
*/
function init() {
configurePastingInElement("xmlArea");
}
/**
* Function returns processor that will be used to transform XML.
* This solution allows to use one function for sending request from every tool
*
* @function
* @name getProcessor
* @kind function
*/
function getProcessor() {
return "libxml";
}
/**
* Function returns version of XML processor that will be used to transform XML.
* This solution allows to use one function for sending request from every tool
*
* @function
* @name getVersion
* @kind function
*/
function getVersion() {
return "1.0"
}

View File

@@ -0,0 +1,174 @@
/**
* The `processVersionSelector()` function is responsible for updating the display of the web page
* based on the selected processor and version.
*
* @function
* @name processVersionSelector
* @kind function
* @returns {void}
*/
function processVersionSelector() {
var processor = getProcessor();
var hideableOptions = document.getElementsByClassName("hideable");
for (let i = 0; i < hideableOptions.length; i++) {
hideableOptions[i].style = "display: none;";
}
if (processor == "xalan" || processor == "libxml") {
var xalanOptions = document.getElementsByClassName("xalan");
for (let i = 0; i < xalanOptions.length; i++) {
xalanOptions[i].style = "";
}
document.getElementById("versions").selectedIndex = 0;
}
else {
var saxonOptions = document.getElementsByClassName("saxon");
for (let i = 0; i < saxonOptions.length; i++) {
saxonOptions[i].style = "";
}
document.getElementById("versions").selectedIndex = 3;
}
processTooltip();
}
/**
* The `processTooltip()` function is responsible for updating the display of the tooltip based on the selected version of the processor.
* It shows or hides different sections of the tooltip based on the selected version.
* It also handles the click event on the form and updates the tooltip accordingly.
*
* @function
* @name processTooltip
* @kind function
*/
function processTooltip() {
var filter = "collapse" + getVersion();
var collList;
if (filter == "collapse3.0") {
document.getElementById("tooltipFunctionInfo").innerText = "XPath 3.0 functions";
hideList(document.getElementsByName("collapse10"));
hideList(document.getElementsByName("collapse20"));
showList(document.getElementsByName("collapse30"));
hideList(document.getElementsByName("collapse31"));
} else if (filter == "collapse3.1") {
document.getElementById("tooltipFunctionInfo").innerText = "XPath 3.1 functions";
hideList(document.getElementsByName("collapse10"));
hideList(document.getElementsByName("collapse20"));
hideList(document.getElementsByName("collapse30"));
showList(document.getElementsByName("collapse31"));
} else if (filter == "collapse2.0") {
document.getElementById("tooltipFunctionInfo").innerText = "XPath 2.0 functions";
hideList(document.getElementsByName("collapse10"));
showList(document.getElementsByName("collapse20"));
hideList(document.getElementsByName("collapse30"));
hideList(document.getElementsByName("collapse31"));
} else {
document.getElementById("tooltipFunctionInfo").innerText = "XPath 1.0 functions";
showList(document.getElementsByName("collapse10"));
hideList(document.getElementsByName("collapse20"));
hideList(document.getElementsByName("collapse30"));
hideList(document.getElementsByName("collapse31"));
}
}
/**
* This function is executed after the page is loaded.
*
* @function
* @name init
* @kind function
*/
function init() {
// Make sure that only plain text is pasted
configurePastingInElement("xmlArea");
configurePastingInElement("transformArea");
//Handle clicks in whole form and set info in tooltip
setDefaultContent(document.getElementById("xmlArea"), 'Insert XML here');
setDefaultContent(document.getElementById("transformArea"), 'Insert XPath expression here');
processVersionSelector();
processTooltip();
tool.addEventListener('change', event => {
//Check if script was called from textarea or selector
var targetID = event.target.getAttribute('id');
if (targetID == "processors") {
processVersionSelector();
processTooltip();
}
else if (targetID == "versions") {
processTooltip();
}
})
tool.addEventListener('click', event => {
//Check if script was called from textarea or selector
var targetID = event.target.getAttribute('id');
if (targetID !== "xmlArea" && targetID !== "transformArea") {
return;
}
processTooltip();
})
tool.addEventListener('change', event => {
//Check if script was called from textarea or selector
var targetID = event.target.getAttribute('id');
if (targetID !== "xmlArea" && targetID !== "transformArea") {
return;
}
processTooltip();
})
var triggerList = document.getElementsByClassName("collapseTrigger");
for (i = 0; i < triggerList.length; i++) {
triggerList[i].addEventListener("click", function () {
var collapsible = this.parentElement;
if (this.tagName == "A") {
var collapsibleData = this.nextElementSibling;
} else {
var collapsibleData = this.parentElement.nextElementSibling;
}
if (collapsibleData.style.maxHeight > "0px") {
collapsibleData.style.maxHeight = "0px";
this.classList.toggle("active", false);
if (!this.classList.contains("collapsibleMini")) {
collapsible.classList.toggle("active", false);
}
var subLists1 = collapsibleData.getElementsByClassName("content");
var subLists2 = collapsibleData.getElementsByClassName("active");
for (j = 0; j < subLists1.length; j++) {
subLists1[j].style.maxHeight = "0px";
}
for (j = 0; j < subLists2.length; j++) {
subLists2[j].classList.toggle("active", false);
}
} else {
collapsibleData.style.maxHeight = (collapsibleData.scrollHeight) + "px";
this.classList.toggle("active", true);
if (!this.classList.contains("collapsibleMini")) {
collapsible.classList.toggle("active", true);
} else {
var parentContent = this.closest(".content");
parentContent.style.maxHeight = (parentContent.scrollHeight + collapsibleData.scrollHeight) + "px";
}
}
});
}
}

View File

@@ -0,0 +1,51 @@
/**
* This function is executed after the page is loaded.
*
* @function
* @name init
* @kind function
*/
function init() {
// Make sure that only plain text is pasted
configurePastingInElement("xmlArea");
configurePastingInElement("transformArea");
//Handle clicks in whole form and set info in tooltip
setDefaultContent(document.getElementById("xmlArea"), 'Insert XML here');
setDefaultContent(document.getElementById("transformArea"), 'Insert XSD here');
// refreshTooltip();
processTooltip();
tool.addEventListener('click', event => {
//Check if script was called from textarea or selector
var targetID = event.target.getAttribute('id');
if (targetID !== "processors" && targetID !== "xmlArea" && targetID !== "transformArea" && targetID !== "versions") {
return;
}
processTooltip();
})
}
/**
* The `processTooltip()` function is responsible for updating the display of the tooltip based on the selected version of the processor.
* It shows or hides different sections of the tooltip based on the selected version.
* It also handles the click event on the form and updates the tooltip accordingly.
*
* @function
* @name processTooltip
* @kind function
*/
function processTooltip() {
if (getProcessor() == "xalan") {
document.getElementById("tooltipFunctionInfo").innerText = "XSLT 1.0 functions";
document.getElementById("processorTooltipInfo").innerText = "Supports XSLT 1.0";
hideList(document.getElementsByName("collapse30"));
} else {
document.getElementById("tooltipFunctionInfo").innerText = "XSLT 1.0, 2.0 & 3.0 functions";
document.getElementById("processorTooltipInfo").innerText = "Supports XSLT up to 3.0";
showList(document.getElementsByName("collapse30"));
}
}

View File

@@ -0,0 +1,100 @@
/**
* The `processTooltip()` function is responsible for updating the display of the tooltip based on the selected version of the processor.
* It shows or hides different sections of the tooltip based on the selected version.
* It also handles the click event on the form and updates the tooltip accordingly.
*
* @function
* @name processTooltip
* @kind function
*/
function processTooltip() {
if (getProcessor() == "xalan" || getProcessor() == "libxml") {
document.getElementById("tooltipFunctionInfo").innerText = "XSLT 1.0 functions";
document.getElementById("processorTooltipInfo").innerText = "Supports XSLT 1.0";
hideList(document.getElementsByName("collapse30"));
} else {
document.getElementById("tooltipFunctionInfo").innerText = "XSLT 1.0, 2.0 & 3.0 functions";
document.getElementById("processorTooltipInfo").innerText = "Supports XSLT up to 3.0";
showList(document.getElementsByName("collapse30"));
}
}
/**
* This function is executed after the page is loaded.
*
* @function
* @name init
* @kind function
*/
function init() {
// Make sure that only plain text is pasted
configurePastingInElement("xmlArea");
configurePastingInElement("transformArea");
//Handle clicks in whole form and set info in tooltip
setDefaultContent(document.getElementById("xmlArea"), 'Insert XML here');
setDefaultContent(document.getElementById("transformArea"), 'Insert XSLT here');
// refreshTooltip();
processTooltip();
tool.addEventListener('click', event => {
//Check if script was called from textarea or selector
var targetID = event.target.getAttribute('id');
if (targetID !== "processors" && targetID !== "xmlArea" && targetID !== "transformArea" && targetID !== "versions") {
return;
}
processTooltip();
})
tool.addEventListener('change', event => {
//Check if script was called from textarea or selector
var targetID = event.target.getAttribute('id');
if (targetID !== "processors") {
return;
}
processTooltip();
})
var triggerList = document.getElementsByClassName("collapseTrigger");
for (i = 0; i < triggerList.length; i++) {
triggerList[i].addEventListener("click", function () {
var collapsible = this.parentElement;
var collapsibleData = this.nextElementSibling;
if (collapsibleData.style.maxHeight > "0px") {
collapsibleData.style.maxHeight = "0px";
this.classList.toggle("active", false);
if (!this.classList.contains("collapsibleMini")) {
collapsible.classList.toggle("active", false);
}
var subLists1 = collapsibleData.getElementsByClassName("content");
var subLists2 = collapsibleData.getElementsByClassName("active");
for (j = 0; j < subLists1.length; j++) {
subLists1[j].style.maxHeight = "0px";
}
for (j = 0; j < subLists2.length; j++) {
subLists2[j].classList.toggle("active", false);
}
} else {
collapsibleData.style.maxHeight = (collapsibleData.scrollHeight) + "px";
this.classList.toggle("active", true);
if (!this.classList.contains("collapsibleMini")) {
collapsible.classList.toggle("active", true);
} else {
var parentContent = this.closest(".content");
parentContent.style.maxHeight = (parentContent.scrollHeight + collapsibleData.scrollHeight) + "px";
}
}
});
}
}

View File

@@ -4,9 +4,7 @@
<head>
<link rel="stylesheet" href="assets/css/frame.css">
<script src="assets/scripts/common/jquery-3.6.0.slim.min.js"></script>
<script src="assets/scripts/dyn_host.js"></script>
<script src="assets/scripts/frame.js"></script>
<!-- <link rel="stylesheet" href="common.css"> -->
<link rel="shortcut icon" href="assets/images/favicon.ico" type="image/x-icon">
<!-- Meta tags for SEO and SEM -->
<title>Release11 Web Tools</title>
@@ -22,9 +20,9 @@
<div id="leftElements">
<div id="logo"><a href="http://release11.com/"><img src="assets/images/logo_czarne.svg" alt="Release11"></a></div>
<div id="menu">
<a href="#" onclick="changeActiveTools('xmlTool', 'XML')" class="active">XML</a>
<a href="#" onclick="changeActiveTools('jsonTool', 'JSON')">JSON</a>
<a href="#" onclick="changeActiveTools('restTool', 'REST')">REST</a>
<a href="#" onclick="changeActiveTools('XML')" class="active">XML</a>
<a href="#" onclick="changeActiveTools('JSON')">JSON</a>
<a href="#" onclick="changeActiveTools('REST')">REST</a>
</div>
</div>
@@ -34,14 +32,12 @@
<div id="content">
<div id="leftBar">
<ul id="toolList">
<li class="dynamic restTool toolListRow" style="display: none;">
<a id="rest-mock" href="http://tools.zipper.release11.com:8097/" target="iframe">REST Mock</a>
</li>
<li class="toolListRow xmlTool"><a href="./tools/xpath.html" target="iframe">XPath</a></li>
<li class="toolListRow xmlTool"><a href="./tools/xslt.html" target="iframe">XSLT</a></li>
<li class="toolListRow xmlTool"><a href="./tools/xsd.html" target="iframe">XSD</a></li>
<li class="toolListRow xmlTool"><a href="tools/xmlFormatter.html" target="iframe">XML Formatter</a></li>
<li class="toolListRow jsonTool" style="display: none;"><a href="tools/jsonFormatter.html" target="iframe">JSON Formatter</a></li>
<li class="toolListRow restTool"><a href="#" onclick="changeTool('mock');">REST Mock</a></li>
<li class="toolListRow xmlTool"><a href="#" onclick="changeTool('xpath');">XPath</a></li>
<li class="toolListRow xmlTool"><a href="#" onclick="changeTool('xslt');">XSLT</a></li>
<li class="toolListRow xmlTool"><a href="#" onclick="changeTool('xsd');">XSD</a></li>
<li class="toolListRow xmlTool"><a href="#" onclick="changeTool('xmlform');">XML Formatter</a></li>
<li class="toolListRow jsonTool"><a href="#" onclick="changeTool('jsonform');">JSON Formatter</a></li>
</ul>
<div id="copyright">
Build: [:VERSION:]<br>
@@ -53,7 +49,7 @@
<a href="mailto:bugs@release11.com">Found a bug?</a>
</div>
</div>
<iframe id="frame" name="iframe" src="./tools/xpath.html" frameborder="0"></iframe>
<iframe id="iframe" name="iframe" frameborder="0"></iframe>
</div>
</body>

View File

@@ -12,8 +12,26 @@ server {
add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
}
location /java/ {
proxy_pass http://xmltools-backend:8081/;
proxy_set_header Host $host;
}
location /libxml/ {
proxy_pass http://xmltools-libxml-backend/;
proxy_set_header Host $host;
}
location /mock/ {
proxy_pass http://xmltools-mocked-services:8097/;
proxy_set_header Host $host;
proxy_set_header Content-Type $http_content_type;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;

View File

@@ -7,10 +7,9 @@
<link rel="stylesheet" href="../assets/css/tools/r11form.css">
<link rel="stylesheet" href="../assets/css/highlight.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
<script src="../assets/scripts/tools/scripts.js"></script>
<script src="../assets/scripts/common/hljs.min.js"></script>
<script src="../assets/scripts/tools/jsonFormatter.js"></script>
<script src="../assets/scripts/tools/highlight.js"></script>
<script src="../assets/scripts/tools/json.js"></script>
<script>hljs.highlightAll();</script>
</head>
@@ -32,7 +31,7 @@
<button class="action-button active" id="clearXMLButton" style="padding: 3px 10px;"
onclick="clearJsonData()">Clear</button>
<button class="action-button active" id="defaultXMLButton" style="padding: 3px 10px;"
onclick="insertDefaultJson()">Insert default XML</button>
onclick="insertDefaultJson()">Insert default JSON</button>
</div>
</div>
<pre>
@@ -61,175 +60,5 @@
</div>
</div>
<script>
const mergeHTMLPlugin = (function () {
'use strict';
var originalStream;
/**
* @param {string} value
* @returns {string}
*/
function escapeHTML(value) {
return value
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#x27;');
}
/* plugin itself */
/** @type {HLJSPlugin} */
const mergeHTMLPlugin = {
// preserve the original HTML token stream
"before:highlightElement": ({el}) => {
originalStream = nodeStream(el);
},
// merge it afterwards with the highlighted token stream
"after:highlightElement": ({el, result, text}) => {
if (!originalStream.length) {
return;
}
const resultNode = document.createElement('div');
resultNode.innerHTML = result.value;
result.value = mergeStreams(originalStream, nodeStream(resultNode), text);
el.innerHTML = result.value;
}
};
/**
* @param {Node} node
*/
function tag(node) {
return node.nodeName.toLowerCase();
}
/**
* @param {Node} node
*/
function nodeStream(node) {
/** @type Event[] */
const result = [];
(function _nodeStream(node, offset) {
for (let child = node.firstChild; child; child = child.nextSibling) {
if (child.nodeType === 3) {
offset += child.nodeValue.length;
} else if (child.nodeType === 1) {
result.push({
event: 'start',
offset: offset,
node: child
});
offset = _nodeStream(child, offset);
if (!tag(child).match(/br|hr|img|input/)) {
result.push({
event: 'stop',
offset: offset,
node: child
});
}
}
}
return offset;
})(node, 0);
return result;
}
/**
* @param {any} original - the original stream
* @param {any} highlighted - stream of the highlighted source
* @param {string} value - the original source itself
*/
function mergeStreams(original, highlighted, value) {
let processed = 0;
let result = '';
const nodeStack = [];
function selectStream() {
if (!original.length || !highlighted.length) {
return original.length ? original : highlighted;
}
if (original[0].offset !== highlighted[0].offset) {
return (original[0].offset < highlighted[0].offset) ? original : highlighted;
}
return highlighted[0].event === 'start' ? original : highlighted;
}
/**
* @param {Node} node
*/
function open(node) {
/** @param {Attr} attr */
function attributeString(attr) {
return ' ' + attr.nodeName + '="' + escapeHTML(attr.value) + '"';
}
// @ts-ignore
result += '<' + tag(node) + [].map.call(node.attributes, attributeString).join('')
+ '>';
}
/**
* @param {Node} node
*/
function close(node) {
result += '</' + tag(node) + '>';
}
/**
* @param {Event} event
*/
function render(event) {
(event.event === 'start' ? open : close)(event.node);
}
while (original.length || highlighted.length) {
let stream = selectStream();
result += escapeHTML(value.substring(processed, stream[0].offset));
processed = stream[0].offset;
if (stream === original) {
/*
On any opening or closing tag of the original markup we first close
the entire highlighted node stack, then render the original tag along
with all the following original tags at the same offset and then
reopen all the tags on the highlighted stack.
*/
nodeStack.reverse().forEach(close);
do {
render(stream.splice(0, 1)[0]);
stream = selectStream();
} while (stream === original && stream.length && stream[0].offset === processed);
nodeStack.reverse().forEach(open);
} else {
if (stream[0].event === 'start') {
nodeStack.push(stream[0].node);
} else {
nodeStack.pop();
}
render(stream.splice(0, 1)[0]);
}
}
return result + escapeHTML(value.substr(processed));
}
return mergeHTMLPlugin;
}());
hljs.addPlugin(mergeHTMLPlugin);
function init() {
// Make sure that only plain text is pasted
configurePastingInElement("jsonBlock");
}
</script>
</body>
</html>

View File

@@ -3,55 +3,54 @@
<head>
<title>R11 MockedServices</title>
<meta charset="utf-8">
<link rel="stylesheet" href="../css/fontello.css" type="text/css">
<link rel="stylesheet" href="../css/main.css" type="text/css">
<!-- <link rel="stylesheet" href="css/common.css" type="text/css"> -->
<link rel="stylesheet" href="../css/common.css" type="text/css">
<link rel="stylesheet" href="../assets/css/tools/mock/fontello.css" type="text/css">
<link rel="stylesheet" href="../assets/css/tools/mock/main.css" type="text/css">
<link rel="stylesheet" href="../assets/css/tools/mock/common.css" type="text/css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- <script src="../js/dyn_host.js"></script> -->
</head>
<body>
<body onload="onLoad()">
<div class="popup-flex hiddable-container">
<div class="popup-body" id="popup-body">
<div class="popup-button-close-container">
<button type="button" class="popup-button-close"> X </button>
</div>
<div class="popup-header-table hiddable-popup-option" id="history-headers-table">
<table id="header-table">
<thead>
<tr>
<th>
Header Name
</th>
<th>
Header Value
</th>
</tr>
</thead>
<tbody id="header-history-table-body">
</tbody>
</table>
</div>
<div class="popup-request-body hiddable-popup-option" id="history-request-body">
<pre class="code-content" id="history-request-body-content"><code id="code-highlight-content"></code></pre>
</div>
</div>
</div>
<div class="container">
<div class="tool extended">
<div class="tool-context">
<div>
<h1>MockedServices</h1>
</div>
<div>
<label for="uuid-input" class="block-display">UUID</label>
<div id="uuid-edit">
<div id="uuid-edit-field" class="bordered-field disabled">
<input id="uuid-input" disabled onfocusout="changeUUID(this);" value="UUID" />
<button onclick="copyUUIDToClipboard();" class="uuid-inputField-icon modification-button flex-item btn-copy action-button">
<span class="material-icons uuid-inputField-icon-span ">content_copy</span>
</button>
</div>
<div id="editableBlock">
<input type="checkbox" onchange="changeEditionOfUUID(this)" name="editable" id="editable" value="false"/>
<label for="editable">Editable</label>
</div>
</div>
<div class="hiddable" id="uuid-validation-strategy">
<label><b>UUID generation strategy:</b></label>
<input type="radio" checked name="uuid-validation-type" value="new" id="generateNew"/>
<label for="generateNew">Generate new UUID</label>
<input type="radio" name="uuid-validation-type" value="restore" id="restore"/>
<label for="restore">Restore previous UUID</label>
</div>
</div>
<div>
<!-- h2 -->
<div id="basicItemData" class="hiddable active"><h2>Your Message</h2></div>
<div id="advancedItemData" class="hiddable"><h2>Messaged id: <span id="mockedMessageId">1</span></h2></div>
<div><h2>Your Message</h2></div>
<!-- link -->
<div>
<label for="messageLink" class="block-display">Link</label>
<div id="messageLink" class="bordered-field max-width with-padding disabled-background"><a class="hyperlink" href="www.google.com" target="_blank">www.google.com</a></div>
<div id="messageLink" class="bordered-field max-width with-padding disabled-background tooltipped"><a class="hyperlink" href="www.google.com" target="_blank">www.google.com</a></div>
<!-- <input id="messageLink" disabled class="bordered-field max-width with-padding" value="http://yourlink.com/r/api/mock/blablabla"> -->
</div>
<div class="display-space-between max-width">
@@ -60,7 +59,7 @@
<!-- status -->
<div class="max-width small-vertical-margin">
<label for="httpStatus">Http Status</label>
<input id="httpStatus" type="number" class="bordered-field max-width data-field" value="200" list="httpStatusSuggestion"/>
<input id="httpStatus" type="number" class="bordered-field max-width data-field tooltipped" value="200" list="httpStatusSuggestion"/>
<datalist id="httpStatusSuggestion">
<option value="200">
<option value="300">
@@ -69,12 +68,11 @@
<option value="404">
<option value="500">
</datalist>
</div>
<!-- content type -->
<div class="max-width small-vertical-margin">
<label for="typeSelector">Content Type</label>
<input id="typeSelector" class="bordered-field max-width data-field" type="text" value="application/xml" list="contentTypes">
<input id="typeSelector" class="bordered-field max-width data-field tooltipped" type="text" value="application/xml" list="contentTypes">
<datalist id="contentTypes">
<option value="application/xml">
<option value="application/json">
@@ -82,14 +80,14 @@
</datalist>
</div>
</div>
<div id="btnSave" class="small-margins half-width with-padding action-button" style="background-color: white; border: 0px;">
<div id="btnSave" class="small-margins half-width with-padding action-button tooltipped" style="background-color: white; border: 0px;">
<button id="btn-save" class="small-margins half-width with-padding action-button" style="width: 100%; height: 100%;">Save</button>
</div>
</div>
<!-- body -->
<div class="small-vertical-margin">
<label for="bodyEditor">Body</label>
<textarea id="bodyEditor" class="data-field bordered-field max-width with-padding height-300 vertically-resizeable"></textarea>
<textarea id="bodyEditor" class="data-field bordered-field max-width with-padding height-300 vertically-resizeable tooltipped"></textarea>
</div>
<!-- show/hide -->
<button id="optional" class="clickable-text highlight switch"><span class="toggleIndicator"></span> show/hide advanced settings</button>
@@ -97,8 +95,8 @@
<div id="advanced" class="max-width with-padding hiddable">
<!-- tab menu -->
<div class="tabmenu medium-vertical-margin">
<button id="headersTab" class="tabitem active clickable-text big-font">Headers</button>
<button id="historyTab" class="tabitem clickable-text big-font">History</button>
<button id="headersTab" class="tabitem active clickable-text big-font tooltipped">Headers</button>
<button id="historyTab" class="tabitem clickable-text big-font tooltipped">History</button>
</div>
<!-- container -->
<div class="medium-vertical-margin">
@@ -120,8 +118,8 @@
</tr>
</tbody>
<tr>
<td><input id="headerKeyInput" placeholder="name"></td>
<td><input id="headerValueInput" placeholder="value"></td>
<td><input id="headerKeyInput" class="tooltipped" placeholder="name"></td>
<td><input id="headerValueInput" class="tooltipped" placeholder="value"></td>
<td><button id="btn-newRow" class="modification-button btn-add"><i class="icon-plus"></i></button></td>
</tr>
</table>
@@ -129,40 +127,19 @@
<!-- history -->
<div id="history" class="medium-vertical-margin tabcontent">
<div class="block-display max-width">
<button id="btn-history-filter" class="clickable-text highlight switch"><span class="toggleIndicator"></span> filter</button>
<div id ="history-filter" class="display-space-between max-width small-vertical-margin hiddable">
<div class="three-fourth-width display-space-evenly">
<div class="block-display half-width with-padding">
<label for="historyFrom" class="block-label">From</label>
<input id="historyFrom" type="date" class="bordered-field max-width with-padding">
<input id="historyTimeFrom" type="time" class="small-vertical-margin bordered-field max-width with-padding">
</div>
<div class="block-display half-width with-padding">
<label for="historyTo" class="block-label">To</label>
<input id="historyTo" type="date" class="bordered-field max-width with-padding">
<input id="historyTimeTo" type="time" class="small-vertical-margin bordered-field max-width with-padding">
</div>
</div>
<button id="btn-searchHistory" class="quater-width action-button active small-margins">Search</button>
</div>
<button type="button" class="refresh-button" onclick="refreshHistoryRecords();" ></button>
<div class="max-width centered-content large-vertical-margin overflowedTableContent">
<table id="historyTable" class="table-default">
<thead>
<tr class="bottom-border">
<th>Timestamp</th>
<th>Type</th>
<th>Method</th>
<th>Request Body</th>
<th>Headers</th>
</tr>
</thead>
<tbody>
<!-- <tr class="even">
<td>2021-01-01T10:57:26</td>
<td>Client request</td>
</tr>
<tr>
<td>2021-01-01T10:57:26</td>
<td>Client request</td>
</tr> -->
</tbody>
</table>
</div>
@@ -172,31 +149,6 @@
</div>
</div>
</div>
<div id="selectMenuContent" class="tool-extention">
<!-- header -->
<div>
<h2>Message List</h2>
</div>
<!-- tile list -->
<div id="listItems">
<!-- <div class="tile">
<div class="content">
<div class="display-space-between">
<div class="centered-vertically">
<p>Id: 2</p>
<p>Status: 200</p>
</div>
<div>
<button id="test1" class="modification-button btn-tile"><i class="icon-cancel"></i></button>
</div>
</div>
</div>
</div> -->
</div>
<div id="new-tile" class="max-width centered-content small-vertical-margin">
<button id="btn-newtile" class="modification-button btn-addtile"><i class="icon-plus"></i></button>
</div>
</div>
</div>
<div class="tooltip-window lite">
<div>
@@ -216,36 +168,8 @@
<p>To save message, the message must be changed!</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="btn-newTileTip" class="tip">
<h3>Add new message</h3>
<p>This button adds new message.</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="UUIDFieldTip" class="tip">
<h3>UUID</h3>
<p>UUID is an Unique ID that represents you in API. By UUID your messages is saved in database. You can change it to access your previous configuration of mocked messages</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="UUIDValidationStrategyTip" class="tip">
<h3>UUID Checking Strategy</h3>
<p>When you provide invalid UUID you can choose what do with it. You can generate new UUID or restore previous.</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="UUIDEditionTip" class="tip">
<h3>UUID Edition</h3>
<p>Unlocks you ability to edit UUID</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="messagesTip" class="tip">
<h3>Message</h3>
<p>This is saved messages, with unique id.</p>
</div>
</div>
<div class="large-vertical-margin">
<div id="httpStatusTip" class="tip">
@@ -287,22 +211,12 @@
</div>
</div>
<div id="overlay"></div>
<div id="modal-uuidChanged" class="modal">
<div class="header">
<div>Change UUID info<i class="r-exclamation"></i></div>
<button onclick="window.location.reload();">&times;</button>
</div>
<div id="changeUUIDSuccess" class="body hiddable uuid-modal-body">Your message UUID has been changed successfully.</div>
<div id="newUUID" class="body hiddable uuid-modal-body">You provided wrong UUID! <br> New UUID has been generated!</div>
<div id="restoredUUID" class="body hiddable uuid-modal-body">You provided wrong UUID! <br> Old UUID has been restored!</div>
<div id="noChgUUID" class="body hiddable uuid-modal-body">You doesn't provide any change to UUID!</div>
</div>
<div id="modal-confirm" class="modal">
<div class="header">
<div>Message saved<i class="r-exclamation"></i></div>
<button>&times;</button>
</div>
<div class="body">Your message has been successfuly saved.<br>You might view it under the link.</div>
<div class="body">Your message has been successfully saved.<br>You might view it under the link.</div>
</div>
<div id="modal-query" class="modal">
<div class="header">
@@ -311,16 +225,18 @@
</div>
<div class="body">You haven't saved your message!<br> Do you want to save it?</div>
<div class="function">
<button type = "button" onclick = "updateData()" value = "Display">Save</button>
<button>No</button>
</div>
</div>
<script type="text/javascript" src="../js/modal.js"></script>
<script type="text/javascript" src="../js/uianimation.js"></script>
<script type="text/javascript" src="../js/datatransfer.js"></script>
<script type="text/javascript" src="../js/historyloader.js"></script>
<script type="text/javascript" src="../js/fiddle.js"></script>
<script type="text/javascript" src="../assets/scripts/tools/mock/modal.js"></script>
<script type="text/javascript" src="../assets/scripts/tools/mock//uianimation.js"></script>
<script type="text/javascript" src="../assets/scripts/tools/mock/datatransfer.js"></script>
<script type="text/javascript" src="../assets/scripts/tools/mock/historyloader.js"></script>
<script type="text/javascript" src="../assets/scripts/tools/mock/fiddle.js"></script>
<script type="text/javascript" src="../assets/scripts/tools/mock/popup.js"></script>
<script type="text/javascript" src="../assets/scripts/tools/xmlFormatter.js"></script>
<script type="text/javascript" src="../assets/scripts/tools/highlight.js"></script>
<script type="text/javascript" src="../assets/scripts/common/hljs.min.js"></script>
</body>
</html>

View File

@@ -5,8 +5,9 @@
<!-- <link rel="stylesheet" href="styles.css"> -->
<link rel="stylesheet" href="../assets/css/tools/r11form.css">
<link rel="stylesheet" href="../assets/css/highlight.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
<script src="../assets/scripts/common/hljs.min.js"></script>
<script src="../assets/scripts/tools/scripts.js"></script>
<script src="../assets/scripts/tools/xmlFormatter.js"></script>
<script src="../assets/scripts/tools/highlight.js"></script>
<script>hljs.highlightAll();</script>
@@ -62,20 +63,6 @@
</div>
<script>
function getProcessor() {
return "libxml";
}
function getVersion() {
return "1.0"
}
function init() {
configurePastingInElement("xmlArea");
}
</script>
</body>
</html>

View File

@@ -5,6 +5,7 @@
<link rel="stylesheet" href="../assets/css/tools/r11form.css">
<link rel="stylesheet" href="../assets/css/highlight.css">
<script src="../assets/scripts/common/hljs.min.js"></script>
<script src="../assets/scripts/tools/xpath.js"></script>
<script src="../assets/scripts/tools/scripts.js"></script>
<script src="../assets/scripts/tools/highlight.js"></script>
<script>hljs.highlightAll();</script>
@@ -17115,156 +17116,6 @@
</div>
<script>
function processVersionSelector() {
var processor = getProcessor();
var hideableOptions = document.getElementsByClassName("hideable");
for (let i = 0; i < hideableOptions.length; i++) {
hideableOptions[i].style = "display: none;";
}
if (processor == "xalan" || processor == "libxml") {
var xalanOptions = document.getElementsByClassName("xalan");
for (let i = 0; i < xalanOptions.length; i++) {
xalanOptions[i].style = "";
}
document.getElementById("versions").selectedIndex = 0;
}
else {
var saxonOptions = document.getElementsByClassName("saxon");
for (let i = 0; i < saxonOptions.length; i++) {
saxonOptions[i].style = "";
}
document.getElementById("versions").selectedIndex = 3;
}
processTooltip();
}
function processTooltip() {
var filter = "collapse" + getVersion();
var collList;
if (filter == "collapse3.0") {
document.getElementById("tooltipFunctionInfo").innerText = "XPath 3.0 functions";
hideList(document.getElementsByName("collapse10"));
hideList(document.getElementsByName("collapse20"));
showList(document.getElementsByName("collapse30"));
hideList(document.getElementsByName("collapse31"));
} else if (filter == "collapse3.1") {
document.getElementById("tooltipFunctionInfo").innerText = "XPath 3.1 functions";
hideList(document.getElementsByName("collapse10"));
hideList(document.getElementsByName("collapse20"));
hideList(document.getElementsByName("collapse30"));
showList(document.getElementsByName("collapse31"));
} else if (filter == "collapse2.0") {
document.getElementById("tooltipFunctionInfo").innerText = "XPath 2.0 functions";
hideList(document.getElementsByName("collapse10"));
showList(document.getElementsByName("collapse20"));
hideList(document.getElementsByName("collapse30"));
hideList(document.getElementsByName("collapse31"));
} else {
document.getElementById("tooltipFunctionInfo").innerText = "XPath 1.0 functions";
showList(document.getElementsByName("collapse10"));
hideList(document.getElementsByName("collapse20"));
hideList(document.getElementsByName("collapse30"));
hideList(document.getElementsByName("collapse31"));
}
}
var triggerList = document.getElementsByClassName("collapseTrigger");
for (i = 0; i < triggerList.length; i++) {
triggerList[i].addEventListener("click", function () {
var collapsible = this.parentElement;
if (this.tagName == "A") {
var collapsibleData = this.nextElementSibling;
} else {
var collapsibleData = this.parentElement.nextElementSibling;
}
if (collapsibleData.style.maxHeight > "0px") {
collapsibleData.style.maxHeight = "0px";
this.classList.toggle("active", false);
if (!this.classList.contains("collapsibleMini")) {
collapsible.classList.toggle("active", false);
}
var subLists1 = collapsibleData.getElementsByClassName("content");
var subLists2 = collapsibleData.getElementsByClassName("active");
for (j = 0; j < subLists1.length; j++) {
subLists1[j].style.maxHeight = "0px";
}
for (j = 0; j < subLists2.length; j++) {
subLists2[j].classList.toggle("active", false);
}
} else {
collapsibleData.style.maxHeight = (collapsibleData.scrollHeight) + "px";
this.classList.toggle("active", true);
if (!this.classList.contains("collapsibleMini")) {
collapsible.classList.toggle("active", true);
} else {
var parentContent = this.closest(".content");
parentContent.style.maxHeight = (parentContent.scrollHeight + collapsibleData.scrollHeight) + "px";
}
}
});
}
function init() {
// Make sure that only plain text is pasted
configurePastingInElement("xmlArea");
configurePastingInElement("transformArea");
//Handle clicks in whole form and set info in tooltip
setDefaultContent(document.getElementById("xmlArea"), 'Insert XML here');
setDefaultContent(document.getElementById("transformArea"), 'Insert XPath expression here');
processVersionSelector();
processTooltip();
tool.addEventListener('change', event => {
//Check if script was called from textarea or selector
var targetID = event.target.getAttribute('id');
if (targetID == "processors") {
processVersionSelector();
processTooltip();
}
else if (targetID == "versions") {
processTooltip();
}
})
tool.addEventListener('click', event => {
//Check if script was called from textarea or selector
var targetID = event.target.getAttribute('id');
if (targetID !== "xmlArea" && targetID !== "transformArea") {
return;
}
processTooltip();
})
tool.addEventListener('change', event => {
//Check if script was called from textarea or selector
var targetID = event.target.getAttribute('id');
if (targetID !== "xmlArea" && targetID !== "transformArea") {
return;
}
processTooltip();
})
}
</script>
</body>
</html>

View File

@@ -6,6 +6,7 @@
<link rel="stylesheet" href="../assets/css/tools/r11form.css">
<link rel="stylesheet" href="../assets/css/highlight.css">
<script src="../assets/scripts/common/hljs.min.js"></script>
<script src="../assets/scripts/tools/xsd.js"></script>
<script src="../assets/scripts/tools/scripts.js"></script>
<script src="../assets/scripts/tools/highlight.js"></script>
<script>hljs.highlightAll();</script>
@@ -79,45 +80,6 @@
</div>
<script>
function init() {
// Make sure that only plain text is pasted
configurePastingInElement("xmlArea");
configurePastingInElement("transformArea");
//Handle clicks in whole form and set info in tooltip
setDefaultContent(document.getElementById("xmlArea"), 'Insert XML here');
setDefaultContent(document.getElementById("transformArea"), 'Insert XSD here');
// refreshTooltip();
processTooltip();
tool.addEventListener('click', event => {
//Check if script was called from textarea or selector
var targetID = event.target.getAttribute('id');
if (targetID !== "processors" && targetID !== "xmlArea" && targetID !== "transformArea" && targetID !== "versions") {
return;
}
processTooltip();
})
}
function processTooltip() {
if (getProcessor() == "xalan") {
document.getElementById("tooltipFunctionInfo").innerText = "XSLT 1.0 functions";
document.getElementById("processorTooltipInfo").innerText = "Supports XSLT 1.0";
hideList(document.getElementsByName("collapse30"));
} else {
document.getElementById("tooltipFunctionInfo").innerText = "XSLT 1.0, 2.0 & 3.0 functions";
document.getElementById("processorTooltipInfo").innerText = "Supports XSLT up to 3.0";
showList(document.getElementsByName("collapse30"));
}
}
</script>
</body>
</html>

View File

@@ -6,6 +6,7 @@
<link rel="stylesheet" href="../assets/css/tools/r11form.css">
<link rel="stylesheet" href="../assets/css/highlight.css">
<script src="../assets/scripts/common/hljs.min.js"></script>
<script src="../assets/scripts/tools/xslt.js"></script>
<script src="../assets/scripts/tools/scripts.js"></script>
<script src="../assets/scripts/tools/highlight.js"></script>
<script>hljs.highlightAll();</script>
@@ -1147,93 +1148,6 @@
</div>
<script>
function processTooltip() {
if (getProcessor() == "xalan" || getProcessor() == "libxml") {
document.getElementById("tooltipFunctionInfo").innerText = "XSLT 1.0 functions";
document.getElementById("processorTooltipInfo").innerText = "Supports XSLT 1.0";
hideList(document.getElementsByName("collapse30"));
} else {
document.getElementById("tooltipFunctionInfo").innerText = "XSLT 1.0, 2.0 & 3.0 functions";
document.getElementById("processorTooltipInfo").innerText = "Supports XSLT up to 3.0";
showList(document.getElementsByName("collapse30"));
}
}
var triggerList = document.getElementsByClassName("collapseTrigger");
for (i = 0; i < triggerList.length; i++) {
triggerList[i].addEventListener("click", function () {
var collapsible = this.parentElement;
var collapsibleData = this.nextElementSibling;
if (collapsibleData.style.maxHeight > "0px") {
collapsibleData.style.maxHeight = "0px";
this.classList.toggle("active", false);
if (!this.classList.contains("collapsibleMini")) {
collapsible.classList.toggle("active", false);
}
var subLists1 = collapsibleData.getElementsByClassName("content");
var subLists2 = collapsibleData.getElementsByClassName("active");
for (j = 0; j < subLists1.length; j++) {
subLists1[j].style.maxHeight = "0px";
}
for (j = 0; j < subLists2.length; j++) {
subLists2[j].classList.toggle("active", false);
}
} else {
collapsibleData.style.maxHeight = (collapsibleData.scrollHeight) + "px";
this.classList.toggle("active", true);
if (!this.classList.contains("collapsibleMini")) {
collapsible.classList.toggle("active", true);
} else {
var parentContent = this.closest(".content");
parentContent.style.maxHeight = (parentContent.scrollHeight + collapsibleData.scrollHeight) + "px";
}
}
});
}
function init() {
// Make sure that only plain text is pasted
configurePastingInElement("xmlArea");
configurePastingInElement("transformArea");
//Handle clicks in whole form and set info in tooltip
setDefaultContent(document.getElementById("xmlArea"), 'Insert XML here');
setDefaultContent(document.getElementById("transformArea"), 'Insert XSLT here');
// refreshTooltip();
processTooltip();
tool.addEventListener('click', event => {
//Check if script was called from textarea or selector
var targetID = event.target.getAttribute('id');
if (targetID !== "processors" && targetID !== "xmlArea" && targetID !== "transformArea" && targetID !== "versions") {
return;
}
processTooltip();
})
tool.addEventListener('change', event => {
//Check if script was called from textarea or selector
var targetID = event.target.getAttribute('id');
if (targetID !== "processors") {
return;
}
processTooltip();
})
}
</script>
</body>
</html>

6
Redis/Dockerfile Normal file
View File

@@ -0,0 +1,6 @@
FROM redis:latest
EXPOSE 6379
# COPY redis.conf /usr/local/etc/redis/redis.conf
CMD [ "redis-server", "--save ''", "--appendonly no" ]

View File

@@ -1,3 +1,3 @@
url = "http://localhost:5000/minimize"
url = "http://localhost/libxml/minimize"
data = "@minimize.json"
request = POST

View File

@@ -1,3 +1,3 @@
url = "http://localhost:5000/prettify"
url = "http://localhost:5000/libxml/prettify"
data = "@prettify.json"
request = POST

View File

@@ -1,4 +1,4 @@
#url = "localhost:8081/xpath"
url = "localhost:5000/xpath"
url = "localhost/java/xpath"
#url = "localhost/libxml/xpath"
request = "POST"
data = "@data.json"

View File

@@ -1,4 +1,4 @@
#url = "localhost:8081/xpath"
url = "localhost:5000/xpath"
url = "localhost/java/xpath"
#url = "localhost/libxml/xpath"
request = "POST"
data = "@dataNS.json"

View File

@@ -1,4 +1,4 @@
#url = "http://localhost:8081/xsd"
url = "http://localhost:5000/xsd"
url = "localhost/java/xsd"
#url = "localhost/libxml/xsd"
data = "@xsd.json"
request = POST

View File

@@ -1,4 +1,4 @@
#url = "http://localhost:8081/xslt"
url = "http://localhost:5000/xslt"
url = "localhost/java/xslt"
#url = "localhost/libxml/xslt"
data = "@xslt.json"
request = POST

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,8 @@ version: "3"
services:
redis:
image: 'redis'
container_name: xmltools-redis
build: ./Redis
restart: "no"
xmltools-frontend:
@@ -10,21 +11,21 @@ services:
container_name: xmltools-frontend
image: xmltools-frontend
ports:
- 8086:80
- 80:80
xmltools-backend:
build: ./Backend/tools-services
container_name: xmltools-backend
image: xmltools-backend
ports:
- 8081:8081
- 8081:8081
xmltools-libxml-backend:
build: ./Backend-libXML
container_name: xmltools-libxml-backend
image: xmltools-libxml-backend
ports:
- 8082:80
- 8082:80
xmltools-mocked-services:
build:
@@ -38,6 +39,7 @@ services:
- redis
environment:
SPRING_PROFILES_ACTIVE: DEV
TZ: Europe/Warsaw
swagger:
image: "swaggerapi/swagger-ui:latest"