2009-08-24 32 views
14

¿Cuál es la mejor manera de establecer la zona horaria en Tomcat para una sola aplicación web? He visto opciones para cambiar los parámetros de línea de comandos o las variables de entorno para Tomcat, pero ¿hay alguna manera de configurarlo en el archivo WAR y no depender de ninguna configuración de Tomcat?¿Cómo configuro la zona horaria en Tomcat para una única aplicación web?

Editar: para enfatizar, estoy buscando una solución que pueda estar contenida dentro de un archivo WAR, no depende de la configuración de Tomcat. Para decirlo de otra manera, ¿puede una aplicación web configurarse para tener una zona horaria diferente a la de otras aplicaciones que se ejecutan en la misma instancia de Tomcat?

+0

Buena pregunta; Me estoy rascando la cabeza en una instalación de Tomcat que tengo donde las marcas de tiempo en los registros de Tomcat están una hora detrás de la hora del sistema. –

Respuesta

8

La única forma que he encontrado es para configurar un filtro y cambiar la zona horaria en el filtro,

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
     throws IOException, ServletException { 
    TimeZone savedZone = TimeZone.getDefault(); 
    TimeZone.setDefault(webappZone); 
    chain.doFilter(request, response); 
    TimeZone.setDefault(savedZone); 
} 

El setDefault() cambia la zona para el hilo. Entonces, todo lo que se ejecute en el hilo dentro del filtro tendrá una zona horaria predeterminada diferente. Tenemos que volver a cambiarlo porque otras aplicaciones comparten el hilo. También necesita hacer lo mismo para sus métodos init(), destroy() y cualquier otro hilo que pueda iniciar en su aplicación.

Tuve que hacer esto porque una biblioteca de terceros asume la zona horaria predeterminada y no tenemos el código fuente. Fue un desastre porque esto cambia la zona horaria del registro, pero no queremos iniciar sesión en horarios diferentes. La forma correcta de manejar esto es usar una zona horaria específica en cualquier valor de tiempo expuesto a los usuarios finales.

+3

Deberías usar try-finally para eso. Tenga en cuenta que cualquier subproceso creado durante el proceso heredará la zona horaria que se configuró en ese momento. Los futuros JRE pueden tener un comportamiento diferente y extraño. –

+0

Buena captura. Estoy de acuerdo en que esto puede romper con los JRE futuros porque no veo en ninguna parte del documento que el mensaje setDefault() solo afecte al hilo de llamada. Esto es un truco después de todo. No lo hagas a menos que tengas que hacerlo. –

+0

Espero que te des cuenta de que esto fallará en TIEMPO GRANDE si tienes varias aplicaciones web. La llamada a setDefault() cambia la zona horaria predeterminada para cada subproceso individual en la JVM. –

7

Establecer la variable de sistema a CATALINA_OPTS=-Duser.timezone=America/Denver

También puede especificar los CATALINA_OPTS en el TOMCAT_HOME $/bin/o catalina.sh% catalina.bat archivo bin \ TOMCAT_HOME% \ así.

Here's a list of acceptable timezones.

Source

+3

Esta solución cambiaría la zona horaria general para el servidor Tomcat; el autor de la pregunta quería establecer diferentes zonas horarias por aplicación web. –

7

EDIT: yo estaba equivocado acerca de esto. Esta edición lo corrige.

La respuesta es que no se puede portably establecer la zona horaria (predeterminada) para una sola aplicación web. Pero si está utilizando Java 6 (al menos), la clase java.util.TimeZone implementa los métodos de zona horaria predeterminados getDefault(), setDefault() y setDefault(TimeZone) utilizando un hilo heredable local. En otras palabras, llamar al setDefault() solo afecta el subproceso actual y los futuros subprocesos secundarios.

El comportamiento es no documentado en Sun Javadocs. Funciona para Java 6 y 5 (ver arriba), pero no hay garantías de que funcione en Sun JRE anteriores o posteriores. Sin embargo, me sorprendería mucho si Sun decidiera cambiar/revertir a un modelo 'global' para el TimeZone predeterminado. Rompería demasiadas aplicaciones existentes, y además los globales son MALOS.

+0

Los globales de aplicación son solo un poco peores que los globales globulares ... :) –

0

Echa un vistazo a SimpleTimeZone. Puede crear una instancia basada en una identificación de zona horaria y usarla para mostrar las fechas/horas utilizando esa zona horaria. Si quisiera, podría leer esa identificación desde un archivo de configuración específico del proyecto.

0

La mejor manera es modificar la aplicación web para que acepte la configuración de zona horaria explícita a través de web.xml en lugar de utilizar la zona horaria JVM predeterminada.

0
+0

** Responde algo en tu respuesta **, no solo pegues un enlace. De lo contrario, déjalo como comentario en la publicación de la pregunta. – XenoRo

+0

Su pregunta ha sido desestimada al menos una vez, la he votado por encima ya que su respuesta parece ser un mejor enfoque. Proporcione los puntos principales de esa URL en su respuesta, ya que seamfreamwork.org puede no estar siempre activo. – tomdemuyt

3

En el JDK 6, Sun/Oracle ha cambiado la implementación de zona horaria. En JDK 5.0, setDefault establece la zona horaria en una variable local de subproceso siempre y no a través de la JVM, lo que ocasionó algunos problemas. Sun reconoció esto como un error y lo corrigió en JDK 1.6.

En el JDK 1.6 en adelante (he comprobado el código fuente tanto para JDK 1.6 y JDK 1.7) si la JVM no se ha iniciado con un controlador de seguridad (o no se establece con System.SetsecurityManager()), setDefault método establece que a nivel mundial a través de la JVM y no de una manera específica de hilo. Si desea configurarlo solo para un hilo dado, entonces debe iniciar JVM con un administrador de seguridad.

Cuando inicie Tomcat JVM con un administrador de seguridad, debe proporcionar permisos individuales que no nos servían para nada, ya que estábamos retrasados ​​en el ciclo de publicación. Por lo tanto, en el archivo de política de seguridad proporcionamos todos los permisos y reemplazamos el administrador de seguridad JAVA predeterminado para denegar selectivamente el acceso de escritura de la zona horaria. Debido al problema de inicialización lenta con la clase Timezone, tuve que llamar al Timezone.getDefault() en el bloque estático que hace que la clase Timezone se inicialice antes de que el securityManager entre en juego.

Aquí está mi programa de prueba.

archivo test.policy --policy

grant { 
     permission java.security.AllPermission; 

}; 

- administrador de seguridad personalizado

import java.security.Permission; 
import java.util.TimeZone; 


public class CustomSecurityManager extends SecurityManager { 

static { 
    TimeZone.getDefault().getDisplayName(); 
} 



public CustomSecurityManager() { 
    super(); 
} 


public void checkPermission(Permission perm) throws SecurityException,NullPointerException 
{ 

      String propertyName = perm.getName(); 
      String actionName = perm.getActions(); 
      if(propertyName != null && actionName != null) 
      { 
       if(propertyName.equalsIgnoreCase("user.timezone") 
         && actionName.equalsIgnoreCase("write")) 
       { 
        throw new SecurityException("Timezone write is not permitted."); 
       } 

      } 

} 

}

- JVM inicio Parámetros

-Djava.security .manager = CustomSecurityManager -Djava.security.po lítica = C: /workspace/test/src/test.policy

0

Con Java 7/Tomcat 7, hay una solución/hack que permite al desarrollador establecer una zona horaria única por cada aplicación web. Tuvimos que implementar esto en nuestra aplicación, ya que tuvimos que admitir varias aplicaciones web que se ejecutan con diferentes zonas horarias predeterminadas en la misma JVM.

Otras soluciones que he visto en el desbordamiento de pila no resuelven completamente el problema.

  • Usar Timezone.setDefault() no funciona, porque cambia la zona horaria en la JVM.
  • El uso de filtros de servlet es completamente inseguro de subprocesos y no tiene en cuenta los subprocesos secundarios
  • El uso de enfoques de SecurityManager tampoco tiene en cuenta los problemas de zona horaria relacionados con hilos secundarios.

También investigó el código fuente de Java para el huso horario, he encontrado una manera de tener una zona horaria dinámica vuelto como la zona horaria predeterminada para todas las personas que llaman por la inyección de una implementación personalizada de la interfaz JavaAWTAccess. Esto se puede hacer mirando el cargador de clases Thread, y determinando el contexto real de la aplicación de Internet, y luego manejándolo de forma adecuada en función de algún nombre de aplicación web para el mapeo de la zona horaria.

Una vez más, esto es específico del servidor de aplicaciones, y debe hacerse de manera diferente para Tomcat, Jetty, Jboss, etc.Este enfoque también es específico de la implementación JVM (solo funciona en Oracle/Sun), pero creo que se puede extender a OpenJDK y otros.

Tenemos una solución de trabajo verificada para Oracle JDK 7 SE + Tomcat 7, implementada tanto en Windows como en Linux, que aloja varias aplicaciones web en diferentes zonas horarias.

+0

¿Cuál es la solución que ha utilizado con JDK7 + Tomcat 7? – Stauz

0

También puede utilizar un argumento de VM para definirlo

-Djdk.util.TimeZone.allowSetDefault=true 
Cuestiones relacionadas