11'''
2- Copyright (c) 2014
2+ Copyright (c) 2014-2018
33All rights reserved. Use is subject to license terms and conditions.
4- Created on Dec 30, 2014
5- Updated on Mar 19,2015
64@author: Yongxiang Qiu, Kay Kasemir
75'''
86
97import time
108import xml .etree .ElementTree as ET
119import urllib
12- import urllib2
1310from scan .client .logdata import parseXMLData
1411from scan .commands .commandsequence import CommandSequence
1512from scaninfo import ScanInfo
1613
17-
18- # Bug https://github.com/PythonScanClient/PyScanClient/issues/18
14+ # Python code uses urllib2.
15+ # When accessed from jython, there were two problems.
1916#
17+ # 1) https://github.com/PythonScanClient/PyScanClient/issues/18
2018# urllib2 is based on _socket.py.
2119# Depending on how BOY invokes jython,
2220# even a new threadLocalStateInterpreter and a newly compiled
2523# its threadLocalStateInterpreter.
2624# Calls to urllib2 will then receive a connection error based on
2725# "RejectedExecutionException: event executor terminated".
26+ # Workaround was to re-create the _socket.NIO_GROUP
27+ # and call sys.registerCloser(_socket._shutdown_threadpool)
28+ #
29+ # 2) https://github.com/ControlSystemStudio/cs-studio/issues/2535
30+ # After updating to jython 2.7.1, the HTTP 'POST' appeared limited
31+ # to sending 65k of data.
32+ #
33+ # Workaround for both is to use Java HTTP API for jython
2834import os
2935if os .name == 'java' :
30- import sys , _socket
31- # Log detail of the _socket code
32- #import logging
33- #logging.basicConfig(level=logging.DEBUG)
34- #log = logging.getLogger("_socket")
35- #log.setLevel(level=logging.DEBUG)
36-
37- def checkSocketLib ():
38- # Workaround: Detect closed NIO_GROUP and ee-create it
39- try :
40- if _socket .NIO_GROUP .isShutdown ():
41- # print "RE-CREATEING NIO_GROUP!!!!!!!!!"
42- # _socket._NUM_THREADS is 10. Using only 2 threads.
43- _socket .NIO_GROUP = _socket .NioEventLoopGroup (2 , _socket .DaemonThreadFactory ("PyScan-Netty-Client-%s" ))
44- sys .registerCloser (_socket ._shutdown_threadpool )
45- except AttributeError :
46- print "Jython _socket.py has changed from jython_2.7.0"
47- else :
48- def checkSocketLib ():
49- # C-Python _socket.py needs no fix
50- pass
36+ import java .lang
37+ from java .io import BufferedReader , InputStreamReader , OutputStream
38+ from java .net import HttpURLConnection , URL
5139
52-
53- class ScanClient (object ):
54- """Client interface to the scan server
55-
56- :param host: The IP address or name of scan server host.
57- :param port: The TCP port of the scan server.
58-
59- Example:
40+ def perform_request (url , method = 'GET' , data = None ):
41+ try :
42+ connection = URL (url ).openConnection ()
43+ connection .setRequestProperty ("Connection" , "close" )
44+ connection .setRequestProperty ("User-Agent" , "PyScanClient" )
45+ connection .setRequestProperty ("Accept" , "text/xml" )
46+ connection .setDoOutput (True )
47+ connection .setRequestMethod (method )
48+ if data is not None :
49+ data = java .lang .String (data ).getBytes ()
50+ connection .setRequestProperty ("Content-Type" , "text/xml" )
51+ connection .setRequestProperty ("Content-Length" , str (len (data )))
52+ out = connection .getOutputStream ()
53+ out .write (data )
54+ out .close ()
6055
61- >>> client = ScanClient('localhost')
62- """
63- __baseURL = None
64- __serverResource = "/server"
65- __serverInfoResource = "/info"
66- __simulateResource = "/simulate"
67- __scansResource = "/scans"
68- __scansCompletedResource = "/completed"
69- __scanResource = "/scan"
70-
71- def __init__ (self , host = 'localhost' , port = 4810 ):
72- self .__host = host
73- self .__port = int (port ) #no matter what type of 'port' input, self._port keeps to be int.
74- #May implement a one to one host+port with instance in the future.
75- self .__baseURL = "http://" + self .__host + ':' + str (self .__port )
56+ inp = BufferedReader (InputStreamReader (connection .getInputStream ()))
57+ result = java .lang .StringBuilder ()
58+ while True :
59+ line = inp .readLine ()
60+ if line is None :
61+ break
62+ result .append (line ).append ('\n ' )
63+ inp .close ()
64+ result = result .toString ()
65+ connection .disconnect ()
66+ return result
67+ except java .lang .Exception as e :
68+ raise Exception ("%s: %s" % (url , str (e )))
7669
77-
78- def __repr__ (self ):
79- return "ScanClient('%s', %d)" % (self .__host , self .__port )
70+ else :
71+ import urllib2
8072
81-
82- def __do_request (self , url , method = 'GET' , data = None ):
73+ def perform_request (url , method = 'GET' , data = None ):
8374 """Perform HTTP request with scan server
8475
8576 :param url: URL
@@ -88,7 +79,6 @@ def __do_request(self, url, method='GET', data=None):
8879
8980 :return: XML response from scan server
9081 """
91- checkSocketLib ()
9282 response = None
9383 try :
9484 # Register a Request Object with url:
@@ -118,14 +108,43 @@ def __do_request(self, url, method='GET', data=None):
118108 return response .read ()
119109 except urllib2 .URLError as e :
120110 if hasattr (e , 'reason' ):
121- raise Exception ("Failed to reach scan server at %s:%d: %s" % (self . __host , self . __port , e .reason ))
111+ raise Exception ("Failed to reach scan server at %s: %s" % (url , e .reason ))
122112 elif hasattr (e , 'code' ):
123- raise Exception ("Scan server at %s:%d returned error code %d" % (self . __host , self . __port , e .code ))
113+ raise Exception ("Scan server at %s returned error code %d" % (url , e .code ))
124114 finally :
125115 if response :
126116 response .close ()
127117
128-
118+
119+ class ScanClient (object ):
120+ """Client interface to the scan server
121+
122+ :param host: The IP address or name of scan server host.
123+ :param port: The TCP port of the scan server.
124+
125+ Example:
126+
127+ >>> client = ScanClient('localhost')
128+ """
129+ __baseURL = None
130+ __serverResource = "/server"
131+ __serverInfoResource = "/info"
132+ __simulateResource = "/simulate"
133+ __scansResource = "/scans"
134+ __scansCompletedResource = "/completed"
135+ __scanResource = "/scan"
136+
137+ def __init__ (self , host = 'localhost' , port = 4810 ):
138+ self .__host = host
139+ self .__port = int (port ) #no matter what type of 'port' input, self._port keeps to be int.
140+ #May implement a one to one host+port with instance in the future.
141+ self .__baseURL = "http://" + self .__host + ':' + str (self .__port )
142+
143+
144+ def __repr__ (self ):
145+ return "ScanClient('%s', %d)" % (self .__host , self .__port )
146+
147+
129148 def serverInfo (self ):
130149 """Get scan server information
131150
@@ -140,7 +159,7 @@ def serverInfo(self):
140159 >>> client = ScanClient()
141160 >>> print client.serverInfo()
142161 """
143- return self . __do_request (self .__baseURL + self .__serverResource + self .__serverInfoResource )
162+ return perform_request (self .__baseURL + self .__serverResource + self .__serverInfoResource )
144163
145164
146165 def simulate (self , cmds ):
@@ -167,7 +186,7 @@ def simulate(self, cmds):
167186
168187 url = self .__baseURL + self .__simulateResource
169188
170- result = self . __do_request (url , 'POST' , scan )
189+ result = perform_request (url , 'POST' , scan )
171190 xml = ET .fromstring (result )
172191 if xml .tag != 'simulation' :
173192 raise Exception ("Expected scan <simulation>, got <%s>" % xml .tag )
@@ -232,7 +251,7 @@ def __submitScanXML(self, scanXML, scanName, queue=True):
232251 url = self .__baseURL + self .__scanResource + '/' + scanName
233252 if not queue :
234253 url = url + "?queue=false"
235- r = self . __do_request (url , 'POST' , scanXML )
254+ r = perform_request (url , 'POST' , scanXML )
236255 return r
237256
238257
@@ -260,7 +279,7 @@ def scanInfos(self):
260279 >>> infos = client.scanInfos()
261280 >>> print [ str(info) for info in infos ]
262281 """
263- xml = self . __do_request (self .__baseURL + self .__scansResource )
282+ xml = perform_request (self .__baseURL + self .__scansResource )
264283 scans = ET .fromstring (xml )
265284 result = list ()
266285 for scan in scans .findall ('scan' ):
@@ -281,7 +300,7 @@ def scanInfo(self, scanID):
281300 >>> client = ScanClient()
282301 >>> print client.scanInfo(42)
283302 """
284- xml = self . __do_request (self .__baseURL + self .__scanResource + '/' + str (scanID ))
303+ xml = perform_request (self .__baseURL + self .__scanResource + '/' + str (scanID ))
285304 return ScanInfo (ET .fromstring (xml ))
286305
287306
@@ -305,7 +324,7 @@ def scanCmds(self, scanID):
305324 >>> client.submit(client.scanCmds(scanid))
306325 """
307326 url = self .__baseURL + self .__scanResource + '/' + str (scanID )+ '/commands'
308- xml = self . __do_request (url )
327+ xml = perform_request (url )
309328 return xml
310329
311330
@@ -332,7 +351,7 @@ def lastSerial(self, scanID):
332351 >>> time.sleep(10
333352 """
334353 url = self .__baseURL + self .__scanResource + '/' + str (scanID )+ '/last_serial'
335- xml = self . __do_request (url )
354+ xml = perform_request (url )
336355 ET .fromstring (xml )
337356 return int (ET .fromstring (xml ).text )
338357
@@ -352,7 +371,7 @@ def scanDevices(self, scanID=-1):
352371 :return: XML with info about devices.
353372 """
354373 url = self .__baseURL + self .__scanResource + '/' + str (scanID )+ '/devices'
355- xml = self . __do_request (url )
374+ xml = perform_request (url )
356375 return xml
357376
358377
@@ -393,7 +412,7 @@ def pause(self, scanID=-1):
393412 >>> client.pause(id)
394413 """
395414 url = self .__baseURL + self .__scanResource + '/' + str (scanID ) + '/pause'
396- self . __do_request (url , 'PUT' )
415+ perform_request (url , 'PUT' )
397416
398417
399418 def resume (self , scanID = - 1 ):
@@ -410,7 +429,7 @@ def resume(self, scanID=-1):
410429 >>> client.resume(id)
411430 """
412431 url = self .__baseURL + self .__scanResource + '/' + str (scanID ) + '/resume'
413- self . __do_request (url , 'PUT' )
432+ perform_request (url , 'PUT' )
414433
415434
416435 def abort (self , scanID = - 1 ):
@@ -426,7 +445,7 @@ def abort(self, scanID=-1):
426445 >>> client.abort(id)
427446 """
428447 url = self .__baseURL + self .__scanResource + '/' + str (scanID ) + '/abort'
429- self . __do_request (url , 'PUT' )
448+ perform_request (url , 'PUT' )
430449
431450
432451 def delete (self , scanID ):
@@ -442,7 +461,7 @@ def delete(self, scanID):
442461 >>> client.abort(id)
443462 >>> client.delete(id)
444463 """
445- self . __do_request (self .__baseURL + self .__scanResource + '/' + str (scanID ), 'DELETE' )
464+ perform_request (self .__baseURL + self .__scanResource + '/' + str (scanID ), 'DELETE' )
446465
447466
448467 def clear (self ):
@@ -454,7 +473,7 @@ def clear(self):
454473
455474 >>> client.clear()
456475 """
457- self . __do_request (self .__baseURL + self .__scansResource + self .__scansCompletedResource , 'DELETE' )
476+ perform_request (self .__baseURL + self .__scansResource + self .__scansCompletedResource , 'DELETE' )
458477
459478 def patch (self , scanID , address , property , value ): # @ReservedAssignment
460479 """Update scan on server.
@@ -482,7 +501,7 @@ def patch(self, scanID, address, property, value): # @ReservedAssignment
482501 >>> client.resume(id)
483502 """
484503 xml = "<patch><address>%d</address><property>%s</property><value>%s</value></patch>" % (address , property , str (value ))
485- self . __do_request (self .__baseURL + self .__scanResource + '/' + str (id ) + '/patch' , 'PUT' , xml )
504+ perform_request (self .__baseURL + self .__scanResource + '/' + str (id ) + '/patch' , 'PUT' , xml )
486505
487506
488507 def getData (self , scanID ):
@@ -519,6 +538,6 @@ def getData(self, scanID):
519538 Times in Posix milliseconds
520539 """
521540 url = self .__baseURL + self .__scanResource + '/' + str (scanID )+ '/data'
522- xml = self . __do_request (url )
541+ xml = perform_request (url )
523542 return parseXMLData (xml )
524543
0 commit comments