com.zimbra.cs.session.WaitSetValidator.java Source code

Java tutorial

Introduction

Here is the source code for com.zimbra.cs.session.WaitSetValidator.java

Source

/*
 * ***** BEGIN LICENSE BLOCK *****
 * Zimbra Collaboration Suite Server
 * Copyright (C) 2008, 2009, 2010, 2013, 2014, 2016 Synacor, Inc.
 *
 * 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,
 * version 2 of the License.
 *
 * 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 <https://www.gnu.org/licenses/>.
 * ***** END LICENSE BLOCK *****
 */
package com.zimbra.cs.session;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;

import com.zimbra.common.auth.ZAuthToken;
import com.zimbra.common.service.ServiceException;
import com.zimbra.common.soap.AdminConstants;
import com.zimbra.common.soap.Element;
import com.zimbra.common.soap.MailConstants;
import com.zimbra.common.soap.SoapFaultException;
import com.zimbra.common.soap.SoapHttpTransport;
import com.zimbra.common.soap.Element.XMLElement;
import com.zimbra.common.soap.SoapTransport.DebugListener;
import com.zimbra.common.util.CliUtil;
import com.zimbra.common.zclient.ZClientException;

/**
 * Test utility for verifying the state of a running wait set
 */
public class WaitSetValidator implements DebugListener {

    private long mSendStart;
    private int mTimeout = -1;
    private int mRetryCount = -1;
    private SoapHttpTransport mTransport;
    private ZAuthToken mAuthToken;
    private long mAuthTokenLifetime;
    private long mAuthTokenExpiration;
    private DebugListener mDebugListener = null;

    void setVerbose(boolean value) {
        if (value) {
            mDebugListener = this;
        } else {
            mDebugListener = null;
        }
    }

    /**
     * @param uri URI of server we want to talk to
     */
    void soapSetURI(String uri) {
        if (mTransport != null)
            mTransport.shutdown();
        mTransport = new SoapHttpTransport(uri);
        if (mTimeout >= 0)
            mTransport.setTimeout(mTimeout);
        if (mRetryCount > 0)
            mTransport.setRetryCount(mRetryCount);
        if (mAuthToken != null)
            mTransport.setAuthToken(mAuthToken);
        if (mDebugListener != null)
            mTransport.setDebugListener(mDebugListener);
    }

    private String serverName() {
        try {
            return new URI(mTransport.getURI()).getHost();
        } catch (URISyntaxException e) {
            return mTransport.getURI();
        }
    }

    private void checkTransport() throws ServiceException {
        if (mTransport == null)
            throw ServiceException.FAILURE("transport has not been initialized", null);
    }

    protected Element invoke(Element request) throws ServiceException {
        checkTransport();

        try {
            return mTransport.invoke(request);
        } catch (SoapFaultException e) {
            throw e; // for now, later, try to map to more specific exception
        } catch (IOException e) {
            throw ZClientException.IO_ERROR("invoke " + e.getMessage() + ", server: " + serverName(), e);
        }
    }

    protected Element invokeOnTargetAccount(Element request, String targetId) throws ServiceException {
        checkTransport();

        String oldTarget = mTransport.getTargetAcctId();
        try {
            mTransport.setTargetAcctId(targetId);
            return mTransport.invoke(request);
        } catch (SoapFaultException e) {
            throw e; // for now, later, try to map to more specific exception
        } catch (IOException e) {
            throw ZClientException.IO_ERROR("invoke " + e.getMessage() + ", server: " + serverName(), e);
        } finally {
            mTransport.setTargetAcctId(oldTarget);
        }
    }

    protected Element invokeQueryWaitSet(String id) throws ServiceException {
        XMLElement req = new XMLElement(AdminConstants.QUERY_WAIT_SET_REQUEST);
        req.addAttribute(MailConstants.A_WAITSET_ID, id);
        Element response = invoke(req);
        return response;
    }

    protected List<WaitSetSession> queryWaitSet(String id) throws ServiceException {
        Element qws = invokeQueryWaitSet(id);

        List<WaitSetSession> toRet = new ArrayList<WaitSetSession>();

        for (Iterator<Element> iter = qws.elementIterator("session"); iter.hasNext();) {
            Element selt = iter.next();
            WaitSetSession wss = new WaitSetSession();
            wss.accountId = selt.getAttribute("account");
            wss.token = selt.getAttribute("token", null);
            toRet.add(wss);
        }
        return toRet;
    }

    protected boolean validateSessionStatus(WaitSetSession wss) throws ServiceException {
        XMLElement req = new com.zimbra.common.soap.Element.XMLElement(MailConstants.SYNC_REQUEST);
        req.addAttribute("token", wss.token);
        Element syncResponse = invokeOnTargetAccount(req, wss.accountId);
        String newToken = syncResponse.getAttribute("token");
        String md = syncResponse.getAttribute("md");

        long diff = Long.parseLong(newToken) - Long.parseLong(wss.token);
        if (!newToken.equals(wss.token) && (diff > 10)) {
            System.out.println("ERROR: Account " + wss.accountId + " -- old token " + wss.token
                    + " doesn't match new token: " + newToken + " md=" + md + " Difference=" + diff);
            return false;
        } else {
            System.out.println("Account " + wss.accountId + " diff=" + diff + " -- OK");
            return true;
        }
    }

    static class WaitSetSession {
        public String accountId;
        public String token;

    }

    /**
     * used to authenticate via admin AuthRequest. can only be called after setting the URI with setURI.
     * 
     * @param name
     * @param password
     * @throws ServiceException
     * @throws IOException 
     */
    public void soapAdminAuthenticate(String name, String password) throws ServiceException {
        if (mTransport == null)
            throw ZClientException.CLIENT_ERROR("must call setURI before calling adminAuthenticate", null);
        XMLElement req = new XMLElement(AdminConstants.AUTH_REQUEST);
        req.addElement(AdminConstants.E_NAME).setText(name);
        req.addElement(AdminConstants.E_PASSWORD).setText(password);
        Element response = invoke(req);
        mAuthToken = new ZAuthToken(response.getElement(AdminConstants.E_AUTH_TOKEN), true);
        mAuthTokenLifetime = response.getAttributeLong(AdminConstants.E_LIFETIME);
        mAuthTokenExpiration = System.currentTimeMillis() + mAuthTokenLifetime;
        mTransport.setAuthToken(mAuthToken);
    }

    public void receiveSoapMessage(Element envelope) {
        long end = System.currentTimeMillis();
        System.out.printf("======== SOAP RECEIVE =========\n");
        System.out.println(envelope.prettyPrint());
        System.out.printf("=============================== (%d msecs)\n", end - mSendStart);

    }

    public void sendSoapMessage(Element envelope) {
        mSendStart = System.currentTimeMillis();
        System.out.println("========== SOAP SEND ==========");
        System.out.println(envelope.prettyPrint());
        System.out.println("===============================");
    }

    void usage() {
        System.out.println("");
        System.out.println("testwaitset -i waitsetid [-u admin_user] [-p password] [-h host]");
        System.exit(1);
    }

    private static void printError(String text) {
        PrintStream ps = System.err;
        try {
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(ps, "UTF-8"));
            writer.write(text + "\n");
            writer.flush();
        } catch (UnsupportedEncodingException e) {
            ps.println(text);
        } catch (IOException e) {
            ps.println(text);
        }
    }

    void run(String id, String host, String user, String pw) {
        try {
            soapSetURI(host);
            soapAdminAuthenticate(user, pw);
            List<WaitSetSession> wss = queryWaitSet(id);
            boolean hasFailures = false;
            for (WaitSetSession w : wss) {
                if (!validateSessionStatus(w))
                    hasFailures = true;
            }
            if (hasFailures) {
                Element qws = invokeQueryWaitSet(id);
                System.out.println(qws.prettyPrint());
            }

        } catch (ServiceException e) {
            e.printStackTrace();
            System.out.println("Caught exception: " + e);
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        CliUtil.toolSetup();

        WaitSetValidator t = new WaitSetValidator();

        CommandLineParser parser = new PosixParser();
        Options options = new Options();

        options.addOption("i", "id", true, "Wait Set ID");
        options.addOption("h", "host", true, "Hostname");
        options.addOption("u", "user", true, "Username");
        options.addOption("p", "pw", true, "Password");
        options.addOption("?", "help", false, "Help");
        options.addOption("v", "verbose", false, "Verbose");

        CommandLine cl = null;
        boolean err = false;

        String[] hosts;
        String[] ids;

        try {
            cl = parser.parse(options, args, true);
        } catch (ParseException pe) {
            printError("error: " + pe.getMessage());
            err = true;
        }

        if (err || cl.hasOption('?')) {
            t.usage();
        }

        String id = null, host = null, user = null, pw = null;

        if (!cl.hasOption('i'))
            t.usage();

        id = cl.getOptionValue('i');

        if (cl.hasOption('h'))
            host = cl.getOptionValue('h');
        else
            host = "http://localhost:7071/service/admin";

        if (cl.hasOption('u'))
            user = cl.getOptionValue('u');
        else
            user = "admin";

        if (cl.hasOption('p'))
            pw = cl.getOptionValue('p');
        else
            pw = "test123";

        if (cl.hasOption('v'))
            t.setVerbose(true);

        hosts = host.split(",");
        ids = id.split(",");

        if (hosts.length != ids.length) {
            System.err.println("If multiple hosts or ids are specified, the same number is required of each");
            System.exit(3);
        }

        for (int i = 0; i < hosts.length; i++) {
            if (i > 0)
                System.out.println("\n\n");
            System.out.println("Checking server " + hosts[i] + " waitsetId=" + ids[i]);
            t.run(ids[i], hosts[i], user, pw);
        }
    }

}