How to load a configuration file at startup within tomcat - configuration

I want to be able to load my configuration for the webapp at startup of tomcat (apache commons configuration library) is this a possible way:
public class MyAppCfg implements javax.servlet.ServletContextListener {
private ServletContext context = null;
#Override
public void contextInitialized(ServletContextEvent event) {
try{
this.context = event.getServletContext();
XMLConfiguration config = new XMLConfiguration("cfg.xml");
config.setReloadingStrategy(new FileChangedReloadingStrategy());
this.context.setAttribute("mycfg", config);
}
catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void contextDestroyed(ServletContextEvent arg0) {
this.context = null;
}
}
web.xml
<listener>
<listener-class>mypackage.MyAppCfg</listener-class>
</listener>
and later acces them in the webapp via
this.cfg = (XMLConfiguration) servletRequest.getAttribute("mycfg");

No. You wouldn't be able to get the configuration this way. You are setting it in servlet context but retrieving it in request context.
You need to retrieve the cfg in your Servlet init like this,
public void init(final ServletConfig config) {
// log it to the ServletContext
ServletContext context = config.getServletContext();
this.cfg = (Configuration)context.getAttribute("mycfg");
}

Related

How Do I Verify and Capture the Contents of an InputStream in JUnit Mockito?

I have the following setup:
public interface CommandRunner
{
void run(String cmd, InputStream is) throws IOException;
}
public class CommandRunnerInputFile
{
private final CommandRunner commandRunner;
public CommandRunnerInputFile(CommandRunner commandRunner) {
this.commandRunner = commandRunner;
}
public void run(String command, File inputFile) throws IOException {
try (FileInputStream is = new FileInputStream(inputFile)) {
this.commandRunner.run(command, is);
}
}
}
#ExtendWith(MockitoExtension.class)
public class TestCommandRunnerInputFile
{
#Mock CommandRunner commandRunner;
#Captor ArgumentCaptor<InputStream> inputStream;
private CommandRunnerInputFile commandRunnerInputFile;
#BeforeEach
void initService() {
commandRunnerInputFile = new CommandRunnerInputFile(commandRunner);
}
#Test
public void testHappyPath() throws IOException {
ClassLoader classLoader = this.getClass().getClassLoader();
File file = new File(classLoader.getResource("MyTestInputFile.txt").getFile());
commandRunnerInputFile .run("MyApplication.exe", file);
verify(commandRunner).run(eq("MyApplication.exe"), inputStream.capture());
assertEquals('c', (char)inputStream.getValue().read());
}
}
When I run this test, it fails with the following Exception:
java.io.IOException: Stream Closed
at java.io.FileInputStream.read0(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:207)
This make sense to me since, during the execution of the method, the underlying FileInputStream is closed when it has completed execution. That is to say, at the point in time that the FileInputStream is captured by Mockito, it is open, but by the time I verify that it was passed (and attempt to verify its contents) it is closed. What can I do not to simply capture the InputStream object itself, but actually capture its contents for verification?

How to connect to multiple MySQL databases as per the header in REST API request

I'm creating a multi tenant spring boot - JPA application.
In this application, I want to connect to MySQL Databases using DB name which is sent through API request as header.
I checked many multi tenant project samples online but still can't figure out a solution.
Can anyone suggest me a way to do this?
You can use AbstractRoutingDataSource to achieve this. AbstractRoutingDataSource requires information to know which actual DataSource to route to(referred to as Context), which is provided by determineCurrentLookupKey() method. Using example from here.
Define Context like:
public enum ClientDatabase {
CLIENT_A, CLIENT_B
}
Then you need to define Context Holder which will be used in determineCurrentLookupKey()
public class ClientDatabaseContextHolder {
private static ThreadLocal<ClientDatabase> CONTEXT = new ThreadLocal<>();
public static void set(ClientDatabase clientDatabase) {
Assert.notNull(clientDatabase, "clientDatabase cannot be null");
CONTEXT.set(clientDatabase);
}
public static ClientDatabase getClientDatabase() {
return CONTEXT.get();
}
public static void clear() {
CONTEXT.remove();
}
}
Then you can extend AbstractRoutingDataSource like below:
public class ClientDataSourceRouter extends AbstractRoutingDataSource {
#Override
protected Object determineCurrentLookupKey() {
return ClientDatabaseContextHolder.getClientDatabase();
}
}
Finally, DataSource bean configuration:
#Bean
public DataSource clientDatasource() {
Map<Object, Object> targetDataSources = new HashMap<>();
DataSource clientADatasource = clientADatasource();
DataSource clientBDatasource = clientBDatasource();
targetDataSources.put(ClientDatabase.CLIENT_A,
clientADatasource);
targetDataSources.put(ClientDatabase.CLIENT_B,
clientBDatasource);
ClientDataSourceRouter clientRoutingDatasource
= new ClientDataSourceRouter();
clientRoutingDatasource.setTargetDataSources(targetDataSources);
clientRoutingDatasource.setDefaultTargetDataSource(clientADatasource);
return clientRoutingDatasource;
}
https://github.com/wmeints/spring-multi-tenant-demo
Following this logic, I can solve it now. Some of the versions need to be upgraded and the codes as well.
Spring Boot version have changed.
org.springframework.boot
spring-boot-starter-parent
2.1.0.RELEASE
Mysql version has been removed.
And some small changed in MultitenantConfiguration.java
#Configuration
public class MultitenantConfiguration {
#Autowired
private DataSourceProperties properties;
/**
* Defines the data source for the application
* #return
*/
#Bean
#ConfigurationProperties(
prefix = "spring.datasource"
)
public DataSource dataSource() {
File[] files = Paths.get("tenants").toFile().listFiles();
Map<Object,Object> resolvedDataSources = new HashMap<>();
if(files != null) {
for (File propertyFile : files) {
Properties tenantProperties = new Properties();
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(this.getClass().getClassLoader());
try {
tenantProperties.load(new FileInputStream(propertyFile));
String tenantId = tenantProperties.getProperty("name");
dataSourceBuilder.driverClassName(properties.getDriverClassName())
.url(tenantProperties.getProperty("datasource.url"))
.username(tenantProperties.getProperty("datasource.username"))
.password(tenantProperties.getProperty("datasource.password"));
if (properties.getType() != null) {
dataSourceBuilder.type(properties.getType());
}
resolvedDataSources.put(tenantId, dataSourceBuilder.build());
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
// Create the final multi-tenant source.
// It needs a default database to connect to.
// Make sure that the default database is actually an empty tenant database.
// Don't use that for a regular tenant if you want things to be safe!
MultitenantDataSource dataSource = new MultitenantDataSource();
dataSource.setDefaultTargetDataSource(defaultDataSource());
dataSource.setTargetDataSources(resolvedDataSources);
// Call this to finalize the initialization of the data source.
dataSource.afterPropertiesSet();
return dataSource;
}
/**
* Creates the default data source for the application
* #return
*/
private DataSource defaultDataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(this.getClass().getClassLoader())
.driverClassName(properties.getDriverClassName())
.url(properties.getUrl())
.username(properties.getUsername())
.password(properties.getPassword());
if(properties.getType() != null) {
dataSourceBuilder.type(properties.getType());
}
return dataSourceBuilder.build();
}
}
This change is here due to the DataSourceBuilder has been moved to another path and its constructor has been changed.
Also changed the MySQL driver class name in application.properties like this
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

How to correctly load Firebase ServiceAccount json resource with Spring MVC?

I'm trying to connect my Spring MVC (not Spring Boot) application to Firebase. My application's folder structure looks like this:
folder structure
The problem is that I don't know where to place the api key json file, how to load the resource, and the correct order of the method calls.
I tried loading the resource the way shown below. Before that I also tried using ClassLoader to load it from the WEB-INF folder and it worked, but changed the code and kept receiving NullPointer Exception (why not FileNotFound Exception?) for the InputStream and couldn't restore the previous state.
With the current state I keep receiving FileNotFound Exception as I'm am not able to load the resource no matter how much I googled "Spring MVC load resource" and as I checked the debugger the service account's "init" method with #PostConstruct isn't running at starting the server.
I understand that I should be able to load the resource and call the "init" method in order to make it work. (I suppose it's enough to call it once after creating the bean and before using firebase methods) But I just couldn't come up with a working implementation.
I used examples from here:
https://github.com/savicprvoslav/Spring-Boot-starter
(Bottom of the Page)
My Controller Class:
#Controller
#RequestMapping("/firebase")
public class FirebaseController {
#Autowired
private FirebaseService firebaseService;
#GetMapping(value="/upload/maincategories")
public void uploadMainRecordCategories() {
firebaseService.uploadMainRecordCategories();
}
My Service Class:
#Service
public class FirebaseServiceBean implements FirebaseService {
#Value("/api.json")
Resource apiKey;
#Override
public void uploadMainRecordCategories() {
// do something
}
#PostConstruct
public void init() {
try (InputStream serviceAccount = apiKey.getInputStream()) {
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl(FirebaseStringValue.DB_URL).build();
FirebaseApp.initializeApp(options);
} catch (IOException e) {
e.printStackTrace();
}
}
}
how about saving value in a spring property and using #Value("${firebase.apiKey}")?
Alternatively, save path to file in property and reference that in #Value()
#Value("${service.account.path}")
private String serviceAccountPath;
In application.properties:
service.account.path = /path/to/service-account.json
then config code:
private String getAccessToken() throws IOException {
GoogleCredential googleCredential = GoogleCredential
.fromStream(getServiceAccountInputStream())
.createScoped(Collections.singletonList("https://www.googleapis.com/auth/firebase.messaging"));
googleCredential.refreshToken();
return googleCredential.getAccessToken();
}
private InputStream getServiceAccountInputStream() {
File file = new File(serviceAccountPath);
try {
return new FileInputStream(file);
} catch (FileNotFoundException e) {
throw new RuntimeException("Couldn't find service-account.json");
}
}

Castle Windsor Singleton Instantiated On Each Call To Resolve

I'm using Castle Windsor 2.5.3 in an ASP.NET 4.0 Web Application (not ASP.NET MVC)
I have an interceptor which is being used to intercept calls to a data access component. The interceptor depends on a cache manager. The cache manager is used by the interceptor to avoid calling the data access component if the cache manager has the required data.
Even though the cache manager is registered as a Singleton, it is being instantiated multiple times. I can prove this with a debug message or a hit-count breakpoint in its default constructor.
A new requirement is for the cache to be clearable on demand, so I thought it would be a simple matter of resolving the Cache Manager and calling EmptyCache. What is happening is that the container is creating a new instance of the Cache Manager on which the call to EmptyCache has no effect (since the new cache manager has no cached data). Here is the code in the web page for clearing the cache:
protected void flushButton_Click(object sender, EventArgs e)
{
ICacheManager cacheManager = null;
try
{
cacheManager = Global.Container.Resolve<ICacheManager>();
cacheManager.EmptyCache();
resultLabel.Text = "Cache has been flushed";
}
catch (Exception ex)
{
resultLabel.Text = "An error occurred. The reason given was: " + ex.Message;
}
finally
{
if (cacheManager != null)
Global.Container.Release(cacheManager);
}
}
When I hover over the Container in Visual Studio and drill into the Components, the CacheManager is marked as Singleton. How can this be happening?
My Cache Manager is registered like this:
public class WindsorComponentInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For(typeof(Data.Common.Cache.ICacheManager))
.ImplementedBy(typeof(Data.Common.Cache.CacheManager))
.LifeStyle.Singleton
);
container.Register(
Component.For<Data.Common.CachingInterceptor>()
);
}
}
The Cache Manager interface looks like this:
public interface ICacheManager
{
object CacheItem(string cacheKey, DateTime absoluteExpiration, CacheItemPriority priority, Func<object> itemProvider);
object CacheItem(string cacheKey, TimeSpan slidingExpiration, CacheItemPriority priority, Func<object> itemProvider);
void EmptyCache();
}
The interceptor looks like this:
public class CachingInterceptor : IInterceptor
{
private ILogger logger = NullLogger.Instance;
private ICacheManager cacheManager;
public CachingInterceptor(ICacheManager cacheManager)
{
this.cacheManager = cacheManager;
}
public ILogger Logger
{
set
{
if (value != null) logger = value;
}
}
public void Intercept(IInvocation invocation)
{
try
{
string cacheItemKey = MakeCacheItemKey(invocation);
//Debug.WriteLine("Cache Key: {0}", cacheItemKey);
TimeSpan lifespan = TimeSpan.Parse("00:20:00");
bool cacheHit = true;
object result = cacheManager.CacheItem(cacheItemKey, lifespan, CacheItemPriority.Low,
() =>
{
invocation.Proceed();
//Debug.WriteLine(String.Format("populate-the-cache callback was invoked and returned a {0}", invocation.ReturnValue ?? "null"));
cacheHit = false;
return invocation.ReturnValue;
}
);
logger.DebugFormat("Interceptor {0} Cache Hit: {1}", (invocation.Method.Name ?? "null"), cacheHit.ToString());
invocation.ReturnValue = result;
}
catch (Exception ex)
{
logger.Error("Intercept Error", ex);
}
}
private string MakeCacheItemKey(IInvocation invocation)
{
StringBuilder sb = new StringBuilder();
sb.Append(invocation.InvocationTarget);
sb.Append("|" + invocation.MethodInvocationTarget.Name);
sb.Append("|" + invocation.MethodInvocationTarget.ReturnType);
foreach (ParameterInfo pi in invocation.MethodInvocationTarget.GetParameters())
sb.Append("|" + pi.ParameterType.ToString());
foreach (var arg in invocation.Arguments)
{
sb.Append("|");
sb.Append(arg ?? "null");
}
return sb.ToString();
}
}
The data components are registered like this:
public void Install(IWindsorContainer container, IConfigurationStore store)
{
string connStr = ConfigurationManager.ConnectionStrings["Database"].ConnectionString;
container.Register(
Component.For<IActualCostsVersusBudgetDataProvider>()
.ImplementedBy<ActualCostsVersusBudgetDataProvider>()
.DependsOn(Property.ForKey("connectionString").Eq(connStr))
.LifeStyle.Transient
.Interceptors(InterceptorReference.ForType<CachingInterceptor>())
.Anywhere
);
/* Many calls to .Register omitted */
}
The business objects that depend on data providers are registered like this:
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
AllTypes.FromThisAssembly()
.Where(t => t.Name.EndsWith("Manager"))
.Configure(c => c.LifeStyle.Transient)
);
}
The container is initialized like this in global.asax:
public static IWindsorContainer Container { get; private set; }
public Global()
{
Container = BootstrapContainer();
}
private IWindsorContainer BootstrapContainer()
{
WindsorContainer container = new WindsorContainer();
container.AddFacility<LoggingFacility>(f => f.LogUsing(LoggerImplementation.Log4net).WithAppConfig());
container.Install(
new Data.Common.Installers.WindsorComponentInstaller(),
new Data.Installers.WindsorComponentInstaller(),
new Business.Installers.WindsorComponentInstaller()
);
return container;
}

Ehcache hangs in test

I am in the process of rewriting a bottle neck in the code of the project I am on, and in doing so I am creating a top level item that contains a self populating Ehcache. I am attempting to write a test to make sure that the basic call chain is established, but when the test executes it hands when retrieving the item from the cache.
Here are the Setup and the test, for reference mocking is being done with Mockito:
#Before
public void SetUp()
{
testCache = new Cache(getTestCacheConfiguration());
recordingFactory = new EntryCreationRecordingCache();
service = new Service<Request, Response>(testCache, recordingFactory);
}
#Test
public void retrievesResultsFromSuppliedCache()
{
ResultType resultType = mock(ResultType.class);
Response expectedResponse = mock(Response.class);
addToExpectedResults(resultType, expectedResponse);
Request request = mock(Request.class);
when(request.getResultType()).thenReturn(resultType);
assertThat(service.getResponse(request), sameInstance(expectedResponse));
assertTrue(recordingFactory.requestList.contains(request));
}
private void addToExpectedResults(ResultType resultType,
Response response) {
recordingFactory.responseMap.put(resultType, response);
}
private CacheConfiguration getTestCacheConfiguration() {
CacheConfiguration cacheConfiguration = new CacheConfiguration("TEST_CACHE", 10);
cacheConfiguration.setLoggingEnabled(false);
return cacheConfiguration;
}
private class EntryCreationRecordingCache extends ResponseFactory{
public final Map<ResultType, Response> responseMap = new ConcurrentHashMap<ResultType, Response>();
public final List<Request> requestList = new ArrayList<Request>();
#Override
protected Map<ResultType, Response> generateResponse(Request request) {
requestList.add(request);
return responseMap;
}
}
Here is the ServiceClass
public class Service<K extends Request, V extends Response> {
private Ehcache cache;
public Service(Ehcache cache, ResponseFactory factory) {
this.cache = new SelfPopulatingCache(cache, factory);
}
#SuppressWarnings("unchecked")
public V getResponse(K request)
{
ResultType resultType = request.getResultType();
Element cacheEntry = cache.get(request);
V response = null;
if(cacheEntry != null){
Map<ResultType, Response> resultTypeMap = (Map<ResultType, Response>) cacheEntry.getValue();
try{
response = (V) resultTypeMap.get(resultType);
}catch(NullPointerException e){
throw new RuntimeException("Result type not found for Result Type: " + resultType);
}catch(ClassCastException e){
throw new RuntimeException("Incorrect Response Type for Result Type: " + resultType);
}
}
return response;
}
}
And here is the ResponseFactory:
public abstract class ResponseFactory implements CacheEntryFactory{
#Override
public final Object createEntry(Object request) throws Exception {
return generateResponse((Request)request);
}
protected abstract Map<ResultType,Response> generateResponse(Request request);
}
After wrestling with it for a while, I discovered that the cache wasn't being initialized. Creating a CacheManager and adding the cache to it resolved the problem.
I also had a problem with EHCache hanging, although only in a hello-world example. Adding this to the end fixed it (the application ends normally).
CacheManager.getInstance().removeAllCaches();
https://stackoverflow.com/a/20731502/2736496