Skip to content

Commit

Permalink
add autoconfig support
Browse files Browse the repository at this point in the history
  • Loading branch information
ar committed Nov 23, 2021
1 parent f823d66 commit c4afdf2
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 27 deletions.
23 changes: 23 additions & 0 deletions doc/src/asciidoc/ch03/configuration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,26 @@ deployments, HSM based EnvironmentProvider should be used instead.
The `obf` CLI command can be used to create these obfuscated entries.
=====

Since version 2.1.7, jPOS supports the `@Config` annotation that pushes configuration properties (String, int, Integer, long, Long) down to classes
instanciated through QFactory (Qbeans, Transaction Participants, etc.), i.e:

[source,java]
-------------
public class MyClass {
@Config("port") int port;
}
-------------

The 'port' variable would be picked from:


[source,xml]
------------
...
<property name="port" value="1234" />
...
------------

from the QBean or participant configuration.

27 changes: 27 additions & 0 deletions jpos/src/main/java/org/jpos/core/annotation/Config.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* jPOS Project [http://jpos.org]
* Copyright (C) 2000-2021 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jpos.core.annotation;

import java.lang.annotation.*;


@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Config {
String value();
}
36 changes: 31 additions & 5 deletions jpos/src/main/java/org/jpos/q2/QFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@

import org.jdom2.Element;
import org.jpos.core.*;
import org.jpos.core.annotation.Config;
import org.jpos.q2.qbean.QConfig;
import org.jpos.util.LogSource;
import org.jpos.util.Logger;
import org.jpos.util.NameRegistrar;

import javax.management.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
Expand Down Expand Up @@ -111,7 +113,7 @@ public ObjectInstance createQBean (Q2 server, Element e, Object obj)
configureQBean(mserver,objectName,e);
setConfiguration (obj, e); // handle legacy (QSP v1) Configurables

if (obj instanceof QBean)
if (obj instanceof QBean)
mserver.invoke (objectName, "init", null, null);
}
catch (Throwable t) {
Expand Down Expand Up @@ -164,7 +166,7 @@ objectName, new Attribute (attribute, value)
// okay to fail (produced by some application servers instead of AttributeNotFoundException)
}
}

public void startQBean (Q2 server, ObjectName objectName)
throws InstanceNotFoundException,
MBeanException,
Expand Down Expand Up @@ -365,15 +367,18 @@ public static String getAttributeValue (Element e, String name) {
String s = e.getAttributeValue(name);
return Environment.getEnvironment().getProperty(s, s);
}
public void setConfiguration (Object obj, Element e)
public void setConfiguration (Object obj, Element e)
throws ConfigurationException
{
try {
Configuration cfg = getConfiguration (e);
autoconfigure(obj, cfg);

if (obj instanceof Configurable)
((Configurable)obj).setConfiguration (getConfiguration (e));
((Configurable)obj).setConfiguration (cfg);
if (obj instanceof XmlConfigurable)
((XmlConfigurable)obj).setConfiguration(e);
} catch (ConfigurationException ex) {
} catch (ConfigurationException | IllegalAccessException ex) {
throw new ConfigurationException (ex);
}
}
Expand Down Expand Up @@ -436,4 +441,25 @@ public static boolean isEnabled (Element e) {
public static String getEnabledAttribute (Element e) {
return Environment.get(e.getAttributeValue("enabled", "true"));
}

public static void autoconfigure (Object obj, Configuration cfg) throws IllegalAccessException {
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Config.class)) {
Config config = field.getAnnotation(Config.class);
String v = cfg.get(config.value(), null);
if (v != null) {
if (!field.isAccessible())
field.setAccessible(true);
Class<?> c = field.getType();
if (c.isAssignableFrom(String.class))
field.set(obj, v);
else if (c.isAssignableFrom(int.class) || c.isAssignableFrom(Integer.class))
field.set(obj, cfg.getInt(config.value()));
else if (c.isAssignableFrom(long.class) || c.isAssignableFrom(Long.class))
field.set(obj, cfg.getLong(config.value()));
}
}
}
}
}
7 changes: 6 additions & 1 deletion jpos/src/main/java/org/jpos/q2/qbean/SystemMonitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.jpos.core.Configuration;
import org.jpos.core.ConfigurationException;
import org.jpos.core.Environment;
import org.jpos.core.annotation.Config;
import org.jpos.iso.ISOUtil;
import org.jpos.q2.Q2;
import org.jpos.q2.QBeanSupport;
Expand Down Expand Up @@ -65,6 +66,9 @@ public class SystemMonitor extends QBeanSupport
private String localHost;
private String processName;

@Config("metrics-dir")
private String metricsDir;

public void startService() {
try {
log.info("Starting SystemMonitor");
Expand Down Expand Up @@ -221,6 +225,7 @@ private String generateFrozenDump(String indent) {
zi.getDisplayName(TextStyle.FULL, Locale.getDefault()),
zi.getRules().getOffset(instant).toString());
p.printf("%swatch service: %s%n", indent, getServer().getWatchServiceClassname());
p.printf("%s metrics dir: %s%n", indent, metricsDir);
List<ZoneOffsetTransitionRule> l = zi.getRules().getTransitionRules();
for (ZoneOffsetTransitionRule tr : l) {
p.printf("%s rule: %s%n", indent, tr.toString());
Expand Down Expand Up @@ -270,7 +275,7 @@ private double loadAverage () {
}

private void dumpMetrics() {
if (cfg.get("metrics-dir", null) != null) {
if (metricsDir != null) {
File dir = new File(cfg.get("metrics-dir"));
dir.mkdir();
NameRegistrar.getAsMap().forEach((key, value) -> {
Expand Down
78 changes: 78 additions & 0 deletions jpos/src/test/java/org/jpos/core/ConfigAnnotationTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* jPOS Project [http://jpos.org]
* Copyright (C) 2000-2021 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.jpos.core;

import org.jpos.core.annotation.Config;
import org.jpos.q2.Q2;
import org.jpos.q2.QFactory;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Field;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class ConfigAnnotationTest {
@Test
public void testConfig() throws ConfigurationException, IllegalAccessException {
MyAutoConfigurable bean = new MyAutoConfigurable();
Configuration cfg = new SimpleConfiguration();
cfg.put("mystring", "My String");
cfg.put("mylong", "10000");
cfg.put("myint", "1000");
QFactory.autoconfigure(bean, cfg);
assertEquals("My String", bean.getMystring());
assertEquals(1000, bean.getMyint());
assertEquals(10000L, bean.getMylong());
}

public static class MyAutoConfigurable {
@Config("mystring")
private String mystring;

@Config("myint")
private int myint;

@Config("mylong")
private Long mylong;


public String getMystring() {
return mystring;
}

public int getMyint() {
return myint;
}

public Long getMylong() {
return mylong;
}


@Override
public String toString() {
return "MyAutoConfigurable{" +
"mystring='" + mystring + '\'' +
", myint=" + myint +
", mylong=" + mylong +
'}';
}
}

}
22 changes: 1 addition & 21 deletions jpos/src/test/java/org/jpos/q2/QFactory2Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -261,27 +261,7 @@ public void testSetConfiguration3() throws Throwable {
assertEquals("testQFactoryName", e.getName(), "e.getName()");
q2.stop();
}

@Test
public void testSetConfigurationThrowsConfigurationException() throws Throwable {
String[] args = new String[0];
Q2 q2 = new Q2(args);
try {
new QFactory(null, q2).setConfiguration(new BSHTransactionParticipant(), null);
fail("Expected ConfigurationException to be thrown");
} catch (ConfigurationException ex) {
if (isJavaVersionAtMost(JAVA_14)) {
assertEquals("org.jpos.core.ConfigurationException (java.lang.NullPointerException)", ex.getMessage(), "ex.getMessage()");
assertNull(ex.getNested().getMessage(), "ex.getNested().getMessage()");
} else {
assertEquals("org.jpos.core.ConfigurationException: Cannot invoke \"org.jdom2.Element.getChild(String)\" because \"e\" is null (java.lang.NullPointerException: Cannot invoke \"org.jdom2.Element.getChild(String)\" because \"e\" is null)", ex.getMessage(), "ex.getMessage()");
assertEquals("Cannot invoke \"org.jdom2.Element.getChild(String)\" because \"e\" is null", ex.getNested().getMessage(), "ex.getNested().getMessage()");
}
} finally {
q2.stop();
}
}


@Test
public void testSetConfigurationThrowsNullPointerException() throws Throwable {
String[] args = new String[0];
Expand Down

0 comments on commit c4afdf2

Please sign in to comment.