<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-15999985</id><updated>2024-09-27T23:29:09.298-04:00</updated><category term="Pentaho"/><category term="Pentaho CAS SSO"/><category term="Pentaho CBF"/><title type='text'>Tigers Eat Giants</title><subtitle type='html'>Strange things happen all the time. Who&#39;s to say it isn&#39;t so?</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://tigerseatgiants.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://tigerseatgiants.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Eric</name><uri>http://www.blogger.com/profile/14352579264754955766</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSGGjDKSu2LZ3In1AsMK-ke7dYjBzLGiai1N45_ZMi7QIFFF-zjOZmB-20ww4Szxr30MqDNjgv56cLqxpLOvgxvWnLP0wWI7imDqXS2WUo3OSWyptazu4RvZtBebgIw/s220/Photo+on+2010-07-29+at+16.30+%232.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>10</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-15999985.post-7392459649815077726</id><published>2011-07-26T09:20:00.003-04:00</published><updated>2011-07-27T10:21:47.756-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Pentaho CAS SSO"/><title type='text'>Pentaho and SSO Part 1: CAS</title><content type='html'>&lt;a href=&quot;http://en.wikipedia.org/wiki/Single_sign-on&quot;&gt;Single Sign On&lt;/a&gt; allows users to log in once and access multiple applications without logging in again. The paid version of Pentaho comes with a script that enables SSO for Pentaho, but the community edition does not. However, since Pentaho uses Spring Security, you can still set up Pentaho to use SSO. This post will describe how to set up Pentaho to use &lt;a href=&quot;http://www.jasig.org/cas&quot;&gt;Jasig CAS&lt;/a&gt;, a popular, free, open-source SSO server.&lt;br /&gt;
&lt;br /&gt;
(As an aside, let me say I am not a Pentaho Enterprise Edition customer, nor have I ever seen the Pentaho SSO script. This is a &quot;clean-room&quot; implementation of the configuration.)&lt;br /&gt;
&lt;br /&gt;
Before getting into configuration, an overview of how CAS works would be helpful. When you try to access a protected webpage in Pentaho, the BI-Server checks to see if you are authenticated (and if you are authenticated, checks to see if you are authorized). If you are not authenticated, you are redirected to a login page. When Pentaho is CAS enabled, instead of beign redirected to the Pentaho login page, you are redirected to the CAS login page, which has an address like this:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;http://cas.server.address/cas/login&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
After you login to CAS, you will be redirected back to the original page you tried to access, which probably is the Pentaho PUC. CAS needs to know what page you&amp;nbsp;attempted&amp;nbsp;to see, so it can redirect you there after you authenticate. To tell CAS, the address of the page you attempted to access is appended to the end of the CAS URL.&amp;nbsp;When you are using the Pentaho User Console (PUC), that page is the Spring Security page that checks for authentication:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;http://your.cas.address/cas/login?service=http://yourPentaho/pentaho/j_spring_cas_security_check&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
When it gets the request for the login page, the first thing CAS does is check to see if you have logged into CAS already. If you have not, you are presented with a login page. If you have a correct username and password you are redirected back to &lt;code&gt;http://youPentaho/pentaho/j_spring_cas_security_check&lt;/code&gt;. If you have already logged in with CAS (maybe you have logged in before accessing another CAS enabled application), you are&amp;nbsp;immediately&amp;nbsp;redirected back to j_spring_cas_security_check without seeing the CAS login page. In both cases, once you are redirected back to j_spring_cas_security_check, you are assigned a one time use ticket, which is append to that URL. Like this:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;http://yourPentaho/pentaho/j_spring_cas_security_check?ticket=ST-3555-McPZ4NKfx6S0EhnCEkHc&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Spring Security takes the ticket and checks to see if it is valid by submitting it back to CAS. Like this:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;http://your.cas.address/cas/serviceValidate?ticket=ST-3555-McPZ4NKfx6S0EhnCEkHc&amp;amp;service=http://yourPentaho/pentaho/j_spring_cas_security_check&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
If the ticket is good, CAS responds with the username. &amp;nbsp;Now that Pentaho knows who you are, the regular Pentaho authorization occurs (checking groups and user access rules). However, for the Pentaho authorization to work, you will either need CAS to point to the database where Pentaho stores its users, or make sure that Pentaho can get group information from the CAS database of users. In this example, we are going to create a new MySQL database of users and point both CAS and Pentaho to it.&lt;br /&gt;
&lt;br /&gt;
The three tables that are needed are a Users table, a groups table (called Authorities) and a many to many table to&amp;nbsp;assigning&amp;nbsp;users to groups.&lt;br /&gt;
&lt;br /&gt;
For the Users:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;CREATE TABLE `USERS` (&lt;br /&gt;
&amp;nbsp; `USERNAME` varchar(50) NOT NULL,&lt;br /&gt;
&amp;nbsp; `PASSWORD` varchar(512) DEFAULT NULL,&lt;br /&gt;
&amp;nbsp; `DESCRIPTION` varchar(100) DEFAULT NULL,&lt;br /&gt;
&amp;nbsp; `ENABLED` bit(1) NOT NULL,&lt;br /&gt;
&amp;nbsp; PRIMARY KEY (`USERNAME`)&lt;br /&gt;
)&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Groups:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;CREATE TABLE `AUTHORITIES` (&lt;br /&gt;
&amp;nbsp; `AUTHORITY` varchar(50) NOT NULL,&lt;br /&gt;
&amp;nbsp; `DESCRIPTION` varchar(100) DEFAULT NULL,&lt;br /&gt;
&amp;nbsp; `AUTH_GROUP` varchar(255) NOT NULL DEFAULT &#39;NONE&#39;,&lt;br /&gt;
&amp;nbsp; PRIMARY KEY (`AUTHORITY`)&lt;br /&gt;
)&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
And group assignment:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;CREATE TABLE `GRANTED_AUTHORITIES` (&lt;br /&gt;
&amp;nbsp; `USERNAME` varchar(50) NOT NULL,&lt;br /&gt;
&amp;nbsp; `AUTHORITY` varchar(50) NOT NULL,&lt;br /&gt;
&amp;nbsp; PRIMARY KEY (`USERNAME`,`AUTHORITY`),&lt;br /&gt;
&amp;nbsp; KEY `FK7471775DD9EDC77F` (`USERNAME`),&lt;br /&gt;
&amp;nbsp; KEY `FK7471775D41B6DA97` (`AUTHORITY`)&lt;br /&gt;
)&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Installing CAS:&lt;br /&gt;
&lt;br /&gt;
CAS runs a regular Java webapp. You can run it in the same Tomcat instance as Pentaho, or on another machine. &amp;nbsp;Once you &lt;a href=&quot;http://www.jasig.org/cas/download&quot;&gt;download CAS&lt;/a&gt;, you will need to edit the &lt;code&gt;deployerConfigContext.xml&lt;/code&gt; file in the &lt;code&gt;WEB-INF&lt;/code&gt; directory to point CAS to the USERS table. In the &lt;code&gt;authenticationHandlers&lt;/code&gt; section of the xml file, delete the &lt;code&gt;SimpleTestUsernamePasswordAuthenticationHandler&lt;/code&gt; bean, and replace it with this bean:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;lt;bean id=&quot;SearchModeSearchDatabaseAuthenticationHandler&quot;&amp;nbsp;class=&quot;org.jasig.cas.adaptors.jdbc.SearchModeSearchDatabaseAuthenticationHandler&quot;&amp;nbsp;abstract=&quot;false&quot; scope=&quot;singeton&quot;&amp;gt;&lt;br /&gt;
&amp;lt;property name=&quot;tableUsers&quot;&amp;gt;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&amp;nbsp; &amp;lt;value&amp;gt;USERS&amp;lt;/value&amp;gt;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;
&amp;lt;property name=&quot;fieldUser&quot;&amp;gt;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&amp;nbsp; &amp;lt;value&amp;gt;USERNAME&amp;lt;/value&amp;gt;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;
&amp;lt;property name=&quot;fieldPassword&quot;&amp;gt;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&amp;nbsp; &amp;lt;value&amp;gt;PASSWORD&amp;lt;/value&amp;gt;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;
&amp;lt;property name=&quot;dataSource&quot; ref=&quot;dataSource&quot;/&amp;gt;&lt;br /&gt;
&amp;lt;!-- Use the same PW Encoder as your db --&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;lt;property name=&quot;passwordEncoder&quot;&amp;gt;&lt;/code&gt;&lt;code&gt;&amp;nbsp; &amp;lt;bean class=&quot;org.jasig.cas.authentication.handler.DefaultPasswordEncoder&quot;&amp;gt;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;lt;constructor-arg value=&quot;SHA-256&quot;/&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;lt;/bean&amp;gt;&lt;br /&gt;
&amp;lt;/property&amp;gt;&lt;br /&gt;
&amp;lt;/bean&amp;gt;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
Note that I am using SHA-256 to encode the password. You can use any encoding that you want, MD5 for example.&lt;br /&gt;
&lt;br /&gt;
Finally, point CAS to the right database by adding this to&amp;nbsp;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;deployerConfigContext.xml&lt;/span&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;lt;bean id=&quot;dataSource&quot; class=&quot;org.apache.commons.dbcp.BasicDataSource&quot;&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;lt;property name=&quot;driverClassName&quot;&amp;gt; &amp;lt;value&amp;gt;com.mysql.jdbc.Driver&amp;lt;/value&amp;gt; &amp;lt;/property&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;lt;property name=&quot;url&quot;&amp;gt; &amp;lt;value&amp;gt;jdbc:mysql://your_mysqlhost:3306/YOUR_DB&amp;lt;/value&amp;gt; &amp;lt;/property&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;lt;property name=&quot;username&quot;&amp;gt; &amp;lt;value&amp;gt;DB_USERNAME&amp;lt;/value&amp;gt; &amp;lt;/property&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;lt;property name=&quot;password&quot;&amp;gt; &amp;lt;value&amp;gt;DB_PASSWORD&amp;lt;/value&amp;gt; &amp;lt;/property&amp;gt;&lt;br /&gt;
&amp;lt;/bean&amp;gt;&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Now CAS is setup. Start up Tomcat (or whatever Servlet container you like).&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Part 2 will go over the Pentaho configuration.&amp;nbsp;&lt;/i&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerseatgiants.blogspot.com/feeds/7392459649815077726/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/15999985/7392459649815077726' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/7392459649815077726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/7392459649815077726'/><link rel='alternate' type='text/html' href='http://tigerseatgiants.blogspot.com/2011/07/pentaho-and-sso-part-1-cas.html' title='Pentaho and SSO Part 1: CAS'/><author><name>Eric</name><uri>http://www.blogger.com/profile/14352579264754955766</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSGGjDKSu2LZ3In1AsMK-ke7dYjBzLGiai1N45_ZMi7QIFFF-zjOZmB-20ww4Szxr30MqDNjgv56cLqxpLOvgxvWnLP0wWI7imDqXS2WUo3OSWyptazu4RvZtBebgIw/s220/Photo+on+2010-07-29+at+16.30+%232.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15999985.post-1736808425891227345</id><published>2011-06-22T10:35:00.001-04:00</published><updated>2011-06-29T21:36:26.257-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Pentaho CBF"/><title type='text'>Touring CBF part 2</title><content type='html'>Long delayed, but here is part II:&lt;br /&gt;
&lt;br /&gt;
Running the CBF is easy if you have defined all your&amp;nbsp;build.properties correctly. Assuming you have ant installed, go to the root cbf directory and run this:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;ant -Dproject=ProjectName build-all&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Note that the name of the project is the part after &quot;project.&quot; So if your directory is &quot;project-test&quot; your project name is &quot;test&quot;. To see a list of all the ant targets to use you can do this:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;ant -Dproject=ProjectName -p&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
The targets you are interested are probably:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;ant -Dproject=ProjectName clean&lt;/code&gt;&amp;nbsp;Which cleans the build (but not the deployed directory).&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;ant -Dproject=ProjectName all&lt;/code&gt; Which builds Pentaho.&lt;br /&gt;
&lt;br /&gt;
and &lt;code&gt;ant -Dproject=ProjectName deploy-all&lt;/code&gt; Which eploys the biserver and solution to the target. &lt;br /&gt;
&lt;br /&gt;
If you want added&amp;nbsp;flexibility, you can create custom properties files for&amp;nbsp;development&amp;nbsp;and production. The&amp;nbsp;structure&amp;nbsp;is the same as&amp;nbsp;regular&amp;nbsp;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;build.properties&lt;/span&gt;. So copy&amp;nbsp;build.properties to a file named &quot;dev.properties&quot; and make any&amp;nbsp;necessarily&amp;nbsp;changes. Then you can do this:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;ant -Dproject=client -Denv=dev  dist-clean all run&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
That was a long wait for a little post....but that should be&amp;nbsp;enough&amp;nbsp;to get started using the CBF.</content><link rel='replies' type='application/atom+xml' href='http://tigerseatgiants.blogspot.com/feeds/1736808425891227345/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/15999985/1736808425891227345' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/1736808425891227345'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/1736808425891227345'/><link rel='alternate' type='text/html' href='http://tigerseatgiants.blogspot.com/2011/06/touring-cbf-part-2.html' title='Touring CBF part 2'/><author><name>Eric</name><uri>http://www.blogger.com/profile/14352579264754955766</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSGGjDKSu2LZ3In1AsMK-ke7dYjBzLGiai1N45_ZMi7QIFFF-zjOZmB-20ww4Szxr30MqDNjgv56cLqxpLOvgxvWnLP0wWI7imDqXS2WUo3OSWyptazu4RvZtBebgIw/s220/Photo+on+2010-07-29+at+16.30+%232.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15999985.post-112493715285815008</id><published>2011-04-13T14:28:00.004-04:00</published><updated>2011-06-29T21:38:40.392-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Pentaho"/><title type='text'>Touring Pentaho CBF part 1</title><content type='html'>&lt;b&gt;What is it?&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The &lt;a href=&quot;http://wiki.pentaho.com/display/COM/CBF+-+Community+Build+Framework&quot;&gt;Pentaho Community Build Framework &lt;/a&gt;(CBF) is an ant script that can compile, setup and deploy the Pentaho BI-server. The CBF allows the central management of multiple server configurations, such as development and production, for multiple projects. The local copy of the Pentaho bi-server source files are not edited or changed in any way and each bi-server project has its own directory of changes for the bi-server, such as the web.xml or context.xml files, and its own solution directory. When run, the CBF apples the project specific changes (called &quot;patches&quot;) to the bi-server, and deploys the project. The CBF was first created by &lt;a href=&quot;http://pedroalves-bi.blogspot.com/&quot;&gt;Pedro Alves&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;How does it work?&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The root of the CBF directory needs a copy of the Pentaho sources file, a copy of the Tomcat source files, and one or more&amp;nbsp;directories&amp;nbsp;for each bi-server project. Each of these projects must be in a directory called &lt;code&gt;project-XXXX&lt;/code&gt; where XXXX is the name of the project. For example, if there are three projects named &quot;client1&quot;, &quot;client2&quot;, and &quot;testing&quot; there should be three directories called &lt;code&gt;project-client1&lt;/code&gt;, &lt;code&gt;project-client2&lt;/code&gt;, and &lt;code&gt;project-testing.&amp;nbsp;&lt;/code&gt;When the CBF is run, two additional directories are created: a build directory called &lt;code&gt;target-build&lt;/code&gt; for the compiled bi-server, and a directory where the final bi-server is prepared for distribution called &lt;code&gt;target-dist&lt;/code&gt;.&amp;nbsp;Here is the directory&amp;nbsp;structure&amp;nbsp;of the CBF looks like:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;code&gt;&lt;br /&gt;
cbf&lt;/code&gt;&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;code&gt;│&lt;br /&gt;
├── pentaho&lt;br /&gt;
├── project-test&lt;br /&gt;
│&amp;nbsp;&amp;nbsp; ├── config&lt;br /&gt;
│&amp;nbsp;&amp;nbsp; ├── patches&lt;br /&gt;
│&amp;nbsp;&amp;nbsp; └── solution&lt;br /&gt;
├── target-build&lt;br /&gt;
├── target-dist&lt;br /&gt;
│&amp;nbsp;&amp;nbsp; ├── administration-console&lt;br /&gt;
│&amp;nbsp;&amp;nbsp; ├── licenses&lt;br /&gt;
│&amp;nbsp;&amp;nbsp; └── server&lt;br /&gt;
└── tomcat&lt;/code&gt;&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;code&gt;&lt;br /&gt;
&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
Every project directory has three sub directions: one for the CBF configuration (&lt;code&gt;config&lt;/code&gt;), one for the project solutions (&lt;code&gt;solutions&lt;/code&gt;), and one for any changes to be made to the bi-server (&lt;code&gt;patches&lt;/code&gt;) when it is deployed.&lt;br /&gt;
&lt;br /&gt;
When the ant script runs, the patches get applied by copying the entire patches directory on top of the root CBF directory. Therefore, in order for the patches to get applied correctly, the patches directory must mirror the structure of the root CBF directory; changes to the final bi-server need to be in a folder called &lt;code&gt;target-dist&lt;/code&gt; and changes to the project solution directory (such as changes in the solution&#39;s &lt;code&gt;system&lt;/code&gt; or &lt;code&gt;admin&lt;/code&gt; directory) need to be a &lt;code&gt;solution&lt;/code&gt; directory under a directory with the same name as the project. For example:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;project-test&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;│&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;├── config&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;├── patches&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;│ &amp;nbsp; ├── project-test&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;│ &amp;nbsp; │ &amp;nbsp; └── solution&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;│ &amp;nbsp; │ &amp;nbsp; &amp;nbsp; &amp;nbsp; └── system&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;│ &amp;nbsp; └── target-dist&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;│ &amp;nbsp; &amp;nbsp; &amp;nbsp; └── server&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;│ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ├── conf&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;│ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; └── webapps&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;│ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; └── pentaho&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;│ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ├── META-INF&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;│ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; └── WEB-INF&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;└── solution&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;b&gt;Setup&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
To download the Pentaho BI-server sources, you can use subversion:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;svn co svn://source.pentaho.org/svnroot/bi-platform-v2/tags/3.8.0-stable/&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
I renamed the folder to &quot;pentaho&quot;:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;mv 3.8.0-stable pentaho&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Download &lt;a href=&quot;http://tomcat.apache.org/download-60.cgi&quot;&gt;Tomcat&lt;/a&gt;, the &lt;a href=&quot;http://wiki.pentaho.com/download/attachments/1048909/cbf-3_7_0.zip?version=1&amp;amp;modificationDate=1292276480000&quot;&gt;CBF&lt;/a&gt;, and make the project directories.&lt;br /&gt;
&lt;br /&gt;
The main configuration for a project is located in the config direcory and is called &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;build.properties&lt;/span&gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;#######################################&lt;br /&gt;
## GENERIC PROPERTIES&lt;br /&gt;
######################################&lt;br /&gt;
&lt;br /&gt;
javac.path = /usr/bin/javac&lt;br /&gt;
&lt;br /&gt;
# Solution path. Required for compile time&lt;br /&gt;
solution.path = ~/cbf/project-test/solution&lt;br /&gt;
&lt;br /&gt;
# Solution path required for runtime. Defaults to the above value but can be different if we&#39;re&lt;br /&gt;
# deploying to another place. Should be used in WEB-INF/web.xml in the solution-path parameter&lt;br /&gt;
solution.deploy.path = NOT SET&lt;br /&gt;
&lt;br /&gt;
#accepted values: tomcat or jboss&lt;br /&gt;
server.name = tomcat&lt;br /&gt;
&lt;br /&gt;
# Tomcat 5.5 path:&lt;br /&gt;
tomcat.path = ~/cbf/tomcat&lt;br /&gt;
&lt;br /&gt;
# Copy the sample solutions to our project directory? true | false&lt;br /&gt;
copy.pentaho.samples = true&lt;br /&gt;
&lt;br /&gt;
# Java options for the run command&lt;br /&gt;
java.opts = -Xmx512m -XX:MaxPermSize=512m -Xrunjdwp:transport=dt_socket,address=8765,server=y,suspend=n&lt;br /&gt;
&lt;br /&gt;
# to allow 3.8 to build correctly&lt;br /&gt;
project.revision=3.8.0-stable&lt;br /&gt;
dependency.pentaho-reporting.revision=3.8.0-stable&lt;br /&gt;
&lt;br /&gt;
#####################################&lt;br /&gt;
## PROJECT DIRECTORIES - The defaults usually work fine&lt;br /&gt;
######################################&lt;br /&gt;
pentaho.dir = pentaho/&lt;br /&gt;
pentaho.build.dir = target-build/&lt;br /&gt;
&lt;br /&gt;
#####################################&lt;br /&gt;
## DEPLOY OPTIONS&lt;br /&gt;
######################################&lt;br /&gt;
deploy.mode = rsync&lt;br /&gt;
deploy.args = -avz --exclude &#39;.svn/&#39; --exclude &#39;*.log&#39; --exclude &#39;work/&#39; --exclude  &#39;temp_user/&#39; --exclude &#39;temp/&#39; --exclude &#39;tmp/&#39;&lt;br /&gt;
deploy.dest.server = user@localhost:/Path/To/Deploy/&lt;br /&gt;
deploy.dest.solution = user@localhost:/Path/To/Solution/&lt;br /&gt;
&lt;br /&gt;
#####################################&lt;br /&gt;
## DYNAMIC TOKENS TO BE USED AS FILTERS&lt;br /&gt;
#####################################&lt;br /&gt;
&lt;br /&gt;
DB_LOCATION = 127.0.0.1&lt;br /&gt;
DB_USER = someone&lt;br /&gt;
DB_PASSWORD = bar&lt;br /&gt;
BASE_URL = http://127.0.0.1:8080/pentaho&lt;/blockquote&gt;&lt;br /&gt;
Finally, there can be different configurations for the project. Each configuration needs its own file in teh config directory called &lt;code&gt;build-XXX.properites&lt;/code&gt;. For example, &lt;code&gt;build-testing.properties&lt;/code&gt;, or &lt;code&gt;build-production.properties&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;An Example&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
After making the appropriate changes to the context.xml for a project, it should go in this direcory:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;project-test/patches/target-dist/server/webapps/pentaho/META-INF&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
And the web.xml should go here:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;project-test/patches/target-dist/server/webapps/pentaho/WEB-INF&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;A Second Example&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The Community Dashboard Editor (CDE) uses files with the&amp;nbsp;.wcdf &amp;nbsp;extension. The bi-server cannot apply ACLs on those files without making a change to the pentaho.xml file. The pentaho.xml file is located in the solution&#39;s system folder, but when the CBF compiles the bi-server, the solution system folder is written over. Any project specific changes needed in pentaho.xml must be put in the patches directory. So make the diretory, make a copy of the pentaho.xml file:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;mkdir patches/project-test/solution/system/&lt;br /&gt;
cp ./solution/system/pentaho.xml patches/project-test/solution/system/&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
and make the following change in patches/project-test/solution/system/pentaho.xml:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;lt;acl-files&amp;gt; xaction,url,prpt,xdash,xcdf&lt;b&gt;,wcdf&lt;/b&gt;&amp;lt;/acl-files&amp;gt;&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Next time: &lt;a href=&quot;http://tigerseatgiants.blogspot.com/2011/06/touring-cbf-part-2.html&quot;&gt;Running it&lt;/a&gt;&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerseatgiants.blogspot.com/feeds/112493715285815008/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/15999985/112493715285815008' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/112493715285815008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/112493715285815008'/><link rel='alternate' type='text/html' href='http://tigerseatgiants.blogspot.com/2011/04/touring-pentaho-cbf-part-1.html' title='Touring Pentaho CBF part 1'/><author><name>Eric</name><uri>http://www.blogger.com/profile/14352579264754955766</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSGGjDKSu2LZ3In1AsMK-ke7dYjBzLGiai1N45_ZMi7QIFFF-zjOZmB-20ww4Szxr30MqDNjgv56cLqxpLOvgxvWnLP0wWI7imDqXS2WUo3OSWyptazu4RvZtBebgIw/s220/Photo+on+2010-07-29+at+16.30+%232.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15999985.post-8284782220478908644</id><published>2011-04-08T15:04:00.002-04:00</published><updated>2011-06-26T10:22:22.588-04:00</updated><title type='text'>Playing with LucidDB: namespace and users</title><content type='html'>One of the challenges (and part of the fun) of using a relatively new open source project, is useing the software despite the lack of complete documentation. The nice thing about open source is that if you have a question, there usually is a discussion board or list-serve where you can ask the creator directly. In the spirit of openness, I am posting some of little pointers about using the column based open source database &lt;a href=&quot;http://www.luciddb.org/&quot;&gt;LucidDB&lt;/a&gt; especially comparing to to MySQL. There is nothing new here, but if you come to LucidDB from MySQL there are a few (minor) gotchas that is would be nice to avoid. So here is a post about the LucidDB namespace and users. (BTW, LucidDB&#39;s approach to namespace and users should be applicable to many databases) &lt;br /&gt;
&lt;br /&gt;
LucidDB is a column-store database designed for data warehousing and business intelligence. It is open source, and has a growing community, including a new&amp;nbsp;corporate&amp;nbsp;sponsor: &lt;a href=&quot;http://www.dynamobi.com/&quot;&gt; Dynamo BI&lt;/a&gt;. Column-store databases are faster than row-store databases when executing the kinds of queries that are common in data warehouses. There are a number of speed comparisons of LucidDB on the web, and it always does rather well. Additionally, Lucid as a number of interesting features such as the ability to connect to other databases (and even Hadoop!) and run queries on the remote database. &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Navigation and basic interaction:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Installing LucidDB is pretty easy, and there are directions on the LudicDB site, so let&#39;s start with some basic navigation, and compare it to MySQL.&lt;br /&gt;
&lt;br /&gt;
In MySQL, the highest level of a namespace is the &quot;database.&quot; So a single project might have a single database, but there might be other databases running on the same MySQL instance. Any table can be referred to by its qualified name as in:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;select * from databaseName.tableName&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
When you refer to a table without a database name, MySQL will assume you are referring to the presently used database. This is equivalent to the above query. &lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;use databaseName;&lt;br /&gt;
select * from tableName;&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
The highest level of the LucidDB namespace is &quot;catalog&quot; and under catalog is &quot;schema.&quot;  (I think this is closer to the SQL standard than MySQL.) Here is an example of a LucidDB query with a qualified name:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;select * from catalogName.schamaName.tableName&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Like MySQL, LucidDB assumes the present catalog and schema when you refer to a table without a catalog and schema. You can change catalog or schema in LucidDB by using the &quot;SET&quot; command (&lt;i&gt;Note the single quotes around the catalog and schema names!&lt;/i&gt;): &lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;set catalog &#39;catalogName&#39;;&lt;br /&gt;
set schema &#39;schemaName&#39;;&lt;br /&gt;
select * from tableName;&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
If you get lost, MySQL has a function to tell you what database you are in:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;select database();&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
LucidDB does not have an equivalent function (though you could write one if you want). Instead, you must query one of the special &lt;a href=&quot;http://pub.eigenbase.org/wiki/LucidDbSystemViews&quot;&gt;systems views&lt;/a&gt;. These views expose information about the state of the system. For the current catalog and current schema, you can query the user_session_parameters view to get both:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;select * from LOCALDB.sys_root.user_session_parameters where param_name in (&#39;schemaName&#39;, &#39;catalogName&#39;);&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
You can use the same system view to get a lot of information about your current session as well. &lt;br /&gt;
&lt;br /&gt;
In Mysql, the &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.0/en/show.html&quot;&gt;SHOW&lt;/a&gt; command is useful to see structure of the database (and a list of available databases). For example:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;SHOW databases;&lt;br /&gt;
SHOW TABLES;&lt;br /&gt;
SHOW VIEWS;&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
(PostgresQL has its own commands: \dt to show tables). To get similar information from LucidDB you must again go to the systems views. The view contain all the information about tables, views, triggers, databases, etc. Refer to &lt;a href=&quot;http://pub.eigenbase.org/wiki/LucidDbSystemViews&quot;&gt;this link&lt;/a&gt; for details about all the information you can see, but here are some examples:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;SELECT * FROM sys_root.DBA_SCHEMAS;&lt;br /&gt;
SELECT * FROM sys_root.DBA_TABLES;&lt;br /&gt;
SELECT * FROM sys_root.DBA_VIEWS;&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Creating users&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
When you install LucidDB, there is a default administrative user called &quot;sa&quot; with no password. You can log into LucidDB and create a new user, and set the user&#39;s default schema:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;create or replace user &quot;sa&quot; identified by &#39;aGoodPassword&#39;;&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Or create a new user:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;create user &quot;userName&quot; identified by &#39;aBetterPassword&#39; default schema test_schema;&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Lastly, there are a two useful systems views that have information about users, DBA_USERS and DBA_ROLES. However, they are only available in the (yet) unreleased version 0.9.4.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;As a side note, it appears that you can set up LudidDB to use JAAS, but the documentation is unclear (to me), and I have not tried it.&lt;/i&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerseatgiants.blogspot.com/feeds/8284782220478908644/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/15999985/8284782220478908644' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/8284782220478908644'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/8284782220478908644'/><link rel='alternate' type='text/html' href='http://tigerseatgiants.blogspot.com/2011/04/playing-with-luciddb-namespace-and.html' title='Playing with LucidDB: namespace and users'/><author><name>Eric</name><uri>http://www.blogger.com/profile/14352579264754955766</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSGGjDKSu2LZ3In1AsMK-ke7dYjBzLGiai1N45_ZMi7QIFFF-zjOZmB-20ww4Szxr30MqDNjgv56cLqxpLOvgxvWnLP0wWI7imDqXS2WUo3OSWyptazu4RvZtBebgIw/s220/Photo+on+2010-07-29+at+16.30+%232.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15999985.post-8865263722293402580</id><published>2011-03-17T09:48:00.000-04:00</published><updated>2011-03-17T09:48:37.297-04:00</updated><title type='text'>Last note on the impossible PDI pivot</title><content type='html'>Here is a &lt;a href=&quot;http://www.ibridge.be/wp-trackback.php?p=194&quot;&gt;blog post by Matt Casters&lt;/a&gt;, the founder of Kettle (which was rebranded as Pentata Data Integration). In it he is un-pivoting data. That is to say, doing the opposite of what I did in the &lt;a href=&quot;http://tigerseatgiants.blogspot.com/2011/03/when-learning-new-tool-it-is-always-fun.html&quot;&gt;last two posts&lt;/a&gt;. I solved the problem of knowing how many columns to create by hard coding 60. He uses a more elegant solution of analyzing the data in one transformation and then using the results of the analysis in a second one and using the metadata injection step. I suspect that following his lead I could also use the metadata injection step and a separate analysis transformation to dynamically set the number of columns. But first I have to study the metadata injection step to see how it works.</content><link rel='replies' type='application/atom+xml' href='http://tigerseatgiants.blogspot.com/feeds/8865263722293402580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/15999985/8865263722293402580' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/8865263722293402580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/8865263722293402580'/><link rel='alternate' type='text/html' href='http://tigerseatgiants.blogspot.com/2011/03/last-note-on-impossible-pdi-pivot.html' title='Last note on the impossible PDI pivot'/><author><name>Eric</name><uri>http://www.blogger.com/profile/14352579264754955766</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSGGjDKSu2LZ3In1AsMK-ke7dYjBzLGiai1N45_ZMi7QIFFF-zjOZmB-20ww4Szxr30MqDNjgv56cLqxpLOvgxvWnLP0wWI7imDqXS2WUo3OSWyptazu4RvZtBebgIw/s220/Photo+on+2010-07-29+at+16.30+%232.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15999985.post-8011579419990159480</id><published>2011-03-16T14:20:00.110-04:00</published><updated>2011-04-08T11:24:42.206-04:00</updated><title type='text'>Pentaho PDI example Part II: Doing the impossible</title><content type='html'>Continuing from the &lt;a href=&quot;http://tigerseatgiants.blogspot.com/2011/03/when-learning-new-tool-it-is-always-fun.html&quot;&gt;last post&lt;/a&gt;, we now have a list in the format of &quot;symbol&quot;, &quot;date&quot;, &quot;amount&quot; and we want to pivot the data. The normal way to pivot would be to hard code each column name and use the Pivot step. However, we need something a little more dynamic because the list of ticker symbols are in the config file and so are not know until run time. So we will cheat (based on an idea from the &lt;a href=&quot;http://forums.pentaho.com/showthread.php?80610-Dynamic-Denomormalizer&amp;p=251934#post251934&quot;&gt;Pentaho Users Forum&lt;/a&gt;). The output file will look like pivoted data, but the Kettle transformation, and will (semi)-dynamic, but will not be an actual dynamic pivot. But first, the data needs to cleaned. &lt;br /&gt;
&lt;br /&gt;
The same parameters were used for all symbols, so all the symbols &lt;i&gt;should&lt;/i&gt; have the same set of dates. However, there are some dates that appear in the date set of a single symbol list. This is usually the stock&#39;s inception date and first trade. A second date problem is that there are no prices for dates before a stock started trading. For example, if we ask for monthly amounts for 2000-2010, but a stock was first offered on April 8, 2008, there is no data at all from 2000-2008 and the first price is April 8, 2008 instead of the first trading day of that month. No other stocks have prices on April 8, 2008. That date must be cut out, and nulls or 0 must be put in for all the dates from 2000 to April 2008. &lt;br /&gt;
&lt;br /&gt;
To solve the first problem, we can do a cartesian join between all possible dates, and all symbols.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfzM7I4qBE82f5iKStDo1z5UFFoBXJQNHHK24THkc5Snx8zSPML2Z6-2P-mUrGzCpYu_RNJRaJWDZz5__HwGeipwsEyQ2yMT95ZrQ9WVqjpczflEZN7iOgUrYFNBzkx6R7TMcE/s1600/Screen+shot+2011-03-16+at+2.05.54+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;400&quot; width=&quot;185&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfzM7I4qBE82f5iKStDo1z5UFFoBXJQNHHK24THkc5Snx8zSPML2Z6-2P-mUrGzCpYu_RNJRaJWDZz5__HwGeipwsEyQ2yMT95ZrQ9WVqjpczflEZN7iOgUrYFNBzkx6R7TMcE/s400/Screen+shot+2011-03-16+at+2.05.54+PM.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
From the filtering step (last step discussed in the last post), two streams are created. One stream will be used to get the dates, the other for the symbols. The Pentaho &quot;Group by&quot; step can be used to get the distinct values:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlXQeaYzn1v8CtCtT1tYWCBChX6jiVoHD68FVsEfkpffKst0eVPDiDbA87nrxKchxoNZHbr9G2ers0Siw7r-Z_xOvdw8Z6yfhEVCFcN2irw6ZdM25NtF2mDGrJxlU63CsxjZZ6/s1600/Screen+shot+2011-03-16+at+2.09.30+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;400&quot; width=&quot;362&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlXQeaYzn1v8CtCtT1tYWCBChX6jiVoHD68FVsEfkpffKst0eVPDiDbA87nrxKchxoNZHbr9G2ers0Siw7r-Z_xOvdw8Z6yfhEVCFcN2irw6ZdM25NtF2mDGrJxlU63CsxjZZ6/s400/Screen+shot+2011-03-16+at+2.09.30+PM.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
The same is done for the symbols, and then the &quot;cartesian join&quot; step produces all possible combinations of dates and symbols. To get the prices, we do another stream lookup on a third stream coming from the filtering step. (I put a dummy step between the filter and the lookup for layout) We will be putting a &quot;0&quot; for the price of a stock at any unknown date. &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisNxwifgQ9CyuttJdRIQfNRyhEadpoopdXqnKehe7ahx2OLG4U3xCMk0WA3qE6y_58l4dtGCjfl2mTVFCtHBEhMT3hWMdBi7sekxNldOyjvVplutwhE7hxrqnHOxb-qOpWdQ0c/s1600/Screen+shot+2011-03-16+at+2.15.15+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;282&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisNxwifgQ9CyuttJdRIQfNRyhEadpoopdXqnKehe7ahx2OLG4U3xCMk0WA3qE6y_58l4dtGCjfl2mTVFCtHBEhMT3hWMdBi7sekxNldOyjvVplutwhE7hxrqnHOxb-qOpWdQ0c/s400/Screen+shot+2011-03-16+at+2.15.15+PM.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Before we start with the real work of pivoting, we need a stream without the extraneous dates. To get rid of the unwanted dates, such as the inception trading date, we will take a copy of the stream of all dates, sort them, and use the &quot;Group by&quot; step.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQW1CYWLISpjIxqmzyMlnp4JXs6ZFbLYxvnwZS4uyjbz01eX9PVL47PVuQV2-vSqFrCLRMZBdX-MlGcZAfv1FfmiWOXa_tEXM2XX1sLiYdtKgPwU4MxTgtc2IQWWTo63n4eFi4/s1600/Screen+shot+2011-03-16+at+2.22.27+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;91&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQW1CYWLISpjIxqmzyMlnp4JXs6ZFbLYxvnwZS4uyjbz01eX9PVL47PVuQV2-vSqFrCLRMZBdX-MlGcZAfv1FfmiWOXa_tEXM2XX1sLiYdtKgPwU4MxTgtc2IQWWTo63n4eFi4/s400/Screen+shot+2011-03-16+at+2.22.27+PM.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
The &quot;Group by&quot; step is used to get the minimum day for each month/year combination. This will cut out extra dates, such as the April 8 example above.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi87HRhIBnA8KYEQBIrTSROHN_XvkmQm0FBq-zqPO8pUWZipd6ot_vRbc4MjcBLqNh178RTPfNXjzlXvkF1pMELaiR6FzFL_Zw7brKqM66ABilwWXx-oufXTqEPoXcMknzgoBEu/s1600/Screen+shot+2011-03-16+at+2.20.04+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;358&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi87HRhIBnA8KYEQBIrTSROHN_XvkmQm0FBq-zqPO8pUWZipd6ot_vRbc4MjcBLqNh178RTPfNXjzlXvkF1pMELaiR6FzFL_Zw7brKqM66ABilwWXx-oufXTqEPoXcMknzgoBEu/s400/Screen+shot+2011-03-16+at+2.20.04+PM.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Next, a little Javascript to create a date from the year, month and day columns:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPY-7JyYcbexnATLYQKRscEQUAw82l4k-JNCBEeGULW4m07cnns4b-_yq-TufBX3o4WYWdKNC5pZ9V5_RID0YJYnQd1bdUzeUx41aWzR_EJbLa6uleQwwHplQwOvXjN-Qcgtkj/s1600/Screen+shot+2011-03-16+at+2.21.55+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;398&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPY-7JyYcbexnATLYQKRscEQUAw82l4k-JNCBEeGULW4m07cnns4b-_yq-TufBX3o4WYWdKNC5pZ9V5_RID0YJYnQd1bdUzeUx41aWzR_EJbLa6uleQwwHplQwOvXjN-Qcgtkj/s400/Screen+shot+2011-03-16+at+2.21.55+PM.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
We will return to this stream of good dates after we start the magic pivot.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;The Pivot:&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
We can&#39;t really do a pivot  with arbitrary columns, so we cheat a little. Once the stream is sorted by date and symbol, we can join all the symbols in one comma delimited field, and the prices in another. Because we made sure that every symbol has a value for every date, and the stream is ordered by symbols and date, these combined fields will have the values for each date and the symbols for each value in the same order. Here is the step:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF8Dr3u_pwDGTlzYBj9905FsfP4mU_SPMFBNXbKU1t7mQES9kno-cExe_0gXKt5iTM0eghL2SjGclTZWF5OGRw2jHqF-R7FJzOE7_eB2baIaMtv5shkHezTNw8atLj3bhvttf1/s1600/Screen+shot+2011-03-16+at+2.33.37+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;391&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF8Dr3u_pwDGTlzYBj9905FsfP4mU_SPMFBNXbKU1t7mQES9kno-cExe_0gXKt5iTM0eghL2SjGclTZWF5OGRw2jHqF-R7FJzOE7_eB2baIaMtv5shkHezTNw8atLj3bhvttf1/s400/Screen+shot+2011-03-16+at+2.33.37+PM.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
And here is a sample of the output:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWitDzWIegg1lHCzVV2GmVxNpifofh7yWR4F6hl6QURP8UTLm36MVhJrE3MPcGf_dadoEAdxmN_xxY-UvaooCV5MEU5kNFT9yi7QQKWbitXqGQUlpemy7-PdJRAQQjKprQRnzo/s1600/Screen+shot+2011-03-16+at+2.37.25+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;80&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWitDzWIegg1lHCzVV2GmVxNpifofh7yWR4F6hl6QURP8UTLm36MVhJrE3MPcGf_dadoEAdxmN_xxY-UvaooCV5MEU5kNFT9yi7QQKWbitXqGQUlpemy7-PdJRAQQjKprQRnzo/s400/Screen+shot+2011-03-16+at+2.37.25+PM.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
If we can align the symbol cell with the data cell, and then split them on the commas to create new fields, we would almost have our pivot. The symbols will be the first row, the values the rest. If the output file does not print the real headers it will look like we performed an arbitrary pivot. &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOOCwslJXkjGtXWWAYbSKhz_TQ0juvH7I2Fg2TDzdUlXz9EpJ5QI2lv-UxWKAgPRlfb_2TjhPt8PTZkwuKPpm5CXJ7ZJppHzx56JJI_VSW9bymYUJSVXrlvoFWRgwCeGLWuG7q/s1600/Screen+shot+2011-03-16+at+2.46.50+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;267&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOOCwslJXkjGtXWWAYbSKhz_TQ0juvH7I2Fg2TDzdUlXz9EpJ5QI2lv-UxWKAgPRlfb_2TjhPt8PTZkwuKPpm5CXJ7ZJppHzx56JJI_VSW9bymYUJSVXrlvoFWRgwCeGLWuG7q/s400/Screen+shot+2011-03-16+at+2.46.50+PM.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
The split is done to create fields with meaningless names. The two streams can be combined as long as both the symbol stream and the value streams use the same field names. I used 60 fields so I can use up to 60 symbols. Here is the split for the symbols:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ5bSMpFpBHHduRwfB015QhIAPfRS_Sijccbqag15dhC_v93YoVnExwrNA8K7gZWipdiEna1ibmhFTcaErlVywiDUP2B6GJkjRa_4tCqCKwndEf34u8DLQT6LfKVPEVbmxUAC-/s1600/Screen+shot+2011-03-16+at+2.47.45+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;388&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ5bSMpFpBHHduRwfB015QhIAPfRS_Sijccbqag15dhC_v93YoVnExwrNA8K7gZWipdiEna1ibmhFTcaErlVywiDUP2B6GJkjRa_4tCqCKwndEf34u8DLQT6LfKVPEVbmxUAC-/s400/Screen+shot+2011-03-16+at+2.47.45+PM.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Now that the prices are grouped by date, we can go back do a stream lookup with the stream of good dates. This will make sure that we get values only for dates that we want. &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpuPnDNz02-XaPiHRMUxT7u7TlHigL8PmryRCVpQOdzSQ4QGzgiMUmx4Tg7hq19cv5Gy16FWgWm4l8erxWrLyfrfry1DJut4iYFnV1QqI9UIRZdXN7Y-WB6g75zpRVNHmV6T4Z/s1600/Screen+shot+2011-03-16+at+2.51.46+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;353&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpuPnDNz02-XaPiHRMUxT7u7TlHigL8PmryRCVpQOdzSQ4QGzgiMUmx4Tg7hq19cv5Gy16FWgWm4l8erxWrLyfrfry1DJut4iYFnV1QqI9UIRZdXN7Y-WB6g75zpRVNHmV6T4Z/s400/Screen+shot+2011-03-16+at+2.51.46+PM.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Add a constant and the &quot;Group by&quot; step can be used to limit the symbol stream to 1 row. Append the two streams together and output the results (without headers). If the resulting file it imported into a spreadsheet, the first row will act as headers for the data:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1P6dFC3tC0GOKvAIUN5Gz5JJ6EDQFzlx3OjYul5rYrsYQ1lgKWR7FtTeHRdTkctrDQtKJSJHwbRVQ-cM1tPI7yXqQhcfPsTFOvn-NbOLPYefXbC3K7VbJ_jCGtf3eZGOUV5Md/s1600/Screen+shot+2011-03-16+at+2.58.01+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;202&quot; width=&quot;380&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1P6dFC3tC0GOKvAIUN5Gz5JJ6EDQFzlx3OjYul5rYrsYQ1lgKWR7FtTeHRdTkctrDQtKJSJHwbRVQ-cM1tPI7yXqQhcfPsTFOvn-NbOLPYefXbC3K7VbJ_jCGtf3eZGOUV5Md/s400/Screen+shot+2011-03-16+at+2.58.01+PM.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
There is a &lt;a href=&quot;http://jira.pentaho.com/browse/PDI-5422&quot;&gt;Jira request&lt;/a&gt; to do a arbitrary pivot by changing the metadata. Until then, this little trick is a good work around.</content><link rel='replies' type='application/atom+xml' href='http://tigerseatgiants.blogspot.com/feeds/8011579419990159480/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/15999985/8011579419990159480' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/8011579419990159480'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/8011579419990159480'/><link rel='alternate' type='text/html' href='http://tigerseatgiants.blogspot.com/2011/03/pentaho-pdi-example-part-ii-doing.html' title='Pentaho PDI example Part II: Doing the impossible'/><author><name>Eric</name><uri>http://www.blogger.com/profile/14352579264754955766</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSGGjDKSu2LZ3In1AsMK-ke7dYjBzLGiai1N45_ZMi7QIFFF-zjOZmB-20ww4Szxr30MqDNjgv56cLqxpLOvgxvWnLP0wWI7imDqXS2WUo3OSWyptazu4RvZtBebgIw/s220/Photo+on+2010-07-29+at+16.30+%232.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfzM7I4qBE82f5iKStDo1z5UFFoBXJQNHHK24THkc5Snx8zSPML2Z6-2P-mUrGzCpYu_RNJRaJWDZz5__HwGeipwsEyQ2yMT95ZrQ9WVqjpczflEZN7iOgUrYFNBzkx6R7TMcE/s72-c/Screen+shot+2011-03-16+at+2.05.54+PM.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15999985.post-5356504478681287900</id><published>2011-03-15T16:31:00.006-04:00</published><updated>2011-04-18T15:05:06.578-04:00</updated><title type='text'>Pentaho PDI example</title><content type='html'>The PDI task is to get the historical numbers for some stocks from Yahoo&#39;s REST-ful service and format the data so the column headers are the ticker symbol. Each row will be the date and the prices for each ticker. &lt;br /&gt;
&lt;br /&gt;
Part I: getting the data&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPb5Zlk3vIDkd5yqK89nyNOod4QBQ4XCTFxj17X4qTOJ8H9QJnI1BlJdBTVaAs_qMo0pO3MOMPVkChPM-zriBcex8GItARDjHeqmFJ1Oz0rmRY8Mut70WNRMa0enpbwkVP4R6z/s1600/start.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;89&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPb5Zlk3vIDkd5yqK89nyNOod4QBQ4XCTFxj17X4qTOJ8H9QJnI1BlJdBTVaAs_qMo0pO3MOMPVkChPM-zriBcex8GItARDjHeqmFJ1Oz0rmRY8Mut70WNRMa0enpbwkVP4R6z/s400/start.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
The first part of the transformation reads the configuration from an XML file: a list of ticker symbols to get, and the parameters for the Yahoo service. The Yahoo REST parameters need to be the same for all the symbols, but are only in the config.xml file one. To combine the single set of parameters with the list of symbols, the config is read twice. The first stream gets the list of symbols, and a second stream gets the parameters. The PDI stream lookup step combines the two streams. Because there is only one set, all the symbols get the same parameters&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrMJAfsj0wMVoOGJvGWEyeaGxw5gGF549tARlYXvTCQvRsUiaf9u3GvvgnZBHYZ4UY_PyxnC-fb5Qv1o-hlm4YTbR5I6pxIS6HFApyWsIixMl14LjOuOdJYFPMg1bVOFoY1PZv/s1600/Screen+shot+2011-03-15+at+4.02.33+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrMJAfsj0wMVoOGJvGWEyeaGxw5gGF549tARlYXvTCQvRsUiaf9u3GvvgnZBHYZ4UY_PyxnC-fb5Qv1o-hlm4YTbR5I6pxIS6HFApyWsIixMl14LjOuOdJYFPMg1bVOFoY1PZv/s400/Screen+shot+2011-03-15+at+4.02.33+PM.png&quot; width=&quot;344&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
The result of the stream lookup step is fed to the HTTP client step. This step does the REST lookup of the Yahoo server. The base URL is http://ichart.finance.yahoo.com/table.csv and with the parameters it looks something like this: &lt;br /&gt;
&lt;blockquote&gt;http://ichart.finance.yahoo.com/table.csv?s=VFINX&amp;amp;a=03&amp;amp;b=6&amp;amp;c=2006&amp;amp;d=02&amp;amp;e=29&amp;amp;f=2011&amp;amp;g=m&amp;amp;ignore=.csv&lt;/blockquote&gt;The result of the RESTfull lookup is a csv file, but the HTTP client step puts the entire result (and so the entire text file) in one field called &quot;Result.&quot; To use the data, we need to parse up the csv file so that each row in the file is one row in the transformation, and each cell is a column. The first step is to split the one row into multiple rows, each with one line of the csv file. To do that we use the &quot;split field to rows&quot; step. I was not sure what the line delimiter was coming out of Yahoo (or even if it was set by Yahoo, or the Http Client Step), so I used the Java internal variable to set it. &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCKVUxhUVfJj5Nexsbj5jgB1D1Vrtdr0YR3IYpy2apms0VfUHiyccnkZz7EUF3XOINFibYQt8aWeN8bhkAEFG8WC9QZsyIkoQNlSLU-dMecfZyArDBsUJMHBqcl-6jNS1CnfUy/s1600/Screen+shot+2011-03-15+at+3.48.16+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;142&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCKVUxhUVfJj5Nexsbj5jgB1D1Vrtdr0YR3IYpy2apms0VfUHiyccnkZz7EUF3XOINFibYQt8aWeN8bhkAEFG8WC9QZsyIkoQNlSLU-dMecfZyArDBsUJMHBqcl-6jNS1CnfUy/s320/Screen+shot+2011-03-15+at+3.48.16+PM.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Now we have a row in the transformation for each row in the CSV that came from Yahoo. We still need to get one field in the transformation for each cell in the CSV file. Using &quot;Split field&quot; step to split on a comma takes care of that. &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihkxmBeaEwzn1bZMYTS0UZy8fLLwvr4u5ErHqB1cNdemXxGDAz1FK4jSJ4QJcPehZnKtz0YfKBJ-uXGrLpa-Pi5xQKXwSRVSY_P71oq3Nx6L7ZPHWETwjQZaAulwJblTUHFvcp/s1600/Screen+shot+2011-03-15+at+3.54.10+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;231&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihkxmBeaEwzn1bZMYTS0UZy8fLLwvr4u5ErHqB1cNdemXxGDAz1FK4jSJ4QJcPehZnKtz0YfKBJ-uXGrLpa-Pi5xQKXwSRVSY_P71oq3Nx6L7ZPHWETwjQZaAulwJblTUHFvcp/s320/Screen+shot+2011-03-15+at+3.54.10+PM.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
We don&#39;t need the header from Yahoo, so that is filtered out.&lt;br /&gt;
&lt;br /&gt;
The results from Yahoo has the opening price, closing price, high, and low but we only want one price. The one we want is set in the configuration file. The easiest way to select the price is to use a Javascript step. The script has a case statement based on the &quot;value_to_use&quot; field from the original XML config file. &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2pL3gJS4dmcrn1gTAYlODu6hfR67Z5EOcYOkqtkUHabf1jnvPycswoIlRh_DpOPFROdDTXKUemDidTDdl7NI2wNx1JSirpSNv7LxC3b6gDLHLBW6Ge82IeAK4ku4r03iMmbe-/s1600/Screen+shot+2011-03-15+at+4.04.30+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;282&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2pL3gJS4dmcrn1gTAYlODu6hfR67Z5EOcYOkqtkUHabf1jnvPycswoIlRh_DpOPFROdDTXKUemDidTDdl7NI2wNx1JSirpSNv7LxC3b6gDLHLBW6Ge82IeAK4ku4r03iMmbe-/s400/Screen+shot+2011-03-15+at+4.04.30+PM.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Now we have field for the symbol (fron the config), the amount (from the Javascript step) and the date (from Yahoo). To make debugging easier, it would be nice to clear out extraneous info, so I filter out out all the unneeded columns. I have read that the Select/Rename step can be slow, but the REST calls are far slower, so that is not a worry here:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYOpKJW6CMVzOyirl1lyYcip0iZZsIIl2nncS5x86B-3XpZE-e_1_2kn02IqIkAkFw9BGWDwerooAv3RgQsrd2q2CdmD2oIeaYAaS0erKr67pJmx4awNtpvfYaGjWVXGm7_TCI/s1600/Screen+shot+2011-03-15+at+4.11.35+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;184&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYOpKJW6CMVzOyirl1lyYcip0iZZsIIl2nncS5x86B-3XpZE-e_1_2kn02IqIkAkFw9BGWDwerooAv3RgQsrd2q2CdmD2oIeaYAaS0erKr67pJmx4awNtpvfYaGjWVXGm7_TCI/s400/Screen+shot+2011-03-15+at+4.11.35+PM.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
This step can also turn the date field into a DATE data type. This is needed because it came from Yahoo (and the splits) as a STRING:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2V3WRwn3ls6_K4r09aNDjHSrv-e7rrgX2-0L0AVc7Ar925I3S2WPItA2C5Gs2yOBOHZljz-zDlAgiz2K8lzAF5UGPrVJ309iuFNE5c7q9HOTf6wUMLPxoaN4JAxqf9XbBpu8c/s1600/Screen+shot+2011-03-15+at+4.13.54+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;147&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2V3WRwn3ls6_K4r09aNDjHSrv-e7rrgX2-0L0AVc7Ar925I3S2WPItA2C5Gs2yOBOHZljz-zDlAgiz2K8lzAF5UGPrVJ309iuFNE5c7q9HOTf6wUMLPxoaN4JAxqf9XbBpu8c/s400/Screen+shot+2011-03-15+at+4.13.54+PM.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Now we can take a look at the results using the PDI Preview (in Spoon):&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5VhXoMEw1qxIqbWbECj5oujelyscf7gX0VgbsMg_71TvayDKlZJe2twkmW0_tcMvHu_DqXHwS2LdH7g4ffdJgz_dL_z4q8zRqPND5wRV8UKToZ8VIP62gCiQEt-7BOunSZeu7/s1600/Screen+shot+2011-03-15+at+4.15.26+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;373&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5VhXoMEw1qxIqbWbECj5oujelyscf7gX0VgbsMg_71TvayDKlZJe2twkmW0_tcMvHu_DqXHwS2LdH7g4ffdJgz_dL_z4q8zRqPND5wRV8UKToZ8VIP62gCiQEt-7BOunSZeu7/s400/Screen+shot+2011-03-15+at+4.15.26+PM.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
All and all, it was pretty quick and easy to make. Next post I&#39;ll show how to do the seemingly impossible step of a data pivot in PDI with arbitrary columns.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;click &lt;a href=&quot;http://tigerseatgiants.blogspot.com/2011/03/pentaho-pdi-example-part-ii-doing.html&quot;&gt;here&lt;/a&gt; for Part 2&lt;/i&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerseatgiants.blogspot.com/feeds/5356504478681287900/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/15999985/5356504478681287900' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/5356504478681287900'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/5356504478681287900'/><link rel='alternate' type='text/html' href='http://tigerseatgiants.blogspot.com/2011/03/when-learning-new-tool-it-is-always-fun.html' title='Pentaho PDI example'/><author><name>Eric</name><uri>http://www.blogger.com/profile/14352579264754955766</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSGGjDKSu2LZ3In1AsMK-ke7dYjBzLGiai1N45_ZMi7QIFFF-zjOZmB-20ww4Szxr30MqDNjgv56cLqxpLOvgxvWnLP0wWI7imDqXS2WUo3OSWyptazu4RvZtBebgIw/s220/Photo+on+2010-07-29+at+16.30+%232.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPb5Zlk3vIDkd5yqK89nyNOod4QBQ4XCTFxj17X4qTOJ8H9QJnI1BlJdBTVaAs_qMo0pO3MOMPVkChPM-zriBcex8GItARDjHeqmFJ1Oz0rmRY8Mut70WNRMa0enpbwkVP4R6z/s72-c/start.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15999985.post-2388123575839104655</id><published>2011-03-11T11:02:00.000-05:00</published><updated>2011-03-11T11:02:12.625-05:00</updated><title type='text'>Why I like Amazon AWS (Theoretically)</title><content type='html'>When I say I like Amazon &lt;a href=&quot;http://aws.amazon.com/&quot;&gt;AWS&lt;/a&gt; (the whole Amazon cloud services) &quot;theoretically,&quot; I mean that I have not actually used it (yet). Instead, I like the design and the possibilities the service creates. &lt;br /&gt;
&lt;br /&gt;
First, some background. I have had been using a virtual computing service for many years. I had a virtual machine with &lt;a href=&quot;http://www.linode.com/&quot;&gt;Linode&lt;/a&gt; before they were using Xen (it was Usermode Linux back then, which was the cheap man&#39;s virtualization by running a kernel in usermode). That is probably 7 years or more. I have always been happy with their service and uptime. I virtualized my personal mail server, and freed up space in my living room the first chance I got. Having a virtual server is great. because I love&amp;nbsp;concentrating&amp;nbsp;on the OS and application while letting someone else worry about the hardware.&lt;br /&gt;
&lt;br /&gt;
I have seen a number of&amp;nbsp;performance&amp;nbsp;tests&amp;nbsp;comparing&amp;nbsp;AWS, Linode and the &lt;a href=&quot;http://www.rackspace.com/managed_hosting/private_cloud/index.php&quot;&gt;Rackspace&lt;/a&gt; virtual machines. Linode often comes out on top, and Amazon often near the bottom. I never understood why anyone&amp;nbsp;would&amp;nbsp;choose the Amazon service over Linode to host a virtual machine. Plus the virtual machine&amp;nbsp;service&amp;nbsp;&lt;a href=&quot;http://aws.amazon.com/ec2/&quot;&gt;EC2&lt;/a&gt; did not save the server&#39;s state when it crashes or after a&amp;nbsp;shutdown (though that is different now). That made no sense to me. But Amazon&#39;s service is really something more than virtual servers. AWS is not a virtual machine service, it is a virtual&amp;nbsp;infrastructure&amp;nbsp;service that&amp;nbsp;contains&amp;nbsp;machines. &lt;br /&gt;
&lt;br /&gt;
It it like this: You can write a program to respond to HTTP and serve up web pages. Or, you can use a prewritten program (such as Apache) that is dedicated to responding to HTTP and give that program&amp;nbsp;directions (HTML pages)&amp;nbsp;for service up a website. If the website is complicated and dynamic, you could create an application that talks to the&amp;nbsp;web server, and can &lt;i&gt;dynamically&lt;/i&gt; create the HTML pages, or you could use a pre-written program (the PHP&amp;nbsp;interpreter) and just give it directions for dynamically creating the website (a bunch of php files). The php files can be plopped on any Apache instance and run (you might need to configure Apache, but that is a separate job from the web site creation).&lt;br /&gt;
&lt;br /&gt;
In Java, you create a bunch of classes that you can bundle together as a JAR or WAR file and then hand that bundle to a Java virtual machine or give it to a J2EE container to run. The JVM or JVM + J2EE container takes care of instantiating the classes and running the program. If you need more processing power, you can hand that same JAR or WAR file to many Java virtual machines or J2EE containers and have the program run many times without changing it. Complicated arrangements or clusters of Java programs can be created that comunicate to each other to balance load. These programs do not hold data, they loose their state when they shutdown or crash. The state of the program is stored&amp;nbsp;externally to the Java program&amp;nbsp;in a database or on a file system.&lt;br /&gt;
&lt;br /&gt;
The Amazon EC2 is like the Java virtual machine. You can create an image of a system made up of a set of applications (shell scripts, Java programs, .Net files, Apache, Tomcat) plus a configurations of the OS (I like Linux). And then hand that image to Amazon. The important data is stored in another system (an outside database, some NoSQL thing such as &lt;a href=&quot;http://aws.amazon.com/simpledb/&quot;&gt;SampleDB&lt;/a&gt;, or Amazon&#39;s persistant storage &lt;a href=&quot;http://aws.amazon.com/ebs/&quot;&gt;EBS&lt;/a&gt;), but the rest of the state of the system is not really&amp;nbsp;important. You don&#39;t patch an EC2 instance like I have patched my Linode boxes or my real live servers. You don&#39;t patch a running J2EE server with new libraries. You update the images (be they Jar files, War files, or AMI Amazon Images) and roll it out.&lt;br /&gt;
&lt;br /&gt;
When I realized that, then AWS made sense and seemed great. I would imaging building a system of interconnected services that run on different EC2 instances. I could configure them as needed and roll them out to be instantiated as needed.</content><link rel='replies' type='application/atom+xml' href='http://tigerseatgiants.blogspot.com/feeds/2388123575839104655/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/15999985/2388123575839104655' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/2388123575839104655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/2388123575839104655'/><link rel='alternate' type='text/html' href='http://tigerseatgiants.blogspot.com/2011/03/why-i-like-amazon-aws-theoretically.html' title='Why I like Amazon AWS (Theoretically)'/><author><name>Eric</name><uri>http://www.blogger.com/profile/14352579264754955766</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSGGjDKSu2LZ3In1AsMK-ke7dYjBzLGiai1N45_ZMi7QIFFF-zjOZmB-20ww4Szxr30MqDNjgv56cLqxpLOvgxvWnLP0wWI7imDqXS2WUo3OSWyptazu4RvZtBebgIw/s220/Photo+on+2010-07-29+at+16.30+%232.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15999985.post-3350398959831024329</id><published>2011-03-10T16:21:00.002-05:00</published><updated>2011-03-10T21:09:26.922-05:00</updated><title type='text'>Data Warehouse Toolkit</title><content type='html'>I started rereading Ralph Kimball&#39;s &quot;&lt;a href=&quot;http://www.amazon.com/gp/product/0471200247/ref=as_li_tf_tl?ie=UTF8&amp;tag=tigeatgia-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0471200247&quot;&gt;The Data Warehouse Toolkit: The Complete Guide to Dimensional Modeling&lt;/a&gt;&lt;img src=&quot;http://www.assoc-amazon.com/e/ir?t=tigeatgia-20&amp;l=as2&amp;o=1&amp;a=0471200247&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot; alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot; /&gt;&quot; &amp;nbsp; So far, it is as good on the second read as it is on the first. My only complaint is that the sub title is more accurate: &quot;The Complete Guide to Dimensional Modeling.&quot; The book is a great intro to dimensional modeling, with a lot of examples. Until I read it, I really did not get the point of dimensional modeling, as apposed to the entity-relationships/3rd-normal-form type modeling. I had to re-read the first chapter a few times before dimensional modeling clicked, but once it did the rest of the book was crystal clear. In fact, all the Kimball groups book I have read have been excellent--&lt;a href=&quot;http://www.amazon.com/Data-Warehouse-ETL-Toolkit-Techniques/dp/0764567578/ref=pd_sim_b_2&quot;&gt;the Data Warehouse ETL Toolkit&lt;/a&gt;, and the &lt;a href=&quot;http://www.amazon.com/Data-Warehouse-Lifecycle-Toolkit/dp/0470149779/ref=pd_sim_b_1&quot;&gt;The Data Warehouse Lifecycle Toolkit.&lt;/a&gt;&lt;span id=&quot;btAsinTitle&quot;&gt;&lt;span style=&quot;font-size: 16px; text-transform: capitalize;&quot;&gt;&lt;/span&gt;&lt;/span&gt; (I read the first edition of the DW Lifestyle toolkit, and that is a link to the 2nd edition, but I assume it is not substantially different) I recommended them to everyone who asks about dimensional modeling. I have such success using the Kimball model that I never got around to looking at the &quot;opposing&quot; data warehouse camp.&amp;nbsp; I suppose I should read something by Bill Inmom. Maybe &lt;a href=&quot;http://www.amazon.com/Corporate-Information-Factory-W-Inmon/dp/0471399612&quot;&gt;Corporate Information Factory&lt;/a&gt;?</content><link rel='replies' type='application/atom+xml' href='http://tigerseatgiants.blogspot.com/feeds/3350398959831024329/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/15999985/3350398959831024329' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/3350398959831024329'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/3350398959831024329'/><link rel='alternate' type='text/html' href='http://tigerseatgiants.blogspot.com/2011/03/data-warehouse-toolkit.html' title='Data Warehouse Toolkit'/><author><name>Eric</name><uri>http://www.blogger.com/profile/14352579264754955766</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSGGjDKSu2LZ3In1AsMK-ke7dYjBzLGiai1N45_ZMi7QIFFF-zjOZmB-20ww4Szxr30MqDNjgv56cLqxpLOvgxvWnLP0wWI7imDqXS2WUo3OSWyptazu4RvZtBebgIw/s220/Photo+on+2010-07-29+at+16.30+%232.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15999985.post-7184540179797140917</id><published>2011-03-10T15:59:00.000-05:00</published><updated>2011-03-10T15:59:39.011-05:00</updated><title type='text'>Favorite Applications--Mirth</title><content type='html'>One of my favorite applications is&amp;nbsp;&lt;a href=&quot;http://www.mirthcorp.com/community/overview&quot;&gt;Mirth&lt;/a&gt;.&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;In Healthcare IT, there is a messaging&amp;nbsp;protocol&amp;nbsp;called HL7. It can be used to send nearly any healthcare based information between systems, such as appointments made, demographics updated, insurance&amp;nbsp;information, lab results, etc. However, the protocol is not&amp;nbsp;completely&amp;nbsp;standard, and an connection between two systems (an interface) has to be configured by hand.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Mirth is an open source&amp;nbsp;application&amp;nbsp;built on the open source ESB (Enterprise Service Bus) &lt;a href=&quot;http://www.mulesoft.org/&quot;&gt;Mule&lt;/a&gt;.&amp;nbsp;It used the HL7 &lt;a href=&quot;http://hl7api.sourceforge.net/&quot;&gt;HAPI&lt;/a&gt; library--thus the name. Mirth&#39;s&amp;nbsp;main use is helping connect systems that use HL7. &amp;nbsp;But it can do much more--plain text, email, JDBC, DICOM, and so on. Any message can be&amp;nbsp;copied, altered,&amp;nbsp;disassembled, reassembled, sent on, and so on. The best part is that the UI is nice and clean, and makes setting up the connections, and processes the messages easy. You can also use Javascript to process the messages, and even create pure Java clases to proceses the message. So all that means nearly anything can be done withe the messages and the information in them. And that makes it great.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Here is a little example:&lt;/div&gt;&lt;div&gt;I had a system that sent appointment messages, but was not set up to send laterality information (right side or left side) about the appointment. So &quot;X-ray Foot&quot; instead of &quot;X-ray Left Foot&quot;. The vendor could not or would not fix it. The information was locked up in a&amp;nbsp;legacy system that did not use JDBC or ODBC--I think it was running on Cobol. &amp;nbsp;So I wrote a Java class that could telnet to its&amp;nbsp;terminal, and query its SQL&amp;nbsp;like language. After adding the Java jar to the Mirth external library folder,&amp;nbsp;I could have Mirth grab the each HL7 message, extract the appointment info, query the&amp;nbsp;original&amp;nbsp;system (via my&amp;nbsp;custom&amp;nbsp;class), &amp;nbsp;get the laterality, change the appointment type name, and send it on.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;I have numerous examples of Mirth letting me do the implausible; maybe I&#39;ll give more examples later. In all theses cases Mirth&amp;nbsp;made&amp;nbsp;it easy, and that it why it is one of my favorite&amp;nbsp;applications.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerseatgiants.blogspot.com/feeds/7184540179797140917/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/15999985/7184540179797140917' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/7184540179797140917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15999985/posts/default/7184540179797140917'/><link rel='alternate' type='text/html' href='http://tigerseatgiants.blogspot.com/2011/03/favorite-applications-mirth.html' title='Favorite Applications--Mirth'/><author><name>Eric</name><uri>http://www.blogger.com/profile/14352579264754955766</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSGGjDKSu2LZ3In1AsMK-ke7dYjBzLGiai1N45_ZMi7QIFFF-zjOZmB-20ww4Szxr30MqDNjgv56cLqxpLOvgxvWnLP0wWI7imDqXS2WUo3OSWyptazu4RvZtBebgIw/s220/Photo+on+2010-07-29+at+16.30+%232.jpg'/></author><thr:total>0</thr:total></entry></feed>