Index: topia/doc/DevDoc.rst diff -u topia/doc/DevDoc.rst:1.2 topia/doc/DevDoc.rst:1.3 --- topia/doc/DevDoc.rst:1.2 Wed Jun 16 09:41:26 2004 +++ topia/doc/DevDoc.rst Thu Jul 15 13:13:12 2004 @@ -1,45 +1,52 @@ +Pour l'instant si une methode est abstraite elle est distante, est-ce +vraiment cela ? + ========================= Documentation développeur ========================= -Fichier de propriété du context -=============================== - -Sous classage d'entité ou de service ------------------------------------- - -Les services et les entités peuvent être étendu en sous classant les classes -générées. Pour prendre en compte ces sous classes il faut les déclarer dans -le fichier de propriété chargé par le context. - -Pour chaque classe il y a deux entrées, une pour l'interface et une pour la -classe à utiliser. - -Pour les entities on a donc:: - - mapping.enitity.to.interface - mapping.enitity.to.class - mapping.enitity.do.interface - mapping.enitity.do.class - -Pour le service de persistence:: - - mapping.service.persistence.interface - mapping.service.persistence.to.class - -Normalement le développeur utilisant le framework ToPIA ne doit modifier -si besoin que les valeurs de:: - - mapping.enitity.to.class - mapping.service.persistence.to.class +Les limites +=========== -Pour récupérer une interface ou une classe pour un service de persitence il -faut utiliser la méthode du context **getPersistenceService(Class)**. La -classe passé en argument est la classe de l'interface de l'entité. - -Pour récupérer un TO ou un DO, il faut utiliser la methode du context -**createEntity(Class):TopiaEntityTO** et **createEntityDO(Class)**. L'argument -est l'interface de l'entité. +Il est impossible de sous classer une entite car si on veux pouvoir faire de +l'heritage dans le framework il faudrait que les classes générées par le +framework n'héritent pas des autres classes générées par le framework mais des +classes écritent par l'utilisateur, hors on ne connait pas leur nom lors de la +génération. + +Le même problème se pose pour les PersistenceServices. + +Sous classage d'entité +====================== + +Toutes les méthodes déclarées sur l'entité sont executées en délègant leur +exécution sur l'objet EntityOperation associé. Ce qui permet de gérer la +distribution des méthodes de l'entité. Ceci permet aux developpeurs et au +framework de toujours manipuler l'entity et non pas une classe spéciale ce qui +poserait des problèmes lors du passage d'une entity au travers du reseau +car elle n'aurait pas les attributs. Il faudrait alors trouver des astuces +pour convertir par exemple un EntityDist en EntityImpl à chaque fois que +l'entité doit migrer. + +Il est donc plus simple de délèguer toutes les operations, hors méthodes +d'accès aux attributs, sur l'objet EntityOperation que le développeur +implante. L'implantation du développeur doit prendre en compte l'héritage +entre les entités. + +Comment surcharger une méthode d'accès à un attribut +---------------------------------------------------- + +Il est impossible de le faire. + +Comment implanter les opérations des entites +-------------------------------------------- + +Il faut implanter les objets Operations. Ces opérations ont comme premier +argument un objet de type entite, qui est l'entité qui fait l'appel à la +méthode. Il faut ensuite utiliser cette nouvelle +classe dans le fichier de propriete du context dans la section +*mapping.implementation.Operation* où *interface* est le nom +de package et de la classe de l'interface de l'entite Chargement d'un service ======================= @@ -61,8 +68,7 @@ une abstraction entre le service qui répond réellement à l'utilisateur et l'objet service que l'utilisateur manipule. -Les fonctionnalitées sont: les hooks, les appels distant, les méthodes -privées +Les fonctionnalitées sont: les hooks Les hooks --------- @@ -76,28 +82,64 @@ avant, soit après l'appel à la méthode du service. Les appels distants -------------------- +=================== Le framework masque complètement l'implantation réelle du service. Hors un service peut-être distant (serveur d'application (EJB, XML-RPC), ou local (JDO, JDBC). Mais l'utilisateur n'a rien a faire pour prendre en compte ces -différence. Le proxy se charge de rediriger la demande au bonne endroit. - -Les méthodes privées au framework ---------------------------------- - -Les services sont utilisé par les utilisateurs, mais aussi par le framework. -Pour que les utilisateurs ne voit pas les méthodes du framework dans les -interfaces du service. Celle-ci ont été placées dans une autre interface. -Qui porte le même nom que le service mais prefixé par Private. Par exemple -pour le service de persistence:: - - TopiaPersistenceService - PrivateTopiaPersistenceService - -Le context lors de la recherche d'un service, regarde s'il y a une interface -de ce nom si c'est le cas, alors il l'ajoute a la liste des interfaces -instanciées par le proxy qui encapsule le service. +différence. La classe Dist se charge de rediriger la demande au bonne endroit. +La configuration de la distribution se fait dans le fichier de configuration +du Context. + +Par exemple si l'on ne souhaite aucune distribution même si dans le +diagramme de classe on avait explicitement indique que certaine méthode +était distribuée, il suffit de mettre dans le fichier de propriété du +context comme class de distribution la classe d'implantation:: + + mapping.implementation.org.codelutin.chorem.TaskOperation=org.codelutin.chorem.TaskOperationImpl + mapping.distribution.org.codelutin.chorem.TaskOperation=org.codelutin.chorem.TaskOperationDist + devient + mapping.implementation.org.codelutin.chorem.TaskOperation=org.codelutin.chorem.TaskOperationImpl + mapping.distribution.org.codelutin.chorem.TaskOperation=org.codelutin.chorem.TaskOperationImpl + +Le TopiaId +========== + +Le TopiaId identifie de façon unique une entite dans toutes l'application. +Il est composé de deux choses, le nom de la classe de l'interface de l'entity +et d'une portion unique d'identification UID ou RANDOM. Les deux éléments +sont séparé par un #, par exemple:: + + org.codelutin.chorem.entities.Customer#243456845923#56378387474 + +La deuxième partie peu très bien elle même contenir d'autre #. Mais on +certifie que la première partie de l'identifiant est le nom de l'interface +suivie d'un #. + +La persistence +============== + +L'implantation des Entites dans le framework est completement basic, elle ne +prend en compte aucun cache aucun chargement retardé, ... +Ces deux choses doivent être fait dans l'implantation des persistences. +Pour le chargement au plus tard une idée est d'utiliser des proxies +(LazyEntityProxy) qui encapsule une Entite. Ce proxy répond à l'interface +de l'entite. Au départ le proxy ne contient que le TopiaId de l'entite, puis +a la premiere demande fait sur le proxy, le veritable objet est chargé et le +proxy redirige les demandes sur lui. + +Ce mécanisme peut-être utilisé pour les champs des entités qui sont des +références vers d'autres entités. + +Pour les collections d'entites, la même chose peut-être faite, mais Il +peut aussi mettre en place d'autre mécanisme de chargement à retardement +plus adapté au collection. Par exemple le chargement par groupe d'entite, +suivant les demandes faites sur la collection. + +:REMARQUE: Il absolument trouvé un moyen de dire que ce que l'on demande a +la persitence, doit être retourné directement et non pas se charger plus +tard lors de l'utilisation. Sinon dans certain cas cela serait trop +pénalisant. Les templates ============= @@ -111,30 +153,99 @@ Template des Entities --------------------- -Les Entities sont sépararé en deux, les DO (Data Object) qui servent au -stokage pure des données. Et les TO (Transfer Object) qui servent à la -manipulation de l'information. Chacun d'eux herite d'une interface qui -reprend toutes les méthodes d'acces aux attributs. Ils héritent aussi -d'interface où sont declarés les méthodes d'accès et de modification des -attributs du framework (date de creation, date de modification, ...) - -Lorsque l'utilisateur demande un Entity. On lui retourne toujours un TO. -Le chemin pour cela est la creation d'un TO vide, dans lequel on recopie les -information d'un DO que l'on vient de charger. - -Pour les attributs du DO qui pointe vers d'autre entity, seul l'Id est -conservé dans le TO, Le TO associé a cette Id ne sera chargé que si -l'attribut est réellement utilisé. - -Si l'attribut est une liste d'entity on a alors une liste d'Id. Les Entities -seront alors tous chargés en même temps lors de la première utilisation de -l'attribut (en écriture comme en lecture). Il n'y a aucune mise à jour de la -liste d'Id, au fur et à mesure de l'utilisation de Entity. - -Implantation des templates --------------------------- - -Le template des DO hérite du template des TO en surchargeant quelque -méthode. Car que se soit un DO ou un TO on retrouve les mêmes méthodes et -les mêmes attributs. La seul chose qui varie réellement est la gestion du -topiaId. +Pour chaque entite on genere: + +- une interface sur lequel on trouve: + + - les méthodes d'acces aux attributs + - les opérations définis + +- une class implantant cette interface: + + - implatation d'un constructeur qui met a jour creationDate, topiaId, version, + ... + - déclaration des attributs + - déclaration d'un attribut **boolean modified** pour chaque attribut + - implantation des méthodes d'acces au attrbut + - implantation des opérations par délégation sur l'objet + TopiaEntityOperation associé + - implantation de la méthode set_allProperties_ + +- une interface pour le service de persistence: + + - déclaration de deux méthodes finds pour chaque attribut: + findAllBy, findBy + +- une classe implantant cette interface + + - implantation des méthodes find en utilisant la méthode find de + AbstractPersistenceService et les TopiaQuery + +- une interface reprenant les operations de l'entite + + - declaration des operations en ajoutant comme premier argument une + variable du type de l'entite. + +- une classe implantant cette interface pour prendre en compte la + distribution + + - implantation de chaque operation, si elle doit être local appelle + directement la méthode sur l'implantation faite par le développeur, si + elle doit être distante utilise le DistributionHelper pour faire l'appel + +L'utilisateur n'a qu'a implanter l'interface reprenant les operations de +l'entite et de déclarer sa classe dans le fichier de proprietes du context. +L'implantation de cette interface doit se faire en repectant l'héritage des +entité. Si une entité B hérite d'une entité A ayant toutes les deux des +opérations alors le développeur doit implanté une classe pour l'entité A +puis une classe pour l'entité B qui hérite de l'implantation de l'entité A. + +Le cache coté client +==================== + +:status: à implanter + +Le cache coté client conserve pour chaque couple (topiaId, version), l'objet +réèl. Lorsqu'un Lazy demande au PersistenceHelper de lui donner un objet il +le demande avec le topiaId et la version. Le PersistenceHelper regarde dans +le cache si l'objet est déjà présent. S'il y est, alors il est retourné, +sinon il est demandé au serveur par un find. + +Lorsqu'un objet n'est plus utilisé coté client, il est libéré de la mémoire. +Ceci est possible car il est encapsulé dans le cache dans un SoftReference. +L'id de l'objet libéré est tout de même conservé. + +Comment synchroniser simplement les parties clientes +==================================================== + +:status: à implanter + +Le seul moyen pour la partie clients de récupérer un objet est de le +demander par un find. Soit directement soit indirectement par les objets +Lazy. Le serveur conserve donc pour chaque application client un HashSet de +tous les topiaId des entités que le client a. Lorsque qu'un client modifie +un objet ou des objets, leur topiaId sont comparé au topiaId de connu par +chaque client. Si un client connait ce topiaId alors il est supprimé de la +première HashSet des topiaId connus et mis dans une deuxième HashSet des +topiaId connu mais non à jour. + +Il y a donc deux HashSet par client modifier lors d'appelle de méthode des +clients. + +Lorsqu'un client appel une méthode coté serveur il passe en plus des +renseignement pour l'appel de la méthode la liste des entités qui ont été +libérées depuis le dernier appel au serveur. Si tout se passe bien cette +liste est alors vidé du cache. + +Le serveur supprime alors des objets connus par le client la liste que le +client vient de lui donner. + +lors de l'envoie de la réponse de l'appel de méthode du client, le serveur +envoie en même temps la liste des topiaId des entités qui ont été modifiées +coté serveur et dont le client n'est pas au courant. Si tout se passe bien +alors la liste des topiaId connus par le client et modifié est remise dans +la liste connu par le client. + +Après l'opération le client sait alors qu'il n'a plus la bonne version de +certain objet et il sait lesquels. Il peut alors demander au serveur la mise +à jour de ces objets par un find. Index: topia/doc/topiaArchitecture.zuml Index: topia/doc/Context.rst diff -u /dev/null topia/doc/Context.rst:1.1 --- /dev/null Thu Jul 15 13:13:17 2004 +++ topia/doc/Context.rst Thu Jul 15 13:13:12 2004 @@ -0,0 +1,25 @@ +Propriétés context +================== + +context.class= +context.helper.persistence= +context.helper.persistence.properties.file= +context.helper.distribution= +context.helper.distribution.properties.file= +context.helper.hook= +context.helper.hook.properties.file= + +Les entités +=========== + +Pour les classes de type TopiaOperation et TopiaService on doit retrouver +la classe de l'implantation que l'utilisateur a fait de l'interface. + +mapping.implementation.= + +Propriétés Hook +=============== + +hook.call.pre=(true|false) +hook.call.method=(true|false) +hook.call.post=(true|false)