Package com.salas.bb.service

Source Code of com.salas.bb.service.ServerService

// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2006 by R. Pito Salas
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software Foundation;
// either version 2 of the License, or (at your option) any later version.
//
// 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, write to the Free Software Foundation, Inc., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id: ServerService.java,v 1.52 2007/07/04 09:38:30 spyromus Exp $
//

package com.salas.bb.service;

import com.jgoodies.uif.application.Application;
import com.jgoodies.uif.util.ResourceUtils;
import com.salas.bb.domain.CommunityFields;
import com.salas.bb.utils.ResourceID;
import com.salas.bb.utils.StringUtils;
import com.salas.bb.utils.i18n.Strings;
import org.apache.xmlrpc.XmlRpcClientSimple;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.XmlRpcHandler;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* BlogBridge server service. Communicates with server and exchanges information
* with it.
*/
public final class ServerService
{
    private static final Logger LOG = Logger.getLogger(ServerService.class.getName());

    private static final String MSG_COM_PROBLEM = "Communication problem.";
    private static final String MSG_PROCESSING_ERROR = "Processing error.";
    private static final String MSG_UNABLE_TO_STORE_DATA = "Unable to store data on the server.";

    // getSessionId error codes
    private static final int ERROR_ACCOUNT_NOT_ACTIVATED    = -1;
    private static final int ERROR_PASSWORD_INCORRECT       = -2;
    private static final int ERROR_ACCOUNT_NOT_REGISTERED   = -3;

    private static final URL SERVICE_URL;

    private static ServerService instance;
    private static final int OPML_VERSION = 1;

    private final static Object opmlURLsLock = new Object();
    private static Map opmlURLs = null;


    static
    {
        String serviceURL = System.getProperty(ResourceID.URL_SERVICE);
        if (serviceURL == null) serviceURL = ResourceUtils.getString(ResourceID.URL_SERVICE);

        LOG.config("Server service URL: " + serviceURL);

        URL url = null;
        try
        {
            url = new URL(serviceURL);
        } catch (MalformedURLException e)
        {
            LOG.severe(MessageFormat.format("Failed to initialize service with bad URL: {0}",
                serviceURL));
        } finally
        {
            SERVICE_URL = url;
        }
    }

    /**
     * Private singleton constructor.
     */
    private ServerService()
    {
    }

    /**
     * Returns instances of service.
     *
     * @return instance.
     */
    public static synchronized ServerService getInstance()
    {
        if (instance == null) instance = new ServerService();

        return instance;
    }

    /**
     * Returns server XML-RPC client.
     *
     * @return client or null in case of error.
     */
    public static XmlRpcHandler getClient()
    {
        return new XmlRpcClientSimple(SERVICE_URL);
    }

    /**
     * Registers user on the server.
     *
     * @param fullName        full user name.
     * @param email           user's email.
     * @param password        user's password.
     * @param locale          user's locale.
     * @param notifyOnUpdates if user allowed to use his email for updates notifications.
     *
     * @throws ServerServiceException in case of any errors.
     */
    public void registerUser(String fullName, String email, String password, String locale,
                             boolean notifyOnUpdates)
            throws ServerServiceException
    {
        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(5);
        params.add(fullName);
        params.add(email);
        params.add(password);
        params.add(locale);
        params.add(notifyOnUpdates);

        String errMessage;
        try
        {
            errMessage = (String)cl.execute("accounts.registerAccount", params);
        } catch (XmlRpcException e)
        {
            throw new ServerServiceException(MSG_COM_PROBLEM, e);
        } catch (Exception e)
        {
            logError(Strings.error("service.unable.to.process.registration.on.server"), e);
            throw new ServerServiceException(MSG_PROCESSING_ERROR, e);
        }

        // If not-empty error message, then throw error.
        if (errMessage != null && errMessage.length() > 0)
        {
            throw new ServerServiceException(errMessage);
        }
    }

    /**
     * Simple ping showing whether the service is there or no.
     *
     * @return <code>TRUE</code> if service is accessible.
     */
    public static boolean ping()
    {
        boolean online = false;

        XmlRpcHandler cl = getClient();
        Vector params = new Vector(0);

        try
        {
            String response = (String)cl.execute("ping.ping", params);
            online = "pong".equals(response);
        } catch (XmlRpcException e)
        {
            // Service is offline
        } catch (Exception e)
        {
            logError(Level.WARNING, "Invalid response.", e);
        }

        return online;
    }

    /**
     * Sends ping with information to the server.
     *
     * @param installationId ID of application instance.
     * @param appVersion     version of application.
     * @param runs           number of runs.
     * @param os             OS name and version.
     * @param javaVersion    JRE version.
     * @param email          user's account email (nullable).
     * @param password       user's account password (nullable).
     *
     * @throws ServerServiceException in case of communication problem.
     */
    public void ping(long installationId, String appVersion, int runs,
                     String os, String javaVersion, String email, String password)
        throws ServerServiceException
    {
        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(7);
        params.add(Long.toString(installationId));
        params.add(appVersion);
        params.add(runs);
        params.add(os);
        params.add(javaVersion);

        if (!StringUtils.isEmpty(email) && !StringUtils.isEmpty(password))
        {
            try
            {
                params.add(email);
                params.add(StringUtils.digestMD5(email, password));
            } catch (NoSuchAlgorithmException e)
            {
                LOG.log(Level.SEVERE, "There's no necessary digesting algorithm implemetned.", e);
            }
        }

        try
        {
            cl.execute("ping.ping1", params);
        } catch (XmlRpcException e)
        {
            throw new ServerServiceException(MSG_COM_PROBLEM, e);
        } catch (Exception e)
        {
            logError("Can't ping the server.", e);
            throw new ServerServiceException(MSG_PROCESSING_ERROR, e);
        }
    }

    /**
     * Stores data on server.
     *
     * @param email    email of account.
     * @param password password of account.
     * @param opml     opml with all necessary information.
     *
     * @return returns the ID of the user by the session ID.
     *
     * @throws ServerServiceException in case of any errors.
     */
    public static int syncStore(String email, String password, String opml)
            throws ServerServiceException
    {
        int userId;
        byte[] opmlBytes = StringUtils.toUTF8(opml);

        Integer sessionId = getSessionId(email, password);

        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(2);
        params.add(sessionId);
        params.add(opmlBytes);

        String errMessage;
        try
        {
            errMessage = (String)cl.execute("sync.storeInUtf8", params);
            userId = getUserId(sessionId);
        } catch (XmlRpcException e)
        {
            throw new ServerServiceException(MSG_COM_PROBLEM, e);
        } catch (Exception e)
        {
            logError(MSG_UNABLE_TO_STORE_DATA, e);
            throw new ServerServiceException(MSG_PROCESSING_ERROR, e);
        }

        if (errMessage != null && errMessage.length() > 0)
        {
            throw new ServerServiceException(errMessage);
        }

        return userId;
    }

    /**
     * Gets current user ID using the session ID and stores it in the cache.
     *
     * @param sessionId session ID.
     *
     * @return id.
     */
    private static int getUserId(Integer sessionId)
    {
        // Small trick here. We would need to ask the service if only we didn't know
        // that sessionId is our user id. :)
        return sessionId == null ? -1 : sessionId;
    }

    /**
     * Stores preferences on the server.
     *
     * @param email     email of account.
     * @param password  password of account.
     * @param prefs     preferences to store.
     *
     * @throws ServerServiceException in case of any errors.
     */
    public static void syncStorePrefs(String email, String password, Map prefs)
        throws ServerServiceException
    {
        Integer sessionId = getSessionId(email, password);

        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(2);
        params.add(sessionId);
        params.add(prefs);

        try
        {
            cl.execute("sync.storePrefs", params);
        } catch (XmlRpcException e)
        {
            throw new ServerServiceException(MSG_COM_PROBLEM, e);
        } catch (Exception e)
        {
            logError(MSG_UNABLE_TO_STORE_DATA, e);
            throw new ServerServiceException(MSG_PROCESSING_ERROR, e);
        }
    }

    /**
     * Restores information stored on the server.
     *
     * @param email    user's account email.
     * @param password user's account password.
     *
     * @return OPML with set of guides for replacement.
     *
     * @throws ServerServiceException in case of errors with communication or account.
     */
    public static String syncRestore(String email, String password)
            throws ServerServiceException
    {
        Integer sessionId = getSessionId(email, password);

        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(2);
        params.add(sessionId);
        params.add(OPML_VERSION);

        byte[] opmlBytes;
        try
        {
            opmlBytes = (byte[])cl.execute("sync.restoreInUtf8", params);
        } catch (XmlRpcException e)
        {
            throw new ServerServiceException(MSG_COM_PROBLEM, e);
        } catch (Exception e)
        {
            logError("Unable to restore data from the server.", e);
            throw new ServerServiceException(MSG_PROCESSING_ERROR, e);
        }

        // Convert result to string
        return StringUtils.fromUTF8(opmlBytes);
    }

    /**
     * Restores preferences previously stored on the server.
     *
     * @param email    user's account email.
     * @param password user's account password.
     *
     * @return map of stored preferences.
     *
     * @throws ServerServiceException in case of errors with communication or account.
     */
    public static Map syncRestorePrefs(String email, String password)
        throws ServerServiceException
    {
        Integer sessionId = getSessionId(email, password);

        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(1);
        params.add(sessionId);

        Map prefs;
        try
        {
            prefs = (Map)cl.execute("sync.restorePrefs", params);
        } catch (XmlRpcException e)
        {
            throw new ServerServiceException(MSG_COM_PROBLEM, e);
        } catch (Exception e)
        {
            logError("Unable to restore preferences from the server.", e);
            throw new ServerServiceException(MSG_PROCESSING_ERROR, e);
        }

        return prefs;
    }

    /**
     * Takes session id using account information.
     *
     * @param email    user's account email.
     * @param password user's account password.
     *
     * @return id of account.
     *
     * @throws ServerServiceException in case of errors with communication or account.
     */
    private static Integer getSessionId(String email, String password)
            throws ServerServiceException
    {
        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(2);
        params.add(email);
        params.add(password);

        Integer idInt;
        try
        {
            idInt = (Integer)cl.execute("accounts.getSessionId", params);
        } catch (XmlRpcException e)
        {
            throw new ServerServiceException(MSG_COM_PROBLEM, e);
        } catch (Exception e)
        {
            logError("Unable to get session id.", e);
            throw new ServerServiceException(MSG_PROCESSING_ERROR, e);
        }

        int sessionId = idInt;

        switch (sessionId)
        {
            case ERROR_ACCOUNT_NOT_ACTIVATED:
                throw new ServerServiceException(Strings.error("service.you.need.active.account"));
            case ERROR_PASSWORD_INCORRECT:
                throw new ServerServiceException(Strings.error("service.account.password.is.incorrect"));
            case ERROR_ACCOUNT_NOT_REGISTERED:
                throw new ServerServiceException(Strings.error("service.account.is.not.registered"));
            default:
        }

        return idInt;
    }

    /**
     * Fetches the list of shared tags for a given URL.
     *
     * @param email     user's email.
     * @param password  user's password.
     * @param aLink     link to get tags for.
     *
     * @return list of tags.
     *
     * @throws ServerServiceException in case of errors with communication or account.
     */
    public static List tagsFetch(String email, String password, URL aLink)
        throws ServerServiceException
    {
        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(2);
        params.add(getSessionId(email, password));
        params.add(StringUtils.toUTF8(aLink.toString()));

        Vector tags;
        try
        {
            tags = (Vector)cl.execute("tags.getTags", params);
        } catch (XmlRpcException e)
        {
            throw new ServerServiceException(MSG_COM_PROBLEM, e);
        } catch (Exception e)
        {
            throw new ServerServiceException(MSG_PROCESSING_ERROR, e);
        }

        return tags;
    }

    /**
     * Stores user's tags for a given URL.
     *
     * @param email         user's email.
     * @param password      user's password.
     * @param aLink         link to assign tags to.
     * @param aFeed         <code>TRUE</code> if link corresponds to feed.
     * @param aUserTags     list of tags to assign.
     * @param aDescription  link description.
     * @param aExtended     extended description.
     *
     * @throws ServerServiceException in case of errors with communication or account.
     */
    public static void tagsStore(String email, String password, URL aLink, boolean aFeed,
                                 String[] aUserTags, String aDescription, String aExtended) throws ServerServiceException
    {
        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(6);
        params.add(getSessionId(email, password));
        params.add(StringUtils.toUTF8(aLink.toString()));
        params.add(aFeed);
        params.add(StringUtils.toUTF8(StringUtils.arrayToQuotedKeywords(aUserTags)));
        params.add(StringUtils.toUTF8(aDescription));
        params.add(StringUtils.toUTF8(aExtended));

        String error;
        try
        {
            error = (String)cl.execute("tags.tag", params);
        } catch (XmlRpcException e)
        {
            throw new ServerServiceException(MSG_COM_PROBLEM, e);
        } catch (Exception e)
        {
            logError(MessageFormat.format("Could not save user tags for: {0}", aLink), e);
            throw new ServerServiceException(MSG_PROCESSING_ERROR, e);
        }

        if (error != null && error.length() > 0)
        {
            throw new ServerServiceException(error);
        }
    }

    /**
     * Sends request to the server to resend password on a given email.
     *
     * @param email email address of registered account.
     *
     * @throws ServerServiceException in case of any errors.
     */
    public void requestPasswordResending(String email)
        throws ServerServiceException
    {
        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(1);
        params.add(email);

        String msg;
        try
        {
            msg = (String)cl.execute("accounts.requestPasswordResending", params);
        } catch (XmlRpcException e)
        {
            throw new ServerServiceException(MSG_COM_PROBLEM, e);
        } catch (Exception e)
        {
            logError("Could not process password resending request.", e);
            throw new ServerServiceException(MSG_PROCESSING_ERROR, e);
        }

        if (msg.length() > 0) throw new ServerServiceException(msg);
    }

    /**
     * Performs discovery of feed by specified <code>ref</code>.
     *
     * @param ref   reference string (URL, word or whatever).
     *
     * @return result of resolution.
     *
     * @throws ServerServiceException in case of any errors.
     */
    public Map discover(String ref)
        throws ServerServiceException
    {
        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(1);
        params.add(ref);

        Map result;
        try
        {
            result = (Map)cl.execute("meta.getBlogByUrlInUtf8", params);
        } catch (XmlRpcException e)
        {
            throw new ServerServiceException(MSG_COM_PROBLEM, e);
        } catch (Exception e)
        {
            logError("Could not process the discovery request.", e);
            throw new ServerServiceException(MSG_PROCESSING_ERROR, e);
        }

        // Convert community fields into client-side format
        Map serviceFields = (Map)result.get("communityFields");
        if (serviceFields != null)
        {
            result.put("communityFields", convertToClientFields(serviceFields));
        }

        return result;
    }

    /**
     * Suggests the Feed URL associated with the reference. If this reference still has no
     * association in service database or associated with BadBlog record then it will be
     * (re)associated to a newly discovered blog (if it will be discovered, of course).
     *
     * @param reference         original reference.
     * @param suggestedFeedUrl  suggested Feed Url.
     */
    public static void metaSuggestFeedUrl(String reference, String suggestedFeedUrl)
    {
        if (LOG.isLoggable(Level.FINE))
        {
            LOG.fine("Suggesting Feed URL: Ref=" + reference + ", Feed URL=" + suggestedFeedUrl);
        }

        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(2);
        params.add(reference);
        params.add(suggestedFeedUrl);

        try
        {
            cl.execute("meta.suggestFeedUrl", params);
        } catch (XmlRpcException e)
        {
            // No feedback here or we can get in dead cycle
        } catch (Exception e)
        {
            // No feedback here or we can get in dead cycle
            logError(Level.WARNING, "Could not suggest feed URL.", e);
        }
    }

    /**
     * Loads community fields for the given blog.
     *
     * @param dataUrl   data URL of the blog.
     *
     * @return fields map (Name:Value) where Name is String and Value is String or String[].
     *
     * @throws ServerServiceException in case of any errors.
     */
    public static CommunityFields metaGetCommunityFields(String dataUrl)
        throws ServerServiceException
    {
        if (dataUrl == null) return null;

        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(1);
        params.add(dataUrl);

        Map fields;
        try
        {
            fields = (Map)cl.execute("meta.getCommunityFields", params);
        } catch (XmlRpcException e)
        {
            throw new ServerServiceException(MSG_COM_PROBLEM, e);
        } catch (Exception e)
        {
            logError("Could not load community fields.", e);
            throw new ServerServiceException(MSG_PROCESSING_ERROR, e);
        }

        return new CommunityFields(convertToClientFields(fields));
    }

    /**
     * Saves community fields.
     *
     * @param email     user account email.
     * @param password  user account password.
     * @param dataUrl   feed URL of the blog.
     * @param fields    fields to save (Name:Vector(Value)). Name should be String.
     *
     * @throws ServerServiceException in case of any errors.
     */
    public static void metaSetCommunityFields(String email, String password, String dataUrl,
                                              CommunityFields fields)
        throws ServerServiceException
    {
        if (fields == null || fields.size() == 0) return;

        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(3);
        params.add(getSessionId(email, password));
        params.add(dataUrl);
        params.add(convertToServiceFields(fields));

        String message;
        try
        {
            message = (String)cl.execute("meta.setCommunityFields", params);
        } catch (XmlRpcException e)
        {
            throw new ServerServiceException(MSG_COM_PROBLEM, e);
        } catch (Exception e)
        {
            logError("Could not save community fields.", e);
            throw new ServerServiceException(MSG_PROCESSING_ERROR, e);
        }

        if (message.length() > 0)
        {
            throw new ServerServiceException(message);
        }
    }

    /**
     * Converts the values assigned to keys into valid values understood by client.
     *
     * @param serviceFields   service fields map.
     *
     * @return result.
     */
    static Map convertToClientFields(Map serviceFields)
    {
        if (serviceFields == null) return null;

        Map<String, Object> clientFields = new HashMap<String, Object>(serviceFields.size());

        for (Object o : serviceFields.entrySet())
        {
            Map.Entry entry = (Map.Entry)o;

            String name = (String)entry.getKey();
            Object value = convertFieldToClientValue(entry.getValue());

            if (value != null) clientFields.put(name, value);
        }

        return clientFields;
    }

    /**
     * Converts byte[] to String and Vector(byte[]) to String[].
     *
     * @param serviceValue  service value to convert.
     *
     * @return client value.
     */
    static Object convertFieldToClientValue(Object serviceValue)
    {
        if (serviceValue == null) return null;

        Object clientValue = null;

        if (serviceValue instanceof byte[])
        {
            clientValue = StringUtils.fromUTF8((byte[])serviceValue);
        } else if (serviceValue instanceof Vector)
        {
            Vector vector = (Vector)serviceValue;
            String[] values = new String[vector.size()];

            for (int i = 0; i < vector.size(); i++)
            {
                byte[] value = (byte[])vector.get(i);
                values[i] = StringUtils.fromUTF8(value);
            }

            clientValue = values;
        }

        return clientValue;
    }

    /**
     * Converts the values assigned to keys into valid values understood by service.
     *
     * @param clientFields   source fields map.
     *
     * @return result.
     */
    static Map convertToServiceFields(Map clientFields)
    {
        if (clientFields == null) return null;

        Map<String, Object> serviceFields = new HashMap<String, Object>(clientFields.size());

        for (Object o : clientFields.entrySet())
        {
            Map.Entry entry = (Map.Entry)o;

            String name = entry.getKey().toString();
            Object value = convertFieldToServiceValue(entry.getValue());

            if (value != null) serviceFields.put(name, value);
        }

        return serviceFields;
    }

    /**
     * Converts String to byte[], arrayof(Object) to Vector(byte[]).
     *
     * @param aValue    String, Vector or array.
     *
     * @return value or NULL if conversion is not possible.
     */
    static Object convertFieldToServiceValue(Object aValue)
    {
        if (aValue == null) return null;

        Object value;
        boolean isList = false;

        if (aValue instanceof byte[])
        {
            value = aValue;
        } else if (aValue instanceof Object[] || (isList = aValue instanceof List))
        {
            Object[] array = !isList ? (Object[])aValue : ((List)aValue).toArray();

            Vector<byte[]> vector = new Vector<byte[]>(array.length);
            for (Object o : array) vector.add(StringUtils.toUTF8(o.toString()));

            value = vector;
        } else
        {
            value = StringUtils.toUTF8(aValue.toString());
        }

        return value;
    }

    /**
     * Sends client error report to the service.
     *
     * @param message error message.
     * @param details error details.
     */
    public static void reportClientError(final String message, final String details)
    {
        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(3);
        params.add(message);
        params.add(details);
        params.add(Application.getDescription().getVersion());

        try
        {
            cl.execute("reports.clientError", params);
        } catch (Exception e)
        {
            // No feedback here or we can get in dead cycle
        }
    }

    /**
     * Sends feedback to the service.
     *
     * @param message feedback message (UTF-8 is supported).
     *
     * @return TRUE if successfully sent.
     */
    public static boolean reportFeedback(String message)
    {
        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(1);
        params.add(StringUtils.toUTF8(message));

        boolean sent = false;
        try
        {
            cl.execute("reports.feedbackMessage", params);
            sent = true;
        } catch (XmlRpcException e)
        {
            // No feedback here or we can get in dead cycle
        } catch (Exception e)
        {
            // No feedback here or we can get in dead cycle
            logError(Level.WARNING, "Could not send feedback message.", e);
        }

        return sent;
    }

    /**
     * Reports exception.
     *
     * @param message       message.
     * @param description   description of exception.
     * @param exception     exception to report.
     */
    public static void reportClientError(String message, String description, Throwable exception)
    {
        StringBuffer details = new StringBuffer();

        if (description != null) details.append(description).append("\n\n");

        if (exception != null)
        {
            dumpThrowable(exception, details);
        } else details.append("No stack dump.");

        reportClientError(message, details.toString());
    }

    /**
     * Recursively dumps throwable.
     *
     * @param exception exception.
     * @param details   details buffer.
     */
    static void dumpThrowable(Throwable exception, StringBuffer details)
    {
        details.append(exception.toString());
        for (int i = 0; i < exception.getStackTrace().length; i++)
        {
            StackTraceElement element = exception.getStackTrace()[i];
            details.append("\n\t").append(element);
        }

        Throwable cause = exception.getCause();
        if (cause != null)
        {
            details.append("\nCaused by:\n");
            dumpThrowable(cause, details);
        }
    }

    /**
     * Asks service for available updates.
     *
     * @param aCurrentVersion current version.
     *
     * @return service XML response or empty packet if no updates available.
     *
     * @throws ServerServiceException in case of any errors.
     */
    public static String checkForUpdates(String aCurrentVersion)
        throws ServerServiceException
    {
        // We use this property to test new release detection
        // When set the service provides the list of all updates since
        // current version as if the latest version were final.
        boolean productionOnly = System.getProperty("service.checkupdates.allversions") == null;

        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(2);
        params.add(aCurrentVersion);
        params.add(productionOnly);

        String response;
        try
        {
            response = (String)cl.execute("updates.checkForUpdates", params);
        } catch (XmlRpcException e)
        {
            throw new ServerServiceException(MSG_COM_PROBLEM, e);
        } catch (Exception e)
        {
            logError("Could not check for updates.", e);
            throw new ServerServiceException(MSG_PROCESSING_ERROR, e);
        }

        return response;
    }

    /**
     * Questions the service for the list of available forums.
     *
     * @return forums list.
     *
     * @throws ServerServiceException in case of any errors.
     */
    public static Map forumGetForums()
        throws ServerServiceException
    {
        XmlRpcHandler cl = getClient();
        Vector params = new Vector(0);

        Map response;
        try
        {
            response = (Map)cl.execute("forum.getForums", params);
        } catch (XmlRpcException e)
        {
            throw new ServerServiceException(MSG_COM_PROBLEM, e);
        } catch (Exception e)
        {
            logError("Could not fetch forums list.", e);
            throw new ServerServiceException(MSG_PROCESSING_ERROR, e);
        }

        return response;
    }

    /**
     * Posts message to the forum.
     *
     * @param aName     name of the author.
     * @param aEmail    email address of the author.
     * @param aForumId  ID of selected forum.
     * @param aSubject  subject of the message.
     * @param aMessage  message text.
     *
     * @return <code>TRUE</code> if the message has been delivered.
     */
    public static boolean forumPost(String aName, String aEmail, int aForumId, String aSubject,
                                    String aMessage)
    {
        XmlRpcHandler cl = getClient();
        Vector<Object> params = new Vector<Object>(5);
        params.add(StringUtils.toUTF8(aName));
        params.add(StringUtils.toUTF8(aEmail));
        params.add(aForumId);
        params.add(StringUtils.toUTF8(aSubject));
        params.add(StringUtils.toUTF8(aMessage));

        boolean sent = false;
        try
        {
            cl.execute("forum.post", params);
            sent = true;
        } catch (XmlRpcException e)
        {
            // No feedback here or we can get in dead cycle
        } catch (Exception e)
        {
            // No feedback here or we can get in dead cycle
            logError(Level.WARNING, "Could not send forum message.", e);
        }

        return sent;
    }

    /**
     * Returns starting points OPML URL.
     *
     * @return starting points OPML URL.
     */
    public static URL getStartingPointsURL()
    {
        return getOPMLURLbyKey("opml.starting.points.url");
    }

    /**
     * Returns experts OPML URL.
     *
     * @return experts OPML URL.
     */
    public static URL getExpertsURL()
    {
        return getOPMLURLbyKey("opml.experts.url");
    }

    /**
     * Loads OPML URLs list if necessary from the service.
     *
     * @param urlKey key to get URL.
     *
     * @return URL or NULL if opml URLs aren't loaded or the key is missing.
     */
    private static URL getOPMLURLbyKey(String urlKey)
    {
        URL url = getSystemURLProperty(urlKey);

        if (url == null)
        {
            synchronized (opmlURLsLock)
            {
                loadOPMLURLs();

                // There can be a problem with the service not responding.
                if (opmlURLs != null)
                {
                    String urlS = StringUtils.fromUTF8((byte[])opmlURLs.get(urlKey));
                    try
                    {
                        if (urlS == null) url = null; else url = new URL(urlS);
                    } catch (MalformedURLException e)
                    {
                        url = null;
                    }
                }
            }
        }

        return url;
    }

    /**
     * Checks if there's a system property for the given key.
     *
     * @param key key.
     *
     * @return URL.
     */
    private static URL getSystemURLProperty(String key)
    {
        URL url = null;
        String val = System.getProperty(key);

        if (val != null)
        {
            try
            {
                url = new URL(val);
            } catch (MalformedURLException e)
            {
                LOG.log(Level.WARNING, MessageFormat.format( "Invalid overriden URL for key {0}", key), e);
            }
        }

        return url;
    }

    /**
     * Loads the list of OPML URLs from the service.
     */
    private static void loadOPMLURLs()
    {
        if (opmlURLs == null)
        {
            XmlRpcHandler cl = getClient();
            Vector params = new Vector(0);

            try
            {
                opmlURLs = (Map)cl.execute("meta.getOPMLURLs", params);
            } catch (Exception e)
            {
                logError("Could not retrieve OPML URLs.", e);
            }
        }
    }

    // ------------------------------------------------------------------------
    // Plan and Feature related calls to the service
    // ------------------------------------------------------------------------

    /**
     * Returns the plan hash to compare with the current and decided if it's time
     * to update the features list or no.
     *
     * @param email     user email.
     * @param password  user password.
     *
     * @return the hash.
     */
    public static String getPlanHash(String email, String password)
    {
        XmlRpcHandler cl = getClient();

        Vector<String> params = new Vector<String>(2);
        params.add(email);
        params.add(password);

        String hash = null;
        try
        {
            hash = (String)cl.execute("plans.getHash", params);
        } catch (Exception e)
        {
            // No feedback here or we can get in dead cycle
            LOG.log(Level.WARNING, "Failed to get plan hash.", e);
        }

        return hash;
    }

    public static Map<String, String> getPlanFeatures(String email, String password)
    {
        XmlRpcHandler cl = getClient();

        Vector<String> params = new Vector<String>(2);
        params.add(email);
        params.add(password);

        Map<String, String> features = null;
        try
        {
            features = (Map<String, String>)cl.execute("plans.getFeatures", params);
        } catch (Exception e)
        {
            // No feedback here or we can get in dead cycle
            logError(Level.WARNING, "Failed to get plan features.", e);
        }

        return features;
    }

    private static void logError(String msg, Exception ex)
    {
        logError(Level.SEVERE, msg, ex);
    }

    private static void logError(Level level, String msg, Exception ex)
    {
        level = ex instanceof IOException ? Level.FINE : level;
        LOG.log(level, msg, ex);
    }
}
TOP

Related Classes of com.salas.bb.service.ServerService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.