Spring boot push notification restTemplate - spring-boot

I have a web application using spring boot as a back end and vue.js as a front end, and I have a script python capture frames and when get information send it to server and the last add a row to database, So I need to get notification, Can I use RestTemplate ? If yes how can I do it ?
#PostMapping("/plate")
public ResponseEntity<Void> createPositionOc(#RequestParam String plate) {
LocalDateTime myDateObj = LocalDateTime.now();
DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
List<Car> cars = carController.getAllCars();
boolean exist = cars.stream().anyMatch(o -> o.getPlate().equals(plate));
List<Car> carsIn = carController.getAllCarsIn();
boolean existIn = carsIn.stream().anyMatch(o -> o.getPlate().equals(plate));
List<Position> free = getAllPositiosFree();
PositionOcp position = new PositionOcp(free.get(0).getId_pos(), plate,
myDateObj.format(myFormatObj));
if (exist && free.size() > 0 && !existIn) {
PositionOcp createdPositionOc = positionOcpRepository.save(position);
//send notification
}
return null;
}

You need to layer your code first.
Create a service and inject in your controller class. All the logic that you will write, should be in service layer. Not in your controller. Then you need the inject your repository layer in your service class. Thats the layering.
You created an endpoint in your Controller class..
#PostMapping("/plate")
public ResponseEntity<Plate> createPositionOc(#RequestParam String plate) {
return ResponseEntity.ok(service.createPosition(plate));
}
in your service layer you can easily add a row to database...
For your frontend ; you need the gave it something to use. You should return what you are gonna use in the front. Return them a model to use.
Resttemplate is for communicate the services. I cant ask a question , not quite understand phyton part.

Related

How to assign values, call method in Subscribe method in Spring boot web client(non blocking)

I have a Spring boot application. End point A calls three different REST endpoints X, Y, Z. All the calls were using RestTemplate. I am trying to change from RestTemplate to Webclient. As a part of this I changed endpoint Y from RestTemplate to Webclient.
I had a blocking code. It was working as expected. But when I changed it to non-blocking using subscribe things are not working as expected.
With Blocking code
public class SomeImplClass {
#Autowired
private WebClient webClient;
public someReturnType someMethodName()
{
List myList = new ArrayList<>();
Mono<SomeResponse> result = this.webclient.post().uri(url).header(…).bodyValue(….).retrieve().bodyToMone(responseType);
someResponse = result.block(someDuration);
if(someResponse.getId().equals(“000”)
{
myList.addAll(this.somemethod(someResponse));
}else{
log.error(“some error”);
throw new SomeCustomException(“some error”)
}
return myList;
}
With Non Blocking Code
public class SomeImplClass {
#Autowired
private WebClient webClient;
public someReturnType someMethodName()
{
List myList = new ArrayList<>();
Mono<SomeResponse> result = this.webclient.post().uri(url).header(…).bodyValue(….).retrieve().bodyToMone(responseType);
result.subscribe(someResponse -> {
if(someResponse.getId().equals(“000”)
{
myList.addAll(this.somemethod(someResponse));
}
else{
log.error(“some error”);
throw new SomeCustomException(“some error”) //Not able to throw custom exception here.
}
});
return myList;
}
I am getting 2 issues
With non-blocking code the list which I am returning is empty. I guess return is called before subscribe consumes the data. How to resolve this? I tried result.doOnSuccess and doOnNext but both are not working. If I ad d Thread.sleep(5000) before return, everything is working as expected. How to achieve this without adding Thread.sleep.
I am able to throw RunTimeExceptions alone from subscribe. How to throw customeExceptions.

SSE events, check if there is active session

In a Spring Boot application I have an endpoint which returns a Flux which is set with a custom Sink similar to this post.
I dont have a Flux with interval.
The code looks like this, constructor:
private final Flux<MyDto> events;
public MyController(MyService service,
EventPublisher publisher
) {
this.service = service;
this.events = Flux.create(publisher).share();
}
API:
#GetMapping(path = "/path/events-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<MyDto> fluxEvents() {
return this.events.map(event -> {
return (MyDto) event.getSource();
});
}
The event is triggered by an external factor exactly like the post mentioned.
How can I know if there are active connections on the events-stream ?
I need this to know if I should trigger new events to the user
The question is asked here again with no answer

Looking for Matched CachePublicMetrics in spring-boot 2.1.9.release

I am using following classes in one of controllers of (spring-boot.1.5.12 release)
I am unable to find matching classes in spring 2.1.9 release.
The following is the code snippet
import org.springframework.boot.actuate.endpoint.CachePublicMetrics;
import org.springframework.boot.actuate.metrics.Metric;
public class CachingController extends CloudRestTemplate {
#Autowired
private CachePublicMetrics metrics;
public #ResponseBody Map<String, Object> getData(#Pattern(regexp=Constants.STRING_VALID_PATTERN, message=Constants.STRING_INVALID_MSG) #PathVariable(required = true) final String name) throws Exception {
boolean success = false;
Map<String, Object> m = Maps.newHashMap();
Collection<Metric<?>> resp = new ArrayList<>();
Collection<Metric<?>> mets = metrics.metrics();
for (Iterator<Metric<?>> iterator = mets.iterator(); iterator.hasNext();) {
Metric<?> met = iterator.next();
String metName = met.getName();
logger.debug(metName+":"+met.getValue());
if(StringUtils.isNotEmpty(metName)
&& metName.indexOf(name) != -1 ){
resp.add(met);
}
}
}
I think you should take a deeper look into Spring boot actuator, once you expose your all endpoints you might find what you are looking for. Spring Boot provides bunch of pre-defined endpoints, below is a list of Spring boot actuator endpoints (source)
/auditevents: Exposes audit events information for the current application.
/beans: Returns list of all spring beans in the application.
/caches: Gives information about the available caches.
/health: Provides applications health information.
/conditions: Provides list of conditions those were evaluated during auto configurations.
/configprops: Returns list of application level properties.
/info: Provides information about current application. This info can be configured in a properties file.
/loggers: Displays logging configurations. Moreover, this endpoint can be used to modify the configurations.
/headdump: Produces a head dump file and returns it.
/metrics: Returns various metrics about the application. Includes memory, heap and threads info. However, this endpoint doesn’t return any metrics. While, it only returns list of available metrics, the
metrics names can be used in a separate request to fetch the respective details. For instance, /actuator/metrics/jvm.memory.max like this.
/scheduledtasks: Returns a list of Scheduled tasks in the application.
/httptrace: Returns last 100 http interactions in the form of request and response. Including, the actuator endpoints.
/mappings: List of all Http Request Mappings. Also includes the actuator endpoints.
Edit:
As discussed in comments, you need to access /actuator/metrics/jvm.memory.max , you can invoke same using RestTemplate if you want to access using Java, you need to explore Actuator APIs, I wrote a quick program, you can refer the same
#Autowired
private MetricsEndpoint metricsEndpoint;
public MetricResponse printJavaMaxMemMetrics() {
ListNamesResponse listNames = metricsEndpoint.listNames();
listNames.getNames().stream().forEach(name -> System.out.println(name));
MetricResponse metric = metricsEndpoint.metric("jvm.memory.max", new ArrayList<>());
System.out.println("metric (jvm.memory.max) ->" + metric);
List<AvailableTag> availableTags = metric.getAvailableTags();
availableTags.forEach(tag -> System.out.println(tag.getTag() + " : " + tag.getValues()));
List<Sample> measurements = metric.getMeasurements();
measurements.forEach(sample -> System.out.println(sample.getStatistic() + " : " + sample.getValue()));
return metric;
}

How to mimic SimpMessagingTemplate.convertAndSendToUser using RabbitTemplate?

So I've been reading about Spring Message Relay (Spring Messaging stuff) capability with a RabbitMQ broker. What I want to achieve is as follows:
Have a service (1), which acts as a message relay between rabbitmq and a browser. This works fine now. I'm using MessageBrokerRegistry.enableStompBrokerRelay to do that.
Have another service (2) on the back-end, which will send a message to a known queue onto RabbitMQ and have that message routed to a specific user. As a sender, I want to have a control over who the message gets delivered to.
Normally, you'd use SimpMessagingTemplate to do that. Problem is though, that the origin of the message doesn't actually have access to that template, as it's not acting as a relay, it's not using websockets and it doesn't hold mapping of queue names to session ids.
One way I could think of doing it, is writing a simple class on the service 1, which will listen on all queues and forward them using simp template. I fell however this is not an ideal way to do it, and I feel like there might be already a way to do it using Spring.
Can you please advise?
This question got me thinking about the same dilemma I was facing. I have started playing with a custom UserDestinationResolver that arrives at a consistent topic naming scheme that uses just the username and not the session ID used by the default resolver.
That lets me subscribe in JS to "/user/exchange/amq.direct/current-time" but send via a vanilla RabbitMQ application to "/exchange/amqp.direct/users.me.current-time" (to a user named "me").
The latest source code is here and I am "registering" it as a #Bean in an existing #Configuration class that I had.
Here's the custom UserDestinationResolver itself:
public class ConsistentUserDestinationResolver implements UserDestinationResolver {
private static final Pattern USER_DEST_PREFIXING_PATTERN =
Pattern.compile("/user/(?<name>.+?)/(?<routing>.+)/(?<dest>.+?)");
private static final Pattern USER_AUTHENTICATED_PATTERN =
Pattern.compile("/user/(?<routing>.*)/(?<dest>.+?)");
#Override
public UserDestinationResult resolveDestination(Message<?> message) {
SimpMessageHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, SimpMessageHeaderAccessor.class);
final String destination = accessor.getDestination();
final String authUser = accessor.getUser() != null ? accessor.getUser().getName() : null;
if (destination != null) {
if (SimpMessageType.SUBSCRIBE.equals(accessor.getMessageType()) ||
SimpMessageType.UNSUBSCRIBE.equals(accessor.getMessageType())) {
if (authUser != null) {
final Matcher authMatcher = USER_AUTHENTICATED_PATTERN.matcher(destination);
if (authMatcher.matches()) {
String result = String.format("/%s/users.%s.%s",
authMatcher.group("routing"), authUser, authMatcher.group("dest"));
UserDestinationResult userDestinationResult =
new UserDestinationResult(destination, Collections.singleton(result), result, authUser);
return userDestinationResult;
}
}
}
else if (accessor.getMessageType().equals(SimpMessageType.MESSAGE)) {
final Matcher prefixMatcher = USER_DEST_PREFIXING_PATTERN.matcher(destination);
if (prefixMatcher.matches()) {
String user = prefixMatcher.group("name");
String result = String.format("/%s/users.%s.%s",
prefixMatcher.group("routing"), user, prefixMatcher.group("dest"));
UserDestinationResult userDestinationResult =
new UserDestinationResult(destination, Collections.singleton(result), result, user);
return userDestinationResult;
}
}
}
return null;
}
}

Orientdb partitioned graph java implementation

I've got a backend Spring application and Orientdb graph database. I use Tinkerpop Frames to map orientdb vertices to java objects and OPS4J for spring transaction management. Now I want to implement there a multitenancy where several customers (tenants) uses this one application instance. This application completely works on REST principles and it is opened to several Angular applications - each per customer. So there's as many frontend Angular applications as our customers and only one backend REST Spring application. Backend recognize the tenant from a HTTP request.
Now I'm not sure about the best solution...
First solution
When I read the Orientdb documentation, I found there a way how to implement multitenancy in orientdb - http://orientdb.com/docs/2.1/Partitioned-Graphs.html. However I don't know how to use it through the Java API unless I don't want to create a new database connection for each request. Because right now the spring transaction manager takes connections from connection pool which is centrally set in Spring transaction management configuration. I didn't find any Java example to this.
Spring transaction management config:
#Configuration
#EnableTransactionManagement
public class TransactionConfig {
#Bean
#Qualifier("graphDbTx")
public OrientTransactionManager graphDbTransactionManager() {
OrientTransactionManager bean = new OrientTransactionManager();
bean.setDatabaseManager(graphDatabaseFactory());
return bean;
}
#Bean
public OrientBlueprintsGraphFactory graphDatabaseFactory() {
OrientBlueprintsGraphFactory dbf = new OrientBlueprintsGraphFactory();
dbf.setMaxPoolSize(6);
dbf.setUrl(DbConfig.DATABASE_URL);
dbf.setUsername("admin");
dbf.setPassword("admin");
return dbf;
}
#Bean
public FramedGraphFactory framedGraphFactory() {
return new FramedGraphFactory(new JavaHandlerModule());
}
}
Getting connection:
protected FramedGraph<OrientGraph> framedGraph() {
return framedGraphFactory.create(gdbf.graph());
}
Second solution
Another solution is to use the Tinkerpop
PartitionGraph
class which works on Orientdb but I didn't find any sentence about this possibility in Orientdb documentation. Just this in Tinkerpop - https://github.com/tinkerpop/blueprints/wiki/Partition-Implementation. It works but in the end it just creates a not indexed property in every orientdb vertex so I'm afraid about performance of querying here.
Does anyone have any experiences with this? Any suggestion?
Using the Java API to create a partitioned DB (if I understand what you're interested in) macro steps are:
get connection (using the pool the istance of db are reused);
modify class V and E; create new user enable to write;
when you log in the db, user1 can write Vertices, invisible to the
user2 and contrary;
//WRITE IN YOUR CONTROLLER: CREATE USER ENABLE TO WRITE ON DB ..............
Connection con = new Connection();
OrientGraph noTx = con.getConnection();
//create partition
noTx.begin();
noTx.command(new OCommandSQL("ALTER CLASS V superclass orestricted")).execute();
noTx.command(new OCommandSQL("ALTER CLASS E superclass orestricted")).execute();
noTx.commit();
//create different users
noTx.begin();
String ridRule = "";
Iterable<Vertex> rule = noTx.command(new OCommandSQL("select from ORole where name = 'writer'")).execute();
ridRule = rule.iterator().next().getId().toString();
noTx.command(new OCommandSQL("INSERT INTO ouser SET name = 'user1', status = 'ACTIVE', password = 'user1', roles = ["+ridRule+"]")).execute();
noTx.command(new OCommandSQL("INSERT INTO ouser SET name = 'user2', status = 'ACTIVE', password = 'user2', roles = ["+ridRule+"]")).execute();
noTx.commit();
//will not close the graph instance, but will keep open and available for the next requester
noTx.shutdown();
//finally To release all the instances and free all the resources
con.clodeAllConnect();
//WRITE IN YOUR CONTROLLER: LOGIN WITH USER APPROPRIATE .....................
//CODE to login with user1 or user2, CREATE VERTEX SET label = 'food', name = 'Pizza' etc....
}
//beans
public static class Connection {
private OrientGraphFactory factory = null;
public Connection() {
//recyclable pool of instances
factory = new OrientGraphFactory("remote:localhost/blog").setupPool(1, 10);
}
//return the connection
public OrientGraph getConnection() {
OrientGraph txGraph = factory.getTx();
return txGraph;
}
public void clodeAllConnect(){
factory.close();
}
}
To adapt these steps and insert them in Spring might be useful this link that is OrientDB - spring implementation. it isn't much but I hope will be of help.

Resources