11984 items (11984 unread) in 19 feeds
Blog
(67 unread)
Google
(2043 unread)
Oracle
(3668 unread)
OracleERP
(1622 unread)
ReadBlog
(1874 unread)
nix
(368 unread)
OpenSource
(370 unread)
TechNews
(1829 unread)
Design
(143 unread)
OracleERP (100 unread)
Friends of BIP, STR Software have put together a great web based resource 'BIP University'
Focused on the E Business Suite flavor and their own integrations with BIP under EBS R12; its a great resource and well worth a few clicks and a read. Check it out here - http://www.bipuniversity.com/
Yep, found another integration with BIP. I get asked about Oracle Policy Automation quite a lot; I do not profess to know much; enough to be dangerous I guess. However, I was not aware that they had been working with BIP to help automate the generation of documents from the system.
For the uninitiated, here's the blurb care of :
Oracle Policy Modeling is a Windows desktop application for transforming legislation and policy documents into executable business rules. Rules are written in Word and Excel documents using phrases in languages such as English, Chinese and French. These rule documents can be shared amongst business and information technology stakeholders, and commentary can be added into the documents without affecting the structure of the rules themselves. Other features of Oracle Policy Modeling include integrated test case execution and debugging capabilities, and the definition of interviews for interactive rule-based assessments. Interview screen order and branching logic can be defined using visual flow diagrams.
In other words, a cool piece of technology, but tell us Tim how is it used? Well, it has been publicly deployed within several government web-sites. Australia's Department of Immigration uses it for visitors to check their eligibility for visas. The UK uses it for their Employment Status Indicator assessment tool, the UK governments online portal for businesses also uses OPA for over 60 interactive tools while the United States uses the software for guidance on tax law. The last one might be pertinent for me this weekend as W-2s have arrived and I have a night of misery trying to get a refund.
How does BIP fit in? Pictures are worth a thousands words and Fiona from the development team down under has recorded a great YouTube session explaining the integration and how to take advantage of it. I know I'm becoming more American cos I found it a little hard to place her accent at first, not to be rude Fiona but was it Brit, Aussie or maybe New Zealand? I plumped for Aussie, 10 points to me ... phew!
Direct link to the OPA YouTube channel - some other great vids on use cases and features.
You can find the OPA Homepage here lots of info on the tool and its possible applications.
The BI Publisher January patch for 11.1.1.5.0 is now available on Metalink; look for patch 13554951. Thanks to Shinji and team, this is one of the easiest posts of the year so far :0) Contents of the readme below, enjoy!
One-off patch for
Oracle Business Intelligence Publisher 11.1.1.5.0
READ ME File
==================================================
This patch contains fixes of following bugs for Oracle Business Intelligence Publisher 11.1.1.5.0.
9102877 - QA: QUERY BUILDER GENERATES INCORRECT SQL FOR MANY DBS 10071370 - IF 'USE SECURE FTP' IS CHECKD ON ADMIN PAGE, ITS SERVER IS NOT LISTD WHEN SCHED 10402890 - SETTINGS FROM "DELIVERY CONFIGURATION" PAGE NOT BEING HONORED WHEN REPORTS RUN 11725468 - ER: RTE HTML SUPPORT IN DATA XML 11828672 - QA: INCORRECT INACTIVE WARNING MESSAGE 11835845 - 11G SQL DATA SET CREATION ORA-01756 ERROR BECAUSE COLON IS READ AS BIND VARIABLE 11850902 - SHARE REPORT LINK "NO PARAMETERS" AND "DOCUMENT ONLY" RENDER INCORRECTLY 11870449 - BI PUBLISHER XDOXSLT:SDIV() FUNCTION RESULTS NOT CORRECT 12312539 - QA: REPORT VIEWER SCREEN FREEZES FOR A FLEX REPORT WHEN SESSION EXPIRES 12376386 - REMOVETEMPLATEFORREPORT API DOESN'T REMOVE TEMPLATE 12405904 - CANNOT DEPLOY BIP WHEN DEPLOYMENT PATH INCLUDES SPACE CHARACTERS 12406034 - CANNOT USE JAVA DB - DERBY - FOR SCHEDULER DATABASE 12570248 - PROJECTS : -GENERATE REV/INV PROCESS ERRORING OUT 12588342 - DELETEOBJECT RANDOM FAILURE 12595931 - WHEN PRINTING CHARTS TO PDF, NUMBERS BECOME ARABIC NUMBERS 12615821 - MISSING MEMBERS ON THE XML GENERATED BY BIP 12634030 - RE-PACKAGING MLR#11893189 TO XDOPARSER11G.JAR 12646493 - ORA-22902 CURSOR EXPRESSION NOT ALLOWED 12666066 - ER: EXCEL 2007 SUPPORT IN REST API 12705244 - JOINED MDX DATA SETS DO NOT PRODUCE CORRECT DATA - DATA MISSING 12726163 - NUMBER OF SESSIONS INCREASES AFTER RUNNING SCHEDULED JOBS 12737670 - GROUP BY FOR MDX DATA SET MISSING IN 11.1.1.5 - WAS PRESENT IN 11.1.1.3 12741858 - BI ASNWERS ANALYSIS IMPLEMENTING CASE WHEN STATEMENTS CAN NOT BE CONSUMED IN BIP 12750192 - ER: GENERATE NATIVE COMBINATION DUAL Y GRAPH IN PPTX OUTPUT FROM RTF AND XPT 12766932 - VERTICAL DUAL Y COMBO CHART MISSING SETTINGS TO ASSIGN VALUES TO AXIS 12775400 - DBFW:GENERATING IN XLXS OUTPUT IS THROWING AN ERROR 12822514 - SQL WITH CLAUSE - DATASET DOESN'T WORK (AND DIAGNOSTIC ISN'T HELPFUL) 12828845 - ISSUE WITH XDO_USER_NAME PARAMETER ON BIP 11.1.1.5.0 12835431 - INTRANSIT VALUATION REPORT QUERY GIVING ERROR IN EDITOR 12847306 - BI PUBLISHER DATA SET - WON'T SAVE 12872831 - EXCEL TEMPLATES GENERATING INCORRECT RESULTS FROM NESTED GROUPS 12879801 - ALLOW SAVING DATA MODEL WITH SPECIAL CHARACTER 12945367 - NOT ABLE TO EDIT DATA MODEL WHEN LINKS EXIT AMONG DATA SETS 12945475 - IE: NOT ABLE TO EDIT DATA MODEL WITH MANY DATA SET AND LINKS 12956901 - IN SQL SERVER CLOB IN DATA MODEL UI MARKED AS STRING DATA TYPE 12956915 - INCORRECT DATA WHEN PROCESSING OF CLOB COLUMNS FOR SQLSERVER 12956934 - DATA MODEL SHOULD RESPECT CASE SENSITIVITY FOR COLUMN AND TABLE NAMES 12972559 - XML DATA FILE TRUNCATED 12972852 - DYNAMIC IMAGES BROKEN FOR FO/PDF 12989467 - NEED TO CONVERT DOCUMENT FORMAT "EXCEL" TO "EXCEL2000" 13005659 - PSR:PERF:BIP:POOR PERF ACCESSING CATALOG FOLDER IN BIP 11G WITH SECURITY ENABLED 13007341 - DISPLAY ISSUES IN PARAMETER TAB OF OBI PUBLISHER 11G 13095050 - STRESS: OUTOFMEMORY ERRORS WITH VIEW REPORT STRESS 13100021 - BI PUBLISHER: QUERY BUILDER RESULTS RETURN COLUMN TYPE (APPEARS) INSTEAD VALUE 13100220 - HOW TO USE 11.1.1.5 WITH THE IDENTITY ASSERTER 13250009 - FOR METADATA LOGICAL SQL BIND WITH DUMMY VALUES INSTEAD OF NULL 13321449 - RESOURCELIMITEXCEPTION DURING ANY OPS THAT USE JNDI DATA SOURCE 13346737 - MULTIPLE VALUES IN A DASHBOARD PROMPT DOESN'T WORK WITH BI PUBLISHER INTEGRATED 13351305 - QUERY BUILDER DOES NOT BUILD CORRECT SYNTAX FOR SQL SERVER 13393658 - PRINTER DELIVERY [0] STATUS: FAILED PRINTING FROM WEB SERVICE CALL FROM EXTERNAL 13421264 - ADDING PARAMETER TO SQL BI SERVER DATA SET CORRUPTS DATA MODEL 13481659 - CAN'T SAVE ON BI DEV ENV RC2 13501838 - ORA-00923 ISSUE WHEN CREATING A BI PUBLISHER DATASET 13521951 - BIP UPGRADE FROM 10G TO 11.1.1.5.0 IS NOT SUCCESSFULL FOR TIAA-CREF 13529494 - BI REPORT NOT GENERATED WHEN HTML CONTAINS INVALID ATTRIBUTES----------------------------- INSTALLATION FOR ENTERPRISE -----------------------------
SELECT NON EMPTY Hierarchize([Product].Generations(3).Members) ON Axis(0), Hierarchize(Union([Market].Generations(3).Members, [Market].Generations(4).Members, ALL)) ON Axis(1) FROM Demo.BasicIt should be written using a With Set member:
with set [UnionMarket] as '{Union([Market].Generations(3).Members, [Market].Generations(4).Members, ALL)}'
SELECT
NON EMPTY Hierarchize([Product].Generations(3).Members) ON Axis(0),
Hierarchize(([UnionMarket]) ON Axis(1)
FROM Demo.Basic
This MDX set is recreated for the Join clause to:
with set [UnionMarket] as '{Union([Market].Generations(3).Members, [Market].Generations(4).Members, ALL)}'
SELECT
NON EMPTY Hierarchize([Product].Generations(3).Members) ON Axis(0),
Hierarchize(Filter([UnionMarket], [Market].CurrentMember.Member_Name = "Boston")) ON Axis(1)
FROM Demo.Basic
-----------------------------------------
Query Builder limitation with Microsoft SQL Server
-----------------------------------------
<?xml version="1.0" encoding="UTF-8"?> <RTECODE> <![CDATA[ <font style="font-style: italic; font-weight: bold;" size="3"><a href="http://www.oracle.com">oracle</a></font> <br/> <font size="6"><a href="www.oracle.com">www.oracle.com</a></font><br/><br/> ]]> </RTECODE>
<?html2fo:RTECODE?>Supported html formats: Paragraph Font style ( bold, italic, plain, underline, subscript, superscript and strikes-through) Font size Font family Background color Foreground color Paragraph alignment (center, left, right and justify) Paragraph indent URL link List Bullet List Number List Non-Supported formats: Nested List (List with Indent) Some HTML tags/attributes which manually inserted like Table, Image, etc... in stead of HTML editor Sample Report: XML: html_test.xml RTF tempalte: html_test.rtf
Whether you build dashboards using OBIEE, Cognos or SAP Business Objects, it is always a pain to build quick dashboard prototypes to demonstrate users and build project momentum.
Project Momentum is very important in predicting the outcome of your new project proposal.
Before the client approaches you for a quote and a POC they have definitely done some internal research and probably installed the basic setup. So why waste time in demonstrating the same packaged OBIEE stuff which your client has already done it by visiting various blogs and updates on the web.
What is so unique that you can demonstrate?
This is something that will catch your client’s attention among heaps of other consultant companies.
But producing them is time consuming with the toolset itself.
So why not just build some cool wireframes and prototypes and send your unique approach to your potential client?
This is so easy. Just login to https://www.wireframes.org and build your dashboard prototype, add some cool visualization, comments and demonstrate how different your dashboard can be.
For e.g OBIEE is fully web based and using jquery and various plugins it is possible to completely blow the minds of everyone when you demonstrate something so cool done in OBIEE which no one has ever dared to do it till now.
Good tidings for the season to all of you. Its been erratic I know but we have stumbled along this year ...
I have been working with Eric, a Siebel sales consultant whiz on the BIP integration. He shared some really useful tips with a Siebel-BIP customer yesterday which I thought were well worth sharing.
Date Formatting
Firstly, some help with formatting dates when you are using a Siebel integration objects to generate the data. Siebel IOs do not generate the XSD date format that BIP needs to let you format dates to your hearts content. Attached are a couple files that provide some examples on how to manipulate dates to get the desired formats. Some are easy to get working and some need a little effort.
MSWord Plugin Testing
Siebel development have shipped some Siebel-BIP functions that are deployed to the server. However, to be able to test them locally on your desktop you need to get the java libraries into your classpath prior to starting MSWord. Here is the code Eric uses for starting Word with the Siebel classes in a batch
file. It assumes that the jar files are available locally on the client machine
at C:\811DQSSIA\Client\CLASSES. This will make the classes used by some
Siebel report templates available to test directly in Word. I have two
versions, one for Word 2003 and one for Word 2007.
Word 2003:
echo %1
set _JAVA_OPTIONS=-Xbootclasspath/a:C:\811DQSSIA\Client\CLASSES\SiebelXMLP.jar;C:\811DQSSIA\Client\CLASSES\XMLP.jar;C:\811DQSSIA\Client\CLASSES\Siebel.jar;C:\811DQSSIA\Client\CLASSES\XSLFunctions.jar;C:\811DQSSIA\Client\CLASSES\SiebelCustomXMLP.jar;C:\811DQSSIA\Client\CLASSES\SiebelCustomXMLP_SIA.jar;
"C:\Program Files\Microsoft Office\Office12\Winword.exe" %1
Word 2007:
echo %1
set _JAVA_OPTIONS=-Xbootclasspath/a:C:\811DQSSIA\Client\CLASSES\SiebelXMLP.jar;C:\811DQSSIA\Client\CLASSES\XMLP.jar;C:\811DQSSIA\Client\CLASSES\Siebel.jar;C:\811DQSSIA\Client\CLASSES\XSLFunctions.jar;C:\811DQSSIA\Client\CLASSES\SiebelCustomXMLP.jar;C:\811DQSSIA\Client\CLASSES\SiebelCustomXMLP_SIA.jar;
"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Office\Microsoft Office Word 2007.lnk" %1
Happy Holidays!
As many of you have found out, everything is not as it seems with the Excel output that gets generated from an RTF template. It has non-Excel like limitations and the files are quite big. Those of you using Excel 2007 will have noticed another niggle. When you open an 'Excel' output you get a warning along the lines of:
The file you are trying to open, '*.XLS', is in a different format than specified by the file extension. Verify that the file is not corrupted and is from a trusted source before opening the file. Do you want to open the file now?
This is down to BIP actually generating HTML and setting the mime type and extension to get Excel to open it. This is the cause of the limitations and the cause of the warnings. The limitations can be addressed by using an Excel template more on those in the user docs and elsewhere in this blog. Addressing the warning is going to require a modification to your users' registries.
Huge thanks to Abhishek Gupta for digging up a note from Oracle Support on it and thanks to whoever wrote the original. The note number is 1077728.1. I have uploaded Abhishek's snippet form the note here.
Update: Leslie has reminded me; for she is my Jimney Cricket to my Pinocchio, constantly prodding my conscious :0)
As an additional option in 11.1.1.5 Excel 2007
is a new output type from RTF that generates .xlsx.
Excel 2007 is a new output type available for reports. When
selected,
BI Publisher generates the output in Excel XML format (.xlsx). If
you have Excel 2007 or later installed, this option provides the
best
preservation of layout and formatting.
As noted in the comments, the Excel templates generate binary xls output not xlsx format and therefore have xls limitations in their abilities.
Latest and greatest from the boys and girls at the coal face for December. Bug fixes and some interesting enhancements that I hope to dig into to here soon.
Search for patch 13366758: UPDATE FOR BI PUBLISHER ENTERPRISE 11.1.1.5.0 DECEMBER 2011 on Oracle Support. Make sure you check out the readme for patch installation instructions.
9102877 - QA: QUERY BUILDER GENERATES INCORRECT SQL FOR MANY DBS 10402890 - SETTINGS FROM "DELIVERY CONFIGURATION" PAGE NOT BEING HONORED WHEN REPORTS RUN 11725468 - ER: RTE HTML SUPPORT IN DATA XML 11828672 - QA: INCORRECT INACTIVE WARNING MESSAGE 11835845 - 11G SQL DATA SET CREATION ORA-01756 ERROR BECAUSE COLON IS READ AS BIND VARIABLE 11850902 - SHARE REPORT LINK "NO PARAMETERS" AND "DOCUMENT ONLY" RENDER INCORRECTLY 11870449 - BI PUBLISHER XDOXSLT:SDIV() FUNCTION RESULTS NOT CORRECT 12312539 - QA: REPORT VIEWER SCREEN FREEZES FOR A FLEX REPORT WHEN SESSION EXPIRES 12376386 - REMOVETEMPLATEFORREPORT API DOESN'T REMOVE TEMPLATE 12405904 - CANNOT DEPLOY BIP WHEN DEPLOYMENT PATH INCLUDES SPACE CHARACTERS 12406034 - CANNOT USE JAVA DB - DERBY - FOR SCHEDULER DATABASE 12588342 - DELETEOBJECT RANDOM FAILURE 12595931 - WHEN PRINTING CHARTS TO PDF, NUMBERS BECOME ARABIC NUMBERS 12615821 - MISSING MEMBERS ON THE XML GENERATED BY BIP 12634030 - RE-PACKAGING MLR#11893189 TO XDOPARSER11G.JAR 12646493 - ORA-22902 CURSOR EXPRESSION NOT ALLOWED 12666066 - ER: EXCEL 2007 SUPPORT IN REST API 12705244 - JOINED MDX DATA SETS DO NOT PRODUCE CORRECT DATA - DATA MISSING 12726163 - NUMBER OF SESSIONS INCREASES AFTER RUNNING SCHEDULED JOBS 12737670 - GROUP BY FOR MDX DATA SET MISSING IN 11.1.1.5 - WAS PRESENT IN 11.1.1.3 12741858 - BI ASNWERS ANALYSIS IMPLEMENTING CASE WHEN STATEMENTS CAN NOT BE CONSUMED IN BIP 12750192 - ER: GENERATE NATIVE COMBINATION DUAL Y GRAPH IN PPTX OUTPUT FROM RTF AND XPT 12766932 - VERTICAL DUAL Y COMBO CHART MISSING SETTINGS TO ASSIGN VALUES TO AXIS 12775400 - DBFW:GENERATING IN XLXS OUTPUT IS THROWING AN ERROR 12822514 - SQL WITH CLAUSE - DATASET DOESN'T WORK (AND DIAGNOSTIC ISN'T HELPFUL) 12828845 - ISSUE WITH XDO_USER_NAME PARAMETER ON BIP 11.1.1.5.0 12835431 - INTRANSIT VALUATION REPORT QUERY GIVING ERROR IN EDITOR 12847306 - BI PUBLISHER DATA SET - WON'T SAVE 12872831 - EXCEL TEMPLATES GENERATING INCORRECT RESULTS FROM NESTED GROUPS 12879801 - ALLOW SAVING DATA MODEL WITH SPECIAL CHARACTER 12945367 - NOT ABLE TO EDIT DATA MODEL WHEN LINKS EXIT AMONG DATA SETS 12945475 - IE: NOT ABLE TO EDIT DATA MODEL WITH MANY DATA SET AND LINKS 12956901 - IN SQL SERVER CLOB IN DATA MODEL UI MARKED AS STRING DATA TYPE 12956915 - INCORRECT DATA WHEN PROCESSING OF CLOB COLUMNS FOR SQLSERVER 12956934 - DATA MODEL SHOULD RESPECT CASE SENSITIVITY FOR COLUMN AND TABLE NAMES 12972559 - XML DATA FILE TRUNCATED 12972852 - DYNAMIC IMAGES BROKEN FOR FO/PDF 12989467 - NEED TO CONVERT DOCUMENT FORMAT "EXCEL" TO "EXCEL2000" 13005659 - PSR:PERF:BIP:POOR PERF ACCESSING CATALOG FOLDER IN BIP 11G WITH SECURITY ENABLED 13007341 - DISPLAY ISSUES IN PARAMETER TAB OF OBI PUBLISHER 11G 13095050 - STRESS: OUTOFMEMORY ERRORS WITH VIEW REPORT STRESS 13100021 - BI PUBLISHER: QUERY BUILDER RESULTS RETURN COLUMN TYPE (APPEARS) INSTEAD VALUE 13100220 - HOW TO USE 11.1.1.5 WITH THE IDENTITY ASSERTER 13250009 - FOR METADATA LOGICAL SQL BIND WITH DUMMY VALUES INSTEAD OF NULL 13321449 - RESOURCELIMITEXCEPTION DURING ANY OPS THAT USE JNDI DATA SOURCE 13346737 - MULTIPLE VALUES IN A DASHBOARD PROMPT DOESN'T WORK WITH BI PUBLISHER INTEGRATED 13351305 - QUERY BUILDER DOES NOT BUILD CORRECT SYNTAX FOR SQL SERVER 13421264 - ADDING PARAMETER TO SQL BI SERVER DATA SET CORRUPTS DATA MODEL
Enjoy!
I have written about sub templates in the past on a few occasions; the principle behind them is pretty simple. If you have common report components that can be shared across reports; be they blocks of text like standard contract clauses or maybe some common calculation or function, drop them into a sub template and share the love. Develop once, use everywhere!
A colleague was recently tasked with conditionally bringing into a report output, paragraphs of static text based on some user preferences. That’s an ideal candidate for a sub template approach; drop all of the paragraphs in to an RTF subtemplate and then just conditionally pull them in based on some boolean expressions.
You might, quite naturally think about conditionally importing a series of sub templates rather than defining one, with all the content. However, XSL does not allow the conditional import of sub templates so you must take the single template approach. You can of course, import multiple sub templates if you have a lot of content to bring in but in most cases I would expect a single sub template will suffice.
BIP does need to know what those paragraphs need to be for each user whether that’s as a set of parameter values or a data element in the incoming data set. For this example I have used both approaches and they work all flavors of BIP. Implementation of the sub template onto the servers is going to be a little different but the main principle is the same. I have mercilessly ripped out a nice graphic from Leslie’s (doc writer extraordinaire) documentation.
This is for the 11g version that supports loading sub templates into the report catalog as objects. They can then be referenced in your main template using the import statement:
<?import:xdoxsl:///subtemplatefolder/subtemplatename.xsb?>
The subtemplate folder is going to be from the /SharedFolders or /My Folders root. For instance, I have a sub template ‘paragraphs’ loaded into a ‘test’ folder under Shared Folders. The import statement in my main template is ‘<?import:xdoxsl:///Test/ParaSubTemplate.xsb?>’
Update from Leslie
For those of you testing using your own My Folder area. The syn tax is
<?import:xdoxsl:///~username/path to subtemplate.xsb?> where username is your user name. For example: <?import:xdoxsl:///~tdexter/Subtemplates/Template1.xsb?>
Recommend you move them into the shared folder area in production.
For 10g you will either need to drop them into an accessible directory and use the file URI or mount them into the web server directory structure and access them via an http URI. I normally mount them in a directory under the ‘xmlpserver’ directory e.g J2EE_HOME\applications\xmlpserver\xmlpserver\subtemplates, a template is then accessible via the URI ‘http://server:port/subtemplates/template.rtf’
Make sure you set the Allow External References property to true for the report so that the sub template can be accessed.
The actual content of the sub template is pretty straight forward. It’s a series of paragraphs bounded by the ‘template’ command e.g.
<?template:para1?> … … <?end template?> <?template:para2?> … … <?end template?> <?template:para3?> … … <?end template?>Now we have the dynamic content defined it’s a case of conditionally bringing it into the main template. For this example I have demonstrated two approaches; both rely on the required paragraph information to be in the main dataset:
This means creating the parameters and ensuring that you have set the property on the data model to include the parameter values in the XML result set.
<?if:.//PARA1='1'?><?call:para1?><?end if?>
2. Including a value in the data to define what paragraphs should be included. If you have stored what paragraphs should be included for a given entity i.e. customer, supplier, employee, etc. Then you can extract those values into the data set and test for them. For this demo I have a 5 character set of ‘1’s and ‘0’s to represent the paragraphs that need to be included e.g. 10110. I just use a substring command to find out if a particular paragraph needs to be included.
<?if:substring(.//PARAS,1,1)='1'?><?call:para1?><?end if?>
Where PARAS is the element holding the ‘1’s and ‘0’s string to be parsed.
You can of course use some other means of marking whether a paragraph needs to be included or not. It’s just a case of parsing out the values with a substring or similar command.
You should be able to generate dynamic content such as this:

Notice that I have rendered the code so that I can see that the paragraphs are coming in i.e 10001 means we get paragraphs 1 and 5. I have built out demo files for the second method, available here.
It's Friday, that means its patch release time. Why do we do this to ourselves, 'we'll release on Friday!' It might 11.59 on Friday but by golly we'll have released on Friday. I can remember a release of BIP years ago that for some reason we went for 12/31 as a release date ... were we mad? I seem to remember we made it but talk about ridiculous pressure!
The latest 10g rollup is out in the wild and available from Oracle support. A bug fixing rollup but worth getting to and know that support will want you to get to it and re-test before going forward on an SR. One simple but very useful fix or enhancement:
[Cause of the bug]
I told a group of customers once that they have a headache and we have a non-steroidal anti-inflammatory drug, alright, I actually said 'aspirin'. This little gem of a fix helps relieve another little headache that our aspirin was causing. The patch number for all this BIP pain killing is 13399232, enjoy!
Couple of inquiries this week around the default timeout for BIP 11g installs and being able to change it. Its not currently documented (Leslie is working on that :) and when you see what you need to do you might understand why. It's ugly, very ugly but in the interest of getting the information out there, here we go.
The BIP session timeout is controlled in a section in the web.xml file under the WEB-INF directory.
<session-config>
<session-timeout>30</session-timeout>
</session-config>
The weblogic server (WLS) has a couple of features that are one, a pain and two useful. The first is the inability to update the web application's web.xml and have the changes take effect when you restart WLS. So far in my web diggings, I have found that you have to completely delete the application from WLS, update the web.xml and then re-deploy it with your new settings. Here's the steps:
It's messy I know but it works. Now, some of you may have found the page in the WLS console application that allows you to set a session timeout. Naturally, you'd think this would work if you changed it (that's the other feature of WLS that is useful.) The web.xml setting however, takes precedence over the WLS setting.
I have not tried this yet but I have been told that, if you remove the session-config section from the web.xml file and then redeploy BIP, the WLS setting will be respected. It's gotta be a better way to manage sessions. Just remember that until the development team either provide a better way to do it or remove the default time out in the web.xml file you are going to have to maintain your timeout method if you patch or upgrade.
Couple of inquiries this week around the default timeout for BIP 11g installs and being able to change it. Its not currently documented (Leslie is working on that :) and when you see what you need to do you might understand why. It's ugly, very ugly but in the interest of getting the information out there, here we go.
The BIP session timeout is controlled in a section in the web.xml file under the WEB-INF directory.
<session-config>
<session-timeout>30</session-timeout>
</session-config>
The weblogic server (WLS) has a couple of features that are one, a pain and two useful. The first is the inability to update the web application's web.xml and have the changes take effect when you restart WLS. So far in my web diggings, I have found that you have to completely delete the application from WLS, update the web.xml and then re-deploy it with your new settings. Here's the steps:
It's messy I know but it works. Now, some of you may have found the page in the WLS console application that allows you to set a session timeout. Naturally, you'd think this would work if you changed it (that's the other feature of WLS that is useful.) The web.xml setting however, takes precedence over the WLS setting.
I have not tried this yet but I have been told that, if you remove the session-config section from the web.xml file and then redeploy BIP, the WLS setting will be respected. It's gotta be a better way to manage sessions. Just remember that until the development team either provide a better way to do it or remove the default time out in the web.xml file you are going to have to maintain your timeout method if you patch or upgrade.
A week off trying to catch up with all the stuff that builds up was not enough but it was pretty fruitful. You clear the decks the week before you leave, you even answer a few mails in the first few days of vacation, until your manager slaps your wrists. But there is always a pile of work waiting when you get back. It was not too bad this time; I at least deleted the crap mail during the week via my phone.
How the heck did we survive without smart phones? I took a trip to north Denver last week to pick up a part for our bear ravaged pop up camper. I think he wanted a cold beer from the fridge just wish he'd used the front door rather than slicing the camper open. That gaping hole is meant to be covered!
I guess I could have checked a map before we left but my phone got us through the mess of roads up there. An 80 mile round trip for a $10 louvered cover! Still, we found a great Indian place for lunch, delicious curry!
Today's tidbit (titbit for my British brethren) is a bit tough to describe. It comes from Charlotte in New Zealand. On the surface it looks simple and it is when you know how :0) But there's a wrinkle in to smooth out.
Here's the data:
<DATA_DS> <G_1> <SERIALNUMBER>HSS0000156</SERIALNUMBER> <LOCATION>1 The Street Anytown USA</LOCATION> <ATTRIBDESC>Lettable Date</ATTRIBDESC> <ATTRIBVALUE>15/JUN/11</ATTRIBVALUE> </G_1> <G_1> <SERIALNUMBER>HSS0000156</SERIALNUMBER> <LOCATION>1 The Street Anytown USA</LOCATION> <ATTRIBDESC>Status Reason</ATTRIBDESC> <ATTRIBVALUE>Planned Major Repair/Upgrade</ATTRIBVALUE> </G_1> <G_1> <SERIALNUMBER>HSS0000276</SERIALNUMBER> <LOCATION>11 The Street Anytown USA</LOCATION> <ATTRIBDESC>Lettable Date</ATTRIBDESC> <ATTRIBVALUE>18/MAY/11</ATTRIBVALUE> </G_1> <G_1> <SERIALNUMBER>HSS0000276</SERIALNUMBER> <LOCATION>11 The Street Anytown USA</LOCATION> <ATTRIBDESC>Status Reason</ATTRIBDESC> <ATTRIBVALUE>Planned Major Repair/Upgrade</ATTRIBVALUE> </G_1> <G_1> <SERIALNUMBER>HSS0001046</SERIALNUMBER> <LOCATION>21 The Street Anytown USA</LOCATION> <ATTRIBDESC>Lettable Date</ATTRIBDESC> <ATTRIBVALUE>21/JUN/11</ATTRIBVALUE> </G_1> <G_1>Heres the desired output:
| Serialnumber | Status Reason | Date |
| HSS0000156 | Planned Major Repair/Upgrade | 15/JUN/11 |
| HSS0000276 | Planned Major Repair/Upgrade | 18/MAY/11 |
| HSS0001046 | Planned Major Repair/Upgrade | 21/JUN/11 |
| HSS0001303 | Planned Major Repair/Upgrade | 19/MAY/11 |
| HSS0001403 | Planned Major Repair/Upgrade | 14/JUN/11 |
Hok-Min, Zen Master of the RTF template, jumped on this for me and nailed it first time. On first look you think, ah this is just a simple re-group left, using some xpath to repeat the ATTRIBVALUE element twice in the table based on the ATTRIBDESC. Along the lines of:
<?ATTRIBVALUE[../ATTRIBDESC='Planned Major Repair/Upgrade']?> and <?ATTRIBVALUE[../ATTRIBDESC='Lettable Date']?>
But you oh so very easily end up with this:
| Serialnumber | Status Reason | Date |
| HSS0000156 | 15/JUN/11 | |
| Planned Major Repair/Upgrade | ||
| HSS0000276 | 18/MAY/11 | |
| Planned Major Repair/Upgrade | ||
| HSS0001046 | 21/JUN/11 | |
| Planned Major Repair/Upgrade | ||
| HSS0001303 | 19/MAY/11 | |
| Planned Major Repair/Upgrade | ||
| HSS0001403 | 14/JUN/11 | |
| Planned Major Repair/Upgrade |
and start scratching your head? With the 10.1.3.4.1 and 11g template builders there is a nice Group Left feature that removes the need for nasty nested tables but for this slightly corner case, it drops you into a world of misery. You need to take a step back from what the wizard has given you.
Yes, you need to group by serial number but you do not need to loop over the remaining data (current-group().) Rather, you just need to drop into that current-group() and bring the values you need up to the level of the serial number group. So you just need to modify your XPATHs thus:
<?current-group()/ATTRIBVALUE[../ATTRIBDESC='Status Reason']?>
i.e. provide a complete path to the element you want within the serial number re-group level. Neat!
Template and sample data available here.
A week off trying to catch up with all the stuff that builds up was not enough but it was pretty fruitful. You clear the decks the week before you leave, you even answer a few mails in the first few days of vacation, until your manager slaps your wrists. But there is always a pile of work waiting when you get back. It was not too bad this time; I at least deleted the crap mail during the week via my phone.
How the heck did we survive without smart phones? I took a trip to north Denver last week to pick up a part for our bear ravaged pop up camper. I think he wanted a cold beer from the fridge just wish he'd used the front door rather than slicing the camper open. That gaping hole is meant to be covered!
I guess I could have checked a map before we left but my phone got us through the mess of roads up there. An 80 mile round trip for a $10 louvered cover! Still, we found a great Indian place for lunch, delicious curry!
Today's tidbit (titbit for my British brethren) is a bit tough to describe. It comes from Charlotte in New Zealand. On the surface it looks simple and it is when you know how :0) But there's a wrinkle in to smooth out.
Here's the data:
<DATA_DS> <G_1> <SERIALNUMBER>HSS0000156</SERIALNUMBER> <LOCATION>1 The Street Anytown USA</LOCATION> <ATTRIBDESC>Lettable Date</ATTRIBDESC> <ATTRIBVALUE>15/JUN/11</ATTRIBVALUE> </G_1> <G_1> <SERIALNUMBER>HSS0000156</SERIALNUMBER> <LOCATION>1 The Street Anytown USA</LOCATION> <ATTRIBDESC>Status Reason</ATTRIBDESC> <ATTRIBVALUE>Planned Major Repair/Upgrade</ATTRIBVALUE> </G_1> <G_1> <SERIALNUMBER>HSS0000276</SERIALNUMBER> <LOCATION>11 The Street Anytown USA</LOCATION> <ATTRIBDESC>Lettable Date</ATTRIBDESC> <ATTRIBVALUE>18/MAY/11</ATTRIBVALUE> </G_1> <G_1> <SERIALNUMBER>HSS0000276</SERIALNUMBER> <LOCATION>11 The Street Anytown USA</LOCATION> <ATTRIBDESC>Status Reason</ATTRIBDESC> <ATTRIBVALUE>Planned Major Repair/Upgrade</ATTRIBVALUE> </G_1> <G_1> <SERIALNUMBER>HSS0001046</SERIALNUMBER> <LOCATION>21 The Street Anytown USA</LOCATION> <ATTRIBDESC>Lettable Date</ATTRIBDESC> <ATTRIBVALUE>21/JUN/11</ATTRIBVALUE> </G_1> <G_1>Heres the desired output:
| Serialnumber | Status Reason | Date |
| HSS0000156 | Planned Major Repair/Upgrade | 15/JUN/11 |
| HSS0000276 | Planned Major Repair/Upgrade | 18/MAY/11 |
| HSS0001046 | Planned Major Repair/Upgrade | 21/JUN/11 |
| HSS0001303 | Planned Major Repair/Upgrade | 19/MAY/11 |
| HSS0001403 | Planned Major Repair/Upgrade | 14/JUN/11 |
Hok-Min, Zen Master of the RTF template, jumped on this for me and nailed it first time. On first look you think, ah this is just a simple re-group left, using some xpath to repeat the ATTRIBVALUE element twice in the table based on the ATTRIBDESC. Along the lines of:
<?ATTRIBVALUE[../ATTRIBDESC='Planned Major Repair/Upgrade']?> and <?ATTRIBVALUE[../ATTRIBDESC='Lettable Date']?>
But you oh so very easily end up with this:
| Serialnumber | Status Reason | Date |
| HSS0000156 | 15/JUN/11 | |
| Planned Major Repair/Upgrade | ||
| HSS0000276 | 18/MAY/11 | |
| Planned Major Repair/Upgrade | ||
| HSS0001046 | 21/JUN/11 | |
| Planned Major Repair/Upgrade | ||
| HSS0001303 | 19/MAY/11 | |
| Planned Major Repair/Upgrade | ||
| HSS0001403 | 14/JUN/11 | |
| Planned Major Repair/Upgrade |
and start scratching your head? With the 10.1.3.4.1 and 11g template builders there is a nice Group Left feature that removes the need for nasty nested tables but for this slightly corner case, it drops you into a world of misery. You need to take a step back from what the wizard has given you.
Yes, you need to group by serial number but you do not need to loop over the remaining data (current-group().) Rather, you just need to drop into that current-group() and bring the values you need up to the level of the serial number group. So you just need to modify your XPATHs thus:
<?current-group()/ATTRIBVALUE[../ATTRIBDESC='Status Reason']?>
i.e. provide a complete path to the element you want within the serial number re-group level. Neat!
Template and sample data available here.
?MockupTiger Personal Edition? is an excellent way of doing wireframes in the browser without the heavy baggage of server or database.
Our Enterprise edition comes with complete user management system and uses MySQL database to maintain all the information. It also needs a webserver to operate.
MockupTiger Personal Edition is an extremely innovative way of delivering the same experience without the need of a webserver and a database system.
How is that possible?
Here is what we did
What are the benefits?
Get MockupTiger license Mockuptiger Personal Edition
Download MockupTiger Wireframes. It is the best time saving application you will download for prototyping
Mockuptiger allows you to create any number of groups. Each member of your team can create their own groups. Groups is like the “Circles” feature in Google plus.
Groups can represent full company, it can represent individual small teams, it can represent individual clients of a web design agency or a small department of a big company
. It is a simple and very powerful concept. This power is available when you use Mockuptiger to build your wireframes and prototypes.
Groups is a very powerful and simple concept. If you are a web agency then every client and members working for them is part of a small group. ?ClientA group? and ?ClientB group?.
If you are a big organization then each small team can be a group ?Web design group?, ?Software Development Group? and so on.
A group is like an umbrella, you can add users to the group and users can share their projects to the group. So now every member of the group can see all the projects in the group. Project access is tightly controlled through the dashboard.
Each user can create groups
Each user can add members to its own groups
Each user in the group can share their own projects to the group
Each user who shares their project can control the Editor and viewership of their own content
Every user in the group can atleast view each and every project in the group
Not every user can edit the projects and pages in the group
You can now share your documents to public by simply providing the link.
Clickable wireframes allows for unique presentation ways of mockups to your clients
http://www.mockuptiger.com/wireframe/mockups/mt.php?pa=dashboard_sample_4e5bbfcf3d57f
See, how easy it is!
But wait, sharing the URL does not mean you lose control over it. You need to make the document public through the dashboard. And yes, once public you can always revoke the public access.
Read more about Group and project management for wireframe and prototyping
The dust has finally settled at the Moscone Center.
I hope everyone had a wonderful time at Open World.
For those of you who would like copies of the presentations we made, as promised, they are now available on the Publisher OTN page. Here are direct links:
Create All Your Reports More Easily and Quickly with Oracle Business Intelligence Publisher (14982)
Oracle Business Intelligence Publisher: The Reporting Platform for Oracle Applications (12426)
Become a Reporting Superstar with Oracle Business Intelligence Publisher Best Practices (16762)
Oracle Business Intelligence Publisher: Anatomy of an RTF Template (15010)
Still to come: Hands On Lab exercises and an updated RTF Template that goes along with Anatomy of a Template.
The dust has finally settled at the Moscone Center.
I hope everyone had a wonderful time at Open World.
For those of you who would like copies of the presentations we made, as promised, they are now available on the Publisher OTN page. Here are direct links:
Create All Your Reports More Easily and Quickly with Oracle Business Intelligence Publisher (14982)
Oracle Business Intelligence Publisher: The Reporting Platform for Oracle Applications (12426)
Become a Reporting Superstar with Oracle Business Intelligence Publisher Best Practices (16762)
Oracle Business Intelligence Publisher: Anatomy of an RTF Template (15010)
Still to come: Hands On Lab exercises and an updated RTF Template that goes along with Anatomy of a Template.
Dang folks, we're on part four already, things start to get really groovy now.
If you're jumping in at part four, here are the previous episodes:
The current approach to get the maps into the output using encoded concatenated URL strings works but if you need to make changes to the map request call it gets fiddly and annoying quite quickly and if you need to drop another map into another output you'll need to embed the code into the second RTF template. What if we could simplify all of this and create a 'map request broker' that sat between the template and the map server? Even better if that broker could handle any map request and support as many layout templates that I want. I have just the solution built and ready to roll.

Of course all three components might be running on the same physical server inside the same weblogic domain. Its a pretty simple concept and it makes life so much easier when embedding a map into an output. The servlet is called from the RTF template using a URL that is constructed on the fly; we can also pass parameters on the URL to influence the map. For my example those parameters include the mapviewer server and port (to make the template portable) the map title, what needs to be mapped and the map request file to be used. The servlet receives the request grabs the parameters off the URL. It then reads the map request files and substitutes the appropriate variable values and then makes the call to mapviewer requesting a map. Once it receives the map it streams the image back to the template for rendering by BI Publisher. No messy encoded URL's minimal concatenation in the template to create the servlet URL and I have fine control over the map request. Best of all any template can call the same servlet, we just need the base map request on the server.
The Breakdown
There are three components to consider, what's in the RTF template the servlet code and the map request. Lets look at the map request first.
<?xml version="1.0" encoding="UTF-8"?> <map_request title="param1" basemap="world_map" datasource = "obiee_navteq_sample" width="640" height="480" bgcolor="#a6cae0" antialiase="false" format="param2"> <center size="45"> <geoFeature> <geometricProperty typeName="center"> <Point srsName="SDO:8307"> <coordinates>-96, 34</coordinates> </Point> </geometricProperty> </geoFeature> </center> <legend bgstyle="fill:#ffffff;stroke:#ff0000" profile="MEDIUM" position="SOUTH_WEST"> <column> <entry text="Number of Renal Disease Cases:"/> <entry style="V.POPULATION_COUNTY" tab="1"/> </column> </legend> <themes> <theme name="theme1" min_scale="5.0E7" max_scale="0.0"> <jdbc_query datasource="obiee_navteq_sample" jdbc_srid="8307" spatial_column="geometry" render_style="OBIEE_NAVTEQ:V.POPULATION_COUNTY"> SELECT geometry, param3 from obiee_state where iso_country_code='USA'</jdbc_query> </theme> </themes> </map_request>
Its just a well formed XML file. This has loads going on and to find out more you're going to have to hit the books - the mapviewer documentation is here - check out the XML API section for some samples. I was playing with it last night and found that the 'size' attribute under the 'center' element controls the zoom level ... go figure. But combining that with the 'coordinates' value under geoFeature and some nifty LOVs in your BIP report and folks can move around a map and zoom in and out. More on that later.
Testing your map requests is simple enough inside the mapviewer web console http://server:port/mapviewer >> Requests. Just copy, paste and submit.
The other features of note are my parameters highlighted in blue. Before I pass this request on to the mapviewer server I do a search and replace on the 3 parameters. You'll see that in the servlet code. Remember, this XML is not hard coded into the servlet, its a separate XML file in a 'resource' directory that is read by the servlet. Taking this approach I can re-use the servlet for multiple map requests.
Next, the servlet code, ready for my awesome java skills? Read on ...
package oracle.bipmapper;
//Read-write libs
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
//Handle the URL call
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
//Servlet libs
import javax.servlet.*;
import javax.servlet.http.*;
public class bipmap extends HttpServlet {
private String CONTENT_TYPE = "";
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
((1)) - Fetch the URL params. Check that we have values, if not, assign defaults.
String measure1 =
(request.getParameter("a1").toString() == "") ? "sqkm" :
request.getParameter("a1");
String server =
(request.getParameter("serv").toString() == "") ? "75.101.156.237" :
request.getParameter("serv");
String port =
(request.getParameter("port").toString() == "") ? "9704" :
request.getParameter("port");
String title =
(request.getParameter("title").toString() == "") ? "Default Title" :
request.getParameter("title");
String format =
(request.getParameter("format").toString() == "") ? "PNG_STREAM" :
request.getParameter("format");
String filename =
(request.getParameter("file").toString() == "") ? "mapreq.xml" :
request.getParameter("file") + ".xml";
// Needed objects for the mapviewer call
HttpURLConnection huc = null;
URL mapAddress = null;
((2)) Set the content format based on the format parameter value
// The else value is just text, thats for the SVG support
if (format == "PNG_STREAM") {
CONTENT_TYPE = "image/png";
} else if (format == "JPG_STREAM") {
CONTENT_TYPE = "image/jpg";
} else {
CONTENT_TYPE = "text/javascript";
}
response.setContentType(CONTENT_TYPE);
((3)) //Find the request file
ServletContext context = request.getSession().getServletContext();
String separator = System.getProperty("file.separator");
final String TMPDIR =
context.getAttribute("javax.servlet.context.tempdir").toString();
// With WLS the tempdir drops you into the _WL_user/APP_NAME/RANDOM_DIR/public
// we need the 'war' directory to find the resource directory
String reqFile =
TMPDIR.substring(0, TMPDIR.lastIndexOf(separator)) + "/war/resource/" +
filename;
((4))// Construct the start of the URL map request
String mapURL =
"http://" + server + ":" + port + "/mapviewer/omserver?xml_request=";
((5)) // Load the XML request file
String xmlReq = getMapReq(reqFile);
((6)) // Look for a replace the parameters in the XML request.
xmlReq = xmlReq.replace("param1", title);
xmlReq = xmlReq.replace("param2", format);
xmlReq = xmlReq.replace("param3", measure1);
InputStream is = null;
((7)) // Fetch the output stream from the mapviewer request
try {
mapAddress = new URL(mapURL + URLEncoder.encode(xmlReq));
huc = (HttpURLConnection)mapAddress.openConnection();
huc.setDoOutput(true);
huc.setDoInput(true);
huc.setUseCaches(false);
huc.setRequestMethod("POST"); //Use HTTP POST method.
is = huc.getInputStream();
// Write the image stream back to the caller ie BIP in the template layer
OutputStream out = response.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = is.read(buf)) >= 0) {
out.write(buf, 0, len);
}
is.close();
out.close();
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(1);
}
}
private static String getMapReq(String fname) throws java.io.IOException {
((5.5)) // Fetch the XML request file and load it into a string object
byte[] buffer = new byte[(int)new File(fname).length()];
BufferedInputStream f = null;
try {
f = new BufferedInputStream(new FileInputStream(fname));
f.read(buffer);
} finally {
if (f != null)
try {
f.close();
} catch (IOException ignored) {
}
}
return new String(buffer);
}
}
I have highlighted the important bits:
(1) Standard stuff here, pulling the parameters off the URL and assigning them to string variables. For the un-initiated each entry is an inline if statement.
(2) Im checking the requested output so that I can set the appropriate content type. In my example Im supporting PNG, JPG and SVG. The SVG is handled in the else condition. More on that in another post.
(3) Here I fetch the request XML file. Its in a 'resource' directory in the deployment. This was a bit of a pain, I expected the 'javax.servlet.context.tempdir' to return he root of the web application but in weblogic you end up in a 'public' directory under the root. My resource directory is actually under the 'war' directory under the root so this piece of code:
ServletContext context = request.getSession().getServletContext();
String separator = System.getProperty("file.separator");
final String TMPDIR = context.getAttribute("javax.servlet.context.tempdir").toString();
String reqFile =
TMPDIR.substring(0, TMPDIR.lastIndexOf(separator)) + "/war/resource/" +
filename;
does some substringing and concatentation to build a path to the correct directory. Im sure there is an easier way but it works for now. Note the user of the 'separator' string so that the servlet can be deployed to windblows, unix or linux. I had a devil of a time catching that one. I developed on Linux but it would not run on windblows until I grabbed the appropriate separator ... grrr!
(4) Starting to construct the URL request for the XML map request
(5) Fetching the map request XML from the file in the resource directory
(5.5) This is the function to read the map request file and load it int a string variable
(6) A simple replace for each of the parameters created in the map request. We could have gotten fancier here with an XML parser but its not a huge string and there are three replacements to do. Its not a slow process.
(7) Now we construct the full http request for the map. Note the encoding of the xml request string, thats a must. Once we get the result we just have the servlet write it back to the response object for BIP to render.
Nothing earth shattering, could it be better, sure, if you fail to pass enough parameters you get an ugly null pointer exception which could be handled better but just make sure you pass enough parameters :0)
Finally the RTF template, its a case of declaring parameters for the report parameters and then building the URL request to the servlet. You can see the fields in the graphic on the right. The only ones of note are:
Then just use the external-graphic place holder as we have before to reference the mURL parameter. The curly braces {} get BIP to pre-process the value before processing the graphic.
Finally ...
Thats it, put the three pieces together et voila, you have a mapping solution that's more manageable and configurable. You can of course increase the number of parameterized values in the xml map request.
I have bundled up the JDeveloper (11.1.1.5) project as it is ... its only really got the servlet and XML request in it. You can just copy and paste into your own project - get the project here. I have also zipped the 11g BIP report with the RTF template (Mapviewer4.rtf) get that here. For 10g'ers just unzip the xdoz file to get at the RTF template.
So, we can now get maps into our BIP outputs, the quality is pretty good but it could be better. Having spent some time digging around in the mapviewer docs I spotted that they support SVG outputs ... more on that next time.
Dang folks, we're on part four already, things start to get really groovy now.
If you're jumping in at part four, here are the previous episodes:
The current approach to get the maps into the output using encoded concatenated URL strings works but if you need to make changes to the map request call it gets fiddly and annoying quite quickly and if you need to drop another map into another output you'll need to embed the code into the second RTF template. What if we could simplify all of this and create a 'map request broker' that sat between the template and the map server? Even better if that broker could handle any map request and support as many layout templates that I want. I have just the solution built and ready to roll.

Of course all three components might be running on the same physical server inside the same weblogic domain. Its a pretty simple concept and it makes life so much easier when embedding a map into an output. The servlet is called from the RTF template using a URL that is constructed on the fly; we can also pass parameters on the URL to influence the map. For my example those parameters include the mapviewer server and port (to make the template portable) the map title, what needs to be mapped and the map request file to be used. The servlet receives the request grabs the parameters off the URL. It then reads the map request files and substitutes the appropriate variable values and then makes the call to mapviewer requesting a map. Once it receives the map it streams the image back to the template for rendering by BI Publisher. No messy encoded URL's minimal concatenation in the template to create the servlet URL and I have fine control over the map request. Best of all any template can call the same servlet, we just need the base map request on the server.
The Breakdown
There are three components to consider, what's in the RTF template the servlet code and the map request. Lets look at the map request first.
<?xml version="1.0" encoding="UTF-8"?> <map_request title="param1" basemap="world_map" datasource = "obiee_navteq_sample" width="640" height="480" bgcolor="#a6cae0" antialiase="false" format="param2"> <center size="45"> <geoFeature> <geometricProperty typeName="center"> <Point srsName="SDO:8307"> <coordinates>-96, 34</coordinates> </Point> </geometricProperty> </geoFeature> </center> <legend bgstyle="fill:#ffffff;stroke:#ff0000" profile="MEDIUM" position="SOUTH_WEST"> <column> <entry text="Number of Renal Disease Cases:"/> <entry style="V.POPULATION_COUNTY" tab="1"/> </column> </legend> <themes> <theme name="theme1" min_scale="5.0E7" max_scale="0.0"> <jdbc_query datasource="obiee_navteq_sample" jdbc_srid="8307" spatial_column="geometry" render_style="OBIEE_NAVTEQ:V.POPULATION_COUNTY"> SELECT geometry, param3 from obiee_state where iso_country_code='USA'</jdbc_query> </theme> </themes> </map_request>
Its just a well formed XML file. This has loads going on and to find out more you're going to have to hit the books - the mapviewer documentation is here - check out the XML API section for some samples. I was playing with it last night and found that the 'size' attribute under the 'center' element controls the zoom level ... go figure. But combining that with the 'coordinates' value under geoFeature and some nifty LOVs in your BIP report and folks can move around a map and zoom in and out. More on that later.
Testing your map requests is simple enough inside the mapviewer web console http://server:port/mapviewer >> Requests. Just copy, paste and submit.
The other features of note are my parameters highlighted in blue. Before I pass this request on to the mapviewer server I do a search and replace on the 3 parameters. You'll see that in the servlet code. Remember, this XML is not hard coded into the servlet, its a separate XML file in a 'resource' directory that is read by the servlet. Taking this approach I can re-use the servlet for multiple map requests.
Next, the servlet code, ready for my awesome java skills? Read on ...
package oracle.bipmapper;
//Read-write libs
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
//Handle the URL call
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
//Servlet libs
import javax.servlet.*;
import javax.servlet.http.*;
public class bipmap extends HttpServlet {
private String CONTENT_TYPE = "";
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
((1)) - Fetch the URL params. Check that we have values, if not, assign defaults.
String measure1 =
(request.getParameter("a1").toString() == "") ? "sqkm" :
request.getParameter("a1");
String server =
(request.getParameter("serv").toString() == "") ? "75.101.156.237" :
request.getParameter("serv");
String port =
(request.getParameter("port").toString() == "") ? "9704" :
request.getParameter("port");
String title =
(request.getParameter("title").toString() == "") ? "Default Title" :
request.getParameter("title");
String format =
(request.getParameter("format").toString() == "") ? "PNG_STREAM" :
request.getParameter("format");
String filename =
(request.getParameter("file").toString() == "") ? "mapreq.xml" :
request.getParameter("file") + ".xml";
// Needed objects for the mapviewer call
HttpURLConnection huc = null;
URL mapAddress = null;
((2)) Set the content format based on the format parameter value
// The else value is just text, thats for the SVG support
if (format == "PNG_STREAM") {
CONTENT_TYPE = "image/png";
} else if (format == "JPG_STREAM") {
CONTENT_TYPE = "image/jpg";
} else {
CONTENT_TYPE = "text/javascript";
}
response.setContentType(CONTENT_TYPE);
((3)) //Find the request file
ServletContext context = request.getSession().getServletContext();
String separator = System.getProperty("file.separator");
final String TMPDIR =
context.getAttribute("javax.servlet.context.tempdir").toString();
// With WLS the tempdir drops you into the _WL_user/APP_NAME/RANDOM_DIR/public
// we need the 'war' directory to find the resource directory
String reqFile =
TMPDIR.substring(0, TMPDIR.lastIndexOf(separator)) + "/war/resource/" +
filename;
((4))// Construct the start of the URL map request
String mapURL =
"http://" + server + ":" + port + "/mapviewer/omserver?xml_request=";
((5)) // Load the XML request file
String xmlReq = getMapReq(reqFile);
((6)) // Look for a replace the parameters in the XML request.
xmlReq = xmlReq.replace("param1", title);
xmlReq = xmlReq.replace("param2", format);
xmlReq = xmlReq.replace("param3", measure1);
InputStream is = null;
((7)) // Fetch the output stream from the mapviewer request
try {
mapAddress = new URL(mapURL + URLEncoder.encode(xmlReq));
huc = (HttpURLConnection)mapAddress.openConnection();
huc.setDoOutput(true);
huc.setDoInput(true);
huc.setUseCaches(false);
huc.setRequestMethod("POST"); //Use HTTP POST method.
is = huc.getInputStream();
// Write the image stream back to the caller ie BIP in the template layer
OutputStream out = response.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = is.read(buf)) >= 0) {
out.write(buf, 0, len);
}
is.close();
out.close();
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(1);
}
}
private static String getMapReq(String fname) throws java.io.IOException {
((5.5)) // Fetch the XML request file and load it into a string object
byte[] buffer = new byte[(int)new File(fname).length()];
BufferedInputStream f = null;
try {
f = new BufferedInputStream(new FileInputStream(fname));
f.read(buffer);
} finally {
if (f != null)
try {
f.close();
} catch (IOException ignored) {
}
}
return new String(buffer);
}
}
I have highlighted the important bits:
(1) Standard stuff here, pulling the parameters off the URL and assigning them to string variables. For the un-initiated each entry is an inline if statement.
(2) Im checking the requested output so that I can set the appropriate content type. In my example Im supporting PNG, JPG and SVG. The SVG is handled in the else condition. More on that in another post.
(3) Here I fetch the request XML file. Its in a 'resource' directory in the deployment. This was a bit of a pain, I expected the 'javax.servlet.context.tempdir' to return he root of the web application but in weblogic you end up in a 'public' directory under the root. My resource directory is actually under the 'war' directory under the root so this piece of code:
ServletContext context = request.getSession().getServletContext();
String separator = System.getProperty("file.separator");
final String TMPDIR = context.getAttribute("javax.servlet.context.tempdir").toString();
String reqFile =
TMPDIR.substring(0, TMPDIR.lastIndexOf(separator)) + "/war/resource/" +
filename;
does some substringing and concatentation to build a path to the correct directory. Im sure there is an easier way but it works for now. Note the user of the 'separator' string so that the servlet can be deployed to windblows, unix or linux. I had a devil of a time catching that one. I developed on Linux but it would not run on windblows until I grabbed the appropriate separator ... grrr!
(4) Starting to construct the URL request for the XML map request
(5) Fetching the map request XML from the file in the resource directory
(5.5) This is the function to read the map request file and load it int a string variable
(6) A simple replace for each of the parameters created in the map request. We could have gotten fancier here with an XML parser but its not a huge string and there are three replacements to do. Its not a slow process.
(7) Now we construct the full http request for the map. Note the encoding of the xml request string, thats a must. Once we get the result we just have the servlet write it back to the response object for BIP to render.
Nothing earth shattering, could it be better, sure, if you fail to pass enough parameters you get an ugly null pointer exception which could be handled better but just make sure you pass enough parameters :0)
Finally the RTF template, its a case of declaring parameters for the report parameters and then building the URL request to the servlet. You can see the fields in the graphic on the right. The only ones of note are:
Then just use the external-graphic place holder as we have before to reference the mURL parameter. The curly braces {} get BIP to pre-process the value before processing the graphic.
Finally ...
Thats it, put the three pieces together et voila, you have a mapping solution that's more manageable and configurable. You can of course increase the number of parameterized values in the xml map request.
I have bundled up the JDeveloper (11.1.1.5) project as it is ... its only really got the servlet and XML request in it. You can just copy and paste into your own project - get the project here. I have also zipped the 11g BIP report with the RTF template (Mapviewer4.rtf) get that here. For 10g'ers just unzip the xdoz file to get at the RTF template.
So, we can now get maps into our BIP outputs, the quality is pretty good but it could be better. Having spent some time digging around in the mapviewer docs I spotted that they support SVG outputs ... more on that next time.

This is the third installment of the BIP and Mapviewer Mashup, for the previous entries:
BIP and Mapviewer Mash Up III
Its been a hectic couple of weeks which has included all things mapviewer and integration. I have finally got my piece de resistance in mapping integration working but more on that next time. Its very cool in a geeky BIP, kinda way; my wife was completely fascinated when I told her all about it over dinner last night. Either that, or she has become very adept at nodding and saying 'that's nice honeycakes' at appropriate times. I hope the former but suspect the latter :0(
The next part of this mashup series, I said we would parameterize the map call. That's actually pretty easy to do, just a bit more effort with the parameters and the concat functions.
1. Set up your parameters in the data model. These do not have
to be tied to the query. We support 'template ' only parameters.
they just all have to be defined in the datamodel. Note the name
you give to the parameter(s)
2. In your RTF template you need to declare 'interest' in the
parameters. Its the same as the CURRENT_SERVER_URL format.
<?param@begin:name;defaultvalue?>
<xsl:param xdofo:ctx="begin" name="pMapRq">concat
("%3Cmap_request%20title%3D%22",$title,
"%20basemap%3D%22world_map%22%20datasource%20%3D%20%22
obiee_navteq_sample%22%20width%3D%22640%22%20height
%3D%22480%22%20bgcolor%3D%22%23a6cae0%22%20antialiase
%3D%22false%22%20format%3D%22JPG_STREAM%22%3E")
</xsl:param>
Its not tough but boy is it a bit of a nightmare to manage and keep track of everything in that encoded URL.
As I mentioned in my last post its a good idea to maintain the parts of the URL as un-encoded text in the template surrounded by an 'if:1=2' if statement to keep it hidden at runtime.
Next post, we get to a much more robust, easier to manage and as I mentioned cooler solution ... enter the mapping servlet. It acts as a map request broker between the BIP template and the mapviewer server. The RTF template is not full of encoded URLs but just a simple URL call to the servlet that will call the mapviewer server and stream the image back to BIP for rendering. I have built in a couple of tricks but more on that next time.

This is the third installment of the BIP and Mapviewer Mashup, for the previous entries:
BIP and Mapviewer Mash Up III
Its been a hectic couple of weeks which has included all things mapviewer and integration. I have finally got my piece de resistance in mapping integration working but more on that next time. Its very cool in a geeky BIP, kinda way; my wife was completely fascinated when I told her all about it over dinner last night. Either that, or she has become very adept at nodding and saying 'that's nice honeycakes' at appropriate times. I hope the former but suspect the latter :0(
The next part of this mashup series, I said we would parameterize the map call. That's actually pretty easy to do, just a bit more effort with the parameters and the concat functions.
1. Set up your parameters in the data model. These do not have
to be tied to the query. We support 'template ' only parameters.
they just all have to be defined in the datamodel. Note the name
you give to the parameter(s)
2. In your RTF template you need to declare 'interest' in the
parameters. Its the same as the CURRENT_SERVER_URL format.
<?param@begin:name;defaultvalue?>
<xsl:param xdofo:ctx="begin" name="pMapRq">concat
("%3Cmap_request%20title%3D%22",$title,
"%20basemap%3D%22world_map%22%20datasource%20%3D%20%22
obiee_navteq_sample%22%20width%3D%22640%22%20height
%3D%22480%22%20bgcolor%3D%22%23a6cae0%22%20antialiase
%3D%22false%22%20format%3D%22JPG_STREAM%22%3E")
</xsl:param>
Its not tough but boy is it a bit of a nightmare to manage and keep track of everything in that encoded URL.
As I mentioned in my last post its a good idea to maintain the parts of the URL as un-encoded text in the template surrounded by an 'if:1=2' if statement to keep it hidden at runtime.
Next post, we get to a much more robust, easier to manage and as I mentioned cooler solution ... enter the mapping servlet. It acts as a map request broker between the BIP template and the mapviewer server. The RTF template is not full of encoded URLs but just a simple URL call to the servlet that will call the mapviewer server and stream the image back to BIP for rendering. I have built in a couple of tricks but more on that next time.