AjCoRe, un simple Repositorio de Contenido (2) Almacenando en Stores

Published on Author lopezLeave a comment

Anterior Post

En mi semana sabática hice algunos avances en mi proyecto de código abierto AjCore, una implementación simple de un repositorio de contenido escrito en C#:

https://github.com/ajlopez/AjCoRe

Si Content Repository es un nuevo concepto para Uds., pueden ver mis enlaces http://delicious.com/ajlopez/contentrepository y la introducción al tema escrita por Roy Fielding JSR-170 overview .

Los conceptos principales: hay Workspaces. Cada workspace tiene un Root Node (nodo raíz). Cada Node puede tener Child Nodes (nodos hijos), y Properties. Una Property tiene un Name y un Value:

En el diagrama de arriba, nodos y espacios de trabajo están represetnados por interfaces. La idea es tener diferentes implementaciones de esas abstracciones. En mi anterior post presenté dos implementaciones: una representando un sistema de archivos/directorios, permitiendo solamente operaciones de lecturas. Y otra implementación, más extensible, usando nodos arbitrarios en memoria. Desde entonces, agregué el soporte de grabar y recuperar nodos arbitrarios usando un almancén, un lugar de persistencia.

Ahora, el proyecto está así:

donde:

A: Es la implementación de las clases concretas de workspaces y nodes en memoria, con el nuevo soporte OPCIONAL de tener un store.

B: La implementación de solo lectura de espacio de trabajo representando un directorio, donde los nodos son más directorios y archivos.

C: El nuevo IStore (abstracto) y la primer implementación concreta, usando una jerarquía de directorios y archivos XML para persistir las propiedades de un nodo.

D: El soporte de transacciones que dura la vida de una sesión.

Veamos las nuevas capacidades de almacenamiento. La interfaz  Stores.IStore:

public interface INode
{
    string Name { get; }
    INode Parent { get; }
    PropertyList Properties { get; }
    NodeList ChildNodes { get; }
    string Path { get; }
}

Stores.Xml.Store es la primer implementación de esta abstracción. Uds. podrían agregar otras, por ejemplo usando JSON, una base de datos relacional, o un NoSQL. Pueden crear, remover nodos y actualizar sus propiedades, dentro de una sesión, igual que en el anterior posts. Pero ahora, el espacio de trabajo puede ser inyectado con una implementación de IStore, que comienza a usarse entonces automáticamente. Ejemplo (ver más detalle en el código de los tests):

// Reference store in a directory
Store store = new Store("c:\\myworkspace");
// Workspace using that store to retrieve root node and their descendant
// (lazy loading)
Workspace workspace = new Workspace(store, "myws");
// Session accesing that workspace
Session session = new Session(workspace);
// You can use session to get the root node
// in case you have no direct workspace reference
INode root = session.Workspace.RootNode;
// Updates are made into a transaction
using (var tr = session.OpenTransaction())
{
    // Accessing a node
    INode node = root.ChildNodes["father"];
    // Changing a property
    session.SetPropertyValue(node, "Name", "Adam");
    
    // Creating a nodes    
    INode newnode = session.CreateNode(node, "newson", new Property[] {
                        new Property("Name", "Abel")
                    });
    
    // Removing a node
    session.RemoveNode(newson);
    tr.Complete();
}

El tr.Complete()  es el encargado de actualizar los archivos XML con las propiedades de los nodos que cambiaron. Un archivo de ejemplo:

<?xml version="1.0" encoding="utf-8"?>
<Properties>
  <Name>John</Name>
  <Age type="int">35</Age>
  <Male type="bool">true</Male>
  <Hired type="datetime">2000-01-01T00:00:00</Hired>
  <Height type="double">167.2</Height>
  <Salary type="decimal">120000.5</Salary>
</Properties>

El código en Transaction.Complete:

var nodestoupdate = 
    this.operations.Where(op => !(op is RemoveNodeOperation)).Select(op => op.Node).Distinct();
var nodestodelete = 
    this.operations.Where(op => op is RemoveNodeOperation).Select(op => op.Node).Distinct();
nodestoupdate = nodestoupdate.Except(nodestodelete);
foreach (var node in nodestoupdate)
    this.store.SaveProperties(node.Path, node.Properties);
foreach (var node in nodestodelete)
    this.store.RemoveNode(node.Path);

Podría mejorarla, tomando en cuante que algunas implementaciones de IStore podría preferir actualizar propiedades, en lugar de un nodo completo (por ejemplo, una implementación que use como almacén una base de datos).

Quiero escribir otra implementación de IStore usando JSON (debería pensar cómo guardar los tipos originales de cada propiedad). Otro trabajo pendiente: recuperar un node desde un espacio de trabajo sabiendo su path completo, y permitir hacer consultas de nodos (¿usando XPath? Estoy todavía decidiendo).

Si ven los commit en el repositorio, verán cómo fue implementado todo esto de almacenamiento usando TDD (Test-Driven Development).

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

Leave a Reply

Your email address will not be published. Required fields are marked *