001/* 002// $Id: XmlaOlap4jHttpProxy.java 482 2012-01-05 23:27:27Z jhyde $ 003// 004// Licensed to Julian Hyde under one or more contributor license 005// agreements. See the NOTICE file distributed with this work for 006// additional information regarding copyright ownership. 007// 008// Julian Hyde licenses this file to you under the Apache License, 009// Version 2.0 (the "License"); you may not use this file except in 010// compliance with the License. You may obtain a copy of the License at: 011// 012// http://www.apache.org/licenses/LICENSE-2.0 013// 014// Unless required by applicable law or agreed to in writing, software 015// distributed under the License is distributed on an "AS IS" BASIS, 016// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017// See the License for the specific language governing permissions and 018// limitations under the License. 019*/ 020package org.olap4j.driver.xmla.proxy; 021 022import org.olap4j.driver.xmla.XmlaOlap4jDriver; 023import org.olap4j.driver.xmla.XmlaOlap4jServerInfos; 024import org.olap4j.impl.Base64; 025 026import java.io.*; 027import java.net.*; 028import java.util.concurrent.Future; 029 030/** 031 * Extends the AbstractCachedProxy and serves as 032 * a production ready http communication class. Every SOAP request 033 * sends a POST call to the destination XMLA server and returns 034 * the response as a byte array, conforming to the Proxy interface. 035 * 036 * <p>It also takes advantage of the AbstractHttpProxy cookie 037 * managing facilities. All cookies received from the end point 038 * server will be sent back if they are not expired and they also 039 * conform to cookie domain rules. 040 * 041 * @author Luc Boudreau and Julian Hyde 042 * @version $Id: XmlaOlap4jHttpProxy.java 482 2012-01-05 23:27:27Z jhyde $ 043 */ 044public class XmlaOlap4jHttpProxy extends XmlaOlap4jAbstractHttpProxy 045{ 046 private final XmlaOlap4jDriver driver; 047 048 /** 049 * Creates a XmlaOlap4jHttpProxy. 050 * 051 * @param driver Driver 052 */ 053 public XmlaOlap4jHttpProxy( 054 XmlaOlap4jDriver driver) 055 { 056 this.driver = driver; 057 } 058 059 private static final String DISCOVER = 060 "<Discover xmlns=\"urn:schemas-microsoft-com:xml-analysis\""; 061 062 private static final String EXECUTE = 063 "<Execute xmlns=\"urn:schemas-microsoft-com:xml-analysis\""; 064 065 @Override 066 public byte[] getResponse(XmlaOlap4jServerInfos serverInfos, String request) 067 throws XmlaOlap4jProxyException 068 { 069 URLConnection urlConnection = null; 070 try { 071 URL url = serverInfos.getUrl(); 072 // Open connection to manipulate the properties 073 urlConnection = url.openConnection(); 074 urlConnection.setDoOutput(true); 075 076 // Set headers 077 urlConnection.setRequestProperty( 078 "content-type", 079 "text/xml"); 080 urlConnection.setRequestProperty( 081 "User-Agent", 082 "Olap4j(" 083 .concat(driver.getVersion()) 084 .concat(")")); 085 urlConnection.setRequestProperty( 086 "Accept", 087 "text/xml;q=1"); 088 urlConnection.setRequestProperty( 089 "Accept-Charset", 090 getEncodingCharsetName() 091 .concat(";q=1")); 092 093 // Some servers expect a SOAPAction header. 094 // TODO There is bound to be a better way to do this. 095 if (request.contains(DISCOVER)) { 096 urlConnection.setRequestProperty( 097 "SOAPAction", 098 "\"urn:schemas-microsoft-com:xml-analysis:Discover\""); 099 } else if (request.contains(EXECUTE)) { 100 urlConnection.setRequestProperty( 101 "SOAPAction", 102 "\"urn:schemas-microsoft-com:xml-analysis:Execute\""); 103 } 104 105 // Encode credentials for basic authentication 106 StringBuilder sb = new StringBuilder(); 107 if (serverInfos.getUsername() != null 108 && serverInfos.getPassword() != null) 109 { 110 sb.append(serverInfos.getUsername()); 111 sb.append(":"); 112 sb.append(serverInfos.getPassword()); 113 } else if (url.getUserInfo() != null) { 114 sb.append(url.getUserInfo()); 115 } 116 if (!sb.toString().equals("")) { 117 String encoding = 118 Base64.encodeBytes( 119 sb.toString().getBytes(), 0); 120 urlConnection.setRequestProperty( 121 "Authorization", "Basic " + encoding); 122 } 123 124 // Set correct cookies 125 this.useCookies(urlConnection); 126 127 // Send data (i.e. POST). Use same encoding as specified in the 128 // header. 129 final String encoding = getEncodingCharsetName(); 130 urlConnection.getOutputStream().write(request.getBytes(encoding)); 131 132 // Get the response, again assuming default encoding. 133 InputStream is = urlConnection.getInputStream(); 134 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 135 byte[] buf = new byte[1024]; 136 int count; 137 138 while ((count = is.read(buf)) > 0) { 139 baos.write(buf, 0, count); 140 } 141 142 // Save the returned cookies for later use 143 this.saveCookies(urlConnection); 144 145 return baos.toByteArray(); 146 // All exceptions should be trapped here. 147 // The response will only be available here anyways. 148 } catch (Exception e) { 149 // In order to prevent the JDK from keeping this connection 150 // in WAIT mode, we need to empty the error stream cache. 151 try { 152 final int espCode = 153 ((HttpURLConnection)urlConnection).getResponseCode(); 154 InputStream errorStream = 155 ((HttpURLConnection)urlConnection).getErrorStream(); 156 final ByteArrayOutputStream baos = 157 new ByteArrayOutputStream(); 158 final byte[] buf = new byte[1024]; 159 int count; 160 if (errorStream != null) { 161 while ((count = errorStream.read(buf)) > 0) { 162 baos.write(buf, 0, count); 163 } 164 errorStream.close(); 165 } 166 baos.close(); 167 } catch (IOException ex) { 168 // Well, we tried. No point notifying the user here. 169 } 170 throw new XmlaOlap4jProxyException( 171 "This proxy encountered an exception while processing the " 172 + "query.", 173 e); 174 } 175 } 176 177 @Override 178 public Future<byte[]> getResponseViaSubmit( 179 final XmlaOlap4jServerInfos serverInfos, 180 final String request) 181 { 182 return XmlaOlap4jDriver.getFuture(this, serverInfos, request); 183 } 184 185 // implement XmlaOlap4jProxy 186 public String getEncodingCharsetName() { 187 return "UTF-8"; 188 } 189} 190 191// End XmlaOlap4jHttpProxy.java 192 193 194