Skip to content

Commit

Permalink
Merge pull request #2 from cbmw/master
Browse files Browse the repository at this point in the history
Add JasperClient.get() method. Add attach support for JasperClient.run() method.
  • Loading branch information
agaoglu committed Apr 15, 2014
2 parents 4fa0cae + d33a24f commit d979474
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 49 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -1,3 +1,4 @@
build
dist
pyjasperclient.egg-info
*.pyc
39 changes: 30 additions & 9 deletions README.md
Expand Up @@ -22,10 +22,11 @@ For the impatient
from pyjasperclient import JasperClient

url = 'http://localhost:8080/jasperserver/services/repository?wsdl'
j = JasperClient(url,'joeuser','joeuser')
ret = j.runReport('/reports/samples/AllAccounts',"PDF")
f = file('AllAccounts.pdf','w')
f.write(ret['data'])
jc = JasperClient()
js.login(url, 'jlogin', 'jpass')
report = js.run('/Reports/reporting_to_the_explanatory_note/Report30', 'XLS', {'Year': u'2011'}, {'onePagePerSheet': 'true'})
report_file = file('report.xls','wb')
f.write(report[1]['data'])
f.close()


Expand All @@ -35,14 +36,34 @@ Create your Jasper object with JasperServer wsdl url and JasperServer credential

j = JasperClient( 'http://localhost:8080/jasperserver/services/repository?wsdl', 'joeuser', 'joeuser')

There are only two methods that can be used.
There are only three methods that can be used.

JasperClient.listReports(dir="")
JasperClient.list(dir="")

Returns a list of strings that are report URIs of the JasperServer. Optional dir param may be used to define the directory to look for. It should start with / and end with directory name. (No / at the end)

Jasper.runReport(uri,output="PDF",params={})

This will run the report for the URI given in uri and generate a dict containing 'content-type' and 'data'. 'content-type' can be used to send as an HTTP response header. params is a simple dict to pass directly to the running report.
JasperClient.get(uri)

Returns a dict with report (uri) parametrs:
report:
* name
* id (uriString)
* label
* description
* controls [list]:
* id (inputControl uri)
* name
* type
* label
* description
* parameters [list]:
* name
* class
* default (default value)

<!-- endlist -->
Jasper.run(uri, output="PDF", params={}, args={})

This will run the report for the URI given in uri and generate a dict containing 'content-type' and 'data'. 'content-type' can be used to send as an HTTP response header. params is a simple dict to pass directly to the running report. Uri should be report URI on JasperServer. Output may be PDF, JRPRINT, HTML, XLS, XML, CSV and RTF; default PDF

Check the source for more info
220 changes: 180 additions & 40 deletions pyjasperclient/jasperclient.py
Expand Up @@ -16,62 +16,205 @@
except ImportError, e:
from elementtree import ElementTree as ET
from suds.client import Client
import email,re
from suds.transport.http import HttpAuthenticated
from operator import itemgetter
import email
import re


class NotMultipartError(Exception): pass
class WrongOutputFormat(Exception): pass
class UnknownResponse(Exception): pass
class ServerError(Exception): pass

class JasperClient:
def __init__(self,url,username,password):
self.client = Client(url,username=username,password=password)

def listReports(self,dir=""):
class JasperClient(object):
def __init__(self, url=None, username=None, password=None, timeout=300):
self.timeout = timeout
if url and username and password:
self.client = self.login(url, username=username, password=password, timeout=self.timeout)

def login(self, url, username, password):
#self.transport = HttpAuthenticated(username=username, password=password)
#self.client = Client(url, transport=self.transport)
self.client = Client(url, username=username,
password=password, timeout=self.timeout)

def list(self, dir=""):
""" get a list containing report URIs on JasperServer
optional dir param shows the directory to list in JasperServer
"""
req = createRequest(
uriString=dir,
wsType="folder",
uriString=dir,
wsType="folder",
operationName="list")
res = self.client.service.list(req)
res = res.encode('utf-8')
reports = []
for rd in ET.fromstring(res).findall('resourceDescriptor'):
if rd.get('wsType') == 'reportUnit':
report = {}
report['id'] = rd.get('uriString')
for infotag in ['label','description']:
try:
report[infotag] = rd.find(infotag).text
except AttributeError, e:
report[infotag] = None
reports.append(report)
report = {}
report['id'] = rd.get('uriString')
report['type'] = rd.get('wsType')
for infotag in ['label', 'description']:
try:
report[infotag] = rd.find(infotag).text
except AttributeError:
report[infotag] = None
reports.append(report)
return reports

def runReport(self,uri,output="PDF",params={}):
""" uri should be report URI on JasperServer

def get(self, uri):
''' Return a dict containing Report's parameters:
report:
- name
- id (uriString)
- label
- description
- controls [list]:
- id (inputControl uri)
- name
- type
- label
- description
- parameters [list]:
- name
- class
- default (default value)
'''
req = createRequest(
uriString=uri,
wsType='reportUnit',
operationName='get')

res = self.client.service.get(req)
res = res.encode('utf-8')
ru = ET.fromstring(res).find('resourceDescriptor')
report = {}
if ru is None:
return report
report['name'] = ru.get('name')
report['id'] = ru.get('uriString')
for infotag in ['label', 'description']:
try:
report[infotag] = ru.find(infotag).text
except AttributeError:
report[infotag] = None

controls = []
for rd in ru.findall('resourceDescriptor'):
if rd.get('wsType') == 'inputControl':
control = {}
control['id'] = rd.get('uriString')
control['name'] = rd.get('name')
control['type'] = self.get_control_type(
[rp.find('value').text for rp in rd.findall('resourceProperty') if rp.get('name') == 'PROP_INPUTCONTROL_TYPE'][0])
for infotag in ['label', 'description']:
try:
control[infotag] = rd.find(infotag).text
except AttributeError:
control[infotag] = None
controls.append(control)
elif rd.get('wsType') == 'jrxml':
report['jrxmlpath'] = rd.get('uriString')
report['controls'] = controls
report['parameters'] = self.get_parameters(report['jrxmlpath'])
return report

def get_control_type(self, jasper_type):
''' InputControl types: Python type
1 -> Boolean -> bool
2 -> Single Value -> str
3 -> Single-select List of Values -> str
8 -> Single-select List of Values (radio) -> str
6 -> Multi-select List of Values -> list
10 -> Multi-select List of Values (check box) -> list
4 -> Single-select Query -> str
9 -> Single-select Query (radio) -> str
7 -> Multi-select Query -> list
11 -> Multi-select Query (check box) -> list
* -> Other -> NoneType
'''
jasper_type = int(jasper_type)
if jasper_type in [1]:
return bool
if jasper_type in [2, 3, 8, 4, 9]:
return str
if jasper_type in [6, 10, 7, 11]:
return list
else:
return type(None)

def get_parameter_type(self, java_type):
''' Parameter type Pyton type
java.lang.Integer -> int
java.lang.String -> str
* -> NoneType
'''
if java_type == 'java.lang.Integer':
return int
if java_type == 'java.lang.String':
return str
else:
return type(None)

def get_parameters(self, uri):
''' Get report parameters from jr_xml object.
return parameters list with type
'''
req = createRequest(
uriString=uri,
wsType='jrxml',
operationName='get')
self.client.set_options(retxml=True)
res = self.client.service.get(req)
self.client.set_options(retxml=False)
out = parse_multipart(res)
jrxml = out[map(itemgetter('content-id'), out).index('<attachment>')]

#parse jrxml
namespace = '{http://jasperreports.sourceforge.net/jasperreports}'
parameters = []
ps = ET.fromstring(jrxml['data']).findall(
'{0}parameter'.format(namespace))
for p in ps:
parameters.append({
'name': p.get('name'),
'class': self.get_parameter_type(p.get('class')),
'default': p.find('{0}defaultValueExpression'.format(namespace)).text})
return parameters

def run(self, uri, output='PDF', params={}, args={}):
''' uri should be report URI on JasperServer
output may be PDF, JRPRINT, HTML, XLS, XML, CSV and RTF; default PDF
but JRPRINT is useless, so don't use it
params may contain parameters as a simple dict for passing to the report
this method will return a dict containing 'content-type' and 'data'.
"""
self.client.set_options(retxml=True) # suds does not parse MIME encoded so we cancel it
'''
self.client.set_options(retxml=True) # suds does not parse MIME encoded so we cancel it
if output.upper() in ['PDF', 'JRPRINT', 'HTML', 'XLS', 'XML', 'CSV', 'RTF']:
args['RUN_OUTPUT_FORMAT'] = output
else:
raise WrongOutputFormat()

req = createRequest(
arguments={"RUN_OUTPUT_FORMAT" : output},
uriString = uri,
wsType = "reportUnit",
arguments=args,
uriString=uri,
wsType="reportUnit",
operationName="runReport",
params=params)
res = self.client.service.runReport(req)
self.client.set_options(retxml=False) # temporarily of course
try :
return parseMultipart(res)
self.client.set_options(retxml=False) # temporarily of course
try:
data = parse_multipart(res)
return data
except NotMultipartError:
soapelement = ET.fromstring(res)
jasperres = soapelement.find('{http://schemas.xmlsoap.org/soap/envelope/}Body/{http://axis2.ws.jasperserver.jaspersoft.com}runReportResponse/runReportReturn')
if jasperres is None: raise UnknownResponse(res)
if jasperres is None:
raise UnknownResponse(res)
jasperres.text = jasperres.text.encode('utf-8')
jasperelement = ET.fromstring(jasperres.text)
raise ServerError(", ".join(map(lambda e: '%s: %s'% (e.tag, e.text), list(jasperelement))))
raise ServerError(", ".join(map(lambda e: '%s: %s' % (e.tag.encode('utf-8'), e.text.encode('utf-8')), list(jasperelement))))

def createRequest(**kwargs):
r = ET.Element("request")
Expand Down Expand Up @@ -99,20 +242,17 @@ def createRequest(**kwargs):
p.text = pval
return ET.tostring(r)

def parseMultipart(res):

def parse_multipart(res):
out = []
srch = re.search(r'----=[^\r\n]*',res)
if srch is None: raise NotMultipartError()
boundary = srch.group()
res = " \n"+res
res = "Content-Type: multipart/alternative; boundary=%s\n%s" % (boundary, res)
message = email.message_from_string(res)
attachment = message.get_payload()[1]
return {'content-type': attachment.get_content_type(), 'data': attachment.get_payload()}

if __name__ == "__main__":
url = 'http://localhost:8080/jasperserver/services/repository?wsdl'
j = JasperClient(url,'jasperadmin','jasperadmin')
a = j.runReport('/reports/samples/AllAccounts',"PDF")
f = file('AllAccounts.pdf','w')
f.write(a['data'])
f.close()
payloads = message.get_payload()
for attach in payloads:
out.append({'content-type': attach.get_content_type(), 'data': attach.get_payload(), 'content-id': attach.get('Content-Id')})
return out

0 comments on commit d979474

Please sign in to comment.