OBIEE Web Service API 中的 HtmlViewService 未呈现报告(仅显示旋转加载器)
Posted
技术标签:
【中文标题】OBIEE Web Service API 中的 HtmlViewService 未呈现报告(仅显示旋转加载器)【英文标题】:HtmlViewService in OBIEE Web Service API is not rendering report (it's only showing spinning loader) 【发布时间】:2014-10-04 00:18:56 【问题描述】:我有一个 Java 应用程序,它利用 OBIEE Web 服务 API 来使用来自 BI 服务器的数据。我能够很好地使用 XMLViewService 和 WebCatalogService,但我不能完全让 htmlViewService 在 Java 应用程序中正确呈现报告。该报告仅显示旋转加载器,但从未实际呈现报告。我很确定这与 Java 应用程序和 BI 服务器位于不同域的事实有关。 API 文档是这样说的:
在 Oracle BI Web 服务和第三方 Web 服务器不属于同一个域名服务 (DNS) 域的情况下,用户可能会收到与跨域脚本的浏览器安全约束相关的 JavaScript 错误。要避免这些问题,请使用 setBridge() 方法修改回调 URL 以指向第三方 Web 服务器。请注意,不提供由第三方 Web 服务器执行以将请求重新路由到 Oracle BI Web 服务的 Web 组件。此功能需要由第三方应用程序来实现。
几年前,由于 .NET 应用程序和 BI 服务器位于不同的域中,我使用 .NET/C# 进行了相同类型的集成并遇到了相同的问题。结果,我不得不创建一个 HTTP 处理程序(.ashx 文件)并使用 setBridge() 方法来解决问题。
我面临的挑战是找不到 Java 的 servlet 桥接示例。而且我对将.NET/.ASHX 代码移植到Java servlet/bridge 并不太有信心。有没有人可以提供任何代码示例或方向来为我指明正确的方向?这是一段代码,向您展示我正在做什么来拉回报告数据:
// define report path
ReportRef reportRef = new ReportRef();
reportRef.setReportPath(reportFolder + "/" + reportName);
// set page params
StartPageParams pageParams = new StartPageParams();
pageParams.setDontUseHttpCookies(true);
// set report params
String pageId = htmlService.startPage(pageParams, sawSessionId);
String reportId = pageId + reportName;
htmlService.addReportToPage(pageId, reportId, reportRef, null, null, null, sawSessionId);
// get report html
StringBuffer reportHtml = new StringBuffer();
reportHtml.append(htmlService.getHtmlForReport(pageId, reportId, sawSessionId));
// return html
return reportHtml.toString();
这是浏览器中返回的错误:
XMLHttpRequest 无法加载 http://myobiserver.com/analytics/saw.dll?ajaxGo。请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,Origin 'http://myjavaapp.com' 不允许访问。
根据要求,这是我的 .NET/.ASHX 桥:
using System.Collections.Specialized;
using System.Net;
using System.Text;
using System.Web;
using System;
using System.Collections;
using System.Configuration;
using System.Collections.Specialized;
using System.Web;
using System.Text;
using System.Net;
using System.IO;
using System.Diagnostics;
/*
This is a ASP.NET handler that handles communication
between the SharePoint site and OracleBI.
It will be deployed to:
C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\OracleBI
*/
public class OracleBridge: IHttpHandler
public bool IsReusable getreturn true;
public OracleBridge()
string getServer()
string strServer = "http://<enter-domain>/analytics/saw.dll";
int index = strServer.LastIndexOf("/");//split off saw.dll
if (index >=0)
return strServer.Substring(0,index+1);
else
return strServer;
public void ProcessRequest(HttpContext context)
HttpWebRequest req = forwardRequest(context);
forwardResponse(context,req);
private HttpWebRequest forwardRequest(HttpContext context)
string strURL = makeURL(context);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(strURL);
req.Method = context.Request.HttpMethod;
NameValueCollection headers = context.Request.Headers;
req.Accept = headers.Get("Accept");
req.Expect = headers.Get("Expect");
req.ContentType = headers.Get("Content-Type");
string strModifiedSince = headers.Get("If-Modified-Since");
if (strModifiedSince != null && strModifiedSince.Length != 0)
req.IfModifiedSince = DateTime.Parse(strModifiedSince);
req.Referer = headers.Get("Referer");
req.UserAgent = headers.Get("User-Agent");
if (!req.Method.Equals("GET"))
CopyStreams(context.Request.InputStream,req.GetRequestStream());
return req;
private void forwardResponse(HttpContext context, HttpWebRequest req)
HttpWebResponse resp =null;
try
resp = (HttpWebResponse)req.GetResponse();
catch(WebException e)
resp = (HttpWebResponse)e.Response;
context.Response.StatusCode = (int)resp.StatusCode;
for (int i = 0; i < resp.Cookies.Count; i++)
Cookie c = resp.Cookies[i];
HttpCookie hc = new HttpCookie(c.Name, c.Value);
hc.Path = c.Path;
hc.Domain = getServer();
context.Response.Cookies.Add(hc);
context.Response.ContentType = resp.ContentType;
CopyStreams(resp.GetResponseStream(), context.Response.OutputStream);
private string makeURL(HttpContext context)
string strQuery = context.Request.Url.Query;
string[] arrParams = strQuery.Split('?','&');
StringBuilder resultingParams = new StringBuilder();
string strURL=null;
foreach(string strParam in arrParams )
string[] arrNameValue = strParam.Split('=');
if (!arrNameValue[0].Equals("RedirectURL"))
if (strParam.Length != 0)
if (resultingParams.Length != 0)
resultingParams.Append("&");
resultingParams.Append(strParam);
else if (arrNameValue.Length >1)
strURL = HttpUtility.UrlDecode(arrNameValue[1]);
if (strURL ==null)
throw new Exception("Invalid URL format. requestURL parameter is missing");
String sAppendChar = strURL.Contains("?") ? "&" : "?";
if (strURL.StartsWith("http:") || strURL.StartsWith("https:"))
String tmpURL = strURL + sAppendChar + resultingParams.ToString();
return tmpURL;
else
String tmpURL = getServer() + strURL + sAppendChar + resultingParams.ToString();
return tmpURL;
private void CopyStreams(Stream inStr,Stream outStr)
byte[] buf = new byte[4096];
try
do
int iRead = inStr.Read(buf,0,4096);
if (iRead == 0)
break;
outStr.Write(buf,0,iRead);
while (true);
finally
outStr.Close();
【问题讨论】:
【参考方案1】:使用先前答案中发布的链接 (http://pastebin.com/NibVnBLb) 中的 BridgeServlet 对我们不起作用。在我们的门户网站中,使用上面的 BridgeServlet 嵌入 Oracle BI 仪表板,将我们重定向到 OBI 登录页面,并且控制台日志显示不正确的资源 (js/css) Web 链接(本地 URL 而不是 OBIEE URL)。
相反,我们使用了这个类(稍作调整)https://gist.github.com/rafaeltuelho/9376341#file-obieehttpservletbridge-java。
使用 Java 11、Oracle Business Intelligence 12.2.1.4.0、OBIEE (http://OBIEE-server:port/analytics/saw.dll/wsdl/v12) 的 WSDL v12 测试,禁用 SSO。
这里是 BridgeServlet 类:
package com.abs.bi;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class OBIEEBridge
*/
public class BridgeServlet extends HttpServlet
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public BridgeServlet()
super();
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
try
this.processRequest(request, response);
catch (Exception e)
throw new ServletException(e);
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
try
this.processRequest(request, response);
catch (Exception e)
throw new ServletException(e);
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
HttpURLConnection urlCon = forwardRequest(request);
forwardResponse(response, urlCon);
@SuppressWarnings("unchecked")
private String decodeURL(HttpServletRequest request)
StringBuffer bufURL = new StringBuffer("");
Map<String, String[]> params = request.getParameterMap();
String[] arrURL = params.get("RedirectURL");
String strURL = arrURL == null || arrURL.length == 0 ? null : arrURL[0];
bufURL.append(strURL);
int nQIndex = strURL.lastIndexOf('?');
if (params != null && !params.isEmpty())
bufURL.append(((nQIndex >= 0) ? "&" : "?"));
Set<String> keys = params.keySet();
Iterator<String> it = keys.iterator();
while (it.hasNext())
try
String strKey = it.next();
if (strKey.equalsIgnoreCase("RedirectURL"))
continue;
String strEncodedKey = URLEncoder.encode(strKey, "UTF-8");
String[] paramValues = params.get(strKey);
for (String paramValue : paramValues)
bufURL.append(strEncodedKey);
bufURL.append("=");
bufURL.append(URLEncoder.encode(paramValue, "UTF-8"));
bufURL.append("&");
catch (UnsupportedEncodingException e)
e.printStackTrace();
bufURL.deleteCharAt(bufURL.length() - 1);
return bufURL.toString();
@SuppressWarnings("unchecked")
private HttpURLConnection forwardRequest(HttpServletRequest request) throws IOException
String strURL = decodeURL(request);
String[] arrURL = strURL.split("&", 2);
String baseURL = arrURL[0];
URL url = new URL(baseURL);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
String strMethod = request.getMethod();
con.setRequestMethod(strMethod);
Enumeration<String> en = request.getHeaderNames();
String strHeader;
while (en.hasMoreElements())
strHeader = en.nextElement();
String strHeaderValue = request.getHeader(strHeader);
con.setRequestProperty(strHeader, strHeaderValue);
// is not a HTTP GET request
if (strMethod.compareTo("GET") != 0)
con.setDoOutput(true);
con.setDoInput(true);
con.setUseCaches(false);
DataOutputStream forwardStream = new DataOutputStream(con.getOutputStream());
try
String urlParameters = arrURL[1];
forwardStream.writeBytes(urlParameters);
forwardStream.flush();
finally
forwardStream.close();
return con;
private void forwardResponse(HttpServletResponse response, HttpURLConnection con) throws IOException
int nContentLen = -1;
String strKey;
String strValue;
try
response.setStatus(con.getResponseCode());
for (int i = 1; true; ++i)
strKey = con.getHeaderFieldKey(i);
strValue = con.getHeaderField(i);
if (strKey == null)
break;
if (strKey.equals("Content-Length"))
nContentLen = Integer.parseInt(con.getHeaderField(i));
continue;
if (strKey.equalsIgnoreCase("Connection") || strKey.equalsIgnoreCase("Server")
|| strKey.equalsIgnoreCase("Transfer-Encoding") || strKey.equalsIgnoreCase("Content-Length"))
continue; // skip certain headers
if (strKey.equalsIgnoreCase("Set-Cookie"))
String[] cookieStr1 = strValue.split(";");
String[] cookieStr2 = cookieStr1[0].split("=");
// String[] cookieStr3 = cookieStr1[1].split("=");
/*
* Change the Set-Cookie HTTP Header to remove the 'path' attribute. Thus the
* browser can accept the ORA_BIPS_NQID cookie from Oracle BI Server
*/
Cookie c = new Cookie(cookieStr2[0], cookieStr2[1]);
c.setPath("/");
response.addCookie(c);
else
response.setHeader(strKey, strValue);
copyStreams(con.getInputStream(), response.getOutputStream(), nContentLen);
finally
response.getOutputStream().close();
con.getInputStream().close();
private void copyStreams(InputStream inputStream, OutputStream forwardStream, int nContentLen) throws IOException
byte[] buf = new byte[1024];
int nCount = 0;
int nBytesToRead = 1024;
int nTotalCount = 0;
do
if (nContentLen != -1)
nBytesToRead = nContentLen - nTotalCount > 1024 ? 1024 : nContentLen - nTotalCount;
if (nBytesToRead == 0)
break;
// try to read some bytes from src stream
nCount = inputStream.read(buf, 0, nBytesToRead);
if (nCount < 0)
break;
nTotalCount += nCount;
// try to write some bytes in target stream
forwardStream.write(buf, 0, nCount);
while (true);
AbsServiceUtils,其中包含对 Oracle BI 服务器的 SAWSessionService 和 HtmlViewService Web 服务调用:
package com.abs.bi;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspWriter;
import oracle.bi.web.soap.AuthResult;
import oracle.bi.web.soap.HtmlViewService;
import oracle.bi.web.soap.HtmlViewServiceSoap;
import oracle.bi.web.soap.ReportHTMLLinksMode;
import oracle.bi.web.soap.ReportHTMLOptions;
import oracle.bi.web.soap.ReportRef;
import oracle.bi.web.soap.SAWLocale;
import oracle.bi.web.soap.SAWSessionParameters;
import oracle.bi.web.soap.SAWSessionService;
import oracle.bi.web.soap.SAWSessionServiceSoap;
import oracle.bi.web.soap.StartPageParams;
public class AbsServiceUtils
private AbsServiceUtils()
public static URL buildWsdlUrl() throws MalformedURLException
return new URL(IAbsService.BASEWSDLURL);
public static void writeBiContent(HttpServletRequest request, JspWriter out, String biReport) throws IOException
String userAgent = request.getHeader("User-Agent");
Locale userLocale = request.getLocale();
String bridgeServletContextPath = request.getContextPath() + "/bridgeservlet";
String reportHtml = writeBiContent(biReport, userAgent, userLocale, bridgeServletContextPath);
if (out != null)
out.println(reportHtml);
public static String writeBiContent(String biReport, String userAgent, Locale userLocale,
String bridgeServletContextPath) throws MalformedURLException
HtmlViewService htmlViewService = new HtmlViewService(buildWsdlUrl());
HtmlViewServiceSoap htmlClient = htmlViewService.getHtmlViewService();
SAWSessionService sAWSessionService = new SAWSessionService(buildWsdlUrl());
SAWSessionServiceSoap myPort = sAWSessionService.getSAWSessionServiceSoap();
SAWSessionParameters sessionparams = new SAWSessionParameters();
sessionparams.setUserAgent(userAgent);
SAWLocale sawlocale = new SAWLocale();
sawlocale.setLanguage(userLocale.getLanguage());
sawlocale.setCountry(userLocale.getCountry());
sessionparams.setLocale(sawlocale);
sessionparams.setAsyncLogon(false);
AuthResult result = myPort.logonex(IAbsService.BIUSERNAME, IAbsService.BIPASSWORD, sessionparams);
String sessionID = result.getSessionID();
List<String> keepAliveSessionList = new ArrayList<>(1);
keepAliveSessionList.add(sessionID);
myPort.keepAlive(keepAliveSessionList);
StartPageParams spparams = new StartPageParams();
spparams.setDontUseHttpCookies(true);
String pageID = htmlClient.startPage(spparams, sessionID);
/**
* This method will set the path to the servlet which will act like a bridge to
* retrieve all the OBIEE resources like the javascript, CSS and the report.
*/
if (bridgeServletContextPath != null)
htmlClient.setBridge(bridgeServletContextPath, sessionID);
ReportHTMLOptions htmlOptions = new ReportHTMLOptions();
htmlOptions.setEnableDelayLoading(false);
htmlOptions.setLinkMode(ReportHTMLLinksMode.IN_PLACE.value());
ReportRef reportref = new ReportRef();
reportref.setReportPath(IAbsService.BIROOTPATH + biReport);
StartPageParams startpageparams = new StartPageParams();
startpageparams.setDontUseHttpCookies(false);
htmlClient.addReportToPage(pageID, biReport.replace(" ", ""), reportref, null, null, htmlOptions, sessionID);
String reportHtml = htmlClient.getHeadersHtml(pageID, sessionID);
reportHtml = reportHtml + htmlClient.getHtmlForReport(pageID, biReport.replace(" ", ""), sessionID);
reportHtml = reportHtml + htmlClient.getCommonBodyHtml(pageID, sessionID);
return reportHtml;
IAbsService:
package com.abs.bi;
public interface IAbsService
public static final String BASEWSDLURL = "http://<OracleBIServer:port>/analytics/saw.dll/wsdl/v12";
public static final String BIUSERNAME = "USER";
public static final String BIPASSWORD = "PASS";
public static final String BIROOTPATH = "/shared/sharedfolder/";
public static final String BIREPORTNAME = "report";
【讨论】:
【参考方案2】:使用链接http://pastebin.com/NibVnBLb 查看java 的桥接代码。希望这可能会有所帮助。
【讨论】:
我遇到了三个不允许我构建的问题,我无法找到解决方法:1) "HttpProxyServlet.getHeaders(request, hashtable);"正在抛出“无法解决” 2)“URLConnection httpConnection = urlconn.openConnection();”正在抛出“类型 URL 未定义” 2) “com.abs.util.GetPost.rewriteHeaders(httpConnection, response);”正在抛出“无法解决”...最后,我在哪里插入 BI 服务器的基本 URL 的 URL? (在原始 C# 代码中是 "string strServer = "http://以上是关于OBIEE Web Service API 中的 HtmlViewService 未呈现报告(仅显示旋转加载器)的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Azure Service Fabric 中的自托管 Web API 上配置 SSL