Modifying Configuration for Embedded tomcat webapp - heroku

I've been trying to modify embedded tomcat configuration for my heroku app. I've installed heroku app using the wiki link below that configures a simple embedded tomcat.
http://devcenter.heroku.com/articles/create-a-java-web-application-using-embedded-tomcat
The source code is here:
public static void main(String[] args) throws Exception {
String webappDirLocation = "src/main/webapp/";
Tomcat tomcat = new Tomcat();
//The port that we should run on can be set into an environment variable
//Look for that variable and default to 8080 if it isn't there.
String webPort = System.getenv("PORT");
if(webPort == null || webPort.isEmpty()) {
webPort = "8080";
}
tomcat.setPort(Integer.valueOf(webPort));
tomcat.addWebapp("/", new File(webappDirLocation).getAbsolutePath());
System.out.println("configuring app with basedir: " + new File("./" + webappDirLocation).getAbsolutePath());
tomcat.start();
tomcat.getServer().await();
}
Questions:
Since I'm using embedded tomcat, how do I configure default session timeout for my web application? It seems to default to 30 min for some reason? I want to set to something like one week.
If I launch the application from within eclipse, how do I set autodeploy = true so that I don't have to compile and restart my application every time I modify java code?
is there way to set my web.xml and server.xml?
how do I run apache tomcat manager?
The documentation on the internet is not very clear. Can you please help?
Thanks in advance..
Kiran

Use Context.setSessionTimeout(int). Java docs here. Here's the same Main class with a session timeout set to 30 days:
package launch;
import java.io.File;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.Context;
public class Main {
public static void main(String[] args) throws Exception {
String webappDirLocation = "src/main/webapp/";
Tomcat tomcat = new Tomcat();
//The port that we should run on can be set into an environment variable
//Look for that variable and default to 8080 if it isn't there.
String webPort = System.getenv("PORT");
if(webPort == null || webPort.isEmpty()) {
webPort = "8080";
}
tomcat.setPort(Integer.valueOf(webPort));
Context ctx = tomcat.addWebapp("/", new File(webappDirLocation).getAbsolutePath());
ctx.setSessionTimeout(2592000);
System.out.println("configuring app with basedir: " + new File("./" + webappDirLocation).getAbsolutePath());
tomcat.start();
tomcat.getServer().await();
}
}
Notice the Context ctx = ... and ctx.setSessionTimeout(...).
As for Tomcat Manager, you can't use it when you embed Tomcat in your application this way. I am curious what you would like to use Tomcat Manager for?
Anything you would normally do from server.xml you can do via the embed API. The whole point of embedding is that you configure everything programmatically.
You can still set up your own web.xml as you normally would. Just add it in a WEB-INF directory under the directory you pass in as webappDirLocation. But again, I am curious what you would want to put in web.xml? Because you "own" the main application loop, you can set up any configuration you need from your main method. I highly recommend a practice of initializing everything you need in the main loop and reading OS environment variables for anything that is environment specific (e.g. a JDBC url).
Finally, as for Eclipse, you don't need hot deploy anymore because you are not using a container deployment model. You can simply run your application from inside Eclipse with "Debug as..." and Eclipse will auto compile and reload code as you change it. It's not exactly similar to hot deploy. For example, it won't hot reload classes with new method signatures. But it's much faster to cycle the whole app compared to when using a container, so overall, I find it much more productive.

Related

ehcache-clustered not working in OSGi when project is installed several times

Having troubles with clustered ehcache in osgi/aem. Only with first project build/installation it works fine, but with second build/installation it stops working, generate a lot of errors. It looks like terracotta connection, cachemanager or something third is not properly closed.
Even after deleting bundles it tries connect to terracotta.
ok log, errors in log
I'm installing ehcache and ehcache-clustered as standalone bundles in osgi. Also tried with embedding them into my bundle. Ehcache and ehcache-clustered are set as dependencies, also tried with org.apache.servicemix.bundles.javax-cache-api (embedding, not sure if it's needed)
First time all ehcache and ehcache-clustered services are active, 2nd time are satisfied.
Ehcache bundle, ehcache-clustered bundle, javax-cache-api bundle, my project bundle
pom.xml
Same code I have tired as standalone java app and it works perfectly fine (https://github.com/ehcache/ehcache3-samples/blob/master/clustered/src/main/java/org/ehcache/sample/ClusteredXML.java)
So not sure what I have missed (dependencies, import packages..)?
ehcache config, terracotta config
#Activate
private void activate() {
LOGGER.info("Creating clustered cache manager from XML");
URL myUrl = ClusteredService.class.getResource("/com/myco/services/ehcache-clustered-local2.xml");
Configuration xmlConfig = new XmlConfiguration(myUrl);
try (CacheManager cacheManager = CacheManagerBuilder.newCacheManager(xmlConfig) ) {
cacheManager.init();
org.ehcache.Cache<String, String> basicCache = cacheManager.getCache("basicCache4", String.class, String.class);
LOGGER.info("1. Putting to cache");
basicCache.put("1","abc");
LOGGER.info("1. Getting from cache");
String value = basicCache.get("1");
LOGGER.info("1. Retrieved '{}'", value);
LOGGER.info("cache manager status2, " + cacheManager.getStatus().toString());
}
}
You have to also create a #Deactivate method where you do a cacheManager.shutdown();
I guess if you call your code in a non OSGi project twice you would also experience the same error.

How do I set a context path with embedded jetty?

I'm banging my head against the wall on this. I wrote a tiny embedded jetty server (jetty 9.4.18, jersey 1.19.4) and I cannot for the life of me get it to respect the context path and my REST services deployed.
I tried setContextPath, but that never worked on ServletContextHandler, so I went with WebAppContext.
This is about as simple as I can get it:
Server jettyServer = new Server(9999);
// set up the web app
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/app/");
webapp.setResourceBase("web");
jettyServer.setHandler(webapp);
// add REST service
ServletHolder jerseyServlet = webapp.addServlet(ServletContainer.class, "/service/*");
final ResourceConfig resourceConfig = new ResourceConfig(RestService.class);
resourceConfig.register(MultiPartFeature.class);
jerseyServlet.setInitParameter("jersey.config.server.provider.packages", "org.futureboy.app.server.rest");
try {
jettyServer.start();
jettyServer.join();
} catch (Exception e) {
e.printStackTrace();
//jettyServer.stop();
jettyServer.destroy();
}
The static HTML files are served up in the web directory, and this works fine if I keep this line as follows:
ServletHolder jerseyServlet = webapp.addServlet(ServletContainer.class, "/service/*");
However this means the REST service (which operates under /app/service) does not work. If I swap this line out:
ServletHolder jerseyServlet = webapp.addServlet(ServletContainer.class, "/*");
Then the REST service works fine, but now the static HTML content does NOT work fine. So I either get a working static HTML service on /app/ or a working REST service underneath /app/service, but I can't have both. What am I doing wrong? The RestService.java file starts like:
#Path("/service")
public class RestService {
Any help would be appreciated, for I feel I am stuck on the one-yard line here.
Why do you want Jersey to serve static content?
That's not the role of a JAX-B server.
What do do ...
Switch from WebAppContext to ServletContextHandler (you don't need the overhead of WebAppContext or any of the bytecode scanning or annotation scanning deployment techniques that a full blown WebAppContext brings to the table.
Prevent Jersey from serving static content.
Setup a proper ResourceBase - use a fully qualified path or URI (no relative paths, no partial URIs)
Add a DefaultServlet on the default url-pattern "/" named "default".
Which these changes Jetty will serve static content, from your Resource Base.
Some prior answers/examples of the Jetty side configuration and DefaultServlet usage:
Deploying Jetty server via .jar. Why can't I access the index?
How to get embedded Jetty serving html files from a Jar, not a War
Serving static files from alternate path in embedded Jetty
What is difference between ServletContextHandler.setResourceBase and ResourceHandler.setResourceBase when using Jetty embedded container?
Jetty: default servlet context path
Display static HTML file from resources folder in Jetty Serverlet doGet method
And there's many many answers on how to configure Jersey to not serve static content.
One my favs is the solution provided at ...
Servlet for serving static content

Environment Configuration Spring Boot

Created a Spring Boot application that will need to migrate from "Local Dev" to "Test", "QA" and "Prod" environments.
Application currently uses a "application.properties" for database connectivity and Kafka configuration.
I am wanting to deploy to "Test" and realized that the properties will not work for that enviornment. After reading the ref docs, it looks like I can simply copy the application.properties file and add a new one application-test.properties, so on, and then run the standalone jar with a -Dspring.profiles.active=test and that seems to work.
But by the time I am done, that means I h ave 4 different appliction-XXXXX.properties files in the jar which may or may not be bad. I know the ultimate configuration would be to use Spring Config server, but right now we are not there with regards to this.
Can anyone validate that using multiple properties files is viable and will work for a bit, or if I am looking at th is all wrong. I do not want to have configuration on the servers in each environment, as I am thinking these mini-services should be self-contained.
Any input would be appreciated.
in a word, your configuration file should be outside your source code.
#PropertySource(value = {"classpath:system.properties"})
public class EnvironmentConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Let's say it's named "system.properties", which will be uploaded to server at deployment stage under your application classpath.

Initialize spring cloud config client, for SDK development

This question is somewhat similar to this existing question
I am still trying to navigate or trying to find right spring boot code, which i can customize. I need to develop java SDK which connects with existing config server and provides values to key. This SDK will be used in java applications, which might or might not be spring application. Same SDK will be used by QA for regression testing of config server.
So question is, if given
Config server URL
application name
active profile (no need for label, it will be default master),
Can I initialize some config client class which will give me simple methods like public String getKeyValue(final String key)
I am looking at source of classes like ConfigServicePropertySourceLocator, CompositePropertySource, ConfigClientAutoConfiguration, ConfigServiceBootstrapConfiguration etc.
Do I need to build Environment object manually? If yes, how?
I have some success. Posting a possible answer for others to further fine tune it.
#SpringBootApplication
public class ConfigSDKApp {
#Autowired
public SomeSpringBean someBean = null;
private static ConfigSDKApp INSTANCE = null;
public synchronized static ConfigSDKApp getInstance(String[] args) {
if (null != INSTANCE) {
return INSTANCE;
}
SpringApplication sprApp = new SpringApplication(ConfigSDKApp.class);
sprApp.setWebEnvironment(false);
ConfigurableApplicationContext appContext = sprApp.run(args);
ConfigSDKApp app = appContext.getBean(ConfigSDKApp.class);//new ConfigSDKApp();
INSTANCE = app;
return INSTANCE;
}
}
It's kind of singleton class (but public constructor). Hence code smell.
Also, what if this SDK is running with-in springboot client. ApplicationContext & environment is already initialized.

Configuring Tomee to allow WebSphere JNDI Lookups

We are currently developing an application intended for deployment on a WebSphere server. The application should use an in-house Service Provider, that provides access to services implemented as remote EJBs. The Service Provider bean has some hard-coded jndi-names to use.
Now during development we are using Tomee and in general all is working nicely. All except one thing:
The ServiceProvider does a jndi-lookup of "cell/persistent/configService". Now I tried to create a mock ear that contains mock EJBs for these services. I am able to deploy them, and I am able to access them from the application using jndi-names like: "java:global/framework-mock-ear-1.0.0-SNAPSHOT/framework-mock-impl/ConfigServiceMock" but it seems to be impossible to access them using a jndi lookup of: "cell/persistent/configService" ... now I added an openejb-jar.xml file to my mock implementation containing:
<openejb-jar>
<ejb-deployment ejb-name="ConfigServiceMock">
<jndi name="cell/persistent/configService"
interface="de.thecompany.common.services.config.ConfigService"/>
</ejb-deployment>
</openejb-jar>
And I can see during startup, that the bean seems to be registered correctly under that name:
INFORMATION: Jndi(name=cell/persistent/configService) --> Ejb(deployment-id=ConfigServiceMock)
But I have now idea how to make the other ear be able to access this bean using that name.
The Service Provider part is given and we are not able to change this at all, so please don't suggest to change the hard-coded jndi names. We surely would like to do so, but are not able to change anything.
Ok ... to I wasted quite some time on this. Until I finally came up with a solution. Instead of configuring Tomee and OpenEJB to find my beans, I hijacked the InitialContext and rewrote my queries.
package de.mycompany.mock.tomee;
import org.apache.naming.java.javaURLContextFactory;
import javax.naming.Context;
import javax.naming.NamingException;
import java.util.Hashtable;
public class MycompanyNamingContextFactory extends javaURLContextFactory {
private static Context initialContext;
#Override
public Context getInitialContext(Hashtable environment) throws NamingException {
if(initialContext == null) {
Hashtable childEnv = (Hashtable) environment.clone();
childEnv.put("java.naming.factory.initial", "org.apache.naming.java.javaURLContextFactory");
initialContext = new MycompanyInitialContext(childEnv);
}
return initialContext;
}
}
By setting the system property
java.naming.factory.initial=de.mycompany.mock.tomee.MycompanyNamingContextFactory
I was able to inject my MycompanyInitialContext context implementation:
package de.mycompany.mock.tomee;
import org.apache.openejb.core.ivm.naming.IvmContext;
import org.apache.openejb.core.ivm.naming.NameNode;
import javax.naming.NamingException;
import java.util.Hashtable;
public class MycomanyInitialContext extends IvmContext {
public MycomanyInitialContext(Hashtable<String, Object> environment) throws NamingException {
super(environment);
}
#Override
public Object lookup(String compositName) throws NamingException {
if("cell/persistent/configService".equals(compositName)) {
return super.lookup("java:global/mycompany-mock-ear-1.0.0-SNAPSHOT/mycompany-mock-impl/ConfigServiceMock");
}
if("cell/persistent/authorizationService".equals(compositName)) {
Object obj = super.lookup("java:global/mycompany-mock-ear-1.0.0-SNAPSHOT/mycompany-mock-impl/AuthServiceMock");
return obj;
}
return super.lookup(compositName);
}
}
I know this is not pretty and if anyone has an idea how do make this easier and prettier, I'm all ears and this solution seems to work. As it's only intended on simulating production services during development, this hack doesn't induce any nightmares for me. Just thought I'd post it, just in case someone else stumbles over something similar.
I know this answer is coming a few years after the question, but a simpler solution would be to simply set the system property as follows (say in catalina.properties):
java.naming.initial.factory=org.apache.openejb.core.OpenEJBInitialContextFactory
This allows you to lookup the ejb by the name you set, and the one that shows in tomee logs during startup, eg your 'cell/persistent/configService' from
INFORMATION: Jndi(name=cell/persistent/configService) --> Ejb(deployment-id=ConfigServiceMock)
With the system property set you can lookup the ejb the way you would want
final Context ctx = new InitialContext();
ctx.lookup("cell/persistent/configService")
The OpenEJBInitialContextFactory allows access to local EJBs as well as container resources.
If you didn't want to set the system property (as it would affect all applications in the tomee) you could still use the factory setting it the 'standard' way:
Properties properties = new Properties();
properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.core.OpenEJBInitialContextFactory");
final Context ctx = new InitialContext(properties);
ctx.lookup("cell/persistent/configService");
And of course you could still look them up using the global "java:global/" as well with that factory.

Resources