Writing Jython scripts for Deploy
You can use Jython scripting to extend or customize Deploy actions, events, or components. This topic describes best practices for writing, organizing and packaging your Jython scripts.
Pointing to a Jython script from configuration files
Usually when you attach a Jython script to a Deploy action, event, or component, you specify a relative path to it. In this situation, 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 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. 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 run.py
script.
Creating a JAR
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/
Splitting your Jython code into modules
You can split your code into modules. Note the following:
- You have to create an empty
__init__.py
in 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.repo
is a better name thanutils.repo
.
Consider an example in which you have the following code in run.py
:
# 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)
Then, in run.py
, you can import and use RepositoryHelper
:
# 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
Using third-party libraries from scripts
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.
Best practice: Develop in directories, run in JARs
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 plugins
folder.
Best practice: Restarting the server
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 reload()
function.
from myproject.modules import repo
reload(repo)
# ...
Finding scripting examples
You can find an example of scripting in the UI extension demo plugin, which is available in the samples
folder of your Deploy installation.