How to deliver Realm with the war with Tomcat? - java

we have a simple web application running on Tomcat 7.0.56. Now we want to use our
own realm for authentication.
public class SpecialAuth extends DataSourceRealm{
#Override
public Principal authenticate(String username, String credentials){
....
}
}
This is defined in the /META-INF/context.xml inside the war
<Context>
<Realm className="some.package.SpecialAuth" dataSourceName="jdbc/MySQL" />
</Context>
Where to put the SpecialAuth.class?
What we expected was simply to have the SpecialAuth.class inside our war but then we're getting folling exception on startup
Caused by: java.lang.ClassNotFoundException: some.package.BackOfficeAuth
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
....
If we make a jar, putting it into $TOMCAT/lib everything works fine.
But this CAN'T be the solution! That would mean every time I work on this class(es) I have to touch my tomcat server and can't use the normal deployment.
How can I use the build-in authentication mechanism without touching the tomcat all the timeß

As you said I don't like your answers :) So what I did (and I'm 100% sure that you don't like it) was to set the realm on the dirties possible way BUT now I can run it on a ontouched tomcat. After 163 acceptance tests nothing seems to break.
public final class ContextListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
ServletContext servletContext = event.getServletContext();
TomcatContextManipulator tomcat = new TomcatContextManipulator(servletContext);
tomcat.applyRealm(new MyOwnRealm());
}
}
.
public class TomcatContextManipulator {
private static final String EXPEXCTED_TOMCAT_VERSION = "7.0.52.0";
private ApplicationContextFacade servletContext;
/**
* #param servletContext must be of type {#link ApplicationContextFacade}
*/
public TomcatContextManipulator(ServletContext servletContext) {
checkTomcatVersion();
ensureEquals(servletContext.getClass(), ApplicationContextFacade.class, "class of servletContext");
this.servletContext = (ApplicationContextFacade) servletContext;
}
/**
* checks if the correct version of tomcat is in use, throws {#link IllegalStateException} if not
*/
private void checkTomcatVersion() {
// we use several internal parts of tomcat (for example with reflection)
// by doing this we bind ourself hardly to a explicit version
ensureEquals(EXPEXCTED_TOMCAT_VERSION, ServerInfo.getServerNumber(), "Tomcat-Server-Version");
}
/**
* overrides the existing realm with the given on
*/
public void applyRealm(Realm realm) {
ensureNotNull(realm, "realm");
ApplicationContext applicationContext = (ApplicationContext) ReflectionUtil.get(servletContext, "context");
StandardContext standardContext = (StandardContext) ReflectionUtil.get(applicationContext, "context");
standardContext.setRealm(realm);
}
}
Note:
Reflection.get() returns the value of the (private) instance variable of the given object
ensure...() is like assert... but it throws Exception

Related

Spring Boot customize server.tomcat.threads.min-spare for management server only

I have an application with management.server enabled:
management.server.port=8081
When I start application, I have:
10 threads for 8080 HTTP nio connector
10 threads for 8081 HTTP nio connector
But I would like to reduce min-spare only for management (8081) and not for the web application (8080)
Looking at Spring code, it seems it's not possible, can someone confirm ?
EDIT: The approach below is not sufficient as the ManagementWebServerFactoryCustomizer is also a ConfigurableWebServerFactory and will thus be applied to the main server.
Adding logic to check againgst the management port is not helping as the management context has its very own wiring and won't pick up the bean.
Looks like it's not possible to hook into the management server configuration easily (would be easier if ServletManagementContextFactory were public).
You can look into ServletManagementChildContextConfiguration to see how the management server is wired.
You could hook into the management server configuration by providing a ManagementWebServerFactoryCustomizer like this (not sure if there's an easier way):
#Configuration
public class TomcatManagementCustomizerConfiguration {
#Bean
ManagementWebServerFactoryCustomizer<ConfigurableServletWebServerFactory> servletManagementWebServerFactoryCustomizer(
#Value("${management.server.threads.min-spare:5}") int managementMinSpareThreads,
ListableBeanFactory beanFactory) {
return new TomcatManagementCustomizer(beanFactory, managementMinSpareThreads);
}
static class TomcatManagementCustomizer extends ManagementWebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
private final int managementMinSpareThreads;
protected TomcatManagementCustomizer(ListableBeanFactory beanFactory, int managementMinSpareThreads) {
super(beanFactory, TomcatWebServerFactoryCustomizer.class);
this.managementMinSpareThreads = managementMinSpareThreads;
}
#Override
#SuppressWarnings("rawtypes")
protected void customize(ConfigurableServletWebServerFactory factory, ManagementServerProperties managementServerProperties, ServerProperties serverProperties) {
super.customize(factory, managementServerProperties, serverProperties);
((TomcatServletWebServerFactory) factory).addConnectorCustomizers((connector) -> {
ProtocolHandler handler = connector.getProtocolHandler();
if (handler instanceof AbstractProtocol) {
AbstractProtocol protocol = (AbstractProtocol) handler;
protocol.setMinSpareThreads(managementMinSpareThreads);
}
});
}
}
}
Can you not just put the following in either properties file or YAML file?
Or is there something I misunderstood?
server.tomcat.threads.min-spare=2
(This is for properties file)
Just to verify (You don't need this as you have been checking the updated value in the log)
Put the following in either properties file or YAML file
management.endpoints.web.exposure.include=health,info,metrics,env
(This is for properties file)
And visit /actuator/env/server.tomcat.threads.min-spare
You need actuator dependency for the link above to work.
You can use #ManagementConfigurationContext and add the configuration class to to your META-INF/spring.properties file.
It is also important to place the configuration class in a package which is not the main package or sub-package of your main application context. This is so that this configuration only applies to the management context.
Below is the sampel configuration following #Holgzn's response.
#ManagementContextConfiguration
public class TomcatManagementCustomizerConfiguration {
#Bean
ManagementWebServerFactoryCustomizer<ConfigurableServletWebServerFactory> servletManagementWebServerFactoryCustomizer(
#Value("${management.server.threads.min-spare:5}") int managementMinSpareThreads,
ListableBeanFactory beanFactory) {
return new TomcatManagementCustomizer(beanFactory, managementMinSpareThreads);
}
static class TomcatManagementCustomizer extends ManagementWebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
private final int managementMinSpareThreads;
protected TomcatManagementCustomizer(ListableBeanFactory beanFactory, int managementMinSpareThreads) {
super(beanFactory, TomcatWebServerFactoryCustomizer.class);
this.managementMinSpareThreads = managementMinSpareThreads;
}
#Override
#SuppressWarnings("rawtypes")
protected void customize(ConfigurableServletWebServerFactory factory, ManagementServerProperties managementServerProperties, ServerProperties serverProperties) {
super.customize(factory, managementServerProperties, serverProperties);
((TomcatServletWebServerFactory) factory).addConnectorCustomizers((connector) -> {
ProtocolHandler handler = connector.getProtocolHandler();
if (handler instanceof AbstractProtocol) {
AbstractProtocol protocol = (AbstractProtocol) handler;
protocol.setMinSpareThreads(managementMinSpareThreads);
}
});
}
}
}
The spring.properties file
org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration=<package>.TomcatManagementCustomizerConfiguration

SpringBoot Tomcat Embedded Global JNDI Resource

I know there are a lot of questions about JNDI Resources in tomcat embedded, but I tried all the solutions I found without success.
I have an application that expose Rest API for my clients. Inside this app, we have a async solution using JMS and Amazon SQS. The App uses third-part libs, that uses JNDI to get sql.Datasource, because of that, I need use JNDI Datasource.
The problem is, when the App does a call to this libs in the same thread of Rest Controller, the JNDI Lookup works, and the datasource is getted.
When my #JmsListener calls this libs, I get a NamingNotFoungException.
I've used context.list("java") in 2 points of my code and confirmed that, inside JmsListener, there is no JNDI Context.
My tomcat factory class:
Configuration
public class CustomTomcatEmbeddedServletContainerFactory {
#Value("${spring.log.datasource.jndiName}")
private String logJndiName;
#Value("${spring.log.datasource.password}")
private String logPassword;
#Value("${spring.log.datasource.url}")
private String logUrl;
#Value("${spring.log.datasource.username}")
private String logUsername;
#Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
return new TomcatEmbeddedServletContainerFactory() {
#Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
tomcat.enableNaming();
return super.getTomcatEmbeddedServletContainer(tomcat);
}
#Override
protected void postProcessContext(Context context) {
// LogDS
context.getNamingResources()
.addResource(
getContextResource(logJndiName, logUrl, logUsername, logPassword)
);
ContextResourceLink contextResourceLink = new
ContextResourceLink();
contextResourceLink.setGlobal(logJndiName);
contextResourceLink.setName(logJndiName);
contextResourceLink.setType("javax.sql.DataSource");
context.getNamingResources().addResourceLink(contextResourceLink);
}
private ContextResource getContextResource(
final String name
, final String url
, final String username
, final String password
) {
ContextResource resource = new ContextResource();
resource.setName(name);
resource.setType(DataSource.class.getName());
resource.setProperty("factory", "com.zaxxer.hikari.HikariJNDIFactory");
resource.setProperty("jdbcUrl", url);
resource.setProperty("dataSource.user", username);
resource.setProperty("dataSource.password", AESCrypto.decrypt(password));
resource.setScope("Sharable");
return resource;
}
};
}
}
Any idea of this problem?
-------Update---------
When I use the code below, the context in JMSListener solve but my RestController doesn't answer anymore, a 404 http status happen.
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
tomcat.enableNaming();
TomcatEmbeddedServletContainer container = super.getTomcatEmbeddedServletContainer(tomcat);
for (Container child : container.getTomcat().getHost().findChildren()) {
if (child instanceof Context) {
ClassLoader contextClassLoader = ((Context) child).getLoader().getClassLoader();
Thread.currentThread().setContextClassLoader(contextClassLoader);
break;
}
}
return container;
}
-------Update2---------
My problem is fixed. Instead of returning "container", like I said above, I was returning super.getTomcatEmbeddedServletContainer(tomcat); The manual GlobalContext in my first update works well!
My problem is fixed. Instead of returning "container", like I said above, I was returning super.getTomcatEmbeddedServletContainer(tomcat); The manual GlobalContext in my first update works well!

shared classloader with embedded Tomcat 8

I have upgraded tomcat from version 7.0.34 to version 8.0.33, and since then I have been facing a problem to share the web application context and Junit context.
I have a web application with singleton class that gathers statistic data about the web application. I also have Junit that runs the web application in embedded tomcat. the Junit queries the web application and then checks the statistic data.
I try to make a simple example:
the singleton:
public class Counter {
private static Counter instance;
private AtomicLong counter;
private Counter(){}
public static Counter getInstance(){
if(instance == null){
synchronized (Counter.class) {
if(instance == null){
instance = new Counter();
}
}
}
return instance;
}
public long incrementAndGet(){
return counter.incrementAndGet();
}
public long getValue(){
return counter.get();
}
}
the servlet:
#WebServlet(name="servlet",loadOnStartup=1, urlPatterns="/servletTest")
public class Servlet extends HttpServlet{
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Hi, you are the #" + Counter.getInstance().incrementAndGet() + " visitor");
}
}
contextListener:
public class MyContextListener implements ServletContextListener{
#Override
public void contextDestroyed(ServletContextEvent arg0) {}
#Override
public void contextInitialized(ServletContextEvent arg0) {
Counter.getInstance().incrementAndGet();
}
}
Test unit:
public void mainTest() throws ServletException, LifecycleException{
Tomcat tomcat = new Tomcat();
tomcat.setPort(50000);
StandardContext ctx = (StandardContext) tomcat.addWebapp("/fe", System.getProperty("FEBaseDir")); //The FEBaseDir property is supposed to be taken from Maven build using 'test' profile
tomcat.start();
Counter.getInstance().getValue();
}
when I used Tomcat 7, everything worked fine. but since I upgraded tomcat to tomcat 8.0.33, It hasn't been working. the singleton class with the static data loads twice. first by the tomcat and then by the Junit itself.
I have tried to pass tomcat a classloader but it doesn't work.
public void mainTest() throws ServletException, LifecycleException{
Tomcat tomcat = new Tomcat();
tomcat.setPort(50000);
StandardContext ctx = (StandardContext) tomcat.addWebapp("/fe", System.getProperty("FEBaseDir")); //The FEBaseDir property is supposed to be taken from Maven build using 'test' profile
ctx.setCrossContext(true);
ctx.setLoader((Loader) new WebappLoader(Thread.currentThread().getContextClassLoader()));
ctx.setParentClassLoader(Thread.currentThread().getContextClassLoader());
tomcat.getEngine().setParentClassLoader(Thread.currentThread().getContextClassLoader());
tomcat.getHost().setParentClassLoader(Thread.currentThread().getContextClassLoader());
tomcat.getService().setParentClassLoader(Thread.currentThread().getContextClassLoader());
tomcat.getServer().setParentClassLoader(Thread.currentThread().getContextClassLoader());
tomcat.start();
Counter.getInstance().getValue();
}
What am I doing wrong?
You could try using the setDelegate method in StandardContext to prevent the web-app classloader from reloading the Counter class, but this impacts security in a bad manner so I advice against that.
The usual way to expose statistics is to use JMX (MBeans). You enable this by calling the setUseNaming method in StandardContext with value true.
You can register a mbean like this (copied from here):
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName beanPoolName = new ObjectName("com.zaxxer.hikari:type=Pool (" + poolName + ")");
mBeanServer.registerMBean(hikariPool, beanPoolName);
And you can retrieve a value like this (copied from here):
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName poolName = new ObjectName("com.zaxxer.hikari:type=Pool (foo)");
HikariPoolMXBean poolProxy = JMX.newMXBeanProxy(mBeanServer, poolName, HikariPoolMXBean.class);
int idleConnections = poolProxy.getIdleConnections();
See also this SO question and you'll probably have to read some more documentation (in my experience, it takes a while to understand the whole JMX thing and get it to work). I have not tried this in combination with unit-tests though, so YMMV.

CDI Extension to automatically resolve call to Remote EJB from one EAR to another EAR

I'm getting problems trying to call a remote service deployed in an EAR from another EAR.
I do not specify any names for my EJB, no matter they are #Local or #Remote and so just use annotation and inject it via #EJB.
This is what i have:
EAR A/
lib/any lib jar (including API jar for remote service B)
war
ejb module(s) with service A calling remote service B
EAR B/
lib/any API lib jar
ejb module with service B
Additional information: Service B implement both #Local and #Remote interfaces, and Service A inject Service B with Remote interface via:
#EJB private MyRemoteInterface remoteService;
This structure works perfectly fine with jboss server, but with websphere (8.5.5.1) one i must bind names onto my remote EJB. If do not add bindings on both EARs (i did it though admin console directly not to have to edit ejb-jar.xml) then my remote bean is not resolved at runtime.
Of course, i have to make it work with WAS, else i won't not post :)
My question: is that normal to be forced to name remote EJB with WebSphere or is it a regression (from any previous version) ? I'm expecting the injection #EJB on remote beans to works with automatic resolution on types, but maybe i'm wrong somewhere ?
Solution:
Because lookup must be done to make the resolution work, i decided to add the lookup configuration part onto the client ejb-jar.xml file(s). This is done automatically by maven plugin execution, with lookup name based on remote interface full name (package included) as this is the default binding WebSphere use if nothing is specified in EJB implementation.
I've chosen this solution for two reasons:
i don't want to do the lookup in my code (duplicate code with no interest)
i need to make it automatic and transparent for other developers
Thanks bkail for the answer.
Finally, for business delays reason i've written a CDI extension to make the job.
The extension scan all injection point with Remote contract and proxify them. Proxies are #ApplicationScoped managed beans created on demand, and their job only consists in:
lookup the target bean related to the scanned remote contract
delegate the execution of the called remote method
This solution also offers me the possibility to handle lookup operation on different machine(s) by configuration though ENV variables so that deployement by container (i.e Docker) would easily works (which is one of our target in a comming future)
EDIT: CDI extension code below
RemoteEjbExtension.java:
public class RemoteEjbExtension implements Extension {
/**
* This method is fired by the container for every Java EE component class
* supporting injection that may be instantiated by the container at runtime,
* including every managed bean declared using javax.annotation.ManagedBean,
* EJB session or message-driven-bean, enabled bean, enabled interceptor or
* enabled decorator.
*
* #param pit the event that has been fired
*/
<T> void processInjectionTarget(#Observes final ProcessInjectionTarget<T> pit) {
for (AnnotatedField<? super T> field : pit.getAnnotatedType().getFields()) {
if (field.getJavaMember().getType().isAnnotationPresent(Remote.class)) {
RemoteProxyFactory.putIfAbsent(field.getJavaMember().getType());
}
}
}
/**
* This method is fired by the container when it has fully completed the
* bean discovery process, validated that there are no definition errors
* relating to the discovered beans, and registered Bean and ObserverMethod
* objects for the discovered beans, but before detecting deployment problems.
*
* #param abd AfterBeanDiscovery fired events
* #param bm Allows a portable extension to interact directly with the container.
* Provides operations for obtaining contextual references for beans,
* along with many other operations of use to portable extensions.
*/
#SuppressWarnings("unchecked")
void afterBeanDiscovery(#Observes final AfterBeanDiscovery abd, final BeanManager bm) {
// Roll over discovered remote interfaces
for (final Entry<String, Class<?>> remoteClassEntry : RemoteProxyFactory.getProxyClassEntries()) {
// Proxy that points to the remote EJB
final Object remoteProxy;
final Class<?> remoteClass = remoteClassEntry.getValue();
try {
// Build a proxy that fetches the remote EJB using JNDI
// and delegate the call.
remoteProxy = RemoteProxyFactory.Builder.createEJBRemoteProxy(remoteClass);
} catch (Exception e) {
throw new IllegalStateException("Proxy creation for " + remoteClass.getCanonicalName() + " failed.", e);
}
final InjectionTarget<Object> it;
try {
AnnotatedType<Object> at = ((AnnotatedType<Object>) bm.createAnnotatedType(remoteProxy.getClass()));
it = bm.createInjectionTarget(at);
} catch (Exception e) {
throw new IllegalStateException("Injection target for " + remoteClass.getCanonicalName() + " is invalid.", e);
}
final Bean<?> beanRemoteProxy = RemoteProxyFactory.Builder.createBeanForProxy(remoteProxy, it, remoteClass, ApplicationScoped.class);
abd.addBean(beanRemoteProxy);
}
}
}
RemoteProxyFactory.java:
public final class RemoteProxyFactory {
/** The JNDI initial context */
private static InitialContext CTX;
static {
try {
RemoteProxyFactory.CTX = new InitialContext();
} catch (NamingException e) {
throw new IllegalStateException("Unable to get initial context.", e);
}
}
private static final Map<String, Class<?>> REMOTE_EJB_CLASS_MAP = new ConcurrentHashMap<String, Class<?>>();
/**
* Register given class into proxy map
* #param remoteEJBContractClass the remote contract's class to register
*/
public static void putIfAbsent(final Class<?> remoteEJBContractClass) {
// Works only for same class-loader. You would change this code
// and transform the map to handle multiple class-loader for same contract.
// In our current configuration there is no need as APIs / IMPL libraries share the same CL.
if (!REMOTE_EJB_CLASS_MAP.containsKey(remoteEJBContractClass.getSimpleName())) {
REMOTE_EJB_CLASS_MAP.put(remoteEJBContractClass.getSimpleName(), remoteEJBContractClass);
}
}
public static Set<Entry<String, Class<?>>> getProxyClassEntries() {
return REMOTE_EJB_CLASS_MAP.entrySet();
}
public static InitialContext getContext() {
return RemoteProxyFactory.CTX;
}
public static final class Builder {
private static final Logger LOGGER = Logger.getLogger(Builder.class.getName());
/**
* Create a new proxy that lookup the remote EJB
* though JNDI.
* #param remoteEJBClazz the remote class contract
* #return a new remote EJB proxy
*/
public static Object createEJBRemoteProxy(final Class<?> remoteEJBClazz) {
return Proxy.newProxyInstance(remoteEJBClazz.getClassLoader(), new Class[] {
remoteEJBClazz
}, new InvocationHandler() {
#Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
Object ejbInstance = null;
try {
// Pull the remote EJB from the JNDI
ejbInstance = RemoteProxyFactory.getContext().lookup(remoteEJBClazz.getName());
} catch (Exception e) {
throw new IllegalStateException("Remote EJB not found : " + remoteEJBClazz.getSimpleName(), e);
}
// Delegates the call to the remote EJB
return method.invoke(ejbInstance, args);
}
});
}
/**
* Create a bean for given proxy / injection target / type / scope
* #param proxy the proxy object
* #param it the injection target
* #param clazz the proxy type
* #param targetScope the returned managed bean' scope
* #return the managed bean handling given proxy
*/
public static <T extends Object> Bean<T> createBeanForProxy(final T proxy, final InjectionTarget<T> it, final Class<?> clazz, final Class<? extends Annotation> targetScope) {
return new Bean<T>() {
#Override
public T create(final CreationalContext<T> ctx) {
return proxy;
}
#Override
public void destroy(final T instance, final CreationalContext<T> ctx) {
it.preDestroy(instance);
it.dispose(instance);
ctx.release();
}
#Override
public Class<?> getBeanClass() {
return clazz;
}
#Override
public Set<InjectionPoint> getInjectionPoints() {
return it.getInjectionPoints();
}
#Override
public String getName() {
return clazz.toString();
}
#Override
public Set<Annotation> getQualifiers() {
Set<Annotation> qualifiers = new HashSet<Annotation>();
qualifiers.add(new AnnotationLiteral<Default>() {
/** Default serial-id. */
private static final long serialVersionUID = 1L;
});
qualifiers.add(new AnnotationLiteral<Any>() {
/** Default serial-id. */
private static final long serialVersionUID = 1L;
});
return qualifiers;
}
#Override
public Class<? extends Annotation> getScope() {
return targetScope;
}
#Override
public Set<Class<? extends Annotation>> getStereotypes() {
return Collections.emptySet();
}
#Override
public Set<Type> getTypes() {
Set<Type> types = new HashSet<Type>();
types.add(clazz);
return types;
}
#Override
public boolean isAlternative() {
return false;
}
#Override
public boolean isNullable() {
return false;
}
};
}
}
}
This is working as expected for WebSphere Application Server, and it is not a regression. The javadoc only requires automatic binding for #EJB when the type is within the same application:
If no explicit linking information is provided and there is only one
session bean within the same application that exposes the matching
client view type, by default the EJB dependency resolves to that
session bean.

Getting server context path on application startup

I am trying to get the server URL (eg. http://www.mywebapp.com/myapp) from the ServletContext when the application starts up, I am doing this by invoking a bean method on startup (using #Startup) and getting the servlet context,
#Startup
#Name("startupActions")
#Scope(ScopeType.APPLICATION)
public class StartupActionsBean implements StartupActions,
Serializable {
#Logger private Log log;
/**
*
*/
private static final long serialVersionUID = 1L;
#Create
#Override
public void create(){
ServletContext sc = org.jboss.seam.contexts.ServletLifecycle.getServletContext();
String context = sc.getContextPath();
String serverInfo = sc.getServerInfo();
log.debug("__________________START__________________");
log.debug("Context Path: "+context);
log.debug("Server Info: "+serverInfo);
}
// Cleanup methods
#Remove
#BypassInterceptors
#Override
public void cleanUp(){}
}
This work ok, however the ServletContext path is blank, see console output below..
18:52:54,165 DEBUG [uk.co.app.actions.startup.StartupActionsBean] __________________START__________________
18:52:54,165 DEBUG [uk.co.app.actions.startup.StartupActionsBean] Context Path:
18:52:54,165 DEBUG [uk.co.app.actions.startup.StartupActionsBean] Server Info: JBoss Web/3.0.0-CR1
Does anyone know how to get the contextpath through this, or other means?
ps. using SEAM 2.2.2, Jboss AS6 Final, Richfaces 3.3.3
Don't use #Startup, your component startup code gets called before contexts are fully setup and some other factories could not be yet initialized.
Observe the org.jboss.seam.postInitialization event and use the same ServletLifecycle.getCurrentServletContext() to get hold of the data needed. A quick example:
#Name("contextPath")
public class ContextPathInit implements Serializable {
private String contextPath;
#Observer("org.jboss.seam.postInitialization")
public void init() {
contextPath = ServletLifecycle.getCurrentServletContext().getContextPath();
}
}
Have you tried getting it from ExternalContext using the getContextName method?
FacesContext.getCurrentInstance().getExternalContext().getContextName()

Categories