---
title: "BeanShell Scripting Reference"
source: beanshell-scripting-reference.html
---

# BeanShell Scripting Reference

> BeanShell is a lightweight Java scripting language that gives FirstSpirit developers powerful capabilities for automation, content manipulation, and workflow customization. This reference covers the execution model, the Access API essentials, common use-case recipes, best practices, and troubleshooting.

## Overview

BeanShell is a lightweight Java scripting language that provides FirstSpirit developers with powerful capabilities for automation, content manipulation, and workflow customization.

> [!INFO]
> BeanShell scripts execute within the FirstSpirit server context and have full access to the FirstSpirit Access API, making them ideal for administrative tasks, content processing, and integration scenarios.

### What is BeanShell?

**BeanShell** is a Java-like scripting language that runs in the Java Runtime Environment. In FirstSpirit, BeanShell scripts can be executed in various contexts:

- **Executable Components** — Run scripts from the ServerManager or SiteArchitect
- **Workflows** — Automate workflow transitions and actions
- **Scheduled Tasks** — Execute scripts at defined intervals
- **Template Code** — Dynamic content generation in templates

### Quick Start

Here's a simple BeanShell script that prints all page references in the PageStore:

```java
//!BeanShell
import de.espirit.firstspirit.access.store.pagestore.*;

pageStore = context.getProject().getUserService().getStore(Store.Type.PAGESTORE);
pages = pageStore.getStoreRoot().getChildren(Page.class, true);

for (Page page : pages) {
    context.logInfo("Page: " + page.getDisplayName(context.getProject().getMasterLanguage()));
}
```

### Key Benefits

- **No Compilation Required** — Scripts are interpreted at runtime
- **Full API Access** — Complete access to FirstSpirit Access API
- **Context Awareness** — Automatic access to execution context
- **Java Compatibility** — Use Java syntax and libraries
- **Rapid Development** — Quick iteration without deployment cycles

## Getting Started

### Creating a BeanShell Script

BeanShell scripts can be created in several locations within FirstSpirit:

1. **ServerManager** → Tools → Execute Script
2. **Executable Components** in project configuration
3. **Workflow Scripts** in workflow definitions
4. **Templates** using `$CMS_SET()$` or format templates

### Script Header

Every BeanShell script should start with the BeanShell comment marker:

```java
//!BeanShell
```

> [!WARNING]
> The `//!BeanShell` header is required for FirstSpirit to recognize the file as a BeanShell script. Without it, the script will not execute.

### Basic Script Structure

```java
//!BeanShell
import de.espirit.firstspirit.access.*;
import de.espirit.firstspirit.access.store.*;

// Access the context (automatically available)
project = context.getProject();
user = context.getUser();

// Your script logic here
context.logInfo("Script started by: " + user.getLogin());

// Return values (optional)
return true;
```

### Execution Contexts

BeanShell scripts run in different contexts depending on where they're executed:

| Context | Available Objects | Use Cases |
|---------|-------------------|-----------|
| **Executable** | `context`, `project`, `user` | Administrative tasks, content manipulation |
| **Workflow** | `context`, `workflowable`, `transition` | Workflow automation, validation |
| **Template** | `context`, `#global`, `#item` | Dynamic content generation |
| **Scheduled** | `context`, `project` | Periodic maintenance, reporting |

## Core Concepts

### The Context Object

The `context` object is automatically available in all BeanShell scripts and provides access to the execution environment.

```java
//!BeanShell
// Get project
project = context.getProject();

// Get current user
user = context.getUser();

// Logging
context.logInfo("Information message");
context.logWarning("Warning message");
context.logError("Error message");

// Check environment
isWebEdit = context.is(BaseContext.Env.WEBEDIT);
isSiteArchitect = context.is(BaseContext.Env.PREVIEW);
```

#### Context Methods

| Method | Description | Example |
|--------|-------------|---------|
| `getProject()` | Get current project | `context.getProject()` |
| `getUser()` | Get executing user | `context.getUser()` |
| `logInfo(msg)` | Log info message | `context.logInfo("Done")` |
| `logError(msg)` | Log error message | `context.logError("Failed")` |
| `is(Env)` | Check environment | `context.is(Env.WEBEDIT)` |
| `requireSpecialist()` | Get agent/service | `context.requireSpecialist(LockService.TYPE)` |

### Accessing Stores

FirstSpirit organizes content in stores. Access them through the project:

```java
//!BeanShell
import de.espirit.firstspirit.access.store.*;

project = context.getProject();
userService = project.getUserService();

// Get stores
pageStore = userService.getStore(Store.Type.PAGESTORE);
mediaStore = userService.getStore(Store.Type.MEDIASTORE);
siteStore = userService.getStore(Store.Type.SITESTORE);
contentStore = userService.getStore(Store.Type.CONTENTSTORE);
templateStore = userService.getStore(Store.Type.TEMPLATESTORE);

// Access store roots
pageRoot = pageStore.getStoreRoot();
mediaRoot = mediaStore.getStoreRoot();
```

### Working with Store Elements

Store elements are the building blocks of FirstSpirit projects:

```java
//!BeanShell
import de.espirit.firstspirit.access.store.pagestore.*;

// Find element by UID
element = pageStore.getStoreElement("homepage");

if (element != null) {
    // Get basic properties
    uid = element.getUid();
    id = element.getId();
    name = element.getName();
    displayName = element.getDisplayName(project.getMasterLanguage());

    // Check element type
    if (element instanceof Page) {
        page = (Page) element;
        formData = page.getFormData();
    }
}
```

### Using Agents and Services

Agents provide specialized functionality through the Access API:

```java
//!BeanShell
import de.espirit.firstspirit.agency.*;

// GenerationAgent - for generating pages
generationAgent = context.requireSpecialist(GenerationAgent.TYPE);

// QueryAgent - for searching content
queryAgent = context.requireSpecialist(QueryAgent.TYPE);
hits = queryAgent.answer("fs.type = Page", null);

// LockService - for locking elements
lockService = context.requireSpecialist(LockService.TYPE);
lockService.setLock(element);

// ReleaseAgent - for release operations
releaseAgent = context.requireSpecialist(ReleaseAgent.TYPE);
releaseAgent.releaseStoreElement(element, recursive);
```

## Common Use Cases

### Example 1: Find and Update Pages

Find all pages with a specific template and update a form field:

```java
//!BeanShell
import de.espirit.firstspirit.access.store.pagestore.*;
import de.espirit.firstspirit.forms.*;

pageStore = context.getProject().getUserService().getStore(Store.Type.PAGESTORE);
pages = pageStore.getStoreRoot().getChildren(Page.class, true);

int updated = 0;
for (Page page : pages) {
    formData = page.getFormData();

    // Check if page uses specific template
    if (page.getTemplate().getUid().equals("news_page")) {
        // Update form field
        form = formData.getForm();
        authorField = form.findEditor("pt_author");

        if (authorField != null) {
            formData.get(page.getLanguageInfo().getLanguage(), "pt_author").set("Admin");
            page.setFormData(formData);
            page.save();
            updated++;
        }
    }
}

context.logInfo("Updated " + updated + " pages");
```

### Example 2: Export Media Files

Export all images from MediaStore to the file system:

```java
//!BeanShell
import de.espirit.firstspirit.access.store.mediastore.*;
import de.espirit.firstspirit.io.*;
import java.io.*;

mediaStore = context.getProject().getUserService().getStore(Store.Type.MEDIASTORE);
media = mediaStore.getStoreRoot().getChildren(Media.class, true);

exportDir = new File("C:/export/media");
exportDir.mkdirs();

for (Media mediaItem : media) {
    if (mediaItem instanceof MediaFile) {
        file = (MediaFile) mediaItem;

        // Get binary data
        fileHandle = file.getFile("original");
        if (fileHandle != null) {
            // Copy to export directory
            outputFile = new File(exportDir, file.getUid() + "_" + fileHandle.getFileName());
            FileOutputStream fos = new FileOutputStream(outputFile);
            FileUtil.stream(fileHandle.load(), fos);
            fos.close();

            context.logInfo("Exported: " + file.getUid());
        }
    }
}
```

### Example 3: Generate Content Report

Create a CSV report of all content in the ContentStore:

```java
//!BeanShell
import de.espirit.firstspirit.access.store.contentstore.*;
import de.espirit.firstspirit.access.store.templatestore.*;
import java.io.*;

contentStore = context.getProject().getUserService().getStore(Store.Type.CONTENTSTORE);
datasets = contentStore.getStoreRoot().getChildren(Content2.class, true);

reportFile = new File("C:/reports/content_report.csv");
writer = new PrintWriter(new FileWriter(reportFile));
writer.println("UID,Name,Template,EntityType,RecordCount");

for (Content2 content : datasets) {
    schema = content.getSchema();
    uid = content.getUid();
    name = content.getDisplayName(context.getProject().getMasterLanguage());
    template = schema.getDisplayName(context.getProject().getMasterLanguage());
    entityType = schema.getEntityType().getName();

    // Count datasets
    dataProvider = content.getDataProvider();
    count = dataProvider.getDatasets().size();

    writer.println(uid + "," + name + "," + template + "," + entityType + "," + count);
}

writer.close();
context.logInfo("Report generated: " + reportFile.getAbsolutePath());
```

### Example 4: Workflow Validation

Validate content before workflow transition:

```java
//!BeanShell
import de.espirit.firstspirit.access.store.pagestore.*;

// workflowable is automatically available in workflow context
element = workflowable.getElement();

if (element instanceof Page) {
    page = (Page) element;
    formData = page.getFormData();
    form = formData.getForm();

    // Check required fields
    titleField = formData.get(page.getLanguageInfo().getLanguage(), "pt_title");

    if (titleField == null || titleField.get() == null || titleField.get().isEmpty()) {
        context.logError("Title field is required!");
        return false;  // Prevent transition
    }
}

return true;  // Allow transition
```

### Example 5: Bulk Release Pages

Release all pages in a specific folder to live:

```java
//!BeanShell
import de.espirit.firstspirit.access.store.pagestore.*;
import de.espirit.firstspirit.agency.*;

// Get folder
pageStore = context.getProject().getUserService().getStore(Store.Type.PAGESTORE);
folder = pageStore.getStoreElement("news");

if (folder instanceof PageFolder) {
    // Get ReleaseAgent
    releaseAgent = context.requireSpecialist(ReleaseAgent.TYPE);

    // Get all pages in folder
    pages = folder.getChildren(Page.class, true);

    for (Page page : pages) {
        // Check if page has changes
        if (page.hasChangedMetaData() || page.hasChangedReleaseData()) {
            // Release page (recursive = false)
            releaseAgent.releaseStoreElement(page, false);
            context.logInfo("Released: " + page.getUid());
        }
    }
}
```

## Access API Essentials

### FormData Manipulation

Working with form data in pages and content:

```java
//!BeanShell
import de.espirit.firstspirit.forms.*;

page = pageStore.getStoreElement("mypage");
formData = page.getFormData();
language = page.getLanguageInfo().getLanguage();

// Read form field
titleField = formData.get(language, "pt_title");
title = titleField.get();

// Write form field
titleField.set("New Title");

// Work with different field types
// Text field
textValue = formData.get(language, "pt_text").get();

// Number field
numberValue = formData.get(language, "pt_count").get();

// Date field
dateValue = formData.get(language, "pt_date").get();

// Option (select/radio)
optionValue = formData.get(language, "pt_option").get();

// Save changes
page.setFormData(formData);
page.save();
```

### Reference Handling

Working with references (links to other elements):

```java
//!BeanShell
import de.espirit.firstspirit.access.store.*;

page = pageStore.getStoreElement("mypage");
formData = page.getFormData();
language = page.getLanguageInfo().getLanguage();

// Get reference field (e.g., FS_REFERENCE)
refField = formData.get(language, "pt_linked_page");

// Check if reference is set
if (refField != null && refField.get() != null) {
    referencedElement = refField.get();
    context.logInfo("Linked to: " + referencedElement.getUid());

    // Set new reference
    newPage = pageStore.getStoreElement("other_page");
    refField.set(newPage);
}

// Work with InlineReferences (multiple references)
inlineRefField = formData.get(language, "pt_related_pages");
if (inlineRefField != null) {
    references = inlineRefField.get();
    for (ref : references) {
        element = ref.getReferencedElement();
        context.logInfo("Related: " + element.getUid());
    }
}
```

### Dataset Operations

Working with ContentStore datasets:

```java
//!BeanShell
import de.espirit.firstspirit.access.store.contentstore.*;

contentStore = context.getProject().getUserService().getStore(Store.Type.CONTENTSTORE);
content2 = contentStore.getStoreElement("products");

// Get schema and entity type
schema = content2.getSchema();
entityType = schema.getEntityType();

// Get data provider
dataProvider = content2.getDataProvider();

// Create new dataset
dataset = dataProvider.createDataset();
language = project.getMasterLanguage();

// Set field values
dataset.set("ps_name", language, "New Product");
dataset.set("ps_price", language, 99.99);
dataset.set("ps_active", language, true);

// Save dataset
dataProvider.save(dataset);

// Query datasets
allDatasets = dataProvider.getDatasets();
for (ds : allDatasets) {
    name = ds.get("ps_name", language);
    context.logInfo("Product: " + name);
}
```

### Generation and Deployment

Trigger generation programmatically:

```java
//!BeanShell
import de.espirit.firstspirit.agency.*;
import de.espirit.firstspirit.generate.*;

generationAgent = context.requireSpecialist(GenerationAgent.TYPE);

// Get generation context for specific page
page = pageStore.getStoreElement("homepage");
generationContext = generationAgent.getGenerationContext(page);

// Generate page
generationContext.generate();

// Check generation status
if (generationContext.successful()) {
    context.logInfo("Generation successful");

    // Deploy generated files (if deployment configured)
    generationContext.deploy();
} else {
    context.logError("Generation failed");
}
```

## Best Practices

### Error Handling

Always use try-catch blocks for robust scripts:

```java
//!BeanShell
try {
    element = pageStore.getStoreElement("mypage");

    if (element == null) {
        context.logWarning("Element not found");
        return false;
    }

    // Process element
    element.save();

} catch (Exception e) {
    context.logError("Error: " + e.getMessage());
    e.printStackTrace();
    return false;
}

return true;
```

### Locking Elements

Always lock elements before modifying:

```java
//!BeanShell
import de.espirit.firstspirit.agency.*;

lockService = context.requireSpecialist(LockService.TYPE);

try {
    // Lock element
    lockService.setLock(element);

    // Modify element
    formData = element.getFormData();
    // ... make changes ...
    element.save();

} finally {
    // Always release lock
    lockService.releaseLock(element);
}
```

### Performance Optimization

For large-scale operations, use efficient iteration:

```java
//!BeanShell
// BAD - loads all children into memory
children = folder.getChildren();
for (child : children) {
    // process
}

// GOOD - uses iterator
iterator = folder.getChildrenIterator();
while (iterator.hasNext()) {
    child = iterator.next();
    // process
}
```

### Logging Best Practices

Use appropriate log levels:

```java
//!BeanShell
// Info - normal operation
context.logInfo("Processing " + count + " pages");

// Warning - non-critical issues
context.logWarning("Element '" + uid + "' not found, skipping");

// Error - critical failures
context.logError("Failed to save element: " + e.getMessage());

// Debug - detailed information (check log level settings)
if (context.getLogLevel() == LogLevel.DEBUG) {
    context.logInfo("DEBUG: Element state = " + element.getState());
}
```

### Transaction Handling

Use transactions for atomic operations:

```java
//!BeanShell
import de.espirit.firstspirit.agency.*;

transactionAgent = context.requireSpecialist(TransactionAgent.TYPE);

try {
    transactionAgent.beginTransaction();

    // Multiple operations that should be atomic
    page1.save();
    page2.save();
    content.save();

    transactionAgent.commitTransaction();
    context.logInfo("Transaction committed successfully");

} catch (Exception e) {
    transactionAgent.rollbackTransaction();
    context.logError("Transaction rolled back: " + e.getMessage());
}
```

### Memory Management

For large datasets, process in batches:

```java
//!BeanShell
import de.espirit.firstspirit.access.store.contentstore.*;

content2 = contentStore.getStoreElement("large_dataset");
dataProvider = content2.getDataProvider();

// Process in batches
batchSize = 100;
offset = 0;
language = project.getMasterLanguage();

while (true) {
    // Get batch
    datasets = dataProvider.getDatasets(offset, batchSize);

    if (datasets.isEmpty()) {
        break;
    }

    // Process batch
    for (dataset : datasets) {
        // Process individual dataset
        name = dataset.get("ps_name", language);
        context.logInfo("Processing: " + name);
    }

    offset += batchSize;
}
```

## Troubleshooting

### Common Errors

| Error | Cause | Solution |
|-------|-------|----------|
| `NullPointerException` | Element not found or field is null | Add null checks before accessing objects |
| `AccessDeniedException` | User lacks permissions | Check user rights or execute as admin |
| `ElementDeletedException` | Element was deleted | Refresh references or check element state |
| `LockException` | Element is locked by another user | Check locks with LockService |
| `ClassCastException` | Wrong type assumption | Use `instanceof` before casting |

### Debugging Tips

#### Enable Detailed Logging

```java
//!BeanShell
// Print variable values
context.logInfo("Variable value: " + myVariable);

// Print object type
context.logInfo("Object class: " + element.getClass().getName());

// Print stack trace for debugging
try {
    // code
} catch (Exception e) {
    e.printStackTrace();
    context.logError("Error: " + e.getMessage());
}
```

#### Check Element State

```java
//!BeanShell
element = pageStore.getStoreElement("mypage");

context.logInfo("UID: " + element.getUid());
context.logInfo("ID: " + element.getId());
context.logInfo("State: " + element.getState());
context.logInfo("Locked: " + element.isLocked());
context.logInfo("Has changes: " + element.hasChangedMetaData());
```

#### Verify Permissions

```java
//!BeanShell
import de.espirit.firstspirit.access.*;

user = context.getUser();
element = pageStore.getStoreElement("mypage");

// Check permissions
permission = element.getPermission(user);
canRead = permission.isAllowed(Permission.READ);
canChange = permission.isAllowed(Permission.CHANGE);
canDelete = permission.isAllowed(Permission.DELETE);

context.logInfo("Can read: " + canRead);
context.logInfo("Can change: " + canChange);
context.logInfo("Can delete: " + canDelete);
```

### Script Execution Issues

> [!WARNING]
> BeanShell scripts must be executed with appropriate user permissions. Admin tasks require Admin user context.

**Common execution issues:**

- **Script doesn't start**: Check for syntax errors, verify `//!BeanShell` header
- **Permission denied**: Execute as user with sufficient rights
- **Elements not found**: Verify UIDs and store paths
- **Changes not saved**: Ensure `.save()` is called and no exceptions occurred
- **Locks preventing modification**: Check and release locks with LockService

### Variable Scope Issues

BeanShell has different scoping rules than Java:

```java
//!BeanShell
// GOOD - explicit typing for clarity
String myVariable = "value";
int count = 0;

// ACCEPTABLE - dynamic typing
myVariable = "value";  // BeanShell infers type

// AVOID - can cause issues with method overloading
result = element.getFormData();  // Type unclear
```

### FirstSpirit 5.2 Compatibility

For scripts that need to run on FS 5.2 and newer versions:

```java
//!BeanShell
// Check FirstSpirit version
version = context.getProject().getVersion();
context.logInfo("FirstSpirit version: " + version);

// Use version-specific code when needed
if (version.startsWith("5.2")) {
    // FS 5.2 compatible code
} else {
    // Newer API features
}
```

## Advanced Topics

### Dynamic Class Loading

Load Java classes dynamically in BeanShell:

```java
//!BeanShell
import java.lang.reflect.*;

// Load custom class from project lib
classLoader = context.getProject().getClassLoader();
customClass = classLoader.loadClass("com.example.CustomHelper");

// Create instance
instance = customClass.newInstance();

// Call methods via reflection
method = customClass.getMethod("processData", String.class);
result = method.invoke(instance, "mydata");
```

### Working with Metadata

Access and modify element metadata:

```java
//!BeanShell
import de.espirit.firstspirit.access.*;

element = pageStore.getStoreElement("mypage");
metaData = element.getMetaData();

// Read metadata
createdBy = metaData.getCreatedBy();
createdDate = metaData.getCreatedDate();
changedBy = metaData.getChangedBy();
changedDate = metaData.getChangedDate();

context.logInfo("Created by: " + createdBy.getLogin() + " on " + createdDate);
context.logInfo("Last changed by: " + changedBy.getLogin() + " on " + changedDate);
```

### Scheduled Task Integration

Create scripts for scheduled execution:

```java
//!BeanShell
import de.espirit.firstspirit.access.schedule.*;

// Script executed as scheduled task
context.logInfo("Scheduled task started at: " + new Date());

// Perform maintenance tasks
// - Clean up old content
// - Generate reports
// - Synchronize data
// - Backup operations

// Return status
return ScheduleEntry.State.SUCCESS;  // or State.ERROR, State.INTERRUPTED
```

### GUI Dialogs in SiteArchitect

Show dialogs when executing from SiteArchitect:

```java
//!BeanShell
import de.espirit.firstspirit.client.access.*;
import javax.swing.*;

// Check if running in SiteArchitect
if (context.is(BaseContext.Env.PREVIEW)) {
    // Show confirmation dialog
    result = JOptionPane.showConfirmDialog(
        null,
        "Do you want to proceed?",
        "Confirmation",
        JOptionPane.YES_NO_OPTION
    );

    if (result != JOptionPane.YES_OPTION) {
        context.logInfo("User cancelled operation");
        return false;
    }
}

// Continue with operation
```

## Resources

### Official Documentation

- FirstSpirit Access API JavaDoc
- BeanShell User Manual: http://www.beanshell.org/manual.html
- FirstSpirit Developer Portal

### Quick Reference

| Task | Code Pattern |
|------|--------------|
| Get element | `store.getStoreElement("uid")` |
| Save element | `element.save()` |
| Lock element | `lockService.setLock(element)` |
| Release element | `releaseAgent.releaseStoreElement(element)` |
| Get form field | `formData.get(language, "fieldname")` |
| Log message | `context.logInfo("message")` |
| Get agent | `context.requireSpecialist(AgentType.TYPE)` |

### Common Imports

```java
//!BeanShell
// Core API
import de.espirit.firstspirit.access.*;
import de.espirit.firstspirit.access.store.*;
import de.espirit.firstspirit.access.store.pagestore.*;
import de.espirit.firstspirit.access.store.mediastore.*;
import de.espirit.firstspirit.access.store.contentstore.*;
import de.espirit.firstspirit.access.store.templatestore.*;

// Agencies
import de.espirit.firstspirit.agency.*;

// Forms
import de.espirit.firstspirit.forms.*;

// Generation
import de.espirit.firstspirit.generate.*;

// Utilities
import java.util.*;
import java.io.*;
import java.text.*;
```
