Ignition SDK Programmer's Guide
How-to Articles
Strategic Partner Links
Sepasoft - MES Modules
Cirrus Link - MQTT Modules
Resources
Inductive University
Ignition Demo Project
Knowledge Base Articles
Forum
IA Support
SDK Examples
Project Resources, as described in the Programming for the Gateway section, are the primary data persistence mechanism for modules that need to store data on a per-project basis. The definition of what a resource represents is completely undefined, allowing modules to define them in any way that they like. There are certain paradigms that generally should be followed, such as displaying the resources in the Project Resource Tree in the designer and adding actions for creating new instances to the Designer menus.
Project resources are essentially raw data with a unique id. There are a variety of useful accessories built in, such as support for folder hierarchies, but at their core they are very simple. They are contained in a Project object, which may represent either the full project, or a subset of it. For example, when resource changes are communicated to the modules, an instance of Project containing only the modified rows is delivered.
The process of creating a new resource involves generating an id for it, creating the resource, and then updating the project to include it.
Resource ids must be created atomically through the resource lock manager. For example:
long newId = designerContext.getLockManager().newResourceId();
Instantiate a new ProjectResource class with the new id, your module id, resource type id, and other data. For example:
ProjectResource resource = new ProjectResource(newId, moduleId, resourceType, resourceName, ApplicationScope.GATEWAY, resourceData);
Remember that project resources dictate a scope that indicates where they will be used. This is primarily to avoid sending resources that are only used in the gateway to the clients. The designer, of course, will have access to all resources. This example expects that you have all of the fields already defined in variables. The resource data is a byte array, and can be obtained by any method that you desire. Most commonly though, modules will simply use the serialization facilities provided by Igntion. For example, the following code could have easily proceeded the previous example:
MyModuleObject newObj = new MyModuleObject(); XMLSerializer s = designerContext.createSerializer(); byte[] resourceData; s.addObject(object); resourceData = s.serializeAndGZip();
Finally, the resource is added to the project:
designerContext.updateResource(resource);
While folders are simply project resources like the others, the way that they are created is a bit different than other resource types. The procedure resembles the steps above, in that a new resource id must be generated, and the folder is defined with a scope and module id, but instead of instantiating a new ProjectResource and adding it to the project, you simply call DesignerContext.addFolder(). For example:
designerContext.addFolder(newId, moduleId, ApplicationScope.GATEWAY, folderName, parent);
This function handles generating a new UUID for you, and also ensures that the folder name will be
unique for the module.
The general process of modifying resources is similar to that of creating them, in terms of serializing data, setting it, and calling updateResource(), with the exception that care should be given to managing Resource Lock s.
Since Ignition supports concurrent designer sessions, it is possible that two people may try to edit the same resources at once. Allowing both parties to edit a resource and then simply using one would not be intuitive to the user. To prevent this, resources can be locked for editing, which is communicated through the gateway so that all other designers are prevented from editing the same resource. Resource locks are tracked by session, and are automatically released when the session expires or the project saved. Still, careful management of locks by the module writer is important, as it reduces the number of times users encounter unexpected locked resource errors.
All lock management is performed through the ResourceLockManager
, which is obtained through the static ResourceLockManagerFactory.getManager()
function.
The process for properly managing locks is as follows:
At any time, the ResourceManager.hasLock()
function may be called to see if the current session currently has the lock for the resource. This is important because the updateLock()
and releaseLock()
functions require that the caller knows that it has the lock.
This contrived example shows the general process of modifying a resource object. The actual process would involve multiple stages of locking the resource, presenting it for modification, and later committing it.
long resourceId = getCurrentResourceId(); //Would return the currently selected resource if(ResourceLockManager.getManager().requestLock(resourceId)){ try{ ProjectResource resource = designerContext.getProject().getResource (resourceId); MyModuleObject object = getObjectFromResource(resource); //This function would deserialize the data in the resource ... edit the resource object ... resource.setData(serializeObject(object)); //User defined function serialize as described above ResourceLockManager.getManager().updateLock(resourceId); }finally{ } }else{ //Make sure to release the lock, even if an error occurs ResourceLockManager.getManager().releaseLock(resourceId); //Could not obtain lock, show an error }
Deleting resources is as simple as calling DesignerContext.getProject().deleteResource()
for the resource id with the markDeleted flag set to true. Note, however, that in regards to locking, the deletion of a resource should be treated the same as a modification, and the procedure outlined above should be followed.
Listening for project resource modifications is as easy as implementing a ProjectChangeListener
and registering it by calling ClientContext.addProjectChangeListener()
. The ProjectChangeListener
receives only the subset of the project that has changed, or the specific resource modified. At any time, however, it's possible to get the full project by calling Context.getProject()
.
As mentioned in the Creating New Resources section, ProjectResources support hierarchical organization with folders. Folders are simply ProjectResources themselves, with the important distinction that their resource data is actually a UUID
(universally unique identifier). This unique id stays consistent across resource renaming, and is what is used by resources to identify their parent folder.
Each resource, therefore, has a "parent uuid" field that defines the folder resource it belongs to. A null value indicates that the resource is at the root level. Folders are stored according to the module that they belong to, but are all of the same resource type, defined by ProjectResource.
To help make working with folders easier, the Project class has a variety of functions for browsing the structure. Additionally, the ProjectResource class has the getDataAsUUID() function that makes it simple to obtain the UUID value of a folder resource.
2 Comments
Anonymous
Anonymous
also:
serializeAndGZip()
serializeXMLAndGZip()
instead.