7.5 KiB
7.5 KiB
Architecture
Module Overview
clotho-core
Zero Spring dependency.
All mapping, session, registry, and query logic.
clotho-spring-boot-starter
Spring Boot 3.x autoconfiguration.
Thin layer: creates beans, bridges @Transactional, scans @ClothoRepository.
Depends on clotho-core.
clotho-dev-app
Minimal Spring Boot application.
Connected to a live ArcadeDB instance.
Used throughout development for real-DB testing.
Not a production artifact; not published.
clotho-core Component Map
ClothoSessionFactory (entry point)
│ Holds: DriverRemoteConnection, TypeRegistry, global config
│
├── TypeRegistry
│ Built once at startup from classpath scan.
│ Maps: ArcadeDB label → Class<? extends ClothoEntity>
│ Knows: Java + ArcadeDB inheritance hierarchy, additionalParents
│
└── ClothoSession (unit of work, one per transaction/request)
│ Holds: identity map (ARID → ClothoEntity instance)
│
├── load(Class<T>, ARID) → T
│ └── SubgraphLoader
│ Uses: TypeRegistry, ObjectMapper
│ Executes Gremlin traversal for root vertex + @Include boundary
│ Cycle detection via visited-ARID set
│
├── save(entity)
│ └── SubgraphPersistor
│ Upserts root vertex/edge + all @Include elements recursively
│ Uses ArcadeDB @version for optimistic locking
│ @SubgraphType: iterates all ClothoEntity fields, saves each
│
├── delete(entity)
│ Removes root vertex/edge from graph
│ Does NOT cascade deletion to @Include elements
│
└── query(Class<T>, queryName, params) → List<T>
└── QueryExecutor
Resolves named @Query, binds params, executes, maps results
Also drives @ClothoRepository proxy methods
ObjectMapper (used by SubgraphLoader and QueryExecutor)
Gremlin Vertex/Edge → ClothoEntity subclass
Always uses most-specific registered class (TypeRegistry lookup by label)
Sets @Property fields, @OutVertex/@InVertex fields on edges
SubgraphTypeAssembler (used by QueryExecutor for @SubgraphType returns)
Maps Gremlin select() result map → @SubgraphType fields
Binding: field name or @Alias → select key
Each bound value is mapped via ObjectMapper
Data Flow: Loading a Composite Object
Developer: session.load(Order.class, arid)
│
▼
SubgraphLoader
1. g.V(arid.asString()) → TinkerPop Vertex (Order)
2. ObjectMapper.map(vertex) → Order instance (most-specific class)
3. Register in identity map
4. For each @Include field on Order:
@Include @Via("HAS_LINE") List<OrderLine> lines
┌──────────────────────────────────────────┐
│ g.V(arid).out("HAS_LINE") │
│ → [TinkerPop Vertex, Vertex, ...] │
│ for each: ObjectMapper.map(v) │
│ → OrderLine (or subtype by label) │
│ recurse: load OrderLine @Include fields│
└──────────────────────────────────────────┘
5. Assemble Order.lines = [OrderLine, ...]
6. Return fully assembled Order
Data Flow: Saving a Composite Object
Developer: session.save(order)
│
▼
SubgraphPersistor
1. Upsert root Order vertex
if order.getId() == null → create vertex with label "Order"
else → update vertex, check @version (optimistic lock)
2. For each @Include field on Order:
Field type is @VertexType (e.g., List<OrderLine>):
for each element → recursively save (SubgraphPersistor.save(orderLine))
ensure edge "HAS_LINE" exists from Order to OrderLine
Field type is @EdgeType (e.g., List<WorksAt>):
save edge properties; ensure @OutVertex and @InVertex are already persisted
3. Identity map deduplication: elements already saved in this call are skipped
4. Removed elements: NOT deleted automatically
Data Flow: @Query on a @ClothoRepository
Developer: employeeQueries.findByDepartment("Engineering")
│
▼
ClothoRepository proxy (generated by QueryExecutor at startup)
1. Read @Query gremlin string from method annotation
2. Bind @Param values: replace :dept with "Engineering"
3. Execute: g.V().hasLabel('Employee').has('dept','Engineering')
4. For each result vertex:
ObjectMapper.map(vertex) → most-specific Employee subclass
5. Return List<Employee>
For @SubgraphType return:
3. Execute query with select() → List of Maps
4. For each Map:
SubgraphTypeAssembler.assemble(EmployeeProfile.class, map)
→ bind map keys to fields by name / @Alias
→ ObjectMapper.map() each value
5. Return List<EmployeeProfile>
Session Identity Map
The identity map is the session's in-memory cache of loaded vertices and edges.
- Key:
ARID - Value:
ClothoEntityinstance
Rules:
- First load of an ARID → fetch from DB, map to Java, store in map, return
- Subsequent load of same ARID → return existing instance (no DB call)
save()does NOT clear the identity map; the instance is mutated in placeclose()clears the map and releases the Gremlin connection
The map operates at the individual vertex/edge level. Multiple composite objects (e.g., an
Order and an EmployeeProfile) may both hold references to the same Address instance
if their traversals reached the same ARID.
TypeRegistry Startup Validation
At ClothoSessionFactory.build() time, the TypeRegistry validates:
- Every
@VertexTypeclass extendsClothoVertex - Every
@EdgeTypeclass extendsClothoEdge - No two classes claim the same label
additionalParentslabels are resolvable to registered classesparentLabelvalues are resolvable to registered classes- Every
@Includefield is paired with@Via @OutVertex/@InVertexfield types are@VertexTypeclasses
Startup failure with a descriptive message is strongly preferred over silent misconfiguration that produces confusing runtime errors.
Package Structure
com.binarygolem.clotho
.model
ClothoEntity
ClothoVertex
ClothoEdge
ARID
UnknownTypeBehavior
.annotation
VertexType
EdgeType
SubgraphType
RID
Property
Include
Via
Direction
OutVertex
InVertex
Alias
Query
Queries (container for @Repeatable @Query)
Param
ClothoRepository
.session
ClothoSession
ClothoSessionFactory
ClothoSessionFactoryBuilder
.registry
TypeRegistry
TypeRegistryBuilder
TypeDescriptor (holds metadata for one registered type)
.mapping
ObjectMapper
SubgraphLoader
SubgraphPersistor
SubgraphTypeAssembler
.query
QueryExecutor
QueryDescriptor (holds parsed @Query metadata for one method)
ParameterBinder
.exception
ClothoException
UnknownTypeException
OptimisticLockException
ClothoConfigurationException
// clotho-spring-boot-starter
com.binarygolem.clotho.spring
.config
ClothoAutoConfiguration
ClothoProperties
.tx
ClothoTransactionManager
ClothoTransactionObject
.repository
ClothoRepositoryScanner
ClothoRepositoryProxyFactory