Java tutorial
/** * Copyright (C) 2013 Seajas, the Netherlands. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.seajas.search.attender.wsdl; import com.seajas.search.attender.bridge.model.notifier.NotifierProfile; import com.seajas.search.attender.model.profile.ProfileSubscriber; import com.seajas.search.attender.model.profile.ProfileSubscriber.NotificationType; import com.seajas.search.attender.model.searchresult.SearchResult; import com.seajas.search.attender.service.attender.AttenderService; import com.seajas.search.attender.service.mail.MailService; import com.seajas.search.attender.service.search.SearchService; import com.seajas.search.attender.service.template.TemplateService; import com.seajas.search.attender.service.template.TemplateService.TemplateResult; import com.seajas.search.attender.wsdl.profile.ProfileError; import com.seajas.search.utilities.ui.InterfaceQueryUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.TimeZone; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.validator.EmailValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.context.NoSuchMessageException; import org.springframework.http.MediaType; import org.springframework.transaction.annotation.Transactional; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.script.ScriptException; /** * Simple profile service implementation. * * @author Jasper van Veghel <jasper@seajas.com> */ @WebService(endpointInterface = "com.seajas.search.attender.wsdl.IProfile") @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.WRAPPED) @Transactional public class Profile implements IProfile { /** * The logger. */ private static final Logger logger = LoggerFactory.getLogger(Profile.class); /** * Attender service. */ @Autowired private AttenderService attenderService; /** * Template service. */ @Autowired private TemplateService templateService; /** * Search service. */ @Autowired private SearchService searchService; /** * Mail service. */ @Autowired private MailService mailService; /** * The message source. */ @Autowired private MessageSource messageSource; /** * {@inheritDoc} */ @Override public List<ProfileError> createProfile(final String email, final String emailLanguage, final String timeZone, final String notificationType, final Integer day, final Integer hour, final Integer minute, final Integer interval, final Integer maximum, final String query, final String searchParameterFormat, final String searchParameterLanguage, final String searchParameterAuthor, final String searchParameterType, final String searchParameterGeo, final List<Integer> taxonomyIdentifiers) { List<ProfileError> errors = new ArrayList<ProfileError>(); // Validate the given input if (StringUtils.isEmpty(query)) errors.add(new ProfileError("query", "profiles.error.query.empty")); String unescapedQuery = StringEscapeUtils.unescapeXml(StringEscapeUtils.unescapeXml(query)); // Validate the subscriber(s) String[] emails = email.trim().split(","); for (String subscriberEmail : emails) if (StringUtils.isEmpty(subscriberEmail.trim()) || !EmailValidator.getInstance().isValid(subscriberEmail.trim())) errors.add(new ProfileError("email", "profiles.error.subscriber.emails.invalid")); if (StringUtils.isEmpty(emailLanguage)) errors.add(new ProfileError("emailLanguage", "profiles.error.subscriber.email.languages.invalid")); else if (!attenderService.getAvailableSearchLanguages().contains(emailLanguage)) errors.add(new ProfileError("emailLanguage", "profiles.error.subscriber.email.languages.invalid")); if (StringUtils.isEmpty(timeZone)) errors.add(new ProfileError("timeZone", "profiles.error.subscriber.timezones.invalid")); else if (!Arrays.asList(TimeZone.getAvailableIDs()).contains(timeZone) && !timeZone.matches("^GMT[+\\-][0-9]{2}:[0-9]{2}$")) errors.add(new ProfileError("timeZone", "profiles.error.subscriber.timezones.invalid")); if (StringUtils.isEmpty(notificationType)) errors.add(new ProfileError("notificationType", "profiles.error.subscriber.types.invalid")); else try { NotificationType.valueOf(notificationType); } catch (IllegalArgumentException e) { errors.add(new ProfileError("notificationType", "profiles.error.subscriber.types.invalid")); } if (day == null) errors.add(new ProfileError("day", "profiles.error.subscriber.days.invalid")); else if (day < 0 || day > 6) errors.add(new ProfileError("day", "profiles.error.subscriber.days.invalid")); if (hour == null) errors.add(new ProfileError("subscriberHours", "profiles.error.subscriber.hours.invalid")); else if (hour < 0 || hour > 23) errors.add(new ProfileError("subscriberHours", "profiles.error.subscriber.hours.invalid")); if (minute == null) errors.add(new ProfileError("minute", "profiles.error.subscriber.minutes.invalid")); else if (minute < 0 || minute > 59) errors.add(new ProfileError("minute", "profiles.error.subscriber.minutes.invalid")); // Validate the search parameters if (!StringUtils.isEmpty(searchParameterFormat)) try { MediaType.parseMediaTypes(searchParameterFormat.replaceAll(" ", ",")); } catch (IllegalArgumentException e) { errors.add(new ProfileError("searchParameterFormat", "profiles.error.search.parameter.format.invalid")); } else if (!StringUtils.isEmpty(searchParameterLanguage)) { if (!attenderService.getAvailableSearchLanguages().contains(searchParameterLanguage)) errors.add(new ProfileError("searchParameterLanguage", "profiles.error.search.parameter.language.invalid")); } // Validate the taxonomy identifiers for (Integer taxonomyIdentifier : taxonomyIdentifiers) if (taxonomyIdentifier == null) errors.add(new ProfileError("taxonomyIdentifiers", "profiles.error.taxonomy.identifiers.empty")); // Add it up if there aren't any errors if (errors.size() == 0) { List<ProfileSubscriber> subscribers = new ArrayList<ProfileSubscriber>(emails.length); for (String subscriberEmail : emails) subscribers.add(new ProfileSubscriber(subscriberEmail.trim(), emailLanguage, false, null, timeZone, NotificationType.valueOf(notificationType), day, hour, minute, interval, maximum, null)); Map<String, String> searchParameters = new HashMap<String, String>(); if (!StringUtils.isEmpty(searchParameterFormat)) searchParameters.put("dcterms_format", searchParameterFormat); if (!StringUtils.isEmpty(searchParameterLanguage)) searchParameters.put("dcterms_language", searchParameterLanguage); if (!StringUtils.isEmpty(searchParameterAuthor)) searchParameters.put("dcterms_author", searchParameterAuthor); if (!StringUtils.isEmpty(searchParameterType)) searchParameters.put("dcterms_type", searchParameterType); if (!StringUtils.isEmpty(searchParameterGeo)) searchParameters.put("geo_total", searchParameterGeo); attenderService.addProfile(unescapedQuery, true, subscribers, searchParameters, taxonomyIdentifiers); } return errors; } /** * {@inheritDoc} */ @Override public List<NotifierProfile> retrieveConfirmedDirectNotifierProfiles() { List<NotifierProfile> result = new ArrayList<NotifierProfile>(); for (ProfileSubscriber subscriber : attenderService .getConfirmedProfileSubscribersByType(NotificationType.Direct)) { com.seajas.search.attender.model.profile.Profile profile = attenderService .getProfileById(subscriber.getProfileId()); // Round up the search parameters and taxonomies into a concise parameter list Map<String, String> searchParameters = InterfaceQueryUtils.combineParametersAndTaxonomies( profile.getSearchParametersMap(), profile.getTaxonomyIdentifierNumbers()); List<String> searchParameterList = InterfaceQueryUtils .createSearchParameterListFromParameters(searchParameters); if (logger.isInfoEnabled()) { logger.info("Adding subscriber '" + subscriber.getUniqueId() + "' (e-mail = '" + subscriber.getEmail() + "') and query '" + profile.getQuery() + "'"); for (String searchParameter : searchParameterList) logger.info("\tAdding search parameter '" + searchParameter + "' to notifier profile with e-mail " + subscriber.getEmail()); } // And add it all up to form a notifier profile result.add(new NotifierProfile(subscriber.getUniqueId(), subscriber.getEmail(), subscriber.getEmailLanguage(), profile.getQuery(), searchParameterList, subscriber.getNotificationInterval(), subscriber.getNotificationMaximum())); } return result; } /** * Send out a direct notification result for the given profile subscriber. * * @param subscriberUUID * @param result * @return Boolean */ @Override public Boolean sendDirectNotificationResult(final String subscriberUUID, final SearchResult result) { ProfileSubscriber subscriber = attenderService.getProfileSubscriberByUUID(subscriberUUID); if (subscriber == null) { logger.error("Subscriber " + subscriberUUID + " is unknown - not sending notification result"); return false; } com.seajas.search.attender.model.profile.Profile profile = attenderService .getProfileById(subscriber.getProfileId()); // First determine if we should be sending anything at all if (subscriber.getNotificationMaximum() != -1) { Integer messagesRemaining = attenderService .countAndAdjustRemainingDirectMessagesByProfileSubscriberId(subscriber.getId()); if (messagesRemaining > 0) { if (logger.isInfoEnabled()) logger.info("Profile subscriber has " + messagesRemaining + " messages remaining in its interval threshold"); } else { if (logger.isInfoEnabled()) logger.info("Profile subscriber " + subscriber.getUniqueId() + " has reached its interval threshold - not notifying"); return false; } } // Adjust the result so that taxonomy IDs are resolved to their respective names List<SearchResult> adjustedResult = searchService .adjustSourceIds(Arrays.asList(new SearchResult[] { result }), subscriber.getEmailLanguage()); // Create a new UTC-based calendar to base ourselves on Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); Date utcDate = calendar.getTime(); // Round up the search parameters and taxonomies into a concise parameter list Map<String, String> searchParameters = InterfaceQueryUtils.combineParametersAndTaxonomies( profile.getSearchParametersMap(), profile.getTaxonomyIdentifierNumbers()); String searchQuery = InterfaceQueryUtils.createQueryFromParameters(profile.getQuery(), searchParameters); // Now create a template result based on the search results try { TemplateResult templateResult = templateService.createResults(subscriber.getEmailLanguage(), searchQuery, profile.getQuery(), subscriber.getUniqueId(), profile.getUniqueId(), adjustedResult); if (templateResult != null) { // Take the subject in the given language, or resort to the default language if it doesn't exist (yet) String subject = null; try { subject = messageSource.getMessage( "mail.results.subject." + subscriber.getNotificationType().toString().toLowerCase(), new Object[] { profile.getQuery() }, new Locale(subscriber.getEmailLanguage())); } catch (NoSuchMessageException e) { logger.warn("Could not retrieve results message subject header in language " + subscriber.getEmailLanguage() + ", resorting to the default language " + attenderService.getDefaultApplicationLanguage()); subject = messageSource.getMessage("mail.confirmation.subject", new Object[] { profile.getQuery() }, new Locale(attenderService.getDefaultApplicationLanguage())); } // And send out the actual e-mail boolean mailResult = true; if (isMailServerConfigured()) mailResult = mailService.sendMessage(subscriber.getEmail(), subject, templateResult.getTextResult(), templateResult.getHtmlResult()); else { logger.error( "Could not e-mail the results message - no mail server has been configured. Users may retrieve results using the RSS feed."); return false; } // Update the processed subscribers' lastNotification indicator attenderService.updateProfileSubscriberLastNotification(subscriber.getId(), utcDate); if (mailResult) { if (logger.isInfoEnabled()) logger.info("Successfully sent out mail result for subscriber " + subscriber.getUniqueId() + " and e-mail address '" + subscriber.getEmail() + "'"); // Add it to the list of sent messages, so that we can keep track of the maximum - but only if there is one if (subscriber.getNotificationMaximum() != -1) attenderService.addProfileSubscriberMessage(subscriber.getId()); } else logger.error("Could not send mail result for subscriber " + subscriber.getUniqueId() + " and e-mail address '" + subscriber.getEmail() + "'"); return mailResult; } else { logger.error("No results template could be generated - not sending results e-mail"); return false; } } catch (ScriptException e) { logger.error("Could not create a template result", e); return false; } } /** * {@inheritDoc} */ @Override public Boolean sendGeneralMessage(final String fromAddress, final String toAddress, final String subject, final String content) { logger.error("TODO: Need to implement this (add new template type 'generic' or something)"); return false; } /** * {@inheritDoc} */ @Override public Integer countProfiles() { return attenderService.getProfileCount(); } /** * {@inheritDoc} */ @Override public Integer countDisabledProfiles() { return attenderService.getDisabledProfileCount(); } /** * {@inheritDoc} */ @Override public Boolean isMailServerConfigured() { if (attenderService.getMailServerFixed()) return true; else { mailService.updateWorkingMailServer(); return mailService.hasWorkingMailServer(); } } }