Skip to content
This repository has been archived by the owner on May 26, 2020. It is now read-only.

Commit

Permalink
Add configuration from framework
Browse files Browse the repository at this point in the history
  • Loading branch information
mapingo committed Mar 15, 2017
1 parent 742c88f commit 9cada71
Show file tree
Hide file tree
Showing 14 changed files with 487 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ on [Keep a CHANGELOG](http://keepachangelog.com/). This project adheres to

## [Unreleased]

### Added
- configuration GlobalValue and Value annotation implementations from framework

## [1.5.0] - 2017-03-14

### Added
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package uk.gov.justice.services.common.configuration;

import static java.lang.String.format;
import static uk.gov.justice.services.common.configuration.CommonValueAnnotationDef.NULL_DEFAULT;

import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;

abstract class AbstractValueProducer {

private static final String GLOBAL_JNDI_NAME_PATTERN = "java:global/%s";

InitialContext initialContext;

protected AbstractValueProducer() throws NamingException {
initialContext = new InitialContext();
}

protected String jndiValueFor(final CommonValueAnnotationDef annotation) throws NamingException {
for (String jndiName : jndiNamesFrom(annotation)) {
try {
return (String) initialContext.lookup(jndiName);
} catch (NameNotFoundException e) {
//do nothing
}
}
if (NULL_DEFAULT.equals(annotation.defaultValue())) {
throw new MissingPropertyException(format("Missing property: %s", annotation.key()));
}
return annotation.defaultValue();

}

protected String globalJNDINameFrom(final CommonValueAnnotationDef annotation) {
return format(GLOBAL_JNDI_NAME_PATTERN, annotation.key());
}

/**
* The method is used to specify JNDI names to resolve. If resolution of a name fails
* then the next name in order is picked for resolution
*
* @return jndi name(s) to resolve (in order of priority).
*/
protected abstract String[] jndiNamesFrom(CommonValueAnnotationDef annotation);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package uk.gov.justice.services.common.configuration;

import javax.enterprise.inject.spi.InjectionPoint;

class CommonValueAnnotationDef {

static final String NULL_DEFAULT = "_null_default";

private String key;
private String defaultValue;

private CommonValueAnnotationDef(final String key, final String defaultValue) {
this.key = key;
this.defaultValue = defaultValue;
}

static CommonValueAnnotationDef localValueAnnotationOf(final InjectionPoint ip) {
final Value annotation = ip.getAnnotated().getAnnotation(Value.class);
return new CommonValueAnnotationDef(annotation.key(), annotation.defaultValue());
}

static CommonValueAnnotationDef globalValueAnnotationOf(final InjectionPoint ip) {
final GlobalValue annotation = ip.getAnnotated().getAnnotation(GlobalValue.class);
return new CommonValueAnnotationDef(annotation.key(), annotation.defaultValue());
}

String key() {
return key;
}

String defaultValue() {
return defaultValue;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package uk.gov.justice.services.common.configuration;

import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static uk.gov.justice.services.common.configuration.CommonValueAnnotationDef.NULL_DEFAULT;

import java.lang.annotation.Retention;

import javax.enterprise.util.Nonbinding;
import javax.inject.Qualifier;

@Qualifier
@Retention(RUNTIME)
public @interface GlobalValue {

/**
* Bundle key
*
* @return a valid key
*/
@Nonbinding String key() default "";

/**
* Default value if not provided
*
* @return default value or ""
*/
@Nonbinding String defaultValue() default NULL_DEFAULT;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package uk.gov.justice.services.common.configuration;

import static uk.gov.justice.services.common.configuration.CommonValueAnnotationDef.globalValueAnnotationOf;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.naming.NamingException;

/**
* Looks up global jndi names in order to inject their values into @GlobalValue annotated
* properties.
*/
@ApplicationScoped
public class GlobalValueProducer extends AbstractValueProducer {

public GlobalValueProducer() throws NamingException {
super();
}

@GlobalValue
@Produces
public String stringValueOf(final InjectionPoint ip) throws NamingException {
return jndiValueFor(globalValueAnnotationOf(ip));
}

@GlobalValue
@Produces
public long longValueOf(final InjectionPoint ip) throws NamingException {
return Long.valueOf(stringValueOf(ip));
}

@Override
protected String[] jndiNamesFrom(final CommonValueAnnotationDef annotation) {
return new String[]{globalJNDINameFrom(annotation)};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package uk.gov.justice.services.common.configuration;

import javax.annotation.Resource;
import javax.enterprise.context.ApplicationScoped;

import com.google.common.annotations.VisibleForTesting;

@ApplicationScoped
public class JndiBasedServiceContextNameProvider implements ServiceContextNameProvider {

@Resource(lookup = "java:app/AppName")
String appName;

public JndiBasedServiceContextNameProvider() {
}

@VisibleForTesting
public JndiBasedServiceContextNameProvider(final String appName) {
this.appName = appName;
}

@Override
public String getServiceContextName() {
return appName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package uk.gov.justice.services.common.configuration;

public class MissingPropertyException extends RuntimeException {

private static final long serialVersionUID = -2539036250375591049L;

public MissingPropertyException(final String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package uk.gov.justice.services.common.configuration;

public interface ServiceContextNameProvider {

String getServiceContextName();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package uk.gov.justice.services.common.configuration;

import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static uk.gov.justice.services.common.configuration.CommonValueAnnotationDef.NULL_DEFAULT;

import java.lang.annotation.Retention;

import javax.enterprise.util.Nonbinding;
import javax.inject.Qualifier;

@Qualifier
@Retention(RUNTIME)
public @interface Value {

/**
* Bundle key
*
* @return a valid key
*/
@Nonbinding String key() default "";

/**
* Default value if not provided
*
* @return default value or ""
*/
@Nonbinding String defaultValue() default NULL_DEFAULT;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package uk.gov.justice.services.common.configuration;

import static java.lang.String.format;
import static uk.gov.justice.services.common.configuration.CommonValueAnnotationDef.localValueAnnotationOf;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.inject.Inject;
import javax.naming.NamingException;

/**
* Looks up context specific jndi names in order to inject their values into @Value annotated
* properties.
*/
@ApplicationScoped
public class ValueProducer extends AbstractValueProducer {

private static final String LOCAL_JNDI_NAME_PATTERN = "java:/app/%s/%s";

@Inject
ServiceContextNameProvider serviceContextNameProvider;

public ValueProducer() throws NamingException {
super();
}

@Value
@Produces
public String stringValueOf(final InjectionPoint ip) throws NamingException {
return jndiValueFor(localValueAnnotationOf(ip));
}

@Value
@Produces
public long longValueOf(final InjectionPoint ip) throws NamingException {
return Long.valueOf(stringValueOf(ip));
}

@Override
protected String[] jndiNamesFrom(final CommonValueAnnotationDef annotation) {
return new String[]{localJNDINameFrom(annotation), globalJNDINameFrom(annotation)};
}

private String localJNDINameFrom(final CommonValueAnnotationDef annotation) {
return format(LOCAL_JNDI_NAME_PATTERN, serviceContextNameProvider.getServiceContextName(), annotation.key());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package uk.gov.justice.services.common.configuration;

import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.when;

import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class GlobalValueProducerTest {

@InjectMocks
private GlobalValueProducer valueProducer;

@Mock
private InjectionPoint propertyInjectionPoint;

@Mock
private Annotated annotated;

@Mock
private GlobalValue annotation;

@Mock
private InitialContext initialContext;

@Before
public void setup() throws NamingException {
when(propertyInjectionPoint.getAnnotated()).thenReturn(annotated);
when(annotated.getAnnotation(GlobalValue.class)).thenReturn(annotation);
}

@Test
public void shouldReturnStringPropertyValue() throws NamingException {
when(initialContext.lookup("java:global/myProperty")).thenReturn("some value");
when(annotation.key()).thenReturn("myProperty");

assertThat(valueProducer.stringValueOf(propertyInjectionPoint), equalTo("some value"));
}

@Test
public void shouldReturnLongPropertyValue() throws NamingException {
when(initialContext.lookup("java:global/myLongProperty")).thenReturn("100");
when(annotation.key()).thenReturn("myLongProperty");
assertThat(valueProducer.longValueOf(propertyInjectionPoint), equalTo(100L));
}

@Test
@SuppressWarnings("unchecked")
public void shouldReturnDefaultValueWhenNotFound() throws NamingException {
when(initialContext.lookup("java:global/myOtherProperty")).thenThrow(NameNotFoundException.class);
when(annotation.key()).thenReturn("myOtherProperty");
when(annotation.defaultValue()).thenReturn("some default value");

assertThat(valueProducer.stringValueOf(propertyInjectionPoint), equalTo("some default value"));
}

@Test(expected = MissingPropertyException.class)
@SuppressWarnings("unchecked")
public void shouldThrowExceptionWhenNotFoundAndNoDefaultValue() throws NamingException {
when(initialContext.lookup("java:global/unknownProperty")).thenThrow(NameNotFoundException.class);
when(annotation.key()).thenReturn("unknownProperty");

when(annotation.defaultValue()).thenReturn(CommonValueAnnotationDef.NULL_DEFAULT);

valueProducer.stringValueOf(propertyInjectionPoint);
}
}
Loading

0 comments on commit 9cada71

Please sign in to comment.