JBoss AS 7 application specific properties file - properties

I have several independent Java EE modules (WAR web applications, and JAR EJB modules) which I deploy on JBoss 7.1.1 AS.
I want to:
Centralize configuration of these modules in one *.properties file.
Make this file available in classpath.
Keep the installation/configuration of this file as simple as possible. Ideally would be just to put it in some JBoss folder like: ${JBOSS_HOME}/standalone/configuration.
Make changes to this file available without restarting the application server.
Is this possible?
I already found this link: How to put an external file in the classpath, which explains that preferable way to do this is to make static JBoss module. But, I have to make dependency to this static module in every application module that I deploy, which is a kind of coupling I'm trying to avoid.

Maybe a simple solution is to read the file from a singleton or static class.
private static final String CONFIG_DIR_PROPERTY = "jboss.server.config.dir";
private static final String PROPERTIES_FILE = "application-xxx.properties";
private static final Properties PROPERTIES = new Properties();
static {
String path = System.getProperty(CONFIG_DIR_PROPERTY) + File.separator + PROPERTIES_FILE;
try {
PROPERTIES.load(new FileInputStream(path));
} catch (MalformedURLException e) {
//TODO
} catch (IOException e) {
//TODO
}
}

Here is a full example using just CDI, taken from this site.
This configuration will also work for JBoss AS7.
Create and populate a properties file inside the WildFly configuration folder
$ echo 'docs.dir=/var/documents' >> .standalone/configuration/application.properties
Add a system property to the WildFly configuration file.
$ ./bin/jboss-cli.sh --connect
[standalone#localhost:9990 /] /system-property=application.properties:add(value=${jboss.server.config.dir}/application.properties)
This will add the following to your server configuration file (standalone.xml or domain.xml):
<system-properties>
<property name="application.properties" value="${jboss.server.config.dir}/application.properties"/>
</system-properties>
Create the singleton session bean that loads and stores the application wide properties
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
#Singleton
public class PropertyFileResolver {
private Logger logger = Logger.getLogger(PropertyFileResolver.class);
private String properties = new HashMap<>();
#PostConstruct
private void init() throws IOException {
//matches the property name as defined in the system-properties element in WildFly
String propertyFile = System.getProperty("application.properties");
File file = new File(propertyFile);
Properties properties = new Properties();
try {
properties.load(new FileInputStream(file));
} catch (IOException e) {
logger.error("Unable to load properties file", e);
}
HashMap hashMap = new HashMap<>(properties);
this.properties.putAll(hashMap);
}
public String getProperty(String key) {
return properties.get(key);
}
}
Create the CDI Qualifier. We will use this annotation on the Java variables we wish to inject into.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR })
public #interface ApplicationProperty {
// no default meaning a value is mandatory
#Nonbinding
String name();
}
Create the producer method; this generates the object to be injected
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.inject.Inject;
public class ApplicationPropertyProducer {
#Inject
private PropertyFileResolver fileResolver;
#Produces
#ApplicationProperty(name = "")
public String getPropertyAsString(InjectionPoint injectionPoint) {
String propertyName = injectionPoint.getAnnotated().getAnnotation(ApplicationProperty.class).name();
String value = fileResolver.getProperty(propertyName);
if (value == null || propertyName.trim().length() == 0) {
throw new IllegalArgumentException("No property found with name " + value);
}
return value;
}
#Produces
#ApplicationProperty(name="")
public Integer getPropertyAsInteger(InjectionPoint injectionPoint) {
String value = getPropertyAsString(injectionPoint);
return value == null ? null : Integer.valueOf(value);
}
}
Lastly inject the property into one of your CDI beans
import javax.ejb.Stateless;
import javax.inject.Inject;
#Stateless
public class MySimpleEJB {
#Inject
#ApplicationProperty(name = "docs.dir")
private String myProperty;
public String getProperty() {
return myProperty;
}
}

Related

Using Cucumber with Java, can I use 2 ServiceHooks classes in a project?

I'd like to create a test framework using Cucumber and Java that has both UI and API capabilities.
Can I use a ServiceHooks class with an #Before annotation to run some prerequisites for UI tests and another ServiceHooks class with another #Before annotation to run some prerequisites before the API tests?
If yes, how would I tell cucumber which one to use when a test is run?
This is the TestRunner class:
import cucumber.api.CucumberOptions;
import cucumber.api.SnippetType;
import cucumber.api.testng.CucumberFeatureWrapper;
import cucumber.api.testng.PickleEventWrapper;
import cucumber.api.testng.TestNGCucumberRunner;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
#CucumberOptions(
features = "src/test/resources/features",
glue = {"stepDefs"}, // this is a package in which I have the ServiceHooks class and the StepDefinitions class
snippets = SnippetType.CAMELCASE,
tags = {"not #Ignore"}
,
plugin = {
"pretty",
"html:target/cucumber-reports/cucumber-pretty",
"json:target/cucumber-reports/CucumberTestReport.json",
"rerun:target/cucumber-reports/rerun.txt"
}
)
public class TestRunner {
private TestNGCucumberRunner testNGCucumberRunner;
#BeforeClass(alwaysRun = true)
public void setUpClass() throws Exception {
testNGCucumberRunner = new TestNGCucumberRunner(this.getClass());
}
#Test(groups = "cucumber", description = "Runs Cucumber Feature", dataProvider = "scenarios")
public void scenario(PickleEventWrapper pickleEvent, CucumberFeatureWrapper cucumberFeature) throws Throwable {
testNGCucumberRunner.runScenario(pickleEvent.getPickleEvent());
}
#DataProvider
public Object[][] scenarios() {
return testNGCucumberRunner.provideScenarios();
}
#AfterClass(alwaysRun = true)
public void tearDownClass() throws Exception {
testNGCucumberRunner.finish();
}
}
The service hook class must be in the glue at cucumber options. you have to pass UI or API as argument and set glue class path accordingly. These can be just hard coded runner class ( just like #tag value) or pass it as command line arguments.
public class runner()
{
public static String testPath;
private final string API = "<path to API service hook>";
private final string UI = "<path to UI service hook>";
public static String testPath;
public static void main ( String args[])
{
if(args.length >1)
{
testPath = args[0]
}
else
{
String testPath = API ; //or UI
}
Main.main(new String[]{<Pass cucumber parameters>, "-g" ,testPath});
}
You can do so using tagged hooks and tagging your features or scenarios with the relevant tags, for instance #api and #browser.
From the Cucumber docs on tagged hooks:
"Hooks can be conditionally selected for execution based on the tags of the scenario. To run a particular hook only for certain scenarios, you can associate a Before or After Hook with a tag expression.
nnotated method style:
#After("#browser and not #headless")
public void doSomethingAfter(Scenario scenario){
}
Lambda style:
After("#browser and not #headless", (Scenario scenario) -> {
});
"

Cannot create ExtentReport for Selenium 3.5.1

I have tried with almost all jar files with extentreport from 2.41.2 to
3.13.0 but whenever I try to write the command: extent.loadConfig(new
File(System.getProperty("user.dir")+"//ReportsConfig.xml")); it throws error on multiple lines but for instance i have put up one example
showing as "The method loadConfig(File) is undefined for the type
ExtentReports".
My code for ExtentReport Class is `enter code here`:
package TestNG_package;
import java.io.File;
import java.util.Date;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.reporter.AbstractReporter;
import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
import com.aventstack.extentreports.reporter.configuration.ChartLocation;
import com.aventstack.extentreports.reporter.configuration.Theme;
public class ExtentManager
{
private static ExtentReports extent;
public static String screenshotFolderPath;
static ExtentHtmlReporter htmlReporter;
public static ExtentReports getInstance()
{
if (extent == null)
{
extent = new
ExtentReport("E:\\Selenium\\Workspace\\New_Test\\test-output\\report.html");
extent.loadConfig(new
File(System.getProperty("user.dir")+"//ReportsConfig.xml"));
extent.addSystemInfo("Selenium ver" ,
"3.5.1").addSystemInfo("Environ" , "PROD");
}
return extent;
}
}
My next part of code is to invoke ExtentReport in other class called
loginTest
public class LoginTest()
{
#Test
public void doLogin()
{
ExtentReport rep = ExtentManager.getInstance();
ExtentTest Test = rep.startTest("UATRMS start");
Test.log(LogStatus.Info,"Starting UATRMS Test");
rep.endTest(test);
rep.flush();
}
}
The correct method is
reporter.loadXMLConfig("extent-config.xml");
The method you are using is for instances where you have a properties file. See the docs for more info. This method is used by the reporter, not the core API. Reporters can be configured using these configuration items.

is there any possibility to access ConfigurationAPI inside UserAuthenticationSecurityCheck extended Class

adapter UserAuthenticationSecurityCheck where we have introduced some properties in the adapter.xml file outside the securityCheckDefinition. Which i am able to configure in the Adapter -> Configuration tab in the mfp console.
We are trying to access the configuartion value via ConfigurationAPI with importing
import com.ibm.mfp.adapter.api.ConfigurationAPI inside the UserAuthenticationSecurityCheck extended class.
But we are getting a null pointer exception during this process. I am able to access them inside the java-adapter class via ConfigurationAPI but not inside the security UserAuthenticationSecurityCheck class.
Wanted to access the below image properties inside the UserAuthenticationSecurityCheck extended class.
public class userSecurityCheck extends UserAuthenticationSecurityCheck {
#Context
ConfigurationAPI configurationAPI;
#Override
protected boolean validateCredentials(Map<String, Object> credentials){
String instancename = credentials.get("instancename").toString();
// java null pointer exception is happening at the below line
String httpUrl = configurationAPI.getPropertyValue(instancename);
}
}
There is indeed a way to specify configurable properties on the "Security Check" flavour of adapter, and it is different from the regular type of adapter. It is documented here. I have validated that this approach works. The documentation omits a few key elements, like package names, so below is so very simple example code to demonstrate:
UserAuth.java:
public class UserAuth extends UserAuthenticationSecurityCheck {
#Override
protected boolean validateCredentials(Map<String, Object> credentials) {
String test_property = ((UserAuthSecurityCheckConfig) this.config).test_property;
LOG.warning("auth test_property=" + test_property);
return true;
}
#Override
public SecurityCheckConfiguration createConfiguration(Properties properties) {
return new UserAuthSecurityCheckConfig(properties);
}
}
UserAuthSecurityCheckConfig.java:
import java.util.Properties;
import com.ibm.mfp.security.checks.base.UserAuthenticationSecurityCheckConfig;
public class UserAuthSecurityCheckConfig extends UserAuthenticationSecurityCheckConfig {
public String test_property;
public UserAuthSecurityCheckConfig(Properties properties) {
super(properties);
this.test_property = this.getStringProperty("test_property", properties, "defaultValueInCode");
}
}
adapter.xml:
<securityCheckDefinition name="UserLogin" class="com.xyz.UserAuth">
<property name="test_property" displayName="Test Property Auth" defaultValue="foo_default_in_xml" />
</securityCheckDefinition>

How do I load and store global variables in Jersey/Glassfish

I am creating a RESTful Web Service that wraps an antiquated vendor API. Some external configuration will be required and will be stored on the server either in a file or rdbms. I'm using Jersey 1.11.1 in Glassfish 3.1.2. This configuration data is all in String key/value format.
My first question is this - where can I store global/instance variables in Jersey so that they will be persisted between requests and available to all resources? If this was a pure Servlet application I would use the ServletContext to accomplish this.
The second part to the question is how can I load my configuration once the Jersey server has loaded? Again, my Servlet analogy would be to find the equivalent to the init() method.
#Singleton #Startup EJB matches your requirements.
#Singleton
#Startup // initialize at deployment time instead of first invocation
public class VendorConfiguration {
#PostConstruct
void loadConfiguration() {
// do the startup initialization here
}
#Lock(LockType.READ) // To allow multiple threads to invoke this method
// simultaneusly
public String getValue(String key) {
}
}
#Path('/resource')
#Stateless
public class TheResource {
#EJB
VendorConfiguration configuration;
// ...
}
EDIT: Added annotation as per Graham's comment
You can use a listener for init the variables and set to the context as attribute before the web application start, something like the following:
package org.paulvargas.shared;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class LoadConfigurationListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
// read file or rdbms
...
ServletContext context = sce.getServletContext();
// set attributes
...
}
public void contextDestroyed(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
// remove attributes
...
}
}
This listener is configured in the web.xml.
<listener>
<listener-class>org.paulvargas.shared.LoadConfigurationListener</listener-class>
</listener>
You can use the #Context annotation for inject the ServletContext and retrieving the attribute.
package org.paulvargas.example.helloworld;
import java.util.*;
import javax.servlet.ServletContext;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
#Path("/world")
public class HelloWorld {
#Context
private ServletContext context;
#GET
#Produces("text/plain; charset=UTF-8")
public String getGreeting() {
// get attributes
String someVar = (String) context.getAttribute("someName")
return someVar + " says hello!";
}
}

Arquillian, (embedded) Glassfish & JMS: How to test a worker?

I want to test a JMS-worker included in my glassfish-application using arquillian (to have container-services). My Worker looks the following:
package queue.worker;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.MessageListener;
#MessageDriven(mappedName = "java:app/jms/MailQueue", activationConfig = {
#ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") })
public class MailWorker implements MessageListener {
public MailWorker() {
}
#Override
public void onMessage(javax.jms.Message inMessage) {
}
}
This is the test:
package queueTest.worker;
import java.io.File;
import javax.inject.Inject;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import queue.worker.MailWorker;
#RunWith(Arquillian.class)
public class MailWorkerTest {
#Deployment
public static WebArchive createDeployment() {
WebArchive archive = ShrinkWrap
.create(WebArchive.class)
.addClasses(MailWorker.class)
.addAsWebInfResource(new File("src/test/resources/WEB-INF/glassfish-resources.xml"),
"glassfish-resources.xml")
.addAsWebInfResource(new File("src/main/webapp/WEB-INF/beans.xml"), "beans.xml");
return archive;
}
#Inject
protected MailWorker mailWorker;
#Test
public void sendRegisterMail() {
Assert.assertTrue(true);
}
}
Executing this test, the Glassfish-JSM-Queue is started[1], but I get the following error:
org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [MailWorker] with qualifiers [#Default] at injection point [[field] #Inject protected queueTest.worker.MailWorkerTest.mailWorker]
When I remove "#MessageDrivern[...]" at Mailworker.class and replace it with "#ApplicationScoped", e.g., everything works fine - so there seems to be not a problem with Arquillian in general, but JMS-related.
How can I test the JMS/Queue-Worker?
[1]
Dez 23, 2012 12:42:08 AM com.sun.messaging.jms.ra.ResourceAdapter start
Information: MQJMSRA_RA1101: GlassFish MQ JMS Resource Adapter starting: broker is EMBEDDED, connection mode is Direct
Dez 23, 2012 12:42:10 AM com.sun.messaging.jms.ra.ResourceAdapter start
Information: MQJMSRA_RA1101: GlassFish MQ JMS Resource Adapter Started:EMBEDDED
Testing MDBs is harder than testing usual EJBs and CDI beans as they are executed asynchronously. Even if you were able to inject them into your test, you could just test the onMessage() method by calling it synchronously.
My approach uses the MDB to only catch the message and to extract the underlying presentation (like String or Object). Then pass the extracted message to a separate CDI bean which has a test alternative.
#MessageDriven(mappedName = "jms/queue/example", activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType",
propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination",
propertyValue = "jms/queue/example")
})
public class ExampleMDB implements MessageListener {
#Inject
private ExampleMessageHandler exampleMessageHandler;
#Override
public void onMessage(Message message) {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
try {
exampleMessageHandler.doSomething(textMessage.getText());
} catch (JMSException e) {
throw new RuntimeException("That was unexpected!", e);
}
}
}
}
The ExampleMessageHandler defines doSomething(String text).
For the test scope, we need an implementation that captures the arguments passed to doSomething() and makes them accessible to the test class. You can archieve this with the following implementation:
#Alternative
#ApplicationScoped
public class ExampleMessageHandlerTestable implements ExampleMessageHandler {
private BlockingQueue<String> queue = new LinkedBlockingQueue<String>();
public void doSomething(String text) {
queue.add(text);
}
public String poll(int secondsUntilInterrupt) throws InterruptedException {
return queue.poll(secondsUntilInterrupt, TimeUnit.SECONDS);
}
}
This is a CDI alternative to the real implementation used by the production code. Now just let the Arquillian test use this alternative. Here's the test class:
#RunWith(Arquillian.class)
public class ExampleMDBGoodTest {
#Resource(mappedName = "ConnectionFactory", name = "ConnectionFactory")
private ConnectionFactory connectionFactory;
#Resource(mappedName = "jms/queue/example", name = "jms/queue/example")
private Queue queue;
#Inject
private ExampleMessageHandler exampleMessageHandler;
#Deployment
public static WebArchive createDeployment() {
WebArchive archive = ShrinkWrap.create(WebArchive.class, "exampleMDB.war")
.addPackages(true, ExampleMDB.class.getPackage())
.addAsWebInfResource("hornetq-jms.xml", "hornetq-jms.xml")
.addAsWebInfResource("beans-alternative.xml", "beans.xml");
System.out.println(archive.toString(true));
return archive;
}
#Test
public void testOnMessage() throws Exception {
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(queue);
TextMessage textMessage = session.createTextMessage("Hello world!");
producer.send(textMessage);
session.close();
connection.close();
// We cast to our configured handler defined in beans.xml
ExampleMessageHandlerTestable testHandler =
(ExampleMessageHandlerTestable) exampleMessageHandler;
assertThat(testHandler.poll(10), is("Hello world!"));
}
}
Some explanations what's going on here: The test requests a JMS ConnectionFactory and the Queue on which the MDB listens. These create the JMS messages used by the MDB under test. Then we create a test deployment. The hornetq-jms.xml defines an adhoc queue for the test. By including beans-alternative.xml, we ensure that our test alternative is used by the MDB.
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<alternatives>
<class>com.github.mcs.arquillian.mdb.example.ExampleMessageHandlerTestable</class>
</alternatives>
</beans>
The test case itself should be straight forward. A new JMS message is sent to the queue. Then we wait up to 10 seconds for a new message within our test alternative. By using a blocking queue, we can define a timeout after which the test fails. But the test itself finishes immediately as soon as the MDB calls the alternative bean.
I have uploaded a small Maven example project from where I copied the above code parts. Because I don't know much about Glassfish, it uses JBoss as managed container. Depending on the JBoss version you might use, you need to change the version of jboss-as-arquillian-container-managed.
Hope that helps someone :-)
MDBs are not eligible for injection in to other classes. You cannot inject them in to your test case.