iris-pex-embedded-python 2.3.28b2__py3-none-any.whl → 3.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of iris-pex-embedded-python might be problematic. Click here for more details.

Files changed (71) hide show
  1. grongier/cls/Grongier/PEX/BusinessOperation.cls +1 -28
  2. grongier/cls/Grongier/PEX/BusinessProcess.cls +1 -112
  3. grongier/cls/Grongier/PEX/BusinessService.cls +1 -28
  4. grongier/cls/Grongier/PEX/Common.cls +1 -194
  5. grongier/cls/Grongier/PEX/Director.cls +1 -48
  6. grongier/cls/Grongier/PEX/Duplex/Operation.cls +1 -26
  7. grongier/cls/Grongier/PEX/Duplex/Process.cls +1 -217
  8. grongier/cls/Grongier/PEX/Duplex/Service.cls +1 -6
  9. grongier/cls/Grongier/PEX/InboundAdapter.cls +1 -15
  10. grongier/cls/Grongier/PEX/Message.cls +1 -116
  11. grongier/cls/Grongier/PEX/OutboundAdapter.cls +1 -29
  12. grongier/cls/Grongier/PEX/PickleMessage.cls +1 -46
  13. grongier/cls/Grongier/PEX/PrivateSession/Duplex.cls +1 -253
  14. grongier/cls/Grongier/PEX/PrivateSession/Message/Ack.cls +1 -19
  15. grongier/cls/Grongier/PEX/PrivateSession/Message/Poll.cls +1 -19
  16. grongier/cls/Grongier/PEX/PrivateSession/Message/Start.cls +1 -19
  17. grongier/cls/Grongier/PEX/PrivateSession/Message/Stop.cls +1 -35
  18. grongier/cls/Grongier/PEX/Test.cls +1 -53
  19. grongier/cls/Grongier/PEX/Utils.cls +1 -365
  20. grongier/cls/Grongier/Service/WSGI.cls +1 -307
  21. grongier/pex/__init__.py +11 -11
  22. grongier/pex/__main__.py +1 -1
  23. grongier/pex/_business_host.py +1 -511
  24. grongier/pex/_cli.py +1 -152
  25. grongier/pex/_common.py +1 -347
  26. grongier/pex/_director.py +1 -286
  27. grongier/pex/_utils.py +1 -369
  28. iop/__init__.py +24 -0
  29. iop/__main__.py +4 -0
  30. iop/_business_host.py +511 -0
  31. {grongier/pex → iop}/_business_operation.py +1 -1
  32. {grongier/pex → iop}/_business_process.py +1 -1
  33. {grongier/pex → iop}/_business_service.py +1 -1
  34. iop/_cli.py +152 -0
  35. iop/_common.py +349 -0
  36. iop/_director.py +286 -0
  37. {grongier/pex → iop}/_inbound_adapter.py +1 -1
  38. {grongier/pex → iop}/_outbound_adapter.py +1 -1
  39. {grongier/pex → iop}/_private_session_duplex.py +1 -1
  40. {grongier/pex → iop}/_private_session_process.py +2 -2
  41. iop/_utils.py +374 -0
  42. iop/cls/IOP/BusinessOperation.cls +35 -0
  43. iop/cls/IOP/BusinessProcess.cls +124 -0
  44. iop/cls/IOP/BusinessService.cls +35 -0
  45. iop/cls/IOP/Common.cls +203 -0
  46. iop/cls/IOP/Director.cls +57 -0
  47. iop/cls/IOP/Duplex/Operation.cls +29 -0
  48. iop/cls/IOP/Duplex/Process.cls +229 -0
  49. iop/cls/IOP/Duplex/Service.cls +9 -0
  50. iop/cls/IOP/InboundAdapter.cls +22 -0
  51. iop/cls/IOP/Message.cls +128 -0
  52. iop/cls/IOP/OutboundAdapter.cls +36 -0
  53. iop/cls/IOP/PickleMessage.cls +58 -0
  54. iop/cls/IOP/PrivateSession/Duplex.cls +260 -0
  55. iop/cls/IOP/PrivateSession/Message/Ack.cls +32 -0
  56. iop/cls/IOP/PrivateSession/Message/Poll.cls +32 -0
  57. iop/cls/IOP/PrivateSession/Message/Start.cls +32 -0
  58. iop/cls/IOP/PrivateSession/Message/Stop.cls +48 -0
  59. iop/cls/IOP/Service/WSGI.cls +310 -0
  60. iop/cls/IOP/Test.cls +62 -0
  61. iop/cls/IOP/Utils.cls +374 -0
  62. iop/wsgi/handlers.py +104 -0
  63. {iris_pex_embedded_python-2.3.28b2.dist-info → iris_pex_embedded_python-3.0.0.dist-info}/METADATA +28 -28
  64. {iris_pex_embedded_python-2.3.28b2.dist-info → iris_pex_embedded_python-3.0.0.dist-info}/RECORD +70 -42
  65. {iris_pex_embedded_python-2.3.28b2.dist-info → iris_pex_embedded_python-3.0.0.dist-info}/WHEEL +1 -1
  66. iris_pex_embedded_python-3.0.0.dist-info/entry_points.txt +2 -0
  67. {iris_pex_embedded_python-2.3.28b2.dist-info → iris_pex_embedded_python-3.0.0.dist-info}/top_level.txt +1 -0
  68. iris_pex_embedded_python-2.3.28b2.dist-info/entry_points.txt +0 -2
  69. {grongier/pex → iop}/_message.py +0 -0
  70. {grongier/pex → iop}/_pickle_message.py +0 -0
  71. {iris_pex_embedded_python-2.3.28b2.dist-info → iris_pex_embedded_python-3.0.0.dist-info}/LICENSE +0 -0
iop/_utils.py ADDED
@@ -0,0 +1,374 @@
1
+ import os
2
+ import ast
3
+ import iris
4
+ import inspect
5
+ import xmltodict
6
+ import pkg_resources
7
+
8
+ class _Utils():
9
+ @staticmethod
10
+ def raise_on_error(sc):
11
+ """
12
+ If the status code is an error, raise an exception
13
+
14
+ :param sc: The status code returned by the Iris API
15
+ """
16
+ if iris.system.Status.IsError(sc):
17
+ raise RuntimeError(iris.system.Status.GetOneStatusText(sc))
18
+
19
+ @staticmethod
20
+ def setup(path:str = None):
21
+
22
+ if path is None:
23
+ # get the path of the data folder with pkg_resources
24
+ path = pkg_resources.resource_filename('iop', 'cls')
25
+
26
+ _Utils.raise_on_error(iris.cls('%SYSTEM.OBJ').LoadDir(path,'cubk',"*.cls",1))
27
+
28
+ # for retrocompatibility load grongier.pex
29
+ path = pkg_resources.resource_filename('grongier', 'cls')
30
+
31
+ _Utils.raise_on_error(iris.cls('%SYSTEM.OBJ').LoadDir(path,'cubk',"*.cls",1))
32
+
33
+ @staticmethod
34
+ def register_component(module:str,classname:str,path:str,overwrite:int=1,iris_classname:str='Python'):
35
+ """
36
+ It registers a component in the Iris database.
37
+
38
+ :param module: The name of the module that contains the class
39
+ :type module: str
40
+ :param classname: The name of the class you want to register
41
+ :type classname: str
42
+ :param path: The path to the component
43
+ :type path: str
44
+ :param overwrite: 0 = no, 1 = yes
45
+ :type overwrite: int
46
+ :param iris_classname: The name of the class in the Iris class hierarchy
47
+ :type iris_classname: str
48
+ :return: The return value is a string.
49
+ """
50
+ path = os.path.normpath(path)
51
+ # get the absolute path of the folder
52
+ path = os.path.abspath(path)
53
+ return iris.cls('Grongier.PEX.Utils').dispatchRegisterComponent(module,classname,path,overwrite,iris_classname)
54
+
55
+ @staticmethod
56
+ def register_folder(path:str,overwrite:int=1,iris_package_name:str='Python'):
57
+ """
58
+ > This function takes a path to a folder, and registers all the Python files in that folder as IRIS
59
+ classes
60
+
61
+ :param path: the path to the folder containing the files you want to register
62
+ :type path: str
63
+ :param overwrite:
64
+ :type overwrite: int
65
+ :param iris_package_name: The name of the iris package you want to register the file to
66
+ :type iris_package_name: str
67
+ """
68
+ path = os.path.normpath(path)
69
+ # get the absolute path of the folder
70
+ path = os.path.abspath(path)
71
+ for filename in os.listdir(path):
72
+ if filename.endswith(".py"):
73
+ _Utils._register_file(filename, path, overwrite, iris_package_name)
74
+ else:
75
+ continue
76
+
77
+ @staticmethod
78
+ def register_file(file:str,overwrite:int=1,iris_package_name:str='Python'):
79
+ """
80
+ It takes a file name, a boolean to overwrite existing components, and the name of the Iris
81
+ package that the file is in. It then opens the file, parses it, and looks for classes that extend
82
+ BusinessOperation, BusinessProcess, or BusinessService. If it finds one, it calls register_component
83
+ with the module name, class name, path, overwrite boolean, and the full Iris package name
84
+
85
+ :param file: the name of the file containing the component
86
+ :type file: str
87
+ :param overwrite: if the component already exists, overwrite it
88
+ :type overwrite: int
89
+ :param iris_package_name: the name of the iris package that you want to register the components to
90
+ :type iris_package_name: str
91
+ """
92
+ head_tail = os.path.split(file)
93
+ return _Utils._register_file(head_tail[1],head_tail[0],overwrite,iris_package_name)
94
+
95
+ @staticmethod
96
+ def _register_file(filename:str,path:str,overwrite:int=1,iris_package_name:str='Python'):
97
+ """
98
+ It takes a file name, a path, a boolean to overwrite existing components, and the name of the Iris
99
+ package that the file is in. It then opens the file, parses it, and looks for classes that extend
100
+ BusinessOperation, BusinessProcess, or BusinessService. If it finds one, it calls register_component
101
+ with the module name, class name, path, overwrite boolean, and the full Iris package name
102
+
103
+ :param filename: the name of the file containing the component
104
+ :type filename: str
105
+ :param path: the path to the directory containing the files to be registered
106
+ :type path: str
107
+ :param overwrite: if the component already exists, overwrite it
108
+ :type overwrite: int
109
+ :param iris_package_name: the name of the iris package that you want to register the components to
110
+ :type iris_package_name: str
111
+ """
112
+ #pour chaque classe dans le module, appeler register_component
113
+ f = os.path.join(path,filename)
114
+ with open(f) as file:
115
+ node = ast.parse(file.read())
116
+ #list of class in the file
117
+ classes = [n for n in node.body if isinstance(n, ast.ClassDef)]
118
+ for klass in classes:
119
+ extend = ''
120
+ if len(klass.bases) == 1:
121
+ if hasattr(klass.bases[0],'id'):
122
+ extend = klass.bases[0].id
123
+ else:
124
+ extend = klass.bases[0].attr
125
+ if extend in ('BusinessOperation','BusinessProcess','BusinessService','DuplexService','DuplexProcess','DuplexOperation','InboundAdapter','OutboundAdapter'):
126
+ module = _Utils.filename_to_module(filename)
127
+ iris_class_name = f"{iris_package_name}.{module}.{klass.name}"
128
+ # strip "_" for iris class name
129
+ iris_class_name = iris_class_name.replace('_','')
130
+ _Utils.register_component(module, klass.name, path, overwrite, iris_class_name)
131
+ @staticmethod
132
+ def register_package(package:str,path:str,overwrite:int=1,iris_package_name:str='Python'):
133
+ """
134
+ It takes a package name, a path to the package, a flag to overwrite existing files, and the name of
135
+ the iris package to register the files to. It then loops through all the files in the package and
136
+ registers them to the iris package
137
+
138
+ :param package: the name of the package you want to register
139
+ :type package: str
140
+ :param path: the path to the directory containing the package
141
+ :type path: str
142
+ :param overwrite: 0 = don't overwrite, 1 = overwrite
143
+ :type overwrite: int
144
+ :param iris_package_name: The name of the package in the Iris package manager
145
+ :type iris_package_name: str
146
+ """
147
+ for filename in os.listdir(os.path.join(path,package)):
148
+ if filename.endswith(".py"):
149
+ _Utils._register_file(filename, os.path.join(path,package), overwrite, iris_package_name)
150
+ else:
151
+ continue
152
+
153
+ @staticmethod
154
+ def filename_to_module(filename) -> str:
155
+ """
156
+ It takes a filename and returns the module name
157
+
158
+ :param filename: The name of the file to be imported
159
+ :return: The module name
160
+ """
161
+ module = ''
162
+
163
+ path,file = os.path.split(filename)
164
+ mod = file.split('.')[0]
165
+ packages = path.replace(os.sep, ('.'))
166
+ if len(packages) >1:
167
+ module = packages+'.'+mod
168
+ else:
169
+ module = mod
170
+
171
+ return module
172
+
173
+ @staticmethod
174
+ def migrate(filename=None,root_path=None):
175
+ """
176
+ Read the settings.py file and register all the components
177
+ settings.py file has two dictionaries:
178
+ * CLASSES
179
+ * key: the name of the class
180
+ * value: an instance of the class
181
+ * PRODUCTIONS
182
+ list of dictionaries:
183
+ * key: the name of the production
184
+ * value: a dictionary containing the settings for the production
185
+ """
186
+ # try to load the settings file
187
+ if filename:
188
+ import sys
189
+ path = None
190
+ # check if the filename is absolute or relative
191
+ if os.path.isabs(filename):
192
+ path = os.path.dirname(filename)
193
+ else:
194
+ raise ValueError("The filename must be absolute")
195
+ # add the path to the system path
196
+ sys.path.append(path)
197
+ import settings
198
+ # get the path of the settings file
199
+ path = os.path.dirname(inspect.getfile(settings))
200
+ try:
201
+ # set the classes settings
202
+ _Utils.set_classes_settings(settings.CLASSES,path)
203
+ except AttributeError:
204
+ print("No classes to register")
205
+ try:
206
+ # set the productions settings
207
+ _Utils.set_productions_settings(settings.PRODUCTIONS,path)
208
+ except AttributeError:
209
+ print("No productions to register")
210
+
211
+
212
+
213
+ @staticmethod
214
+ def set_classes_settings(class_items,root_path=None):
215
+ """
216
+ It takes a dictionary of classes and returns a dictionary of settings for each class
217
+
218
+ :param class_items: a dictionary of classes
219
+ :return: a dictionary of settings for each class
220
+ """
221
+ for key, value in class_items.items():
222
+ if inspect.isclass(value):
223
+ path = None
224
+ if root_path:
225
+ path = root_path
226
+ else:
227
+ path = os.path.dirname(inspect.getfile(value))
228
+ _Utils.register_component(value.__module__,value.__name__,path,1,key)
229
+ elif inspect.ismodule(value):
230
+ path = None
231
+ if root_path:
232
+ path = root_path
233
+ else:
234
+ path = os.path.dirname(inspect.getfile(value))
235
+ _Utils._register_file(value.__name__+'.py',path,1,key)
236
+ # if the value is a dict
237
+ elif isinstance(value,dict):
238
+ # if the dict has a key 'path' and a key 'module' and a key 'class'
239
+ if 'path' in value and 'module' in value and 'class' in value:
240
+ # register the component
241
+ _Utils.register_component(value['module'],value['class'],value['path'],1,key)
242
+ # if the dict has a key 'path' and a key 'package'
243
+ elif 'path' in value and 'package' in value:
244
+ # register the package
245
+ _Utils.register_package(value['package'],value['path'],1,key)
246
+ # if the dict has a key 'path' and a key 'file'
247
+ elif 'path' in value and 'file' in value:
248
+ # register the file
249
+ _Utils._register_file(value['file'],value['path'],1,key)
250
+ # if the dict has a key 'path'
251
+ elif 'path' in value:
252
+ # register folder
253
+ _Utils.register_folder(value['path'],1,key)
254
+ else:
255
+ raise ValueError(f"Invalid value for {key}.")
256
+
257
+ @staticmethod
258
+ def set_productions_settings(production_list,root_path=None):
259
+ """
260
+ It takes a list of dictionaries and registers the productions
261
+ """
262
+ # for each production in the list
263
+ for production in production_list:
264
+ # get the production name (first key in the dictionary)
265
+ production_name = list(production.keys())[0]
266
+ # set the first key to 'production'
267
+ production['Production'] = production.pop(production_name)
268
+ # handle Items
269
+ production = _Utils.handle_items(production,root_path)
270
+ # transform the json as an xml
271
+ xml = _Utils.dict_to_xml(production)
272
+ # register the production
273
+ _Utils.register_production(production_name,xml)
274
+
275
+ @staticmethod
276
+ def handle_items(production,root_path=None):
277
+ # if an item is a class, register it and replace it with the name of the class
278
+ if 'Item' in production['Production']:
279
+ # for each item in the list
280
+ for i,item in enumerate(production['Production']['Item']):
281
+ # if the attribute "@ClassName" is a class, register it and replace it with the name of the class
282
+ if '@ClassName' in item:
283
+ if inspect.isclass(item['@ClassName']):
284
+ path = None
285
+ if root_path:
286
+ path = root_path
287
+ else:
288
+ path = os.path.dirname(inspect.getfile(item['@ClassName']))
289
+ _Utils.register_component(item['@ClassName'].__module__,item['@ClassName'].__name__,path,1,item['@Name'])
290
+ # replace the class with the name of the class
291
+ production['Production']['Item'][i]['@ClassName'] = item['@Name']
292
+ # if the attribute "@ClassName" is a dict
293
+ elif isinstance(item['@ClassName'],dict):
294
+ # create a new dict where the key is the name of the class and the value is the dict
295
+ class_dict = {item['@Name']:item['@ClassName']}
296
+ # pass the new dict to set_classes_settings
297
+ _Utils.set_classes_settings(class_dict)
298
+ # replace the class with the name of the class
299
+ production['Production']['Item'][i]['@ClassName'] = item['@Name']
300
+ else:
301
+ raise ValueError(f"Invalid value for {item['@Name']}.")
302
+
303
+ return production
304
+
305
+ @staticmethod
306
+ def dict_to_xml(json):
307
+ """
308
+ It takes a json and returns an xml
309
+
310
+ :param json: a json
311
+ :return: an xml
312
+ """
313
+ xml = xmltodict.unparse(json,pretty=True)
314
+ # remove the xml version tag
315
+ xml = xml.replace('<?xml version="1.0" encoding="utf-8"?>','')
316
+ # remove the new line at the beginning of the xml
317
+ xml = xml[1:]
318
+ return xml
319
+
320
+ @staticmethod
321
+ def register_production(production_name,xml):
322
+ """
323
+ It takes a production name and an xml and registers the production
324
+
325
+ :param production_name: the name of the production
326
+ :type production_name: str
327
+ :param xml: the xml of the production
328
+ :type xml: str
329
+ """
330
+ # split the production name in the package name and the production name
331
+ # the production name is the last part of the string
332
+ package = '.'.join(production_name.split('.')[:-1])
333
+ production_name = production_name.split('.')[-1]
334
+ stream = _Utils.string_to_stream(xml)
335
+ # register the production
336
+ _Utils.raise_on_error(iris.cls('Grongier.PEX.Utils').CreateProduction(package,production_name,stream))
337
+
338
+ @staticmethod
339
+ def export_production(production_name):
340
+ """
341
+ It takes a production name and exports the production
342
+
343
+ :param production_name: the name of the production
344
+ :type production_name: str
345
+ """
346
+ def postprocessor(path, key, value):
347
+ if value is None:
348
+ return key, ''
349
+ return key, value
350
+ # export the production
351
+ xdata = iris.cls('Grongier.PEX.Utils').ExportProduction(production_name)
352
+ # for each chunk of 1024 characters
353
+ string = _Utils.stream_to_string(xdata)
354
+ # convert the xml to a dictionary
355
+ data = xmltodict.parse(string,postprocessor=postprocessor)
356
+ # return the dictionary
357
+ return data
358
+
359
+ @staticmethod
360
+ def stream_to_string(stream)-> str:
361
+ string = ""
362
+ stream.Rewind()
363
+ while not stream.AtEnd:
364
+ string += stream.Read(4092)
365
+ return string
366
+
367
+ @staticmethod
368
+ def string_to_stream(string:str):
369
+ stream = iris.cls('%Stream.GlobalCharacter')._New()
370
+ n = 4092
371
+ chunks = [string[i:i+n] for i in range(0, len(string), n)]
372
+ for chunk in chunks:
373
+ stream.Write(chunk)
374
+ return stream
@@ -0,0 +1,35 @@
1
+ /* Copyright (c) 2021 by InterSystems Corporation.
2
+ Cambridge, Massachusetts, U.S.A. All rights reserved.
3
+ Confidential property of InterSystems Corporation. */
4
+
5
+ Class IOP.BusinessOperation Extends (Ens.BusinessOperation, IOP.Common) [ Inheritance = right, ProcedureBlock, System = 4 ]
6
+ {
7
+
8
+ Parameter SETTINGS = "%classname:Python BusinessOperation,%module:Python BusinessOperation,%settings:Python BusinessOperation,%classpaths:Python BusinessOperation";
9
+
10
+ Method OnMessage(
11
+ request As %Library.Persistent,
12
+ Output response As %Library.Persistent) As %Status
13
+ {
14
+ set tSC = $$$OK
15
+ try {
16
+ set response = ..%class."_dispatch_on_message"(request)
17
+ } catch ex {
18
+ set tSC = ex.AsStatus()
19
+ }
20
+ quit tSC
21
+ }
22
+
23
+ Method OnKeepalive(pStatus As %Status = {$$$OK}) As %Status
24
+ {
25
+ set tSC = $$$OK
26
+ try {
27
+ $$$ThrowOnError(##super(pStatus))
28
+ do ..%class."on_keepalive"()
29
+ } catch ex {
30
+ set tSC = ex.AsStatus()
31
+ }
32
+ quit tSC
33
+ }
34
+
35
+ }
@@ -0,0 +1,124 @@
1
+ /* Copyright (c) 2021 by InterSystems Corporation.
2
+ Cambridge, Massachusetts, U.S.A. All rights reserved.
3
+ Confidential property of InterSystems Corporation. */
4
+
5
+ Class IOP.BusinessProcess Extends (Ens.BusinessProcess, IOP.Common) [ Inheritance = right, ProcedureBlock, System = 4 ]
6
+ {
7
+
8
+ Parameter SETTINGS = "%classname:Python BusinessProcess,%module:Python BusinessProcess,%settings:Python BusinessProcess,%classpaths:Python BusinessProcess";
9
+
10
+ Property persistentProperties As array Of %String(MAXLEN = "");
11
+
12
+ Method dispatchReply(response)
13
+ {
14
+ set tSC = ..Reply(response)
15
+ if $$$ISERR(tSC) throw ##class(%Exception.StatusException).CreateFromStatus(tSC)
16
+ quit
17
+ }
18
+
19
+ Method dispatchSetTimer(
20
+ timeout,
21
+ completionKey)
22
+ {
23
+ set tSC = ..SetTimer(timeout,$g(completionKey))
24
+ if $$$ISERR(tSC) throw ##class(%Exception.StatusException).CreateFromStatus(tSC)
25
+ quit
26
+ }
27
+
28
+ Method dispatchSendRequestAsync(
29
+ target,
30
+ request,
31
+ responseRequired,
32
+ completionKey,
33
+ description)
34
+ {
35
+ set tSC = ..SendRequestAsync(target,request,responseRequired,completionKey,description)
36
+ if $$$ISERR(tSC) throw ##class(%Exception.StatusException).CreateFromStatus(tSC)
37
+ quit
38
+ }
39
+
40
+ Method OnRequest(
41
+ request As %Persistent,
42
+ Output response As %Persistent) As %Status
43
+ {
44
+ set tSC = $$$OK
45
+ try {
46
+ set response = ..%class."_dispatch_on_request"($this,request)
47
+ } catch ex {
48
+ set tSC = ex.AsStatus()
49
+ }
50
+ quit tSC
51
+ }
52
+
53
+ /// Handle a 'Response'
54
+ Method OnResponse(
55
+ request As %Persistent,
56
+ Output response As %Persistent,
57
+ callRequest As %Persistent,
58
+ callResponse As %Persistent,
59
+ pCompletionKey As %String) As %Status
60
+ {
61
+ set tSC = $$$OK
62
+ try {
63
+ set response = ..%class."_dispatch_on_response"($this,request,response,callRequest,callResponse,pCompletionKey)
64
+ } catch ex {
65
+ set tSC = ex.AsStatus()
66
+ }
67
+ quit tSC
68
+ }
69
+
70
+ Method OnComplete(
71
+ request As %Library.Persistent,
72
+ ByRef response As %Library.Persistent) As %Status
73
+ {
74
+ set tSC = $$$OK
75
+ try {
76
+ set response = ..%class."_dispatch_on_complete"($this,request,response)
77
+ } catch ex {
78
+ set tSC = ex.AsStatus()
79
+ }
80
+ quit tSC
81
+ }
82
+
83
+ Method getPersistentProperty(name)
84
+ {
85
+ quit ..persistentProperties.GetAt(name)
86
+ }
87
+
88
+ Method setPersistentProperty(
89
+ name,
90
+ value)
91
+ {
92
+ quit ..persistentProperties.SetAt(value,name)
93
+ }
94
+
95
+ Storage Default
96
+ {
97
+ <Data name="BusinessProcessDefaultData1">
98
+ <Subscript>"BusinessProcess"</Subscript>
99
+ <Value name="1">
100
+ <Value>%classpaths</Value>
101
+ </Value>
102
+ <Value name="2">
103
+ <Value>%classname</Value>
104
+ </Value>
105
+ <Value name="3">
106
+ <Value>%module</Value>
107
+ </Value>
108
+ <Value name="4">
109
+ <Value>%settings</Value>
110
+ </Value>
111
+ <Value name="5">
112
+ <Value>%class</Value>
113
+ </Value>
114
+ </Data>
115
+ <Data name="persistentProperties">
116
+ <Attribute>persistentProperties</Attribute>
117
+ <Structure>subnode</Structure>
118
+ <Subscript>"IOP.BusinessProcess.persistentProperties"</Subscript>
119
+ </Data>
120
+ <DefaultData>BusinessProcessDefaultData1</DefaultData>
121
+ <Type>%Storage.Persistent</Type>
122
+ }
123
+
124
+ }
@@ -0,0 +1,35 @@
1
+ /* Copyright (c) 2021 by InterSystems Corporation.
2
+ Cambridge, Massachusetts, U.S.A. All rights reserved.
3
+ Confidential property of InterSystems Corporation. */
4
+
5
+ Class IOP.BusinessService Extends (Ens.BusinessService, IOP.Common) [ Inheritance = right, ProcedureBlock, System = 4 ]
6
+ {
7
+
8
+ Parameter SETTINGS = "%classname:Python BusinessService,%module:Python BusinessService,%settings:Python BusinessService,%classpaths:Python BusinessService";
9
+
10
+ Method dispatchProcessInput(pInput As %RegisteredObject) As %RegisteredObject
11
+ {
12
+
13
+ quit ..%class."on_process_input"(pInput)
14
+ }
15
+
16
+ Method OnProcessInput(
17
+ request As %RegisteredObject,
18
+ Output response As %RegisteredObject) As %Status
19
+ {
20
+ set tSC = $$$OK
21
+ try {
22
+ try {
23
+ set ..%class."_wait_for_next_call_interval" = ..%WaitForNextCallInterval
24
+ } catch {}
25
+ set response = ..%class."_dispatch_on_process_input"(request)
26
+ try {
27
+ set ..%WaitForNextCallInterval = ..%class."_wait_for_next_call_interval"
28
+ } catch {}
29
+ } catch ex {
30
+ set tSC = ex.AsStatus()
31
+ }
32
+ quit tSC
33
+ }
34
+
35
+ }