OSGi service snippets
Purpose: Service, configuration, scheduler and job skeletons with current DS annotations.
Who this page is for
| Audience | Why it matters to you |
|---|---|
| Backend engineers | Daily |
Configured service
public interface PremiumFormatter { String format(double amount); }
@Component(service = PremiumFormatter.class)
@Designate(ocd = PremiumFormatterImpl.Config.class)
public class PremiumFormatterImpl implements PremiumFormatter {
@ObjectClassDefinition(name = "PHI Premium Formatter")
@interface Config {
@AttributeDefinition(name = "Currency symbol") String currencySymbol() default "$";
@AttributeDefinition(name = "Suffix") String suffix() default "/month";
}
private Config cfg;
@Activate @Modified void activate(Config cfg) { this.cfg = cfg; }
@Override public String format(double amount) {
return String.format("%s%.2f %s", cfg.currencySymbol(), amount, cfg.suffix());
}
}
Config file (ui.config): com.academy.phi.core.services.impl.PremiumFormatterImpl.cfg.json
{ "currencySymbol": "$", "suffix": "/month" }
Service-user repository access
@Reference private ResourceResolverFactory resolverFactory;
private static final Map<String, Object> AUTH =
Map.of(ResourceResolverFactory.SUBSERVICE, "rating-sync");
public void updateRates(List<Rate> rates) {
try (ResourceResolver rr = resolverFactory.getServiceResourceResolver(AUTH)) {
Resource root = rr.getResource("/var/phi/rates");
// … write, then:
rr.commit();
} catch (LoginException | PersistenceException e) {
LOG.error("Rate update failed", e);
}
}
(Plus the mapper config: org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended~phi.cfg.json → {"user.mapping": ["com.academy.phi.core:rating-sync=phi-rating-sync"]} — pattern.)
Scheduled task + durable job pair
@Component(service = Runnable.class)
@Designate(ocd = NightlyRateSync.Config.class)
public class NightlyRateSync implements Runnable {
@ObjectClassDefinition interface Config {
@AttributeDefinition String scheduler_expression() default "0 0 2 * * ?";
@AttributeDefinition boolean scheduler_concurrent() default false;
}
@Reference private JobManager jobManager;
@Override public void run() { jobManager.addJob("phi/rates/sync", Map.of()); }
}
@Component(service = JobConsumer.class,
property = JobConsumer.PROPERTY_TOPICS + "=phi/rates/sync")
public class RateSyncConsumer implements JobConsumer {
@Override public JobResult process(Job job) {
// idempotent work; OK / FAILED (retry) / CANCEL (drop)
return JobResult.OK;
}
}