org.eclipse.mylyn.internal.commons.xmlrpc.XmlRpcOperation.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.mylyn.internal.commons.xmlrpc.XmlRpcOperation.java

Source

/*******************************************************************************
 * Copyright (c) 2010 Steffen Pingel and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Steffen Pingel - initial API and implementation
 *******************************************************************************/

package org.eclipse.mylyn.internal.commons.xmlrpc;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.auth.AuthScheme;
import org.apache.commons.httpclient.auth.NTLMScheme;
import org.apache.xmlrpc.XmlRpcException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.mylyn.commons.core.CoreUtil;
import org.eclipse.mylyn.commons.net.AuthenticationCredentials;
import org.eclipse.mylyn.commons.net.AuthenticationType;
import org.eclipse.mylyn.commons.net.Policy;
import org.eclipse.mylyn.commons.net.UnsupportedRequestException;

/**
 * @author Steffen Pingel
 */
public abstract class XmlRpcOperation<T> {

    private static final Pattern RPC_METHOD_NOT_FOUND_PATTERN = Pattern.compile("No such handler: "); //$NON-NLS-1$

    protected static final int XML_FAULT_GENERAL_ERROR = 1;

    protected static final int XML_FAULT_PERMISSION_DENIED = 403;

    private final CommonXmlRpcClient client;

    public XmlRpcOperation(CommonXmlRpcClient client) {
        this.client = client;
    }

    protected Object call(IProgressMonitor monitor, String method, Object... parameters) throws XmlRpcException {
        monitor = Policy.monitorFor(monitor);
        XmlRpcException lastException = null;
        for (int attempt = 0; attempt < 3; attempt++) {
            //         if (!client.isProbed()) {
            //            try {
            //               probeAuthenticationScheme(monitor);
            //            } finally {
            //               client.setProbed(true);
            //            }
            //         }

            try {
                return executeCall(monitor, method, parameters);
            } catch (XmlRpcLoginException e) {
                try {
                    client.getLocation().requestCredentials(AuthenticationType.REPOSITORY, null, monitor);
                } catch (UnsupportedRequestException ignored) {
                    throw e;
                }
                lastException = e;
            } catch (XmlRpcPermissionDeniedException e) {
                try {
                    client.getLocation().requestCredentials(AuthenticationType.REPOSITORY, null, monitor);
                } catch (UnsupportedRequestException ignored) {
                    throw e;
                }
                lastException = e;
            } catch (XmlRpcProxyAuthenticationException e) {
                try {
                    client.getLocation().requestCredentials(AuthenticationType.PROXY, null, monitor);
                } catch (UnsupportedRequestException ignored) {
                    throw e;
                }
                lastException = e;
            } catch (XmlRpcSslCertificateException e) {
                try {
                    client.getLocation().requestCredentials(AuthenticationType.CERTIFICATE, null, monitor);
                } catch (UnsupportedRequestException ignored) {
                    throw e;
                }
                lastException = e;
            }
        }
        if (lastException != null) {
            throw lastException;
        } else {
            // this path should never be reached
            throw new IllegalStateException();
        }
    }

    private void checkForException(Object result) throws NumberFormatException, XmlRpcException {
        if (result instanceof Map<?, ?>) {
            Map<?, ?> exceptionData = (Map<?, ?>) result;
            if (exceptionData.containsKey("faultCode") && exceptionData.containsKey("faultString")) { //$NON-NLS-1$ //$NON-NLS-2$ 
                throw new XmlRpcException(Integer.parseInt(exceptionData.get("faultCode").toString()), //$NON-NLS-1$
                        (String) exceptionData.get("faultString")); //$NON-NLS-1$
            } else if (exceptionData.containsKey("title")) { //$NON-NLS-1$
                String message = (String) exceptionData.get("title"); //$NON-NLS-1$
                String detail = (String) exceptionData.get("_message"); //$NON-NLS-1$
                if (detail != null) {
                    message += ": " + detail; //$NON-NLS-1$
                }
                throw new XmlRpcException(XML_FAULT_GENERAL_ERROR, message);
            }
        }
    }

    protected boolean credentialsValid(AuthenticationCredentials credentials) {
        return credentials != null;
    }

    public abstract T execute() throws XmlRpcException;

    protected Object executeCall(IProgressMonitor monitor, String method, Object... parameters)
            throws XmlRpcException {
        try {
            if (CommonXmlRpcClient.DEBUG_XMLRPC) {
                System.err.println("Calling " + client.getLocation().getUrl() + ": " + method + " " //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                        + CoreUtil.toString(parameters));
            }

            AuthenticationCredentials credentials = client.updateCredentials();
            XmlRpcClientRequest request = new XmlRpcClientRequest(client.getClient().getClientConfig(),
                    getXmlRpcUrl(credentials), method, parameters, monitor);
            return client.getClient().execute(request);
        } catch (XmlRpcHttpException e) {
            handleAuthenticationException(e.code, e.getAuthScheme());
            // if not handled, re-throw exception
            throw e;
        } catch (XmlRpcIllegalContentTypeException e) {
            throw e;
        } catch (XmlRpcException e) {
            // XXX work-around for http://trac-hacks.org/ticket/5848 
            if ("XML_RPC privileges are required to perform this operation".equals(e.getMessage()) //$NON-NLS-1$
                    || e.code == XML_FAULT_PERMISSION_DENIED) {
                handleAuthenticationException(HttpStatus.SC_FORBIDDEN, null);
                // should never happen as call above should always throw an exception
                throw new XmlRpcRemoteException(e);
            } else if (isNoSuchMethodException(e)) {
                throw new XmlRpcNoSuchMethodException(e);
            } else {
                throw new XmlRpcRemoteException(e);
            }
        } catch (OperationCanceledException e) {
            throw e;
        } catch (Exception e) {
            throw new XmlRpcException("Unexpected exception", e); //$NON-NLS-1$
        }
    }

    protected final CommonXmlRpcClient getClient() {
        return client;
    }

    protected Object getMultiCallResult(Object item) {
        return ((Object[]) item)[0];
    }

    protected URL getXmlRpcUrl(AuthenticationCredentials credentials) {
        try {
            return new URL(client.getLocation().getUrl());
        } catch (MalformedURLException e) {
            throw new RuntimeException("Encoding of URL failed", e); //$NON-NLS-1$
        }
    }

    protected boolean handleAuthenticationException(int code, AuthScheme authScheme) throws XmlRpcException {
        if (code == HttpStatus.SC_UNAUTHORIZED) {
            if (CommonXmlRpcClient.DEBUG_AUTH) {
                System.err.println(client.getLocation().getUrl() + ": Unauthorized (" + code + ")"); //$NON-NLS-1$ //$NON-NLS-2$ 
            }
            client.digestScheme = null;
            XmlRpcLoginException exception = new XmlRpcLoginException();
            exception.setNtlmAuthRequested(authScheme instanceof NTLMScheme);
            throw exception;
        } else if (code == HttpStatus.SC_FORBIDDEN) {
            if (CommonXmlRpcClient.DEBUG_AUTH) {
                System.err.println(client.getLocation().getUrl() + ": Forbidden (" + code + ")"); //$NON-NLS-1$ //$NON-NLS-2$ 
            }
            client.digestScheme = null;
            throw new XmlRpcPermissionDeniedException();
        } else if (code == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED) {
            if (CommonXmlRpcClient.DEBUG_AUTH) {
                System.err
                        .println(client.getLocation().getUrl() + ": Proxy authentication required (" + code + ")"); //$NON-NLS-1$ //$NON-NLS-2$ 
            }
            throw new XmlRpcProxyAuthenticationException();
        }
        return false;
    }

    protected boolean isNoSuchMethodException(XmlRpcException e) {
        if (RPC_METHOD_NOT_FOUND_PATTERN.matcher(e.getMessage()).find()) {
            return true;
        }
        return false;
    }

    //   protected Object[] multicall(IProgressMonitor monitor, Map<String, Object>... calls) throws XmlRpcException {
    //      Object[] result = (Object[]) call(monitor, "system.multicall", new Object[] { calls }); //$NON-NLS-1$
    //      for (Object item : result) {
    //         checkForException(item);
    //      }
    //      return result;
    //   }

    protected MulticallResult call(IProgressMonitor monitor, Multicall call) throws XmlRpcException {
        Object[] response = (Object[]) call(monitor, "system.multicall", new Object[] { call.getCalls() }); //$NON-NLS-1$
        for (Object item : response) {
            checkForException(item);
        }
        return new MulticallResult(response);
    }

}