> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flexagon.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Groovy Libraries

> Groovy Libraries allow custom Groovy functions and helpers to be shared and reused across all Groovy scripts in FlexDeploy Groovy Library access shoul

### Groovy Libraries allow custom Groovy functions and helpers to be shared and reused across all Groovy scripts in FlexDeploy

> [!NOTE]
>
> Groovy Library access should be limited to a small group of trusted users, similar to Administrators, due to its powerful permissions.

## Creating a Library

Libraries can be viewed and created by navigating to the **Administration->Groovy Libraries** page. Next click the **Create Library** ![(blue star)](https://flexagon.atlassian.net/wiki/s/-510684821/6452/64e1779b1cc4eed32fd26c0f5af1f87b02d05b81/_/images/icons/emoticons/72/31-20e3.png) button.

![image-20240920-164403.png](https://mintcdn.com/flexagon-llc-ce77a95c/NkeZh5D-Nf8j_WaD/images/fd111/12590922059.png?fit=max\&auto=format\&n=NkeZh5D-Nf8j_WaD\&q=85\&s=f7bf681a11dcbc1a403d078ffe33c265)

You will be prompted to provide a unique identifier for the library, called the **Library Key** ![(blue star)](https://flexagon.atlassian.net/wiki/s/-510684821/6452/64e1779b1cc4eed32fd26c0f5af1f87b02d05b81/_/images/icons/emoticons/72/32-20e3.png).

> [!NOTE]
>
> The Library Key is also how your Groovy Library will be referenced from other scripts.

Upon saving the form ![(blue star)](https://flexagon.atlassian.net/wiki/s/-510684821/6452/64e1779b1cc4eed32fd26c0f5af1f87b02d05b81/_/images/icons/emoticons/72/33-20e3.png) you will be presented with a blank editor where one or more functions can be defined for your library.

## Writing Functions

A function can be any common logic you would like to share across scripts. Lets take a very simple example and say we want to make a function that returns the FlexDeploy REST API URL.

![image-20240920-171433.png](https://mintcdn.com/flexagon-llc-ce77a95c/NkeZh5D-Nf8j_WaD/images/fd111/12590922056.png?fit=max\&auto=format\&n=NkeZh5D-Nf8j_WaD\&q=85\&s=ee2fb1d8d5c57382cd5e959869f7ce4c)

```
// define any number of helper functions for this library

String getFlexDeployAPIUrl()
{
  def baseURL = FLEXDEPLOY.getFlexDeployBaseUrl()
  return "${baseURL}/flexdeploy/rest/v2"
}
```

Notice the use of the `FLEXDEPLOY` helper library as well. `EMAIL`, `FLEXDEPLOY`, `REST`, `TOPOLOGY`, and `LOG` helpers are all available for use in your custom library.

### Testing Functions

Users must have the `GROOVY_LIBRARY_UPDATE` permission to test any Groovy library.

Libraries can be tested at any point right from the editor by clicking the **Try It** button in the header.

![image-20240920-171944.png](https://mintcdn.com/flexagon-llc-ce77a95c/NkeZh5D-Nf8j_WaD/images/fd111/12590922047.png?fit=max\&auto=format\&n=NkeZh5D-Nf8j_WaD\&q=85\&s=f8b5ef4c3599ed67d3b9cd0250840a00)

Here you can write a sample script to test one or more functions in your library. Note that code suggestions for your library will not be shown in the try it window. With your test script ready simply hit the **Run** button or use the default shortcut of `ctrl+shift+h` to the test the function. In the screen shot we can see the result as `http://localhost:8000/flexdeploy/rest/v2`

### Annotating Functions

By default when accessing library functions from other scripts they will have very basic information as seen below:

![image-20240920-172642.png](https://mintcdn.com/flexagon-llc-ce77a95c/NkeZh5D-Nf8j_WaD/images/fd111/12590922053.png?fit=max\&auto=format\&n=NkeZh5D-Nf8j_WaD\&q=85\&s=3eedd202e84553e318430282350fc99c)

Its often beneficial to provide more information such as a description of the method and/or describing any parameters for your method. Both can be accomplished by using the **SuggestionMethodMeta** annotation.

![image-20240920-172952.png](https://mintcdn.com/flexagon-llc-ce77a95c/NkeZh5D-Nf8j_WaD/images/fd111/12590922050.png?fit=max\&auto=format\&n=NkeZh5D-Nf8j_WaD\&q=85\&s=b17e8ba7ce34719080cb77a96b7251d6)

Now we can see our function description when using it from other scripts:

![image-20240920-173114.png](https://mintcdn.com/flexagon-llc-ce77a95c/NkeZh5D-Nf8j_WaD/images/fd111/12590922044.png?fit=max\&auto=format\&n=NkeZh5D-Nf8j_WaD\&q=85\&s=6054ac7c6f838f599d1564a790420449)

#### SuggestionMethodMeta API

<table><colgroup><col /><col /><col /></colgroup><tbody><tr><th>**Field**</th><th>**Type**</th><th>**Description**</th></tr><tr><td>**description**</td><td>String</td><td>Overall description of the function. Markdown can be used.</td></tr><tr><td>**params**</td><td>List of Strings</td><td>A list of strings describing the function parameters. See full example below.</td></tr><tr><td>**deprecated**</td><td>boolean (default false)</td><td>If true this will indicate the function as deprecated. The name will be \<del>struckthrough\</del> when viewing in other scripts.</td></tr><tr><td>**depAlternate**</td><td>String</td><td>Optional alternative function name to use if this current function is deprecated.</td></tr></tbody></table>

```
import flexagon.ff.common.core.suggestions.SuggestionMethodMeta;

@SuggestionMethodMeta(
  description = "Surely this function is overkill right?",
  params = ["first - The first param", "second - The second param"],
  deprecated = true,
  depAlternate = "multiply2"
)
Long multiply(Long first, Long second)
{
  return first * second;
}

Long multiply2(Long first, Long second)
{
  return first * second;
}
```

## Rename/Delete a Library

To rename a library simply click the edit pencil :Pencil\_Edit: icon next to the Library Key.

> [!NOTE]
>
> **Changing the Library Key** may break existing Groovy scripts using the old key of the Library. It is advised not to change the key once the library is in use.

To delete a library simply click the **Delete** button next to the edit button. Similar to renaming the library - deleting a library that is in use will break any Groovy script using the deleted library.

![image-20240920-174908.png](https://mintcdn.com/flexagon-llc-ce77a95c/NkeZh5D-Nf8j_WaD/images/fd111/12590922041.png?fit=max\&auto=format\&n=NkeZh5D-Nf8j_WaD\&q=85\&s=ed5249e9b71ad5c699826d6940ce3364)

## Library Compilation

The following section explains in detail how the script code you write is compiled and made available to each FlexDeploy Groovy script. This information can be helpful in more advanced Groovy Libraries.

The authored script code for each library is wrapped in a class declaration like so

```
package com.flexagon.groovy.custom;
// imports in the script are moved here

public class LIB_MY_LIB {
  // your script code is inserted here  
}
```

This class is compiled once at server startup and then on each change of the library script.

Finally, when running a Groovy script, an instance of this library class is instantiated and made available to the script as a variable matching the Library Key.

You can think of it as FlexDeploy automatically adding the following lines at the beginning of all of your Groovy scripts:

```
def LIB_MY_LIB = new com.flexagon.groovy.custom.LIB_MY_LIB(); 
```

### Importing Other Custom Libraries

> [!NOTE]
>
> Importing other custom libraries is only supported in version **9.0.0.2+**

Custom libraries are not made available in other custom libraries by default, however they can be imported as needed. The below code snippet shows how the custom `LIB_PIPELINE_UTILS` imports and uses another custom library `LIB_LOGGER`.

```
// imports omitted for brevity

// create a new instance of our custom library
// the LOG variable should be passed in the constructor for any imported custom library instance
def logger = new com.flexagon.groovy.custom.LIB_LOGGER(LOG)

void myPipelineFunction()
{
  logger.logMessage("Logger library import")
  // code omitted for brevity
}
```

#### Static Methods

Methods can be called statically, without an instance created, if they have the static modifier. *Note - this only applies when importing other custom libraries since other Groovy scripts have instances created behind the scenes. See* [*Library Compilation*](#Library-Compilation) *above.*

For example:

**LIB\_LOGGER**

```
static void logMessage(String message)
{
  // log
}

void logMessage2(String message)
{
  // log
}
```

**LIB\_PIPELINE\_UTILS**

```
import com.flexagon.groovy.custom.LIB_LOGGER;

def loggerInstance = new LIB_LOGGER(LOG);

void myPipelineFunction()
{
  // This WILL work
  LIB_LOGGER.logMessage("Logger library static method")
  
  // This will NOT work
  LIB_LOGGER.logMessage2("Logger library instance method")
  
  // BOTH of these will work
  loggerInstance.logMessage("Logger library static method")
  loggerInstance.logMessage2("Logger library instance method")
}
```

> [!NOTE]
>
> **Static method caveat**
>
> A final note on static methods - Static methods cannot access instance variables. This means if you have a static method defined in your library and try to access `FLEXDEPLOY`, `LOG`or any other instance variables it will not work and produce an error like the following: `You attempted to reference a variable in the binding or an instance variable from a static context.`
>
> In this case you must either remove the static modifier or not use the variable in question.

#### Circular Imports

> [!WARNING]
>
> Circular imports of custom libraries are not allowed and if found an error will be thrown `[Circular imports detected. Please check if libraries are creating instances of each other outside of a function scope..]` when attempting to test or save the library.

The below example demonstrates a circular library import and why its a problem:

* LIB\_ONE

```
def libTwo = new com.flexagon.groovy.custom.LIB_TWO(LOG)

def myFunction() {
  // do some logic
}
```

* LIB\_TWO

```
def libOne = new com.flexagon.groovy.custom.LIB_ONE(LOG)

def myFunction() {
  // do some logic
}
```

Lets look at what happens when FlexDeploy compiles and creates instances of your custom libraries for other Groovy scripts to use.

1. FlexDeploy will iterate through all your Groovy Libraries and create an instance of each.

2. A new instance of `LIB_ONE` is created.

3. During initialization of `LIB_ONE` it will create a new instance of `LIB_TWO` as declared on line 1 of `LIB_ONE`

4. An instance of `LIB_TWO` is created during step 3. This in turn creates an instance of `LIB_ONE` as declared on line 1 of `LIB_TWO`.

   1. We are now stuck in a loop between steps 3 and 4, infinitely creating new instances. This is what is known as a circular dependency and will result in an error being thrown.

> [!TIP]
>
> If it is absolutely necessary to have a **circular dependency** between libraries, then the creation of library instances **should be done within a function scope**.
>
> * LIB\_ONE
>
> ```
> def libTwo = new com.flexagon.groovy.custom.LIB_TWO(LOG)
>
> def myFunction() {
>   // do some logic
> }
> ```
>
> * LIB\_TWO
>
> ```
> import com.flexagon.groovy.custom.LIB_ONE;
>
> def myFunction() {
>   def libOne = new LIB_ONE(LOG)
>   // do some logic
> }
> ```
