jueves, 26 de septiembre de 2013

Java y los certificados (HTTPS)

Please, see that:

1. http://alvinalexander.com/java/java-using-keytool-genkey-private-key-keystore
2. http://www.dotkam.com/2008/04/22/creating-public-and-private-certificateskeys/
3. http://alvinalexander.com/java/java-using-keytool-import-certificate-keystore

See also:

http://www.mkyong.com/tomcat/how-to-configure-tomcat-to-support-ssl-or-https/
http://www.thegeekstuff.com/2011/09/ssl-for-tomcat-server/
http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=SSLenTomcat

Muy sencillo bueno y cortito...
http://aprenderdiaadia.wordpress.com/2011/07/23/keystore-truststore/


Ejemplo:

-----------------------
-----------------------
CONFIGURANDO EL SERVER
-----------------------
-----------------------
1)
keytool.exe -genkey -alias smkeystore -keyalg RSA
=> esto me lo tira en el directorio del usuario como .keystore

keytool -genkey -alias smkeystore -keyalg RSA -keystore c:\mkyongkeystore
=> pass: gemalto50

keytool.exe -list -keystore e:\tomcatkeystores

2)
server.xml:

   <!-- Define a SSL HTTP/1.1 Connector on port 8443
         This connector uses the JSSE configuration, when using APR, the
         connector should be using the OpenSSL style configuration
         described in the APR documentation -->  

  <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS"
  keystoreFile="e:/CERTIFICADOS_SERVER/smkeystore"
  keystorePass="xxx" />


Listo: probar https://localhost:8443/

De esta menera activamos el HTTPS al tomcat.

-----------------------
-----------------------
CONFIGURANDO EL CLIENTE
-----------------------
-----------------------
Para esto necesitamos generar un certificado o bien, bajarlo del servidor
Finally (and perhaps the most important), you need to export the self-signed certificate you've generated on the server side
(only the certificate, not the private key) and import it into the keystore you use as a trust store on the client side.

3)
Generamos el certificado

Opcion 1:

Con esto exportamos el certificado q esta dentro del keystore creado anteriormente:
keytool.exe -export -keystore e:\tomcatkeystores -alias smkeystore -file tomcatcer.crt

Opcion 2:

ingresamos a https://localhost:8443
file > properties > certificates > details > copy file > con esto exportamos el certificado de otra manera (sin el keytool de java)

4)
Importamos el certificado al keystore (lo importo en mi propio keystore (porque este va a estar en la PC cliente))

keytool.exe -import -file e:\tomcatcer.crt -keystore e:\tomcatkeystores -storepass xxxx12 (esta clave no tiene que se la misma que se genero cuando generamos el keystore del lado server)



lunes, 26 de agosto de 2013

LOG4j - 2

Ejemplo de como configurar log4j para loguear con varios appenders:

##############################################################
Ejemplo de un properties:

log4j.rootLogger=DEBUG , CONSOLE

log4j.logger.stdout=DEBUG, stdout
log4j.logger.org.springframework=INFO, stdout
log4j.logger.org.apache=INFO, stdout
log4j.logger.httpclient=INFO, stdout
log4j.logger.cdr=INFO, cdr

log4j.appender.stdout=org.apache.log4j.FileAppender
log4j.appender.stdout.File=src/test/resources/Ejemplo-1.log
log4j.appender.stdout.append=true
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern= %d %5p [%t] (%F:%L)- %m%n

log4j.appender.cdr=org.apache.log4j.FileAppender
log4j.appender.cdr.File=src/test/resources/cdr.log
log4j.appender.cdr.append=true
log4j.appender.cdr.layout=org.apache.log4j.PatternLayout
log4j.appender.cdr.layout.ConversionPattern= %d %5p [%t] (%F:%L)- %m%n

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d %-5p %c %x - %m%n
#################################################################

En este caso tenemos 5 loggers, que escriben en 2 archivos (stdout y cdr). Para el resto se utiliza la consola.
Los primeros 4 escriben en : src/test/resources/Ejemplo-1.log y el ultimo es un CDR que escribe en : cdr.log

También tenemos otro appnder llamado CONSOLE que es utilizado para loguear todo lo que no este en los loguers ya definidos (los 5 que tenemos definidos)

viernes, 14 de junio de 2013

WSDL - Contract-first Web Services

Muchas veces queremos a partir de un wsdl generar el WS (server) y respetar la estructura del WSDL
Para esto, tenemos que entender como es el WSDL (estructura), para lo cual compartimos estos links:

http://orangeslate.com/2009/06/15/creating-contract-first-web-services-using-cxf-top-down-approach-part-1-creating-xsds/

http://orangeslate.com/2009/06/15/creating-web-services-using-cxf-contract-first-approach-part-2-wsdl-creation/

http://soa.sys-con.com/node/143909

Importante:

Cuando generamos las clases (utilizando por ejemplo wsdlToJava de CXF o wsimport de la JDK 6) a partir de un WSDL (tecnica conocida como wsdl contract-first), tenemos que dejarlas tal cual están y ademas tenemos que generar la clase que tiene la estructura de la implementacion del servicio respetando todas las anotaciones, incluyendo la de wsdlLocation (ej: serviceImpl.java). En esta anotación (wsdlLocation), vamos a tener que modificar el PATH a absoluto (/wsdl/ejemplo.wsdl) apuntando al wsdl que utilizamos para generar las clases, para que cuando deployemos el WS, este exponga el mismo WSDL que utilizamos para generar las clases.

Por ejemplo, si nuestra implementacion de WS queda sin la anotación targetNameSpace y la interface la tiene apuntando a una URL determinada, nos va a pasar que cuando deployemos el WS, el WSDL generado dinamicamente va a tener un include a otro WSDL a traves del tag wsdl:import. Esto sucede porque la interface del WS y la implememtacion tienen diferentes targetNameSpaces.

Es por esto y otras cosas mas que siempre es conveniente no tocar las clases generadas mediante los comandos wsdlToJava o wsimport.

Otra alternativa es utilzar SOAPUI para generar las clases.

lunes, 8 de abril de 2013

Maven & Aplicaciones Standalone (JARs)

Ver este link:

http://maven.apache.org/plugins/maven-jar-plugin/examples/manifest-customization.html

If you want to make a standalone jar (ie one with no dependencies) executable, here’s how you do it:

<plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <mainClass>com.yourcompany.YourClass</mainClass>
            </manifest>
         </archive>
       </configuration>
    </plugin>
  </plugins>

If however you have dependencies, you will probably want to bundle them into a single jar, otherwise making it executable is not very helpful. You can use the assembly plugin to do it like this:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
    <executions>
      <execution>
         <goals>
           <goal>attached</goal>
         </goals>
         <phase>package</phase>
         <configuration>
           <descriptorRefs>
             <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <archive>
            <manifest>
              <mainClass>com.yourcompany.YourClass</mainClass>
            </manifest>
          </archive>
        </configuration>
     </execution>
  </executions>
</plugin>

De esta menera, ademas de crear el JAR sin dependencias vamos a ver que nos crea un JAR con dependencias donde todas las dependencias las agrega como clases (prueba-tools-1.0-SNAPSHOT-jar-with-dependencies.jar). 

miércoles, 27 de marzo de 2013

AXIS & Maven

Vamos a dejar los pasos necesarios para crear un web service utilizando una tecnología vieja como AXIS:

1. Creamos un arquetipo web con maven

mvn archetype:generate -DgroupId=com.ws -DartifactId=WSProject -DarchetypeArtifactId=maven-archetype-webapp


2. Luego creamos la clase que sera la interface del WS

public interface Calculator {
    int add (int x, int y);
    int subtract(int x, int y);
}


3. Luego creamos el WSDL en base a dicha clase

Armamos una carpeta con los libs del proyecto AXIS, ej E:\cliente_prueba y ahi tiramos todos los libs de dicho proyecto que podemos descargar desde apache

E:\cliente_prueba>set classpath=%CLASSPATH%;axis.jar;axis-ant.jar;commons-discovery-0.2.jar;commons-logging-1.0.4.jar;jaxrpc.jar;log4j-1.2.8.jar;saaj.jar;wsdl4j-1.5.1.jar;e:\cliente_prueba

E:\cliente_prueba>java org.apache.axis.wsdl.Java2WSDL -o prueba.wsdl -n urn:org.axis.ws -l http://localhost:8080/axis/services/calculator org.axis.ws.Calculator


4. Luego con el wsdl (prueba.wsdl) podemos generar las clases necesarias

E:\cliente_prueba>java org.apache.axis.wsdl.WSDL2Java -s prueba.wsdl

Entre las clases que genera, vamos a tener una llamada: CalculatorSoapBindingImpl y es esta la que va a tener nuestra implementacion del WS.

Algunos tips:

o – output folder -> src
p – package for generated classes -> org.kamal.wssample.ws.generated
s – generate server side classes as well


5. Luego agregamos dichas dependencias en el POM

<!-- AXIS dependency  -->

<dependency>
<groupId>axis</groupId>
<artifactId>axis-jaxrpc</artifactId>
<version>1.4</version>
</dependency>

<dependency>
<groupId>org.apache.axis</groupId>
<artifactId>axis</artifactId>
<version>1.4</version>
</dependency>

<dependency>
<groupId>commons-discovery</groupId>
<artifactId>commons-discovery</artifactId>
<version>0.2</version>
</dependency>

<dependency>
<groupId>axis</groupId>
<artifactId>axis-wsdl4j</artifactId>
<version>1.5.1</version>
</dependency>

<dependency>
<groupId>axis</groupId>
<artifactId>axis-saaj</artifactId>
<version>1.4</version>
</dependency>


6. Luego agregamos el server-config.wsdd dentro de /WEB-INF/


Para que nuestro servicio web se despliegue automáticamente cuando hagamos el despliegue del WAR en nuestro servidor de aplicaciones, deberemos crear un archivo llamado server-config-wsdd dentro de la carpeta /WEB-INF. Este archivo indicará al servidor de aplicaciones que clases definen un WS y como están configuradas. Además será donde se pueda integrar cualquier tipo de configuración y manejadores (handlers) para los WS.

La parte que engloba la etiqueta service del archivo wsdd es lo que importa. Lo demás es fijo para todos los WS que hagamos. Si queremos desplegar más de un WS en un mismo WAR, debemos añadir más etiquetas service a nuestro descriptor server-config.wsdd.

<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">

<globalConfiguration>
<parameter name="adminPassword" value="admin"/>
<parameter name="attachments.Directory" value="D:\Tomcat5.0\webapps\axis\WEB-INF\attachments"/>
<parameter name="sendMultiRefs" value="true"/>
<parameter name="sendXsiTypes" value="true"/>
<parameter name="attachments.implementation" value="org.apache.axis.attachments.AttachmentsImpl"/>
<parameter name="sendXMLDeclaration" value="true"/>
<parameter name="axis.sendMinimizedElements" value="true"/>
<parameter name="axis.enableListQuery" value="false"/>

<requestFlow>
<handler type="java:org.apache.axis.handlers.JWSHandler">
<parameter name="scope" value="session"/>
</handler>
<handler type="java:org.apache.axis.handlers.JWSHandler">
<parameter name="scope" value="request"/>
<parameter name="extension" value=".jwr"/>
</handler>
</requestFlow>
</globalConfiguration>

<handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/>
<handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/>
<handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/>

<service name="AdminService" provider="java:MSG">
<parameter name="allowedMethods" value="AdminService"/>
<parameter name="enableRemoteAdmin" value="false"/>
<parameter name="className" value="org.apache.axis.utils.Admin"/>
<namespace>http://xml.apache.org/axis/wsdd/</namespace>
</service>

<service name="Version" provider="java:RPC">
<parameter name="allowedMethods" value="getVersion"/>
<parameter name="className" value="org.apache.axis.Version"/>
</service>

<service name="CalcService" provider="java:RPC" style="wrapped" use="literal">
   <operation name="add" qname="ns15:Add" returnQName="ns15:result" returnType="xsd:int" xmlns:ns15="http://simbit.com/simsave1.0/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<parameter qname="ns15:in0" type="xsd:int"/>
<parameter qname="ns15:in1" type="xsd:int"/>
</operation>

<operation name="subtract" qname="ns15:Subtract" returnQName="ns15:result" returnType="xsd:int" xmlns:ns15="http://simbit.com/simsave1.0/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<parameter qname="ns15:in0" type="xsd:int"/>
<parameter qname="ns15:in1" type="xsd:int"/>
</operation>

<parameter name="allowedMethods" value="add subtract"/>
<parameter name="wsdlPortType" value="Calculator"/>
<parameter name="className" value="org.axis.ws.generated.CalculatorSoapBindingImpl"/>
<parameter name="wsdlServicePort" value="CalcService"/>
<parameter name="wsdlTargetNamespace" value=""/>
<parameter name="wsdlServiceElement" value="CalculatorService"/>

</service>

<transport name="http">
<requestFlow>
<handler type="URLMapper"/>
<handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/>
</requestFlow>
</transport>

<transport name="local">
<responseFlow>
<handler type="LocalResponder"/>
</responseFlow>
</transport>

</deployment>


7. Modificamos el WEB:XML y agregamos una seccion de AXIS:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <!-- Axis section -->
<display-name>Apache-Axis</display-name>
<servlet>
<servlet-name>AxisServlet</servlet-name>
<display-name>Apache-Axis Servlet</display-name>
<servlet-class> org.apache.axis.transport.http.AxisServlet
</servlet-class>
</servlet>
<servlet>
<servlet-name>AdminServlet</servlet-name>
<display-name>Axis Admin Servlet</display-name>
<servlet-class> org.apache.axis.transport.http.AdminServlet
</servlet-class>
<load-on-startup>100</load-on-startup>
</servlet>
<servlet>
<servlet-name>SOAPMonitorService</servlet-name>
<display-name>SOAPMonitorService</display-name>
<servlet-class> org.apache.axis.monitor.SOAPMonitorService
</servlet-class>
<init-param>
<param-name>SOAPMonitorPort</param-name>
<param-value>5001</param-value>
</init-param>
<load-on-startup>100</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/servlet/AxisServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>*.jws</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>SOAPMonitorService</servlet-name>
<url-pattern>/SOAPMonitor</url-pattern>
</servlet-mapping>

</web-app>

8. Listo, levantamos el tomcat y en por ejemplo http://localhost:8081/WSAxisProject/services vamos a ver el ws desplegado.

NOTA: Si lo levantamos con un tomcat 6 la primera vez que listamos los servicios va a lanzar un error que no se sabe porque pero anda a la perfeccion. En cambio con Tomcat 5 no lanza dicho error. El error tiene pinta que sale mediant eun system.out.println y no por logs

java.lang.NoClassDefFoundError: org/apache/axis/deployment/wsdd/WSDDProvider
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$000(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1667)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at org.apache.axis.deployment.wsdd.WSDDProvider.loadPluggableProviders(WSDDProvider.java:106)
at org.apache.axis.deployment.wsdd.WSDDProvider.<clinit>(WSDDProvider.java:74)
at org.apache.axis.deployment.wsdd.WSDDService.makeNewInstance(WSDDService.java:437)
at org.apache.axis.deployment.wsdd.WSDDDeployment.getDeployedServices(WSDDDeployment.java:503)
at org.apache.axis.configuration.FileProvider.getDeployedServices(FileProvider.java:296)
at org.apache.axis.transport.http.AxisServlet.reportAvailableServices(AxisServlet.java:482)
at org.apache.axis.transport.http.AxisServlet.doGet(AxisServlet.java:260)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at org.apache.axis.transport.http.AxisServletBase.service(AxisServletBase.java:327)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: org.apache.axis.deployment.wsdd.WSDDProvider
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 37 more


9. Se podrá descargar el proyecto en:

https://gwt-spring-hibernate-maven.googlecode.com/svn/trunk/WSAxisProject




jueves, 24 de enero de 2013

Fechas en Java

Varios links utiles:

http://www.devrecipes.com/2010/02/14/datetimetimezone-manipulation-and-conversion-in-java-a-few-examples/

http://brian.pontarelli.com/2011/08/16/database-handling-for-timezones/

http://stackoverflow.com/questions/12008801/in-the-oracle-jdbc-driver-what-happens-to-the-time-zone-when-you-write-a-java-d


El siguiente link explica claramente y con ejemplo de BD como actúan los timezones y la conveniencia de insertar los registros en BD en UTC sin ningun timezone por defecto:

http://ooxs-be.goracer.nl/EN/java/Java%20and%20Date.html


".... A user John in New York enters a date/time for a planned teleconference with his colleague Mark in Brussels. He types 2009-07-06 09:30 , the application parses that to a Date - containing a long value of 1246887000000. This Date represents 14:30 UTC . It is inserted as such in the database.

On the other side of the Atlantic ocean, Mark checks the date of the planned meeting, the application reads the date from the database - it still represents 14:30 UTC and contains the same long value of 1246887000000. Mark's session contains a formatter that formats this date to 2009-07-06 15:30

The basic point is that each user's session contains a SimpleDateFormat , configured to the time zone of that particular user and parses or formats localized string representations of the actual (UTC) date in the database........."


"....Databases have some support for working with date/time values taking into account the existence of timezones. Most support is focused on interpreting and showing date/time in the timezone of the 'user' or connection. The fact that in a typical architecture, database connections are shared between application users, changing timezones per connection is not a feasible approach
There are no substantial differences. I still recommend to convert everything to UTC before updating or inserting values to the database..."


"... Oracle supports TIMESTAMP WITH TIME ZONE and TIMESTAMP WITH LOCAL TIME ZONE that enable input and output taking time zones into consideration...."

y por ultimo:

"... If the column is declared as a TIMESTAMP and not, say, a TIMESTAMP WITH TIME ZONE or TIMESTAMP WITH LOCAL TIME ZONE, the timestamp that is stored in the table will not have a time zone component. As a result, SYS_EXTRACT_UTC (http://psoug.org/definition/SYS_EXTRACT_UTC.htm) will convert the timestamp to UTC using the session time zone which is something that is controlled by the client and may be different on different client machines. I suspect that if you run

from your OCCI application and from your SQL*Plus session that you will end up with different results which is causing the strings returned to be different.

If you want the string that is returned to be independent of the client machine, I would tend to suggest storing the time zone in the database column. Is changing the schema definition to use a TIMESTAMP WITH TIME ZONE an option? Barring that, you could ensure that every client machine has the same time zone configured and/or run an explicit ALTER SESSION, i.e. ...."


Texto extraído de aqui: http://stackoverflow.com/questions/3629603/oracle-timestamp-utc-time-format-problem


Ejemplo basico:


Calendar c1 = Calendar.getInstance();
c1.set(Calendar.DAY_OF_MONTH, 1);
c1.set(Calendar.MONTH, 1);
c1.set(Calendar.YEAR, 2013);
c1.set(Calendar.HOUR_OF_DAY, 10);
c1.set(Calendar.MINUTE, 00);
c1.set(Calendar.SECOND, 00);
c1.setTimeZone(TimeZone.getTimeZone("GMT-0"));
System.out.println(c1.getTimeZone());
System.out.println(c1.getTime());
System.out.println("c1.getTimeInMillis() : " + c1.getTimeInMillis());

sun.util.calendar.ZoneInfo[id="GMT-00:00",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null] Fri Feb 01 07:00:00 ART 2013 c1.getTimeInMillis() : 1359712800572

Calendar c1 = Calendar.getInstance();
c1.set(Calendar.DAY_OF_MONTH, 1);
c1.set(Calendar.MONTH, 1);
c1.set(Calendar.YEAR, 2013);
c1.set(Calendar.HOUR_OF_DAY, 07);
c1.set(Calendar.MINUTE, 00);
c1.set(Calendar.SECOND, 00);
c1.setTimeZone(TimeZone.getTimeZone("GMT-3"));
System.out.println(c1.getTimeZone());
System.out.println(c1.getTime());
System.out.println("c1.getTimeInMillis() : " + c1.getTimeInMillis());
sun.util.calendar.ZoneInfo[id="GMT-03:00",offset=-10800000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null] Fri Feb 01 07:00:00 ART 2013 c1.getTimeInMillis() : 1359712800590

Como vemos son iguales salvo los 3 últimos números. Estos 3 últimos números siempre varían en cada prueba que lancemos..

En cambio, si ambos calendars tienen la misma fecha, los milisegundos son distintos.

Aqui dejamos una pagina muy util para el calculo de las fechas:

http://www.ruddwire.com/handy-code/date-to-millisecond-calculators/


IMPORTANTE

Si yo creo dos objetos calendar y le seteo la MISMA fecha (ej 05/11/1980 a las 12hs) a ambos pero distintos timezones (12hs en Argentina y 12hs en Italia), cuando les pida los milisegundos a ambos, dichos milisegundos TIENEN que ser DISTINTOS porque no es el mismo tiempo transcurrido desde 1970.  

Es decir, a las 12hs Italia en la Argentina son las 8hs AM y viceversa, con lo cual, el tiempo que transcurrió desde el 1 de enero de 1970 hasta las 12hs de Argentina es el mismo que el tiempo que transcurrió hasta las 8hs Italia. Pero no es el mismo tiempo transcurrido hasta las 12hs de Argentina y 12hs de Italia.

Esto mismo ocurre cuando tenemos que leer una fecha de una BD.  Si con diferentes timezones (ejemplo, con timezone argentino y de venenzuela) leemos la misma fecha (es decir, que el método getTimestamp() del resultset de jdbc nos devuelve la misma fecha en ambos casos),  los milisegundos transcurridos serán distintos (idem ejemplo anterior entre argentina e italia).

Ahora bien, si en caso que la fecha que se esta leyendo (la misma) en diferentes paises (con diferentes timezones), varia según el timezone, obviamente los milisegundos transcurridos TIENEN QUE SER LOS MISMOS