Pagination continuation token Java/Spring boot examples/tutorials - java

I am having a task of implementing a continuation token for a spring boot app.
So basically I have a duo which contains list of devices:
#Data
public class ResponseDTO implements Serializable {
#JsonProperty("Devices")
private List<Device> devices = new ArrayList<>();
/**
* App
* <p>
*
* (Required)
*
*/
#JsonProperty("App")
private App app;
}
How can I do that? I never done this before, I always used standard Spring pagination. Now I am trying to find some examples, tutorials, but I didn't find anything interesting.
Please help.

Related

How to change message type detection strategy?

I’m using a custom RabbitMQ client in application A and Spring Amqp Library in application B.
I’ve faced with a problem: How to decide witch #RabbitListener to use for different message types?
Problem:
I send custom messages from app A to app B. In a message I set custom header “type” - it’s not a default property and not a default Spring Amqp Header (which is “_ _ TypeId _ _”) - just a new custom header.
In application B (spring amqp) I have to decide which listener to use. As I understood, Spring Amqp uses “_ _ TypeId _ _” as a default mechanism of “message type detection strategy” (I don’t know how to call it properly), but I wanna use my own “strategy”.
I’ve found the next trick, but it seems quite strange and not obvious:
private void determineMessageType(Message message) {
MessageProperties props = message.getMessageProperties();
Map<String, Object> headers = props.getHeaders();
final String type = String.valueOf(headers.get("type"));
if ("popularity-report".equals(type)) {
props.getHeaders().put("__TypeId__",
PopularityReportCommand.class.getName());
}
}
Can I use custom type detection strategy for Spring Amqp application somehow? Or how to solve these the problem properly in Spring Amqp?
The mentioned _ _ TypeId _ _ is used only for JSON message converters. So, if that really a case for you in the part what you really send from that producer, then you can take a look into the AbstractJackson2MessageConverter.setJavaTypeMapper(Jackson2JavaTypeMapper). The default one DefaultJackson2JavaTypeMapper has a property like this:
public String getClassIdFieldName() {
return DEFAULT_CLASSID_FIELD_NAME;
}
Which really is that mentioned above name:
public static final String DEFAULT_CLASSID_FIELD_NAME = "__TypeId__";
so, if you are able to extend this DefaultJackson2JavaTypeMapper and override that getter for your custom header mapper, then that Jackson2JsonMessageConverter can convert properly incoming JSON data into a desired type presented by your custom header. Then #RabbitListener would accept the value.
But you still need to be sure that typePrecedence on that mapper is set to TYPE_ID:
/**
* Set the precedence for evaluating type information in message properties.
* When using {#code #RabbitListener} at the method level, the framework attempts
* to determine the target type for payload conversion from the method signature.
* If so, this type is provided in the
* {#link MessageProperties#getInferredArgumentType() inferredArgumentType}
* message property.
* <p>
* By default, if the type is concrete (not abstract, not an interface), this will
* be used ahead of type information provided in the {#code __TypeId__} and
* associated headers provided by the sender.
* <p>
* If you wish to force the use of the {#code __TypeId__} and associated headers
* (such as when the actual type is a subclass of the method argument type),
* set the precedence to {#link Jackson2JavaTypeMapper.TypePrecedence#TYPE_ID}.
*
* #param typePrecedence the precedence.
* #since 1.6
*/
public void setTypePrecedence(TypePrecedence typePrecedence) {
Otherwise it consults the #RabbitListener method signature.
See more info in docs: https://docs.spring.io/spring-amqp/docs/current/reference/html/#Jackson2JsonMessageConverter-from-message

Cron Scheduler with WebClient

I am working with a spring boot. I am trying to send data from one database to the other.
First, I did this by making a get request to get the data from the first database and applied post through Web Client to send the data to the other database. It worked!
But when I tried to do it with cron scheduler with #Scheduled annotation it's not posting the data to the database. Even though the function is working fine, as i tried printing stuff through that function, but the WebClient is not posting the data (also checked the data, it was fine).
The Cron class is:
#Component
public class NodeCronScheduler {
#Autowired
GraphService graphService;
#Scheduled(cron = "*/10 * * * * *")
public void createAllNodesFiveSeconds()
{
graphService.saveAlltoGraph("Product");
}
}
saveAlltoGraph function takes all the tuples from a Product table and send post request to the api of graph database, which makes node from the tuples.
Here is the function:
public Mono<Statements> saveAlltoGraph(String label) {
JpaRepository currentRepository = repositoryService.getRepository(label);
List<Model> allModels = currentRepository.findAll();
Statements statements = statementService.createAllNodes(allModels, label);
//System.out.println(statements);
return webClientService.sendStatement(statements);
}
First, the label "Product" is used to get the JpaRepository related to that table. Then we fetch all the tuples of that table in the list, and we create objects according to that, (We can use a serializer to get the JSON).
Here is the sendStatement function:
public Mono<Statements> sendStatement(Statements statements){
System.out.println(statements);
return webClient.post().uri("http://localhost:7474/db/data/transaction/commit")
.body(Mono.just(statements), Statements.class).retrieve().bodyToMono(Statements.class);
}
Everything is working when we call this saveAlltoGraph using a get request mapping, but not working with the scheduler.
I tried with adding .block() and .subscribe() to that. And things started working with the cron scheduler.

What is MultiServerUserRegistry in spring websocket?

In package org.springframework.messaging.simp.user there is a class MultiServerUserRegistry.
This class looks like it would work on multi-server application, but I could not find any documentation that could help me understand how it works or how should I use it.
What does this class do and how do I use it? How do I use websocket to work on multi-server application?
The default publish mechanism use a local sessions repository to resolve socket id for a user.
If you are setting up a cluster, you can't use this strategy. We need to use a remote repository.
The removeRepository already exists in Spring as MultiServerUserRegistry. To active it you just have to configure your MessageBrokerRegistry :
registry.enableStompBrokerRelay("/topic/", "/queue/", "/exchange/")
.setUserDestinationBroadcast("/topic/unresolved-user")
.setUserRegistryBroadcast("/topic/user-registry")
It works fine for me. I hope that it will help.
According to the MultiServerUserRegistry's JavaDoc, it's an implementation of SimpUserRegistry, which enable us to look up both local and remote user registries.
SimpUserRegistry that looks up users in a "local" user registry as
well as a set of "remote" user registries. The local registry is provided as
a constructor argument while remote registries are updated via broadcasts
handled by UserRegistryMessageHandler which in turn notifies this
registry when updates are received.
Another SimpUserRegistry's implementation is DefaultSimpUserRegistry, which could only get local user.
I read the related source code knowing that when we config setUserRegistryBroadcast in the enableStompBrokerRelay, a MultiServerUserRegistry will be created, and we can get all the users' online state regardless which server they connected in cluster.
Here is the key source code in AbstractMessageBrokerConfiguration:
#Bean
#SuppressWarnings("deprecation")
public SimpUserRegistry userRegistry() {
SimpUserRegistry registry = createLocalUserRegistry();
if (registry == null) {
registry = createLocalUserRegistry(getBrokerRegistry().getUserRegistryOrder());
}
boolean broadcast = getBrokerRegistry().getUserRegistryBroadcast() != null;
return (broadcast ? new MultiServerUserRegistry(registry) : registry);
}
As this function annotated with #Bean, we can get the SimpUserRegistry instance by #Autowired:
#Autowired
private SimpUserRegistry simpUserRegistry;
Using this interface, we have the ability to:
/**
* Get the user for the given name.
* #param userName the name of the user to look up
* #return the user, or {#code null} if not connected
*/
#Nullable
SimpUser getUser(String userName);
/**
* Return a snapshot of all connected users.
* <p>The returned set is a copy and will not reflect further changes.
* #return the connected users, or an empty set if none
*/
Set<SimpUser> getUsers();
/**
* Return the count of all connected users.
* #return the number of connected users
* #since 4.3.5
*/
int getUserCount();
/**
* Find subscriptions with the given matcher.
* #param matcher the matcher to use
* #return a set of matching subscriptions, or an empty set if none
*/
Set<SimpSubscription> findSubscriptions(SimpSubscriptionMatcher matcher);
We can use it to get the count of all the online users (by getUserCount) in our whole cluster, and detect whether a specific user is online or not (by getUser).
As my practice, the following message broker configure is suggested in multi-server scenario:
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableStompBrokerRelay("/topic", "/queue")
.setUserDestinationBroadcast("/topic/log-unresolved-user")
.setUserRegistryBroadcast("/topic/log-user-registry")
.setRelayHost(brokerConfig.getHost())
.setRelayPort(brokerConfig.getPort())
.setVirtualHost(brokerConfig.getVirtualHost())
.setClientLogin(brokerConfig.getUsername())
.setClientPasscode(brokerConfig.getPassword())
.setSystemLogin(systemUsername)
.setSystemPasscode(systemPassword);
}

A RESTful api, multiple types of user access problems?

A RESTful api, multiple types of user access problems? Api as follows:
/ articles / 1 get It's means that getting an article;
/**
* 获得文章
*
* #param authorId
* #param articleId
* #return
*/
#GetMapping("/articles/{articleId}")
public ArticleEntity getArticle(#CurrentAuthor AuthorEntity author,
#PathVariable("articleId") Integer articleId) {
// get one article for author
ArticleEntity article = articleService.get(author.getId(), articleId);
// get one article for visitor
// ArtilceEntity article = articleVisitorService.get(articleId);
return article;
}
For article viewers, you can only get articles that have a status of published.
For the author of the article, you can get a variety of status (draft, published, recyclable) article.
In the program I used the custom annotation #Authorization and the Spring MVC interceptor to specify which controller methods are logged in to access, obviously this method is not suitable for this way.
If you use the above api, how to distinguish between the request which belongs to the user?
For this api, how to use login authentication?
If the design is unreasonable api, then please give me some suggestions?
thank you very much!

How to create a custom User-Provider for symfony2?

I'm new to symfony and php5 (I'm Java, Spring, Grails developer).
I'm working on a project which has a java-middleware and a php frontend with symfony 2.
The java middleware stores the users and everything my application needs.
I don't want symfony2 to have it's own database. All of the information symfony2 needs comes from the java-middleware via WSDL and my php-soap-api that I can include into my symfony2 project.
The users need to login in the frontend. So I have to write login and logout functionality.
The java-middleware supplys a login method that I can call in php over the php-soap-api.
How should I implement the login/logout functionality in symfony2? Should I implement a custom User-provider which calls the php-soap-api? If yes, how can I do this? ( http://symfony.com/doc/2.0/cookbook/security/custom_provider.html ) isn't available.
Have a look at the User Provider Interface documentation...I think one way is build your own implementation of the interface, which will act as a wrapper for WSDL calls, and then properly setup your security context (security.yml) to use it.
I've got a similar problem, and I'm trying to build my own User Provider as well.
Yes, you will need create your own user provider and add it as a service your Symfony app. The user provider class you create must implement the UserProviderInterface
To get your class started here is an example of my custom class located in Namespace/Bundle/Security/Provider.php:
namespace CB\WebsiteBundle\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use CB\WebsiteBundle\Entity\User;
class Provider implements UserProviderInterface {
protected $user;
public function __contsruct (UserInterface $user) {
$this->user = $user;
}
/**
* Loads the user for the given username.
*
* This method must throw UsernameNotFoundException if the user is not
* found.
*
* #throws UsernameNotFoundException if the user is not found
* #param string $username The username
*
* #return UserInterface
*/
function loadUserByUsername($username) {
$user = User::find(array('username'=>$username));
if(empty($user)){
throw new UsernameNotFoundException('Could not find user. Sorry!');
}
$this->user = $user;
return $user;
}
/**
* Refreshes the user for the account interface.
*
* It is up to the implementation if it decides to reload the user data
* from the database, or if it simply merges the passed User into the
* identity map of an entity manager.
*
* #throws UnsupportedUserException if the account is not supported
* #param UserInterface $user
*
* #return UserInterface
*/
function refreshUser(UserInterface $user) {
return $user;
}
/**
* Whether this provider supports the given user class
*
* #param string $class
*
* #return Boolean
*/
function supportsClass($class) {
return $class === 'MC\WebsiteBundle\Entity\User';
}
}
Some key things to note in this class is that it uses a custom User entity that you would define yourself which would facilitate the connection to your Java middleware. In my case, I am connecting to a REST api to get my user information and my user class uses the User::find($criteria) static function to find users by username.
Once you have your own User class that interacts with your middleware, and you have your new provider, you need to add the provider as a service in your bundle configuration: YourBundle/Resources/config.xml:
<parameters>
<parameter key="cb_security_user.class">CB\WebsiteBundle\Entity\User</parameter>
<parameter key="cb_security_provider.class">CB\WebsiteBundle\Security\Provider</parameter>
</parameters>
<services>
<service id="cb_security_user" class="%cb_security_user.class%" />
<service id="cb_security_provider" class="%cb_security_provider.class%">
<argument type="service" id="cb_security_user" />
</service>
</services>
You can find more details on my blog post here: Custom User Providers in Symfony2
Hope this helps!

Categories