According to Apache Sling official site(https://sling.apache.org/documentation/bundles/apache-sling-eventing-and-job-handling.html#job-consumers), this is the way to write JobConsumer.
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.event.jobs.Job;
import org.apache.sling.event.jobs.consumer.JobConsumer;
#Component
#Service(value={JobConsumer.class})
#Property(name=JobConsumer.PROPERTY_TOPICS, value="my/special/jobtopic",)
public class MyJobConsumer implements JobConsumer {
public JobResult process(final Job job) {
// process the job and return the result
return JobResult.OK;
}
}
However #Service and #Property are both deprecated annotations.
I want to know the proper way to create JobConsumer.
Does anyone know how to write a code equivalent to the above?
The scr annotations are deprecated in AEM and it is recommended to use the official OSGi Declarative Services annotations going forward. There is a seminar by Adobe on using the OSGi R7 annotations.
The new way of writing the same would be
import org.osgi.service.component.annotations.Component;
import org.apache.sling.event.jobs.Job;
import org.apache.sling.event.jobs.consumer.JobConsumer;
#Component(
immediate = true,
service = JobConsumer.class,
property = {
JobConsumer.PROPERTY_TOPICS +"=my/special/jobtopic"
}
)
public class MyJobConsumer implements JobConsumer {
public JobResult process(final Job job) {
// process the job and return the result
return JobResult.OK;
}
}
You can refer to the below blog. I have tried to explain it here.
https://www.linkedin.com/pulse/aem-how-write-sling-jobs-aem-veena-vikraman
Related
Given a Spring Data REST (SDR) server built with Spring Boot Gradle Plugin 2.2.5.RELEASE, is it possible to load an #Entity by self link within the server application?
I'm aware how to access it with an HTTP client, e.g. using curl:
$ curl localhost/users/1 # Responds with 200 OK and JSON representation
What I'm searching for is a mechanism to do this in the server using Java only, ideally using a standard SDR mechanism:
#Service
public class SelfLinkResolver {
public Object findBySelfLink(Link self) {
if (self == null || !self.getRel().equals(SELF)) {
throw new IllegalArgumentException("Non-null self link expected");
}
return null; // How to return the entity using a standard SDR mechanism?
}
public void exampleCall() {
Link self = new Link("localhost/users/1");
Object entity = findBySelfLink(self);
requireNonNull(entity, "Failed to load entity by self link");
}
}
An internal solution is parse your link and extract the ID (1 in your example), the call repository.findById(id).
Another solution would be new a RestTemplate, call your own API.
I finally came up with this solution, which uses SDR's UriToEntityConverter. In contrast to my question, it requires not only the self link, but also the entity class. It therefore doesn't fully answer my initial question.
I guess that there is no SDR solution that does not require the entity class, since there is no need for this within the framework, at least for usual API calls. SDR is always provided with the type information through the Repository, to which the self link refers. However, I didn't dive into other classes such as PersistentEntities, RepositoryInvokerFactory or Repositories, which might provide a solution for this.
WARNING: My tested implementation differs from this. This code is untested, but should illustrate the idea.
import lombok.NonNull;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.repository.support.Repositories;
import org.springframework.data.repository.support.RepositoryInvokerFactory;
import org.springframework.data.rest.core.UriToEntityConverter;
import org.springframework.hateoas.Link;
import org.springframework.stereotype.Component;
import java.net.URI;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static org.springframework.hateoas.IanaLinkRelations.SELF;
#Component
public class SelfLinkToEntityConverter extends UriToEntityConverter {
private static final TypeDescriptor URI_DESCRIPTOR = TypeDescriptor.valueOf(URI.class);
SelfLinkToEntityConverter(#NonNull PersistentEntities entities,
#NonNull RepositoryInvokerFactory invokerFactory,
#NonNull Repositories repositories) {
super(entities, invokerFactory, repositories);
}
#NonNull
public <T> Optional<T> findBySelfLink(#NonNull Link self, #NonNull Class<T> entityClass) {
checkArgument(self.getRel().equals(SELF), "Non-null self link expected");
URI uri = self.expand().toUri();
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(entityClass);
try {
#SuppressWarnings("unchecked")
T entity = (T) super.convert(uri, URI_DESCRIPTOR, typeDescriptor);
return Optional.ofNullable(entity);
} catch (IllegalArgumentException o_O) {
throw new IllegalArgumentException(format("Failed to load %s: %s",
entityClass.getSimpleName(), self.getHref()));
}
}
}
Can we have more than 1 implementation of IAnnotationTransformer in a project that is using TestNG?
I'm using TestNg version 7.0.0.
TestNG currently lets you wire in ONLY ONE implementation of IAnnotationTransformer. If you try to plug in multiple ones of them, the last one that got added is what will get invoked.
There's an open issue that is tracking this ask. See GITHUB-1894.
As an alternative you can build your own composite IAnnotationTransformer which can be used to iterate through all the other annotation transformer instances. Here's a sample (Its available in the above mentioned github link)
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import org.testng.IAnnotationTransformer;
import org.testng.annotations.ITestAnnotation;
import org.testng.collections.Lists;
import org.testng.internal.ClassHelper;
public class CompositeTransformer implements IAnnotationTransformer {
private static final String JVM_ARGS =
"com.rationaleemotions.github.issue1894.Listener1, com.rationaleemotions.github.issue1894.Listener2";
private List<IAnnotationTransformer> transformers = Lists.newArrayList();
public CompositeTransformer() {
// Ideally this would get a value from the command line. But just for demo purposes
// I am hard-coding the values.
String listeners = System.getProperty("transformers", JVM_ARGS);
Arrays.stream(listeners.split(","))
.forEach(
each -> {
Class<?> clazz = ClassHelper.forName(each.trim());
IAnnotationTransformer transformer =
(IAnnotationTransformer) ClassHelper.newInstance(clazz);
transformers.add(transformer);
});
}
#Override
public void transform(
ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
for (IAnnotationTransformer each : transformers) {
each.transform(annotation, testClass, testConstructor, testMethod);
}
}
}
I am following Spring RESTfull API tutorial. The tutorial asks to use Spring HATEOAS at some point. However, my IDE, STS, cannot find the references of the methods, linkTo and methodOn.
#GetMapping("/employees/{id}")
Resource<Employee> one(#PathVariable Long id) {
Employee emp = repository.findById(id)
.orElseThrow(() -> new EmployeeNotFoundException(id));
return new Resource<>(emp,
linkTo(methodOn(EmployeeController.class).one(id)).withSelfRel(),
linkTo(methodOn(EmployeeController.class).all()).withRel("employees")
);
}
Spring HATEOAS dependency is also here:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
The things I have tried:
Updating maven project
I am following the same tutorial and came across the same problem with the methods "linkTo" and "methodOn".
It seems like the import should be from:
import static org.springframework.hateoas.server.mvc.ControllerLinkBuilder.*;
However, it seems it is already deprecated and there is now WebMvcLinkBuilder suggested to be used:
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
I found clues in this class:
https://github.com/spring-projects/spring-hateoas-examples/blob/master/simplified/src/main/java/org/springframework/hateoas/examples/EmployeeController.java
More over, at the bottom of the tutorial page there is a link to the GitHub repo of complete project:
https://github.com/spring-guides/tut-rest
I also found problems running the "LoadDatabase.java" when following the tutorial. To fix this, I had to make it implement the CommandLineRunner and put the original code inside it's run method:
#Component
public class LoadDatabase implements CommandLineRunner {
private static final Logger log = LoggerFactory.getLogger(LoadDatabase.class);
#Override
public void run(String... args) throws Exception {
employeeRepository.save(new Employee("Bilbo", "Baggins", "burglar"));
employeeRepository.save(new Employee("Frodo", "Baggins", "thief"));
employeeRepository.findAll().forEach(employee -> log.info("Preloaded " + employee));
orderRepository.save(new Order("MacBook Pro", Status.COMPLETED));
orderRepository.save(new Order("iPhone", Status.IN_PROGRESS));
orderRepository.findAll().forEach(order -> {
log.info("Preloaded " + order);
});
}
#Autowired
EmployeeRepository employeeRepository;
#Autowired
OrderRepository orderRepository;
}
Here linkTo and methodOn are two static methods of org.springframework.hateoas.mvc.ControllerLinkBuilder class. You just need to add below two static import statements to your class:
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
OR just import ControllerLinkBuilder and use them as:
ControllerLinkBuilder.linkTo
ControllerLinkBuilder.methodOn
I used like that and it worked
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
#GetMapping("/employees/{id}")
EntityModel<Employee> one(#PathVariable Long id) {
Employee employee = repository.findById(id)
.orElseThrow(() -> new EmployeeNotFoundException(id));
return EntityModel.of(employee, //
WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(EmployeeController.class).one(id)).withSelfRel(),
WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(EmployeeController.class).all()).withRel("employees"));
}
due to fact that: ControllerLinkBuilder
is depreacted as mentioned here:
ControllerLinkBuilder java docs
WebMvcLinkBuilder should be used instead.
WebMvcLinkBuilder java docs
Consider using imports:
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
Looks like you need two imports:
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*; >>for the methodOn
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; >> for instatiating WebMvcLinkBuilder
I started my first project on Spring Boot 2 (RC1). Thanks to the already good documentation this has not been to hard coming from Spring Boot 1.x.
However now that I want to integrate metrics I'm stumbeling. As far as I was able to find currently there is only documentation for the metrics shipped by default. But I'd like to also measure service level execution time as well as the time used in dynamodb.
EDIT
I'm looking for a solution using Micrometer, the library used in the new actuator library shipped with spring-boot 2.
Is there any guide on how this should be done? From this I read that there is no easy annotation based solution for arbitrary spring beans yet. Could s.o. give me an example / link to documentation on how a method like below could be metered?
#Service
#Timed
public class MyService {
public void doSomething() {
...;
}
}
#io.micrometer.core.annotation.Timed annotation seems to be out of order for custom calls due to reduction of scope, at it is mentioned in link in your question.
You need to manually setup an Aspect:
#Configuration
#EnableAspectJAutoProxy
public class AutoTimingConfiguration {
#Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
}
This way method like this:
#Timed("GET_CARS")
public List<Car> getCars(){
return Lists.newArrayList();
}
will result in GET_CARS metric in /actuator/metrics (default) endpoint.
Here's a little sample which should get you going. There's more variants to Timer.record() which aren't shown here. (Also: Field injection only used for brevity.)
You don't have to put the called methods name into a tag. You can also make it part of the metric name itself. Just wanted to show what you could do.
Update 2018-03-12: As of Micrometer 1.0.0 a TimedAspect has been introduced so that you can also use the #Timed annotation. For now you need to register the Bean yourself. (You need to be cautious though when you have custom #Timed annotations on your Spring-MVC or Jersey resources.) This was already mentioned by Michal Stepan in a follow-up answer.
package io.github.mweirauch.micrometered.eval;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import io.micrometer.core.annotation.Timed;
import io.micrometer.core.aop.TimedAspect;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.Timer.Sample;
#Configuration
#EnableAspectJAutoProxy
public class TimingStuff {
#Service
static class MyService {
#Autowired
private MeterRegistry registry;
public void helloManual() {
// you can keep a ref to this; ok to call multiple times, though
Timer timer = Timer.builder("myservice").tag("method", "manual").register(registry);
// manually do the timing calculation
long start = System.nanoTime();
doSomething();
timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS);
}
public void helloSupplier() {
Timer timer = Timer.builder("myservice").tag("method", "supplier").register(registry);
// execution of the method is timed internally
timer.record(() -> doSomething());
}
public void helloSample() {
Timer timer = Timer.builder("myservice").tag("method", "sample").register(registry);
// records time taken between Sample creation and registering the
// stop() with the given Timer
Sample sample = Timer.start(registry);
doSomething();
sample.stop(timer);
}
// TimedAspect adds "class" and "method" tags
#Timed(value = "myservice.aspect")
public void helloAspect() {
doSomething();
}
private void doSomething() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
//
}
}
}
#Autowired
private MyService myService;
#Bean
TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
#Scheduled(fixedRate = 1000)
public void postConstruct() {
myService.helloManual();
myService.helloSupplier();
myService.helloSample();
myService.helloAspect();
}
}
In case you go for Prometheus, you'd end up with something like that:
# HELP myservice_seconds
# TYPE myservice_seconds summary
myservice_seconds_count{application="micrometered",method="manual",} 4.0
myservice_seconds_sum{application="micrometered",method="manual",} 0.200378014
myservice_seconds_max{application="micrometered",method="manual",} 0.050115291
myservice_seconds_count{application="micrometered",method="supplier",} 4.0
myservice_seconds_sum{application="micrometered",method="supplier",} 0.200393455
myservice_seconds_max{application="micrometered",method="supplier",} 0.05011635
myservice_seconds_count{application="micrometered",method="sample",} 4.0
myservice_seconds_sum{application="micrometered",method="sample",} 0.200527005
myservice_seconds_max{application="micrometered",method="sample",} 0.050250191
# HELP myservice_aspect_seconds
# TYPE myservice_aspect_seconds summary
myservice_aspect_seconds_count{application="micrometered",class="io.github.mweirauch.micrometered.eval.TimingStuff$MyService",method="helloAspect",} 4.0
myservice_aspect_seconds_sum{application="micrometered",class="io.github.mweirauch.micrometered.eval.TimingStuff$MyService",method="helloAspect",} 0.201824272
myservice_aspect_seconds_max{application="micrometered",class="io.github.mweirauch.micrometered.eval.TimingStuff$MyService",method="helloAspect",} 0.051014296
Is there a Extension Point for the Job REST API?
I want to add some information when http://server/jenkins/job/job_name/job_number/api/json is called.
Any hints?
OK, after a lot of research and tries, I've found the answer.
To expose additional data in the Job/Build REST API, the TransientActionFactory (http://javadoc.jenkins-ci.org/jenkins/model/TransientActionFactory.html) needs to be extended using the AbstractBuild (http://javadoc.jenkins-ci.org/hudson/model/AbstractBuild.html) as it type.
You'll have something like this:
import hudson.Extension;
import hudson.model.AbstractBuild;
import hudson.model.Action;
import java.util.Collection;
import java.util.Collections;
import jenkins.model.TransientActionFactory;
#Extension
public class MyTransientActionFactory extends TransientActionFactory<AbstractBuild> {
#Override
public Class<AbstractBuild> type() {
return AbstractBuild.class;
}
#Override
public Collection<? extends Action> createFor(AbstractBuild target) {
return Collections.singleton(new MyAction(target));
}
}
That will add MyAction to the AbstractBuild actions list which is shown in the REST API.