Extensions in Lucee 5
Lucee 5 - Extensions
Creating an extension in Lucee is convention based. A Lucee Extension file is a zip file but with a .lex file extension (e.g. Lucee EXtension) and containing the correct file structure.
The following is a simple example of a Lucee Extension, that we will extend it step-by-step.
Base structure (required)
At the heart of every extension is the manifest file. This file, MANIFEST.MF
, is located in the /META-INF/
folder inside your lex file.
The manifest file is very powerful and we'll start with the base settings you need to have in place. Simply add the following settings to your manifest file.
Manifest-Version
Manifest-Version: 1.0
The manifest version number. This should always be set to the value 1.0 as above.
ID
id: <uuid>
A unique identifier for your extension. The value for the ID has to be a UUID, which you can create with the help of the Lucee function createuuid
. This identifier will work across multiple extension providers, so if your extension is available on more than one extension provider, Lucee will recognize it and always obtain the newest version.
Version
version: 1.2.3.4
The version number of your extension. Please follow the following pattern for your version number.
<major-number>.<minor-number>.<release-number>.<patches-number-or-string>
Name
name: Beer
This is the name of the extension. You can also add double quotes to your name values to ensure it is interpreted as a string.
These four items are everything we need to have a working extension, so our example MANIFEST.MF
file now looks like this:
Manifest-Version: 1.0
id: "FAD1E8CB-4F45-4184-86359145767C29DE"
version: "1.2.3.4"
name: Beer
Now create a zip file with the file /META-INF/MANIFEST.MF
in it and then change the file extension of the resulting zip file to '.lex'.
To test your new extension you can either copy it to /lucee-server/deploy/
a of a running Lucee 5 installation or go into the Lucee Admin (server or web) and upload the file using the option under the Extension - > Application
section.
If you add the file to the /lucee-server/deploy/
folder, you might need to wait a little bit, it can take Lucee up to a minute to recognize and install the extension. After the extension disappears from the 'deploy' directory it is installed.
If you now go to the Lucee Server Admin and to the Extension -> Application
section, you should see it there as installed.
Base structure (optional)
Now let us make our extension richer by adding some optional settings to the MANIFEST.MF
file.
Description
description: "This extension installs a tag, that when used shows you where to have a Beer nearby."
The description for your extension.
Category
category: Fun
Category of the extension, this can be a list of multiple categories (comma separated).
Built date
Built-Date: 2016-02-05 11:39:44
Built date of the extension.
Lucee core version
lucee-core-version: "5.0.0.157"
Minimal Lucee core version this extension needs to work properly.
Lucee loader version
lucee-loader-version: "5.8"
The minimum Lucee loader version this extension needs to run properly.
Release type
release-type: web
If this extension should be made available in the server context only, then set to server
. If this extension only should be available in the web context, then set to web
. If it should be available in web and server context then set to all
. The all
value is the default.
We now have a MANIFEST.MF
file that covers all the base settings, the extension still does not do anything, but it is now more informative. The manifest file now has this in it:
Manifest-Version: 1.0
id: "FAD1E8CB-4F45-4184-86359145767C29DE"
version: "1.2.3.4"
name: Beer
description: "This extension installs a tag, that when used shows you where to have a Beer nearby."
category: Fun
Built-Date: 2016-02-05 11:39:44
lucee-core-version: "5.0.0.157"
lucee-loader-version: "5.8"
release-type: web
Now we create the .lex file with the file /META-INF/MANIFEST.MF
inside it again and now the extension is ready again.
Logo
/META-INF/logo.png
Adding a logo / icon for your extension is straightforward, simply copy a PNG image file with the name logo.png into the folder /META-INF/
. This image will be used for the extension in the Lucee Admin.
The logo image will be automatically proportionally resized in the Administrator
- Extension Listings, 130px x 50px
- Extension Detail page, 400px x 400px
Installing artifacts
Now that we have covered how the base settings for an extension work, we can make it do something useful.
To begin with we start by installing some CFML based tags.
Adding CFML based tags
/tags
To add CFML based tags create a directory with the name /tags
and copy the CFML based tag(s) into this directory. After creating your tag(s), your .lex file (zip) will have the following structure.
/META-INF/MANIFEST.MF
/tags/Beer.cfc
Documentation of the tag(s) is via the doc comments and/or hint attributes for the tag. You can add as many tags to the tags directory as you need.
After installing this new extension (see above) you will see in the Lucee admin that the extension is installed and the new tag(s) will now be available.
Adding CFML based functions
/functions
To add CFML based functions create a directory with the name /functions
and copy a CFML template containing the function to that directory. After creating your function(s), your .lex file (zip) will have the following structure.
/META-INF/MANIFEST.MF
/tags/Beer.cfc
/functions/beer.cfm
Documentation of the function(s) is via the doc comments and/or hint attributes for the function. You can add as many functions to the functions directory as you need.
After installing this new extension (see above) you will see in the Lucee admin that the extension is installed and the new function(s) will now be available.
Install context files
/context
The context
files are files that are copied to the Lucee context directory. This directory is available via the mapping /lucee
in the case of a web context extension (see release-type
above) or /lucee-server
in the case of a server context extension.
The context
file can be used for various things:
- make a web service available
- make a component available
- extend the Lucee admin with a plugin (by using the path /context/admin/plugin/MyPlugin)
- extend the Lucee admin with a JDBC Driver (by using the path /context/admin/dbdriver/MyDB.cfc)
- extend the Lucee admin with a cache (by using the path /context/admin/cdriver/MyCache.cfc)
- extend the Lucee admin with a debug template (by using the path /context/admin/debug/MyDebugTemplate.cfc)
The content of the extensions context
folder could look something like this:
/META-INF/MANIFEST.MF
/context/admin/plugin/NotePlus/Action.cfc
/context/admin/plugin/NotePlus/language.xml
/context/admin/plugin/NotePlus/overview.cfm
Web Contexts Files
/webcontexts
These are similar to the context files
, the difference being that context files
only define context files for the current context (server or web). The web contexts files however are used in a server context extension to install files to ALL existing and upcoming web contexts. This means that when you add a new web context after this extension is installed, the files defined in this folder will be available to this new web context.
The content of the extensions webcontext
files could look something like this:
/META-INF/MANIFEST.MF
/webcontexts/admin/debug/MyDebugTemplate.cfc
Applications
/application
If this extension is installed in a web context the content of this folder is copied to the web root directory of that context.
The content of the extensions application
folder could look something like this:
/META-INF/MANIFEST.MF
/applications/Application.cfc
/applications/index.cfm
Plugins
/plugins
Installs content from the folder /plugin
to the plugin directory of the server or web context.
This is a shortcut for /context/admin/plugin
(see above).
The content of the extensions plugin
folder could look something like this:
/META-INF/MANIFEST.MF
/plugins/NotePlus/Action.cfc
/plugins/NotePlus/language.xml
/plugins/NotePlus/overview.cfm
You can read more about creating plugins in our guide for Admin Plugins
Archives
/archives
The folder /archives
is used to install regular, component or custom tag archives. Lucee archives can be generated in the details view of regular, component or custom tag mappings in the administrator.
The content of the extensions archives
folder could look something like this:
/META-INF/MANIFEST.MF
/archives/myapp.lar
/archives/mycomponents.lar
/archives/mycustomtag.lar
JARs
/jars
start-bundles:true
Many Lucee extensions use Java libraries (jars) to work.
Lucee 5 support classic
Jars and OSGI bundles (a subset of jars). Lucee will detect if the given input is a classic
jar or an OSGi bundle and handle the file accordingly.
OSGi Bundles
OSGi is the framework Lucee 5 is based on, that allows for the loading and unloading of JAR files on the fly at any time without a server restart being required. In addition you can have different versions of the same JAR in your environment without causing a conflict.
The term Installing an OSGi bundle
is not accurate in this context, adding a bundle to the JARs directory makes the bundle available in the environment but does not install
it.
To make Lucee load (install) the JARs into the environment you need to define the setting start-bundles
in the Manifest file, but in many cases this is not necessary, for example when your JAR contains a tag that you are defining in a tld, you simply define the bundle name and version with the class definition and Lucee will load the JAR automatically when required. This has the benefit that bundles are only loaded into the memory when used.
Please note: It is not actually necessary to bundle the OSGi bundle with the extension, if Lucee cannot find the OSGi bundle locally, Lucee will attempt to download it from the update provider (when available).
Classic JAR
Any JAR that is not an OSGi bundle is considered to be a classic JAR. It is highly recommended that they are not used, however, it is possible to use them but they have downsides.
For example under MS Windows it is not possible to update an already loaded JAR, because Windows has a lock on that JAR. Every update to a "classic" JAR requires a restart of the whole Lucee server.
The content of the extensions jars
folder could look something like this:
/META-INF/MANIFEST.MF
/jars/mybundle.jar
Components
/components
You can make components globally available by adding them to the folder /components
.
The content of the extensions components
folder could look something like this:
/META-INF/MANIFEST.MF
/components/org/lucee/my/com/MyComp.cfc
Installing
Now that we have looked at how to install artifacts and configure base settings, we will explain how to install specific functionality to extend Lucee.
Resources (Virtual file system)
resource:{...}
Lucee has an interface to install a virtual file system that can be used in every aspect of the language.
Lucee support a Java and a CFML interface for virtual file systems, so a virtual filesystem can be written in either Java or CFML.
However the installation of a Java based virtual file system is different to the installation of a CFML based virtual file system, therefore we will cover these 2 things separately.
Java based Virtual File System
For a Java virtual file system we need to register the class that implements the interface ResourceProvider
, to do this we add the following setting to the MANIFEST.MF
file:
resource:"[{
'class':'my.very.special.fs.WhateverProvider',
'bundleName':'my.whatever',
'bundleVersion':'1.2.3.4',
'scheme':'we',
'lock-timeout':'10000'
}]"
We define this setting as a JSON String. We define the class that implements the ResourceProvider and the bundle name and version. In addition we can also define other settings such as lock-timeout
, in the case above. All of these configuration settings are simply forwarded to the init
method of the class defined.
Copy the OSGi bundle (JAR) containing your ResourceProvider to the /jars
folder in your extension. It is not necessary to load the JAR with the help of the start-bundles
setting, Lucee will find the JAR with the help of the bundle definition and only load it as required.
CFML based Virtual File System
For CFML based virtual file systems we need to register the Resource Provider as well, but this time as a CFML component, add something like the following to the MANIFEST.MF
file:
Resource:"[
{'component':'my.very.special.fs.WhateverProvider'
,'scheme':'we',
'lock-timeout':'10000'
}]"
Now we have to make that component available for Lucee, there are two ways to do this. You can make the component available as part of a component archive (see Archives
above) or you simply add the component to the /components
folder (see Components
above).
Example implementation:
https://github.com/lucee/extension-s3
Mapping
mapping:[]
You can define mappings that point to files, archives or virtual file systems you are installing. You can define as many mappings as you need by adding something like the following to the MANIFEST.MF
file:
mapping: "[
{
'virtual':'/org/lucee',
'physical':'https://lucee.org',
'inspect':'never'
},
{
'primary':'archive',
'virtual':'/myApp',
'toplevel':true,
'archive':'/../myapp.lar'
}]"
JDBC
To install a JDBC Driver, add the following setting to the MANIFEST.MF
file:
jdbc: "[{
'label':'${label}',
'class':'${className}',
'bundleName':'${symbolicName}',
'bundleVersion':'${symbolicVersion}'
}]"
Copy the OSGi bundle (JAR) containing your JDBC to the /jars
folder in your extension. It is not necessary to load the JAR with the help of the start-bundles
setting, Lucee will find the JAR with the help of the bundle definition and only load it as required.
Example implementation:
https://github.com/lucee/JDBC-extension-factory
Search
Installing a Search Engine.
To install a search engine you need to register the class that implements the interface lucee.runtime.search.SearchEngine
, to do this we add the following setting to the MANIFEST.MF
file:
search: "[{
'class':'${class}',
'bundleName':'${bundlename}',
'bundleVersion':'${bundleversion}${build.number}'
}]"
Copy the OSGi bundle (JAR) containing your Search Engine implementation to the /jars
folder in your extension. It is not necessary to load the JAR with the help of the start-bundles
setting, Lucee will find the JAR with the help of the bundle definition and only load it as required.
Example implementation:
https://github.com/lucee/extension-lucene
ORM
To install an ORM Engine you need to register the class that implements the interface lucee.runtime.orm.ORMEngine
, to do this we add the following setting to the MANIFEST.MF
file:
orm: "[{
'class':'${class}',
'name':'${bundlename}',
'version':'${bundleversion}${build.number}'
}]"
Copy the OSGi bundle (JAR) containing your ORM Engine implementation to the /jars
folder in your extension. It is not necessary to load the JAR with the help of the start-bundles
setting, Lucee will find the JAR with the help of the bundle definition and only load it as required.
Example implementation:
https://github.com/lucee/extension-hibernate
Java based Tag/Function (TLD/FLD)
/jars
/tlds
/flds
Installing one or multiple Java based tags or functions. Installing a tag or a function is the same process, because of that we handle these two topics together. A Java based tag/function needs two things:
- An OSGi Bundle (JAR) containing the class that implements the interface
javax.servlet.jsp.tagext.Tag
for tags and/orlucee.runtime.ext.function.BIF
for a function. - A tld/fld file that contains the description of one or multiple of the tags/functions.
So copy the OSGi bundles to the folder /jars
and the tld/fld file to the folder /tlds
or /flds
.
Side note: For TLD files please use the extension .tldx
, otherwise it can break Tomcat when it attempts to read the .tld
file. Lucee can handle the extensions .tld
and .tldx
, and Tomcat will ignore .tldx
.
Example implementation:
https://github.com/lucee/extension-pdf
Monitor
Install a Monitor (more detailed documentation will follow).
monitor: "[{
'name':'${actionMonitorName}',
'type':'${actionMonitorType}',
'class':'${actionMonitorClass}',
'bundleName':'${bundlename}',
'bundleVersion':'${bundleversion}${build.number}'
},
{
'name':'${intervalMonitorName}',
'type':'${intervalMonitorType}',
'class':'${intervalMonitorClass}',
'bundleName':'${bundlename}',
'bundleVersion':'${bundleversion}${build.number}'
},
{
'name':'${requestMonitorName}',
'type':'${requestMonitorType}',
'class':'${requestMonitorClass}',
'bundleName':'${bundlename}',
'bundleVersion':'${bundleversion}${build.number}'
}]"
Cache Handler
This has nothing to do with installing a Cache
like EHCache
, this extends the functionality of all cachedwithin
attributes in Lucee.
The Lucee core supports two cache handler types out of the box:
- Time span cache, e.g.
cachewithin=createTimeSpan(0,0,0,10)
- Request span cache, e.g.
cachewithin="request"
So with this option you can extend this functionality.
To install a Cache Handler you need to register the class that implements the interface lucee.runtime.cache.tag.CacheHandler
, to do this we add the following setting to the MANIFEST.MF
file:
cache-handler: "[{
'id':'smart',
'class':'${class}',
'name':'${bundlename}',
'version':'${bundleversion}'
}]"
Copy the OSGi bundle (JAR) containing your Cache Handler implementation to the /jars
folder in your extension. It is not necessary to load the JAR with the help of the start-bundles
setting, Lucee will find the JAR with the help of the bundle definition and only load it as required.
AMF (Flex)
To install an AMF Engine you need to register the class that implements the interface lucee.runtime.net.amf.AMFEngine
, to do this we add the following setting to the MANIFEST.MF
file:
amf: "{
'class':'${class}',
'bundleName':'${bundlename}',
'bundleVersion':'${bundleversion}',
'caster':'modern',
'configuration':'manual'
}"
Example implementation:
https://github.com/lucee/extension-flex
Event Handler
(TODO)
Event Gateway
https://github.com/lucee/task-event-gateway