Writing Jython scripts for XL Deploy
You can use Jython scripting to extend or customize XL Deploy actions, events, or components. This topic describes best practices for writing, organizing and packaging your Jython scripts.
Usually when you attach a Jython script to an XL Deploy action, event, or component, you specify a relative path to it. In this situation, XL Deploy can find this script is by appending the path to each segment of its own classpath and looking there.
If you have a configuration snippet such as
... script="myproject/run.py"..., then XL Deploy can find the script at
ext/myproject/run.py because the
ext folder is on the classpath.
The script can also be packaged into a JAR and placed in the
plugins folder. XL Deploy scans this folder at startup and adds the JARs it finds to the classpath. In this situation, the JAR archive should contain the
myproject folder and
When creating a JAR, verify that the file paths in the plugin JAR do not start with
./. You can check this with
jar tf yourfile.jar. If you package two files and a folder, the output should look like this:
file1.xml file2.xml web/
And not like this:
./file1.xml ./file2.xml web/
You can split your code into modules. Note the following:
- You have to create an empty
__init__.pyin each folder that becomes a module (or a segment of a package name).
- Start the package name with something unique, otherwise it can clash with other extensions or standard Jython modules. For example,
myproject.modules.repois a better name than
Consider an example in which you have the following code in
# myproject/run.py infrastructureCis = repositoryService.query(None, None, "Infrastructure", None, None, None, 0, -1) applicationsCis = repositoryService.query(None, None, "Applications", None, None, None, 0, -1) # do something with those cis
You can create a class that helps perform queries to the repository and hides unnecessary parameters.
# myproject/modules/repo.py class RepositoryHelper: def __init__(self, repositoryService): self._repositoryService = repositoryService def get_all_cis(self, parent): ci_ids = self._repositoryService.query(None, None, parent, None, None, None, 0, -1) return map(lambda ci_id: self._repositoryService.read(ci_id.id), ci_ids)
run.py, you can import and use
# myproject/run.py from myproject.modules import repo repository_helper = repo.RepositoryHelper(repositoryService) infrastructureCis = repository_helper.get_all_cis("Infrastructure") applicationsCis = repository_helper.get_all_cis("Applications") # do something with those cis
The contents of the folder and JAR archive will then be:
myproject myproject/__init__.py myproject/run.py myproject/modules myproject/modules/__init__.py myproject/modules/repo.py
In addition to your own scripts, you can use:
- third-party Python libraries
- third-party Java libraries
- your own Java classes
In each of this cases make sure that they are available on the classpath in the same manner as described for your own Jython modules.
While developing and debugging scripts, you can keep the files open in the editor and change them after every iteration. After you have finished development, it is recommended to package them into a JAR file and place it in the
Normally there is no need to restart the server after changing a Jython script. However, modules are cached by the scripting engine after their first execution. To avoid this effect, you can use built-in
from myproject.modules import repo reload(repo) # ...
You can find an example of scripting in the UI extension demo plugin, which is available in the
samples folder of your XL Deploy installation.