Step 3: Creating a Custom Field Descriptor
Project Picker CF
Let's say you need to provide support for a certain custom field. Power Scripts™ for Jira does offer support for the project picker CF but for educational purposes, let's see how you could add the support if it didn't.
The task is to register a translator from SILValue to the native object type and the other way around.
The code is presented below:
ProjectCFDescriptor.java
/*
* Created at: 3/28/13, 3:02 PM
*
* File: ProjectCFDescriptor.java
*/
package com.mycompany.silexample;
import com.atlassian.jira.project.Project;
import com.atlassian.jira.project.ProjectManager;
import com.keplerrominfo.sil.lang.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ofbiz.core.entity.GenericValue;
import com.keplerrominfo.common.util.MutableString;
import com.keplerrominfo.common.util.StringUtils;
import com.keplerrominfo.jira.commons.ivm.FieldDescriptor;
import com.keplerrominfo.sil.lang.type.TypeInst;
/**
* The project CF descriptor, com.atlassian.jira.plugin.system.customfieldtypes:project
*
* @author Radu Dumitriu (rdumitriu@gmail.com)
*/
public class ProjectCFDescriptor implements FieldDescriptor<GenericValue, MutableString> {
//This template class tells us that the values exchanged are GenericValue (JIRA side) and MutableString (SIL)
private static final Log LOG = LogFactory.getLog(ProjectCFDescriptor.class);
private final ProjectManager projectManager;
public ProjectCFDescriptor(ProjectManager projectManager) {
this.projectManager = projectManager;
}
@Override
public SILType<MutableString> getType() {
return TypeInst.STRING;
}
@Override
public GenericValue toJiraValue(SILContext ctx, SILValue<MutableString> value) {
String projectKey = StringUtils.trim(value.toStringValue());
if (projectKey == null) {
return null;
}
Project project = projectManager.getProjectObjByKey(projectKey);
if(project == null) {
LOG.warn(String.format(">>%s<< is not a valid project key", projectKey));
return null;
}
// Project picker CF stores the value as GenericValue. This is deprecated, but we need to call it
return project.getGenericValue();
}
@Override
public SILValue<MutableString> toSILValue(SILContext ctx, GenericValue value) {
return value != null ? SILValueFactory.string(value.getString("key")) : SILValueFactory.string();
}
}
Register a CF descriptor in the launcher:
BundleActivator.java
@Override
public void doAtLaunch() {
super.doAtLaunch();
//register the function
FunctionRegistry.register(new ReverseStringFunction("myReverseString"));
//register the CF descriptor
customFieldDescriptorRegistry.register("com.atlassian.jira.plugin.system.customfieldtypes:project", //this is the real key of the CF
new AbstractCustomFieldDescriptorFactory(
"example.project.cfdf", //internal identification. Must be unique in the SIL system
"Project Key to String", //short description, followed by a longer one
"Extract the project key using GenericValue or project") {
// Descriptors are created when needed, and some of them might be contextual. This is why you register here a creator of a
// descriptor and not the real descriptor
@Override
public FieldDescriptor createDescriptor(Issue issue, CustomField cf) {
return new ProjectCFDescriptor(projectManager);
}
}
);
}
@Override
public void doAtStop() {
//first, make sure that super is called, even if it has an exception here
try {
//unregister the function
FunctionRegistry.unregister("myReverseString");
//unregister the CF descriptor
customFieldDescriptorRegistry.unregister("com.atlassian.jira.plugin.system.customfieldtypes:project"); //this is the real key of the CF
} catch(Exception e) {
LOG.error("Failed to unregister!", e);
}
super.doAtStop();
}
Line 9 registers the CF into our CF translators map. Hooray!
That's all you need. You can now play with SIL™ like such:
something.sil
summary += " -- " + KProject; //where KProject is your CF name!