From 19f9d9de883823582a154da04880d81733715144 Mon Sep 17 00:00:00 2001 From: Luc Boudreau Date: Mon, 6 Oct 2008 16:46:14 +0000 Subject: [PATCH] Fixed issue 2018878. If a SOAP error is received from the server, it will be included in the exception that is thrown back at the end-user. There is still an issue with some IOException that can reach the end-user layer. This is a no-no and will need to be fixed. I didn't fix it here since the MondrianInprocProxy implements the faulty interface. XmlaOlap4jProxy implementation should not throw any IOException, but should handle it's own exceptions and wrap them in XmlaOlap4jProxyException is necessary. I've added a FIXME tag and will log a bug against it. git-svn-id: https://olap4j.svn.sourceforge.net/svnroot/olap4j/trunk@119 c6a108a4-781c-0410-a6c6-c2d559e19af0 --- src/org/olap4j/OlapExceptionHelper.java | 4 + .../olap4j/driver/xmla/XmlaOlap4jCellSet.java | 17 ++-- .../driver/xmla/XmlaOlap4jConnection.java | 13 ++- .../proxy/XmlaOlap4jAbstractHttpProxy.java | 51 ++++++---- .../xmla/proxy/XmlaOlap4jCookieManager.java | 21 ++-- .../xmla/proxy/XmlaOlap4jHttpProxy.java | 95 ++++++++++--------- .../driver/xmla/proxy/XmlaOlap4jProxy.java | 16 +++- .../xmla/proxy/XmlaOlap4jProxyException.java | 25 +++++ 8 files changed, 153 insertions(+), 89 deletions(-) create mode 100644 src/org/olap4j/driver/xmla/proxy/XmlaOlap4jProxyException.java diff --git a/src/org/olap4j/OlapExceptionHelper.java b/src/org/olap4j/OlapExceptionHelper.java index 4bfe803..258e80e 100644 --- a/src/org/olap4j/OlapExceptionHelper.java +++ b/src/org/olap4j/OlapExceptionHelper.java @@ -21,6 +21,10 @@ public static OlapException createException(String msg) { return new OlapException(msg); } + public static OlapException createException(Throwable cause) { + return new OlapException(cause.getMessage(), cause); + } + public static OlapException createException(String msg, Throwable cause) { return new OlapException(msg, cause); } diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java b/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java index 6f60e1e..158f3cc 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java @@ -13,8 +13,8 @@ import org.olap4j.impl.Olap4jUtil; import static org.olap4j.driver.xmla.XmlaOlap4jUtil.*; import org.olap4j.metadata.*; -import org.w3c.dom.Document; -import org.w3c.dom.Element; +import org.w3c.dom.*; +import org.w3c.dom.ls.*; import org.xml.sax.SAXException; import java.io.*; @@ -107,8 +107,6 @@ void populate() throws OlapException { findChild(body, SOAP_NS, "Fault"); if (fault != null) { /* - Example: - SOAP-ENV:Client.00HSBC01 XMLA connection datasource not found @@ -123,10 +121,15 @@ void populate() throws OlapException { */ // TODO: log doc to logfile - final Element faultstring = findChild(fault, null, "faultstring"); - String message = faultstring.getTextContent(); + // A message must include the fault XML content. This is the right + // and efficient way to do it, according to + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6181019 + // They changed the node.getString() in java... .... + DOMImplementation impl = fault.getOwnerDocument().getImplementation(); + DOMImplementationLS factory = (DOMImplementationLS) impl.getFeature("LS", "3.0"); + LSSerializer serializer = factory.createLSSerializer(); throw OlapExceptionHelper.createException( - "XMLA provider gave exception: " + message); + "XMLA provider gave exception: " + serializer.writeToString(fault)); } Element executeResponse = findChild(body, XMLA_NS, "ExecuteResponse"); diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java index 05a37a7..b76baec 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java @@ -597,7 +597,18 @@ Element xxx(String request) throws OlapException { try { bytes = proxy.get(serverUrl, request); } catch (IOException e) { - throw OlapExceptionHelper.createException(null, e); + /* + * FIXME This type of exception should not reach this point. + * It was maintained because some other proxy implementations + * exists out there that still throw an IOException arround. + * This was a bad design which we will fix at some point but not + * before the 1.0 release. + */ + throw OlapExceptionHelper.createException(e); + } catch (XmlaOlap4jProxyException e) { + throw OlapExceptionHelper.createException( + "This connection encountered an exception while executing a query.", + e); } Document doc; try { diff --git a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jAbstractHttpProxy.java b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jAbstractHttpProxy.java index 37dcaad..0f8b778 100644 --- a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jAbstractHttpProxy.java +++ b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jAbstractHttpProxy.java @@ -63,7 +63,7 @@ public abstract class XmlaOlap4jAbstractHttpProxy * @throws IOException */ abstract public byte[] getResponse(URL url, String request) - throws IOException; + throws XmlaOlap4jProxyException; /** @@ -84,7 +84,7 @@ abstract public Future getResponseViaSubmit( * @throws IOException An io exception gets thrown if the given url * connection has not been opened yet. */ - protected void useCookies(URLConnection urlConn) throws IOException { + protected void useCookies(URLConnection urlConn){ // Initializes the cookie manager this.initCookieManager(); @@ -100,7 +100,7 @@ protected void useCookies(URLConnection urlConn) throws IOException { * @throws IOException An io exception gets thrown if the given url * connection has already been opened. */ - protected void saveCookies(URLConnection urlConn) throws IOException { + protected void saveCookies(URLConnection urlConn){ // Initializes the cookie manager this.initCookieManager(); @@ -151,29 +151,40 @@ public void setCache(Map config, Map properties) } // implement XmlaOlap4jProxy - public byte[] get(URL url, String request) throws IOException { + public byte[] get(URL url, String request) throws XmlaOlap4jProxyException { + byte[] response = null; // Tries to fetch from cache - byte[] response = - getFromCache( - url, - request.getBytes(getEncodingCharsetName())); - - // Returns the cached value if found - if (response != null) { - return response; + try { + response = + getFromCache( + url, + request.getBytes(getEncodingCharsetName())); + // Returns the cached value if found + if (response != null) { + return response; + } + } catch (IOException e) { + throw new XmlaOlap4jProxyException( + "An exception was encountered while browsing the proxy cache.", + e); } // Executes the query response = getResponse(url, request); - // Adds to cache - addToCache( - url, - request.getBytes(getEncodingCharsetName()), - response); - - // Returns result - return response; + try { + // Adds to cache + addToCache( + url, + request.getBytes(getEncodingCharsetName()), + response); + // Returns result + return response; + } catch (IOException e) { + throw new XmlaOlap4jProxyException( + "An exception was encountered while saving a response in the proxy cache.", + e); + } } diff --git a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jCookieManager.java b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jCookieManager.java index 1340c22..14f5498 100644 --- a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jCookieManager.java +++ b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jCookieManager.java @@ -9,16 +9,10 @@ */ package org.olap4j.driver.xmla.proxy; -import java.io.IOException; -import java.net.URL; -import java.net.URLConnection; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Iterator; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.concurrent.ConcurrentHashMap; +import java.net.*; +import java.text.*; +import java.util.*; +import java.util.concurrent.*; /** *

CookieManager is a simple utility for handling cookies when working @@ -88,7 +82,7 @@ public XmlaOlap4jCookieManager() { * or IOException will be thrown * @throws java.io.IOException Thrown if conn is not open. */ - public void storeCookies(URLConnection conn) throws IOException { + public void storeCookies(URLConnection conn){ // Determines the domain from where these cookies are being sent String domain = getDomainFromHost(conn.getURL().getHost()); @@ -164,7 +158,7 @@ public void storeCookies(URLConnection conn) throws IOException { * @param conn a java.net.URLConnection - must NOT be open, or IOException will be thrown * @throws java.io.IOException Thrown if conn has already been opened. */ - public void setCookies(URLConnection conn) throws IOException { + public void setCookies(URLConnection conn){ // Determines the domain and path to retrieve the appropriate cookies URL url = conn.getURL(); @@ -200,9 +194,8 @@ && isNotExpired((String) cookie.get(EXPIRES))) { } conn.setRequestProperty(COOKIE, cookieStringBuffer.toString()); } catch (java.lang.IllegalStateException ise) { - IOException ioe = new IOException( + throw new RuntimeException( "Illegal State! Cookies cannot be set on a URLConnection that is already connected. Only call setCookies(java.net.URLConnection) AFTER calling java.net.URLConnection.connect()."); - throw ioe; } } diff --git a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jHttpProxy.java b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jHttpProxy.java index 9c5f98c..c9ef89b 100644 --- a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jHttpProxy.java +++ b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jHttpProxy.java @@ -34,59 +34,66 @@ public class XmlaOlap4jHttpProxy extends XmlaOlap4jAbstractHttpProxy { @Override public byte[] getResponse(URL url, String request) - throws IOException + throws XmlaOlap4jProxyException { - // Open connection to manipulate the properties - URLConnection urlConnection = url.openConnection(); - urlConnection.setDoOutput(true); + try { + // Open connection to manipulate the properties + URLConnection urlConnection = url.openConnection(); + urlConnection.setDoOutput(true); - // Set headers - urlConnection.setRequestProperty( - "content-type", - "text/xml"); - urlConnection.setRequestProperty( - "User-Agent", - "Olap4j(" - .concat(XmlaOlap4jDriver.VERSION) - .concat(")")); - urlConnection.setRequestProperty( - "Accept", - "text/xml;q=1"); - urlConnection.setRequestProperty( - "Accept-Charset", - getEncodingCharsetName() - .concat(";q=1")); - - // Encode credentials for basic authentication - if (url.getUserInfo() != null) { - String encoding = - Base64.encodeBytes(url.getUserInfo().getBytes(), 0); + // Set headers urlConnection.setRequestProperty( - "Authorization", "Basic " + encoding); - } + "content-type", + "text/xml"); + urlConnection.setRequestProperty( + "User-Agent", + "Olap4j(" + .concat(XmlaOlap4jDriver.VERSION) + .concat(")")); + urlConnection.setRequestProperty( + "Accept", + "text/xml;q=1"); + urlConnection.setRequestProperty( + "Accept-Charset", + getEncodingCharsetName() + .concat(";q=1")); - // Set correct cookies - this.useCookies(urlConnection); + // Encode credentials for basic authentication + if (url.getUserInfo() != null) { + String encoding = + Base64.encodeBytes(url.getUserInfo().getBytes(), 0); + urlConnection.setRequestProperty( + "Authorization", "Basic " + encoding); + } - // Send data (i.e. POST). Use same encoding as specified in the - // header. - final String encoding = getEncodingCharsetName(); - urlConnection.getOutputStream().write(request.getBytes(encoding)); + // Set correct cookies + this.useCookies(urlConnection); - // Get the response, again assuming default encoding. - InputStream is = urlConnection.getInputStream(); - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buf = new byte[1024]; - int count; + // Send data (i.e. POST). Use same encoding as specified in the + // header. + final String encoding = getEncodingCharsetName(); + urlConnection.getOutputStream().write(request.getBytes(encoding)); - while ((count = is.read(buf)) > 0) { - baos.write(buf, 0, count); - } + // Get the response, again assuming default encoding. + InputStream is = urlConnection.getInputStream(); + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buf = new byte[1024]; + int count; - // Save the returned cookies for later use - this.saveCookies(urlConnection); + while ((count = is.read(buf)) > 0) { + baos.write(buf, 0, count); + } - return baos.toByteArray(); + // Save the returned cookies for later use + this.saveCookies(urlConnection); + + return baos.toByteArray(); + // All exceptions should be trapped here. + // The response will only be available here anyways. + } catch (Exception e) { + throw new XmlaOlap4jProxyException( + "This proxy encountered an exception while processing the query.",e); + } } @Override diff --git a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jProxy.java b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jProxy.java index f74a3a4..c47a275 100644 --- a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jProxy.java +++ b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jProxy.java @@ -23,10 +23,20 @@ public interface XmlaOlap4jProxy { * * @param url Target URL * @param request Request string - * @return Response - * @throws IOException + * @return Response The byte array that contains the whole response + * from the server. + * @throws IOException This exception declaration will be removed soon. + * Don't catch this. Catch XmlaOlap4jProxyException instead. + * @throws XmlaOlap4jProxyException If anything occurs during the + * request execution. */ - byte[] get(URL url, String request) throws IOException; + /* + * FIXME We will need to remove the IOException declaration because + * this type of error is linked to the proxy type. A wrapper + * class was created, but some proxies out there (MondrianInprocProxy...) + * still uses this. + */ + byte[] get(URL url, String request) throws XmlaOlap4jProxyException,IOException; /** * Submits a request for background execution. diff --git a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jProxyException.java b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jProxyException.java new file mode 100644 index 0000000..747ed75 --- /dev/null +++ b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jProxyException.java @@ -0,0 +1,25 @@ +/* +// $Id:$ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla.proxy; + +/** + * Gets thrown whenever an exception is encountered during the querying + * of an XmlaOlap4jProxy subclass. + * + * @author Luc Boudreau + * @version $Id:$ + */ +public class XmlaOlap4jProxyException extends Exception { + private static final long serialVersionUID = 1729906649527317997L; + public XmlaOlap4jProxyException(String message, Throwable cause) { + super(message, cause); + } +} +//End XmlaOlap4jProxyException.java \ No newline at end of file