Post

3 followers Follow
0
Avatar

Wrote a custom validator that I can't seem to access from the synthetic

Based on the example here:
https://docs.xebialabs.com/xl-deploy/how-to/create-a-custom-validation-rule.html

I created a jar with a custom validator to use as a POC.  It builds fine, but when I try to access it from the synthetic.xml XLD fails to start:
2018-04-24 13:58:04.803 [main] {} ERROR c.x.deployit.DeployitBootstrapper - Could not find validation rule type url-valid defined on property overthere.CifsHost.customUrl

I put the resultant xldp into the server\plugins directory - does it go somewhere else?

The regex call below works, but not the call to url-valid.  That's where I get the startup error.

synthetic entry:

<type-modification type="overthere.CifsHost">
<property name="ipAddress" kind="string" hidden="false" required="true" description="Use a valid IPv4 address only">
<rule type="regex" pattern="^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
message="You must enter a valid IPv4 address"/>
</property>
<property name="customUrl" kind="string" hidden="false" required="true" description="Use a valid URL only">
<rule type="url-valid" content="http" message="You must enter a valid URL"/>
</property>
</type-modification>


Validator POC:

import com.xebialabs.deployit.plugin.api.validation.Rule;
import com.xebialabs.deployit.plugin.api.validation.ValidationContext;
import com.xebialabs.deployit.plugin.api.validation.ApplicableTo;
import com.xebialabs.deployit.plugin.api.reflect.PropertyKind;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@ApplicableTo(PropertyKind.STRING)
@Retention(RetentionPolicy.RUNTIME)
@Rule(clazz = UrlValid.Validator.class, type = "url-valid")
@Target(ElementType.FIELD)
public @interface UrlValid {
String content();

public static class Validator
implements com.xebialabs.deployit.plugin.api.validation.Validator<String> {
private String content;

@Override
public void validate(String value, ValidationContext context) {
if (!(value.startsWith(content))) {
context.error("URL Invalid <%s>. Please enter a valid url", content);
}
}
}
}

Kevin Kocher

Official comment

Avatar

Hi Kevin, you can apply the validator at the CI level by specifying @Target(ElementType.TYPE).  Then value argument will be a reference to the CI, so then you can use that to obtain other CI data with value.getProperty("myPropertyName") -- or perhaps just value.getId() for your case -- and then parse the app id out of that.

Dave Roberts

Please sign in to leave a comment.

6 comments

0
Avatar

Fixed the above code by moving it to a non default package.  Once I did that I found I was passing values from the synthetic that weren't needed.
The following works as a POC:
<property name="customURL" kind="string" hidden="false" required="true" description="Use valid URL only">
<rule type="url-valid"/>
</property>

package com.xebialabs.deployit.plugin.poc.validator;


import com.xebialabs.deployit.plugin.api.validation.Rule;
import com.xebialabs.deployit.plugin.api.validation.ValidationContext;
import com.xebialabs.deployit.plugin.api.validation.ApplicableTo;
import com.xebialabs.deployit.plugin.api.reflect.PropertyKind;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@ApplicableTo(PropertyKind.STRING)
@Retention(RetentionPolicy.RUNTIME)
@Rule(clazz = UrlValid.Validator.class, type = "url-valid")
@Target(ElementType.FIELD)
public @interface UrlValid {
String content();
public static class Validator
implements com.xebialabs.deployit.plugin.api.validation.Validator<String> {
private static final String valid_url = "http";

@Override
public void validate(String value, ValidationContext context) {
if (!(value.startsWith(valid_url))) {
context.error("<%s> is invalid. Please enter a valid URL", value);
}
}
}
}

 

Kevin Kocher 0 votes
0
Avatar

I worked with Kevin and we determined that the java code needs to be part of a package (e.g. package com.xebialabs.deployit.plugin.poc.validator;). After we added this to our Java code the validator successfully loaded and worked on the field that we specified.

Jeff Kelley 0 votes
0
Avatar

Is there a way to get at the ci information associated with the field being validated?

Our use case is we block the create/update of applications in XLD sunbject to more than one condition.  Specifically

1. Use the file URI to get at some external metadata.  Using the above example this is possible.

2. If we find or don't find this external data, from within the validator we need to get at the app id associated with this field (value) being passed to us whether it already exists (update) or doesn't (create).  This will further determine whether we want to set the context.error and fail the create/update.

Does that make sense?  Is there some way to do this?

Kevin Kocher 0 votes
0
Avatar
/* Including an example.
* Synthetic.xml contains
* <type-modification type="udm.DeploymentPackage">
* <rule type="paychex-demo-ci" appid="MyDemoAppId" />
* </type-modification>
*
* Log output is
* 2018-05-09 21:30:55.685 [qtp475871799-18] {username=admin} INFO  c.x.p.demo.PaychexDemoCI$Validator - Deployment Package getId()=Applications/PaychexDemoApp/1.0
* 2018-05-09 21:30:55.686 [qtp475871799-18] {username=admin} INFO  c.x.p.demo.PaychexDemoCI$Validator - appid from synthetic.xml=MyDemoAppId
*/
package com.xebialabs.paychex.demo;

import com.xebialabs.deployit.plugin.api.udm.DeploymentPackage;
import com.xebialabs.deployit.plugin.api.validation.Rule;
import com.xebialabs.deployit.plugin.api.validation.ValidationContext;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Retention(RetentionPolicy.RUNTIME)
@Rule(clazz = PaychexDemoCI.Validator.class, type = "paychex-demo-ci")
@Target(ElementType.TYPE)
public @interface PaychexDemoCI {

String appid();

    

    public static class Validator implements com.xebialabs.deployit.plugin.api.validation.Validator<DeploymentPackage> {

    private String appid;

    private final static Logger logger = LoggerFactory.getLogger(Validator.class);

    
    @Override
    public void validate(DeploymentPackage value, ValidationContext context) {
            logger.info(String.format("Deployment Package getId()=%s", value.getId()));
            logger.info(String.format("appid from synthetic.xml=%s", appid));
    }

    }

}
Dave Roberts 0 votes
0
Avatar

This is great stuff.  Thanks Dave, I think we could find several uses for this in our environment.  Really appreciate the response!

Kevin Kocher 0 votes