Jump to content
We've recently updated our Privacy Statement, available here ×

integrate jasperintelligence with ruby on rails


paulc

Recommended Posts

Hi all, can anyone show me how to integrate jasperintelligence with ruby on rails application.

 

Mainly is

1) Authentication - let rails handle to the authentication

 

2) url to access reports stored on jasperintelligence

Link to comment
Share on other sites

  • 1 month later...
  • Replies 33
  • Created
  • Last Reply

Top Posters In This Topic

Hi, I'm actually dealing with it. I just can tell you the url connection as I havent been able to get a "fully" authentication.

 

Url: "http://localhost/jasperserver/services/repository/"

 

I've tried to authenticate with this:

conn = Net::HTTP.start('10.128.10.81')

get = Net::HTTP::Get.new('/jasperserver/services/repository/')

get.basic_auth 'jasperadmin', 'jasperadmin'

conn.request(get)

print conn

 

but it answers ok, but when I try to use any other method, it says "SOAP::HTTPStreamError: 401: Full authentication is required to access this resource". Im still looking into it but I'd really appreciate any suggestion.

Link to comment
Share on other sites

Thanks but though I've been checking it my Java knowledge is very low. What I need to do is a web service client in Ruby on Rails and I can understand I dont need to rewrite the code, do I? I mean in Ruby is supposed to be just:

 

JASPER_SERVER = "http://10.128.10.81/jasperserver/services/repository/"

driver = SOAP::RPC::Driver.new(JASPER_SERVER)

driver.add_method('login','username','password')

 

 

Thanks in advance for any suggestion.

Link to comment
Share on other sites

I've been toying around with this concept for at least 3 weeks, and I haven't been able to make any meaningful progress. Part of the problem as I see it is the inability for the default JI web service to display its WSDL, where you get the following error message:

 

<error>

<description>Unable to generate WSDL for this service</description>

<reason>

Either user has not dropped the wsdl into META-INF or operations use message receivers other than RPC.

</reason>

</error>

 

Another forum post addresses this and recommends deploying the repository.aar file as an axis2 service, with the caveat that you have to have all the required jar files, whatever those are supposed to be. All I ever get there is a faulty axis2 service.

 

But back to the rails problem specifically. Based on the methods I see as available in the web service (the WSDL is available on the aforementioned forum post), I should be able to use add_method for the RPC driver to create a login method that works. It's obvious that something is wrong with the authentication method that I am using, because I get:

 

SOAP::HTTPStreamError: 401: Full authentication is required to access this resource

 

The thing is, I really like JasperIntelligence, and I am evaluating ways to integrate it into other web applications that may or may not be java-based. If I can show a solid success story here, I might even be able to convince my company to abandon Crystal entirely.

 

Is there any way we can get more meaningful answers to this kind of question? Has anyone implemented a ruby SOAP client that interfaces with the JI web service? I don't guess I have to point out that existing documentation is understandably java-specific, and since I don't have a strong grasp of java in the first place, I don't relish the idea of digging through the iReport plugin to figure out how this works.

 

Any suggestions?

Link to comment
Share on other sites

Hi, I've got the same error as you and finally Ive got authentication but I cannot do anything more, with add_method I tried the list method and all I got was

Errno::ECONNREFUSED: Connection refused - connect(2) (, #0)

 

My class for a web service client:

 

class WsJasperClient < SOAP::RPC::Driver

 

JASPER_SERVER = "http://10.128.10.81/jasperserver/services/repository/"

 

# Authentication works!!!

def new(nameserver)

# nameserver => JASPER_SERVER

driver = SOAP::RPC::Driver.new(JASPER_SERVER)

driver.options["protocol.http.basic_auth"] <<

[JASPER_SERVER, "jasperadmin", "jasperadmin"]

end

 

# Create driver and set up methods

# It doesnt work yet :-(

def add_methods

# driver = SOAP::RPC::Driver.new("http://10.128.10.81/jasperserver/services/repository/" )

[ %w(login username password),

%w(list uri),

%w(get uri args),

%w(runReport reportUri map)].each do |signature|

self.add_method(*signature)

end

end

 

end

 

I hope this can help you though I havent been able to get it works.

Post edited by: rosisr, at: 2006/12/04 10:27

Link to comment
Share on other sites

I got the following (via irb) to generate both a successful authentication and an error:

 

require 'soap/rpc/driver'

 

server = "http://localhost:8080/jasperserver/services/repository/"

 

driver = SOAP::RPC::Driver.new(server)

 

driver.options["protocol.http.basic_auth"] << [server, "admin", "admin"]

 

driver.add_method('login','username','password')

 

driver.login('admin','admin')

 

 

The error that is generated:

 

SOAP::Parser::FormatDecodeError: Unbalanced tag in XML.

 

from /usr/lib/ruby/1.8/soap/parser.rb:95:in `parse'

 

from /usr/lib/ruby/1.8/soap/processor.rb:39:in `unmarshal'

 

from /usr/lib/ruby/1.8/soap/rpc/proxy.rb:232:in `unmarshal'

 

from /usr/lib/ruby/1.8/soap/rpc/proxy.rb:175:in `route'

 

from /usr/lib/ruby/1.8/soap/rpc/proxy.rb:141:in `call'

 

from /usr/lib/ruby/1.8/soap/rpc/driver.rb:178:in `call'

 

from /usr/lib/ruby/1.8/soap/rpc/driver.rb:232:in `login'

 

from (irb):6

 

 

 

However, getting this to work in the first place required me to install http-access2, since net/http + soap4r does not support basic authentication ( NotImplementedError: basic_auth is not supported under soap4r + net/http.)

 

Kudos, though, for figuring out the mechanism for authentication.

 

Next up, adding the other methods.

 

I tried:

 

driver.add_method('list','uri')

 

which is what your class method attempts to do. I don't get a connection refused, but I do get an error, and it seems that JasperServer is returning this one:

 

09:49:15,778 ERROR ManagementService,http-8080-Processor23:283 - caught exception: Parsing Error : Content is not allowed in prolog.

 

Line : 1

 

Column : 1

 

 

 

Parsing Error : Content is not allowed in prolog.

 

Line : 1

 

Column : 1

 

{file: [not available]; line: 1; column: 1}

 

....

 

 

I suspect I will be able to track that one down, and it's likely just the way I have constructed my argument.

 

Anyway, I will keep trying to figure that out... In the mean time, I would love to hear from anyone else who has tried this.

Link to comment
Share on other sites

If you try from a rails console you can get an authentication with:

JASPER_SERVER = "http://10.128.10.81/jasperserver/services/repository/"

driver = SOAP::RPC::Driver.new(JASPER_SERVER)

driver.options["protocol.http.basic_auth"] <<

[JASPER_SERVER, "jasperadmin", "jasperadmin"]

 

I've also had the same problems as you. I got the authentication with the code above in a rails console and then I got other error when I tried to use list method and what I get is:

 

ws.list('')

Wire dump:

 

= Request

 

POST /jasperserver/services/repository/ HTTP/1.1

! CONNECTION CLOSED

Errno::EPIPE: Broken pipe

from /usr/lib/ruby/gems/1.8/gems/rubyforge-0.3.1/lib/http-access2.rb:1135:in `write'

from /usr/lib/ruby/gems/1.8/gems/rubyforge-0.3.1/lib/http-access2.rb:1135:in `<<'

from /usr/lib/ruby/gems/1.8/gems/rubyforge-0.3.1/lib/http-access2/http.rb:185:in `dump'

from /usr/lib/ruby/gems/1.8/gems/rubyforge-0.3.1/lib/http-access2/http.rb:386:in `dump'

from /usr/lib/ruby/gems/1.8/gems/rubyforge-0.3.1/lib/http-access2.rb:1213:in `query'

from /usr/lib/ruby/1.8/timeout.rb:56:in `timeout'

from /usr/lib/ruby/1.8/timeout.rb:76:in `timeout'

from /usr/lib/ruby/gems/1.8/gems/rubyforge-0.3.1/lib/http-access2.rb:1211:in `query'

from /usr/lib/ruby/gems/1.8/gems/rubyforge-0.3.1/lib/http-access2.rb:892:in `query'

from /usr/lib/ruby/gems/1.8/gems/rubyforge-0.3.1/lib/http-access2.rb:434:in `do_get_block'

from /usr/lib/ruby/gems/1.8/gems/rubyforge-0.3.1/lib/http-access2.rb:370:in `conn_request'

from /usr/lib/ruby/gems/1.8/gems/rubyforge-0.3.1/lib/http-access2.rb:285:in `request'

from /usr/lib/ruby/gems/1.8/gems/rubyforge-0.3.1/lib/http-access2.rb:264:in `post'

from /usr/lib/ruby/1.8/soap/streamHandler.rb:199:in `send_post'

from /usr/lib/ruby/1.8/soap/streamHandler.rb:137:in `send'

from /usr/lib/ruby/1.8/soap/rpc/proxy.rb:170:in `route'

from /usr/lib/ruby/1.8/soap/rpc/proxy.rb:141:in `call'

from /usr/lib/ruby/1.8/soap/rpc/driver.rb:178:in `call'

Link to comment
Share on other sites

I figured a couple of things out this morning with respect to the list operation and authentication. First, the approach we are taking is the correct approach for authentication. Second, the list operation requires an XML document as an argument, not simply a path, like /reports. I found the structure of the XML document that lists the resources in the repository by running Ethereal and digging through the HTTP POST packets generated by iReport with the web service plugin. From that, I was able to construct the following program, which works to get a list of available resources given a URI:

 

 

#!/bin/env ruby

 

require 'soap/rpc/driver'

 

strUser = 'admin'

strPWD = 'admin'

strServer = 'http://localhost:8080/jasperserver/services/repository/'

strURI = %q{<?xml version="1.0" encoding="UTF-8"?>

<request>

<operation-name>list</operation-name>

<resource-descriptor read-only="false" control-type="0"

is-reference="false" is-new="false" strict-max="false"

data-type="0" mandatory="false" has-data="false"

strict-min="false" main-report="false" version="0">

<uri-string>/reports</uri-string><ws-type>folder</ws-type>

</resource-descriptor></request>

}

 

driver = SOAP::RPC::Driver.new(strServer)

driver.wiredump_dev = STDERR

driver.options["protocol.http.basic_auth"] << [strServer, strUser, strPWD]

 

driver.add_method('list','request')

 

puts driver.list(strURI)

 

 

From there, it should be trivial to parse the resulting XML into something that works in rails:

 

 

<?xml version="1.0" encoding="UTF-8"?>

 

<operation-result return-code="0"><resource-descriptors xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" read-only="false" control-type="0" is-reference="false" is-new="false" strict-max="false" data-type="0" mandatory="false" has-data="false" strict-min="false" main-report="false" version="0" xsi:type="java:com.jaspersoft.jasperserver.api.metadata.xml.domain.impl.ResourceDescriptor">

<name>samples</name><description>Samples</description>

<resource-type>com.jaspersoft.jasperserver.api.metadata.common.domain.Folder

</resource-type><parent-folder>/reports</parent-folder>

<creation-date>2006-11-15T12:27:13.000-06:00</creation-date>

<uri-string>/reports/samples</uri-string><ws-type>folder

</ws-type><label>Samples</label></resource-descriptors>

<version>1.1.0</version></operation-result>

 

 

I will hopefully be able to deconstruct a runReport request here in the next couple of hours. Note that it is not necessary to explicitly call the login function, since the headers here are constructed with the authentication present. I believe that was the source of the 500 Internal Server Error mentioned previously.

Link to comment
Share on other sites

As promised, here's a plain ruby example of how to use the runReport method. I am betting it is pretty easy from this point to integrate this into rails. That's my next step, anyway.

 

#!/bin/env ruby

 

require 'soap/rpc/driver'

 

strUser = 'admin'

strPWD = 'admin'

strServer = 'http://localhost:8080/jasperserver/services/repository/'

strOutputFormat = 'HTML' #JRPRINT, RTF, PDF, etc?

strURI = '/reports/samples/Employees'

strRequest = %Q|<?xml version="1.0" encoding="UTF-8"?>

<request><operation-name>runReport</operation-name><resource-descriptor

read-only="false" control-type="0" is-reference="false"

is-new="false" strict-max="false" data-type="0"

mandatory="false" has-data="false" strict-min="false"

main-report="false" version="0">

<uri-string>#{strURI}</uri-string></resource-descriptor>

<arguments xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:type="java:com.jaspersoft.jasperserver.api.metadata.xml.domain.impl.Argument">

<name>RUN_OUTPUT_FORMAT</name><value>#{strOutputFormat}</value></arguments></request>

|

 

driver = SOAP::RPC::Driver.new(strServer)

driver.wiredump_dev = STDERR

driver.options["protocol.http.basic_auth"] << [strServer, strUser, strPWD]

 

driver.add_method('runReport','request')

 

puts driver.runReport(strRequest)

Link to comment
Share on other sites

Thanks a lot, you've been a great help!! But I still have some problems, when I try to run this:

 

#!/bin/env ruby

 

require 'soap/rpc/driver'

 

strUser = 'jasperadmin'

strPWD = 'jasperadmin'

strServer = 'http://10.128.10.81/jasperserver/services/repository/'

 

strOutputFormat = 'HTML' #JRPRINT, RTF, PDF, etc?

strURI = '/reports/samples/Employees'

strRequest = %Q{<?xml version="1.0" encoding="UTF-8"?>

<request> <operation-name>runReport</operation-name>

<resource-descriptor

read-only="false" control-type="0" is-reference="false" is-new="false" strict-max="false" data-type="0" mandatory="false" has-data="false" strict-min="false" main-report="false" version="0">

<uri-string>#{strURI}</uri-string>

</resource-descriptor>

<arguments xmlnssi="http://www.w3.org/2001/XMLSchema-instance"

xsi:type="java:com.jaspersoft.jasperserver.api.metadata.xml.domain.impl.Argument">

<name>RUN_OUTPUT_FORMAT</name>

<value>#{strOutputFormat}</value>

</arguments>

</request>

}

 

driver = SOAP::RPC::Driver.new(strServer)

driver.wiredump_dev = STDERR

driver.options["protocol.http.basic_auth"] << [strServer, strUser, strPWD]

 

driver.add_method('runReport','request')

 

puts driver.runReport(strRequest)

 

What I get is:

 

<?xml version='1.0 'encoding='utf-8'?>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header />

<soapenv:Body><ns1:result xmlns:ns1="http://jasperserver/ws2/namespace1" xmlns:tns="http://ws.apache.org/axis2"><?xml version="1.0" encoding="UTF-8"?>

<operation-result return-code="1"><version>1.1.0</version><message>unable to instantiate java.util.List; </message></operation-result></ns1:result></soapenv:Body></soapenv:Envelope>

 

Any suggestion?

Link to comment
Share on other sites

That looks like an issue with JasperIntelligence, and not with ruby. Try tailing your catalina.out file and see if there is more information there, like a stack trace.

 

As for my progress in general, I still have to do the following:

 

1. Figure out how to pass parameters in the request XML

2. Figure out how to view an HTML-exported report inline (in rails)

3. Figure out everything else rails needs to make this work right

 

Of course I will still be working on it today, but if anyone else comes across this topic and has any suggestions, I would love to hear them. Item number 2 has its own forum thread, since I can't seem to get any meaningful object out of the SOAP::Attachment when I choose HTML as the output format.

Link to comment
Share on other sites

  • 1 month later...

Ok, after some additional time dedicated to this task, I have managed the following:

 

1. Provide a rails front-end that lists the reports residing in a specific folder.

2. Create links to those reports that then return the report in an exportable format, such as PDF.

 

PDF is the only format I have actually gotten to work with the sample reports, but I suspect that other formats should work just fine if the report is set up to handle it.

 

To accomplish this, I needed a model, a controller, a helper, and a view. Here is the code that I am using. Note that I am storing my JI connection information in the local database, since I don't want the user to know anything about the JI credentials explicitly. My table name for this configuration info is site_configs, and I have a corresponding rails model called site_configs.rb

 

##### begin app/models/reports.rb #####

require 'soap/rpc/driver'

class Reports < ActiveRecord::Base

 

class << self

def get_list(strURL, strUser, strPass, strURI)

 

strRequestBody = %Q|<?xml version="1.0" encoding="UTF-8"?>

<request>

<operation-name>list</operation-name>

<resource-descriptor read-only="false" control-type="0"

is-reference="false" is-new="false" strict-max="false"

data-type="0" mandatory="false" has-data="false"

strict-min="false" main-report="false" version="0">

<uri-string>#{strURI}</uri-string><ws-type>folder</ws-type>

</resource-descriptor></request>

|

 

driver = SOAP::RPC::Driver.new(strURL)

driver.options["protocol.http.basic_auth"] << [strURL, strUser, strPass]

driver.add_method('list','request')

 

@report_list = driver.list(strRequestBody)

end

 

def get_report(strURL, strUser, strPass, strURI, strOutputFmt)

 

strRequestBody = %Q|<?xml version="1.0" encoding="UTF-8"?>

<request><operation-name>runReport</operation-name><resource-descriptor

read-only="false" control-type="0" is-reference="false"

is-new="false" strict-max="false" data-type="0"

mandatory="false" has-data="false" strict-min="false"

main-report="false" version="0">

<uri-string>#{strURI}</uri-string></resource-descriptor>

<arguments xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:type="java:com.jaspersoft.jasperserver.api.metadata.xml.domain.impl.Argument">

<name>RUN_OUTPUT_FORMAT</name><value>#{strOutputFmt}</value></arguments></request>

|

 

driver = SOAP::RPC::Driver.new(strURL)

driver.options["protocol.http.basic_auth"] << [strURL, strUser, strPass]

driver.add_method('runReport','request')

 

report = driver.runReport(strRequestBody)["Include"].content

report

end

end

 

end

##### end app/models/reports.rb #####

 

 

##### begin app/helpers/send_doc.rb #####

module SendDoc

def send_doc(strURL, strUser, strPass, strReportName, strReportURI, strOutputFmt)

 

case strOutputFmt

when 'PDF'

mime_type = 'application/pdf'

extension = 'pdf'

else #rtf

mime_type = 'application/rtf'

extension = 'rtf'

end

 

send_data Reports.get_report(strURL, strUser, strPass, strReportURI, strOutputFmt),

:filename => "#{strReportName}.#{extension}", :type => mime_type, :disposition => 'inline'

end

end

##### end app/helpers/send_doc.rb #####

 

 

##### begin app/controllers/reports_controller.rb #####

require 'rexml/document'

class ReportsController < ApplicationController

 

include SendDoc

 

def index

@jasperServer = SiteConfig.find(:first, :conditions => "name = 'JasperServer URL'")["value"]

@jasperUser = SiteConfig.find(:first, :conditions => "name = 'JasperServer User'")["value"]

@jasperPass = SiteConfig.find(:first, :conditions => "name = 'JasperServer Password'")["value"]

@jasperURI = '/reports/samples'

 

@reportsXML = Reports.get_list(@jasperServer, @jasperUser, @jasperPass, @jasperURI)

 

doc = REXML::Document.new(@reportsXML)

@report_names = []

@report_labels = []

@res_type = []

@parent_folder = []

 

doc.elements.each('operation-result/resource-descriptors/name') do |ele|

@report_names << ele.text

end

 

doc.elements.each('operation-result/resource-descriptors/label') do |ele|

@report_labels << ele.text

end

 

doc.elements.each('operation-result/resource-descriptors/resource-type') do |ele|

@res_type << ele.text

end

 

doc.elements.each('operation-result/resource-descriptors/parent-folder') do |ele|

@parent_folder << ele.text

end

end

 

def run

@jasperServer = SiteConfig.find(:first, :conditions => "name = 'JasperServer URL'")["value"]

@jasperUser = SiteConfig.find(:first, :conditions => "name = 'JasperServer User'")["value"]

@jasperPass = SiteConfig.find(:first, :conditions => "name = 'JasperServer Password'")["value"]

 

@reportName = params[:reportURI].gsub(///, '_')

 

@report = send_doc(@jasperServer, @jasperUser, @jasperPass, @reportName, params[:reportURI], params[:format])

end

end

##### end app/controllers/reports_controller.rb #####

 

 

##### begin app/views/reports/index.rhtml #####

<% @page_title = 'Reports' %>

Folder: <%= @parent_folder[0] %><br/><br/>

<% @report_names.each_with_index do |name, idx| %>

<% if @res_type[idx] == 'com.jaspersoft.jasperserver.api.metadata.jasperreports.domain.ReportUnit' %>

<li><%= @report_labels[idx] %>

<%= link_to(image_tag("/images/pdf.gif", :border => 0), :controller => "reports", :action => "run", :reportURI => "#{@jasperURI}/#{name}", :format => 'PDF')

%>

<% end %>

<% end %>

##### end app/views/reports/index.rhtml #####

 

 

If anyone knows how to accomplish this better, I am still interested in learning how. Also, I would like to have a couple other options as far as output goes, so if anyone knows how I can get a native (JRPRINT) report to output from a non-java client, I would be appreciative.

 

My next real task will be to construct the XML document that contains parameters, since reports aren't always very useful unless you can change your parameters.

Link to comment
Share on other sites

  • 2 months later...

I tried this and get the same error :pinch:

 

rosisr wrote:

Thanks a lot, you've been a great help!! But I still have some problems, when I try to run this:

#!/bin/env ruby

require 'soap/rpc/driver'

strUser = 'jasperadmin'
strPWD = 'jasperadmin'
strServer = 'http://10.128.10.81/jasperserver/services/repository/'

strOutputFormat = 'HTML' #JRPRINT, RTF, PDF, etc?
strURI = '/reports/samples/Employees'
strRequest = %Q{<?xml version="1.0" encoding="UTF-8"?>
<request> <operation-name>runReport</operation-name>
<resource-descriptor
read-only="false" control-type="0" is-reference="false" is-new="false" strict-max="false" data-type="0" mandatory="false" has-data="false" strict-min="false" main-report="false" version="0">
<uri-string>#{strURI}</uri-string>
</resource-descriptor>
<arguments xmlnssi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="java:com.jaspersoft.jasperserver.api.metadata.xml.domain.impl.Argument">
<name>RUN_OUTPUT_FORMAT</name>
<value>#{strOutputFormat}</value>
</arguments>
</request>
}

driver = SOAP::RPC::Driver.new(strServer)
driver.wiredump_dev = STDERR
driver.options["protocol.http.basic_auth"] << [strServer, strUser, strPWD]

driver.add_method('runReport','request')

puts driver.runReport(strRequest)

What I get is:

<?xml version='1.0 'encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header />
<soapenv:Body><ns1:result xmlns:ns1="http://jasperserver/ws2/namespace1" xmlns:tns="http://ws.apache.org/axis2"><?xml version="1.0" encoding="UTF-8"?>
<operation-result return-code="1"><version>1.1.0</version><message>unable to instantiate java.util.List; </message></operation-result></ns1:result></soapenv:Body></soapenv:Envelope>

Any suggestion?

 

:x

Post edited by: edxerx, at: 2007/03/15 09:16

Link to comment
Share on other sites

seems that in the end all I get is

#: The AXIS engine could not find a target service to invoke! targetService is repository/ (SOAP::FaultError)

btw my code is as below
 

Code:


I can connect but can't do anything :blink: , anyone got clues?

Link to comment
Share on other sites

I believe my original code is now deprecated with the release of JI 1.2, but the good news (so far in my testing) is that you won't need it.

 

What you should probably do now that the WSDL is generated and exposed, is use the ruby utility wsdl2ruby. To get it to work correctly for me, since it doesn't have HTTP Basic Authentication out of the box, I saved the WSDL file in some location, then used the saved file as the input for the wsdl2ruby script:

 

$ wsdl2ruby --wsdl jasperserver.wsdl --type client

 

I didn't have to force anything. The files that are generated (in my case) are:

 

defaltDriver.rb

defaultMappingRegistry.rb

default.rb

ManagementServiceServiceClient.rb

 

You need the first three files, but any script you want to write should:

 

require 'defaultDriver.rb'

 

ManagementServiceServiceClient.rb is a sample client you can use to test out the available methods. Before you give it a whirl, you should make sure to add the basic authentication method discussed earlier in this thread. Just to get it off the ground, I added the following line after the wiredump_dev line:

 

obj.options["protocol.http.basic_auth"] << [endpoint_url,"admin_user","admin_password"]

 

Run the file with ruby -d to get the full request and response for each of the methods. This will show you how you might construct your own requests.

 

Hopefully, as I get some time, I will be able to rework the code I originally wrote to take advantage of the auto-magic that ruby is capable of. If anyone else manages to get something working, I would love to see it.

Post edited by: MariusAgricola, at: 2007/03/15 22:05

Link to comment
Share on other sites

One other thing to note in the client file is that in all cases the requestXmlString is set to nil:

 

requestXmlString = nil

 

This means that you will still have to construct the request in a particular format. I am not certain if the format is still the same with this version of JI, but a look at the wiredump indicates that it might not be. You could, as an alternative, attempt to get the format from a network analysis tool such as ethereal, while running the same operation inside the updated iReport program. I haven't had a chance to 1) update iReport, and 2) break down the packets.

Link to comment
Share on other sites

First let me thank you for the work you have done on this project. I have Jasperserver 1.2 installed and have the LIST functionality working with your framework. I just had to modify the strRequestBody values in the reports.rb, and the doument elements in the controller. What really has me stumped is the line of code report = driver.call('runReport', strRequestBody)['Include'].content in the reports model. I get this error: Any help would be greatly appreciated...

 

You have a nil object when you didn't expect it!

The error occurred while evaluating nil.content

 

of course if I remove the ['Include'].content... I only get the success response:

<?xml version="1.0" encoding="UTF-8" ?>

- <operationResult version="1.2.0">

- <returnCode>

- <![CDATA[ 0]]>

</returnCode>

</operationResult>

 

A wiredump indicates that the pdf is being delievered as "chunked" just cannot figure out how to caputure it.. I've tried everything I can think of to inspect the object / response to determine what is going on.. YAML::dump, inspect...

Please forgive me! I'm just hacking away at this. I really don't have a clue about how this stuff really works...

I've built a small ruby script to test the wsdl2ruby method, and I have the same problem

while trying to retrieve the response from runReport.

 

##### begin test.rb #####

 

require 'defaultDriver'

strRequestBody = %Q|<?xml version="1.0" encoding="UTF-8"?>

<request operationName="runReport" locale="en">

<argument name="RUN_OUTPUT_FORMAT">PDF</argument>

<resourceDescriptor name="" wsType=""

uriString="/reports/samples/AllAccounts"

isNew="false">

<label>null</label>

</resourceDescriptor>

</request>

|

 

strRequestBody = %Q|<?xml version="1.0" encoding="UTF-8"?>

<request operationName="runReport" locale="en">

<argument name="RUN_OUTPUT_FORMAT">PDF</argument>

<resourceDescriptor name="" wsType=""

uriString="/reports/samples/AllAccounts"

isNew="false">

<label>null</label>

</resourceDescriptor>

</request>

|

obj = ManagementService.new("http://ubuntu:8080/jasperserver/services/repository")

obj.options["protocol.http.basic_auth"] << ["http://ubuntu:8080/jasperserver/services/repository","jasperadmin","jasperadmin"]

puts obj.runReport(strRequestBody)

##### end test.rb #####

 

My 1.2 almost compliant / almost working hack of the integrate jasperintelligence with ruby on rails stuff follows:

 

##### begin app/models/reports.rb #####

require 'soap/rpc/driver'

class Reports < ActiveRecord::Base

 

class << self

def get_list(strURL, strUser, strPass, strURI)

 

 

strRequestBody = %Q|<?xml version="1.0" encoding="UTF-8"?>

<request operationName="list" locale="en">

<resourceDescriptor name="" wsType="folder" uriString="#{strURI}" isNew="false">

<label>null</label>

</resourceDescriptor>

</request>

|

 

 

driver = SOAP::RPC::Driver.new(strURL)

driver.options["protocol.http.basic_auth"] << [strURL, strUser, strPass]

driver.add_method('list','request')

@report_list = driver.list(strRequestBody)

 

end

 

 

def get_report(strURL, strUser, strPass, strURI, strOutputFmt)

 

 

strRequestBody = %Q|<?xml version="1.0" encoding="UTF-8"?>

<request operationName="runReport" locale="en">

<argument name="RUN_OUTPUT_FORMAT">#{strOutputFmt}</argument>

<resourceDescriptor name="" wsType=""

uriString="#{strURI}"

isNew="false">

<label>null</label>

</resourceDescriptor>

</request>

|

driver = SOAP::RPC::Driver.new(strURL)

driver.options["protocol.http.basic_auth"] << [strURL, strUser, strPass]

driver.add_method('runReport','request')

 

 

report = driver.call('runReport', strRequestBody)['Include'].content

report

end

end

 

end

 

##### end app/models/reports.rb #####

 

##### begin app/helpers/send_doc.rb #####

 

module SendDoc

def send_doc(strURL, strUser, strPass, strReportName, strReportURI, strOutputFmt)

 

case strOutputFmt

when 'PDF'

mime_type = 'application/pdf'

extension = 'pdf'

else #rtf

mime_type = 'application/rtf'

extension = 'rtf'

end

 

 

send_data Reports.get_report(strURL, strUser, strPass, strReportURI, strOutputFmt),

:filename => "#{strReportName}.#{extension}", :type => mime_type, :disposition => 'inline'

 

end

end

 

##### end app/helpers/send_doc.rb #####

 

##### begin app/controllers/reports_controller.rb #####

require 'rexml/document'

class ReportsController < ApplicationController

 

include SendDoc

 

def index

@jasperServer = SiteConfig.find(:first, :conditions => "name = 'JasperServer URL'")["value"]

@jasperUser = SiteConfig.find(:first, :conditions => "name = 'JasperServer User'")["value"]

@jasperPass = SiteConfig.find(:first, :conditions => "name = 'JasperServer Password'")["value"]

@jasperURI = '/reports/samples'

 

@reportsXML = Reports.get_list(@jasperServer, @jasperUser, @jasperPass, @jasperURI)

 

doc = REXML::Document.new(@reportsXML)

@report_names = []

@report_labels = []

@res_type = []

@parent_folder = []

 

 

doc.elements.each('operationResult/resourceDescriptor') do |ele|

@report_names << ele.attributes["name"]

end

 

doc.elements.each('operationResult/resourceDescriptor/label') do |ele|

@report_labels << ele.text

end

 

doc.elements.each("operationResult/resourceDescriptor/resourceProperty[@name=PROP_RESOURCE_TYPE]/value") do |ele|

@res_type << ele.text

end

 

doc.elements.each("operationResult/resourceDescriptor/resourceProperty[@name=PROP_PARENT_FOLDER]/value") do |ele|

@parent_folder << ele.text

end

 

end

 

 

 

def run

@jasperServer = SiteConfig.find(:first, :conditions => "name = 'JasperServer URL'")["value"]

@jasperUser = SiteConfig.find(:first, :conditions => "name = 'JasperServer User'")["value"]

@jasperPass = SiteConfig.find(:first, :conditions => "name = 'JasperServer Password'")["value"]

 

@reportName = params[:reportURI].gsub(///, '_')

 

@report = send_doc(@jasperServer, @jasperUser, @jasperPass, @reportName, params[:reportURI], params[:format])

end

end

##### end app/controllers/reports_controller.rb #####

 

##### begin app/views/reports/index.rhtml #####

<% @page_title = 'Reports' %>

Folder: <%= @parent_folder[0] %><br/><br/>

<% @report_names.each_with_index do |name, idx| %>

<% if @res_type[idx] == 'com.jaspersoft.jasperserver.api.metadata.jasperreports.domain.ReportUnit' %>

<li><%= @report_labels[idx] %>

<%= link_to(image_tag("/images/pdf.gif", :border => 0), :controller => "reports", :action => "run", :reportURI => "#{@jasperURI}/#{name}", :format => 'PDF')%>

<% end %>

<% end %>

##### end app/views/reports/index.rhtml #####

Link to comment
Share on other sites

  • 6 months later...
  • 2 weeks later...

I modified the SOAP::RPC:Proxy class to return the SOAP::SOAPEnvelope in addition to the response object.
 

Code:


The SOAP::SOAPEnvelope has an attribute called external_content and this is where the SOAP::Attachment objects are stored. The external_content attribute is a hash and to access the desired SOAP::Attachment, use the Content-Id from the multipart attachment. For JasperServer, the Content-Id for the report attachment is 'report'.
 

Code:
Link to comment
Share on other sites

  • 5 weeks later...

Okay nevermind... I should double-check before I post. Anyway here's a slightly different version of the above monkeypatch. This one should work against soap4r 1.5.8. Also, it adds the instance variable @env to the response object rather than returning an array with the env data. I think this might be a bit safer since it doesn't break the API.

 

Code:

module SOAP
module RPC

class Proxy
include SOAP

def call(name, *params)
# name must be used only for lookup
op_info = lookup_operation(name)
mapping_opt = create_mapping_opt
req_header = create_request_header
req_body = SOAPBody.new(
op_info.request_body(params, @mapping_registry,
@literal_mapping_registry, mapping_opt)
)
reqopt = create_encoding_opt(
:«»soapaction => op_info.soapaction || @soapaction,
:envelopenamespace => @options["soap.envelope.requestnamespace"],
:default_encodingstyle =>
@default_encodingstyle || op_info.request_default_encodingstyle,
:use_default_namespace =>
op_info.use_default_namespace || @use_default_namespace
)
resopt = create_encoding_opt(
:envelopenamespace => @options["soap.envelope.responsenamespace"],
:default_encodingstyle =>
@default_encodingstyle || op_info.response_default_encodingstyle
)
env = route(req_header, req_body, reqopt, resopt)
if op_info.response_use.nil?
return nil
end
raise EmptyResponseError unless env
receive_headers(env.header)
begin
check_fault(env.body)
rescue ::«»SOAP::FaultError => e
op_info.raise_fault(e, @mapping_registry, @literal_mapping_registry)
end
if @return_response_as_xml
return resopt[:response_as_xml]
else
response_obj = op_info.response_obj(env.body, @mapping_registry,
@literal_mapping_registry, mapping_opt)
response_obj.instance_variable_set(:@env, env)
return response_obj
end
end
end

end
end

 

And to use it:

 

Code:
[code]
@driver = SOAP::RPC::«»Driver.new(@url)

@driver.options["protocol.http.basic_auth"] << [@url, @user, @pass]

@driver.add_method('runReport','request')

result = @driver.runReport(request.to_s)

report = result.instance_variable_get(:@env).external_content['report'].data.content
Link to comment
Share on other sites

Okay nevermind... I should double-check before I post. Anyway here's a slightly different version of the above monkeypatch. This one should work against soap4r 1.5.8. Also, it adds the instance variable @env to the response object rather than returning an array with the env data. I think this might be a bit safer since it doesn't break the API.

 

Code:

module SOAP
module RPC

class Proxy
include SOAP

def call(name, *params)
# name must be used only for lookup
op_info = lookup_operation(name)
mapping_opt = create_mapping_opt
req_header = create_request_header
req_body = SOAPBody.new(
op_info.request_body(params, @mapping_registry,
@literal_mapping_registry, mapping_opt)
)
reqopt = create_encoding_opt(
:«»soapaction => op_info.soapaction || @soapaction,
:envelopenamespace => @options["soap.envelope.requestnamespace"],
:default_encodingstyle =>
@default_encodingstyle || op_info.request_default_encodingstyle,
:use_default_namespace =>
op_info.use_default_namespace || @use_default_namespace
)
resopt = create_encoding_opt(
:envelopenamespace => @options["soap.envelope.responsenamespace"],
:default_encodingstyle =>
@default_encodingstyle || op_info.response_default_encodingstyle
)
env = route(req_header, req_body, reqopt, resopt)
if op_info.response_use.nil?
return nil
end
raise EmptyResponseError unless env
receive_headers(env.header)
begin
check_fault(env.body)
rescue ::«»SOAP::FaultError => e
op_info.raise_fault(e, @mapping_registry, @literal_mapping_registry)
end
if @return_response_as_xml
return resopt[:response_as_xml]
else
response_obj = op_info.response_obj(env.body, @mapping_registry,
@literal_mapping_registry, mapping_opt)
response_obj.instance_variable_set(:@env, env)
return response_obj
end
end
end

end
end

 

And to use it:

 

Code:
[code]
@driver = SOAP::RPC::«»Driver.new(@url)

@driver.options["protocol.http.basic_auth"] << [@url, @user, @pass]

@driver.add_method('runReport','request')

result = @driver.runReport(request.to_s)

report = result.instance_variable_get(:@env).external_content['report'].data.content
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...