Implementation Specification¶
A. Functional specification
B. Implementation specification
A. Functional Description: Implemented Capabilities¶
1. Bootstrap and Configuration¶
OdooPlugin- Loads
OdooClientConfig, initializesOdooServiceFactoryandOdooCacheManager. - Exposes
getProperty/setPropertyto read/write client properties at runtime.
- Loads
OdooClientConfig- Singleton, loads properties from
TLINQ_HOMEfolder; exposes getters for Odoo endpoints, credentials, and service/entity-specific settings.
- Singleton, loads properties from
2. Authentication and Session Management¶
OdooServiceFactory- Singleton factory; creates XML-RPC client config for
commonandobjectendpoints. - On construction: authenticates the configured system user; stores
odoo.userIdand systemodoo.session. - Exposes
authenticateUser(user, pwd[, sessionToken])andgetSessionId(sessionToken)usingUserLoginandTlinqClusterCacheuserSessionsmap.
- Singleton factory; creates XML-RPC client config for
3. Service Creation and Invocation¶
OdooClientService(base)- Holds state: server URL, DB, user id, pwd, model, operation; param list and named params map (
dict). initialize(Properties)andinitService(url, db, user, pwd)set connectivity context.addMethodParameter,addNamedParameterto compose XML-RPC calls.invoke(Class<T>)executesexecute_kwwith assembled parameters, returns typed result.invokeMethod(String, Class<T>, RemoteEntityI)allows reflective dispatch to protected methods in subclasses when a custom method name is provided.
- Holds state: server URL, DB, user id, pwd, model, operation; param list and named params map (
OdooServiceFactorycreateService(serviceName, sessionToken): Finds service class, model, and action from config; instantiates and initializes a concrete service; sets model and operation andXmlRpcClientconnection.- Type-safe helpers:
createSearchService,createReadService,createSearchReadService,createClientService(Class, serviceName, sessionToken).
4. Query and Data Access Services¶
OdooEntitySearchService- Maintains
SearchDomaincriteria; supportsoffset,limit,order,countflags. search(): Adds domain, named params, invokes XML-RPC; returnsList<Object>of IDs or records depending on action.addCriterion(field, oper, value);addCriteria(List).
- Maintains
OdooEntityReadService- Manages result fields, object IDs; converts
Object[]responses into typed native entities and optional canonical objects viaOdooEntitymapping. - Methods:
setResultFields,addObjectId,read(),readCanonical().
- Manages result fields, object IDs; converts
OdooEntitySearchReadService- Combines domain filters with
fields, pagination, order; normalizeslike→ilikefor Odoo. search(): Returns native entity list by callingtoNativeResultList.
- Combines domain filters with
OdooEntityWriteService- CRUD-like operations:
create(RemoteEntityI entity): builds a map viaOdooEntity.createObjectMap()and invokes; returns new ID.write(Object id, RemoteEntityI entity): sends[id]and values map; returns ID on success.delete(Object id): sends[id]to unlink; returns deleted ID.
- CRUD-like operations:
OdooDocumentService- Extends
OdooClientService; intended for document download/print or specialized calls defined via configuredaction.
- Extends
5. Entities and Mapping¶
- Base:
OdooEntity- Reflection/annotation-driven mapper from Odoo maps to native Java objects and then to canonical objects (
@TlinqClientEntity("…")). - Supports
@TlinqEntityFieldwithsourceName,index(for tuple-like values from many2one),readOnly, and optionalnamefor canonical alignment. - Key methods:
createNativeEntity(HashMap, Class),toCanonicalList(Object[], Class),createCanonicalObject(...),createObjectMap().
- Reflection/annotation-driven mapper from Odoo maps to native Java objects and then to canonical objects (
- Examples:
OdooCustomer→com.perun.tlinq.entity.customer.CCustomer(@TlinqClientEntity("…CCustomer")) with many field mappings likedisplay_name,country_id(index 0,1),last_website_so_idtuple, etc.OdooProduct,OdooProductVariant,OdooTransfer,OdooWebCategory, etc., following the same pattern.
6. Facades and Domain Logic¶
OdooProductFacade- High-level domain operations for products, variants, attributes, and transfers.
- Uses configured service names like
searchProducts,findProducts,findProductVariants,getProducts,getAttributeValues,getTransfer,getProductTransfers. - Examples:
readManyTemplates(ids...)→OdooEntityReadServicewithGET_TEMPLATE_SERVICE.findProductVariants(crit...)→OdooEntitySearchReadServiceonproduct.productmodel with extrafields/order/limitif set.getExactVariant12(templateId, attrs)→ iterative narrowing search usingSearchRead.
OdooCacheManager- Initializes and maintains an in-memory map of transfers (ID →
OdooTransfer) on startup.
- Initializes and maintains an in-memory map of transfers (ID →
B. Implementation Specification: Architecture, Patterns, and Practices¶
1. Layered Architecture¶
- Framework Layer
OdooPlugin: Module bootstrap; wires configuration and cache; registers/initializes theOdooServiceFactory.OdooCacheManager: Cross-cutting caching concern, initialized at plugin load.
- Configuration Layer
OdooClientConfig: Singleton properties provider; central place forodoo.server,odoo.db,odoo.user,odoo.pwd, date formats, entity/service props.
- Integration/Service Layer
OdooServiceFactory: Singleton; creates configured service instances, manages XML-RPC client configs, system session bootstrap, per-request session resolution.OdooClientService: Base client with shared invocation mechanics (execute_kw); holds model/operation, parameters, and the XML-RPC connection.- Specializations:
OdooEntitySearchService,OdooEntityReadService,OdooEntitySearchReadService,OdooEntityWriteService, andOdooDocumentService.
- Domain Facade Layer
OdooProductFacade: Aggregates multiple low-level calls into cohesive business functions for products and transfers.
- Entity/Mapping Layer
OdooEntitybase class andcom.perun.tlinq.client.odoo.entity.*value objects; annotation-driven mapping to and from Odoo.
2. Construction and Invocation Flow¶
- Service Factory (config-driven):
OdooServiceFactory.getInstance()returns a singleton; on first use, it authenticates system user and storesodoo.userIdandodoo.session.createService(serviceName, sessionToken):- Reads
services.<name>.class,services.<name>.model,services.<name>.actionfrom config. - Instantiates the class via reflection.
- Initializes it with server
/xmlrpc/2/object, DB,userId,userPwdresolved fromUserLoginin session cache. - Sets
modelandoperation; injectsXmlRpcClientfromnewClient().
- Reads
- Invocation (template method through base class):
- Caller sets criteria/fields/ids via service-specific methods (e.g.,
addCriteria,setResultFields,addObjectId). - Base
OdooClientService.invoke(Class<T>)collects parameters:[db, uid, pwd, model, operation, [positional], {kwargs}]. - Executes
execute_kwon XML-RPC client and converts to requested type. - Read/SearchRead services convert
Object[]to native entities viaOdooEntity.toNativeResultListand optionally to canonical.
- Caller sets criteria/fields/ids via service-specific methods (e.g.,
3. Patterns and Practices¶
- Singleton:
OdooClientConfig,OdooServiceFactory,OdooCacheManager. - Factory:
OdooServiceFactoryfor consistent, config-driven instantiation of services. - Facade:
OdooProductFacadeto present coarse-grained APIs to upstream code. - Template Method: Common invoke path in
OdooClientService, specialized parameter preparation in derived services. - Reflection & Annotation Mapping:
OdooEntityconstructs native and canonical entities using@TlinqClientEntity,@TlinqEntityFieldmetadata. - Configuration-First: Bindings for service class, model, and Odoo action are externalized to properties.
- Caching:
OdooCacheManagerwithStaticMapCache; sessions inTlinqClusterCache. - Error Handling: Wraps
XmlRpcExceptionand reflection errors inTlinqClientExceptionwithTlinqErrcodes; logs atSEVERE/INFO.
4. Entity and Service Construction Practices¶
- Entities
- Define a native entity per Odoo model, extend
OdooEntity. - Annotate with
@TlinqClientEntity("<canonical-FQN>")to enable canonical conversion. - Each field annotated with
@TlinqEntityFieldsetssourceNameif different,indexfor many2one tuple extraction, optionalnameto map to canonical name. - Implement no-arg constructor; keep fields private with getters/setters.
- Use
createObjectMap()(provided byOdooEntity) to generate maps forcreate/write.
- Define a native entity per Odoo model, extend
- Services
- Provide a service name in config mapping to a concrete class and Odoo action.
- Prefer
OdooEntitySearchReadServicewhen both filtering and field selection are needed. - Normalize filters: convert
liketoiliketo match Odoo semantics (OdooEntitySearchReadService.addCriteria). - Use
setResultFields(String...)to limit payload when reading. - Use pagination (
setOffset,setLimit) andsetOrderfor performance.
5. Cross-Cutting Concerns and Considerations¶
- Security/SSL: Current code allows hostname
localhostas an exception; ensure production builds enforce strict verification. - Configuration Errors: If
services.<name>.*keys are missing or class cannot be found, factory will throwTlinqClientException(logged with details). - Data Formats: Date and datetime formats read from
odoo.format.dateandodoo.format.datetimeare used by entity utilities (seeOdooEntityandDateUtilusage). - Thread Safety: Singletons are lazily initialized;
OdooServiceFactoryuses avolatileinstance and synchronized access ongetInstance(); param lists in services are instance-scoped and should not be shared across threads.
6. Example Usage Snippets (conceptual)¶
- Create and run a search_read for product variants:
OdooEntitySearchReadService svc = factory.createSearchReadService("findProductVariants", sysSession); svc.setModel("product.product"); svc.setOperation(OdooEntitySearchReadService.SERVICE_NAME); // "search_read" svc.addCriterion("product_tmpl_id", "=", templateId); svc.setLimit(50); List variants = svc.search(); - Read specific product templates:
- Create a customer record:
7. Known Extension Points¶
- Add new service: define
services.<name>.class,.model,.action; implement class extending one of theOdooEntity*Servicetypes if needed. - Add new entity: create a class extending
OdooEntitywith proper annotations; optionally add default service names inentities.<name>.*. - Add new facade: compose multiple services to expose cohesive domain functions; inject factory via
ClientServiceFactory.instance(ClientServiceFactory.ODOO_SF).
Appendix: Key Classes and Files¶
- Framework:
tqodoo/src/main/java/com/perun/tlinq/framework/OdooPlugin.java,OdooCacheManager.java - Config:
tqodoo/src/main/java/com/perun/tlinq/client/odoo/util/OdooClientConfig.java - Factory & Session:
tqodoo/src/main/java/com/perun/tlinq/client/odoo/service/OdooServiceFactory.java,.../service/user/UserLogin.java - Base and Specialized Services:
.../service/OdooClientService.java,OdooEntityReadService.java,OdooEntitySearchService.java,OdooEntitySearchReadService.java,OdooEntityWriteService.java,OdooDocumentService.java - Entities:
.../entity/*includingOdooEntity.java,OdooCustomer.java,OdooProduct.java,OdooProductVariant.java,OdooTransfer.java,OdooWebCategory.java, etc. - Facade:
.../service/product/OdooProductFacade.java