How to print some logs "before" a spring-data repository method, without custom repo - spring-data

I have a Spring data repository.
When http://localhost:8080/persons webservice is called, I want to log something. I DO NOT want to make MyCustomRepository<>. Cleaner options?
Repo class:
#RepositoryRestResource(collectionResourceRel = "persons", path = "persons")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
List<Person> findByLastName(#Param("name") String name);
Sample log:
log.error("AccessToken: " + securityContext.getTokenString());
log.error("User: {} / {}", accessToken.getPreferredUsername(), accessToken.getName());
log.error("Principal: {}", principal.getName());

You can create an aspect to intercept calls to your PersonRepository. From there you can access OAuth2 access token and the security context to retrieve the principal. Here is an example,
#Component
#Aspect
#Log
public class SecurityAspect {
#Autowired
private OAuth2ClientContext oauth2ClientContext;
#Pointcut("execution(public * my.example.repository.PersonRepository.*(..))")
public void pointcut() {
}
#Around("pointcut()")
public Object advice(ProceedingJoinPoint pjp) throws Throwable {
log.info(
"Entering SecurityAspect.advice() in class "
+ pjp.getSignature().getDeclaringTypeName()
+ " - method: " + pjp.getSignature().getName());
OAuth2AccessToken accessToken = oauth2ClientContext.getAccessToken();
log.info("AccessToken: " + accessToken);
if (SecurityContextHolder.getContext().getAuthentication()
instanceof OAuth2Authentication) {
OAuth2Authentication authentication =
(OAuth2Authentication) SecurityContextHolder.getContext().getAuthentication();
if (authentication.getUserAuthentication() instanceof UsernamePasswordAuthenticationToken) {
UsernamePasswordAuthenticationToken userToken =
(UsernamePasswordAuthenticationToken) authentication.getUserAuthentication();
log.info("Principal id: " + userToken.getPrincipal());
if (userToken.getDetails() instanceof Map) {
Map details = (Map) userToken.getDetails();
log.info("Principal Name: " + details.get("name"));
}
}
}
return pjp.proceed();
}
}

Related

Vertx.deployVerticle does not call the supplied completion handler

I writing a service where a deployed verticle is linked to a rest endpoint. The service is working 100% (I dynamically deployed the verticle and calling the REST endpoint execute a function on the verticle). The problem is that the supplied completion handler is never called. Any ideas?
Following is my code:
LOGGER.debug(String.format("Starting runner %s:%s:%s" ,functionName, faasFunctionClass, fileName));
DeploymentOptions deploymentOptions = new DeploymentOptions();
deploymentOptions.setInstances(1);
JsonObject jsonObject = new JsonObject();
jsonObject.put(FUNCTION_NAME, functionName);
jsonObject.put(FUNCTION_CLASS, faasFunctionClass);
jsonObject.put(FUNCTION_FILENAME, fileName);
deploymentOptions.setConfig(jsonObject);
LOGGER.debug(String.format("Deploying [%s]" ,jsonObject.encode()));
this.vertx.deployVerticle("faas:" + VertxFaasRunner.class.getCanonicalName(),deploymentOptions, event->{
if (event.succeeded()) {
System.out.println("Deployment id is: " + event.result());
} else {
System.out.println("Deployment failed!");
}
});
In this case it depends on how you have implemented your Verticle.
in the below code when future.complete() is executed then only event.succeeded() will be true.
public class MainVerticle extends AbstractVerticle {
#Override
public void start() throws Exception {
System.out.println("[Main] Running in " + Thread.currentThread().getName());
vertx
.deployVerticle("io.vertx.example.core.verticle.worker.WorkerVerticle",
new DeploymentOptions().setWorker(true), event -> {
if (event.succeeded()) {
System.out.println("Deployment id is: " + event.result());
} else {
System.out.println("Deployment failed!");
}
});
}
}
public class WorkerVerticle extends AbstractVerticle {
#Override
public void start(Future future) throws Exception {
System.out.println("[Worker] Starting in " + Thread.currentThread().getName());
vertx.eventBus().<String>consumer("sample.data", message -> {
System.out.println("[Worker] Consuming data in " + Thread.currentThread().getName());
String body = message.body();
message.reply(body.toUpperCase());
});
// this notifies that the verticle is deployed successfully.
future.complete();
}
}

Open Perspective programmatically

I am trying to provide a command/ handler to switch to a specific Perspective.
I came up with the following class:
public class OpenPerspectiveHandler {
private static final Logger logger = Logger.getLogger(OpenPerspectiveHandler.class);
#Inject
private MApplication application;
#Inject
private EModelService modelService;
#Inject
private EPartService partService;
private final String perspectiveId;
public OpenPerspectiveHandler(String perspectiveId) {
super();
this.perspectiveId = perspectiveId;
}
public void changePerspective(String perspectiveId) {
Optional<MPerspective> perspective = findPerspective();
if(perspective.isPresent()) {
partService.switchPerspective(perspective.get());
} else {
logger.debug("Perspective not found (" + perspectiveId + ")");
}
}
#Execute
public void execute() {
changePerspective(perspectiveId);
}
private Optional<MPerspective> findPerspective() {
MUIElement element = modelService.find(perspectiveId, application);
if(element instanceof MPerspective) {
return Optional.of((MPerspective)element);
} else {
logger.debug("Wrong type " + element);
}
return Optional.empty();
}
#Override
public String toString() {
return "OpenPerspectiveHandler [application=" + application + ", modelService=" + modelService + ", partService=" + partService + ", perspectiveId=" + perspectiveId + "]";
}
}
Interestingly, this works only once. A workaround is to cache MPerspective once it was found and not to use modelService.find(perspectiveId, application) again.
Why does it work only once? modelService.find(perspectiveId, application) returns null after the first execution.
EDIT:
Another approach (as suggested by greg-449) is the following:
public class OpenPerspectiveHandler {
private static final Logger logger = Logger.getLogger(OpenPerspectiveHandler.class);
private final String perspectiveId;
public OpenPerspectiveHandler(String perspectiveId) {
super();
this.perspectiveId = perspectiveId;
}
#Execute
public void changePerspective(MApplication application, EModelService modelService, EPartService partService) {
Optional<MPerspective> perspective = findPerspective(application, modelService);
if(perspective.isPresent()) {
partService.switchPerspective(perspective.get());
} else {
logger.debug("Perspective not found (" + perspectiveId + ")");
}
}
private Optional<MPerspective> findPerspective(MApplication application, EModelService modelService) {
MUIElement element = modelService.find(perspectiveId, application);
if(element instanceof MPerspective) {
return Optional.of((MPerspective)element);
} else {
logger.debug("Wrong type " + element);
}
return Optional.empty();
}
}
But this approach also changes the perspective only once. modelService.find(perspectiveId, application); returns null after the first execution.
The EPartService varies depending on the context that the handler runs in. In some cases you get the Application part service which only works if there is an active window.
You can get the part service for that window using something like:
MWindow window = (MWindow)modelService.find("top window id", application);
IEclipseContext windowContext = window.getContext();
EPartService windowPartService = windowContext.get(EPartService.class);

How to organize OrientDB DAO in case of transactions in multithreaded environment?

I try to organize architecture of my DAO with OrientDB.
Below - example of my:
Connection manager:
public class DB {
private static final OPartitionedDatabasePoolFactory poolFactory = new OPartitionedDatabasePoolFactory();
public static ODatabaseDocumentTx fromPool() {
return poolFactory.get(sDbUrl, sDbUser, sDbPassword).acquire();
}
}
Dao (it uses in multithreaded environment):
public class Dao {
public static void addGold(String rid, long gold) {
try (ODatabaseDocumentTx db = DB.fromPool()) {
final String updateQuery = "UPDATE " + rid + " INCREMENT gold = " + gold + " LOCK RECORD";
db.command(new OCommandSQL(updateQuery)).execute();
}
}
public static void removeGold(String rid, long gold) {
try (ODatabaseDocumentTx db = DB.fromPool()) {
final String updateQuery = "UPDATE " + rid + " INCREMENT gold = " + -gold + " LOCK RECORD";
db.command(new OCommandSQL(updateQuery)).execute();
}
}
public static String transferGold(String fromRid, String toRid, long gold) {
try (ODatabaseDocumentTx db = DB.fromPool()) {
int numTries = 100;
while (true) {
try {
db.begin(OTransaction.TXTYPE.OPTIMISTIC);
removeGold(fromRid, gold);
addGold(toRid, gold);
db.commit();
return "ok";
} catch (OConcurrentModificationException e) {
db.rollback();
if (--numTries == 0) {
return "error";
}
}
}
}
}
}
It's valid to get connection from pool in case of transaction? So same database instance will be returns in same thread?
Any other advice are welcome
Using the OPartitionedDatabasePool should be thread safe and provide a way to get your connections. I think the OPartitionedDatabasePoolFactory is only used if you want to create multiple OPartitionedDatabasePool instances.
A static instance of OPartitionedDatabasePool:
OPartitionedDatabasePool myPool = new OPartitionedDatabasePool(dbUrl, user, password);
And then anytime a thread needs a connection:
ODatabaseDocumentTx dbConnection = MyClass.myPool.acquire();
(As in your code with OPartitionedDatabasePoolFactory).
The pool should automatically handle getting a database connection that will function on your thread.

Spring Integration / Spring cloud Stream : How to send a single message using #inboundchanneladapter

I have the following piece of code :
#Bean
#InboundChannelAdapter(value = Source.OUTPUT, poller = #Poller(fixedDelay = "${fixedDelay}", maxMessagesPerPoll = "1"))
public MessageSource<String> timerMessageSource() {
logger.info("Sending Message");
return () -> new GenericMessage<>(new SimpleDateFormat().format(new Date()));
}
I wish to disable the poller so that i can send a single message out. How do i do that?
That wouldn't make this application a stream :-) You might just write a task that sends a single message out.
Code:
public interface MessageChannels {
#Output("activationMsgQueue")
MessageChannel save();
}
Code:
#Service
#EnableBinding(MessageChannels.class)
public class CloudStreamProducer implements MessageSender {
private static final Logger LOGGER = LoggerFactory
.getLogger(CloudStreamProducer.class);
#Autowired
MessageChannels msgChannel;
public void sendMessage(ActivationDataInfo msg) {
msgChannel.save().send(MessageBuilder.withPayload(msg).build());
LOGGER.info("Sent Activation Message to apt Topic : Acct NO = " + msg.getAcctNo()
+ " TN = " + msg.getTn() + " FlowType = " + msg.getFlowType());
}
}

Cometd : It seems that ServerChannel lose some subscribers

I used cometd to realize notification push, but i found out the following issue :
After log in the system, at the beginning, the client can receive message from server, but after wait pretty long time or do some other operation, the client may not receive message from server any more. Did anyone else encountered this problem? Thanks in Advance.
Blow is my code :
1. Client Code
var cometd = dojox.cometd;cometd.websocketEnabled = false;
cometd.init(url);
cometd.subscribe("/foo/new", function(message) {
......The business logic......
}
);
2. The ServletContextAttributeListener that integrate with AbstractService
public class BayeuxInitializerListener implements ServletContextAttributeListener {
private static final String CLIENT_CHANNEL = "/foo/new";
#Override
public void attributeAdded(ServletContextAttributeEvent event) {
if(BayeuxServer.ATTRIBUTE.equals(event.getName())) {
BayeuxServer bayeuxServer = (BayeuxServer) event.getValue();
boolean isCreated = bayeuxServer.createIfAbsent(CLIENT_CHANNEL, new ConfigurableServerChannel.Initializer() {
#Override
public void configureChannel(ConfigurableServerChannel channel) {
channel.setPersistent(true);
}
});
new MyService(bayeuxServer);
}
}
3. Service
public class MyService extends AbstractService {
private static final Logger logger = Logger.getLogger(MyService .class);
private static final String CLIENT_CHANNEL = "/foo/new";
private static final String LISTENER_CHANNEL = "/service/notification";
public MyService(BayeuxServer bayeuxServer) {
super(bayeuxServer, "notification");
this.addService(LISTENER_CHANNEL, "processNotification");
}
public void processNotification(ServerSession serverSession, Map<String, Object> data) {
LocalSession localSession = this.getLocalSession();
if(logger.isDebugEnabled()) {
logger.debug("Local Session : " + localSession.getId() + ".");
}
ServerChannel serverChannel = this.getBayeux().getChannel(CLIENT_CHANNEL)
Set<ServerSession> subscribers = serverChannel.getSubscribers();
if(0 == subscribers.size()) {
logger.info("There are no subcribers for " + CLIENT_CHANNEL + ".");
}
for(ServerSession subscriber : subscribers) {
logger.info("The subscriber for " + CLIENT_CHANNEL + " : " + subscriber.getId() + ".");
}
serverChannel.publish(localSession, data, null);
}