Wednesday 16 December 2015

Remote debugging on SOA 12c.

In SOA Suite 12c it is now possible to do step-by-step debugging of your composites, including introspection of your messages and variables.
This is enabled by default in the DefaultDomain of the SOA QuickStart.
But how to do so with a remote server? It is not enabled by default on seperate servers.

A moment ago I saw this tip on the community forum, which states that you have to enable it by adding the following lines to your setDomainEnv.cmd/sh:
export SOA_DEBUG_FLAG="true"
export SOA_DEBUG_PORT="5004"

You can find out all about it here in the docs.

Thursday 10 December 2015

Silent install SOA/BPM 12c QuickStart

Since september 2014, SOA & BPM Suites are available as 12c Release 1. As you may know, the biggest difference in developer experience is the introduction of the QuickStarts, that installs a JDeveloper including a preconfigured IntegratedWeblogic that has the SOA and BPM components have installed. So there is no direct need for a complete Development Server to run and test your developments. By the way, in a project I do think you'll still need a Development Environment to do the end2end testing of your team's complete solution.

But with SOA & BPM 12c you can't do with the standard JDeveloper 12c Studio.

For the SOA 12.2.1 QuickStart a description of the installation process is described here. For BPM the installation is the same, as well as for the 12.1.3 version of both products.

Important to notice is the need for a recent JDK 8 (currently update 65 or 66). Download and install the 64 bit version for your OS.

Download and unzip the BPM or SOA QuickStart files in a temp folder, like 'c:\temp\soa_bpm_1221'). You should then have two files there:
  • fmw_12.2.1.0.0_bpm_quickstart.jar
  • fmw_12.2.1.0.0_bpm_quickstart2.jar

Then for windows you should open an command window as Administrator. For Linux open a terminal window as the user you want to install the product with.

I won't go through the manual install in detail, but given you're working under Windows (for Linux I assume you'll be able to translate it to shell), set the JAVA_HOME and start the intaller as follows:

c:\Temp\soa_bpm_1221>set JAVA_HOME=c:\Program Files\Java\jdk1.8.0_65

c:\Temp\soa_bpm_1221>echo %JAVA_HOME%
c:\Program Files\Java\jdk1.8.0_65

c:\Temp\soa_bpm_1221>"%JAVA_HOME%\bin\java.exe" -jar fmw_12.2.1.0.0_bpm_quickstart.jar
Launcher log file is C:\Users\MAG\AppData\Local\Temp\OraInstall2015-12-09_09-03-34AM\launcher2015-12-09_09-03-34AM.log.

Running through the wizard, in the 'Installation Summary' screen you'll get the chance to save your choices to a response file:
 
I did my installation in  'C:\oracle\JDeveloper\12210_BPMQS' resulting in the following response file that I named 'bpmqs1221_silentInstall.rsp':
[ENGINE]

#DO NOT CHANGE THIS.
Response File Version=1.0.0.0.0

[GENERIC]

#Set this to true if you wish to skip software updates
DECLINE_AUTO_UPDATES=true

#
MOS_USERNAME=

#
MOS_PASSWORD=<secure value="">

#If the Software updates are already downloaded and available on your local system, then specify the path to the directory where these patches are available and set SPECIFY_DOWNLOAD_LOCATION to true
AUTO_UPDATES_LOCATION=

#
SOFTWARE_UPDATES_PROXY_SERVER=

#
SOFTWARE_UPDATES_PROXY_PORT=

#
SOFTWARE_UPDATES_PROXY_USER=

#
SOFTWARE_UPDATES_PROXY_PASSWORD=<secure value="">

#The oracle home location. This can be an existing Oracle Home or a new Oracle Home
ORACLE_HOME=C:\oracle\JDeveloper\12210_BPMQS
Save this as 'bpmqs1221_silentInstall.rsp' (or adapt it if you use either the 12.1.3 version or the SOA QuickStart).
You can change the ORACLE_HOME parameter in this file if you choose to put it elsewhere. I used this because I have all the Oracle software always in a oracle folder, and different JDeveloper installs under JDeveloper. I postfixed the version folder with BPMQS to explicitly state it's a JDeveloper resulting from the QuickStart and not a standard studio install.

To run the silent install you'll issue the following command:
"%JAVA_HOME%\bin\java.exe" -jar fmw_12.2.1.0.0_bpm_quickstart.jar -silent -responseFile %cd%\bpmqs1221_silentInstall.rsp -nowait

I put this in a windows bat file as follows:
@echo off
set JAVA_HOME=c:\Program Files\Java\jdk1.8.0_65
echo JAVA_HOME=%JAVA_HOME%
rem echo "Current dir2:" %~dp0
echo "Silent install BPM QuickStart, using response file:" %cd%\bpmqs1221_silentInstall.rsp
"%JAVA_HOME%\bin\java.exe" -jar fmw_12.2.1.0.0_bpm_quickstart.jar -silent -responseFile %cd%\bpmqs1221_silentInstall.rsp -nowait
BTW: the variable '%cd%' means the current directory. The quickstart installer expects an absolute path to the response file.

UPDATE 26-05-2016:
Some time ago I enhanced this script:
@echo off
@rem set JAVA_HOME="c:\Program Files\Java\jdk1.8.0_65"
set JAVA_HOME=c:\Program Files\Java\jdk1.8.0_65
echo setx -m JAVA_HOME "%JAVA_HOME%"
setx -m JAVA_HOME "%JAVA_HOME%"
echo JAVA_HOME=%JAVA_HOME%
rem Check Java
if exist "%JAVA_HOME%" goto :JAVA_HOME_EXISTS
echo Install %JAVA_HOME% 
jdk-8u65-windows-x64.exe /s INSTALLDIR="%JAVA_HOME%"
:JAVA_HOME_EXISTS
echo %JAVA_HOME% exists
rem check BPM12.2 QS
set FMW_HOME=C:\oracle\JDeveloper\12210_BPMQS
if exist "%FMW_HOME%" goto :BPMQS_HOME_EXISTS
echo Install %FMW_HOME% 
rem echo "Current dir2:" %~dp0
echo "Silent install BPM QuickStart, using response file:" %cd%\bpmqs1221_silentInstall.rsp
"%JAVA_HOME%\bin\java.exe" -jar fmw_12.2.1.0.0_bpm_quickstart.jar -silent -responseFile %cd%\bpmqs1221_silentInstall.rsp -nowait
:BPMQS_HOME_EXISTS
echo %FMW_HOME% exists
if not exist c:\Data mkdir c:\Data
if not exist C:\Data\Jdeveloper\SOA mkdir C:\Data\Jdeveloper\SOA
if not exist C:\Data\Jdeveloper\SOA\SOA mkdir C:\Data\Jdeveloper\SOA\SOA
rem set  JDEV_USER_DIR_SOA and JDEV_USER_HOME_SOA as 'C:\Data\Jdeveloper\SOA\SOA'
echo set  JDEV_USER_DIR_SOA and JDEV_USER_HOME_SOA as C:\Data\Jdeveloper\SOA\SOA
setx -m JDEV_USER_DIR_SOA C:\Data\Jdeveloper\SOA\SOA
setx -m JDEV_USER_HOME_SOA C:\Data\Jdeveloper\SOA\SOA
echo copy jdev.boot naar "%FMW_HOME%\jdeveloper\jdev\bin"
copy jdev.boot "%FMW_HOME%\jdeveloper\jdev\bin" /Y
echo done
This one checks if Java 8 in the given update (in this example 65) is installed and if not it installs it. So the particular java installer should be in the same folder It does not check if there's another version, by the way.
In the end it creates a seperate folder for the User data for JDeveloper. This includes the DefaultServer (Integrated Weblogic) domain. Normally it goes under the user's local settings.
To use that the scripts copies a adapted jdev.boot file to the JDev home, that tells JDeveloper to use the JDEV_USER_DIR_SOA and JDEV_USER_HOME_SOA environment variables for these settings. The adapted jdev.boot file is as follows:
#--------------------------------------------------------------------------
#
#  Oracle JDeveloper Boot Configuration File
#  Copyright 2000-2012 Oracle Corporation. 
#  All Rights Reserved.
#
#--------------------------------------------------------------------------
include ../../ide/bin/ide.boot

#
# The extension ID of the extension that has the <product-hook>
# with the IDE product's branding information. Users of JDeveloper
# should not change this property.
#
ide.product = oracle.jdeveloper

#
# Fallback list of extension IDs that represent the different
# product editions. Users of JDeveloper should not change this
# property.
#
ide.editions = oracle.studio, oracle.j2ee, oracle.jdeveloper

#
# The image file for the splash screen. This should generally not
# be changed by end users.
#
ide.splash.screen = splash.png

#
# The image file for the initial hidden frame icon. This should generally not
# be changed by end users.
#
hidden.frame.icon=jdev_icon.gif

#
# Copyright start is the first copyright displayed. Users of JDeveloper
# should not change this property.
#
copyright.year.start = 1997

#
# Copyright end is the second copyright displayed. Users of JDeveloper
# should not change this property.
#
copyright.year.end = 2014

#
# The ide.user.dir.var specifies the name of the environment variable
# that points to the root directory for user files.  The system and
# mywork directories will be created there.  If not defined, the IDE
# product will use its base directory as the user directory.
#
#ide.user.dir.var = JDEV_USER_HOME,JDEV_USER_DIR
ide.user.dir.var = JDEV_USER_HOME_SOA,JDEV_USER_DIR_SOA

#
# This will enable a "virtual" file system feature within JDeveloper.
# This can help performance for projects with a lot of files,
# particularly under source control.  For non-Windows platforms however,
# any file changes made outside of JDeveloper, or by deployment for
# example, may not be picked by the "virtual" file system feature.  Do
# not enable this for example, on a Linux OS if you use an external editor.
#
#VFS_ENABLE = true

#
# If set to true, prevent laucher from checking/setting the shell
# integration mechanism. Shell integration on Windows associates 
# files with JDeveloper.
#
# The shell integration feature is enabled by default
#
#no.shell.integration = true

#
# Text buffer deadlock detection setting (OFF by default.)  Uncomment
# out the following option if encountering deadlocks that you suspect
# buffer deadlocks that may be due to locks not being released properly.
#
#buffer.deadlock.detection = true

#
# This option controls the parser delay (i.e., for Java error underlining)
# for "small" Java files (<20k).  The delay is in milliseconds.  Files 
# between the "small" (<20k) and "large" (>100k) range will scale the
# parser delay accordingly between the two delay numbers.
#
# The minimum value of this delay is 100 (ms), the default is 300 (ms).
#
ceditor.java.parse.small = 300

#
# This option controls the parser delay (i.e., for Java error underlining)
# for "large" Java files (>100k).  The delay is in milliseconds.
#
# The minimum value for this delay is 500 (ms), the default is 1500 (ms).
#
ceditor.java.parse.large = 1500

#
# This option is to pass additional vm arguments to the out-of-process
# java compiler used to build the project(s).  The arguments
# are used for both Ojc & Javac.
#
compiler.vmargs = -Xmx512m

#
# Additional (product specific) places to look for extension jars.
#
ide.extension.search.path=jdev/extensions:sqldeveloper/extensions

#
# Additional (product specific) places to look for roles.
#
ide.extension.role.search.path=jdev/roles

#
# Tell code insight to suppress @hidden elements 
#
insight.suppresshidden=true

#
# Disable Feedback Manager. The feedback manager is for internal use
# only.
#
feedbackmanager.disable=false

#
# Prevents the product from showing translations for languages other
# than english (en) and japanese (ja). The IDE core is translated into
# other languages, but other parts of JDeveloper are not. To avoid
# partial translations, we throttle all locales other than en and ja.
#
ide.throttleLocale=true

#
# Specifies the locales that we support translations for when 
# ide.throttleLocale is true. This is a comma separated list of 
# languages. The default value is en,ja.
#
ide.supportedLocales=en,ja

#
# Specifies the maximum number of JAR file handles that will be kept
# open by the IDE class loader.  A lower number keeps JDeveloper from
# opening too many file handles, but can reduce performance.
#
ide.max.jar.handles=500

#
# Specifies the classloading layer as OSGi. In the transition period
# to OSGi this flag can be used to check if JDev is running in OSGi
# mode.
#
oracle.ide.classload.layer=osgi

Tuesday 24 November 2015

BPM 12c R2 (12.2.1) download

For a few weeks, BPM 12cR2 is released, next to SOA 12cR2. But if you go to the download area of BPM on OTN, you'll find that the downloads suggest Release 12c (12.1.3.0.0).

Just now on community.oracle.com, I found  an answer to the question I had quitely my self for a few weeks: where to download BPM12cR2?

I didn't check-out edelivery.oracle.com my self yet, but you can go to Oracle BPM Suite Downloads | Oracle Technology Network | Oracle. Then accept the download agreements on the page, as though you were to download the links on the page. Then use the following links to download part one and two of the BPM QuickStart installer:
Thanks mr. Atwood. Hopefully Oracle repairs the links soon.

Saturday 24 October 2015

SOASuite 12.2.1 Available

On the eve of OOW15, I read that Oracle Fusion Middleware 12.2.1 is released, including Oracle SOASuite, but apparently excluding BPM Suite.

You can download the quickinstaller here. Although it is not explicitly stated on the download pages and in the install guide, you'll need Java 8, update 51+ to install. Which is good news actually, because although Weblogic 12c was already Java 8 certified, and SQLDeveloper 4.1 was introduced on Java 8, SOASuite and BPM suite 12c (12.1.3) was not, and actually won't be (I presume).

You can check out the certification in the certification matrix of Fusion Middleware.

Happy OOW15 all the attendees at the other side of the 'big pool'. We'll guard the fortresses over here... ;)

Oh, and in my previous blog I posted about BPM 12.1.3 Bundle Patch 4, but that there was no BP4 yet for SOASuite. Now a moment ago, I saw since october 20th, there is one for SOASuite.

Tuesday 13 October 2015

SOA BPM 12c Bundelpatches

Earlier this year I wrote about some bugs and patches on SOA & BPM suite, I experienced, and the recommended patches I extracted from that journey. A few weeks ago I found that Jan van Zoggel wrote about the latest bundlepatches on SOA and BPM 12c.

It turns out that there are now 4 Bundlepatches:

  • Bundle patch 1: Patch 19707784: SOA/BPM Bundle Patch 12.1.3.0.1
  • Bundle patch 2: Patch 20423408: SOA/BPM Bundle Patch 12.1.3.0.2
  • Bundle patch 3 for SOA: Patch 20900599: SOA Bundle Patch 12.1.3.0.3
  • Bundle patch 3 for BPM: Patch 20645340: BPM Bundle Patch 12.1.3.0.3
Jan mentioned that the both BP3's conflict with each other according to OPatch. So I assume that if you installed the SOA Quickstart you use the BP3 for SOA, and the BPM variant for the BPM Quickstart.

On downloading the Bundle patch 3 for BPM on support.oracle.com, I got the message that it was supersededby Patch 21640312: BPM Bundle Patch 12.1.3.0.4, per 21-Aug-2015.
However for the Bundle patch 3 for SOA (20900599) I could not found an upgrade-patch yet.

Wednesday 16 September 2015

SoapUI: change the location of your user home

At my current customer I use a company supplied laptop. In the office, when I logon I get connected to a Home Folder on a network drive. SoapUI stores it's default workspace in the root of that folder, based on Windows settings.

At home I connect using VPN and somehow this Home Folder is unreachable. Very inconvenient, because with every restart I need to open/import my projects again.

As with the increase of the heap settings like I showed a few days ago, also for the location of the user-home, there is a property, that can be set as a Java -D argument.

So you can add that to the "SoapUI-5.1.3.vmoptions", just add the Duser.home property as follows:
-Xms1024m
-Xmx1536m
-Duser.home=c:\dev\SoapUI
-Dsoapui.properties=soapui.properties
-Dsoapui.home=C:\Program Files\SmartBear\SoapUI-5.1.3/bin
-Dsoapui.ext.libraries=C:\Program Files\SmartBear\SoapUI-5.1.3/bin/ext
-Dsoapui.ext.listeners=C:\Program Files\SmartBear\SoapUI-5.1.3/bin/listeners
-Dsoapui.ext.actions=C:\Program Files\SmartBear\SoapUI-5.1.3/bin/actions
-Dwsi.dir=C:\Program Files\SmartBear\SoapUI-5.1.3/wsi-test-tools
-Djava.library.path=C:\Program Files\SmartBear\SoapUI-5.1.3/bin
-Djava.util.Arrays.useLegacyMergeSort=true
-splash:soapui-splash.png
As easy as that.

The folder needs to exist of course. You can also add it to the JAVA_OPTS variable in soapui.bat/.sh:
rem JVM parameters, modify as appropriate
set JAVA_OPTS=-Xms128m -Xmx1024m -Dsoapui.properties=soapui.properties "-Dsoapui.home=%SOAPUI_HOME%\" -splash:soapui-splash.png -Duser.home=c:\dev\SoapUI

On a restart and a subsequent close of SoapUI you'll notice that it writes the workspace in the denoted folder.

By the way, I found this tip here.

Monday 14 September 2015

SoapUI: increase memory settings

I have some testcases to run a complex of OSB services that processes documents in a content server.
Using a customization file I changed the endpoints of the content server's webservices to mock-services in SoapUI.

In these testcases I kick-off the OSB services, and in successive MockResponse-teststeps I try to catch the service-requests of OSB. This enables me to set assertions on the messages that OSB sends out to the content server, and thus validate the messages built in the OSB-proxies.

I found that one testcase can run correctly for one time, but running it the second time, or running a second testcase succesively, may fail.


Now it is quite important to have the successive MockResponse-teststeps started at the start of the previous teststep.


At the failing test step, OSB apparently sends a request that isn't caught by SoapUI or SoapUI responds with a HTTP-500 (Internal Server error).


Using JVisualVM, monitored the Heap of the JVM of SoapUI, and I found that just about the time the start/run of the failing teststep, there is an increase in heap. Now, since I found that having the set the Start Step property of each MockResponse-step is important, I figured it seems that timing is everything: also an increase of the Heap consumes time, and is presumably triggered by a major Garbage Collect, that halts the application for a brief moment.


So I wanted to increase the amount of heap. Since SoapUI is started with an .exe file (under Windows that is), the JVM properties (SoapUI is a Java application) are stored in a file. Under windows it can be found in "c:\Program Files\SmartBear\SoapUI-5.1.3\bin", depending on the version of SoapUI.
The file is called "SoapUI-5.1.3.vmoptions" and has the following contents:

-Xms1024m
-Xmx1536m
-Dsoapui.properties=soapui.properties
-Dsoapui.home=C:\Program Files\SmartBear\SoapUI-5.1.3/bin
-Dsoapui.ext.libraries=C:\Program Files\SmartBear\SoapUI-5.1.3/bin/ext
-Dsoapui.ext.listeners=C:\Program Files\SmartBear\SoapUI-5.1.3/bin/listeners
-Dsoapui.ext.actions=C:\Program Files\SmartBear\SoapUI-5.1.3/bin/actions
-Dwsi.dir=C:\Program Files\SmartBear\SoapUI-5.1.3/wsi-test-tools
-Djava.library.path=C:\Program Files\SmartBear\SoapUI-5.1.3/bin
-Djava.util.Arrays.useLegacyMergeSort=true
-splash:soapui-splash.png


You'll need to change the security properties to enable yourself to edit/save it. Then change the -Xms and -Xmx properties according to your needs. The defaults are quite "cautious": -Xms200m and -Xms1000m.

Using JVisualVM you can see that with a restart the new memory settings are picked up and in my case that no increase in Heap is needed during the tests.

Wednesday 2 September 2015

Set environment properties in SoapUI (freeware) - Revised

Last july I wrote about setting environment depended properties in SoapUI. I'm looking for the best way to make SoapUI testcases environment independend and to make it easy to switch between target environments.

In that article I suggested to create a set of properties with the actual working values on project level to be refered in the endpoint urls (hostname:port + URI), username/passwords and so on. And per environment a distinct set of the same properties holding the values of that target environment. Then I created a test case per target environment that copies those target-environment values to the working properties.

This works fine for me. However, in my quest to the most comfortable way of registering and toggling between those values, I found a few enhancements quite convenient.

First of all, after the property-transfer step, I created a manual step, listing the values of the working properties, with a remark that it should contain the values of the particular target environment:



My Localhost version of this testcase will run into:
Don't forget to click 'Ok' after this step. Unfortunately I did not find a way to increase the 'Expected Result" Textarea.

The second enhancement was that I moved my Target Environment property values to the "setEnvironment" test case. I found that with an increasing number of properties it is quite hard to have a clear overview of the properties. And I need to think about a proper naming convention. But when I moved those to the "setEnvironment" test case I have a distinctive set of properties per environment and on project level a distinctive set of working properties.
Since the testcase is environment-specific, I don't need a target-environment reference in the property-names. And also, they are scoped and thus not referable within other testsuites/testcases, preventing errors.

Moving those properties in SoapUI is pretty labor-intensive. But moving those in the source is quick (and dirty). If you open the SoapUI project xml file, you'll find the project-properties at the bottom of the file:
For instance:
<con:properties>
<con:property><con:name>CSServiceURI</con:name><con:value>ContentServer/PS_StoreDocumentToCSStage_v1</con:value>
</con:property><con:property><con:name>CSServiceHost</con:name><con:value>localhost:7001</con:value></con:property>
<con:property><con:name>CSUser</con:name><con:value>svc_GSA</con:value></con:property>
<con:property><con:name>CSPassword</con:name><con:value>welcome1</con:value></con:property>
<con:property><con:name>CSHost</con:name><con:value>localhost:8088</con:value></con:property>
<con:property><con:name>CSAuthenticationURI</con:name><con:value>ContentServer/Authentication</con:value></con:property>
<con:property><con:name>CSSearchServiceURI</con:name><con:value>ContentServer/SearchService</con:value></con:property>
<con:property><con:name>CSDocumentManagementURI</con:name><con:value>ContentServer/DocumentManagement</con:value></con:property>
<con:property><con:name>CSAuthenticationToken</con:name><con:value>TsiKqmREU78MhR4Po%2FJFlsv3OzGUAnDsDsPDcymSnxI%3D</con:value></con:property>
</con:properties>

Copy and paste the properties to move (since I did so allready you'll don't find my target-env properties here anymore) to a seperate  file to get them together.
Then find the target-testcase in the file (in this example "SetLocalEnvironment"):

You'll find at the end of the testcase an empty properties element (<con:properties/>). Open it up (<con:properties> </con:properties> ) and copy and paste the properties within the element.
SoapUI doesn't do formatting of the xml, so you might want to add line-feeds like I did in this example.
Finally you need to change the property-transfer-lines. In the example above, you'll see that I found the transfer-step and added line-feeds for each "<con:transfers ..."
<con:transfers setNullOnMissingSource="true"... some other properties... ><con:name>CSServiceHost</con:name><con:sourceType>CSServiceHost-Dev</con:sourceType><con:sourceStep>#Project#</con:sourceStep><con:targetType>CSServiceHost</con:targetType><con:targetStep>#Project#</con:targetStep><con:upgraded>true</con:upgraded></con:transfers>

You'll find in this line the source step: "<con:sourceStep>#Project#</con:sourceStep>" and target step: "<con:targetStep>#Project#</con:targetStep>". Change the value of the source step to: "<con:sourceStep>#TestCase#</con:sourceStep>". Now the property is refered from the testcase instead of the project. The property on project level can be deleted.

Renaming the properties can better be done from the UI, since SoapUI will then change the property-name also in every reference. Even in soap-requests. So after changing the file in your ascii-editor reload the project in SoapUI. And make the final changes and do the tests.

Now, although this is a nice example of source-hacking from outside the UI, you can't expect any support on this of course. So enable a proper version-control and test the SoapUI properly.

Thursday 20 August 2015

Authorized REST request to MCS with SoapUI

In my former post I explained how to do a REST request to a Mobile Cloud Service API using an Unauthorized access. To do so you need to add an HTTP Header property using a Base64 encoded key. But how to do that for authorized access. Using Postman you should be able to add HTTP  Basic authentication, provide the access details and update the request. In SoapUI, it's more or less the same trick: just provide the HTTP Basic Authentication details, and SoapUI does the encoding for you:
Now if you run this and open up the SoapUI Log: you'll see log entries with the message that is send over the line to MCS.
Thu Aug 20 15:19:59 CEST 2015:DEBUG:>> "GET /mobile/custom/incidentreport_M10/incidents/?contact=Lynn HTTP/1.1[\r][\n]"
Thu Aug 20 15:19:59 CEST 2015:DEBUG:>> "Accept-Encoding: gzip,deflate[\r][\n]"
Thu Aug 20 15:19:59 CEST 2015:DEBUG:>> "oracle-mobile-backend-id: 01d3b3a2-7a6b-42c8-b314-d6e8c8f3e898[\r][\n]"
Thu Aug 20 15:19:59 CEST 2015:DEBUG:>> "Host: unit23585.oracleads.com:7201[\r][\n]"
Thu Aug 20 15:19:59 CEST 2015:DEBUG:>> "Connection: Keep-Alive[\r][\n]"
Thu Aug 20 15:19:59 CEST 2015:DEBUG:>> "User-Agent: Apache-HttpClient/4.1.1 (java 1.5)[\r][\n]"
Thu Aug 20 15:19:59 CEST 2015:DEBUG:>> "Authorization: Basic am9lX20xMDpuNlApIXBOdTQkMA==[\r][\n]"
Thu Aug 20 15:19:59 CEST 2015:DEBUG:>> "[\r][\n]"

Here You see in the last line that SoapUI encoded the username/password details into the Authorization header property. Below you'll see the response:
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "HTTP/1.1 200 OK[\r][\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "Connection: keep-alive[\r][\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "Date: Thu, 20 Aug 2015 13:20:00 GMT[\r][\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "Content-Length: 486[\r][\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "Content-Type: text/html; charset=utf-8[\r][\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "Set-Cookie: JSESSIONID=3W1cVVJQTgGmGZMXQy2G3pVG0QvWByQWtmJr212Mh5nQ9hB0yy4b!-920535662; path=/; HttpOnly[\r][\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "oracle-mobile-runtime-version: 15.3.3-201507070814[\r][\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "X-ORACLE-DMS-ECID: 5a67a51e479fa73b:43dd1c99:14f4a5d80d0:-8000-000000000000729a[\r][\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "X-Powered-By: Servlet/2.5 JSP/2.1[\r][\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "X-Powered-By: Express[\r][\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "[\r][\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "{[\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "  "Body" : {[\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "    "GetIncidentsByCustomerResponse" : {[\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "      "Incident" : [ {[\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "        "Date" : "2015-07-22 17:02:14 GMT",[\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "        "Id" : 10,[\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "        "ImageLink" : "storage/collections/2e029813-d1a9-4957-a69a-fbd0d7431d77/objects/6cdaa3a8-097e-49f7-9bd2-88966c45668f?user=lynn1014",[\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "        "Priority" : "Medium",[\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "        "Status" : "InProgress",[\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "        "TechnicianAssigned" : "joe@fixit.com",[\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "        "Title" : "Leaking Water Heater",[\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "        "UserName" : "Lynn"[\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "      } ][\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "    }[\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "  }[\n]"
Thu Aug 20 15:20:00 CEST 2015:DEBUG:<< "}"

Now, currently MCS supports basic authentication, but I've learned that in the next release OAuth will be supported.

Monday 17 August 2015

Test MCS Custom API using SoapUI

I'm at the OPN Summercamps 2015 in Lisbon on the Mobile Cloud Services workshop, doning the FixIt Fast tutorial. Now, one of the steps is to test the API imported from a RAML document and confgured it. Then in step 3 you're going to test it using the build in test console of MCS. But since I have SoapUI installed I found it neat to be able to test it from there. Since then you can create Test Suites/Cases to do automatic tests.


What I did was to create a new SOAP UI Rest project based on the endpoint of the API:

Then I added a  paramter named contact with value 'lynn'.
But there are two HTTP-Header properties needed:
Propertyvalue
AuthorizationBasic TUFOVElT...(rest of very long string)
oracle-mobile-backend-id01d3b3a2-7a6b-42c8-b314-d6e8c8f3e898


Both values can be found on the settings tab of the Mobile Backend:
The 'oracle-mobile-backend-id' is found here literally. But the 'Authorization' is found under 'Anonymous Key', where initially it gives a link 'Show'. Clicking it will show a long string. Copy and paste it and prefix it with the word 'Basic' and a single space:

And then you're good to go....

Tuesday 21 July 2015

Password properties in SoapUI

By accident I encountered the following behaviour of SoapUI. I wanted to register a username/password combination in SoapUI.
Normally in SoapUI property values are shown as plain text.  Here I miss-typed the property for password on purpose:
But see what happens if I correctly type the word "Password":
Apparently if the property contains the word  "Password", prefixed with something indicative, it will consider the property as a password field. Cool!

By the way: the phrase "Password" should be the last in the name. For example, if you post-fix the property with "-Dev", like "ContentServerPassword-Dev", the content becomes visible again. In those case, you should phrase it like "ContentServer-Dev-Password".

Wednesday 15 July 2015

Disable Wrap Data Types

Just  a moment ago I stumbled on a blog entry of Eric Elsinga about the wrapping of datatypes in Weblogic Datasources, related to the DB-Adapter.

Weblogic wraps objects returned by the database-driver to provide functionality related to debugging, connection utilization tracking and transparent transaction support.
However for some native database objects like BLOBS, CLOBS, ARRAYS etc. this wrapping can affect the performance significantly. When this wrapping is disabled, the application (in our case the DB-Adapter) can work directly on the native objects provided by the Database driver.
To disable the object wrapping do the following:
  1. In the Domain Structure tree, expand Services, then select Data Sources.
  2. On the Summary of Data Sources page, click the data source name.
  3. Select the Configuration: Connection Pool tab.
  4. Scroll down and click Advanced to show the advanced connection pool options.
  5. In Wrap Data Types, deselect the checkbox to disable wrapping.
  6. Click Save.
Of course on a production-mode server you need to Lock&Edit upfront and Activate Changes afterwards.
See also:

Wednesday 8 July 2015

OpenSSL and KeyTool commands

Earlier I wrote an article about message transport security in Oracle B2B. It collects a few usefull Java Keytool and OpenSSL commands to convert and import Certificates.

Today I learned another (from co-worker Joris, thanks).

This is how to get a certificate from an external server.
openssl x509 -in <(openssl s_client -connect {remote-host}:443 -prexit 2>/dev/null) -out /tmp/certificate.crt 

This is usefull, because in some cases the remote host, maybe a virtual one, where by means of Server Name Indication the specific virtual-host's certificate is to be 'asked', while the actual certificate of the physical host is presented by default. Note that Weblogic (and other JEE Appserver as JBoss, Websphere, Glassfish, etc.) does not support SNI.

I think I should create a blog-entry to collect these usefull commands in one page. However I've found these:


Thursday 2 July 2015

OSB & MTOM: When to use Include Binary Data by Reference or Value

As can be seen in my blogs of these days, I've been busy with implementing a service using MTOM in OSB. When enabling XOP/MTOM Support you'll have to choose between:
  • Include Binary Data by Reference
  • Include Binary Data by Value

I used the first because I want to process the content in another service on another WLS-Domain. However, in my first service catching the initial request I want to do an XSD validation. And although the rest of the message is valid, the Validate activity raises an exception with the message: 'Element not allowed: binary-content@http://www.bea.com/wli/sb/context in element Bestandsdata....'.

Looking into this problem I came up with this section in the doc,  which states that you use 'Include Binary Data by Value' when you want to:
  • transfer your data to a service that does not support MTOM
  • validate your message
Now, what does this other option? OSB then parses the root of the Inbound MIME message in search for  xop:Include-tags. When found, it will Base64 encode the binary-content and replaces the tags with the Base64-string.

Now, although I want exactly that in the end, I don't want that at this point of the service. I want to transform my message, without the Base64-strings. And I want to encode the data only on my other domain.

So I just want to ignore messages that start with the 'Element not allowed: binary-content@...' messages. To do so I came up with the next expression:
fn:count($fault/ctx:details/con:ValidationFailureDetail/con:message[not(fn:starts-with(text(),'Element not allowed: binary-content@http://www.bea.com/wli/sb/context in element Bestandsdata'))])>0 
Add an If-Then-Else activity to your Error Handler Stage with this expression. Add the following Namespace:
  • Prefix: con
  • Namespace:  http://www.bea.com/wli/sb/stages/transform/config

If the expression evaluates to true, then you have in fact an invalid XML-message. In the else branch you can add a Resume to ignore the exception.

This expression might come in handy in other situations as well.

Set environment properties in SoapUI (freeware)

Ever used SoapUI to test services on multiple environments? Then you probably ran in to the job of ever changing the endpoints to the hosts of the particular environment; development, test, acceptance, production (although I expect you wouldn't use SoapUI against a prod-env). This is not that hard if you have only one service endpoint in the project. But what if you want to test against multiple services or have to call a service on one system with the result of the other during a testcase. You can even have testcases that mock services called by your (BPEL/BPM) process and call back the process to have it process to a further stage. And then you can end up having multiple endpoints per environment.

You can set multiple endpoints on a request and toggle between them. But you'll have to do that for every request.

SoapUI however, supports the use of properties in the endpoints. So you can setup different host-properties and URI properties on the project:
In this case you see that I have one property for the Service URI, the part of the URL after the host:port, and several ...Host properties for each seperate environment, and one actual.

As said, you can have a property based endpoint like this:
So I have one single endpoint defined based on:
http://${#Project#CSServiceHost}/${#Project#CSServiceURI}
Here you see that the endpoint is based on two properties: ${#Project#CSServiceHost} and ${#Project#CSServiceURI}. In those properties '#Project#' refers to the level in SoapUI the properties are defined. You can also refer to #TestSuite#, #TestCase#, etc.

Now you could manually copy and paste the host of the particular environment to the actual host property, but that can be error prone when dealing with multiple endpoints.
What I did was to create a seperate TestSuite called 'ProjectSettings'. In there I created a testcase per environment: 'SetLocalHosts', SsetDevHosts', etc. In there I created a PropertyTransfer that transfers the particular env-host-property to the actual host-property:

You can create a property transfer for each applicable host in your environment. You can enhance the testcase with particular groovyscripts to determine the properties on run-time. You could even call a generic TestCase from there.

Running the particular testcase before your tests will setup your SoapUI project for the target environment in one go.

Maybe I'll enhance this further in my projects, but for now I find this neat. However, it would have been nice if SoapUI would support different environments with hostnames/urls applicable for that environment. And that you could select a target-environment on project level using a poplist.
Also it would be nice to have custom scripts (like macro's) on project level, that could be coupled to a button in the button bar, in stead of how I do it above.

Wednesday 1 July 2015

OSB11g what is the scope of the for-each loop variable?

Earlier I wrote an article on the strange behaviour of the OSB11g For-each activity (Osb-11g: for each is index-variable an integer?). Today I found out some other peculiar behaviour.

I had to loop over a sequence of  documents, each refering to an attachment. The first document processed well, but at the second iteration the attachment couldn't be found. At first I used Soap with Attachments and now I changed my service to use MTOM. Anyway, at first I thought it to be a SoapUI problem. But adding debug-alerts (I find alerts more comfortable then logs) showed me that the second attachment is really referred to in the message. So apparently, it's not a SoapUI problem.

What happened? Well, have the following for-each:
So I loop over a bunch of documents and at each iteration I'll get the particular document in the document variable. Then I get the attachment, transfer it into a base64-encoded-string, and replace the content with the base64-encoded-string, ... , in the $document variable!!!!! Is that wrong? Well, I expected that in the next iteration the $document variable would be replaced by the new occurrence. But apparently changing the for-each-variable will change the scope of the variable and makes it a 'normal' variable, instead of the loop variable. And since I replaced the contents, It did not have the reference to the next attachment. The quick fix I did was to copy the loop variable to a seperate variable using an assign and then do the changes on that next variable. Each new iteration the content of that variable is overwritten by the assing of the new iteration-variable.

But better is probably to use the index variable and do the changes directly on the main variable, in my case $documents.

So conclusion? Don't change the loop variable!

UPDATE: Oh, by the way, the reason that I change a seperate variable during the loop was that it apparently is not possible to do a Replace or Insert within a loop upon using the index variable. You'll get an error like: 'XQuery exception: line 34, column 11: {err}XP0008 [{bea-err}XP0008a]: Variable
 "$documentIndex" used but not declared for expression: declare namespace jca =
 'http://www.bea.com/wli/sb/transports/jca';...
'
in the expression. So what I did was to copy the document-array from the body variable to a $documents variable, delete all the documents in the body variable (leaving the documents-element). Then loop over the $documents variable, create a new $documentNew variable from $document with the changed variables and insert that in the body variable again.

Tuesday 30 June 2015

MTOM using SoapUI and OSB

MTOM (Message Transmission Optimization Mechanism) is incredibly hard... to find practical information about, on SoapUI and OSB. There are loads of articles. Like:
But I need to process documents that are send using MTOM to my service. And to be able to test it, I need to create a working example of a SoapUI project to do exactly that. Also about SoapUI and MTOM there are loads of examples, and it is quite simple really. But I had a more complex wsdl that I was able to use for Soap with Attachments (SwA) wich is also simple really. But how to connect those two in a simple working example? Well, actually, it turns out not so hard either... So bottom-line, MTOM with SoapUI and OSB is not so hard. If you know how, that is.

So let's work this out on a step-by-step basis.

XSD/WSDL

I'll start with a simple XSD:
<?xml version="1.0" encoding="windows-1252" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns="http://www.darwin-it.nl/MTOM"
            targetNamespace="http://www.darwin-it.nl/MTOM"
            elementFormDefault="qualified">
  <xsd:element name="mtomRequest" type="MtomRequestType"/>
  <xsd:complexType name="MtomRequestType">
    <xsd:sequence>
      <xsd:element name="document" type="xsd:base64Binary"/>
    </xsd:sequence>
  </xsd:complexType>
  <xsd:element name="mtomResponse" type="MtomResponseType"/>
  <xsd:complexType name="MtomResponseType">
    <xsd:sequence>
      <xsd:element name="document" type="xsd:string"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>

In JDeveloper, this looks like:
The key is the 'xsd:base64Binary' type of the request document. In the response I have a string: in this example I'll base64-encode the attachment using a java-class. Just to show how to process the document. But in my project this is what I need to do.

The WSDL is just as easy, plain synchronous Request-Response:

<wsdl:definitions name="MTOMService" targetNamespace="http://oracle.com/sca/soapservice/ContentServer/MTOMService/MTOMService" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:inp1="http://www.darwin-it.nl/MTOM" xmlns:tns="http://oracle.com/sca/soapservice/ContentServer/MTOMService/MTOMService" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
    <wsdl:types>
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <xsd:import namespace="http://www.darwin-it.nl/MTOM" schemaLocation="../xsd/MTOMRequestResponse.xsd"/>
        </xsd:schema>
    </wsdl:types>
    <wsdl:message name="requestMessage">
        <wsdl:part name="part1" element="inp1:mtomRequest"/>
    </wsdl:message>
    <wsdl:message name="replyMessage">
        <wsdl:part name="part1" element="inp1:mtomResponse"/>
    </wsdl:message>
    <wsdl:portType name="execute_ptt">
        <wsdl:operation name="execute">
            <wsdl:input message="tns:requestMessage"/>
            <wsdl:output message="tns:replyMessage"/>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="execute_pttSOAP11Binding" type="tns:execute_ptt">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="execute">
            <soap:operation style="document" soapAction="http://oracle.com/sca/soapservice/ContentServer/MTOMService/MTOMService/execute"/>
            <wsdl:input>
                <soap:body use="literal" parts="part1"/>
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal" parts="part1"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="execute_ptt">
        <wsdl:port name="execute_pttPort" binding="tns:execute_pttSOAP11Binding">
            <soap:address location="http://www.example.com"/>
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>
Did you know that in JDeveloper it is really easy to create this WSDL? Just, create a SOA Project, drag and drop a Webservice on the exposed services lane, define a wsdl as synchronous, with a request and response message. Then open the wsdl in the wsdl editor and drag the operations to the binding pane and then the binding to the services pane:

The SoapUI Part

Now, create a new SoapUI project based on this WSDL. It turns out that SoapUI interprets this base64Binary field and creates special content:

This body refers to an attachment, that is not yet added:
      <mtom:mtomRequest>
         <mtom:document>cid:915251933163</mtom:document>
      </mtom:mtomRequest>
Let's add an image to it, by opening the 'Attachments' tab and clicking on the plus-button: You can select the 'Part' to which the attachment is to be linked. Doing so will change the 'Type' into 'CONTENT'. Edit either the 'ContentID' or the id in the document-element (indicated by 'cid:') to match eachother.

At this point, you can create a mock-service on the request and set the host of the mockservice to 'localhost' and 'MTOMService' in the mock-service editor:
Then you can right-click on the Mock-server and select 'Add endpoint to interface'.

Running the Request, will send the following message to the Mock Service:
(Altough the title is 'Response 1', what you see here is the request received by the Mock Service).
Apparently SoapUI base64 encoded the attachment and embedded it into the document-element.

Now you can enable MTOM on the request. Select the Request and go to the properties pane:
When running the request again SoapUI won't base 64 encode the attachment but send it as a compressed MIME/Multipart-attachment, with a reference in the document:
In the http-log you'll find:
POST /MTOMService HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: multipart/related; type="application/xop+xml"; start="<rootpart@soapui.org>"; start-info="text/xml"; boundary="----=_Part_11_531670487.1435664879005"
SOAPAction: "http://oracle.com/sca/soapservice/ContentServer/MTOMService/MTOMService/execute"
MIME-Version: 1.0
Content-Length: 39605
Host: localhost:8080
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)


------=_Part_11_531670487.1435664879005

Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"

Content-Transfer-Encoding: 8bit

Content-ID: <rootpart@soapui.org>


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mtom="http://www.darwin-it.nl/MTOM">
   <soapenv:Header/>
   <soapenv:Body>
      <mtom:mtomRequest>
         <mtom:document><inc:Include href="cid:915251933163" xmlns:inc="http://www.w3.org/2004/08/xop/include"/></mtom:document>
      </mtom:mtomRequest>
   </soapenv:Body>
</soapenv:Envelope>

------=_Part_11_531670487.1435664879005

Content-Type: image/jpeg; name=SoapUIMTOMRequest.jpg

Content-Transfer-Encoding: binary

Content-ID: <915251933163>

Content-Disposition: attachment; name="SoapUIMTOMRequest.jpg"; filename="SoapUIMTOMRequest.jpg"


[0xff][0xd8][0xff][0xe0][0x0][0x10]JFIF[0x0][0x1][0x1][0x0][0x0][0x1][0x0][0x1][0x0][0x0][0xff][0xdb][0x0]C[0x0][0x6][0x4][0x5][0x6][0x5][0x4][0x6][0x6][0x5][0x6][0x7][0x7][0x6][0x8]
[0x10]

[0x9][0x9]
[0x14][0xe][0xf][0xc][0x10][0x17][0x14][0x18][0x18][0x17][0x14][0x16][0x16][0x1a][0x1d]%[0x1f][0x1a][0x1b]#[0x1c][0x16][0x16] , #&')*)[0x19][0x1f]-0-(0%()([0xff][0xdb][0x0]C[0x1][0x7][0x7][0x7]
[0x8]
[0x13]

[0x13]([0x1a][0x16][0x1a](((((((((((((((((((((((((((((((((((((((((((((((((([0xff][0xc0][0x0][0x11][0x8][0x0][0xdc][0x3]7[0x3][0x1]"[0x0][0x2][0x11][0x1][0x3][0x11][0x1][0xff][0xc4][0x0][0x1b][0x0][0x1][0x0][0x2][0x3][0x1][0x1][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x5][0x6][0x2][0x3][0x4][0x1][0x7][0xff][0xc4][0x0]P[0x10][0x0][0x1][0x2][0x5][0x2][0x3][0x4][0x5][0x8][0x6][0x8][0x4][0x4][0x6][0x3][0x0][0x1][0x2][0x3][0x0][0x4][0x5][0x11][0x12][0x13]![0x6]"#[0x14][0x15]1QAVa[0x95][0xd2][0x7]2[0x81][0x92][0xa5][0xb3][0xd3][0xd4][0x16]37Ru[0x94]45Bqt[0xb1][0xb4][0xd1]$6r[0x91]%Dbs[0x17]&C[0xa1][0xc1][0xe1]cd[0xb2][0xff][0xc4][0x0][0x19][0x1][0x1][0x1][0x1][0x1][0x1][0x1][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x1][0x2][0x3][0x4][0x5][0xff][0xc4][0x0]5[0x11][0x0][0x1][0x3][0x0][0x8][0x4][0x6][0x2][0x2][0x2][0x2][0x3][0x1][0x0][0x0][0x0][0x0][0x1][0x2][0x11][0x3][0x12]!1AQa[0xf0][0x4][0x14]q[0xc1][0x13]"[0x81][0x91][0xa1][0xd1][0xb1][0xe1]2[0xf1]Bb[0x5][0x92]#r[0xd2]R[0xff][0xda][0x0][0xc][0x3][0x1][0x0][0x2][0x11][0x3][0x11][0x0]?[0x0][0xfb];[0xf2][0x8d]O|[0xa3][0x19][0x19][0x85]L[0x9]4[0xd2];@i[0x99][0x87][0x19][0x19][0x87][0xad][0x97]![0x1b][0xd8][0xda];;[0xbf][0x87][0xae][0xa0]{[0xc0][0x14][0xa8][0xa0][0x85]O[0xcd][\r][0xc1][0xb1][0xf1]W[0xb3][0xc7][0xd3][0xe3][0x1a][0xd8][0xfd][0xaa][0xb9][0xfc][0x8][0xfd][0xfc]j[0x9d][0xfe][0x98][0xff][0x0][0xfe][0xe2][0xbf][0xce]=[0x1c]=[0x12]R[0xaa][0xa2][0x9c])[0xe9]V[0x8d][0x11]P[0xea][0xee][0xfe][0x1d][0xf3][0x9f][0xf7][0x84][0xd7][0xc7][0xe][0xef][0xe1][0xdf]9[0xff][0x0]xM|q[E~[0x9a][0xb9][0x99][0xb6][0xb5][0xd6][0x94][0xca][0xa5]ky[0xf5][0xb2][0xb4][0xcb][0xa4] [0xd9]}b4[0xc9]I[0xb8] *[0xe0][0xa5]W[0xf9][0xa6][0xdd][0x14][0xba][0x94][0xad]R]OI[0xad]d!E[0xb]C[0x8d])[0xa7][0x1b]U[0x81][0xb2][0x90][0xb0][0x14][0x93]b[\r][0x88][0x17][0x4][0x1f][0x2][0xc]z[0xf9]&[0xea]y[0xf9][0x9a]D[0xc0][0x9c][0xee][0xfe][0x1d][0xf3][0x9f][0xf7][0x84][0xd7][0xc7][0xe][0xef][0xe1][0xdf]9[0xff][0x0]xM|q^[0xab][0xd7])4].[0xf8][0xaa]HHk_O[0xb5]L![0xac][0xed]k[0xdb]"/k[0x8f][0xf]1[0x1d]4[0xf9][0xe9]J[0x94][0x9b]st[0xe9][0xa6]&[0xe5]\[0xbe][0xf]0[0xe0]q
[0xb1] [0xd9]Ccb[0x8][0xfa]#<[0xa5][0x1c][0xc4][0xa8][0xe6][0x9f]|[0x13][0x1d][0xdf][0xc3][0xbe]s[0xfe][0xf0][0x9a][0xf8][0xe1][0xdd][0xfc];[0xe7]?[0xef][0x9][0xaf][0x8e]#[0xe1][0x17][0x93]fjNm[0xf9]!![0xdd][0xfc];[0xe7]?[0xef][0x9][0xaf][0x8e][0x1d][0xdf][0xc3][0xbe]s[0xfe][0xf0][0x9a][0xf8][0xe2]>[0x10][0xe4][0xd9][0x9a][0x8e]m[0xf9]!![0xdd][0xfc];[0xe7]?[0xef][0x9][0xaf][0x8e][0x1d][0xdf][0xc3][0xbe]s[0xfe][0xf0][0x9a][0xf8][0xe2]>[0x10][0xe4][0xd9][0x9a][0x8e]m[0xf9]!![0xdd][0xfc];[0xe7]?[0xef][0x9][0xaf][0x8e][0x1d][0xdf][0xc3][0xbe]s[0xfe][0xf0][0x9a][0xf8][0xe2][0x1d][0xf9][0xe9]F'%[0xa5][0x1f][0x9a]a[0xa9][0xa9][0xac][0xb4][0x19][[0x81]+w[0x11]u`[0x93][0xba][0xac]76[0xf0][0x8d][0xb3]
[0xc6]Y[0xf5]j-[0xab]4[0xbe]t7[0xa8][0xa4][0xf2][0x9d][0xd2][0x9c]Uuy[0xb][0x1d][0xed][0xe]M[0x99][0xa9]y[0xa7][0xe4][0x84][0x9f]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xce]Q[0x9a][0x97][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x87]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8[0x87][0x9a][[0xe8][0xed]Yj[0xb3][0x82][0x14][0x95]`[0x82][0xbd][0x4]u[0xb1])[0xe9][0x1d]G[0x8d][0x93][0xcb][0xbd][0xb6][0xfa]SK}[0x1d][0xab]-VpB[0x92][0xac][0x10]W[0xa0][0x8e][0xb6]%=#[0xa8][0xf1][0xb2]yw[0xb6][0xdf]K[0x94]f[0xa3][0x99]~[0x84][0xc7]w[0xf0][0xef][0x9c][0xff][0x0][0xbc]&[0xbe]8w[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x88]y[0xa5][0xbe][0x8e][0xd5][0x96][0xab]8!IV[0x8]+[0xd0]G[[0x12][0x9e][0x91][0xd4]x[0xd9]<[0xbb][0xdb]o[0xa5]4[0xb7][0xd1][0xda][0xb2][0xd5]g[0x4])*[0xc1][0x5]z[0x8][0xeb]bS[0xd2]:[0x8f][0x1b]'[0x97]{m[0xf4][0xb9]Fj9[0x97][0xe8]Lw[0xe][0xf9][0xcf][0xfb][0xc2]k[0xe3][0x84]G[0xb2][0xa7][0xd3]>B[0x92][0x96][0xf0]8[0xa9].$[0xa9][0xb6]Qwq$[0xe9]s[0xb8][0xab]&[0xe9][0xbf]([0xff][0x0][0xee][0x8c][0xaf]
[0xc4][0xcf]~[0x85]N%[0xda]o[0xd4][0xeb]c[0xf6][0xaa][0xe7][0xf0]#[0xf7][0xf1][0xaa]w[0xfa]c[0xff][0x0][0xfb][0x8a][0xff][0x0]8[0xda][0xc7][0xed]U[0xcf][0xe0]G[0xef][0xe3]T[0xef][0xf4][0xc7][0xff][0x0][0xf7][0x15][0xfe]q[0x8e][0xf][0xf9])[0xae].[0xe4]>r[0x95]PMG[0x89][0x9e][0xa9][0xbd]:[0xe4][0xbc][0xd4][0xb4][0xc8][0x98]q[0xd6][0xdb]m[0xb7][0x98]d[0xe9][0xbe][0x94][0xe8][0x80][0xe2][0xb4][0xc9][0x8][0x5][0xc0]V[0x7][0xea][0xc9][0x5]D[0xcd][0xf0][0x13][0xb2]st[0x97][0xa7]d[0xdd][0x9a]}[0xc9][0x97][0xca][0xdf]~eM)N[0xad])J[0x1][0xc9][0x9e][0x92][0x80]JP[0x9b][0xb7][0xb7]-[0x8f]0Tl[0xfd][0xc][0xe1][0xf0][0xf4][0xf3][0xc9][0xa6]2[0x87][0xa7][0x9b][0x98]je[0xc4][0x12][0x95][0xbc][0x87][0xd5][0x93][0x81]J[0x6][0xe6][0xe7][0xc3][0xd2][0x9f][0x4][0xd8]m[0x16][0x4][0xa4]$XG[0xd3]s[0x91]n[0xde][0xf1]<[0xae]rD![0xf2]?[0x96]t:[0xe7][0x1d][0xf0]
[0x18][0xa1][0xb1]_p[0xf7][0x85][0xa9][0xcf][0xad][0x8]C[0xdd]$x[0x95][0x82][0x91]o[0x9d][0xb8][0xfe][0xcf][0x9c]Gp[0x85]~_[0x85]>F8[0x87][0x8a][0xa8][0x89][0x90][0x98]T[0xd4][0xfb][0x93][0xa8][0x91]d[0x94][0xb7]"[0xb7]V[0xdb]ia[[0x2]p[0x5]$[0x80][0x13]q[0xb0][0xd8][0x85][0x1f][0xae][0xce][0xd1]i[0xf3][0xd5]zmRj_9[0xea]n[0xaf]ew5[\r]=D[0xe2][0xbd][0x81][0xb1][0xb8][0x16][0xdc][0x1b]z#[0x9e]O[0x85][0xe8][0x92]s[0x95][0x99][0x99]jk[0x8]r[0xb1]n[0xde][0x8]%[0x13][0x16]

Where I removed all the new-line and timing codings, for readability. This is what actually goes 'over the line'.

The OSB Part

Now we're ready for the OSB part. Create a new OSB project and add the wsdl and xsd to it. If you created the wsdl, like I did, in JDeveloper, you can create the OSB project with the same name in the same folder as the JDeveloper project.

Create a new Proxy Service, and name it 'MTOMService' for instance. Base it on the MTOMService wsdl, created above.
I added a Pipeline, with stages and alerts to log the $attachments and $body variables. However, it turns out that since we're using MTOM via a base64Binary-element, the Attachments variable is empty. The body variable contains the message as seen in SoapUI.



Now, the most interesting part here is: 'How to get to the attachment-content?' Using 'Soap with Attachments' (SwA), the $attachments variable gives access to the binary content, with an expression like:
$attachments/ctx:attachment[ctx:Content-ID/text()=$contentId]/ctx:body/ctx:binary-content
Where 'ctx:' is an internal namespace of OSB:

But since the $attachments is empty, this won't work. It is the base64Binary element that gives access to the content, in just the same way. So the expression is:
$body//mtom:document/ctx:binary-content

I added an assign with this as an expression to a seperate variable called 'documentBin'.

Then I added a Java Callout to my Base64-encoding method. For this I used the class described in my previous article. I jarred it and added the jar to my project. The input of this class is a 'byte[] bytes' and the output is a 'String' for wich I used the variable 'documentB64'. Then I added a replace with the following to pass back the response:
<mtom:mtomResponse xmlns:mtom="http://www.darwin-it.nl/MTOM">
<mtom:document>{$documentB64}</mtom:document>
</mtom:mtomResponse>

Then, an important setting: enable MTOM: go to the Message Handling tab of the proxy service:
Check the box 'Enabled' of 'XOP/MTOM Support'. Leave radio-button to 'Include Binary Data by Reference'. Save the proxy service.

The proof in the eating

Now, publish it to a running OSB server and change the Endpoint URL within SoapUI to the OSB Service.
Running the SoapUI Request via OSB results in the following response:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header xmlns:mtom="http://www.darwin-it.nl/MTOM"/>
   <soapenv:Body xmlns:mtom="http://www.darwin-it.nl/MTOM">
      <mtom:mtomResponse>
         <mtom:document>/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwg....</mtom:document>
      </mtom:mtomResponse>
   </soapenv:Body>
</soapenv:Envelope>

The Alert of the documentB64 variable shows:

Conclusion

I spent quite some time searching the internet-area on usable articles on SoapUI, OSB and MTOM. But in the end, writing this article cost me more time then implementing this. I hope this article can be rightfully categorized in my 'FMW made Simple'-series.

Downloads

I made my projects downloadable via:


Monday 29 June 2015

Deployment plan of resource adapter missing

Today I was struggling with my OSB domain. Last week I switched laptops and did a new OSB installation on my new laptop and thought it was smart to just zip the OSB Domain from my old laptop to unzip it on my new laptop.

What I forgot was to copy the adapter plan.xml from the oracle home on my old laptop. So the resource adapter did not start correctly. It was even not editable, since it required the missing adapter plan. Searching the domain on files containing the name of the plan brought me to editing the config.xml of the domain.

For all the resource adapters you'll find entries like:
 <app-deployment>
    <name>DbAdapter</name>
    <target>AdminServer</target>
    <module-type>rar</module-type>
    <source-path>C:/Oracle/Middleware/Oracle_OSB1/soa/connectors/DbAdapter.rar</source-path>
    <deployment-order>322</deployment-order>
    <plan-dir xsi:nil="true"></plan-dir>
    <plan-path>C:\Oracle\Middleware\Oracle_OSB1\soa\connectors\DBAdapterPlan.xml</plan-path>
    <security-dd-model>DDOnly</security-dd-model>
    <staging-mode>nostage</staging-mode>
  </app-deployment>
If you compare this to an entry that was not edited before, for instance, the AQ Adapter, you'll find that the other Adapter lacks the elements for  plan-dir and plan-path. So I deleted those and restarted my domain. When I edited the adapter again, it asked for the plan name again, as it would on editing it for the first time. Nice thing is that the default/demo entries were there again. So I only had to edit my own custom datasource and was on track again.

Wednesday 24 June 2015

Base64 encoding/decoding in OSB

Of course there are several java examples to do a base64 encoding on the internet. And there are almost nearly as much encoding implementations in different environments. But which one works in Weblogic/OSB11g? And to implement those examples, compile and jar them, I find myself on a quest for the necessary jars. Of course you can refer to the weblogic.jar in your project of ant file. But that is a little too much, I think. I'd like to find and deliver the bare minimum of jars needed for my project.

For my latest customer/project I came up with this class:

package nl.darwin-it.osb.base64;

import java.io.IOException;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import weblogic.utils.encoders.BASE64Decoder;
import weblogic.utils.encoders.BASE64Encoder;
import java.nio.charset.Charset;

public class Base64EncoderDecoder
{
    private static final Charset UTF8_CHARSET;
    
    public static void main(final String[] args) {
    }
    
    public static String encode(final byte[] bytes) {
        final BASE64Encoder encoder = new BASE64Encoder();
        final String encodedString = encoder.encodeBuffer(bytes);
        return encodedString;
    }
    public static int getLength(final byte[] bytes) {
       int length = bytes.length;
        return length;
    }    
    public static byte[] decode(final String b64Document) throws IOException {
        final BASE64Decoder decoder = new BASE64Decoder();
        final InputStream inputStream = new ByteArrayInputStream(b64Document.getBytes(Base64EncoderDecoder.UTF8_CHARSET));
        final byte[] decodedBytes = decoder.decodeBuffer(inputStream);
        return decodedBytes;
    }
    
    static {
        UTF8_CHARSET = Charset.forName("UTF-8");
    }
}

And if you use JDeveloper11g as a IDE the only lib you need to compile this is: com.bea.core.utils.full_1.9.0.1.jar. Or com.bea.core.utils.full_1.10.0.0.jar, if using oepe version 11.1.1.8. The jars can be found in ${oracle.home}/modules. Where ${oracle.home} refers to your JDeveloper11g or OEPE-Middleware installation.

By the way, in my OSB project I need to process Attachments in my message (Soap with Attachments), where I need to upload the documents to a ContentServer. Unfortunately the ContentServer needs the filesize (it apparenlty does not determine it by base64-decoding it). So I added the getLength() method to determine it with a java-callout similar to the base64-encode.


Input of the methods is a variable like 'attachmentBin' resulted from an Assing with an expression like:
$attachments/ctx:attachment[ctx:Content-ID/text()=$contentId]/ctx:body/ctx:binary-content


Tuesday 16 June 2015

The Byte-Anniversary

I was looking into my blog-entries, and found that my former blog was number 254. So by entering this nonsense blog-entry, I reach the 255. Which makes it my 8-bit, or byte, anniversary:


And apparently my articles have been read as well... Nice thing is that I've reached this amount in nearly 8 years. So up to the next byte. Unfortunately in this case 2 bytes does not make up a Word...

Index variables in Replace/Insert/Delete: Bug or not a bug?

At my current customer I'm to process Attachments in Oracle Service Bus (11g).
I get a soap message, in which several documents are registered to be processed in a Content Server.
For each document the content is delivered as an soap/mime-attachment.

Because of some requirements I need to store the message, complete with the attachments Base64 encoded, in the database. So I have to pick each attachment, base64 encode it and then insert the content at the corresponding document in the soap message. So I need to do an insert or replace of a specific element of the body variable based on an index variable.

It turns out that you can perfectly do an assign with an expression like:
$body/stag:StageDocumentsRequestMessage/Payload/stag:documents/stag:document[contentId/text()=$contentId]
to a variable, for instance called document.

I can do an insert of the base64-encoded content into that document variable. But that does not get into the body variable. Since, apparently, document is a copy of and not a reference to the particular node.

So lets do a replace with the xpath-expresin:
$body/stag:StageDocumentsRequestMessage/Payload/stag:documents/stag:document[contentId/text()=$contentId]
in the variable body. But this gives the error:
[PL_MyPipeLine, Request Pipeline, HandleAttachments, Delete action] XPath expression validation failed: An error was reported compiling the XPath expression: XQuery exception: line 34, column 91: {err}XP0008 [{bea-err}XP0008a]: Variable "$contentId" used but not declared for expression: declare namespace stag = 'http://www.darwin-it.nl/CS/StageDoc';
declare namespace jca = 'http://www.bea.com/wli/sb/transports/jca';
declare namespace wsp = 'http://schemas.xmlsoap.org/ws/2004/09/policy';
...


Same counts for Insert and delete: I thought of inserting a new version of the node in the list and delete the old one, but that would not work either.

I've googled around, and found several occurences of basically the same problem, but no satisfying solution.

At support.oracle.com I found the following bug:
"Bug 17940786 : CANNOT USE INDEX VARIABLE IN THE REPLACE ACTION WITHIN FOR-EACH LOOP" with the following description:

The customer uses 2 for-each loops with index variables ($i, $j).
In the Replace action, in the Xpath expression buider, they want to use
"./entity1[$i]/entity2[$j]". This is not permitted by the editor. The problem
also occurs with only 1 variable like "./entity1[$i]/entity2[1]".

However, for no apparent reason, this "bug" has the status "92 - Closed, Not a Bug". So apparently, Oracle finds it as "functioning as designed". But why can't I modify or delete a particular node indexed by a variable?
Apparently I'm now stuck with building the document list document-by-document and do a replace of the complete document-list...