Error in Web.xml in websphere Liberty and not in Tomcat - websphere-liberty

I am trying to add this filter in my web.xml file and run it on Liberty server. This configuration runs on Tomcat. However on Liberty I get an error,Exception thrown by application class 'java.lang.String.substring:1339'
Is there some length limitation on Liberty?
<filter>
<filter-name>jersey</filter-name>
<filter-class>com.sun.jersey.spi.container.servlet.ServletContainer</filter-class>
<init-param>
<param-name>com.sun.jersey.config.property.WebPageContentRegex</param-name>
<param-value>/(flex|images|js|css|jsp)/.*</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.sun.jersey;com.netflix</param-value>
</init-param>
</filter>
Stack trace:
Exception thrown by application class 'java.lang.String.substring:1339'
java.lang.StringIndexOutOfBoundsException: String index out of range: 8
at java.lang.String.substring(String.java:1339)
at com.sun.jersey.spi.container.ContainerRequest.getEncodedPath(ContainerRequest.java:377)
at com.sun.jersey.spi.container.ContainerRequest.getPath(ContainerRequest.java:370)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1463)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
at com.sun.jersey.spi.container.servlet.ServletContainer.doFilter(ServletContainer.java:895)
at com.sun.jersey.spi.container.servlet.ServletContainer.doFilter(ServletContainer.java:843)
at com.sun.jersey.spi.container.servlet.ServletContainer.doFilter(ServletContainer.java:804)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:207)
at [internal classes]
at com.netflix.eureka.ServerRequestAuthFilter.doFilter(ServerRequestAuthFilter.java:34)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:207)
at [internal classes]
at com.netflix.eureka.StatusFilter.doFilter(StatusFilter.java:68)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:207)
at [internal classes]

It's not clear that the error has to do with the values in web.xml. From a read of the ContainerRequest.getPath API, which has "Get the path of the current request relative to the base URI as a string", what to look at is the request URI and at the processing done within the com.sun classes, several which are listed in the stack. Since the API is computing a relative path, several possibilities suggest themselves: Inconsistent or incorrect path values provided by the com.ibm web container request handling code; Unexpected but valid path values provided to the com.sun classes; a bug in the relative path computation code. I'm not sure how you would get these, but the starting point would be to find out the two URIs which are being processed: The request URI, and the base URI.

Related

Camel RabbitMQ endpoint cannot be created when a dead letter exchange is declared

I'm having an issue creating a RabbitMQ endpoint with Camel. The issue only occurs when I declare a a dead message letter exchange option based on the camel documentation. This is my URN for creating the endpoint:
rabbitmq://localhost/com.mydomain.inbound.exhange?deadLetterExchange=dead.msgs
All is fine when I omit the deadLetterExchange option but as soon as I include it I get the following (not very helpful) exception:
Caused by: java.lang.NullPointerException
at com.rabbitmq.client.impl.ChannelN.validateQueueNameLength(ChannelN.java:1244) ~[amqp-client-3.6.1.jar:?]
at com.rabbitmq.client.impl.ChannelN.queueDeclare(ChannelN.java:843) ~[amqp-client-3.6.1.jar:?]
at com.rabbitmq.client.impl.ChannelN.queueDeclare(ChannelN.java:61) ~[amqp-client-3.6.1.jar:?]
at org.apache.camel.component.rabbitmq.RabbitMQDeclareSupport.declareAndBindQueue(RabbitMQDeclareSupport.java:96) ~[camel-rabbitmq-2.17.0.jar:2.17.0]
at org.apache.camel.component.rabbitmq.RabbitMQDeclareSupport.declareAndBindDeadLetterExchangeWithQueue(RabbitMQDeclareSupport.java:43) ~[camel-rabbitmq-2.17.0.jar:2.17.0]
at org.apache.camel.component.rabbitmq.RabbitMQDeclareSupport.declareAndBindExchangesAndQueuesUsing(RabbitMQDeclareSupport.java:35) ~[camel-rabbitmq-2.17.0.jar:2.17.0]
at org.apache.camel.component.rabbitmq.RabbitMQEndpoint.declareExchangeAndQueue(RabbitMQEndpoint.java:222) ~[camel-rabbitmq-2.17.0.jar:2.17.0]
at org.apache.camel.component.rabbitmq.RabbitConsumer.openChannel(RabbitConsumer.java:288) ~[camel-rabbitmq-2.17.0.jar:2.17.0]
at org.apache.camel.component.rabbitmq.RabbitConsumer.(RabbitConsumer.java:57) ~[camel-rabbitmq-2.17.0.jar:2.17.0]
at org.apache.camel.component.rabbitmq.RabbitMQConsumer.createConsumer(RabbitMQConsumer.java:108) ~[camel-rabbitmq-2.17.0.jar:2.17.0]
at org.apache.camel.component.rabbitmq.RabbitMQConsumer.startConsumers(RabbitMQConsumer.java:90) ~[camel-rabbitmq-2.17.0.jar:2.17.0]
at org.apache.camel.component.rabbitmq.RabbitMQConsumer.doStart(RabbitMQConsumer.java:160) ~[camel-rabbitmq-2.17.0.jar:2.17.0]
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61) ~[camel-core-2.17.0.jar:2.17.0]
at org.apache.camel.impl.DefaultCamelContext.startService(DefaultCamelContext.java:3269) ~[camel-core-2.17.0.jar:2.17.0]
at org.apache.camel.impl.DefaultCamelContext.doStartOrResumeRouteConsumers(DefaultCamelContext.java:3563) ~[camel-core-2.17.0.jar:2.17.0]
at org.apache.camel.impl.DefaultCamelContext.doStartRouteConsumers
....
Just no note that I've also tried creating the exchange and queue manually in a hope that this may work but no luck.
Additional Info:
camel-spring-boot-starter (2.17.0)
camel-rabbitmq (2.17.0)
Try adding a deadLetterQueueoption -
rabbitmq://localhost/com.mydomain.inbound.exhange?deadLetterExchange=dead.msgs&deadLetterQueue=my.dead.letter.queue
I also had to add further options to the uri to get it to work. I added
deadLetterExchangeType
queueArgsConfigurer
The queueArgsConfigurer is an implementation of org.apache.camel.component.rabbitmq.ArgsConfigurer
class MyQueueArgs implements ArgsConfigurer {
void configurArgs(Map<String, Object> args) { //misspelling!!
args.put("x-dead-letter-exchange", "my.dead.letter")
args.put("x-dead-letter-routing-key", "my.dead.letter.key")
}
}
Mine is a Spring app so myArgs (see below) is created in the bean factory.
So, the full uri is like this -
rabbitmq://hostname/exchangeName?routingKey=$routingKey&vhost=virtualHostname&exchangeType=exType&autoDelete=false&queue=my.queue&deadLetterExchange=my.dead.letter&deadLetterExchangeType=dlExType&deadLetterQueue=my.dead.letter.queue&queueArgsConfigurer=#myArgs
I probably don't need to specify the dead letter exchange in the uri and the ArgsConfigurer implementation.
For more on ArgsConfigurer this Camel issue might help - #8457
I had to look at the source code to figure a lot of this out. What is missing from the doc is a definition of dependencies. There are some options, particularly around dead letter exchanges, which become mandatory if another is specified. That's why you are getting your errors. Have a look at populateQueueArgumentsFromDeadLetterExchange in RabbitMQDeclareSupport.
EDIT
A simplification to my answer - I dropped the ArgsConfigurer implementation in the end. I went with this -
rabbitmq://myHostname/myExchangeName?
username=myUserName&
password=myPassword&
queue=myQueueName&
routingKey=myRoutingKey&
vhost=myVirtualHostname&
exchangeType=topic&
autoDelete=false&
deadLetterExchange=myDeadLetter&
deadLetterExchangeType=topic&
deadLetterQueue=myDeadLetterQueue&
deadLetterRoutingKey=myDeadLetterRoutingKey&
autoAck=false

Parsing an xml embedded within another xml using XPath Spring

I'm parsing an xml String using the 'evaluate' function provided by Xpath to read the contents embedded within specific tags in the xml. But i'm having trouble while trying to parse an xml which is embeded within a set of tags which i want to parse.
<Channel>
<channelId>SD0987</channelId>
<parameters>
<param>org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [https://nike-dev.coupahost.com/api/suppliers?return_object=limited]; nested exception is org.springframework.web.client.HttpClientErrorException: 400 Bad Request</param>
<param><?xml version="1.0" encoding="UTF-8"?>
<errors>
<error>
<![CDATA[Unable to find valid PaymentTerm record for payment_term with keys {"code"=>"9999"}. Possible keys are ["id", "code"]. Please verify your xml.]]>
</error>
</errors>
</param>
<param>6-5100</param>
<param><?xml version="1.0" encoding="UTF-8"?><supplier><name>SuTestVDR008-6-5100</name><display-name>SuTestVDR008-6 (SANDALS) - VAT Registration Number - Indirect Europe - INACTIVE</display-name><status>active</status><deleted type="boolean">true</deleted><vendor-account-group-code>1001</vendor-account-group-code><vendor-number>SuTestVDR008-6</vendor-number><on-hold type="boolean">false</on-hold><language-code>E</language-code><purchase-organization-code>5100</purchase-organization-code><group-key>1234</group-key><vendor-partner-type-code>Z4</vendor-partner-type-code><currency-code>EUR</currency-code><primary-address><street1>#### JIU BI VILLAGE</street1><street2>77774</street2><city>GUANGZHOU CITY</city><state>190-Guangdong</state><postal-code>511480</postal-code><country><code>CN</code></country></primary-address><payment-term><code>9999</code></payment-term><content-groups><content-group><name>730_Company Code</name></content-group></content-groups><po-method>prompt</po-method><invoice-matching-level>3-way</invoice-matching-level></supplier></param>
</parameters>
</Channel>
In the above xml sample, i need to read and retrieve everything that is within the tags "param".
Currently, i'm first getting a count of the param tags and then looping thru them to get the data within the tags -
paramCount = XPathUtils.evaluate(originalPayload,"count(/Channel/parameters/param)",XPathUtils.STRING);
for(int i=1;i<=pCount;i++){
pList.add(XPathUtils.evaluate(originalPayload, "/Channel/parameters/param[" +i+ "]",XPathUtils.STRING)
}
This works fine with other xmls but not with the sample given above. I get the below error -
"[Fatal Error] :5:17:The processing instruction target matching "[xX][mM][lL]" is not allowed."
If i remove the part "?xmlversion="1.0" encoding="UTF-8"?
it parses the tags but the output is -
org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [https://nike-dev.coupahost.com/api/suppliers?return_object=limited]; nested exception is org.springframework.web.client.HttpClientErrorException: 400 Bad Request
Unable to find valid PaymentTerm record for payment_term with keys {"code"=>"9999"}. Possible keys are ["id", "code"]. Please verify your xml.
6-5100
SuTestVDR008-6-5100SuTestVDR008-6 (SANDALS) - VAT Registration Number - Indirect Europe - INACTIVEactivetrue1001SuTestVDR008-6falseE51001234Z4EUR#### JIU BI VILLAGE77774GUANGZHOU CITY190-Guangdong511480CN9999730_Company Codeprompt3-way
So as you can see, it just captured the content within the various tags and printed it.
My ask is to print all the text in between the
<param >
tags as is with all the indentation in place.
So the output expected is -
org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [https://nike-dev.coupahost.com/api/suppliers?return_object=limited]; nested exception is org.springframework.web.client.HttpClientErrorException: 400 Bad Request
<?xml version="1.0" encoding="UTF-8"?>
<errors>
<error>
<![CDATA[Unable to find valid PaymentTerm record for payment_term with keys {"code"=>"9999"}. Possible keys are ["id", "code"]. Please verify your xml.]]>
</error>
</errors>
6-5100
<?xml version="1.0" encoding="UTF-8"?>
<supplier><name>SuTestVDR008-6-5100</name><display-name>SuTestVDR008-6 (SANDALS) - VAT Registration Number - Indirect Europe - INACTIVE</display-name><status>active</status><deleted type="boolean">true</deleted><vendor-account-group-code>1001</vendor-account-group-code><vendor-number>SuTestVDR008-6</vendor-number><on-hold type="boolean">false</on-hold><language-code>E</language-code><purchase-organization-code>5100</purchase-organization-code><group-key>1234</group-key><vendor-partner-type-code>Z4</vendor-partner-type-code><currency-code>EUR</currency-code><primary-address><street1>#### JIU BI VILLAGE</street1><street2>77774</street2><city>GUANGZHOU CITY</city><state>190-Guangdong</state><postal-code>511480</postal-code><country><code>CN</code></country></primary-address><payment-term><code>9999</code></payment-term><content-groups><content-group><name>730_Company Code</name></content-group></content-groups><po-method>prompt</po-method><invoice-matching-level>3-way</invoice-matching-level></supplier>
Any ideas?
For that task your content in the <param> must be wrapped to the <![CDATA[ .. ]]>. Otherwise it becomes as a part of the root XML and loses it purpose to be the relaxed data for the XPath result.

C3p0 trying to create a new connection pool and failing with ClassNotFoundException

I'm seeing a very strange behavior in my application.
My application setup: Spring + Hibernate + C3p0
Application keeps running fine, when all of a sudden I start seeing these errors in logs and system totally stop processing any database specific requests.
WARN c3p0.C3P0Registry - Could not create for find ConnectionCustomizer with class name ''.
java.lang.ClassNotFoundException:
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
at com.mchange.v2.c3p0.C3P0Registry.getConnectionCustomizer(C3P0Registry.java:181)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPoolManager.getConnectionCustomizer(C3P0PooledConnectionPoolManager.java:636)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPoolManager.createPooledConnectionPool(C3P0PooledConnectionPoolManager.java:738)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPoolManager.getPool(C3P0PooledConnectionPoolManager.java:257)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPoolManager.getPool(C3P0PooledConnectionPoolManager.java:271)
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128)
at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:80)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:423)
at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:144)
at org.hibernate.jdbc.AbstractBatcher.prepareSelectStatement(AbstractBatcher.java:123)
at org.hibernate.id.SequenceGenerator.generate(SequenceGenerator.java:73)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:99)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:94)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:495)
at org.springframework.orm.hibernate3.HibernateTemplate$18.doInHibernate(HibernateTemplate.java:690)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:365)
at org.springframework.orm.hibernate3.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:687)
Why would C3p0 require to create a new connection pool at this
particular time, before these exceptions application is 100% working
fine and responding perfectly.
Also I've not provided any connectionCustomizerClassName property in
my c3p0 configurations, why would it load one? in this stack trace I
see it's not-null empty string ''.
Any clues?
==============================================================================
Following hibernate jars I see in application's classpath:
hibernate-3.2.6.ga.jar
spring-hibernate-1.2.6.jar
Following c3p0 jars I see in application's classpath:
c3p0-0.9.1.jar
c3p0-0.9.2-pre5.jar
c3p0-oracle-thin-extras-0.9.2-pre5.jar
Code that manually read these properties and set on datasource (I do not read/set any connectionCustomizerClassName property here at all)
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setMinPoolSize(Integer.parseInt(props.getProperty("jdbc.hibernate.c3p0.minPoolSize")));
.....
Here are C3p0 properties being used:
jdbc.hibernate.c3p0.minPoolSize=100
jdbc.hibernate.c3p0.initialPoolSize=100
jdbc.hibernate.c3p0.maxPoolSize=1000
jdbc.hibernate.c3p0.maxIdleTime=21600
jdbc.hibernate.c3p0.maxStatementsPerConnection=0
jdbc.hibernate.c3p0.maxStatements=0
jdbc.hibernate.c3p0.numHelperThreads=30
jdbc.hibernate.c3p0.checkoutTimeout=30000
jdbc.hibernate.c3p0.idleConnectionTestPeriod=900
jdbc.hibernate.c3p0.preferredTestQuery=SELECT 1 FROM dual
jdbc.hibernate.c3p0.maxConnectionAge=0
jdbc.hibernate.c3p0.maxIdleTimeExcessConnections=3600
jdbc.hibernate.c3p0.acquireIncrement=10
jdbc.hibernate.c3p0.acquireRetryDelay=5000
jdbc.hibernate.c3p0.acquireRetryAttempts=6
jdbc.hibernate.c3p0.propertyCycle=180
Following up a conversation in the comments on the posted question, it looks like the issue here is that VisualVM updates the null valued property connectionCustomizerClassName to an empty String value, which c3p0 currently treats an non-null and interprets as a class name.
Going forward (c3p0-0.9.5-pre7 and above), c3p0 will guard against this, interpret an all-whitespace connectionCustomizerClassName as equivalent to null. But in the meantime or for older versions, take care.
One easy workaround would be to define a NullConnectionCustomizer:
package mypkg;
import com.mchange.v2.c3p0.*;
public class NullConnectionCustomizer extends AbstractConnectionCustomizer
{}
And then use mypkg.NullConnectionCustomizer for connectionCustomizerClassName, so that the corresponding field in VisualVM is not empty and ambiguously interpretable as empty String or null.

How do I use jsp files in Spring Roo?

I made a simple Roo project in STS. It created several .jspx files, which I guess are the templates. I'd like to be able to put some HTML and CSS in those, but whenever I change anything significant, I get an exception. For example, when I add some basic HTML:
<div><span><p>Hello</p></span></div>
I get this exception:
SEVERE: Servlet.service() for servlet [msa] in context with path [/msa] threw exception [Request processing failed; nested exception is org.apache.tiles.impl.CannotRenderException: ServletException including path '/WEB-INF/layouts/default.jspx'.] with root cause
org.apache.jasper.JasperException: /WEB-INF/views/homepage/index.jspx (line: 14, column: 6) The content of elements must consist of well-formed character data or markup.
Or let's say I need to loop through a List I get from my controller:
<c:forEach var="announcement" items="${results}">
<option value ="10"><c:out value="${announcement.author}"/></option>
</c:forEach>
Then I get this exception:
SEVERE: Servlet.service() for servlet [msa] in context with path [/msa] threw exception [Request processing failed; nested exception is org.apache.tiles.impl.CannotRenderException: ServletException including path '/WEB-INF/layouts/default.jspx'.] with root cause
org.apache.jasper.JasperException: /WEB-INF/views/homepage/index.jspx (line: 12, column: 54) The prefix "c" for element "c:forEach" is not bound.
I'm not sure why it's so difficult to make simple changes to this template file. After doing quite a bit of searching, I found that the syntax of .jspx files is different than that of .jsp files, and is not recommended for hand-editing. How do I configure Roo to use .jsp files instead? Is this even possible?
Edit: Here's an example of the whole file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:spring="http://www.springframework.org/tags" xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" version="2.0">
<jsp:directive.page contentType="text/html;charset=UTF-8"/>
<jsp:output omit-xml-declaration="yes"/>
<spring:message code="label_homepage_index" htmlEscape="false" var="title"/>
<util:panel id="title" title="${title}">
<spring:message code="application_name" htmlEscape="false" var="app_name"/>
<h3>
<spring:message arguments="${app_name}" code="welcome_titlepane"/>
</h3>
<div><span><p>Hello</p></span></div>
<c:forEach var="announcement" items="${results}">
<option value ="10"><c:out value="${announcement.author}"/></option>
</c:forEach>
</util:panel>
</div>
You can comment out the first example I gave to see the problem with the second. But the issue isn't really these specific cases, it's that I can't use regular HTML in my templates, which will make writing my pages much more difficult. How can I get around that?
Regarding your first example, it seems like you may have put your stuff in the wrong place. Maybe paste the whole file (it's short) so we can see if there's actually an error.
In the second example, the exception says "The prefix "c" for element "c:forEach" is not bound.". That usually means your xmlns prefix probably isn't declared in the jspx header.

Spring security + i18n = how to make it work together?

My first question here and i'll try to be specific. I am quite new to Spring and i'm trying to create quite simple reservation system (but this actually doesn't matter). What matters is that I am creating some basic template which i will then fill in by real webpages. Application works on hibernate,mysql, I also setup i18n and spring security. The poblem is that I cannot change my locale. The only thing which works is changing the default one.
First I browed Web A LOT and I found out that usage a i18n together with spring security is more complicated that usually. What i found out is that i need to have additional filter:
<filter>
<filter-name>localizationFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>localizationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
What I found out is that this filter is indeed processed before the security one however it does not parse the request in a form: http://someserver.com/bla/home?locale=en. I debugged it and it seems that it's not created for such purpose (and that's what I need).
This is taken from spring sample "contacts" however in this example I couldn't find any code that was actually targeting in changing the language. The effect is that it simply doesn't work. It always tries to change locale to my default one. The good news is that if in debug mode I manualy changed the locale-to-set to some other one it worked fine so i felt hope in my heart... ;-)
Then i've found some other way - by creating our own filter. What i did is to merge found example (don't remeber author) together with the way how RequestContextFilter is created. After all the RequestContextFilter works fine - just donest parse my requests. That's code of the new filter:
public class InternationalizationFilter extends OncePerRequestFilter {
#Override
public void destroy() {
// TODO Auto-generated method stub
}
#Override
protected void doFilterInternal(final HttpServletRequest request,
final HttpServletResponse response, final FilterChain filterChain)
throws ServletException, IOException {
final String newLocale = request.getParameter("locale");
if (newLocale != null) {
final Locale locale = StringUtils.parseLocaleString(newLocale
.toLowerCase());
LocaleContextHolder.setLocale(locale);
}
try {
filterChain.doFilter(request, response);
} finally {
LocaleContextHolder.resetLocaleContext();
}
}
}
As you can see the request paramter locale is parsed and the locale is set. There are 2 problems:
1. After sending request xxxxx?locale=en it creates Locale without "country" attribute (only language is set). To be honest I don't know if it's any problem - maybe not.
2. The more serious problem is that it doesn't work... i mean it's in the right place in the filter chain (before the security one), it produces right locale and sets it in exackly the same way like RequestContextFilter... but it simply doesnt work.
I would be very happy if someone could let me know how to make i18n work with spring-security basing on my example given or any other...
Thanks!
ADDITIONAL INFO:
I made some experiments and it seems that the Locale instance from request is somehow specific.
Look at this code (modified the RequestContextFilter class):
#Override
protected void doFilterInternal(final HttpServletRequest request,
final HttpServletResponse response, final FilterChain filterChain)
throws ServletException, IOException {
final ServletRequestAttributes attributes = new ServletRequestAttributes(
request);
final Locale l = Locale.GERMAN;
final Locale l2 = request.getLocale();
LocaleContextHolder.setLocale(l,
this.threadContextInheritable);
RequestContextHolder.setRequestAttributes(attributes,
this.threadContextInheritable);
if (logger.isDebugEnabled()) {
logger.debug("Bound request context to thread: " + request);
}
(...)
if to this method: LocaleContextHolder.setLocale(l, this.threadContextInheritable);
I pass locale 'l' it doesn't work at all. I mean the locale doesn't change even thou it's explicitly changed.
On the other hand if I pass there Locale 'l2' which is modified to german (in debug mode) it works fine!
This means that for some reason the Locale instance from request.getLocale() is somehow favored, maybe something is going on later on in the code which I don't know/understant...
Please let me know how should I use this i18n together with security cause I got to the point where I must admit that I have no idea what's going on...
-====-======-======--=======-====
FINAL SOLUTION/ANSWER (but still with little question)
Thanks to Ralph I managed to fix my issue. Previously I was going the wrong direction but the roo generated project pushed me forward.
It seems that I kept adding the interceptor in a wrong/not accurate way (previous code):
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
</bean>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="pl"/>
</bean>
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<ref bean="localeChangeInterceptor" />
</property>
</bean>
This way the interceptor was never invoked for some reason.
After changing interceptor def to:
<mvc:interceptors>
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
</bean>
</mvc:interceptors>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="pl"/>
</bean>
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
</bean>
... it started to work fine without any other changes to security/web.xml.
Now the problem is gone however I am not sure what happened. From what i understand in the second example (the one that works) I made the interceptor "global". But why the interceptor definded in the first example didn't work? Any hint?
Thanks again for help!
N.
After sending request xxxxx?locale=en it creates Locale without "country" attribute (only language is set).
It is the expected behaviour. In java there is some kind of hierarchy.
The language is more general then the country.
The idea behind is that you can have for example the text in the more common languge but some units (like currency) in the country specific files.
#see: http://java.sun.com/developer/technicalArticles/Intl/IntlIntro/
The more serious problem is that it doesn't work...
It should work without any hand made implementation!
You need to register the Local Change Interceptor, and need to set permitAll for the login page.
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" p:paramName="lang"/>
</mvc:interceptors>
<http auto-config="true" use-expressions="true">
<form-login login-processing-url="/resources/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t"/>
<logout logout-url="/resources/j_spring_security_logout"/>
<!-- Configure these elements to secure URIs in your application -->
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
</http>
To see this example running, create a roo project with that roo script:
// Spring Roo 1.1.5.RELEASE [rev d3a68c3] log opened at 2011-12-13 09:32:23
project --topLevelPackage de.humanfork.test --projectName localtest --java 6
persistence setup --database H2_IN_MEMORY --provider HIBERNATE
ent --class ~.domain.Stuff
field string --fieldName title
controller all --package ~.web
security setup
web mvc language --code de
web mvc language --code es
Then you must only change the security filters intersept-url patterns like I have shown above (applicationContext-security.xml)!
Now you have a application where the user can change its local via the local change interceptor in the application (when the user is logged in) as well as when he is not logged in (in the login page)
I had a similar issue with Localization when I was working with GWT app . The issue I noted was that when we map
<filter-mapping>
<filter-name>localizationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
to the filter, Even image requests are routed to the filter . These requests sometime leave out the locale parameter and hence when multiple requests hit the filter, the Locale parameter was not. Hence as soon as I received the locale parameter , I put it in a session . Log all the request headers and the values and you may find the root cause.

Resources