mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-22 20:13:52 +00:00
Preparations for mail notifications
This commit is contained in:
1 parent
4be2211bab
commit
579f83fade
17 files changed
+307
-47
No files matched your search
@@ -1,7 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -7,6 +7,8 @@ Bundle-Activator: com.sap.sailing.server.impl.Activator
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Import-Package: com.sap.sailing.server.gateway.deserialization,
|
||||
javax.mail;version="1.4.0",
|
||||
javax.mail.internet;version="1.4.0",
|
||||
org.json.simple,
|
||||
org.json.simple.parser,
|
||||
org.osgi.framework;version="1.3.0",
|
||||
@@ -33,7 +35,8 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sse.security,
|
||||
org.apache.shiro.web;bundle-version="1.2.2",
|
||||
org.apache.shiro.core;bundle-version="1.2.2",
|
||||
javax.servlet;bundle-version="3.1.0"
|
||||
javax.servlet;bundle-version="3.1.0",
|
||||
com.sap.sse.mail
|
||||
Bundle-ClassPath: .
|
||||
Export-Package: com.sap.sailing.server,
|
||||
com.sap.sailing.server.impl;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
source.. = src/
|
||||
source.. = src/,\
|
||||
resources/
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.
|
||||
@@ -0,0 +1,6 @@
|
||||
boatClassResultsSubject=New results for boat class {0} in regatta {1} of event {2}
|
||||
boatClassResultsBody=New results for boat class {0} in regatta {1} of event {2} are available. See: {3}
|
||||
boatClassUpcomingRaceSubject=A race for boat class {0} in regatta {1} of event {2} will start soon
|
||||
boatClassUpcomingRaceBody=A race for boat class {0} in regatta {1} of event {2} will start at {4}. See: {3}
|
||||
competitorResultsSubject=New results for competitor {0} in regatta {1} of event {2}
|
||||
competitorResultsBody=New results for competitor {0} in regatta {1} of event {2} are available. See: {3}
|
||||
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
@@ -46,49 +46,56 @@ public class Activator implements BundleActivator {
|
||||
private static final Logger logger = Logger.getLogger(Activator.class.getName());
|
||||
|
||||
private static final String CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME = "persistentcompetitors.clear";
|
||||
|
||||
|
||||
private static ExtenderBundleTracker extenderBundleTracker;
|
||||
|
||||
|
||||
private CachedOsgiTypeBasedServiceFinderFactory serviceFinderFactory;
|
||||
|
||||
private RacingEventServiceImpl racingEventService;
|
||||
|
||||
|
||||
private final boolean clearPersistentCompetitors;
|
||||
|
||||
|
||||
private Set<ServiceRegistration<?>> registrations = new HashSet<>();
|
||||
|
||||
private ObjectName mBeanName;
|
||||
|
||||
|
||||
private ServiceTracker<MasterDataImportClassLoaderService, MasterDataImportClassLoaderService> masterDataImportClassLoaderServiceTracker;
|
||||
|
||||
|
||||
private ServiceTracker<PolarDataService, PolarDataService> polarDataServiceTracker;
|
||||
|
||||
private OSGiBasedTrackedRegattaListener trackedRegattaListener;
|
||||
|
||||
|
||||
public Activator() {
|
||||
clearPersistentCompetitors = Boolean.valueOf(System.getProperty(CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME, ""+false));
|
||||
logger.log(Level.INFO, "setting "+CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME+" to "+clearPersistentCompetitors);
|
||||
clearPersistentCompetitors = Boolean
|
||||
.valueOf(System.getProperty(CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME, "" + false));
|
||||
logger.log(Level.INFO,
|
||||
"setting " + CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME + " to " + clearPersistentCompetitors);
|
||||
// there is exactly one instance of the racingEventService in the whole server
|
||||
}
|
||||
|
||||
|
||||
public void start(BundleContext context) throws Exception {
|
||||
extenderBundleTracker = new ExtenderBundleTracker(context);
|
||||
extenderBundleTracker.open();
|
||||
|
||||
|
||||
// TODO implement
|
||||
// MailQueue mailQueue = new ExecutorMailQueue(ServiceTrackerFactory.createAndOpen(context, MailService.class));
|
||||
// SailingNotificationService notificationService = new SailingNotificationServiceImpl(context, mailQueue);
|
||||
|
||||
trackedRegattaListener = new OSGiBasedTrackedRegattaListener(context);
|
||||
|
||||
|
||||
// At this point the OSGi resolver is used as device type service finder.
|
||||
// In the case that we are not in an OSGi context (e.g. running a JUnit test instead),
|
||||
// this code block is not run, and the test case can inject some other type of finder
|
||||
// instead.
|
||||
serviceFinderFactory = new CachedOsgiTypeBasedServiceFinderFactory(context);
|
||||
racingEventService = new RacingEventServiceImpl(clearPersistentCompetitors, serviceFinderFactory, trackedRegattaListener);
|
||||
|
||||
racingEventService = new RacingEventServiceImpl(clearPersistentCompetitors, serviceFinderFactory,
|
||||
trackedRegattaListener);
|
||||
|
||||
masterDataImportClassLoaderServiceTracker = new ServiceTracker<MasterDataImportClassLoaderService, MasterDataImportClassLoaderService>(
|
||||
context, MasterDataImportClassLoaderService.class,
|
||||
new MasterDataImportClassLoaderServiceTrackerCustomizer(context, racingEventService));
|
||||
masterDataImportClassLoaderServiceTracker.open();
|
||||
|
||||
|
||||
polarDataServiceTracker = new ServiceTracker<PolarDataService, PolarDataService>(context,
|
||||
PolarDataService.class, new PolarDataServiceTrackerCustomizer(context, racingEventService));
|
||||
polarDataServiceTracker.open();
|
||||
@@ -96,41 +103,39 @@ public class Activator implements BundleActivator {
|
||||
// register the racing service in the OSGi registry
|
||||
racingEventService.setBundleContext(context);
|
||||
final Dictionary<String, String> replicableServiceProperties = new Hashtable<>();
|
||||
replicableServiceProperties.put(Replicable.OSGi_Service_Registry_ID_Property_Name, racingEventService.getId().toString());
|
||||
replicableServiceProperties.put(Replicable.OSGi_Service_Registry_ID_Property_Name,
|
||||
racingEventService.getId().toString());
|
||||
context.registerService(Replicable.class.getName(), racingEventService, replicableServiceProperties);
|
||||
context.registerService(RacingEventService.class.getName(), racingEventService, null);
|
||||
context.registerService(ClearStateTestSupport.class.getName(), racingEventService, null);
|
||||
Dictionary<String, String> properties = new Hashtable<String, String>();
|
||||
final GPSFixMongoHandlerImpl gpsFixMongoHandler = new GPSFixMongoHandlerImpl(racingEventService.getMongoObjectFactory(),
|
||||
racingEventService.getDomainObjectFactory());
|
||||
final GPSFixMongoHandlerImpl gpsFixMongoHandler = new GPSFixMongoHandlerImpl(
|
||||
racingEventService.getMongoObjectFactory(), racingEventService.getDomainObjectFactory());
|
||||
properties.put(TypeBasedServiceFinder.TYPE, GPSFixImpl.class.getName());
|
||||
registrations.add(context.registerService(FixMongoHandler.class,
|
||||
gpsFixMongoHandler, properties));
|
||||
registrations.add(context.registerService(FixMongoHandler.class, gpsFixMongoHandler, properties));
|
||||
// legacy type name; some DBs may still contain fixes marked with this old package name:
|
||||
properties.put(TypeBasedServiceFinder.TYPE, "com.sap.sailing.domain.tracking.impl.GPSFixImpl");
|
||||
registrations.add(context.registerService(FixMongoHandler.class,
|
||||
gpsFixMongoHandler, properties));
|
||||
final GPSFixMovingMongoHandlerImpl gpsFixMovingMongoHandler = new GPSFixMovingMongoHandlerImpl(racingEventService.getMongoObjectFactory(),
|
||||
racingEventService.getDomainObjectFactory());
|
||||
registrations.add(context.registerService(FixMongoHandler.class, gpsFixMongoHandler, properties));
|
||||
final GPSFixMovingMongoHandlerImpl gpsFixMovingMongoHandler = new GPSFixMovingMongoHandlerImpl(
|
||||
racingEventService.getMongoObjectFactory(), racingEventService.getDomainObjectFactory());
|
||||
properties.put(TypeBasedServiceFinder.TYPE, GPSFixMovingImpl.class.getName());
|
||||
registrations.add(context.registerService(FixMongoHandler.class, gpsFixMovingMongoHandler, properties));
|
||||
// legacy type name; some DBs may still contain fixes marked with this old package name:
|
||||
properties.put(TypeBasedServiceFinder.TYPE, "com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl");
|
||||
registrations.add(context.registerService(FixMongoHandler.class, gpsFixMovingMongoHandler, properties));
|
||||
properties.put(TypeBasedServiceFinder.TYPE, DoubleVectorFixImpl.class.getName());
|
||||
registrations.add(context.registerService(FixMongoHandler.class, new DoubleVectorFixMongoHandlerImpl(racingEventService.getMongoObjectFactory(),
|
||||
racingEventService.getDomainObjectFactory()), properties));
|
||||
registrations.add(context.registerService(FixMongoHandler.class, new DoubleVectorFixMongoHandlerImpl(
|
||||
racingEventService.getMongoObjectFactory(), racingEventService.getDomainObjectFactory()), properties));
|
||||
|
||||
|
||||
registerPreferenceConvertersForUserStore(context);
|
||||
|
||||
|
||||
// Add an MBean for the service to the JMX bean server:
|
||||
RacingEventServiceMXBean mbean = new RacingEventServiceMXBeanImpl(racingEventService);
|
||||
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
|
||||
mBeanName = new ObjectName("com.sap.sailing:type=RacingEventService");
|
||||
mbs.registerMBean(mbean, mBeanName);
|
||||
logger.log(Level.INFO, "Started "+context.getBundle().getSymbolicName()+". Character encoding: "+
|
||||
Charset.defaultCharset());
|
||||
logger.log(Level.INFO, "Started " + context.getBundle().getSymbolicName() + ". Character encoding: "
|
||||
+ Charset.defaultCharset());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,14 +176,15 @@ public class Activator implements BundleActivator {
|
||||
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
|
||||
mbs.unregisterMBean(mBeanName);
|
||||
}
|
||||
|
||||
|
||||
private class MasterDataImportClassLoaderServiceTrackerCustomizer implements
|
||||
ServiceTrackerCustomizer<MasterDataImportClassLoaderService, MasterDataImportClassLoaderService> {
|
||||
|
||||
private final BundleContext context;
|
||||
private RacingEventServiceImpl racingEventService;
|
||||
|
||||
public MasterDataImportClassLoaderServiceTrackerCustomizer(BundleContext context, RacingEventServiceImpl racingEventService) {
|
||||
public MasterDataImportClassLoaderServiceTrackerCustomizer(BundleContext context,
|
||||
RacingEventServiceImpl racingEventService) {
|
||||
this.context = context;
|
||||
this.racingEventService = racingEventService;
|
||||
}
|
||||
@@ -193,7 +199,8 @@ public class Activator implements BundleActivator {
|
||||
|
||||
@Override
|
||||
public void modifiedService(ServiceReference<MasterDataImportClassLoaderService> reference,
|
||||
MasterDataImportClassLoaderService service) {}
|
||||
MasterDataImportClassLoaderService service) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removedService(ServiceReference<MasterDataImportClassLoaderService> reference,
|
||||
@@ -203,8 +210,8 @@ public class Activator implements BundleActivator {
|
||||
|
||||
}
|
||||
|
||||
private class PolarDataServiceTrackerCustomizer implements
|
||||
ServiceTrackerCustomizer<PolarDataService, PolarDataService> {
|
||||
private class PolarDataServiceTrackerCustomizer
|
||||
implements ServiceTrackerCustomizer<PolarDataService, PolarDataService> {
|
||||
|
||||
private final BundleContext context;
|
||||
private RacingEventServiceImpl racingEventService;
|
||||
@@ -231,5 +238,5 @@ public class Activator implements BundleActivator {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.sap.sailing.server.notification;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
public interface SailingNotificationService {
|
||||
|
||||
void notifyUserOnBoatClassResults(BoatClass boatClass, String eventName, String regattaDisplayName, String link);
|
||||
|
||||
void notifyUserOnBoatClassUpcomingRace(BoatClass boatClass, String eventName, String regattaDisplayName,
|
||||
TimePoint when, String link);
|
||||
|
||||
void notifyUserOnCompetitorResults(Competitor competitor, String eventName, String regattaDisplayName, String link);
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.sap.sailing.server.notification.impl;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.mail.BodyPart;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
|
||||
import com.sap.sse.mail.MailService;
|
||||
import com.sap.sse.mail.queue.MailNotification;
|
||||
import com.sap.sse.security.PreferenceObjectBasedNotificationSet;
|
||||
|
||||
public abstract class NotificationSetNotification<T> implements MailNotification {
|
||||
private static final Logger logger = Logger.getLogger(NotificationSetNotification.class.getName());
|
||||
|
||||
private final T objectToNotifyAbout;
|
||||
private final PreferenceObjectBasedNotificationSet<?, T> associatedNotificationSet;
|
||||
|
||||
public NotificationSetNotification(T objectToNotifyAbout, PreferenceObjectBasedNotificationSet<?, T> associatedNotificationSet) {
|
||||
this.objectToNotifyAbout = objectToNotifyAbout;
|
||||
this.associatedNotificationSet = associatedNotificationSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendNotifications(final MailService mailService) {
|
||||
// TODO idea (c) by Axel Uhl: In case of performance/mail queue problems: group mail addresses by locale and
|
||||
// send batches with the actual mail addresses as bcc?
|
||||
associatedNotificationSet.forUsersWithVerifiedEmailMappedTo(objectToNotifyAbout, (user) -> {
|
||||
// TODO user defined locale
|
||||
Locale locale = Locale.ENGLISH;
|
||||
Multipart multipart = new MimeMultipart();
|
||||
BodyPart bodyPart = new MimeBodyPart();
|
||||
try {
|
||||
bodyPart.setContent(constructBody(objectToNotifyAbout, locale), "text/html");
|
||||
multipart.addBodyPart(bodyPart);
|
||||
mailService.sendMail(user.getEmail(), constructSubject(objectToNotifyAbout, locale), multipart);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE,
|
||||
"Could not send mail notification for \"" + objectToNotifyAbout + "\" to user \" + user + \"", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract String constructSubject(T objectToNotifyAbout, Locale locale);
|
||||
|
||||
protected abstract String constructBody(T objectToNotifyAbout, Locale locale);
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
package com.sap.sailing.server.notification.impl;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.server.impl.preferences.BoatClassResultsNotificationSet;
|
||||
import com.sap.sailing.server.impl.preferences.BoatClassUpcomingRaceNotificationSet;
|
||||
import com.sap.sailing.server.impl.preferences.CompetitorResultsNotificationSet;
|
||||
import com.sap.sailing.server.notification.SailingNotificationService;
|
||||
import com.sap.sse.common.Stoppable;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.i18n.impl.ResourceBundleStringMessagesImpl;
|
||||
import com.sap.sse.mail.queue.MailQueue;
|
||||
|
||||
public class SailingNotificationServiceImpl implements Stoppable, SailingNotificationService {
|
||||
private static final String STRING_MESSAGES_BASE_NAME = "stringmessages/StringMessages";
|
||||
|
||||
private final Set<Stoppable> toStop = new HashSet<>();
|
||||
private final MailQueue mailQueue;
|
||||
private final ResourceBundleStringMessagesImpl messages;
|
||||
|
||||
private final BoatClassResultsNotificationSet boatClassResults;
|
||||
private final BoatClassUpcomingRaceNotificationSet boatClassUpcomingRace;
|
||||
private final CompetitorResultsNotificationSet competitorResults;
|
||||
|
||||
public SailingNotificationServiceImpl(BundleContext bundleContext, MailQueue mailQueue) {
|
||||
this.mailQueue = mailQueue;
|
||||
this.messages = new ResourceBundleStringMessagesImpl(STRING_MESSAGES_BASE_NAME,
|
||||
this.getClass().getClassLoader());
|
||||
|
||||
toStop.add(boatClassResults = new BoatClassResultsNotificationSet(bundleContext));
|
||||
toStop.add(boatClassUpcomingRace = new BoatClassUpcomingRaceNotificationSet(bundleContext));
|
||||
toStop.add(competitorResults = new CompetitorResultsNotificationSet(bundleContext));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
toStop.forEach(Stoppable::stop);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.sap.sailing.server.notification.SailingNotificationService#notifyUserOnBoatClassResults(com.sap.sailing.
|
||||
* domain.base.BoatClass, java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void notifyUserOnBoatClassResults(BoatClass boatClass, String eventName, String regattaDisplayName,
|
||||
String link) {
|
||||
mailQueue.addNotification(new NotificationSetNotification<BoatClass>(boatClass, boatClassResults) {
|
||||
@Override
|
||||
protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) {
|
||||
return messages.get(locale, "boatClassResultsSubject", boatClass.getDisplayName(), regattaDisplayName,
|
||||
eventName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) {
|
||||
return messages.get(locale, "boatClassResultsBody", boatClass.getDisplayName(), regattaDisplayName,
|
||||
eventName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.sap.sailing.server.notification.SailingNotificationService#notifyUserOnBoatClassUpcomingRace(com.sap.sailing.
|
||||
* domain.base.BoatClass, java.lang.String, java.lang.String, com.sap.sse.common.TimePoint, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void notifyUserOnBoatClassUpcomingRace(BoatClass boatClass, String eventName, String regattaDisplayName,
|
||||
TimePoint when, String link) {
|
||||
mailQueue.addNotification(new NotificationSetNotification<BoatClass>(boatClass, boatClassUpcomingRace) {
|
||||
@Override
|
||||
protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) {
|
||||
return messages.get(locale, "boatClassUpcomingRaceSubject", boatClass.getDisplayName(),
|
||||
regattaDisplayName, eventName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) {
|
||||
// TODO properly format time in the user's locale
|
||||
String time = when.toString();
|
||||
return messages.get(locale, "boatClassUpcomingRaceBody", boatClass.getDisplayName(), regattaDisplayName,
|
||||
eventName, time);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.sap.sailing.server.notification.SailingNotificationService#notifyUserOnCompetitorResults(com.sap.sailing.
|
||||
* domain.base.Competitor, java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void notifyUserOnCompetitorResults(Competitor competitor, String eventName, String regattaDisplayName,
|
||||
String link) {
|
||||
mailQueue.addNotification(new NotificationSetNotification<Competitor>(competitor, competitorResults) {
|
||||
@Override
|
||||
protected String constructSubject(Competitor objectToNotifyAbout, Locale locale) {
|
||||
return messages.get(locale, "competitorResultsSubject", competitor.getName(), regattaDisplayName,
|
||||
eventName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String constructBody(Competitor objectToNotifyAbout, Locale locale) {
|
||||
return messages.get(locale, "competitorResultsBody", competitor.getName(), regattaDisplayName,
|
||||
eventName);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user