com.seajas.search.attender.wsdl.Profile.java Source code

Java tutorial

Introduction

Here is the source code for com.seajas.search.attender.wsdl.Profile.java

Source

/**
 * 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();
        }
    }
}