jueves 8 de mayo de 2008

Me hago mayor?¿?¿



Pues sí, después de mucho tiempo detrás de una PDA, terminé comprándome una flamante HTC, con su flamante conexión móvil, su perfecto GPS, su completísima agenda...bien, pues entre todas esas funciones, ha terminado realizando una para la que no estaba preparada, como soporte para mis post-it de toda la vida.

Qué le voy a hacer, no soy nadie sin papel.

lunes 26 de noviembre de 2007

Reto FBI



Dando una vuelta por la web de kriptopolis he encontrado un reto de la web del FBI.
Es muy muy sencillo de sacar. ¿Os animáis a intentarlo?
El texto cifrado es el de la imagen anterior:
PIKODENHFENJIKM!
YIH QELB GDISBK
NQB PICB.
OI NI AGJ.OIL/PICB.QNT
MI WB SKIW,EKC
UFBEMB PIKMJCBD
E PEDBBD WJNQ
NQB AGJ


domingo 25 de noviembre de 2007

Enigma


Me gustaría compartir por aquí una página genial que simula una máquina de cifrado Enigma de tres rotores.
Enhorabuena a Frank Spieß , su creador.
La podéis disfrutar en: http://www.enigmaco.de/enigma/enigma.swf


miércoles 29 de agosto de 2007

¡La ñapa!


Un día tras varias semanas de aguantar unas obras de rehabilitación en el piso de al lado, mis padres hacen limpieza de fondos en el piso y mueven el mueble del comedor que da al piso donde se desarrollan estas obras, y OH, sorpresa!! Se encuentran la madre de todas las ñapas. A los paletas se les fue la mano, y para solucionar el boquete que habían hecho, metieron como pudieron la idem desde el otro piso para realizar esta obra maestra, digna de la más puntera ingeniería del siglo XXI´, como puede apreciarse en la foto.
Esto me ha hecho preguntarme, uno que es un poco friki y no puede evitar llevar todo a su terreno, cuántas “ñapas” ocultas de este tipo he visto en software a lo largo de mi vida. Detrás de espectaculares interfaces de usuarios, o como modo de salir del paso ante un bug, un apuro, un desfase de tiempo, o por un cambio de requisitos a varios días de una entrega... Seguro que todos conocéis unas cuantas, que escondidas entre miles de líneas de código, esperan latentes que a alguien se le ocurra hacer limpieza y dé un vistazo detrás del armario.
En el caso que nos ocupa, tanto mis padres como el promotor fueron razonables y llegaron a un acuerdo, pero es que sobraban palabras, era todo evidente. En el caso del Software, la cosa cambia un poco, no siempre se ven las cosas tan claras y hay cien maneras de , por lo menos, hacer dudar a un cliente en si sus quejas son fundamentadas.. Si tú le dices que el problema de su aplicación está en la “junta de la trócola”, probablemente, bien porque no tiene más remedio a esas alturas, o bien porque confía en tu profesionalidad, o simplemente por no quedarse como un idiota, no dirá nada, y pagará para que se la cambies. Por lo tanto es un campo abonado para los abusos de todo tipo, de empresas y comerciales sin escrúpulos que prometen el oro y el moro en plazos inverosímiles casi “para ayer”.y que obliga a muchos programadores a esconder la ñapa detrás de los armarios para llegar a tiempo.

viernes 17 de agosto de 2007

Lectura, escritura y copia de un mensaje en WCF y III

Tenemos varias opciones si queremos acceder al cuerpo del mensaje más de una vez; por ejemplo una sería copiarlo en un buffer, o bien otra, sería deserializar el cuerpo, cargarlo en algún objeto y trabajar a a través de él.
Pongo un ejemplo de la primera opción.
//creamos el objeto a serializar en el body
busObjeto mObjeto = new busObjeto ();

// si es necesario creamos los knowTypes
List knownTypes = new List();
knownTypes.Add(typeof(busObjeto1));
knownTypes.Add(typeof(busObjeto2));
knownTypes.Add(typeof(busObjeto3));

//creamos el serializador para la creacción del mensaje, pasándole el tipo que //llevará el bodyu, así como los tipos conocidos. Recordad que todos deben ser serializables.
System.Runtime.Serialization.DataContractSerializer mSerializador = new System.Runtime.Serialization.DataContractSerializer(typeof(busObjecto), knownTypes);

//creamos el mensaje
System.ServiceModel.Channels.Message mMensaje = System.ServiceModel.Channels.Message.CreateMessage(System.ServiceModel.Channels.MessageVersion.Soap12WSAddressing10, "Action", mObjeto, mSerializador);

//uso de buffers para realizar acciones con el mensaje
//copiamos el mensaje en un buffer
MessageBuffer buffer = mMensaje.CreateBufferedCopy(65000);

//a través del buffer podemos crear el mensaje las veces que necesitemos (será una copia del original)
System.ServiceModel.Channels.Message mMensajeCopiado = buffer.CreateMessage();
System.ServiceModel.Channels.Message mMensajeCopiado2 = buffer.CreateMessage();

//cerramos el buffer
buffer.Close();

//trabajamos con la copia del mensaje que hayamos creado desde el this.textBoxEstado.Text = this.textBoxEstado.Text + "Enviado mensaje envio al servicio " + mMensajeCopiado.GetBody().GetType().Name + System.Environment.NewLine;

// y así las veces que necesitemos
cliente.RecogerEnvioMensaje(mMensajeCopiado2);

El método CreateBufferedCopy lo tenéis en System.ServiceModel.Channels.Message.
public MessageBuffer CreateBufferedCopy(int maxBufferSize){
if (maxBufferSize < 0) {
throw TraceUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxBufferSize", maxBufferSize, SR.GetString("ValueMustBeNonNegative")), this);
}
switch (this.state) {
case MessageState.Created:
this.state = MessageState.Copied;
if (DiagnosticUtility.ShouldTraceVerbose) { TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.MessageCopied, this, this);
}
return this.OnCreateBufferedCopy(maxBufferSize);
case MessageState.Read:
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageHasBeenRead")), this);

case MessageState.Written:
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageHasBeenWritten")), this);

case MessageState.Copied:
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageHasBeenCopied")), this);

case MessageState.Closed:
throw TraceUtility.ThrowHelperError(this.CreateMessageDisposedException(), this);
}

throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("InvalidMessageState")), this);}

Comentar por encima por si tenéis curiosidad que en la clase System.ServiceModel.SR tenéis las cadenas con los literales que usa WCF para los mensajes de error y de información para su uso interno. Por ejemplo, InvalidMessageState.
Enlaces de interés
http://msdn.microsoft.com/msdnmag/issues/07/04/ServiceStation/default.aspx?loc=es#S6

jueves 16 de agosto de 2007

Lectura, escritura y copia de un mensaje en WCF II

En esta segunda entrada sobre los mensajes en WCF vamos a dar un paseo por los distintos estados de un mensaje, el control de los mismos y donde se encuentra situado en el código este control.

Created
El mensaje pasa a ese estado cuando es creado de diversas maneras. Tanto a través del método estático de la clase Message: System.ServiceModel.Channels.Message.CreateMessage, como del méetodo CreateMessage de la clase MessageBuffer. Sinceramente, he estado navegando por las clases del NameSpace ServiceModel y no he encontrado el momento exacto donde se establece este estado, por lo que si alguien lo sabe, estaría agradecido de que me lo comentase. Intuyo que debe estar por la clase BufferedMessage y relacionadas.

Closed
Este cambio de estado se produce en el método Close() de la clase Message. No hay más misterio.

Written
Cuando llamamos al método expuesto por el servicio a través de nuestro cliente Proxy; este mensaje pasa por la pila de canales y eso supone pasar por el elemento encoder, que por lo tanto, llamará al método WriteMessage para escribir el mensaje en el buffer que pasará al canal de transporte para su envío por red., Por lo tanto el método WriteMessage pasará el estado del mensaje a Written, por lo que cualquier intento posterior de lectura no será posible provocando el error correspondiente.Este método tratará todo el mensaje completo.
El código en System.ServiceModel.Channels.Message:
public void WriteMessage(XmlDictionaryWriter writer){
if (writer == null) {
throw TraceUtility.ThrowHelperError(new ArgumentNullException("writer"), this);
}
switch (this.state) {
case MessageState.Created:
this.state = MessageState.Written;
if (DiagnosticUtility.ShouldTraceVerbose) {
TraceUtility.TraceEve TraceEventType.Verbose,TraceCode.MessageWritten, this);
}
this.OnWriteMessage(writer); return;

case MessageState.Read:
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageHasBeenRead")), this);

case MessageState.Written:
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageHasBeenWritten")), this);

case MessageState.Copied:
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageHasBeenCopied")), this);

case MessageState.Closed:
throw TraceUtility.ThrowHelperError(this.CreateMessageDisposedException(), this);
}
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("InvalidMessageState")), this);}

El método WriteBodyContents también genera un cambio de estado a Written. Se trata también de un método público de la clase Message. A diferencia del anterior, aquí sólo trataremos con el cuerpo del mensaje.
El código en System.ServiceModel.Channels.Message:
public void WriteBodyContents(XmlDictionaryWriter writer){
if (writer == null) {
throw TraceUtility.ThrowHelperError(new ArgumentNullException("writer"), this);
}
switch (this.state) {
case MessageState.Created:
this.state = MessageState.Written;
if (DiagnosticUtility.ShouldTraceVerbose) { TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.MessageWritten, this);
}
this.OnWriteBodyContents(writer); return;

case MessageState.Read:
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageHasBeenRead")), this);

case MessageState.Written:
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageHasBeenWritten")), this);

case MessageState.Copied:
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageHasBeenCopied")), this);

case MessageState.Closed:
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(this.CreateMessageDisposedException());
}
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("InvalidMessageState")), this);}

Read
El cambio a estado Read se producirá en GetReaderAtBodyContents, el cual es llamado a su vez por GetBody, por lo que, como comenté antes, el hecho de acceder al cuerpo de un mensaje, supondrá un cambio de estado en el mismo.
El código en System.ServiceModel.Channels.Message :
public XmlDictionaryReader GetReaderAtBodyContents(){
switch (this.state) {
case MessageState.Created:
this.state = MessageState.Read;
if (DiagnosticUtility.ShouldTraceVerbose) {
TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.MessageRead, this);
}
if (this.IsEmpty) {
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageIsEmpty")), this);
}
return this.OnGetReaderAtBodyContents();

case MessageState.Read:
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageHasBeenRead")), this);

case MessageState.Written:
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageHasBeenWritten")), this);

case MessageState.Copied:
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageHasBeenCopied")), this);

case MessageState.Closed:
throw TraceUtility.ThrowHelperError(this.CreateMessageDisposedException(), this);
}
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("InvalidMessageState")), this);}

Copied
El cambio a Copied, se produce en el método CreateBufferedCopy, el cual comento al final del artículo como una manera de poder acceder al cuerpo de un mensaje repetidamente.
A tener en cuenta, que el mensaje a partir del que se llama al método queda en estado Copied, pero el objeto que devuelve, MessageBuffered, nos permitirá clonar el menaje tantas veces como y todos estas copias estarán en estado Created.
El código en System.ServiceModel.Channels.Message :
public MessageBuffer CreateBufferedCopy(int maxBufferSize)
{
if (maxBufferSize <>

throw TraceUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxBufferSize", maxBufferSize, SR.GetString("ValueMustBeNonNegative")), this);
}
switch (this.state) {
case MessageState.Created:
this.state = MessageState.Copied;
if (DiagnosticUtility.ShouldTraceVerbose) {
TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.MessageCopied, this, this);
}
return this.OnCreateBufferedCopy(maxBufferSize);

case MessageState.Read:
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageHasBeenRead")), this);

case MessageState.Written:
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageHasBeenWritten")), this);

case MessageState.Copied: throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageHasBeenCopied")), this);

case MessageState.Closed: throw TraceUtility.ThrowHelperError(this.CreateMessageDisposedException(), this);
}

throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("InvalidMessageState")), this); }

En el último post, veremos una posible solución a este tema.

miércoles 15 de agosto de 2007

Lectura, escritura y copia de un mensaje en WCF I

Un mensaje de WCF es de un solo uso. ¿Qué quiere decir esto? Que sólo se puede acceder para realizar alguna acción sobre el mismo, ya sea de lectura, escritura o copia, cuando está creado y no se ha realizado anteriormente alguna de estas acciones sobre él.
Si por ejemplo, en algún proceso se intenta obtener el “Body” del mensaje, esto implicará una lectura del mismo, por lo que cualquier otro intento de lectura producirá el error: System.InvalidOperationException, indicándonos que el mensaje ya ha sido leído, Esto sucederá incluso en el caso de que se produzca algún tipo de error durante la lectura como podría ser un error de conversión en el tipo recibido durante el acceso al cuerpo del mensaje, porque como veremos más adelante, lo primero que hace ante una operación sobre el mensaje es comprobar su estado actual y si este es correcto o mejor dicho, adecuado, el siguiente paso es cambiarle al estado que corresponda.

Pueden producir este error varias acciones que llevemos a cabo en el mensaje, por ejemplo:
Dos llamadas consecutivas al método del mensaje, GetBody. volver a pasar el mensaje por la pila de canales para su reenvío a otro servicio mediante un cliente Proxy, si después de acceder al mensaje con GetBody, lo pasamos como parámetro en algún método del servicio; las posibilidades son muchas, en cualquier caso, el hecho común es intentar acceder al mensaje más de una vez.

El motivo de esta implementación del objeto Message, es que pueda admitir stream, por lo que de esta manera se garantiza que sólo se procese una vez.


La propiedad a a través de la cual WCF controla esta situación es State, la cual puede tomar los siguientes valores. Creado, Leido, Escrito, Copiado, y cerrado, que determinará que operaciones se pueden o no se pueden realizar con el mensaje.
La enumeración que nos proporciona los valores de esta propiedad es la siguiente:
Se encuentra en System.ServiceModel.Channels

Public enum MessageState
{
Created,
Read,
Writen,
Copied,
Closed
}
Obviamente la propiedad State hace que sea posible determinar en tiempo de ejecución si el cuerpo de un Message particular ya se ha consumido (cuando ya no está en estado Created) y cómo se consumió (si se leyó, escribió o copió).

Esta propiedad hace posible que en cualquier momento de la ejecución de nuestra aplicación, podamos saber si el mensaje ya ha sido tratado y que se hizo con el mismo, es decir, si se copió, escribió, etc.El único estado correcto que nos permitirá acceder al cuerpo del mensaje, ya sea para leer, escribir o copiar, será el estado Created.