Workflow Validator to require a field on a transition screen

There is an allegedly more complete field validator in the JIRA Suite Utilities. Apparently it handles both custom and system fields

The attached workflow validator plug-in can be associated with a transition screen to make specific fields mandatory. This version has been updated to work with Jira 3.5 and can be used on any transition to make any custom fields required. (Of course, the fields must be on the workflow transition screen.) I have not tested this with all possible custom field types, but it does work with the most common types.

The plugin also works with  bulk edits, but has a peculiar behaviour - if one or more of the required fields is not set, the workflow transition fails, but there is no error message or other indication that the workflow failed. (The validator is not called until after you confirm the bulk transition.)

To use, drop the attached jar into WEB-INF/lib and restart Jira. When you edit a workflow, select Add a new validator, and you should see o Field Validator as an option. When you add the validator, you will see a list of all custom fields. You can select any number of fields to associate with the validator.

Here is a snippet of the updated validator. I've removed logging and some error checking for simplicity.

package com.atlassian.jira.plugin.workflow.field.validator;

import ...

public class FieldValidator  implements Validator
{

    MutableIssue issue=null;
    Map mods;
    CustomFieldManager cfm = ManagerFactory.getCustomFieldManager();
    InvalidInputException invIn = null;

public static ValidatorDescriptor makeDescriptor() {
        return makeDescriptor(null);
    }   public static ValidatorDescriptor makeDescriptor(String param)
    {
        ValidatorDescriptor fieldValidator = new ValidatorDescriptor();
        fieldValidator.setType("class");
        fieldValidator.getArgs().put("class.name", FieldValidator.class.getName());
        return fieldValidator;
    }

public void validate(Map transientVars, Map args, PropertySet ps) throws InvalidInputException
    {
        BasicWorkflowContext context = null;
        if (transientVars!=null) {
            context = (BasicWorkflowContext) transientVars.get("context");
        }
        String username = null;
        if (context!=null) username = context.getCaller();;

        User user = null;

        try
        {
            if (username != null)
            {
                user = UserManager.getInstance().getUser(username);
            }
        }
        catch (EntityNotFoundException e)
        {
            throw new InvalidInputException("Invalid user (" + username + ")");
        }
         issue = (MutableIssue) transientVars.get("issue");           checkFields(args, transientVars, user);
    }
    protected void checkFields(Map args, Map transientVars, User user) throws InvalidInputException
       {
        mods = issue.getModifiedFields();

        String selectedFieldsString = (String)args.get("selectedFields");
        if (selectedFieldsString!=null)  {
             StringTokenizer st = new StringTokenizer(selectedFieldsString, ";");

            while(st.hasMoreTokens())
            {
                String singleSelectedField = st.nextToken();
                checkForVal(singleSelectedField);
            }
        }
        if (invIn!=null) throw invIn;
    }
    protected void checkForVal(String cfName) {
        CustomField cf = cfm.getCustomFieldObjectByName(cfName);
        if (cf==null) {
            setError(null,"Trying to use the field validator with a non-existant custom field: ["+cfName+ "] ");
           return;
        }

        ModifiedValue mv = (ModifiedValue) mods.get(cf.getId());
        String newValue ;

        if (mv==null)   {
            setError(null,cfName+" is not on the transition screen associated with this use of this validator.");
        }
        else  {
            newValue = (String) mv.getNewValue();
            if (!TextUtils.stringSet(newValue) ) {
                // -- value not set for cfName --
                setError(cf, null);
            }
        }
    }
    protected void setError(CustomField cf, String errmsg) {
       if (cf==null) {
           if (invIn==null) invIn = new InvalidInputException(errmsg);
           else invIn.addError(errmsg);
       }
       else {
           if (invIn==null) invIn = new InvalidInputException(cf.getId(),cf.getName()+ " is required.");
           else invIn.addError(cf.getId(),cf.getName()+ " is required.");
       }
   }
}

Labels

 
  1. Jul 21, 2005

    E Joseph Guay says:

    Notes 1. some of the text got mangled when it was posted. In particular a string...

    Notes 1. some of the text got mangled when it was posted. In particular a string concatination ... + cfName + ... became an underlined cfName.
    2. This only works with Jira 3.2 and later. (Uses an Issue object)

    1. Jul 21, 2005

      Philip Herbst says:

      voila

      voila

    2. Oct 27, 2005

      Anonymous says:

      I'm experiencing trouble with this workflow plugin. It's exactly what I need, so...

      I'm experiencing trouble with this workflow plugin.
      It's exactly what I need, so I'm eager to get it working...
      I'm using JIRA Enterprise 3.3.

      mods = issue.getModifiedFields();
      results in:
      cannot find symbol
      symbol : method.getModifiedFields()
      location: interface com.atlassian.jira.issue.Issue
      As an experiment I changed issue from class Issue to MutableIssue.
      The getModifiedFields method is then recognized, but other compile errors are of course the result.

      As I'm a newbie to JIRA (and pretty much to Java...) I'm stumbling around trying grasp all concepts, finding classes etc.
      Building the examples from the toolkit is no problem, but trying to write my own workflow validator using the code posted here, I'm at a loss what to put in atlassian-plugin.xml, especially what the workflow-validator class should be.
      I see factories everywhere, but what do I need for this validator?

      Any help would be very appeciated!

      1. Oct 27, 2005

        Nick Menere says:

        Sorry, this API has recently changed. You should now retrieve a {{MutableIssue}}...

        Sorry, this API has recently changed. You should now retrieve a MutableIssue from the args, not an Issue.

        For people developing their own plugins we recommend using the JIRA Plugin Development Kit.
        This will give you skeletons and examples of things your are after.
        For this example, the {(workflow-validator}} should be:

        com.atlassian.jira.plugin.workflow.fixscreen.validator.FixScreenValidator

        For further development help, please consult the Developer Network. This contains many answers and instructions on how to get development help.

        Cheers,
        Nick

  2. Sep 30, 2005

    Rémy Mouton says:

    What is the ValidatorDescriptor used for? When does the static methods get calle...

    What is the ValidatorDescriptor used for? When does the static methods get called?

  3. Sep 30, 2005

    Rémy Mouton says:

    Very annoying side effect: the InvalidInputException thrown upon invalid input c...

    Very annoying side effect: the InvalidInputException thrown upon invalid input causes an ERROR in the logs and printing a stack trace on the server console. How can I prevent that? (Users providing invalid input isn't a server error at all, it is a quite normal use case.)

  4. Oct 04, 2005

    Anton Mazkovoi says:

    The issue is discussed on JRA8100 JRA8100@JIRA

    The issue is discussed on JRA-8100

  5. Oct 31, 2005

    Frank Polscheit says:

    Hi all, I am trying to get this plugin working with JIRA 3.4 Beta 1 using the pl...

    Hi all,
    I am trying to get this plugin working with JIRA 3.4 Beta 1 using the plugin-dev.-kit, but I have quite some problems in setup the correct XML-files. What factory class do I have to use for instanciating the plugin "fixScreenValidator" (code above)?

    Thank's in advance as I do not found hints within the Developer Network for this.

    1. Nov 02, 2005

      Jeff Turner says:

      There is a sample descriptor at:

      There is a sample descriptor at:

      http://confluence.atlassian.com/display/JIRA/How+to+create+Custom+Workflow+Elements+for+JIRA+3

      as well as system-workflow-plugin.xml in the JIRA distribution.

  6. Feb 14, 2006

    Jeff Huff says:

    I am trying to write a workflow validator that will let the user configure what ...

    I am trying to write a workflow validator that will let the user configure what fields are required to be filled in when passing through a workflow transition.  I have a factory that extends AbstractWorkflowPluginFactory and implements

        protected void getVelocityParamsForInput(Map velocityParams)
        protected void getVelocityParamsForEdit(Map velocityParams, AbstractDescriptor descriptor)
        protected void getVelocityParamsForView(Map velocityParams, AbstractDescriptor descriptor)
        public Map getDescriptorParams(Map conditionParams)
     

    I would like the input-parameters template to have a multiple select box that contains the list of possible fields that are looked up from the FieldManager and put into the velocityParams on getVelocityParamsForEdit and getVelocityParamsForView.

    <select name="requiredfields" size="5" multiple="multiple">

    <option>Resolution</option><option>Comment</option> ...

    </select>

     I assume that when the input-parameters template is completed the getDescriptorParams(Map) method is called with the data entered on the form that is to be saved with the workflow transition configuration.

     My question is if you use an HTML element that is multi-valued, what will the key and value types in the Map be?  <String>,<List> or <String>,<String[]>, or <String>,<String> somehow delimited?  I could then convert from a list or array to a delimited value to save in the workflow descriptor and back for view or edit.

    It seems silly to create a Validator for each transition that has a screen assigned to it. 

    Is it supported to have multi-valued HTML parameters in the way I envision this generic validator design?

  7. May 17, 2006

    Neil Arrowsmith says:

    Is there a version of this plugin available somewhere that works with Jira 3.2.2...

    Is there a version of this plugin available somewhere that works with Jira 3.2.2?

  8. May 17, 2006

    E Joseph Guay says:

    Validator version 1.0 has been added. This works with Jira 3.2.

    Validator version 1.0 has been added. This works with Jira 3.2.

    1. May 17, 2006

      Neil Arrowsmith says:

      Thanks very much for the speedy response. However, this doesn't work either alth...

      Thanks very much for the speedy response. However, this doesn't work either - although the error is a lot tidier than what I got before. This is the error now when I try to progress a workflow step after entering valid values in the validated fields:
      An unknown exception occured executing Validator: com.atlassian.jira.plugin.workflow.field.validator.FieldValidator: root cause: java.lang.ClassCastException

      Any ideas?

  9. May 17, 2006

    E Joseph Guay says:

    I don't have much to go on. Try eliminating "unusual" custom fields from the val...

    I don't have much to go on. Try eliminating "unusual" custom fields from the validation to see if that is the cause. (The validator takes the new value of the field and casts it to (String). I believe this works with simple text fields, select fields and numeric fields, but may not work with some other types of custom fields.) 

  10. May 17, 2006

    E Joseph Guay says:

    Actually, the "numeric" field that we use is actually a text field that we parse...

    Actually, the "numeric" field that we use is actually a text field that we parse into a number, so a numeric field may be the problem.

    1. May 17, 2006

      Neil Arrowsmith says:

      Thanks very much. I'm using this validator on a number of fields and one of them...

      Thanks very much. I'm using this validator on a number of fields and one of them is a numeric field. I'll try taking it off that one.

      Thanks again.

      1. May 18, 2006

        Neil Arrowsmith says:

        Hello again It's not the numeric field as i've removed the validation on that. ...

        Hello again

        It's not the numeric field - as i've removed the validation on that. Problem is happening on a user picker field.

        Is this likely to be a problem with just the 3.2 version or will I see it with the 3.5 version too - once we upgrade?

        Thanks
        Neil

  11. May 18, 2006

    Bettina Zucker says:

    Hello everybody, I just wanted to say that there is a very elegant, configurable...

    Hello everybody,

    I just wanted to say that there is a very elegant, configurable solution of this validator in the Codegeist contribution of Gustavo Martin, the "Jira Suite Utilities".

    The plugin works for custom and system fields alike.

    I don't know if it is working for every field type though.

    The only problem I found with it is if I'm using non default Field Configurations.

    Then some field may be hidden in the fields configuration but required in the default field configuration and the plugin gets  confused. The transition then does not work but there is no error message saying what is the problem.

    But this problem is also shared by the plugin presented in this page, so it's nothing new.

    Cheers

    Bettina 

    1. May 18, 2006

      Neil Arrowsmith says:

      Thanks Bettina that sounds interesting. Do you know if the plugin works for Jira...

      Thanks Bettina - that sounds interesting. Do you know if the plugin works for Jira 3.2.2?

      1. May 22, 2006

        Bettina Zucker says:

        Hi Neil, It is declared to work with Jira 3.5, so I don't think it will work wit...

        Hi Neil,

        It is declared to work with Jira 3.5, so I don't think it will work with an older version.
        But I'm not sure, since I also only tested it with 3.5.1. Why you don't just try it out?

         Cheers

        Bettina Zucker 

  12. May 18, 2006

    E Joseph Guay says:

    I have updated the validator (version 1.2) to work with most&nbsp;custom field t...

    I have updated the validator (version 1.2) to work with most custom field types.

    Cheers.

  13. May 23, 2006

    Christi Austin says:

    Hi, Has anyone had any luck with getting&nbsp;this to work with Jira Enterprise ...

    Hi,

    Has anyone had any luck with getting this to work with Jira Enterprise 3.6?

    Thanks,

    Christi

  14. Jun 02, 2006

    Chris Mountford says:

    Hi Christi, I just tried this with 3.6.2 and it doesn't work properly. There se...

    Hi Christi,

    I just tried this with 3.6.2 and it doesn't work properly. There seems to be some problem finding the templates/field-validator-input-params.vm but as I don't have the source code for this plugin I'm not sure why this has stopped working in recent versions of Jira.

    Perhaps this plugin's author, E. Joseph Guay can make some better informed comment.

    Regards,

    Chris.

  15. Jun 05, 2006

    Christi Austin says:

    Hi Chris, Thanks for verifying the error I was having on 3.6. Even though the pl...

    Hi Chris,

    Thanks for verifying the error I was having on 3.6. Even though the plug-in is not geared for 3.6 it is always good to know that it is not an operator error!

    Christi

  16. Jun 09, 2006

    san pil says:

    Hi I tried the required field option and could not add a&nbsp; selected&nbsp;fie...

    Hi

    I tried the required field option and could not add a  selected field from the list on the left to the required list on the right.

    On trying the seccond option of using the  field value validator on the resolve screen  I get the follwoing error. Any tips would be of great help

    Sanil

     
     
  17. Jun 09, 2006

    E Joseph Guay says:

    I've attached version 1.3 that is a recompile of the plugin with Jira 3.6.2 sour...

    I've attached version 1.3 that is a recompile of the plugin with Jira 3.6.2 source. It should work on 3.6 but it has not been tested. (I do not yet have 3.6 installed.) It does run on 3.5.3

    1. Aug 01, 2006

      Remon van Gijn says:

      Just tested the validator with a test JIRA3.6.2 setup, seems OK, and I was able ...

      Just tested the validator with a test JIRA-3.6.2 setup, seems OK, and I was able to add a validator for one of our custom fields without errors.

      Unfortunately we are looking for a way to make the standard fields manditory in workflow transition, so this is not our solution. (the jira suite has a bug with this so is not usable (yet).)

      1. Aug 30, 2006

        jpp says:

        Hi, &nbsp;I have this "Field Required" issue. We are using JIRA 3.6.4 Enterprise...

        Hi,

         I have this "Field Required" issue. We are using JIRA 3.6.4 Enterprise and that JIRA Suite Utilities does not work.

         It gives following error, when I try to add required custom field to required list:Line: 846Char: 21Error: Invalid argument.Code: 0URL: https://......./secure/admin/workflows/AddWorkflowTransitionParams!default.jspa?workflowName=W1&workwlowStep=1&workflowTransition=4&pluginModuleKey=com.atlassian.jira.plugin.jirasuite%3AfieldsRequired-validator 
        So, it is impossible to add required fields to transactions. This is a "blocker".

        -JP 

  18. Sep 30, 2006

    Neal Applebaum says:

    I was able to get this plugin to work making a field required on a transition, b...

    I was able to get this plugin to work - making a field required on a transition, but in the logs there is this error. Should I be worried about it?

    ERROR [atlassian.jira.workflow.SimpleWorkflowManager] An exception occurred
    [InvalidInputException: [Error map: [

    Unknown macro: {customfield_10130=Files Modified is required.}
    ]] [Error list: [[]]]
        at com.atlassian.jira.plugin.workflow.field.validator.FieldValidator.setError(FieldValidator.java:237)
        at com.atlassian.jira.plugin.workflow.field.validator.FieldValidator.checkForVal(FieldValidator.java:159)
        at com.atlassian.jira.plugin.workflow.field.validator.FieldValidator.checkFields(FieldValidator.java:129)
        at com.atlassian.jira.plugin.workflow.field.validator.FieldValidator.validate(FieldValidator.java:111)
        at com.opensymphony.workflow.AbstractWorkflow.verifyInputs(AbstractWorkflow.java:985)
        at com.opensymphony.workflow.AbstractWorkflow.transitionWorkflow(AbstractWorkflow.java:1198)
        at com.opensymphony.workflow.AbstractWorkflow.doAction(AbstractWorkflow.java:533)
        at com.atlassian.jira.workflow.SimpleWorkflowManager.doWorkflowAction(SimpleWorkflowManager.java:253)
        at com.atlassian.jira.workflow.WorkflowTransitionUtilImpl.progress(WorkflowTransitionUtilImpl.java:271)
        at com.atlassian.jira.web.action.issue.CommentAssignIssue.doExecute(CommentAssignIssue.java:190)
        at webwork.action.ActionSupport.execute(ActionSupport.java:153)
        at com.atlassian.jira.action.JiraActionSupport.execute(JiraActionSupport.java:57)
        at webwork.dispatcher.GenericDispatcher.executeAction(GenericDispatcher.java:132)
        at com.atlassian.jira.web.dispatcher.JiraServletDispatcher.service(JiraServletDispatcher.java:185)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
        at com.atlassian.jira.web.filters.AccessLogFilter.doFilter(AccessLogFilter.java:51)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
        at com.opensymphony.module.sitemesh.filter.PageFilter.parsePage(PageFilter.java:119)
        at com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilter.java:55)
        at com.atlassian.jira.web.filters.SitemeshExcludePathFilter.doFilter(SitemeshExcludePathFilter.java:38)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
        at com.atlassian.seraph.filter.SecurityFilter.doFilter(SecurityFilter.java:182)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
        at com.atlassian.seraph.filter.LoginFilter.doFilter(LoginFilter.java:181)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
        at com.atlassian.util.profiling.filters.ProfilingFilter.doFilter(ProfilingFilter.java:132)
        at com.atlassian.jira.web.filters.ProfilingAndErrorFilter.doFilter(ProfilingAndErrorFilter.java:35)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
        at com.atlassian.jira.web.filters.ActionCleanupDelayFilter.doFilter(ActionCleanupDelayFilter.java:39)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
        at com.atlassian.johnson.filters.JohnsonFilter.doFilter(JohnsonFilter.java:91)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
        at com.atlassian.jira.web.filters.gzip.GzipFilter.doFilter(GzipFilter.java:72)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
        at com.atlassian.core.filters.AbstractEncodingFilter.doFilter(AbstractEncodingFilter.java:37)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:744)
        at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
        at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
        at java.lang.Thread.run(Thread.java:534)

  19. Oct 02, 2006

    E Joseph Guay says:

    Unfortunately, this is how Jira communicates&nbsp;the need for providing the dat...

    Unfortunately, this is how Jira communicates the need for providing the data in the required field, and puts up the red band on the transition screen. Later versions of Jira may handle this situation differently.

    See the comment above "Very annoying side effect" and  JRA-8100

  20. Oct 04, 2006

    Neal Applebaum says:

    Whenever I click on the workflow's validators, I get this error message in the l...

    Whenever I click on the workflow's validators, I get this error message in the log:

    ERROR [velocity] Right side ($statuses.size()) of '!=' operation has null value. Operation not possible. templates/field-validation-view.vm [line 2, column 71]

    It seems to work, though.

    Any ideas? Thanks

  21. Jan 12, 2007

    Alex Holtz says:

    3.7 compatibility?

    3.7 compatibility?

    1. Jan 12, 2007

      Alex Holtz says:

      It seems to work just fine with 3.7.1 from the brief testing I did tonight.

      It seems to work just fine with 3.7.1 from the brief testing I did tonight.

      1. Jan 18, 2007

        Yudong Song says:

        Alex, which version are you using? I have 3.7.1 server. I downloaded workflowfie...

        Alex,

        which version are you using? I have 3.7.1 server. I downloaded workflow-field-validator-1.3.jar and copied to the lib directory, but I didn't see the plugin after restarted the server. Thank you in advance.

        Yudong

        1. Feb 28, 2007

          Adam Attinello says:

          It works fine in 3.7.1 on my linux box, but on a windows box it does not show up...