OK, I guess I figured out what my issue is/was.  I thought the default values 
were returned if a specified property doesn’t exist in the .cfg file OR if the 
property does exist but doesn’t have a value. Experimentation shows me that the 
latter isn’t true.

I assume this is proper behavior.

From: Leschke, Scott [mailto:[email protected]]
Sent: Wednesday, September 07, 2016 3:50 PM
To: [email protected]
Subject: RE: configuration property types and enums

OK, I decided that for the time being at least, I could provide defaults for 
the problematic annotation methods. I still receive the 
IllegalArgumentException I mentioned previously even though I made the 
following change.

@ObjectClassDefinition(name = "BAM Query Metric Provider Configuration")
@interface QueryProviderConfig
{
       String        system();
       String        path();
       int           frequency()   default 60;
       Status        status()      default Status.Requested;
       boolean       postable()    default false;

       RuleType      ruleType()  default RuleType.Custom;
       String        ruleDef()   default "";

       ProviderType         providerType();
       String               dataSource();
       String               queryFile();
       String[]             queryMods()         default {};
       String               nameColumn()      default "";
       String               valueColumn();
       ValueColumnType      valueColumnType() default ValueColumnType.INT;
}

There’s a bit of context that I left out last time though as I didn’t feel it 
was important but perhaps it is.  There another config type that contains a 
subset of the above which is used to set values in a base class. To convert to 
that type I use and anonymous interface as shown below.

@ObjectClassDefinition(name = "BAM Metric Provider Configuration")
public @interface MetricProviderConfig
{
       String        path()      default "";
       int           frequency()   default 60;
       Status        status()    default Status.Requested;
       boolean       postable()    default false;

       RuleType      ruleType()  default RuleType.Custom;
       String        ruleDef()     default "";
}

protected MetricProviderConfig toMPC(final QueryProviderConfig cfg)
throws Exception
{
       return new MetricProviderConfig()
       {
              public Class<? extends Annotation> annotationType()
              {
                     return MetricProviderConfig.class;
              }

              public String path()
              {
                     return cfg.path();
              }

              public int frequency()
              {
                     return cfg.frequency();
              }

              public Status status()
              {
                     return cfg.status();
              }

              public boolean postable()
              {
                     return cfg.postable();
              }

              public RuleType ruleType()
              {
270:                 return cfg.ruleType();   // Exception thrown here
              }

              public String ruleDef()
              {
                     return cfg.ruleDef();
              }
       };
}

The moderately interesting part of the traceback is as follows:
org.osgi.service.component.ComponentException: 
java.lang.IllegalArgumentException: No enum constant 
com.medline.bam.model.rule.IRule.RuleType.
            at 
org.apache.felix.scr.impl.inject.Annotations$Handler.invoke(Annotations.java:243)
            at com.medline.bam.model.metric.provider.$Proxy28.ruleType(Unknown 
Source)
            at 
com.medline.bam.model.metric.provider.QueryProvider$1.ruleType(QueryProvider.java:270)
            at 
com.medline.bam.model.metric.AbstractMetricProvider.update(AbstractMetricProvider.java:285)
            at 
com.medline.bam.model.metric.provider.AbstractQueryProvider.update(AbstractQueryProvider.java:241)
            at 
com.medline.bam.model.metric.provider.QueryProvider.activate(QueryProvider.java:288)

Here’s the activate method in QueryProvider.  An instance of 
MetricProviderConfig is passed into the object (not a component) that provides 
most of the concrete implementation of the QueryProvider component. The config 
is passed up to AbstractMetricProvider.update where cfg.ruleType() is invoked, 
which causes the method in the anonymous interface to be invoked which causes 
the exception.

@Activate
protected void activate(QueryProviderConfig cfg)
throws Exception
{
       ISystem system = Utils.getSystem(systems, cfg.system());

       if (system != null) {
              setImpl(system, cfg);
288:          getImpl().update(toMPC(cfg));
       }

       this.config = cfg;
}

The update method from AbstractMetricProvider:

protected void update(MetricProviderConfig cfg)
       throws Exception
{
       this.status   = cfg.status();
       this.postable = cfg.postable();

       String[] ruleDef = (isBlank(cfg.ruleDef()) ? null : 
cfg.ruleDef().split(","));

285:   switch (cfg.ruleType())
       {

Since cfg.ruleType() has a default, I would expect this to work but clearly 
it’s not. It works fine as long as long as ruleType has an explicit value in 
the .cfg file. The use of a default (in this context) seems to be the issue. Is 
the use of the anonymous interface causing me problems perhaps? I wasn’t sure 
how to make the conversion between types so I found that suggestion online.

I apologize for dumping all this out here but I’m kind of at a loss at this 
point and I figured it was probably best to give as much context as might be 
needed.

Regards,

Scott

From: Leschke, Scott [mailto:[email protected]]
Sent: Wednesday, September 07, 2016 10:31 AM
To: [email protected]<mailto:[email protected]>
Subject: RE: configuration property types and enums

Thanks for the info. My experience / knowledge of annotation interfaces is 
limited to say the least so that clears things up nicely. I’ll take a look at 
the Felix extension per your recommendation.  Thanks so much.

Scott

From: David Jencks [mailto:[email protected]]
Sent: Tuesday, September 06, 2016 6:37 PM
To: [email protected]<mailto:[email protected]>
Subject: Re: configuration property types and enums

OK, that’s pretty straightforward.

Annotations (@interface) can not return null values from their members. This is 
a java language thing, not a DS thing.  You need to assure either that your 
configuration has an appropriate value or specify a default in the annotation.  
You only get notified of the problem when you try to access the member.

Alternatively, you can use a felix extension allowing you to configure with an 
interface, in which case null returns are allowed.  You could define your 
defaults directly in the @Component annotation property member.  To do this 
investigate the DSExt annotations in the org.apache.felix.scr.ext.anno bundle. 
You’d use @DSExt.ConfigureWithInterfaces.

Hope this helps
david jencks

On Sep 6, 2016, at 2:08 PM, Leschke, Scott 
<[email protected]<mailto:[email protected]>> wrote:

Yes, this is a DS component.

@Component(
       configurationPid    = "medline.bam.metric.provider.query",
       configurationPolicy = ConfigurationPolicy.REQUIRE,
       immediate           = true
)
@Designate(ocd = QueryProviderConfig.class)
public class QueryProvider

Configuration Property Type: Name per 
http://njbartlett.name/2015/08/17/osgir6-declarative-services.html

The CFP is the following:

@ObjectClassDefinition(name = "BAM Query Metric Provider Configuration")
@interface QueryProviderConfig
{
       String system();
       String path();
       int           frequency()          default 60;
       Status status()                   default Status.Requested;
       boolean       postable()           default false;

       RuleType      ruleType();
       String        ruleDef()      default "";

       ProviderType         providerType();
       String               dataSource();
       String               queryFile();
       String[]             queryMods()          default {};
       String               nameColumn()      default "";
       String               valueColumn();
       ValueColumnType      valueColumnType() default ValueColumnType.INT;
}

The exception occurs within the Activator when the method ruleType() of the CFP 
is invoked.
I hesitate to post the code as it’s a bit more complicated but that’s the 
upshot. My gut is telling me that since RuleType is an enum, it can’t be null, 
although that make sense in this case.  I can test it of course, by adding 
“None” to the RuleType enum and setting the default to that but I’d prefer not 
to unless that’s the expected approach.

From: David Jencks [mailto:[email protected]]
Sent: Tuesday, September 06, 2016 2:48 PM
To: [email protected]<mailto:[email protected]>
Subject: Re: configuration property types and enums

I have some guesses about what you might be talking about but it doesn’t all 
make sense yet.This is a DS component, right?  Could you be a lot more 
specific, showing at least the activate method signature, whatever you mean by  
configuration property type, the enum, and the stack trace?  If you’ve used any 
extra annotations on the component please show them too.

thanks
david jencks

On Sep 6, 2016, at 11:52 AM, Leschke, Scott 
<[email protected]<mailto:[email protected]>> wrote:

I’m getting the following exception from an activate method.

org.osgi.service.component.ComponentException: 
java.lang.IllegalArgumentException: No enum constant (Enumeration type name).

The activate method takes a Configuration Property Type that has a method that 
returns a value of the type but does NOT have a default defined. The activate 
method checks to see the method returns null. This is what I want but it seems 
like it’s demanding that the Enum be non-null. Am I reading this correctly?  
Must CFPs that return enums always return a valid value for the type?

Scott

Reply via email to