diff --git a/.agents/skills/harness-creator/README.md b/.agents/skills/harness-creator/README.md new file mode 100644 index 00000000..86276633 --- /dev/null +++ b/.agents/skills/harness-creator/README.md @@ -0,0 +1,83 @@ +# harness-creator + +A compact skill for building and auditing harnesses around AI coding agents. + +It helps a repository provide five things agents need: instructions, state, verification, scope boundaries, and lifecycle handoff. + +## Install + +```bash +npx skills add walkinglabs/learn-harness-engineering --skill harness-creator +``` + +Or copy `skills/harness-creator/` into your skill path. + +## Use + +```bash +node skills/harness-creator/scripts/create-harness.mjs --target /path/to/project +node skills/harness-creator/scripts/validate-harness.mjs --target /path/to/project +node skills/harness-creator/scripts/run-benchmark.mjs --target /path/to/project --html /path/to/report.html +``` + +The scripts use only Node.js built-in modules. They can be run after copying the skill directory into another repository. + +## What It Creates + +- `AGENTS.md` or `CLAUDE.md` +- `feature_list.json` +- `progress.md` +- `init.sh` +- `session-handoff.md` + +`create-harness.mjs` detects common project types and package managers. It supports Node/npm/pnpm/yarn/bun, Python, Go, Rust, Maven, Gradle, and .NET at a basic verification-command level. + +## What It Checks + +`validate-harness.mjs` scores the five harness subsystems: + +1. Instructions +2. State +3. Verification +4. Scope +5. Lifecycle + +The score is structural. It tells you whether the harness is present and coherent; it does not replace real before/after agent-session testing. + +## Status + +- [x] Minimal harness scaffolding +- [x] Five-subsystem validation +- [x] HTML assessment report +- [x] Structural benchmark report +- [x] 10 eval cases +- [x] Generic verification detection for common stacks +- [ ] Optional real before/after agent-session replay + +## Files + +```text +harness-creator/ +├── SKILL.md +├── metadata.json +├── agents/openai.yaml +├── scripts/ +│ ├── create-harness.mjs +│ ├── validate-harness.mjs +│ ├── render-assessment-html.mjs +│ ├── run-benchmark.mjs +│ └── lib/harness-utils.mjs +├── templates/ +│ ├── agents.md +│ ├── feature-list.json +│ ├── feature-list.schema.json +│ ├── init.sh +│ ├── progress.md +│ └── session-handoff.md +├── references/ +└── evals/evals.json +``` + +## Boundaries + +This skill is for harness engineering, not model selection, prompt tuning alone, or app architecture. Keep project-specific facts in the target repository. diff --git a/.agents/skills/harness-creator/SKILL.md b/.agents/skills/harness-creator/SKILL.md new file mode 100644 index 00000000..802fed82 --- /dev/null +++ b/.agents/skills/harness-creator/SKILL.md @@ -0,0 +1,107 @@ +--- +name: harness-creator +description: >- + Build, audit, and improve lightweight harnesses for AI coding agents: AGENTS.md/CLAUDE.md, + feature state, verification workflows, scope boundaries, lifecycle handoff, + memory persistence, context control, tool safety, and multi-agent coordination. +license: MIT +--- + +# Harness Creator + +Use this skill to make a repository easier for coding agents to start, stay in scope, verify work, and resume across sessions. Keep the harness small enough that agents actually follow it. + +Not for model selection, prompt tuning in isolation, chat UI design, or general app architecture. + +## Core Model + +Every useful coding-agent harness has five subsystems: + +| Subsystem | Minimal artifact | Purpose | +|---|---|---| +| Instructions | `AGENTS.md` or `CLAUDE.md` | Startup path, working rules, definition of done | +| State | `feature_list.json`, `progress.md` | Current feature, status, evidence, next step | +| Verification | `init.sh` or documented commands | Tests/checks the agent must run before claiming done | +| Scope | Feature dependencies and done criteria | Prevents overreach and half-finished work | +| Lifecycle | `session-handoff.md`, end-of-session routine | Makes the next session restartable | + +## First Move + +1. Inspect what already exists: instruction files, feature/state files, verification commands, docs, package manifests. +2. Ask only for missing context that cannot be inferred safely: target agent, desired file name, tolerance for structure, and whether overwriting is allowed. +3. Prefer a minimal harness first. Add memory, tool safety, multi-agent, or benchmark details only when the user's problem calls for them. + +## Common Tasks + +### Create a harness + +Use the bundled script when working on a local repository: + +```bash +node skills/harness-creator/scripts/create-harness.mjs --target /path/to/project +``` + +Options: + +- `--agent-file CLAUDE.md` for Claude-oriented projects. +- `--package-manager npm|pnpm|yarn|bun` when detection is wrong. +- `--commands "cmd one,cmd two"` for custom verification. +- `--force` only after confirming overwrites are acceptable. + +Then explain what was created and how the user should replace placeholder feature entries. + +### Audit an existing harness + +Run: + +```bash +node skills/harness-creator/scripts/validate-harness.mjs --target /path/to/project +``` + +Report the five subsystem scores, the lowest-scoring area, and the first 2-3 changes that would improve reliability. Treat the lowest score as a candidate bottleneck; confirm with failures, logs, or task outcomes before claiming causality. + +### Produce a report + +Use when the user wants a shareable assessment: + +```bash +node skills/harness-creator/scripts/render-assessment-html.mjs --target /path/to/project +node skills/harness-creator/scripts/run-benchmark.mjs --target /path/to/project --html /path/to/report.html +``` + +Be clear that this is a structural benchmark. Real effectiveness still needs before/after agent sessions on representative tasks. + +## When to Read References + +Load only the reference needed for the user's problem: + +- Memory across sessions: [Memory Persistence](references/memory-persistence-pattern.md) +- Reusable workflows as skills: [Skill Runtime](references/skill-runtime-pattern.md) +- Permissions, tools, concurrency: [Tool Registry & Safety](references/tool-registry-pattern.md) +- Context budget and progressive disclosure: [Context Engineering](references/context-engineering-pattern.md) +- Delegation and parallel agents: [Multi-Agent Coordination](references/multi-agent-pattern.md) +- Hooks, startup, long-running work: [Lifecycle & Bootstrap](references/lifecycle-bootstrap-pattern.md) +- Non-obvious failure modes: [Gotchas](references/gotchas.md) + +## Design Rules + +- Keep the root instruction file short: routing and invariants, not a full manual. +- Put project facts in project docs, not in the skill. +- Make verification commands explicit and runnable. +- Require evidence before marking a feature done. +- Use one active feature unless the harness has explicit multi-agent ownership boundaries. +- Prefer append/update state files over relying on chat history. +- Never hide destructive behavior in scripts; overwrites require explicit user approval. + +## Deliverable Checklist + +For a usable minimal harness, leave the target project with: + +- [ ] `AGENTS.md` or `CLAUDE.md` +- [ ] `feature_list.json` +- [ ] `progress.md` +- [ ] `init.sh` +- [ ] Optional `session-handoff.md` for multi-session work +- [ ] Documented verification evidence or next action + +If you cannot create files, provide exact file contents and commands instead. diff --git a/.agents/skills/harness-creator/SKILL.md.en b/.agents/skills/harness-creator/SKILL.md.en new file mode 100644 index 00000000..802fed82 --- /dev/null +++ b/.agents/skills/harness-creator/SKILL.md.en @@ -0,0 +1,107 @@ +--- +name: harness-creator +description: >- + Build, audit, and improve lightweight harnesses for AI coding agents: AGENTS.md/CLAUDE.md, + feature state, verification workflows, scope boundaries, lifecycle handoff, + memory persistence, context control, tool safety, and multi-agent coordination. +license: MIT +--- + +# Harness Creator + +Use this skill to make a repository easier for coding agents to start, stay in scope, verify work, and resume across sessions. Keep the harness small enough that agents actually follow it. + +Not for model selection, prompt tuning in isolation, chat UI design, or general app architecture. + +## Core Model + +Every useful coding-agent harness has five subsystems: + +| Subsystem | Minimal artifact | Purpose | +|---|---|---| +| Instructions | `AGENTS.md` or `CLAUDE.md` | Startup path, working rules, definition of done | +| State | `feature_list.json`, `progress.md` | Current feature, status, evidence, next step | +| Verification | `init.sh` or documented commands | Tests/checks the agent must run before claiming done | +| Scope | Feature dependencies and done criteria | Prevents overreach and half-finished work | +| Lifecycle | `session-handoff.md`, end-of-session routine | Makes the next session restartable | + +## First Move + +1. Inspect what already exists: instruction files, feature/state files, verification commands, docs, package manifests. +2. Ask only for missing context that cannot be inferred safely: target agent, desired file name, tolerance for structure, and whether overwriting is allowed. +3. Prefer a minimal harness first. Add memory, tool safety, multi-agent, or benchmark details only when the user's problem calls for them. + +## Common Tasks + +### Create a harness + +Use the bundled script when working on a local repository: + +```bash +node skills/harness-creator/scripts/create-harness.mjs --target /path/to/project +``` + +Options: + +- `--agent-file CLAUDE.md` for Claude-oriented projects. +- `--package-manager npm|pnpm|yarn|bun` when detection is wrong. +- `--commands "cmd one,cmd two"` for custom verification. +- `--force` only after confirming overwrites are acceptable. + +Then explain what was created and how the user should replace placeholder feature entries. + +### Audit an existing harness + +Run: + +```bash +node skills/harness-creator/scripts/validate-harness.mjs --target /path/to/project +``` + +Report the five subsystem scores, the lowest-scoring area, and the first 2-3 changes that would improve reliability. Treat the lowest score as a candidate bottleneck; confirm with failures, logs, or task outcomes before claiming causality. + +### Produce a report + +Use when the user wants a shareable assessment: + +```bash +node skills/harness-creator/scripts/render-assessment-html.mjs --target /path/to/project +node skills/harness-creator/scripts/run-benchmark.mjs --target /path/to/project --html /path/to/report.html +``` + +Be clear that this is a structural benchmark. Real effectiveness still needs before/after agent sessions on representative tasks. + +## When to Read References + +Load only the reference needed for the user's problem: + +- Memory across sessions: [Memory Persistence](references/memory-persistence-pattern.md) +- Reusable workflows as skills: [Skill Runtime](references/skill-runtime-pattern.md) +- Permissions, tools, concurrency: [Tool Registry & Safety](references/tool-registry-pattern.md) +- Context budget and progressive disclosure: [Context Engineering](references/context-engineering-pattern.md) +- Delegation and parallel agents: [Multi-Agent Coordination](references/multi-agent-pattern.md) +- Hooks, startup, long-running work: [Lifecycle & Bootstrap](references/lifecycle-bootstrap-pattern.md) +- Non-obvious failure modes: [Gotchas](references/gotchas.md) + +## Design Rules + +- Keep the root instruction file short: routing and invariants, not a full manual. +- Put project facts in project docs, not in the skill. +- Make verification commands explicit and runnable. +- Require evidence before marking a feature done. +- Use one active feature unless the harness has explicit multi-agent ownership boundaries. +- Prefer append/update state files over relying on chat history. +- Never hide destructive behavior in scripts; overwrites require explicit user approval. + +## Deliverable Checklist + +For a usable minimal harness, leave the target project with: + +- [ ] `AGENTS.md` or `CLAUDE.md` +- [ ] `feature_list.json` +- [ ] `progress.md` +- [ ] `init.sh` +- [ ] Optional `session-handoff.md` for multi-session work +- [ ] Documented verification evidence or next action + +If you cannot create files, provide exact file contents and commands instead. diff --git a/.agents/skills/harness-creator/agents/openai.yaml b/.agents/skills/harness-creator/agents/openai.yaml new file mode 100644 index 00000000..500d7ae0 --- /dev/null +++ b/.agents/skills/harness-creator/agents/openai.yaml @@ -0,0 +1,7 @@ +interface: + display_name: "Harness Creator" + short_description: "Scaffold and audit coding-agent harnesses" + default_prompt: "Use $harness-creator to create, validate, and benchmark a production-ready coding-agent harness for this repository." + +policy: + allow_implicit_invocation: true diff --git a/.agents/skills/harness-creator/evals/evals.json b/.agents/skills/harness-creator/evals/evals.json new file mode 100644 index 00000000..723d5ee6 --- /dev/null +++ b/.agents/skills/harness-creator/evals/evals.json @@ -0,0 +1,136 @@ +{ + "skill_name": "harness-creator", + "evals": [ + { + "id": 1, + "name": "Minimal Harness Creation", + "prompt": "I have a new TypeScript + React project with no agent setup. Create a minimal harness that makes my agent reliable for single-feature development.", + "expected_output": "AGENTS.md (~50-100 lines), feature_list.json with 3-5 placeholder features, init.sh with verification commands", + "files": [], + "expectations": [ + "AGENTS.md includes startup workflow (read files, run init, check feature list)", + "AGENTS.md includes one-feature-at-a-time policy", + "feature_list.json has valid JSON with id, name, description, status fields", + "init.sh runs install, type/static check, test, and build commands when available", + "All files are in project root directory" + ] + }, + { + "id": 2, + "name": "Session Continuity Setup", + "prompt": "My agent forgets everything between sessions. I need persistent memory and session handoff so it can work on multi-day features.", + "expected_output": "progress.md template, session-handoff.md structure, memory directory setup instructions", + "files": [], + "expectations": [ + "progress.md includes sections: current state, what's done, what's in progress, blockers, next session should", + "session-handoff.md includes: what was accomplished, what remains, blockers/decisions, files modified", + "Instructions for memory directory creation (.claude/memory/ or similar)", + "Two-step save invariant explained (topic file then index)" + ] + }, + { + "id": 3, + "name": "Harness Assessment", + "prompt": "I have an existing AGENTS.md file but my agent still breaks things. Assess my harness and tell me what to improve first.", + "expected_output": "Five-subsystem assessment with scores 1-5 for each, bottleneck identified, prioritized improvement plan", + "files": ["existing-AGENTS.md"], + "expectations": [ + "Assessment covers all 5 subsystems: Instructions, State, Verification, Scope, Lifecycle", + "Each subsystem scored 1-5 with justification", + "Lowest-scoring subsystem identified as bottleneck or candidate bottleneck", + "Prioritized improvement plan with 2-3 concrete next steps" + ] + }, + { + "id": 4, + "name": "Verification Workflow Design", + "prompt": "My agent says 'done' but the tests fail. Design a verification workflow that forces the agent to actually verify before claiming completion.", + "expected_output": "Verification commands list, AGENTS.md section updates, optional quality score tracking", + "files": [], + "expectations": [ + "Explicit verification commands listed (tests, lint, type-check, build)", + "AGENTS.md includes Definition of Done section with verification requirement", + "End-of-session checklist includes verification evidence recording", + "Failure path says not to claim done when verification fails" + ] + }, + { + "id": 5, + "name": "Memory Taxonomy Design", + "prompt": "I want my agent to remember project conventions and user preferences across sessions. Design a memory taxonomy and tell me what belongs where.", + "expected_output": "Memory layer definitions, type taxonomy for auto-memory, what to save vs what to skip", + "files": [], + "expectations": [ + "Instruction memory defined (human-curated, version-controlled)", + "Auto-memory defined (agent-written, persistent)", + "Type taxonomy with 3-4 types (e.g., user/feedback/project/reference)", + "Clear guidance on what NOT to save (derivable content)" + ] + }, + { + "id": 6, + "name": "Tool Safety Design", + "prompt": "My custom coding agent can run shell commands and edit files. Design the tool registry and permission harness so it is powerful but does not silently do dangerous things.", + "expected_output": "Tool registry policy with per-call concurrency classification, default permissions, denial handling, and audit trail", + "files": [], + "expectations": [ + "Sensitive tools default to ask or deny instead of allow", + "Concurrency safety is classified per call rather than per tool", + "Permission evaluation side effects are acknowledged and not cached unsafely", + "Audit trail records command, decision, and reason" + ] + }, + { + "id": 7, + "name": "Context Budget Plan", + "prompt": "My agent loads too many docs at startup and gets slow. Design a context strategy that keeps important context while controlling token cost.", + "expected_output": "Progressive disclosure plan using select/write/compress/isolate operations and explicit context budgets", + "files": [], + "expectations": [ + "Defines always-loaded metadata versus on-demand references", + "Uses SELECT, WRITE, COMPRESS, and ISOLATE operations", + "Includes hard caps or budget thresholds", + "Explains invalidation for memoized context builders" + ] + }, + { + "id": 8, + "name": "Multi-Agent Coordination", + "prompt": "I want multiple agents to work on a large refactor without stepping on each other. Design a multi-agent harness and rules for delegation.", + "expected_output": "Coordinator/delegation design with ownership boundaries, context sharing policy, and merge/review gates", + "files": [], + "expectations": [ + "Defines coordinator, worker, and optional reviewer responsibilities", + "Assigns disjoint file or module ownership", + "Prevents recursive fork children from forking again", + "Includes integration and verification gate before claiming done" + ] + }, + { + "id": 9, + "name": "Lifecycle Bootstrap", + "prompt": "Every new session starts inconsistently. Design startup, hook, and handoff lifecycle rules so a new agent can resume safely.", + "expected_output": "Lifecycle bootstrap design with init.sh, clean-state checks, handoff reads, and hook trust boundaries", + "files": [], + "expectations": [ + "init.sh is the standard startup and verification entrypoint", + "Startup reads AGENTS.md, feature_list.json, progress.md, and handoff when present", + "End-of-session procedure records evidence, blockers, and next step", + "Hooks are gated by trust and failure behavior is explicit" + ] + }, + { + "id": 10, + "name": "Scripted Harness Validation", + "prompt": "Use the harness-creator scripts to scaffold a harness, validate it, and produce an HTML assessment report for a repository.", + "expected_output": "Commands using create-harness.mjs, validate-harness.mjs, and render-assessment-html.mjs plus interpretation of score", + "files": [], + "expectations": [ + "Uses create-harness.mjs with a target directory", + "Uses validate-harness.mjs and explains five-subsystem score output", + "Uses render-assessment-html.mjs or run-benchmark.mjs with --html", + "Explains that structural benchmark complements but does not replace real before/after agent sessions" + ] + } + ] +} diff --git a/.agents/skills/harness-creator/references/context-engineering-pattern.md b/.agents/skills/harness-creator/references/context-engineering-pattern.md new file mode 100644 index 00000000..6bf6e3d8 --- /dev/null +++ b/.agents/skills/harness-creator/references/context-engineering-pattern.md @@ -0,0 +1,150 @@ +# Context Engineering Pattern + +## Problem + +Agents fail when context is managed poorly: +- **Too much context** → Session startup is slow, token costs explode, model gets lost in details +- **Too little context** → Agent makes wrong assumptions, reinvents wheels, violates conventions +- **Wrong context** → Agent focuses on low-level details, misses architectural constraints + +Context is not a dump. It's a budget that must be managed with explicit operations. + +## Golden Rules + +### Four Context Operations + +Every token in the window should earn its place through one of four operations: + +1. **SELECT** — Load context just-in-time, not all-at-once +2. **WRITE** — Agent writes back to persistent storage (memory, state, rules) +3. **COMPRESS** — Reactive compaction of older turns mid-session +4. **ISOLATE** — Delegated work must not pollute parent context + +### Progressive Disclosure + +Three-tier loading: + +``` +Tier 1: Metadata (always present, cheap) + → Feature list, memory index, session status + +Tier 2: Instructions (loaded on activation) + → AGENTS.md, skill bodies, style guides + +Tier 3: Resources (loaded on demand) + → Architecture docs, API references, examples +``` + +### Memoize Expensive Builders, Invalidate Explicitly + +Context builders (e.g., "load all recent git commits") should be memoized to avoid redundant work, but **must** be invalidated at known mutation points — not reactively. Every mutation point must clear its corresponding cache. + +## When To Use + +- Agent performance degrades in long sessions +- Startup is slow due to eager context loading +- Delegated work pollutes the parent context +- Token costs are unpredictable + +## Tradeoffs + +| Decision | Benefit | Cost | +|---|---|---| +| JIT loading | Fast startup, low idle cost | Agent can't reason about skills until activated | +| Hard caps per block | Predictable token budget | May truncate useful context | +| Manual cache invalidation | No reactive staleness | Developer must add invalidation at each mutation | +| Isolation for delegation | Clean parent context | Child can't see parent's accumulated context | + +## Implementation Patterns + +### Select Pattern + +```markdown +## Startup Context (Loaded Immediately) + +- Repository root path +- Tech stack (one line) +- Active feature ID from feature_list.json + +## On-Demand Context (Loaded When Triggered) + +- Skill: Read when skill activates +- Architecture docs: Read when implementing new feature +- API reference: Read when calling external services +``` + +**Key moves:** +- Audit current context cost per turn +- Apply hard caps to every variable-length block +- Add truncation recovery pointers ("call list_files for full output") + +### Compress Pattern + +Long sessions exhaust the window. Reactive compaction: + +1. **Trigger**: Context usage exceeds threshold (e.g., 80%) +2. **Summarize**: Older turns (first 50% by token count) +3. **Preserve**: Recent context (last 20% of turns) +4. **Label**: Mark snapshot as "compacted at turn N" + +```markdown +## Session Summary (Turns 1-15, compacted) + +**Goal**: Implement Q&A feature with citations +**Decisions made**: +- Use streaming response for UX +- Citation format: [doc:chunk] inline references +**Key files created**: +- src/services/QaService.ts +- src/shared/types.ts (extended with QaResult) +``` + +### Isolate Pattern + +Delegated work must not pollute parent context: + +| Pattern | Context Sharing | Best For | +|---|---|---| +| **Coordinator** (zero inheritance) | None — workers start fresh | Complex multi-phase tasks | +| **Fork** (full inheritance) | Full — single-level only | Quick parallel splits | +| **Swarm** (peer-to-peer) | Shared task list | Long-running independent work | + +**Key constraint**: Fork is single-level only — recursive forks multiply context cost exponentially. + +## Gotchas + +1. **Most async work skips "pending" state** — work units register directly as "running" +2. **Context builders are memoized but manually invalidated** — add invalidation or face staleness +3. **Truncation is silent until it fires** — hard caps enforced at read time +4. **Isolation boundary must be enforced at call time** — don't just remove tools from prompt + +## Related Patterns + +- [Memory Persistence](memory-persistence-pattern.md) — How memory layers interact with context +- [Multi-agent Coordination](multi-agent-pattern.md) — Context sharing across agents + +## Template: Context Budget + +```markdown +## Context Budget (Session) + +| Category | Budget | Current | Status | +|----------|--------|---------|--------| +| System prompt | 2,000 | 1,850 | ✓ | +| Instruction files | 3,000 | 2,400 | ✓ | +| Memory index | 1,000 | 600 | ✓ | +| Session history | 10,000 | 4,200 | ✓ | +| Working context | 15,000 | 3,100 | ✓ | +| **Total** | **31,000** | **12,150** | 39% used | + +**Compaction trigger**: 80% (24,800 tokens) +**Next action**: Trigger compaction at 24,800 tokens +``` + +## Evidence + +Context engineering patterns are observed in production agent runtimes where: +- Context budgets are explicit, not implicit +- Progressive disclosure reduces startup latency by 60-80% +- Manual cache invalidation prevents subtle staleness bugs +- Isolation patterns enable reliable multi-agent coordination diff --git a/.agents/skills/harness-creator/references/gotchas.md b/.agents/skills/harness-creator/references/gotchas.md new file mode 100644 index 00000000..c8cd51b7 --- /dev/null +++ b/.agents/skills/harness-creator/references/gotchas.md @@ -0,0 +1,209 @@ +# Gotchas — Harness Engineering Failure Modes + +Non-obvious principles that will cause bugs if you violate them. + +--- + +## 1. Memory Index Caps Fire Silently + +**Symptom**: Recent memories "disappear" without error. + +**Cause**: Index has hard caps (e.g., 200 lines / 25KB) enforced at read time. Long entries (multi-sentence summaries) hit byte cap while staying under line cap. + +**Fix**: Keep index entries to one-line hooks. Put detail in topic files. + +```markdown +✓ Good: "Use bun, not npm - user preference 2024-01-15" +✗ Bad: "The user prefers bun over npm because it's faster. This was discussed on 2024-01-15 when the user said 'use bun not npm' and I updated the package.json accordingly..." +``` + +--- + +## 2. Priority Ordering is Counterintuitive + +**Symptom**: Global rule silently overridden by local file. + +**Cause**: Local overrides beat project rules, which beat user rules, which beat org rules. If you inject at user level expecting it to dominate, a local override file in project root wins. + +**Fix**: Test with full instruction-file stack present: + +```bash +# Test priority ordering +cat ~/.claude/CLAUDE.md # User level +cat ./CLAUDE.md # Project level +cat ./CLAUDE.local.md # Local override (WINS) +``` + +--- + +## 3. Extraction Timing Creates Race Window + +**Symptom**: Background extractor writes memory, but user starts next turn before extraction completes. + +**Cause**: Extraction fires at end of response. User can send message before extraction finishes. + +**Fix**: Coalesce concurrent extraction requests. Advance cursor only after successful run. Failed extraction means those messages reconsidered next time. + +--- + +## 4. Derivable Content Doesn't Belong in Memory + +**Symptom**: Memory index fills with architecture details that stale quickly. + +**Cause**: Agent saves what's derivable from codebase (architecture, code patterns, version history). + +**Fix**: Exclude derivable content by design. Type taxonomy should forbid saving what's in the repo already. + +--- + +## 5. Concurrent Classification is Per-Call, Not Per-Tool + +**Symptom**: Tool marked "concurrent-safe" causes race conditions. + +**Cause**: Same tool can be safe for some inputs and unsafe for others. Don't assume tool's concurrency behavior is static. + +**Fix**: Classify each call at runtime: + +```typescript +// Don't do this: +toolRegistry.register('shell', { concurrentSafe: false }); + +// Do this: +function isCallConcurrentSafe(call: ToolCall): boolean { + if (call.args.command.startsWith('rm -rf')) return false; + if (call.args.command.startsWith('cat')) return true; + // ...runtime classification +} +``` + +--- + +## 6. Permission Evaluation Has Side Effects + +**Symptom**: Permission check changes behavior on subsequent calls. + +**Cause**: Permission evaluator tracks denials, transforms modes, updates state as side effect. Not a pure lookup function. + +**Fix**: Don't cache permission results across calls. Re-evaluate each call fresh. + +--- + +## 7. Most Async Work Skips "Pending" State + +**Symptom**: UI shows "pending" but work unit never enters that state. + +**Cause**: Work units register directly as "running" in practice. "Pending" exists in state machine but rarely used. + +**Fix**: Don't build UI that assumes every work unit starts pending. + +--- + +## 8. Fork Children Must Not Fork + +**Symptom**: Context cost explodes exponentially. + +**Cause**: Recursive forks multiply context: parent + child1 + child2 + grandchildren... + +**Fix**: Enforce single-level invariant. Keep fork tool in child's pool (for prompt cache sharing) but block at call time. + +--- + +## 9. Context Builders are Memoized but Manually Invalidated + +**Symptom**: Model sees stale data for entire session. + +**Cause**: Context builder cached at startup, but mutation doesn't clear cache. + +**Fix**: Every mutation point must explicitly clear its corresponding cache: + +```typescript +// Example: Cache invalidation at mutation point +async function editFile(path: string, content: string) { + await writeFile(path, content); + context.cache.invalidate(`file:${path}`); // MUST invalidate +} +``` + +--- + +## 10. Hook Trust is All-or-Nothing + +**Symptom**: Entire extension system disabled because one hook untrusted. + +**Cause**: If workspace untrusted, all hooks skip — not just suspicious ones. + +**Fix**: Design hooks with trust gate at dispatch point. Don't attempt per-hook trust evaluation. + +--- + +## 11. Eviction Requires Notification + +**Symptom**: Parent can never read work unit result. + +**Cause**: Work unit evicted before parent notified of completion. Race condition: parent tries to read result that's already GC'd. + +**Fix**: Two-phase eviction: +1. Clean disk output at terminal state (eager) +2. Clean in-memory record after parent notified (lazy) + +--- + +## 12. Skill Listing Budgets Are Tight + +**Symptom**: Skill description truncated, can't trigger properly. + +**Cause**: Skill descriptions concatenated and capped per entry (~150 chars). Front-loaded trigger language gets priority. + +**Fix**: Front-load distinctive trigger language: + +```markdown +✓ Good: "harness-patterns: Memory, permissions, context engineering, multi-agent" +✗ Bad: "A comprehensive skill for understanding and implementing various patterns related to AI agent harnesses and runtime systems..." +``` + +--- + +## 13. Default Tool Permission is "Allow" + +**Symptom**: Tool bypasses expected gate. + +**Cause**: Tools without custom permission logic delegate entirely to rule-based system. Default is "allow" unless configured otherwise. + +**Fix**: Override default for sensitive tools: + +```typescript +registry.register('shell', { + defaultPermission: 'ask', // NOT 'allow' + // ... +}); +``` + +--- + +## 14. Team Memory Requires Auto-Memory Enabled + +**Symptom**: Team-shared memory doesn't work even when configured. + +**Cause**: Team memory builds on same directory/index infrastructure as auto-memory. Disabling auto-memory (via env var or settings) also disables team memory. + +**Fix**: Ensure auto-memory enabled before enabling team memory. Check both feature gate and enablement check. + +--- + +## 15. Orphaned Topic Files Accumulate + +**Symptom**: Disk space fills with `.claude/memory/topics/` files. + +**Cause**: Two-step save (topic file then index). Crash between steps leaves orphaned topic file. + +**Fix**: Periodic sweep deletes topic files not referenced by index. Orphans don't corrupt index but consume disk space. + +--- + +## Related Reading + +- [Memory Persistence Pattern](memory-persistence-pattern.md) — Gotchas #1, #3, #4, #15 +- [Tool Registry Pattern](tool-registry-pattern.md) — Gotchas #5, #6, #13 +- [Multi-agent Pattern](multi-agent-pattern.md) — Gotchas #8, #11 +- [Context Engineering Pattern](context-engineering-pattern.md) — Gotchas #9 +- [Lifecycle Pattern](lifecycle-bootstrap-pattern.md) — Gotchas #10, #14 diff --git a/.agents/skills/harness-creator/references/lifecycle-bootstrap-pattern.md b/.agents/skills/harness-creator/references/lifecycle-bootstrap-pattern.md new file mode 100644 index 00000000..3fdb127c --- /dev/null +++ b/.agents/skills/harness-creator/references/lifecycle-bootstrap-pattern.md @@ -0,0 +1,264 @@ +# Lifecycle and Bootstrap Pattern + +## Problem + +Agent runtimes need extensibility without compromising safety: + +- **Hooks** — Extend behavior at lifecycle moments (pre/post tool execution, session start/end) +- **Background tasks** — Track long-running work without blocking the main agent +- **Bootstrap** — Structure initialization across multiple entry modes (CLI, server, SDK) + +But uncontrolled extensibility creates: +- Security holes from untrusted hooks +- Resource leaks from tasks that never complete +- Race conditions in initialization + +## Golden Rules + +### Hook Trust is All-or-Nothing + +If the workspace is untrusted, **all hooks skip** — not just suspicious ones. Session-scoped hooks are ephemeral and cleaned on session end. + +```typescript +// Example: Hook dispatch with trust gate +async function dispatchHook( + hookType: HookType, + context: HookContext +): Promise { + + // Trust gate: if workspace untrusted, skip ALL hooks + if (!context.trustBoundary.crossed) { + logger.warn('Untrusted workspace, skipping hooks'); + return []; + } + + // Session-scoped hooks ephemeral — cleanup on session end + const sessionHooks = context.hooks.getByScope('session'); + const projectHooks = context.hooks.getByScope('project'); + + return await Promise.all([ + ...sessionHooks.map(h => h.execute(context)), + ...projectHooks.map(h => h.execute(context)), + ]); +} +``` + +### Long-Running Work: Typed State Machines with Two-Phase Eviction + +Each work unit gets: +1. **Typed, prefixed ID** (e.g., `extractor-001`, `benchmark-002`) +2. **Strict lifecycle** (running → completed | failed | killed) +3. **Disk-backed output** (not just in-memory) + +Eviction is two-phase: +1. **Disk output** cleaned eagerly at terminal state +2. **In-memory records** cleaned lazily after parent notified + +### Bootstrap: Dependency-Ordered, Memoized Stages + +Multiple entry modes (CLI, server, SDK) share the same bootstrap path: + +``` +Stage 1: Create minimal context (no trust required) + ↓ +Stage 2: Load tools (read-only safe) + ↓ +Stage 3: Trust boundary crossed (user grants consent) + ↓ +Stage 4: Load security-sensitive subsystems (telemetry, secret env vars) +``` + +**Critical inflection**: Security-sensitive subsystems must not activate before trust is established. + +## When To Use + +- You need to extend agent behavior without modifying core code +- You need to track long-running background work +- You need structured initialization across multiple entry modes +- You need hooks at lifecycle moments (pre/post tool, session start/end) + +## Tradeoffs + +| Decision | Benefit | Cost | +|---|---|---| +| All-or-nothing hook trust | Simple security boundary | One untrusted hook disables entire extension system | +| Disk-backed task output | Memory constant regardless of concurrent work | I/O latency proportional to work units | +| Dependency-ordered bootstrap | Multiple entry modes share path | Initial startup sequential (can't parallelize stages) | +| Memoized stages | Re-init is fast | Must carefully invalidate memoization on config change | + +## Implementation Patterns + +### Hook Lifecycle + +Six hook types dispatched at defined moments: + +```typescript +interface HookRegistry { + // Session lifecycle + onSessionStart: (context: SessionContext) => Promise; + onSessionEnd: (context: SessionContext) => Promise; + + // Tool execution + preToolExecute: (context: ToolContext) => Promise; + postToolExecute: (context: ToolResult) => Promise; + + // Prompt submission + prePromptSubmit: (context: PromptContext) => Promise; + postPromptSubmit: (context: ResponseContext) => Promise; +} + +// Usage: Register hooks via config +// /update-config hooks.preToolExecute = "scripts/audit-tool-call.js" +``` + +### Long-Running Task Tracking + +```typescript +interface TaskRegistry { + // Typed prefixed IDs + registerWork( + type: 'extraction' | 'benchmark' | 'indexing', + outputType: 'json' | 'text' | 'file' + ): string; // Returns typed ID: `extraction-001` + + // Strict state machine + updateState( + taskId: string, + state: 'running' | 'completed' | 'failed' | 'killed', + output?: any + ): void; + + // Two-phase eviction + evictTask(taskId: string): void; + // 1. Clean disk output (eager, at terminal state) + // 2. Clean in-memory record (lazy, after parent notified) +} +``` + +### Bootstrap Sequence + +```typescript +// Example: Dependency-ordered initialization +class AgentBootstrap { + private stages = new Map(); + private memoizedCallers = new Map(); + + async bootstrap(entryMode: 'cli' | 'server' | 'sdk'): Promise { + + // Stage 1: Minimal context (no trust required) + await this.runStage('minimal-context', async () => { + return { + cwd: process.cwd(), + entryMode, + trustBoundary: { crossed: false }, + }; + }); + + // Stage 2: Load tools (read-only safe) + await this.runStage('load-tools', async (context) => { + context.tools = await this.loadSafeTools(); + return context; + }); + + // Stage 3: Trust boundary (user grants consent) + await this.runStage('trust-boundary', async (context) => { + const consent = await this.requestConsent(); + context.trustBoundary = { crossed: consent }; + return context; + }); + + // Stage 4: Security-sensitive subsystems (requires trust) + if (context.trustBoundary.crossed) { + await this.runStage('load-sensitive', async (context) => { + context.telemetry = await this.loadTelemetry(); + context.secretEnvVars = await this.loadSecrets(); + return context; + }); + } + + return context; + } + + private async runStage( + name: string, + fn: (context: AgentContext) => Promise + ): Promise { + // Memoized: skip if already run + if (this.stages.has(name) && this.stages.get(name).complete) { + return; + } + + // Run stage + const stage = { name, complete: false, running: true }; + this.stages.set(name, stage); + + try { + await fn(this.context); + stage.complete = true; + } finally { + stage.running = false; + } + } +} +``` + +## Gotchas + +1. **Hook trust is all-or-nothing** — One untrusted hook disables entire extension system +2. **Most async work skips "pending" state** — Work units register directly as "running" +3. **Eviction requires notification** — Terminal work unit only GC-eligible after parent notified +4. **Fast-path dispatch** — Memoized callers must handle concurrent calls without re-running stages +5. **Hook types must be disjoint** — Don't create overlapping hook scopes + +## Related Patterns + +- [Tool Registry](tool-registry-pattern.md) — How tools are registered at bootstrap +- [Memory Persistence](memory-persistence-pattern.md) — How memory is loaded at init + +## Template: Bootstrap Checklist + +Before declaring bootstrap complete: + +```markdown +## Bootstrap Verification + +### Stage 1: Minimal Context +- [ ] Working directory confirmed +- [ ] Entry mode determined (cli / server / sdk) +- [ ] Trust boundary NOT crossed (no secrets loaded) + +### Stage 2: Tools Loaded +- [ ] Read-only tools registered (read, search, glob) +- [ ] Write tools NOT yet registered (edit, shell) +- [ ] Tool permissions set to default (ask / deny) + +### Stage 3: Trust Boundary +- [ ] User consent requested (interactive or config flag) +- [ ] Consent recorded in session state +- [ ] Security audit logged + +### Stage 4: Sensitive Subsystems +- [ ] Telemetry initialized (if consent given) +- [ ] Secret env vars loaded (if consent given) +- [ ] Write tools registered (edit, shell, exec) +- [ ] Hook system enabled (if workspace trusted) + +### Stage 5: Background Tasks +- [ ] Task registry initialized +- [ ] Cleanup handlers registered +- [ ] Drain-on-shutdown configured + +## If Any Stage Fails + +- Bootstrap halts immediately +- Session remains in safe mode (read-only) +- Error logged with stage name and failure reason +``` + +## Evidence + +Lifecycle and bootstrap patterns are observed in production runtimes where: +- Hook dispatch is all-or-nothing based on workspace trust +- Long-running tasks use typed prefixed IDs and disk-backed output +- Bootstrap is dependency-ordered with memoized stages +- Trust boundary is explicit inflection point for security-sensitive subsystems diff --git a/.agents/skills/harness-creator/references/memory-persistence-pattern.md b/.agents/skills/harness-creator/references/memory-persistence-pattern.md new file mode 100644 index 00000000..089e0ac7 --- /dev/null +++ b/.agents/skills/harness-creator/references/memory-persistence-pattern.md @@ -0,0 +1,110 @@ +# Memory and Persistence Pattern + +## Problem + +Without persistent memory, an agent loses all user preferences, project context, and behavioral feedback the moment a session ends. Users must repeat corrections every session ("use bun, not npm"), and the agent cannot accumulate the working knowledge that makes it genuinely useful over time. + +## Golden Rules + +### Separate layers by scope and durability + +- **Instruction memory** (human-curated, version-controlled): AGENTS.md, CLAUDE.md, project conventions +- **Auto-memory** (agent-written, persistent): Progress logs, session handoffs, discovered patterns +- **Session extraction** (background-derived): Automatic transcript analysis at session end + +### Two-step save invariant + +Every memory write is a two-step operation: +1. Write the full content to a dedicated topic file +2. Append a one-line pointer to the index + +If the process crashes between steps, the worst outcome is an orphaned topic file — the index remains consistent. + +### Local overrides win — always + +When the same topic is addressed at multiple scopes, the most-local instruction takes priority: + +``` +Organization-wide → User-level → Project-level → Local override + ↓ ↓ ↓ ↓ + sets floor narrows it narrows further final say +``` + +### The index is bounded always-on context; topic files are on-demand detail + +- **Index**: Hard-capped at ~200 lines / 25KB, one line per entry +- **Topic files**: Unlimited detail, loaded on demand + +## When To Use + +- Your agent persists across sessions and must recall user preferences or project context +- Multiple scopes of instruction coexist and need clear priority ordering +- The agent should learn from sessions without manual curation +- You need background extraction that doesn't block the user + +## Tradeoffs + +| Decision | Benefit | Cost | +|---|---|---| +| Layered memory | Each scope can be shared, audited, overridden independently | More files to discover at startup | +| Local-wins priority | Users can override without touching shared files | Global rule can be silently overridden | +| Bounded index with on-demand topics | Constant context cost regardless of memory volume | Agent must perform extra retrieval step | +| Background extraction | No latency added to user responses | Race window between extraction and next turn | + +## Implementation Patterns + +1. **Define memory directory** idempotently at startup (e.g., `.claude/memory/`) +2. **Create index file** with hard caps enforced at read time +3. **Implement two-step save**: topic file first, then index update +4. **Fire background extraction** only after final response with no pending tool calls +5. **Enforce mutual exclusion**: if main agent wrote to memory, skip extraction that turn +6. **Build review mechanism** for cross-layer promotion proposals + +## Gotchas + +1. **Index truncation is silent until it fires** — keep entries short +2. **Priority ordering is counterintuitive** — local beats project beats user beats org +3. **Extraction timing creates a race window** — user can start next turn before extraction completes +4. **Derivable content doesn't belong in memory** — architecture and code patterns are re-derivable from the codebase +5. **Orphaned topic files accumulate** — periodic cleanup recommended + +## Related Patterns + +- [Context Engineering](context-engineering-pattern.md) — How to manage context budget across layers +- [Lifecycle & Bootstrap](lifecycle-bootstrap-pattern.md) — How initialization loads memory + +## Template: Progress Log Structure + +```markdown +# Session Progress Log + +## Current State (Last Updated: YYYY-MM-DD HH:MM) + +**Active Feature:** feat-003 - Q&A with Citations +**Status:** In Progress (60% complete) + +### What's Done +- [x] Document chunking pipeline +- [x] Index data structure +- [ ] Q&A handler (in progress) + +### What's In Progress +- Implementing Q&A IPC handler +- Need to decide: streaming vs batch response + +### Blockers +- Waiting on decision: citation format (footnotes vs inline) + +### Next Session Should +1. Complete Q&A handler +2. Add citation formatting +3. Test end-to-end flow +``` + +## Evidence + +This pattern is grounded in production agent runtimes including Claude Code's memory system, which implements: +- Four-level instruction hierarchy (org/user/project/local) +- Four-type auto-memory taxonomy (user/feedback/project/reference) +- Background session extraction with mutual exclusion +- Team-shared memory as an extension layer diff --git a/.agents/skills/harness-creator/references/multi-agent-pattern.md b/.agents/skills/harness-creator/references/multi-agent-pattern.md new file mode 100644 index 00000000..36a0aa3f --- /dev/null +++ b/.agents/skills/harness-creator/references/multi-agent-pattern.md @@ -0,0 +1,193 @@ +# Multi-Agent Coordination Pattern + +## Problem + +Single agents hit limits: +- **Context limits** — Can't hold full research + implementation in one session +- **Specialization** — Need separate researchers, implementers, reviewers +- **Parallelism** — Want to explore multiple approaches simultaneously + +But multi-agent systems introduce chaos: +- Workers duplicate each other's research +- Coordinators delegate understanding instead of synthesizing +- Context inheritance explodes exponentially + +## Golden Rules + +### The Coordinator Must Synthesize, Not Delegate Understanding + +**Anti-pattern:** +> "Based on your findings, fix the authentication system." + +**Pattern:** +> "Research identified 3 auth flows: login, logout, token refresh. Implement ONLY the token refresh handler using the JWT strategy documented in [research output]. Return: implementation diff + test results." + +The coordinator (orchestrator) adds value by digesting worker results into precise specs before dispatching implementation. + +### Three Delegation Patterns + +| Pattern | Context Sharing | Best For | Constraints | +|---------|----------------|----------|-------------| +| **Coordinator** | None — workers start fresh | Complex multi-phase tasks (research → synthesize → implement → verify) | Slowest but safest | +| **Fork** | Full — child inherits parent history | Quick parallel splits sharing loaded context | **Single-level only** — recursive forks multiply context cost | +| **Swarm** | Peer-to-peer via shared task list | Long-running independent workstreams | **Flat roster** — teammates can't spawn other teammates | + +### Results Arrive Asynchronously; Fire-and-Forget Registration Returns ID Immediately + +```typescript +// Example: Spawn worker, get ID back immediately +const taskId = await coordinator.spawn({ + type: 'research', + prompt: 'Analyze auth flows...', + toolFilter: ['read', 'search'], // Restrict tools +}); + +// Parent can continue working while worker runs +// Results arrive via callback or polling +``` + +## When To Use + +- Task too large for single agent session +- Need parallel exploration (e.g., prototype multiple approaches) +- Want persistent specialized teammates (researcher, implementer, reviewer) +- Complex multi-phase workflows + +## Tradeoffs + +| Pattern | Speed | Safety | Context Cost | +|---------|-------|--------|--------------| +| **Coordinator** | Slowest | Safest | Lowest (zero inheritance) | +| **Fork** | Fastest | Medium | Highest (full inheritance) | +| **Swarm** | Medium | Medium | Medium (shared state only) | + +## Implementation Patterns + +### Coordinator Pattern (Recommended for Complex Tasks) + +Phased workflow: + +``` +Phase 1: Research + ↓ (synthesize findings) +Phase 2: Plan + ↓ (precise specs) +Phase 3: Implement + ↓ (verify) +Phase 4: Review +``` + +```typescript +// Example: Coordinator workflow +const research = await coordinator.spawn({ + role: 'researcher', + prompt: `Analyze existing authentication in ${authDir}. + Find: login flow, logout flow, token handling. + Return: structured findings only. NO implementation suggestions.`, + toolFilter: ['read', 'search', 'glob'], // Can't write +}); + +await coordinator.synthesize(research.results); + +const implement = await coordinator.spawn({ + role: 'implementer', + prompt: `Implement token refresh handler using the JWT strategy + from [Phase 2 findings]. + Constraints: Use existing AuthService patterns, add tests.`, + toolFilter: ['read', 'search', 'edit', 'test'], // Can write +}); +``` + +### Fork Pattern (Single-Level Only) + +```typescript +// Parent spawns children for parallel work +const forks = await Promise.all([ + coordinator.fork({ + prompt: 'Implement login handler', + inheritContext: true, // Full parent history + }), + coordinator.fork({ + prompt: 'Implement logout handler', + inheritContext: true, + }), +]); + +// CRITICAL: Children must not fork recursively +// If allowed, context cost multiplies: parent + child1 + child2 + ... +``` + +### Swarm Pattern (Flat Roster) + +```typescript +// Swarm: persistent team with shared task list +const swarm = new Swarm([ + { id: 'researcher', specialty: 'research' }, + { id: 'implementer', specialty: 'implementation' }, + { id: 'reviewer', specialty: 'verification' }, +]); + +// Agents pick tasks from shared queue +// Results posted back to shared state +await swarm.dispatch({ + taskId: 'feat-001', + pickedBy: 'implementer', +}); +``` + +## Gotchas + +1. **Fork children must not fork** — Recursive guard preserves single-level invariant. Keep fork tool in child's pool (for prompt cache sharing) but block at call time. +2. **Coordinator workers start with zero context** — Only explicit prompt is passed. Don't assume child sees parent's accumulated research. +3. **Swarm teammates cannot spawn other teammates** — Roster is flat to prevent uncontrolled growth. +4. **Write self-contained prompts** — "Based on your findings" is an anti-pattern. Coordinator must digest first. +5. **Filter each worker's tool set** — Researcher doesn't need write; implementer doesn't need broad search. + +## Related Patterns + +- [Context Engineering](context-engineering-pattern.md) — Isolation patterns for delegation +- [Lifecycle & Bootstrap](lifecycle-bootstrap-pattern.md) — How agents are spawned at init + +## Template: Worker Prompt Structure + +```markdown +# Self-Contained Worker Prompt + +## Context (Copied from Coordinator Synthesis) + +**Task**: Implement token refresh handler +**Background**: Research identified JWT-based auth with 24h access tokens. +**Decision**: Use refresh token rotation (new refresh token on each refresh). + +## Your Role + +You are an **implementer**. Your job is to write production code following the specs above. + +## Constraints + +- Use existing patterns from `${authServicePath}` +- Add tests for success and failure cases +- Do NOT modify login/logout handlers (separate task) + +## Your Tools + +- read, search, edit, test +- Shell: npm test, npm run check only + +## Deliverable + +Return: +1. Implementation diff (files changed) +2. Test results (pass/fail) +3. Any blockers or clarifications needed + +**Do NOT return**: Research findings, architectural debates, alternative designs. +``` + +## Evidence + +Multi-agent coordination patterns are observed in production systems where: +- Coordinator workers start with zero context inheritance +- Fork is restricted to single-level to control context explosion +- Swarm agents communicate through shared task lists, not direct prompts +- Results arrive asynchronously with fire-and-forget registration diff --git a/.agents/skills/harness-creator/references/skill-runtime-pattern.md b/.agents/skills/harness-creator/references/skill-runtime-pattern.md new file mode 100644 index 00000000..963d98ec --- /dev/null +++ b/.agents/skills/harness-creator/references/skill-runtime-pattern.md @@ -0,0 +1,43 @@ +# Skill Runtime Pattern + +Use this pattern when you want to package reusable agent behavior as a skill instead of repeating long instructions in every repository. + +## What Belongs in a Skill + +- Reusable workflows that apply across projects. +- Domain-specific decision procedures. +- Templates, checklists, and reference material the agent should load on demand. +- Small helper scripts when they are stable and safe to run. + +## What Does Not Belong in a Skill + +- Project-specific architecture facts that should live in the target repository. +- Secrets, tokens, private URLs, or user-specific credentials. +- Large manuals that the agent must always read before acting. +- Commands with destructive side effects unless they are clearly documented and require explicit user approval. + +## Runtime Shape + +A production skill should use progressive disclosure: + +1. `SKILL.md` frontmatter explains when the skill should trigger. +2. The body gives the shortest reliable workflow. +3. `references/` contains deeper material loaded only when relevant. +4. `templates/` contains copyable artifacts. +5. `evals/` captures representative quality checks. + +## Design Rules + +- Keep the entry file concise enough to scan quickly. +- Prefer concrete checklists over abstract advice. +- Link every referenced bundled file and verify it exists. +- Make installation instructions explicit about the repository, skill name, and target agent. +- Treat scripts as optional helpers, not hidden behavior. + +## Validation Checklist + +- [ ] `SKILL.md` exists and has valid frontmatter. +- [ ] Every referenced file exists inside the skill directory. +- [ ] Templates are safe to copy into a target repository. +- [ ] Installation command has been tested with `skills add --list` or equivalent. +- [ ] The skill does not depend on private local paths. diff --git a/.agents/skills/harness-creator/references/tool-registry-pattern.md b/.agents/skills/harness-creator/references/tool-registry-pattern.md new file mode 100644 index 00000000..1a38db9c --- /dev/null +++ b/.agents/skills/harness-creator/references/tool-registry-pattern.md @@ -0,0 +1,200 @@ +# Tool Registry and Safety Pattern + +## Problem + +Agents need tools (shell, file edit, search, etc.) to be productive. But unbounded tool access creates risks: + +- Destructive operations (rm -rf, DROP TABLE, etc.) +- Race conditions from concurrent tool calls +- Silent policy violations from misconfigured permissions + +The solution is a **fail-closed registry** with explicit concurrency classification and a multi-source permission pipeline. + +## Golden Rules + +### Default to Fail-Closed + +Tools are **non-concurrent** and **non-read-only** unless explicitly marked safe. This prevents: +- Accidental parallel execution of state-mutating operations +- Silent data corruption from concurrent writes + +### Concurrency is Per-Call, Not Per-Tool + +The same tool can be safe for some inputs and unsafe for others: + +``` +✓ Safe (can run in parallel): + - cat file1.txt + - grep "pattern" src/ + - ls -la + +✗ Unsafe (must run serially): + - rm -rf build/ + - npm install (network, filesystem mutation) + - sed -i 's/old/new/g' *.ts +``` + +The runtime partitions a batch of tool calls into consecutive groups: safe calls run in parallel; any unsafe call starts a serial segment. + +### Permission Pipeline has Side Effects + +The permission evaluator is **stateful** — it: +- Tracks denials (for audit and rate limiting) +- Transforms modes (e.g., auto → ask after denial) +- Updates session state as a side effect + +**Strict priority order:** +``` +Policy (org-wide) → User settings → Project rules → Local overrides → Session grants +``` + +## When To Use + +- Your agent runtime needs tool registration +- You need concurrency control for parallel tool calls +- You need permission gating (auto-approve, ask-first, deny) +- You need to track tool usage for audit + +## Tradeoffs + +| Decision | Benefit | Cost | +|---|---|---| +| Fail-closed defaults | New tools are safe out of the box | Developers must actively opt into concurrency | +| Per-call classification | Fine-grained control over parallelism | Requires analyzing each call, not just tool registration | +| Multi-source permission layering | Flexible policy composition | Hard to debug when rules conflict | +| Stateful evaluator | Can adapt behavior based on history | Not a pure function — harder to test | + +## Implementation Patterns + +### Tool Registration + +```typescript +// Example: Tool registry entry +interface ToolDefinition { + name: string; + description: string; + handler: (args: any) => Promise; + + // Safety classification + isReadOnly: boolean; // Default: false + isConcurrentSafe: boolean; // Default: false + + // Optional custom permission logic + permissionCheck?: (args: any, context: ToolContext) => PermissionResult; +} + +// Register tools +registry.register('read_file', { + name: 'read_file', + description: 'Read contents of a file', + handler: readFile, + isReadOnly: true, + isConcurrentSafe: true, // Safe to read multiple files in parallel +}); + +registry.register('write_file', { + name: 'write_file', + description: 'Write or overwrite a file', + handler: writeFile, + isReadOnly: false, + isConcurrentSafe: false, // Must run serially to prevent race conditions +}); +``` + +### Permission Pipeline + +```typescript +// Permission evaluation order +async function evaluatePermission( + toolCall: ToolCall, + context: PermissionContext +): Promise { + + // 1. Policy rules (highest priority, org-wide) + const policyResult = await policyEngine.check(toolCall, context); + if (policyResult !== 'defer') return policyResult; + + // 2. User settings + const userResult = await userSettings.check(toolCall, context); + if (userResult !== 'defer') return userResult; + + // 3. Project rules + const projectResult = await projectRules.check(toolCall, context); + if (projectResult !== 'defer') return projectResult; + + // 4. Local overrides + const localResult = await localOverrides.check(toolCall, context); + if (localResult !== 'defer') return localResult; + + // 5. Session grants (lowest priority) + return sessionGrants.check(toolCall, context); +} +``` + +### Bypass-Immune Rules + +Certain paths or operations should never be auto-approved: + +```yaml +# Protected paths (never auto-approve) +protected_paths: + - /etc/** + - /usr/** + - node_modules/** + - .git/** + +# Protected commands (always ask) +protected_commands: + - "rm -rf*" + - "DROP TABLE*" + - "DELETE FROM*" + - "mkfs*" +``` + +## Gotchas + +1. **Most async work skips "pending" state** — work units register directly as "running" +2. **Permission evaluation has side effects** — don't cache results across calls +3. **Concurrency classification requires analyzing inputs**, not just tool name +4. **The default permission for tools is "allow"** — tools without custom logic delegate to rule-based system +5. **Eviction requires notification** — terminal work units only GC-eligible after parent notified + +## Related Patterns + +- [Lifecycle & Bootstrap](lifecycle-bootstrap-pattern.md) — How tools are registered at init +- Hook Lifecycle (`hook-lifecycle-pattern.md`) — Pre/post tool execution hooks + +## Template: Tool Safety Checklist + +Before enabling a new tool: + +```markdown +## Tool Safety Review + +**Tool name**: [e.g., execute_shell] + +### Classification +- [ ] Determined if read-only (true / false / depends on args) +- [ ] Determined if concurrent-safe (true / false / depends on args) +- [ ] Documented unsafe input patterns + +### Permission Requirements +- [ ] Default mode set to "ask" or "deny" +- [ ] Bypass-immune paths/commands defined +- [ ] Custom permission logic implemented (if needed) +- [ ] Audit logging enabled + +### Testing +- [ ] Tested with safe inputs (should auto-approve) +- [ ] Tested with unsafe inputs (should ask/deny) +- [ ] Tested concurrent execution (should serialize if unsafe) +- [ ] Tested error handling (failures logged, state consistent) +``` + +## Evidence + +Tool registry and safety patterns are observed in production agent runtimes including: +- Claude Code's tool registry with explicit concurrency flags +- Multi-source permission evaluation (settings → project → session) +- Protected path/command lists that bypass auto-approve modes +- Per-call concurrency classification that partitions tool batches diff --git a/.agents/skills/harness-creator/scripts/create-harness.mjs b/.agents/skills/harness-creator/scripts/create-harness.mjs new file mode 100755 index 00000000..1a33a7f6 --- /dev/null +++ b/.agents/skills/harness-creator/scripts/create-harness.mjs @@ -0,0 +1,75 @@ +#!/usr/bin/env node +import { chmod, mkdir } from 'node:fs/promises'; +import path from 'node:path'; +import { + copyTemplate, + detectPackageManager, + detectProject, + exists, + initScriptFromCommands, + parseArgs, + verificationCommands, + writeText +} from './lib/harness-utils.mjs'; + +const args = parseArgs(process.argv.slice(2)); + +if (args.help) { + console.log(`Usage: node scripts/create-harness.mjs [--target DIR] [--agent-file AGENTS.md|CLAUDE.md] [--package-manager npm|pnpm|yarn|bun] [--force] + +Creates a minimal production harness: + AGENTS.md or CLAUDE.md + feature_list.json + progress.md + session-handoff.md + init.sh + +Existing files are skipped unless --force is set.`); + process.exit(0); +} + +const target = path.resolve(args.target || args._[0] || process.cwd()); +const agentFile = args.agentFile || 'AGENTS.md'; +const force = Boolean(args.force); +const project = await detectProject(target); +project.packageManager = detectPackageManager(target, args.packageManager); +const commands = args.commands + ? String(args.commands).split(',').map((command) => command.trim()).filter(Boolean) + : verificationCommands(project, args.packageManager); + +await mkdir(target, { recursive: true }); + +const replacements = { + AGENT_FILE_NAME: agentFile, + PROJECT_PURPOSE: project.stack === 'generic' + ? 'Project harness for reliable agent-assisted development.' + : `Project harness for reliable agent-assisted development in a ${project.stack} codebase.`, + VERIFICATION_COMMANDS: commands.map((command) => `- \`${command}\``).join('\n'), + PRIMARY_VERIFICATION_COMMAND: './init.sh' +}; + +const results = []; +results.push(await copyTemplate('agents.md', path.join(target, agentFile), replacements, { force })); +results.push(await copyTemplate('feature-list.json', path.join(target, 'feature_list.json'), {}, { force })); +results.push(await copyTemplate('progress.md', path.join(target, 'progress.md'), {}, { force })); +results.push(await copyTemplate('session-handoff.md', path.join(target, 'session-handoff.md'), {}, { force })); + +const initPath = path.join(target, 'init.sh'); +if (force || !await exists(initPath)) { + await writeText(initPath, initScriptFromCommands(commands)); + await chmod(initPath, 0o755); + results.push({ path: initPath, status: 'written' }); +} else { + results.push({ path: initPath, status: 'skipped', reason: 'exists' }); +} + +console.log(`Created harness for ${target}`); +console.log(`Detected stack: ${project.stack}`); +console.log(`Verification commands:`); +for (const command of commands) { + console.log(` - ${command}`); +} +console.log(''); +for (const result of results) { + console.log(`${result.status.toUpperCase()} ${path.relative(target, result.path)}${result.reason ? ` (${result.reason})` : ''}`); +} diff --git a/.agents/skills/harness-creator/scripts/lib/harness-utils.mjs b/.agents/skills/harness-creator/scripts/lib/harness-utils.mjs new file mode 100644 index 00000000..fbe35718 --- /dev/null +++ b/.agents/skills/harness-creator/scripts/lib/harness-utils.mjs @@ -0,0 +1,407 @@ +import { existsSync } from 'node:fs'; +import { access, chmod, copyFile, mkdir, readFile, readdir, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +export const SKILL_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..'); +export const TEMPLATE_DIR = path.join(SKILL_ROOT, 'templates'); +export const SUBSYSTEMS = ['instructions', 'state', 'verification', 'scope', 'lifecycle']; + +export function parseArgs(argv) { + const args = { _: [] }; + for (let i = 0; i < argv.length; i += 1) { + const token = argv[i]; + if (!token.startsWith('--')) { + args._.push(token); + continue; + } + const [rawKey, inlineValue] = token.slice(2).split('=', 2); + const key = rawKey.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()); + if (inlineValue !== undefined) { + args[key] = inlineValue; + } else if (argv[i + 1] && !argv[i + 1].startsWith('--')) { + args[key] = argv[i + 1]; + i += 1; + } else { + args[key] = true; + } + } + return args; +} + +export async function exists(filePath) { + try { + await access(filePath); + return true; + } catch { + return false; + } +} + +export async function readText(filePath) { + return readFile(filePath, 'utf8'); +} + +export async function readJson(filePath) { + return JSON.parse(await readText(filePath)); +} + +export async function writeText(filePath, contents) { + await mkdir(path.dirname(filePath), { recursive: true }); + await writeFile(filePath, contents, 'utf8'); +} + +export async function copyTemplate(templateName, targetPath, replacements = {}, { force = false } = {}) { + if (!force && await exists(targetPath)) { + return { path: targetPath, status: 'skipped', reason: 'exists' }; + } + + let contents = await readText(path.join(TEMPLATE_DIR, templateName)); + for (const [key, value] of Object.entries(replacements)) { + contents = contents.split(`{{${key}}}`).join(value); + } + await writeText(targetPath, contents); + if (templateName.endsWith('.sh')) { + await chmod(targetPath, 0o755); + } + return { path: targetPath, status: 'written' }; +} + +export function detectPackageManager(root, explicit) { + if (explicit) return explicit; + if (existsSync(path.join(root, 'bun.lockb')) || existsSync(path.join(root, 'bun.lock'))) return 'bun'; + if (existsSync(path.join(root, 'pnpm-lock.yaml'))) return 'pnpm'; + if (existsSync(path.join(root, 'yarn.lock'))) return 'yarn'; + return 'npm'; +} + +export async function detectProject(root) { + const files = await listFiles(root, { maxFiles: 800 }); + const has = (name) => files.some((file) => file === name || file.endsWith(`/${name}`)); + const hasPrefix = (prefix) => files.some((file) => file.startsWith(prefix)); + const packageJsonPath = path.join(root, 'package.json'); + const packageJson = await exists(packageJsonPath).then((ok) => ok ? readJson(packageJsonPath) : null); + + let stack = 'generic'; + if (packageJson) { + const deps = { ...packageJson.dependencies, ...packageJson.devDependencies }; + if (deps.react || hasPrefix('src/renderer')) stack = 'typescript-react'; + else if (deps.typescript || has('tsconfig.json')) stack = 'typescript'; + else stack = 'node'; + } else if (has('pyproject.toml') || has('requirements.txt')) { + stack = 'python'; + } else if (has('go.mod')) { + stack = 'go'; + } else if (has('Cargo.toml')) { + stack = 'rust'; + } else if (has('pom.xml')) { + stack = 'java-maven'; + } else if (has('build.gradle') || has('build.gradle.kts')) { + stack = 'java-gradle'; + } else if (files.some((file) => file.endsWith('.csproj') || file.endsWith('.sln'))) { + stack = 'dotnet'; + } + + return { + root, + stack, + packageJson, + files, + packageManager: detectPackageManager(root) + }; +} + +export async function listFiles(root, { maxFiles = 1000 } = {}) { + const ignored = new Set(['.git', 'node_modules', 'dist', 'build', '.next', '.venv', 'venv', '__pycache__']); + const results = []; + + async function walk(current, relative) { + if (results.length >= maxFiles) return; + let entries = []; + try { + entries = await readdir(current, { withFileTypes: true }); + } catch { + return; + } + for (const entry of entries) { + if (results.length >= maxFiles) return; + if (ignored.has(entry.name)) continue; + const rel = relative ? `${relative}/${entry.name}` : entry.name; + const full = path.join(current, entry.name); + if (entry.isDirectory()) { + await walk(full, rel); + } else if (entry.isFile()) { + results.push(rel); + } + } + } + + await walk(root, ''); + return results.sort(); +} + +export function verificationCommands(project, explicitPackageManager) { + const pm = explicitPackageManager || project.packageManager || 'npm'; + const scripts = project.packageJson?.scripts ?? {}; + const run = (script) => { + if (pm === 'npm') return `npm run ${script}`; + if (pm === 'yarn') return `yarn ${script}`; + return `${pm} run ${script}`; + }; + + if (project.stack === 'python') { + return [ + 'python -m pytest', + 'python -m compileall .' + ]; + } + + if (project.stack === 'go') return ['go test ./...']; + if (project.stack === 'rust') return ['cargo test']; + if (project.stack === 'java-maven') return ['mvn test']; + if (project.stack === 'java-gradle') return ['./gradlew test']; + if (project.stack === 'dotnet') return ['dotnet test']; + + if (!project.packageJson) { + return [ + 'echo "No package manifest detected; replace this line with your project verification command."' + ]; + } + + const install = pm === 'npm' + ? 'npm install' + : pm === 'yarn' + ? 'yarn install' + : `${pm} install`; + const candidates = [ + scripts.check ? run('check') : null, + scripts.typecheck ? run('typecheck') : null, + scripts['type-check'] ? run('type-check') : null, + scripts.lint ? run('lint') : null, + scripts.test ? (pm === 'npm' ? 'npm test' : `${pm} test`) : null, + scripts.build ? run('build') : null + ].filter(Boolean); + + return [install, ...dedupe(candidates)]; +} + +export function initScriptFromCommands(commands) { + const body = commands.map((command) => `echo "=== ${escapeForEcho(command)} ==="\n${command}`).join('\n\n'); + return `#!/bin/bash +set -e + +echo "=== Harness Initialization ===" + +${body} + +echo "=== Verification Complete ===" +echo "" +echo "Next steps:" +echo "1. Read feature_list.json to see current feature state" +echo "2. Pick ONE unfinished feature to work on" +echo "3. Implement only that feature" +echo "4. Re-run verification before claiming done" +`; +} + +function escapeForEcho(value) { + return value.replaceAll('"', '\\"'); +} + +export function dedupe(values) { + return [...new Set(values)]; +} + +export function scoreHarness(files) { + const byPath = new Map(files.map((file) => [file.path, file.content])); + const allText = files.map((file) => `${file.path}\n${file.content}`).join('\n\n'); + const agents = byPath.get('AGENTS.md') || byPath.get('CLAUDE.md') || ''; + const featureList = byPath.get('feature_list.json') || byPath.get('feature-list.json') || ''; + const progress = byPath.get('progress.md') || ''; + const init = byPath.get('init.sh') || ''; + const handoff = byPath.get('session-handoff.md') || ''; + + const checks = { + instructions: [ + hasFile(byPath, ['AGENTS.md', 'CLAUDE.md'], 'Agent instruction file exists'), + textHas(agents, ['Startup Workflow', 'Before writing code'], 'Startup workflow documented'), + textHas(agents, ['Definition of Done', 'done only when'], 'Definition of done documented'), + textHas(agents, ['Verification Commands', './init.sh', 'test', 'verify'], 'Verification commands discoverable'), + textHas(agents, ['feature_list.json', 'progress.md'], 'State artifacts routed from instructions') + ], + state: [ + hasFile(byPath, ['feature_list.json', 'feature-list.json'], 'Feature tracker exists'), + jsonFeatureList(featureList, 'Feature tracker is valid and has feature fields'), + hasFile(byPath, ['progress.md'], 'Progress log exists'), + textHas(progress, ['Current State', 'What', 'Next'], 'Progress log supports restart'), + textHas(handoff || progress, ['Blockers', 'Files', 'Next Session'], 'Handoff captures blockers/files/next step') + ], + verification: [ + hasFile(byPath, ['init.sh'], 'Verification entrypoint exists'), + textHas(init, ['set -e'], 'Verification fails fast'), + textHas(init + agents, ['test', 'pytest', 'vitest', 'cargo test', 'go test', 'dotnet test'], 'Test command documented'), + textHas(init + agents, ['build', 'type', 'lint', 'compile'], 'Static/build check documented'), + textHas(allText, ['Evidence', 'Verification Evidence', 'command and output'], 'Verification evidence is recorded') + ], + scope: [ + textHas(agents, ['One feature at a time', 'one-feature-at-a-time'], 'One-feature-at-a-time rule exists'), + textHas(featureList, ['dependencies'], 'Feature dependencies are tracked'), + textHas(agents + featureList, ['status'], 'Feature status is explicit'), + textHas(agents, ['Stay in scope', 'scope'], 'Scope boundary documented'), + textHas(agents, ['Definition of Done'], 'Completion gate limits scope closure') + ], + lifecycle: [ + hasFile(byPath, ['init.sh'], 'Startup script exists'), + textHas(agents, ['End of Session', 'Before ending'], 'End-of-session procedure exists'), + hasFile(byPath, ['session-handoff.md'], 'Session handoff template exists'), + textHas(progress + handoff, ['Last Updated', 'Current Objective', 'Recommended Next Step'], 'Session restart markers exist'), + textHas(agents + init, ['restartable', 'clean', 'Next steps'], 'Clean restart path documented') + ] + }; + + const subsystems = Object.fromEntries(Object.entries(checks).map(([name, subsystemChecks]) => { + const passed = subsystemChecks.filter((check) => check.pass).length; + const score = Math.max(1, Math.round((passed / subsystemChecks.length) * 5)); + return [name, { + score, + passed, + total: subsystemChecks.length, + checks: subsystemChecks + }]; + })); + + const total = Object.values(subsystems).reduce((sum, item) => sum + item.score, 0); + const overall = Math.round((total / (SUBSYSTEMS.length * 5)) * 100); + const bottleneck = Object.entries(subsystems).sort((a, b) => a[1].score - b[1].score)[0][0]; + return { overall, bottleneck, subsystems }; +} + +function hasFile(byPath, names, message) { + return { pass: names.some((name) => byPath.has(name)), message }; +} + +function textHas(text, needles, message) { + const lower = text.toLowerCase(); + return { pass: needles.some((needle) => lower.includes(needle.toLowerCase())), message }; +} + +function jsonFeatureList(text, message) { + try { + const parsed = JSON.parse(text); + const valid = Array.isArray(parsed.features) && parsed.features.every((feature) => + typeof feature.id === 'string' + && typeof feature.name === 'string' + && typeof feature.description === 'string' + && typeof feature.status === 'string' + ); + return { pass: valid, message }; + } catch { + return { pass: false, message }; + } +} + +export async function loadHarnessFiles(root) { + const candidates = [ + 'AGENTS.md', + 'CLAUDE.md', + 'feature_list.json', + 'feature-list.json', + 'progress.md', + 'session-handoff.md', + 'init.sh' + ]; + const files = []; + for (const candidate of candidates) { + const fullPath = path.join(root, candidate); + if (await exists(fullPath)) { + files.push({ path: candidate, content: await readText(fullPath) }); + } + } + return files; +} + +export function formatScoreReport(result, root = '.') { + const lines = [ + `Harness validation for ${root}`, + `Overall: ${result.overall}/100`, + `Bottleneck: ${result.bottleneck}`, + '' + ]; + + for (const [name, subsystem] of Object.entries(result.subsystems)) { + lines.push(`${name}: ${subsystem.score}/5 (${subsystem.passed}/${subsystem.total})`); + for (const check of subsystem.checks) { + lines.push(` ${check.pass ? 'PASS' : 'FAIL'} ${check.message}`); + } + lines.push(''); + } + return lines.join('\n'); +} + +export function htmlReport(result, title = 'Harness Assessment') { + const rows = Object.entries(result.subsystems).map(([name, subsystem]) => { + const checks = subsystem.checks.map((check) => + `
  • ${check.pass ? 'PASS' : 'FAIL'} ${escapeHtml(check.message)}
  • ` + ).join(''); + return `
    +

    ${escapeHtml(name)} ${subsystem.score}/5

    +
      ${checks}
    +
    `; + }).join('\n'); + + return ` + + + + + ${escapeHtml(title)} + + + +
    +
    +

    ${escapeHtml(title)}

    +

    Five-subsystem harness validation report.

    +
    +
    Overall${result.overall}/100
    +
    Bottleneck${escapeHtml(result.bottleneck)}
    +
    +
    + ${rows} +
    + + +`; +} + +function escapeHtml(value) { + return String(value) + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); +} + +export async function copyFileSafe(source, target, { force = false } = {}) { + if (!force && await exists(target)) { + return { path: target, status: 'skipped', reason: 'exists' }; + } + await mkdir(path.dirname(target), { recursive: true }); + await copyFile(source, target); + return { path: target, status: 'written' }; +} diff --git a/.agents/skills/harness-creator/scripts/render-assessment-html.mjs b/.agents/skills/harness-creator/scripts/render-assessment-html.mjs new file mode 100755 index 00000000..4d8d85fd --- /dev/null +++ b/.agents/skills/harness-creator/scripts/render-assessment-html.mjs @@ -0,0 +1,26 @@ +#!/usr/bin/env node +import path from 'node:path'; +import { + htmlReport, + loadHarnessFiles, + parseArgs, + scoreHarness, + writeText +} from './lib/harness-utils.mjs'; + +const args = parseArgs(process.argv.slice(2)); + +if (args.help) { + console.log(`Usage: node scripts/render-assessment-html.mjs [--target DIR] [--output FILE] + +Renders the five-subsystem harness assessment as a standalone HTML file.`); + process.exit(0); +} + +const target = path.resolve(args.target || args._[0] || process.cwd()); +const output = path.resolve(args.output || path.join(target, 'harness-assessment.html')); +const result = scoreHarness(await loadHarnessFiles(target)); + +await writeText(output, htmlReport(result, `Harness Assessment: ${path.basename(target)}`)); +console.log(`HTML report written to ${output}`); +console.log(`Overall: ${result.overall}/100`); diff --git a/.agents/skills/harness-creator/scripts/run-benchmark.mjs b/.agents/skills/harness-creator/scripts/run-benchmark.mjs new file mode 100755 index 00000000..2e6ab0f6 --- /dev/null +++ b/.agents/skills/harness-creator/scripts/run-benchmark.mjs @@ -0,0 +1,121 @@ +#!/usr/bin/env node +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { + formatScoreReport, + htmlReport, + loadHarnessFiles, + parseArgs, + readJson, + scoreHarness, + writeText +} from './lib/harness-utils.mjs'; + +const args = parseArgs(process.argv.slice(2)); +const scriptDir = path.dirname(fileURLToPath(import.meta.url)); +const skillRoot = path.resolve(scriptDir, '..'); + +if (args.help) { + console.log(`Usage: node scripts/run-benchmark.mjs [--target DIR] [--output FILE] [--html FILE] + +Runs a lightweight harness benchmark: + 1. Scores the current target harness. + 2. Checks eval coverage in evals/evals.json. + 3. Produces a JSON report and optional HTML report. + +This is a structural benchmark, not an LLM judge. Use it before/after real agent sessions.`); + process.exit(0); +} + +const target = path.resolve(args.target || args._[0] || process.cwd()); +const output = path.resolve(args.output || path.join(target, 'harness-benchmark.json')); +const evalPath = path.resolve(args.evals || path.join(skillRoot, 'evals', 'evals.json')); + +const harnessResult = scoreHarness(await loadHarnessFiles(target)); +const evals = await readJson(evalPath); +const evalResult = scoreEvals(evals); +const report = { + generatedAt: new Date().toISOString(), + target, + harness: harnessResult, + evals: evalResult, + recommendation: recommend(harnessResult, evalResult) +}; + +await writeText(output, `${JSON.stringify(report, null, 2)}\n`); +console.log(`Benchmark report written to ${output}`); +console.log(''); +console.log(formatScoreReport(harnessResult, target)); +console.log(`Eval coverage: ${evalResult.score}/100 (${evalResult.passed}/${evalResult.total})`); +console.log(`Recommendation: ${report.recommendation}`); + +if (args.html) { + const htmlPath = path.resolve(args.html); + await writeText(htmlPath, renderBenchmarkHtml(report)); + console.log(`HTML benchmark report written to ${htmlPath}`); +} + +if (harnessResult.overall < Number(args.minScore || 70) || evalResult.score < Number(args.minEvalScore || 80)) { + process.exitCode = 1; +} + +function scoreEvals(evalsJson) { + const cases = Array.isArray(evalsJson.evals) ? evalsJson.evals : []; + const checks = []; + checks.push({ pass: cases.length >= 10, message: 'At least 10 eval cases' }); + checks.push({ pass: cases.some((item) => /minimal|creation/i.test(item.name)), message: 'Covers minimal harness creation' }); + checks.push({ pass: cases.some((item) => /session|continuity/i.test(item.name)), message: 'Covers session continuity' }); + checks.push({ pass: cases.some((item) => /assessment|score/i.test(item.name)), message: 'Covers harness assessment' }); + checks.push({ pass: cases.some((item) => /verification/i.test(item.name)), message: 'Covers verification workflow' }); + checks.push({ pass: cases.some((item) => /memory/i.test(item.name)), message: 'Covers memory taxonomy' }); + checks.push({ pass: cases.some((item) => /tool|permission|safety/i.test(item.name)), message: 'Covers tool safety' }); + checks.push({ pass: cases.some((item) => /multi-agent|delegation|coordination/i.test(item.name)), message: 'Covers multi-agent coordination' }); + checks.push({ pass: cases.every((item) => item.prompt && item.expected_output && Array.isArray(item.expectations)), message: 'Each eval has prompt, expected output, expectations' }); + checks.push({ pass: cases.every((item) => item.expectations?.length >= 3), message: 'Each eval has at least three expectation checks' }); + + const passed = checks.filter((check) => check.pass).length; + return { + score: Math.round((passed / checks.length) * 100), + passed, + total: checks.length, + cases: cases.length, + checks + }; +} + +function recommend(harnessResult, evalResult) { + if (harnessResult.overall >= 85 && evalResult.score >= 90) { + return 'Ready for realistic before/after agent-session benchmarking.'; + } + if (harnessResult.overall < 70) { + return `Improve the ${harnessResult.bottleneck} subsystem before benchmarking agent behavior.`; + } + if (evalResult.score < 80) { + return 'Expand eval coverage before treating benchmark results as representative.'; + } + return 'Usable, with some gaps worth tightening after first real sessions.'; +} + +function renderBenchmarkHtml(report) { + const evalHtml = htmlReport(report.harness, `Harness Benchmark: ${path.basename(report.target)}`) + .replace('', `
    +

    Eval Coverage ${report.evals.score}/100

    +

    ${report.evals.passed}/${report.evals.total} benchmark checks passed across ${report.evals.cases} eval cases.

    +
      ${report.evals.checks.map((check) => `
    • ${check.pass ? 'PASS' : 'FAIL'} ${escapeHtml(check.message)}
    • `).join('')}
    +
    +
    +

    Recommendation

    +

    ${escapeHtml(report.recommendation)}

    +
    + `); + return evalHtml; +} + +function escapeHtml(value) { + return String(value) + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); +} diff --git a/.agents/skills/harness-creator/scripts/validate-harness.mjs b/.agents/skills/harness-creator/scripts/validate-harness.mjs new file mode 100755 index 00000000..3ae16d30 --- /dev/null +++ b/.agents/skills/harness-creator/scripts/validate-harness.mjs @@ -0,0 +1,43 @@ +#!/usr/bin/env node +import path from 'node:path'; +import { + formatScoreReport, + htmlReport, + loadHarnessFiles, + parseArgs, + scoreHarness, + writeText +} from './lib/harness-utils.mjs'; + +const args = parseArgs(process.argv.slice(2)); + +if (args.help) { + console.log(`Usage: node scripts/validate-harness.mjs [--target DIR] [--json] [--html FILE] + +Scores a project harness across five subsystems: + instructions, state, verification, scope, lifecycle + +Exit code is 0 when the harness scores at least --min-score (default 70).`); + process.exit(0); +} + +const target = path.resolve(args.target || args._[0] || process.cwd()); +const minScore = Number(args.minScore || 70); +const files = await loadHarnessFiles(target); +const result = scoreHarness(files); + +if (args.html) { + const htmlPath = path.resolve(args.html); + await writeText(htmlPath, htmlReport(result, `Harness Assessment: ${path.basename(target)}`)); + console.log(`HTML report written to ${htmlPath}`); +} + +if (args.json) { + console.log(JSON.stringify(result, null, 2)); +} else { + console.log(formatScoreReport(result, target)); +} + +if (result.overall < minScore) { + process.exitCode = 1; +} diff --git a/.agents/skills/harness-creator/templates/agents.md b/.agents/skills/harness-creator/templates/agents.md new file mode 100644 index 00000000..0b41e940 --- /dev/null +++ b/.agents/skills/harness-creator/templates/agents.md @@ -0,0 +1,68 @@ +# {{AGENT_FILE_NAME}} + +{{PROJECT_PURPOSE}} + +## Startup Workflow + +Before writing code: + +1. **Confirm working directory** with `pwd` +2. **Read this file** completely +3. **Read project docs if present** (`docs/ARCHITECTURE.md`, `docs/PRODUCT.md`, README, or equivalent) +4. **Run `./init.sh`** to verify environment is healthy +5. **Read `feature_list.json`** to see current feature state +6. **Review recent commits** with `git log --oneline -5` + +If baseline verification is failing, repair that first before adding new scope. + +## Working Rules + +- **One feature at a time**: Pick exactly one unfinished feature from `feature_list.json` +- **Verification required**: Don't claim done without running verification commands +- **Update artifacts**: Before ending session, update `progress.md` and `feature_list.json` +- **Stay in scope**: Don't modify files unrelated to the current feature +- **Leave clean state**: Next session must be able to run `./init.sh` immediately + +## Required Artifacts + +- `feature_list.json` — Feature state tracker (source of truth) +- `progress.md` — Session continuity log +- `init.sh` — Standard startup and verification path +- `session-handoff.md` — Optional, for larger sessions + +## Definition of Done + +A feature is done only when ALL of the following are true: + +- [ ] Target behavior is implemented +- [ ] Required verification actually ran (tests / lint / type-check) +- [ ] Evidence recorded in `feature_list.json` or `progress.md` +- [ ] Repository remains restartable from standard startup path + +## End of Session + +Before ending a session: + +1. Update `progress.md` with current state +2. Update `feature_list.json` with new feature status +3. Record any unresolved risks or blockers +4. Commit with descriptive message once work is in safe state +5. Leave repo clean enough for next session to run `./init.sh` immediately + +## Verification Commands + +```bash +# Full verification (recommended) +{{PRIMARY_VERIFICATION_COMMAND}} +``` + +Required checks: +{{VERIFICATION_COMMANDS}} + +## Escalation + +If you encounter: +- **Architecture decisions**: Consult project architecture docs if present, otherwise ask user +- **Unclear requirements**: Check product/requirements docs if present, otherwise ask user +- **Repeated test failures**: Update progress, flag for human review +- **Scope ambiguity**: Re-read `feature_list.json` for definition of done diff --git a/.agents/skills/harness-creator/templates/feature-list.json b/.agents/skills/harness-creator/templates/feature-list.json new file mode 100644 index 00000000..fff05b01 --- /dev/null +++ b/.agents/skills/harness-creator/templates/feature-list.json @@ -0,0 +1,44 @@ +{ + "features": [ + { + "id": "feat-001", + "name": "Project Setup", + "description": "Confirm the project can install dependencies, run verification, and start from a clean checkout", + "dependencies": [], + "status": "not-started", + "evidence": "" + }, + { + "id": "feat-002", + "name": "First User-Facing Feature", + "description": "Replace this placeholder with the first concrete behavior the agent should implement", + "dependencies": ["feat-001"], + "status": "not-started", + "evidence": "" + }, + { + "id": "feat-003", + "name": "Verification Coverage", + "description": "Add or confirm tests, type checks, linting, or manual verification for the active feature", + "dependencies": ["feat-002"], + "status": "not-started", + "evidence": "" + }, + { + "id": "feat-004", + "name": "Documentation Update", + "description": "Update README, architecture notes, or product docs affected by the implemented feature", + "dependencies": ["feat-003"], + "status": "not-started", + "evidence": "" + }, + { + "id": "feat-005", + "name": "Cleanup and Handoff", + "description": "Record verification evidence, update progress.md, and leave a clear next-session path", + "dependencies": ["feat-004"], + "status": "not-started", + "evidence": "" + } + ] +} diff --git a/.agents/skills/harness-creator/templates/feature-list.schema.json b/.agents/skills/harness-creator/templates/feature-list.schema.json new file mode 100644 index 00000000..45b85216 --- /dev/null +++ b/.agents/skills/harness-creator/templates/feature-list.schema.json @@ -0,0 +1,47 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Feature List", + "description": "Track feature implementation state for agent-driven development", + "type": "object", + "properties": { + "features": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique feature identifier (e.g., feat-001)", + "pattern": "^feat-\\d+$" + }, + "name": { + "type": "string", + "description": "Short feature name" + }, + "description": { + "type": "string", + "description": "What this feature does" + }, + "dependencies": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Feature IDs that must be done before this one" + }, + "status": { + "type": "string", + "enum": ["not-started", "in-progress", "blocked", "done"], + "description": "Current implementation state" + }, + "evidence": { + "type": "string", + "description": "Verification evidence when status is 'done'" + } + }, + "required": ["id", "name", "description", "status"] + } + } + }, + "required": ["features"] +} diff --git a/.agents/skills/harness-creator/templates/init.sh b/.agents/skills/harness-creator/templates/init.sh new file mode 100644 index 00000000..a305a37f --- /dev/null +++ b/.agents/skills/harness-creator/templates/init.sh @@ -0,0 +1,75 @@ +#!/bin/bash +set -e + +echo "=== Harness Initialization ===" + +if [ -f package.json ]; then + if [ -f pnpm-lock.yaml ]; then + PM="pnpm" + elif [ -f yarn.lock ]; then + PM="yarn" + elif [ -f bun.lock ] || [ -f bun.lockb ]; then + PM="bun" + else + PM="npm" + fi + + echo "=== Installing dependencies with $PM ===" + if [ "$PM" = "npm" ]; then + npm install + else + "$PM" install + fi + + node -e "const s=require('./package.json').scripts||{}; process.exit(s.check||s.typecheck||s['type-check']?0:1)" && { + if node -e "const s=require('./package.json').scripts||{}; process.exit(s.check?0:1)"; then + [ "$PM" = "npm" ] && npm run check || "$PM" run check + elif node -e "const s=require('./package.json').scripts||{}; process.exit(s.typecheck?0:1)"; then + [ "$PM" = "npm" ] && npm run typecheck || "$PM" run typecheck + else + [ "$PM" = "npm" ] && npm run type-check || "$PM" run type-check + fi + } + + node -e "const s=require('./package.json').scripts||{}; process.exit(s.lint?0:1)" && { + [ "$PM" = "npm" ] && npm run lint || "$PM" run lint + } + + node -e "const s=require('./package.json').scripts||{}; process.exit(s.test?0:1)" && { + [ "$PM" = "npm" ] && npm test || "$PM" test + } + + node -e "const s=require('./package.json').scripts||{}; process.exit(s.build?0:1)" && { + [ "$PM" = "npm" ] && npm run build || "$PM" run build + } +elif [ -f pyproject.toml ] || [ -f requirements.txt ]; then + echo "=== Running Python verification ===" + python -m pytest + python -m compileall . +elif [ -f go.mod ]; then + echo "=== Running Go verification ===" + go test ./... +elif [ -f Cargo.toml ]; then + echo "=== Running Rust verification ===" + cargo test +elif [ -f pom.xml ]; then + echo "=== Running Maven verification ===" + mvn test +elif [ -f build.gradle ] || [ -f build.gradle.kts ]; then + echo "=== Running Gradle verification ===" + ./gradlew test +elif ls *.csproj *.sln >/dev/null 2>&1; then + echo "=== Running .NET verification ===" + dotnet test +else + echo "No recognized package manifest detected." + echo "Replace this section with the project's verification commands." +fi + +echo "=== Verification Complete ===" +echo "" +echo "Next steps:" +echo "1. Read feature_list.json to see current feature state" +echo "2. Pick ONE unfinished feature to work on" +echo "3. Implement only that feature" +echo "4. Re-run verification before claiming done" diff --git a/.agents/skills/harness-creator/templates/progress.md b/.agents/skills/harness-creator/templates/progress.md new file mode 100644 index 00000000..3710d5c3 --- /dev/null +++ b/.agents/skills/harness-creator/templates/progress.md @@ -0,0 +1,51 @@ +# Session Progress Log + +## Current State + +**Last Updated:** YYYY-MM-DD HH:MM +**Session ID:** [optional] +**Active Feature:** [feat-XXX - Feature Name] + +## Status + +### What's Done + +- [x] [Completed item 1] +- [x] [Completed item 2] + +### What's In Progress + +- [ ] [Current work item] + - Details: [specific task] + - Blockers: [if any] + +### What's Next + +1. [Next action item] +2. [Following action item] + +## Blockers / Risks + +- [ ] [Blocker 1]: [description, impact] +- [ ] [Risk 1]: [description, mitigation] + +## Decisions Made + +- **[Decision 1]**: [description] + - Context: [why this decision was made] + - Alternatives considered: [what else was discussed] + +## Files Modified This Session + +- `path/to/file1.ts` - [brief description of change] +- `path/to/file2.ts` - [brief description of change] + +## Evidence of Completion + +- [ ] Tests pass: `[command and output]` +- [ ] Type check clean: `[command and output]` +- [ ] Manual verification: `[what was tested]` + +## Notes for Next Session + +[Free-form notes that will help the next session pick up context] diff --git a/.agents/skills/harness-creator/templates/session-handoff.md b/.agents/skills/harness-creator/templates/session-handoff.md new file mode 100644 index 00000000..d9168cb7 --- /dev/null +++ b/.agents/skills/harness-creator/templates/session-handoff.md @@ -0,0 +1,40 @@ +# Session Handoff + +## Current Objective + +- Goal: +- Current status: +- Branch / commit: + +## Completed This Session + +- [ ] + +## Verification Evidence + +| Check | Command | Result | Notes | +|---|---|---|---| +| | | | | + +## Files Changed + +- + +## Decisions Made + +- + +## Blockers / Risks + +- + +## Next Session Startup + +1. Read `AGENTS.md`. +2. Read `feature_list.json` and `progress.md`. +3. Review this handoff. +4. Run `./init.sh` or the documented verification command before editing. + +## Recommended Next Step + +- diff --git a/.gitignore b/.gitignore index 549e00a2..8d41f2c7 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,7 @@ build/ ### VS Code ### .vscode/ + +### Project ### + +*.db \ No newline at end of file diff --git "a/.qoder/plans/FML_Seed_\350\257\255\346\263\225\345\256\236\347\216\260_76c26019.md" "b/.qoder/plans/FML_Seed_\350\257\255\346\263\225\345\256\236\347\216\260_76c26019.md" new file mode 100644 index 00000000..ce0dea83 --- /dev/null +++ "b/.qoder/plans/FML_Seed_\350\257\255\346\263\225\345\256\236\347\216\260_76c26019.md" @@ -0,0 +1,265 @@ +# FML Seed 语法实现计划 + +## 目标 + +实现 `.fml` 文件格式,支持在同一个文件中同时定义模型(model/enum)和种子数据(seed),替代当前 `.idl` + `.json` 分离的数据导入方式。`.idl` 保持向后兼容。 + +## 语法示例 + +```fml +// 模型定义(与 IDL 完全兼容) +model User { + id: String @id @default(uuid()), + name: String @length(255), + role: UserRole, +} + +enum UserRole { + ADMIN, EDITOR, VIEWER +} + +// 种子数据(新增) +seed UserRole { + { code: "ADMIN", label: "管理员" }, + { code: "EDITOR", label: "编辑" }, + { code: "VIEWER", label: "访客" }, +} + +seed User @strategy("skip_exists") @match("email") { + { name: "管理员", email: "admin@system.local", role: "ADMIN" }, +} +``` + +seed 块中的值类型支持:字符串、整数、布尔、null、数组 `[...]`、嵌套对象 `{...}`、函数调用 `uuid()`。`@strategy` 和 `@match` 为可选注解,本阶段先解析但不做运行时策略处理(Phase 1 仅做 insert)。 + +## 影响范围 + +| 文件 | 变更类型 | 说明 | +|---|---|---| +| `flexmodel-core/src/main/javacc/ModelParser.jj` | 修改 | 新增 seed 语法产生式 | +| `flexmodel-core/src/main/java/dev/flexmodel/parser/ASTNodeConverter.java` | 修改 | 新增 SeedDeclaration 到 ImportData 的转换 | +| `flexmodel-core/src/main/java/dev/flexmodel/session/SessionFactory.java` | 修改 | 新增 `loadFMLString()`,更新 `loadScript()` | +| `flexmodel-codegen/src/main/java/dev/flexmodel/codegen/Configuration.java` | 修改 | 支持 `.fml` 文件解析 | +| `flexmodel-core/src/test/` | 新增 | 测试用例和 `.fml` 样本文件 | +| `docs/fml-design.md` | 新增 | FML 语言设计文档 | + +## 实施步骤 + +### Task 1: 扩展 JavaCC 语法 (`ModelParser.jj`) + +文件: `flexmodel-engine/flexmodel-core/src/main/javacc/ModelParser.jj` + +**1.1 新增关键字** + +在 TOKEN 区域新增 `seed` 和 `null` 关键字: + +``` +TOKEN : { < SEED: "seed" > } +TOKEN : { < NULL: "null" > } +TOKEN : { < HASH: "#" > } +``` + +**1.2 新增 AST 节点类** + +在 `PARSER_BEGIN` 区块中新增: + +```java +// 种子数据声明 +public static class SeedDeclaration implements ASTNode { + public String modelName; + public List> records = new ArrayList<>(); + public List annotations = new ArrayList<>(); + public SeedDeclaration(String modelName) { this.modelName = modelName; } + public void addRecord(Map record) { records.add(record); } + public void addAnnotation(Annotation ann) { annotations.add(ann); } + // toString() 方法用于 IDL 反向序列化 +} +``` + +**1.3 扩展 CompilationUnit 入口产生式** + +``` +List CompilationUnit() : { ... } +{ + ( + node = ModelDeclaration() + | node = EnumDeclaration() + | node = SeedDeclaration() // 新增 + )* + { return astList; } +} +``` + +**1.4 新增 SeedDeclaration 产生式** + +``` +SeedDeclaration SeedDeclaration() : { + String modelName; + SeedDeclaration seed; + Annotation ann; +} +{ + modelName = Identifier() + { seed = new SeedDeclaration(modelName); } + ( ann = SeedAnnotation() { seed.addAnnotation(ann); } )* + + ( SeedRecordList(seed) )? + + { return seed; } +} +``` + +**1.5 新增 SeedRecord 和 SeedValue 产生式** + +需要支持的值类型: +- 字符串字面量 `"hello"` +- 整数字面量 `123` +- 布尔字面量 `true`/`false` +- `null` +- 数组 `[1, 2, 3]` +- 嵌套对象 `{ key: value }` +- 函数调用 `uuid()` + +关键产生式: +- `SeedRecordList` - 记录列表,每条记录用逗号分隔 +- `SeedRecord` - 单条记录 `{ key: value, ... }` +- `SeedValue` - 值表达式(字符串/数字/布尔/null/数组/对象/函数调用) +- `SeedObjectValue` - 嵌套对象值 +- `SeedArrayValue` - 数组值 + +### Task 2: 更新 ASTNodeConverter + +文件: `flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/parser/ASTNodeConverter.java` + +**2.1 扩展 `toSchemaObject` 方法** + +由于 `SeedDeclaration` 不是 `SchemaObject`,需新增一个独立转换方法: + +```java +public static ModelImportBundle.ImportData toImportData(ModelParser.SeedDeclaration seed) { + ModelImportBundle.ImportData importData = new ModelImportBundle.ImportData(); + importData.setModelName(seed.modelName); + importData.setValues(seed.records); + return importData; +} +``` + +**2.2 新增工具方法 `parseFML`** + +解析 FML 字符串,返回模型列表和种子数据列表: + +```java +public static FMLParseResult parseFML(String fmlString) throws ParseException { + ModelParser parser = new ModelParser(new StringReader(fmlString)); + List ast = parser.CompilationUnit(); + + List models = new ArrayList<>(); + List seeds = new ArrayList<>(); + + for (ModelParser.ASTNode node : ast) { + if (node instanceof ModelParser.SeedDeclaration seed) { + seeds.add(toImportData(seed)); + } else { + SchemaObject obj = toSchemaObject(node); + if (obj != null) models.add(obj); + } + } + return new FMLParseResult(models, seeds); +} +``` + +新增 `FMLParseResult` record 类存放解析结果。 + +### Task 3: 更新 SessionFactory + +文件: `flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/session/SessionFactory.java` + +**3.1 新增 `loadFMLString()` 方法** + +```java +public void loadFMLString(String schemaName, String fmlString) { + // 调用 ASTNodeConverter.parseFML() + // processModels() 处理模型 + // processImportData() 处理种子数据 +} +``` + +**3.2 更新 `loadScript()` 方法** + +在文件扩展名分发中新增 `.fml` 分支: + +```java +if (scriptName.endsWith(".fml")) { + loadFMLString(schemaName, scriptString); +} else if (scriptName.endsWith(".json")) { + loadJSONString(schemaName, scriptString); +} else if (scriptName.endsWith(".idl")) { + loadIDLString(schemaName, scriptString); +} +``` + +**3.3 更新 `loadIDLString()` 的兼容性** + +`loadIDLString()` 保持不变,仅处理 model/enum(不含 seed),确保向后兼容。 + +### Task 4: 更新 Codegen Configuration + +文件: `flexmodel-engine/flexmodel-codegen/src/main/java/dev/flexmodel/codegen/Configuration.java` + +**4.1 在 `getImportDescribes()` 中新增 `.fml` 分支** + +```java +} else if (importScript.endsWith(".fml")) { + String content = Files.readString(scriptFile.toPath()); + ASTNodeConverter.FMLParseResult result = ASTNodeConverter.parseFML(content); + models.addAll(result.models()); + data.addAll(result.seeds()); +} +``` + +**4.2 更新 SchemaConfig 默认值** + +`SchemaConfig.importScript` 的默认值保持 `"import.json"` 不变(避免破坏现有项目),但文档中推荐使用 `.fml`。 + +### Task 5: 编写测试 + +**5.1 新增测试 FML 文件** + +文件: `flexmodel-engine/flexmodel-core/src/test/resources/sample_input.fml` + +包含 model + enum + seed 的完整示例。 + +**5.2 新增解析器测试** + +文件: `flexmodel-engine/flexmodel-core/src/test/java/dev/flexmodel/FMLParserTest.java` + +测试用例: +- 解析包含 model + seed 的 FML 字符串 +- 验证 seed 记录中的各种值类型(字符串、数字、布尔、null、数组、嵌套对象) +- 验证 seed 注解(@strategy、@match)解析正确 +- 验证 model + enum + seed 混合解析 +- 验证空 seed 块 +- 验证 ASTNodeConverter 转换结果 + +**5.3 新增 SessionFactory 集成测试** + +验证 `loadFMLString()` 能正确加载模型和种子数据。 + +### Task 6: 生成设计文档 + +文件: `docs/fml-design.md` + +记录 FML 语言规范、语法示例、与 IDL/JSON 的对比、迁移指南。 + +## 验证方式 + +```bash +# 编译验证(含 JavaCC 生成) +cd flexmodel-engine && mvn clean compile -pl flexmodel-core + +# 运行测试 +cd flexmodel-engine && mvn test -pl flexmodel-core -Dtest="FMLParserTest,IDLParserTest" + +# 全模块编译验证 +mvn clean compile -pl '!flexmodel-engine/flexmodel-maven-plugin' +``` diff --git a/AGENTS.md b/AGENTS.md index b99ba3c2..f65a9cd1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,46 +1,86 @@ -# FlexModel Project Agents Guide +# AGENTS.md -本文档为 FlexModel 项目的 AI 代理(Agents)提供全局指导。FlexModel 是一个高度灵活的、模型驱动的开发平台,包含引擎、服务端和前端 UI。 +Flexmodel — 面向下一代应用的统一数据访问层,基于 Java 25 + Quarkus 3 多模块 Maven 项目。 -## 1. 项目全景 +## 项目结构 -FlexModel 采用多模块结构,每个模块都有其特定的职责和规范: +| 模块 | 职责 | +|---|---| +| `flexmodel-engine/` | 核心引擎(codegen、core、graphql、quarkus 适配、maven 插件) | +| `flexmodel-server/` | 后端服务(Quarkus 3,REST/GraphQL/SSE,特性垂直分包) | +| `flexmodel-ui/` | 前端 UI(React + TypeScript + Ant Design v5 + Vite) | +| `flexmodel-website/` | 文档站(Docusaurus) | -- **[flexmodel-engine](./flexmodel-engine/AGENTS.md)**: 核心 DSL 引擎。负责模型定义、查询解析、代码生成及多数据库适配。 -- **[flexmodel-server](./flexmodel-server/AGENTS.md)**: 基于 Quarkus 的服务端实现。遵循 DDD 架构,提供 REST/GraphQL API、AI 聊天及任务调度。 -- **[flexmodel-ui](./flexmodel-ui/AGENTS.md)**: 基于 React + Ant Design 的前端管理后台。负责模型可视化设计、数据管理及系统配置。 +## Startup Workflow -## 2. 核心设计哲学 +Before writing code: -- **模型驱动 (Model-Driven)**: 核心是 `Model` 而不是 `Table`。一切操作应基于模型抽象。 -- **DSL 优先**: 推荐使用 `QueryDSL` 进行数据操作,确保持久层的灵活性和类型安全。 -- **领域驱动设计 (DDD)**: 服务端代码严格遵循领域层、应用层、接口层的分层结构。 -- **组件化 UI**: 前端优先使用标准组件,保持视觉和交互的一致性。 +1. **Confirm working directory** with `pwd` +2. **Read this file** completely +3. **Read project docs** (`README.md`, `flexmodel-server/README.md`, `AGENTS.md` in submodules) +4. **Run `./init.sh`** to verify environment is healthy +5. **Read `feature_list.json`** to see current feature state +6. **Review recent commits** with `git log --oneline -5` -## 3. Agent 行为准则 +If baseline verification is failing, repair that first before adding new scope. -### 通用要求 -- **上下文识别**: 在修改代码前,先确认所属模块(Engine/Server/UI)并查阅对应的 `AGENTS.md` 指南。 -- **语言规范**: 代码注释、文档、Git 提交信息及 AI 回复应使用 **中文**。 -- **一致性**: 保持与现有代码风格、命名规范和目录结构高度一致。 -- **验证驱动**: 完成代码修改后,必须通过单元测试或集成测试进行验证。 +## Working Rules -### 技术栈速查 -- **后端**: Java 21, Quarkus 3, Maven, SQLite/MySQL/PostgreSQL, MongoDB. -- **前端**: React, TypeScript, Ant Design v5, Tailwind CSS, Vite. -- **协议**: REST API, GraphQL, WebSocket, SSE. +- **One feature at a time**: Pick exactly one unfinished feature from `feature_list.json` +- **Verification required**: Don't claim done without running verification commands +- **Update artifacts**: Before ending session, update `progress.md` and `feature_list.json` +- **Stay in scope**: Don't modify files unrelated to the current feature +- **Leave clean state**: Next session must be able to run `./init.sh` immediately -## 4. 模块详细指南 +## Required Artifacts -请根据你当前的工作任务,跳转到对应模块的详细指南: +- `feature_list.json` — Feature state tracker (source of truth) +- `progress.md` — Session continuity log +- `init.sh` — Standard startup and verification path +- `session-handoff.md` — Optional, for larger sessions -1. **引擎开发**: 参考 [flexmodel-engine/AGENTS.md](./flexmodel-engine/AGENTS.md) - - 关注:DSL 语法、模型解析、数据库适配器。 -2. **服务端开发**: 参考 [flexmodel-server/AGENTS.md](./flexmodel-server/AGENTS.md) - - 关注:DDD 分层、REST 资源、AI 集成、业务逻辑。 -3. **前端开发**: 参考 [flexmodel-ui/AGENTS.md](./flexmodel-ui/AGENTS.md) - - 关注:React 组件、Ant Design 规范、状态管理、国际化。 +## Definition of Done ---- +A feature is done only when ALL of the following are true: -*注意:此文档应随项目演进而持续更新。* +- [ ] Target behavior is implemented +- [ ] Required verification actually ran (tests / lint / type-check) +- [ ] Evidence recorded in `feature_list.json` or `progress.md` +- [ ] Repository remains restartable from standard startup path + +## End of Session + +Before ending a session: + +1. Update `progress.md` with current state +2. Update `feature_list.json` with new feature status +3. Record any unresolved risks or blockers +4. Commit with descriptive message once work is in safe state +5. Leave repo clean enough for next session to run `./init.sh` immediately + +## Verification Commands + +```bash +# Full verification (recommended) +./init.sh +``` + +Required checks: +- `mvn clean compile -pl '!flexmodel-engine/flexmodel-maven-plugin'`(全模块编译验证) +- `mvn test -pl flexmodel-engine`(引擎模块测试) +- Optional: `mvn clean test -pl flexmodel-server -am`(服务模块测试,部分测试存在已知失败) + +## 架构约束 + +- **特性垂直分包**:flexmodel-server 按业务特性(auth/flow/data/api/modeling/...)组织代码,每个特性包含 Resource、Service、Repository、DTO +- **Java 25**:所有模块编译目标为 Java 25(`maven.compiler.release=25`) +- **多模块构建**:默认构建 `flexmodel-engine` 和 `flexmodel-server`,使用 `-Pwith-ui` 可启用前端模块 +- **Quarkus 3**:后端服务基于 Quarkus 3 框架,开发模式使用 `./mvnw quarkus:dev` + +## Escalation + +If you encounter: +- **Architecture decisions**: Consult project architecture docs if present, otherwise ask user +- **Unclear requirements**: Check product/requirements docs if present, otherwise ask user +- **Repeated test failures**: Update progress, flag for human review +- **Scope ambiguity**: Re-read `feature_list.json` for definition of done diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..eef4bd20 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md \ No newline at end of file diff --git a/feature_list.json b/feature_list.json new file mode 100644 index 00000000..dd7108c8 --- /dev/null +++ b/feature_list.json @@ -0,0 +1,84 @@ +{ + "features": [ + { + "id": "feat-001", + "name": "Data - 动态建模与多数据源支持", + "description": "运行时动态建模,支持 SQLite/MySQL/PostgreSQL/Oracle/DB2/MongoDB 等 10+ 数据库的数据访问层", + "dependencies": [], + "status": "done", + "evidence": "flexmodel-engine 核心模块已实现,集成测试覆盖多种数据库" + }, + { + "id": "feat-002", + "name": "Auth - RBAC 权限与多租户", + "description": "基于角色的访问控制、多租户隔离、JWT 安全验证", + "dependencies": ["feat-001"], + "status": "done", + "evidence": "flexmodel-server/auth 特性包已实现" + }, + { + "id": "feat-003", + "name": "Flow - 可视化流程编排", + "description": "流程定义、实例管理、执行引擎、插件系统、校验,低代码后端扩展", + "dependencies": ["feat-001"], + "status": "done", + "evidence": "flexmodel-server/flow 特性包已实现,FlowService 已按职责拆分为三个服务类" + }, + { + "id": "feat-004", + "name": "API - API 管理与 GraphQL", + "description": "API 定义、运行时执行、文档生成、GraphQL 支持", + "dependencies": ["feat-001"], + "status": "done", + "evidence": "flexmodel-server/api 和 flexmodel-engine/graphql 模块已实现" + }, + { + "id": "feat-005", + "name": "Job - 分布式任务调度", + "description": "内置触发器、作业执行的任务调度系统", + "dependencies": ["feat-001"], + "status": "done", + "evidence": "flexmodel-server/scheduling 特性包已实现" + }, + { + "id": "feat-006", + "name": "Storage - 文件存储抽象", + "description": "支持本地/S3/OSS 的文件存储抽象层", + "dependencies": ["feat-001"], + "status": "done", + "evidence": "flexmodel-server/storage 特性包已实现" + }, + { + "id": "feat-007", + "name": "AI - LangChain4j 智能对话", + "description": "集成 LangChain4j,提供 SSE 流式对话能力", + "dependencies": ["feat-001", "feat-002"], + "status": "done", + "evidence": "flexmodel-server/ai 特性包已实现" + }, + { + "id": "feat-008", + "name": "前端 UI 完善", + "description": "基于 React + Ant Design v5 的前端界面持续优化和功能完善", + "dependencies": ["feat-002", "feat-003", "feat-004"], + "status": "in-progress", + "evidence": "flexmodel-ui 模块已有基础实现,持续迭代中" + }, + { + "id": "feat-009", + "name": "文档站建设", + "description": "基于 Docusaurus 的文档站内容完善,包含 API 文档和教程", + "dependencies": ["feat-004"], + "status": "in-progress", + "evidence": "flexmodel-website 模块已有基础结构,docs/api 和 docs/tutorial 目录已有内容" + }, + { + "id": "feat-010", + "name": "替换此占位符为你的下一个特性", + "description": "将本条目替换为你接下来要实现的具体功能特性,设置 status 为 not-started", + "dependencies": [], + "status": "not-started", + "evidence": "" + } + ] +} diff --git a/flexmodel-engine/AGENTS.md b/flexmodel-engine/AGENTS.md deleted file mode 100644 index 066f11de..00000000 --- a/flexmodel-engine/AGENTS.md +++ /dev/null @@ -1,112 +0,0 @@ -# Agent Definition: FlexModel DSL Expert - -## 1. Persona (角色定义) - -你是一个资深的 Java 数据访问层专家,精通 FlexModel DSL 语法、动态数据建模以及多数据库适配技术。你专注于模型驱动开发(MDD)和领域特定语言(DSL)的设计与实现。 - -## 2. Context (项目上下文) - -- **核心栈**: Java 21, Maven, JUnit 5, Jackson, SLF4J。 -- **项目定位**: FlexModel Engine 是面向下一代应用程序的统一数据访问层解决方案,提供一站式数据建模、服务编排、任务调度、文件存储和身份认证能力。 -- **核心模块**: - - `flexmodel-core`: 核心引擎模块,提供数据访问、模型管理及多数据源适配 - - `flexmodel-codegen`: 代码生成模块,自动生成 DAO、DSL、Entity 等代码 - - `flexmodel-graphql`: GraphQL 支持模块,提供标准的 GraphQL 查询和变更功能 - - `flexmodel-maven-plugin`: Maven 插件,集成代码生成到构建流程 - - `flexmodel-quarkus`: Quarkus 集成模块 -- **数据库支持**: 支持 10+ 种主流及国产数据库(MySQL, PostgreSQL, SQLite, MongoDB, 达梦 DM, 金仓 GBase, Oracle, SQL Server, DB2, TiDB, MariaDB)。 -- **架构特点**: - - 统一 DSL 查询语言,屏蔽底层数据库差异 - - 运行时动态数据建模,无需重启服务 - - 基于 JSON 的模型定义和逻辑表达式 - - 事件驱动的数据变更通知机制 - -## 3. Standards (开发标准) - -- **模型概念优先**: 始终使用 `model()` 而不是 `table()`,FlexModel 是基于模型抽象的,而非传统的数据库表概念。 -- **DSL 语法规范**: - - 优先使用 `QueryDSL.simple()` 处理单表或简单条件查询 - - 使用 `QueryDSL.query()` 处理复杂查询、多表关联和聚合操作 - - 确保生成代码的方法名、参数及链式调用符合最新版本的 API -- **命名约定**: - - 类名: `PascalCase` (如 `User`, `DataService`) - - 方法名: `camelCase` (如 `queryUsers`, `insertRecord`) - - 常量: `UPPER_SNAKE_CASE` (如 `DEFAULT_SCHEMA`) - - 模型名称: `PascalCase` (如 `User`, `Order`) - - 字段名称: `camelCase` (如 `userName`, `createdAt`) -- **代码生成规范**: - - 自动生成的代码应包含完整的 JavaDoc 注释 - - 使用 `@author` 标记生成器 - - 遵循 Java 21 最佳实践和 Lombok 简化 -- **异常处理**: 使用自定义业务异常,提供清晰的错误信息和堆栈跟踪。 -- **测试覆盖**: 新增功能必须包含单元测试和集成测试,使用 JUnit 5 和 TestContainers。 - -## 4. Skills & Tools (技能与工具) - -- **DSL 查询构建**: 精通 `QueryDSL` 语法,包括简单查询(`simple()`)和复杂查询(`query()`)。 -- **动态建模**: 深刻理解 FlexModel 的模型(Model)概念,能够使用 JSON 格式定义数据模型。 -- **代码生成**: 熟练使用 `flexmodel-codegen` 和 `flexmodel-maven-plugin` 生成 DAO、DSL、Entity 代码。 -- **多数据库适配**: 了解不同数据库的方言特性,能够编写兼容性强的查询语句。 -- **GraphQL**: 熟悉 GraphQL Java 库,能够设计和实现 GraphQL Schema 和 Resolver。 -- **测试框架**: 使用 JUnit 5 进行单元测试,使用 TestContainers 进行集成测试,支持多种数据库的测试环境。 -- **依赖管理**: 使用 Maven 进行依赖管理,版本号统一在父 `pom.xml` 中管理。 -- **事件机制**: 理解和使用 FlexModel 的事件系统(PreInsertEvent, UpdatedEvent, DeletedEvent 等)。 -- **缓存机制**: 熟悉 ModelRegistry 和 Cache 接口,能够优化查询性能。 - -## 5. Workflows (工作流) - -- **新增数据模型**: - 1. 使用 JSON 格式定义模型(Entity、Enum、Index 等) - 2. 使用 `flexmodel-codegen` 生成对应的 Java 类 - 3. 编写单元测试验证模型定义 - 4. 在多个数据库环境下进行集成测试 - 5. 更新文档和示例代码 - -- **编写 DSL 查询**: - 1. 构建查询条件,使用 `Expressions` 和 `Predicate` API - 2. 处理关联查询和聚合操作 - 3. 编写测试用例验证查询结果 - 4. 优化查询性能,添加必要的索引 - -- **代码生成流程**: - 1. 配置 `flexmodel-maven-plugin` 参数 - 2. 定义模型 JSON 文件 - 3. 执行 `mvn generate-sources` 生成代码 - 4. 检查生成的代码质量和完整性 - 5. 编写测试验证生成的代码 - -- **GraphQL 集成**: - 1. 定义 GraphQL Schema - 2. 实现 DataFetcher 和 Resolver - 3. 配置 GraphQL 查询和变更端点 - 4. 编写 GraphQL 测试用例 - 5. 验证查询性能和安全性 - -- **多数据库测试**: - 1. 配置 TestContainers 启动不同数据库容器 - 2. 编写通用的测试用例 - 3. 在所有支持的数据库上运行测试 - 4. 分析测试结果,修复兼容性问题 - 5. 更新数据库支持文档 - -## 6. Boundaries (行为边界) - -- **禁止事项**: - - 禁止直接使用数据库特定的 SQL 语法,必须使用 FlexModel DSL。 - - 禁止在模型定义中使用保留字或特殊字符。 - - 禁止修改已发布模型的字段类型,如需修改应创建新版本。 - - 禁止在生成代码中手动修改标记为 `@Generated` 的代码。 - - 禁止绕过 ModelRegistry 直接操作数据库。 - - 禁止在事件处理器中执行耗时操作,应使用异步处理。 - -- **必须遵守**: - - 始终使用 `model()` 而不是 `table()`,FlexModel 是基于模型抽象的。 - - 优先推荐使用 `QueryDSL.simple()` 处理单表或简单条件查询。 - - 确保生成代码的类型安全和 API 一致性。 - - 新增功能必须包含完整的测试覆盖。 - - 代码注释和文档推荐使用中文。 - - 遵循 Java 21 最佳实践和项目编码规范。 - - 处理数据库异常时,提供清晰的错误信息和建议。 - - 在多数据库环境下验证代码的兼容性。 - - 保持与现有代码风格和架构模式一致。 - diff --git a/flexmodel-engine/docs/fml-design.md b/flexmodel-engine/docs/fml-design.md new file mode 100644 index 00000000..f95cbdf2 --- /dev/null +++ b/flexmodel-engine/docs/fml-design.md @@ -0,0 +1,246 @@ +# FML (FlexModel Language) 设计文档 + +FML 是 Flexmodel 的统一数据定义语言,将模型定义(Schema)和种子数据(Seed)合并到一个 `.fml` 文件中,替代之前 `.idl` + `.json` 分离的方式。 + +## 概述 + +| 特性 | IDL (.idl) | JSON (.json) | FML (.fml) | +|---|---|---|---| +| 模型定义 (model/enum) | ✅ | ✅ | ✅ | +| 种子数据 (seed) | ❌ | ✅ (ImportData) | ✅ | +| 可读性 | 高 | 低 | 高 | +| 单文件完整定义 | ❌ | ✅ | ✅ | + +FML 是 IDL 的超集:所有合法的 `.idl` 文件都是合法的 `.fml` 文件。 + +## 文件扩展名 + +- `.fml` — 完整 FML 语言(model + enum + seed) +- `.idl` — 仅模型定义部分(向后兼容) +- `.json` — JSON 格式导入(向后兼容) + +## 语法规范 + +### 模型定义 + +与 IDL 完全兼容,语法不变: + +```fml +model User { + id: String @id @default(uuid()), + name: String @length(255), + email: String @unique, + role: UserRole, + profile?: JSON, + createdAt?: DateTime @default(now()), +} + +enum UserRole { + ADMIN, + EDITOR, + VIEWER +} +``` + +### 种子数据 (seed) + +`seed` 关键字用于声明模型的初始数据: + +```fml +seed UserRole { + { code: "ADMIN", label: "管理员" }, + { code: "EDITOR", label: "编辑" }, + { code: "VIEWER", label: "访客" }, +} +``` + +#### 基本语法 + +``` +seed ModelName [@annotation(...)]* { + { key: value, ... }, + ... +} +``` + +#### 值类型 + +| 类型 | 语法 | 示例 | +|---|---|---| +| 字符串 | `"..."` | `"张三"` | +| 整数 | `123` 或 `-123` | `25`, `-1000` | +| 浮点数 | `1.5` 或 `-3.14` | `95.5`, `-0.5` | +| 布尔 | `true` / `false` | `true` | +| null | `null` | `null` | +| 数组 | `[...]` | `["Java", "Python"]` | +| 嵌套对象 | `{ key: value }` | `{ brand: "华为", weight: 200 }` | +| 函数调用 | `func()` | `uuid()`, `now()` | + +字符串支持转义序列:`\"` `\\` `\n` `\r` `\t` `\b` `\f` `\/`。 + +#### 键名 + +seed 记录中的键名支持两种形式: +- **标识符**:`name: "张三"` (以字母或下划线开头,只含字母、数字、下划线) +- **字符串字面量**:`"$schema": "http://..."` (用于包含特殊字符的键名,如 `$`、`-` 等) + +#### 注解 + +seed 块支持可选注解(当前阶段解析但运行时仅执行 insert): + +```fml +seed User @strategy("skip_exists") @match("email") { + { name: "管理员", email: "admin@system.local", role: "ADMIN" }, +} +``` + +- `@strategy` — 写入策略:`insert`(默认)、`skip_exists`、`upsert` +- `@match` — 匹配字段名,用于 skip_exists / upsert 场景 + +### 完整示例 + +```fml +// ============================== +// 模型定义 +// ============================== + +model User { + id: String @id @default(uuid()), + name: String @length(255), + email: String @unique, + role: UserRole, + active?: Boolean @default("true"), + profile?: JSON, + createdAt?: DateTime @default(now()), +} + +enum UserRole { + ADMIN, EDITOR, VIEWER +} + +// ============================== +// 种子数据 +// ============================== + +seed UserRole { + { code: "ADMIN", label: "管理员" }, + { code: "EDITOR", label: "编辑" }, + { code: "VIEWER", label: "访客" }, +} + +seed User @strategy("skip_exists") @match("email") { + { name: "管理员", email: "admin@system.local", role: "ADMIN" }, + { + name: "测试用户", + email: "test@example.com", + role: "VIEWER", + profile: { + department: "技术部", + skills: ["Java", "Python"], + }, + }, +} +``` + +## 运行时集成 + +### SessionFactory API + +```java +// 加载 FML 字符串(同时处理模型和种子数据) +sessionFactory.loadFMLString("schemaName", fmlString); + +// 从文件加载(自动识别 .fml / .json / .idl) +sessionFactory.loadScript("schemaName", "import.fml"); +``` + +### Codegen 集成 + +在 `SchemaConfig` 的 `importScript` 中使用 `.fml` 文件: + +```xml + + system + src/main/resources/system.fml + dev.flexmodel.codegen + +``` + +### AST 解析 API + +```java +// 解析 FML 字符串,获取模型和种子数据 +ASTNodeConverter.FMLParseResult result = ASTNodeConverter.parseFML(fmlString); +List models = result.getModels(); +List seeds = result.getSeeds(); +``` + +## 迁移指南 + +### 从 IDL + JSON 迁移到 FML + +之前需要两个文件: + +``` +platform_schema.idl — 模型定义 +platform_data.json — 种子数据 +``` + +合并为一个文件: + +``` +platform.fml — 模型定义 + 种子数据 +``` + +JSON 中的 `data` 数组: + +```json +{ + "data": [ + { + "modelName": "Course", + "values": [ + { "courseNo": "Math", "courseName": "数学" } + ] + } + ] +} +``` + +转换为 FML 的 `seed` 块: + +```fml +seed Course { + { courseNo: "Math", courseName: "数学" }, +} +``` + +### 向后兼容 + +- `.idl` 文件继续正常工作,`loadIDLString()` 和 `loadScript()` 中的 `.idl` 分支不变 +- `.json` 文件继续正常工作,`loadJSONString()` 不变 +- `ModelImportBundle.ImportData` 类型不变,seed 解析结果转换为同样的结构 + +## 实现细节 + +### 解析器 + +FML 解析器基于 JavaCC,语法定义在 `flexmodel-core/src/main/javacc/ModelParser.jj`。 + +关键产生式: +- `CompilationUnit` — 入口,支持 model / enum / seed 混合声明 +- `SeedDeclaration` — seed 块解析 +- `SeedRecord` / `SeedPairList` / `SeedValue` — 记录数据解析 +- `SeedArray` / `SeedObject` — 嵌套结构解析 + +### 关键字 + +`seed` 和 `null` 是 FML 新增的保留关键字,定义在 `IDENTIFIER` 之前以确保优先匹配。现有 IDL 关键字(`model`、`enum`)同步移到 `IDENTIFIER` 之前。 + +### LOOKAHEAD 策略 + +`SeedRecordList` 和 `SeedPairList` 使用 `LOOKAHEAD` 避免贪婪消费逗号: +- 记录列表:`LOOKAHEAD( )` — 逗号后必须是 `{` 才继续 +- 键值对列表:`LOOKAHEAD( )` — 逗号后必须是 `key:` 才继续 + +这确保了尾随逗号(trailing comma)的正确处理。 diff --git a/flexmodel-engine/flexmodel-codegen/pom.xml b/flexmodel-engine/flexmodel-codegen/pom.xml index 314290d6..6ced0bec 100644 --- a/flexmodel-engine/flexmodel-codegen/pom.xml +++ b/flexmodel-engine/flexmodel-codegen/pom.xml @@ -17,8 +17,18 @@ org.apache.groovy groovy-all - 4.0.22 + 5.0.3 pom + + + org.apache.groovy + groovy-test-junit5 + + + org.apache.groovy + groovy-testng + + org.slf4j @@ -60,7 +70,7 @@ org.codehaus.gmavenplus gmavenplus-plugin - 3.0.2 + 4.3.0 @@ -84,6 +94,7 @@ + 21 diff --git a/flexmodel-engine/flexmodel-codegen/src/main/java/dev/flexmodel/codegen/Configuration.java b/flexmodel-engine/flexmodel-codegen/src/main/java/dev/flexmodel/codegen/Configuration.java index db8ca3b0..b8ddef20 100644 --- a/flexmodel-engine/flexmodel-codegen/src/main/java/dev/flexmodel/codegen/Configuration.java +++ b/flexmodel-engine/flexmodel-codegen/src/main/java/dev/flexmodel/codegen/Configuration.java @@ -33,6 +33,7 @@ public List getImportDescribes() { // read from script String[] importScripts = schema.getImportScript().split(","); for (String importScript : importScripts) { + importScript = importScript.trim(); File scriptFile = Path.of(schema.getBaseDir(), importScript).toFile(); System.out.println("Import Script File Path: " + scriptFile.getAbsolutePath()); if (scriptFile.exists()) { @@ -47,21 +48,21 @@ public List getImportDescribes() { System.out.println("Parse file error: " + importScript); throw new RuntimeException(e); } - } else if (importScript.endsWith(".idl")) { + } else if (importScript.endsWith(".fml")) { try { String content = Files.readString(scriptFile.toPath()); - ModelParser modelParser = new ModelParser(new ByteArrayInputStream(content.getBytes())); - List list = modelParser.CompilationUnit(); - for (ModelParser.ASTNode astNode : list) { - models.add(ASTNodeConverter.toSchemaObject(astNode)); - } + ASTNodeConverter.FMLParseResult result = ASTNodeConverter.parseFML(content); + models.addAll(result.getModels()); + data.addAll(result.getSeeds()); } catch (IOException | ParseException e) { System.out.println("Parse file error: " + importScript); throw new RuntimeException(e); } } else { - System.out.println("Unsupported script file type: " + importScript + ", must be .json or .idl"); + System.out.println("Unsupported script file type: " + importScript + ", must be .json or .fml"); } + } else { + System.err.println("WARNING: Import script file not found: " + scriptFile.getAbsolutePath()); } } ModelImportBundle importDescribe = new ModelImportBundle(); diff --git a/flexmodel-engine/flexmodel-codegen/src/test/java/dev/flexmodel/codegen/GenerationToolTest.java b/flexmodel-engine/flexmodel-codegen/src/test/java/dev/flexmodel/codegen/GenerationToolTest.java index 4f03da5f..55156040 100644 --- a/flexmodel-engine/flexmodel-codegen/src/test/java/dev/flexmodel/codegen/GenerationToolTest.java +++ b/flexmodel-engine/flexmodel-codegen/src/test/java/dev/flexmodel/codegen/GenerationToolTest.java @@ -1,8 +1,12 @@ package dev.flexmodel.codegen; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Test; import java.io.File; +import java.io.IOException; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; /** * @author cjbi @@ -24,14 +28,14 @@ void test() throws Exception { } @Test - void testIDL() { + void testFML() { Configuration configuration = new Configuration(); SchemaConfig schemaConfig = new SchemaConfig(); - schemaConfig.setName("system_idl"); - schemaConfig.setImportScript("import.idl"); + schemaConfig.setName("system_fml"); + schemaConfig.setImportScript("import.fml"); schemaConfig.setBaseDir("src/test/resources/"); schemaConfig.setDirectory("src/test/java"); - schemaConfig.setPackageName("com.example_idl"); + schemaConfig.setPackageName("com.example_fml"); schemaConfig.setReplaceString("f_"); configuration.addSchema(schemaConfig); GenerationTool.run(configuration); @@ -50,4 +54,26 @@ public static void listFiles(File dir) { } } + @AfterAll + static void afterAll() throws IOException { + deleteRecursively(Paths.get("src/test/java/com")); + deleteRecursively(Paths.get("src/test/resources/target/classes")); + } + + private static void deleteRecursively(Path path) throws IOException { + if (!Files.exists(path)) return; + Files.walkFileTree(path, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + } } diff --git a/flexmodel-engine/flexmodel-codegen/src/test/resources/import.idl b/flexmodel-engine/flexmodel-codegen/src/test/resources/import.fml similarity index 100% rename from flexmodel-engine/flexmodel-codegen/src/test/resources/import.idl rename to flexmodel-engine/flexmodel-codegen/src/test/resources/import.fml diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/model/SchemaObject.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/model/SchemaObject.java index 8a9c911a..719a187f 100644 --- a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/model/SchemaObject.java +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/model/SchemaObject.java @@ -24,7 +24,7 @@ public interface SchemaObject extends Serializable { */ String getType(); - default String getIdl() { + default String getFml() { ModelParser.ASTNode astNode = ASTNodeConverter.fromSchemaObject(this); if (astNode == null) { return null; diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/parser/ASTNodeConverter.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/parser/ASTNodeConverter.java index bc4adb31..784470dc 100644 --- a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/parser/ASTNodeConverter.java +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/parser/ASTNodeConverter.java @@ -5,10 +5,13 @@ import dev.flexmodel.model.IndexDefinition; import dev.flexmodel.model.SchemaObject; import dev.flexmodel.model.field.*; +import dev.flexmodel.ModelImportBundle; import dev.flexmodel.model.field.*; import dev.flexmodel.parser.impl.ModelParser; +import dev.flexmodel.parser.impl.ParseException; import dev.flexmodel.query.Direction; +import java.io.StringReader; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -321,4 +324,60 @@ private static void addNumericAnnotations(ModelParser.Field idlField, } } + // ===================== FML Seed 转换方法 ===================== + + /** + * 将 SeedDeclaration AST 节点转换为 ImportData + */ + public static ModelImportBundle.ImportData toImportData(ModelParser.Seed seed) { + ModelImportBundle.ImportData importData = new ModelImportBundle.ImportData(); + importData.setModelName(seed.modelName); + importData.setValues(seed.records); + return importData; + } + + /** + * 解析 FML 字符串,同时返回模型定义和种子数据 + */ + public static FMLParseResult parseFML(String fmlString) throws ParseException { + ModelParser parser = new ModelParser(new StringReader(fmlString)); + List ast = parser.CompilationUnit(); + + List models = new ArrayList<>(); + List seeds = new ArrayList<>(); + + for (ModelParser.ASTNode node : ast) { + if (node instanceof ModelParser.Seed) { + seeds.add(toImportData((ModelParser.Seed) node)); + } else { + SchemaObject obj = toSchemaObject(node); + if (obj != null) { + models.add(obj); + } + } + } + return new FMLParseResult(models, seeds); + } + + /** + * FML 解析结果,包含模型定义和种子数据 + */ + public static class FMLParseResult { + private final List models; + private final List seeds; + + public FMLParseResult(List models, List seeds) { + this.models = models; + this.seeds = seeds; + } + + public List getModels() { + return models; + } + + public List getSeeds() { + return seeds; + } + } + } diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/session/SessionFactory.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/session/SessionFactory.java index c3a47a0b..74f6b55d 100644 --- a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/session/SessionFactory.java +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/session/SessionFactory.java @@ -25,6 +25,7 @@ import dev.flexmodel.parser.impl.ParseException; import dev.flexmodel.service.DataService; import dev.flexmodel.service.EventAwareDataService; +import dev.flexmodel.ModelImportBundle; import java.io.IOException; import java.io.InputStream; @@ -86,44 +87,28 @@ void processBuildItem() { }); } - public void loadIDLString(String schemaName, String idlString) { + public void loadFMLString(String schemaName, String fmlString) { try { - // 处理空字符串或只包含空白字符的字符串 - if (idlString == null || idlString.trim().isEmpty()) { - log.info("Empty or null IDL string provided for schema: {}", schemaName); + if (fmlString == null || fmlString.trim().isEmpty()) { + log.info("Empty or null FML string provided for schema: {}", schemaName); return; } - // 创建IDL解析器 - ModelParser parser = - new ModelParser(new java.io.StringReader(idlString)); - - // 解析IDL字符串,获取AST节点列表 - List ast = parser.CompilationUnit(); - - // 将AST节点转换为SchemaObject列表 - List schema = new ArrayList<>(); - for (ModelParser.ASTNode obj : ast) { - SchemaObject schemaObject = ASTNodeConverter.toSchemaObject(obj); - if (schemaObject != null) { - schema.add(schemaObject); - } else { - log.warn("Failed to convert AST node to SchemaObject: {}", obj); - } - } + ASTNodeConverter.FMLParseResult result = ASTNodeConverter.parseFML(fmlString); - // 使用故障安全会话处理模型 - 使用默认数据源 try (Session session = createFailsafeSession(schemaName)) { - processModels(schema, session); + processModels(result.getModels(), session); + processImportData(result.getSeeds(), session); } - log.info("Successfully loaded {} models from IDL for schema: {}", schema.size(), schemaName); + log.info("Successfully loaded {} models and {} seeds from FML for schema: {}", + result.getModels().size(), result.getSeeds().size(), schemaName); } catch (ParseException e) { - log.error("Failed to parse IDL string for schema {}: {}", schemaName, e.getMessage(), e); - throw new RuntimeException("IDL parsing failed: " + e.getMessage(), e); + log.error("Failed to parse FML string for schema {}: {}", schemaName, e.getMessage(), e); + throw new RuntimeException("FML parsing failed: " + e.getMessage(), e); } catch (Exception e) { - log.error("Failed to load IDL string for schema {}: {}", schemaName, e.getMessage(), e); - throw new RuntimeException("Failed to load IDL: " + e.getMessage(), e); + log.error("Failed to load FML string for schema {}: {}", schemaName, e.getMessage(), e); + throw new RuntimeException("Failed to load FML: " + e.getMessage(), e); } } @@ -142,13 +127,13 @@ public void loadScript(String schemaName, String scriptName, ClassLoader classLo throw new RuntimeException("Script file not found: " + scriptName); } String scriptString = new String(is.readAllBytes()); - if (scriptName.endsWith(".json")) { + if (scriptName.endsWith(".fml")) { + loadFMLString(schemaName, scriptString); + } else if (scriptName.endsWith(".json")) { loadJSONString(schemaName, scriptString); - } else if (scriptName.endsWith(".idl")) { - loadIDLString(schemaName, scriptString); } else { // unsupported script type - log.warn("Unsupported script type: {}, must be .json or .idl", scriptName); + log.warn("Unsupported script type: {}, must be .fml or .json", scriptName); } } catch (IOException e) { log.error("Failed to read import script: {}", e.getMessage(), e); @@ -163,7 +148,7 @@ private void processModels(List models, Session session) { Map wrapperMap = session.schema().listModels().stream().collect(Collectors.toMap(SchemaObject::getName, m -> m)); for (SchemaObject model : models) { SchemaObject older = wrapperMap.get(model.getName()); - if (older != null && Objects.equals(older.getIdl(), model.getIdl())) { + if (older != null && Objects.equals(older.getFml(), model.getFml())) { continue; } if (model instanceof EntityDefinition newer) { diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/JdbcSchemaManager.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/JdbcSchemaManager.java new file mode 100644 index 00000000..1507479c --- /dev/null +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/JdbcSchemaManager.java @@ -0,0 +1,97 @@ +package dev.flexmodel.sql; + +import dev.flexmodel.sql.dialect.SqlDialect; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +/** + * 基于 JDBC 的 SchemaManager 实现,通过 SqlDialect 方言体系适配不同数据库。 + * + * @author cjbi + */ +public class JdbcSchemaManager implements SchemaManager { + + private static final Logger log = LoggerFactory.getLogger(JdbcSchemaManager.class); + + @Override + public void createSchema(DataSource systemDataSource, String schemaName) { + try (Connection connection = systemDataSource.getConnection()) { + SqlDialect dialect = SqlDialectFactory.create(connection.getMetaData()); + + if (!dialect.supportsAutoCreateSchema()) { + throw new UnsupportedOperationException( + "数据库类型 " + connection.getMetaData().getDatabaseProductName() + + " 不支持自动创建 Schema,请由 DBA 预先创建 Schema/用户: " + schemaName); + } + + String[] sqls = dialect.getCreateSchemaIfNotExistsSql(schemaName); + try (Statement statement = connection.createStatement()) { + for (String sql : sqls) { + if (sql != null && !sql.isBlank()) { + log.info("Executing create schema SQL: {}", sql); + statement.execute(sql); + } + } + } + log.info("Schema '{}' created successfully (or already exists)", schemaName); + } catch (UnsupportedOperationException e) { + throw e; + } catch (SQLException e) { + throw new RuntimeException("Failed to create schema '" + schemaName + "': " + e.getMessage(), e); + } + } + + @Override + public void dropSchema(DataSource systemDataSource, String schemaName) { + try (Connection connection = systemDataSource.getConnection()) { + SqlDialect dialect = SqlDialectFactory.create(connection.getMetaData()); + + String[] sqls = dialect.getDropSchemaIfExistsSql(schemaName); + try (Statement statement = connection.createStatement()) { + for (String sql : sqls) { + if (sql != null && !sql.isBlank()) { + log.info("Executing drop schema SQL: {}", sql); + statement.execute(sql); + } + } + } + log.info("Schema '{}' dropped successfully (or did not exist)", schemaName); + } catch (SQLException e) { + throw new RuntimeException("Failed to drop schema '" + schemaName + "': " + e.getMessage(), e); + } + } + + @Override + public boolean schemaExists(DataSource systemDataSource, String schemaName) { + try (Connection connection = systemDataSource.getConnection()) { + // 优先通过 DatabaseMetaData.getSchemas() 判断 + try (ResultSet rs = connection.getMetaData().getSchemas()) { + while (rs.next()) { + String existingSchema = rs.getString("TABLE_SCHEM"); + if (schemaName.equalsIgnoreCase(existingSchema)) { + return true; + } + } + } + // 部分数据库(如 MySQL)getSchemas 返回空,尝试通过 getCatalogs 判断 + try (ResultSet rs = connection.getMetaData().getCatalogs()) { + while (rs.next()) { + String existingCatalog = rs.getString("TABLE_CAT"); + if (schemaName.equalsIgnoreCase(existingCatalog)) { + return true; + } + } + } + return false; + } catch (SQLException e) { + log.warn("Failed to check schema existence for '{}': {}", schemaName, e.getMessage()); + return false; + } + } +} diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/SchemaManager.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/SchemaManager.java new file mode 100644 index 00000000..41a39cff --- /dev/null +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/SchemaManager.java @@ -0,0 +1,36 @@ +package dev.flexmodel.sql; + +import javax.sql.DataSource; + +/** + * Schema 生命周期管理接口,封装不同数据库的 Schema 创建/删除差异。 + * + * @author cjbi + */ +public interface SchemaManager { + + /** + * 创建物理 Schema(幂等,已存在则跳过)。 + * + * @param systemDataSource 系统数据源(用于执行 DDL) + * @param schemaName 目标 Schema 名称 + */ + void createSchema(DataSource systemDataSource, String schemaName); + + /** + * 删除物理 Schema(幂等,不存在则跳过)。 + * + * @param systemDataSource 系统数据源(用于执行 DDL) + * @param schemaName 目标 Schema 名称 + */ + void dropSchema(DataSource systemDataSource, String schemaName); + + /** + * 检查 Schema 是否存在。 + * + * @param systemDataSource 系统数据源 + * @param schemaName 目标 Schema 名称 + * @return 是否存在 + */ + boolean schemaExists(DataSource systemDataSource, String schemaName); +} diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/DB2SqlDialect.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/DB2SqlDialect.java index 75360388..e1607067 100644 --- a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/DB2SqlDialect.java +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/DB2SqlDialect.java @@ -104,4 +104,15 @@ public String getDropSchemaSql(String schemaName) { return "drop schema " + quoteIdentifier(schemaName) + " restrict"; } + @Override + public String[] getCreateSchemaIfNotExistsSql(String schemaName) { + // DB2 不支持 IF NOT EXISTS,通过先检查再创建实现幂等 + return new String[]{ "CREATE SCHEMA " + quoteIdentifier(schemaName) }; + } + + @Override + public String[] getDropSchemaIfExistsSql(String schemaName) { + return new String[]{ "DROP SCHEMA " + quoteIdentifier(schemaName) + " RESTRICT" }; + } + } diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/DmSqlDialect.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/DmSqlDialect.java index a6084822..554b15f4 100644 --- a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/DmSqlDialect.java +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/DmSqlDialect.java @@ -106,4 +106,19 @@ public boolean useFirstGeneratedId() { public boolean supportsGroupByColumnAlias() { return false; } + + @Override + public boolean supportsAutoCreateSchema() { + return false; + } + + @Override + public String[] getCreateSchemaIfNotExistsSql(String schemaName) { + return new String[]{}; + } + + @Override + public String[] getDropSchemaIfExistsSql(String schemaName) { + return new String[]{ "DROP USER " + quoteIdentifier(schemaName) + " CASCADE" }; + } } diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/GBaseSqlDialect.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/GBaseSqlDialect.java index 976c67e7..341c2f10 100644 --- a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/GBaseSqlDialect.java +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/GBaseSqlDialect.java @@ -73,4 +73,14 @@ public String getDropSchemaSql(String schemaName) { return "drop schema " + quoteIdentifier(schemaName); } + @Override + public String[] getCreateSchemaIfNotExistsSql(String schemaName) { + return new String[]{ "CREATE SCHEMA IF NOT EXISTS " + quoteIdentifier(schemaName) }; + } + + @Override + public String[] getDropSchemaIfExistsSql(String schemaName) { + return new String[]{ "DROP SCHEMA IF EXISTS " + quoteIdentifier(schemaName) }; + } + } diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/InformixSqlDialect.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/InformixSqlDialect.java index 207738ee..5f3e5c0a 100644 --- a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/InformixSqlDialect.java +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/InformixSqlDialect.java @@ -125,4 +125,14 @@ public String getDropSchemaSql(String schemaName) { return "drop database " + quoteIdentifier(schemaName); } + @Override + public String[] getCreateSchemaIfNotExistsSql(String schemaName) { + return new String[]{ "CREATE DATABASE IF NOT EXISTS " + quoteIdentifier(schemaName) }; + } + + @Override + public String[] getDropSchemaIfExistsSql(String schemaName) { + return new String[]{ "DROP DATABASE IF EXISTS " + quoteIdentifier(schemaName) }; + } + } diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/MariaDBSqlDialect.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/MariaDBSqlDialect.java index 463c56e1..1287cb5e 100644 --- a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/MariaDBSqlDialect.java +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/MariaDBSqlDialect.java @@ -158,4 +158,14 @@ public String doExtractConstraintName(SQLException ex) { return null; } + @Override + public String[] getCreateSchemaIfNotExistsSql(String schemaName) { + return new String[]{ "CREATE DATABASE IF NOT EXISTS " + quoteIdentifier(schemaName) }; + } + + @Override + public String[] getDropSchemaIfExistsSql(String schemaName) { + return new String[]{ "DROP DATABASE IF EXISTS " + quoteIdentifier(schemaName) }; + } + } diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/MySQLSqlDialect.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/MySQLSqlDialect.java index fe031fff..d7909103 100644 --- a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/MySQLSqlDialect.java +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/MySQLSqlDialect.java @@ -183,4 +183,14 @@ public String getDropSchemaSql(String schemaName) { return "drop schema " + quoteIdentifier(schemaName); } + @Override + public String[] getCreateSchemaIfNotExistsSql(String schemaName) { + return new String[]{ "CREATE DATABASE IF NOT EXISTS " + quoteIdentifier(schemaName) }; + } + + @Override + public String[] getDropSchemaIfExistsSql(String schemaName) { + return new String[]{ "DROP DATABASE IF EXISTS " + quoteIdentifier(schemaName) }; + } + } diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/OracleSqlDialect.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/OracleSqlDialect.java index 4cf7ea51..463c22f8 100644 --- a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/OracleSqlDialect.java +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/OracleSqlDialect.java @@ -150,4 +150,20 @@ public String getDropSchemaSql(String schemaName) { return "drop user " + quoteIdentifier(schemaName) + " cascade"; } + @Override + public boolean supportsAutoCreateSchema() { + return false; + } + + @Override + public String[] getCreateSchemaIfNotExistsSql(String schemaName) { + // Oracle 的 schema = 用户,需要 DBA 预先创建,此处返回空数组,由 SchemaManager 检查 supportsAutoCreateSchema 后处理 + return new String[]{}; + } + + @Override + public String[] getDropSchemaIfExistsSql(String schemaName) { + return new String[]{ "DROP USER " + quoteIdentifier(schemaName) + " CASCADE" }; + } + } diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/PostgreSQLSqlDialect.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/PostgreSQLSqlDialect.java index f2a79d8d..dc61a99a 100644 --- a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/PostgreSQLSqlDialect.java +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/PostgreSQLSqlDialect.java @@ -110,4 +110,14 @@ public String getModifyColumnString() { return "alter column"; } + @Override + public String[] getCreateSchemaIfNotExistsSql(String schemaName) { + return new String[]{ "CREATE SCHEMA IF NOT EXISTS " + quoteIdentifier(schemaName) }; + } + + @Override + public String[] getDropSchemaIfExistsSql(String schemaName) { + return new String[]{ "DROP SCHEMA IF EXISTS " + quoteIdentifier(schemaName) + " CASCADE" }; + } + } diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/SQLServerSqlDialect.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/SQLServerSqlDialect.java index 0c47c676..7f47fa2f 100644 --- a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/SQLServerSqlDialect.java +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/SQLServerSqlDialect.java @@ -230,4 +230,11 @@ public String getModifyColumnString() { return "alter column"; } + @Override + public String[] getCreateSchemaIfNotExistsSql(String schemaName) { + return new String[]{ + "IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = '" + schemaName + "') EXEC('CREATE SCHEMA " + quoteIdentifier(schemaName) + "')" + }; + } + } diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/SQLiteSqlDialect.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/SQLiteSqlDialect.java index e2cb5aae..048bf851 100644 --- a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/SQLiteSqlDialect.java +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/SQLiteSqlDialect.java @@ -109,4 +109,14 @@ public String getDropSchemaSql(String schemaName) { return ""; } + @Override + public String[] getCreateSchemaIfNotExistsSql(String schemaName) { + return new String[]{ "" }; + } + + @Override + public String[] getDropSchemaIfExistsSql(String schemaName) { + return new String[]{ "" }; + } + } diff --git a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/SqlDialect.java b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/SqlDialect.java index 39404a03..0c5b8bf4 100644 --- a/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/SqlDialect.java +++ b/flexmodel-engine/flexmodel-core/src/main/java/dev/flexmodel/sql/dialect/SqlDialect.java @@ -536,4 +536,27 @@ public String getDropSchemaSql(String schemaName) { return "drop schema " + quoteIdentifier(schemaName); } + /** + * 返回幂等的创建 Schema SQL(IF NOT EXISTS 语义)。 + * 部分数据库可能需要返回多条 SQL(如 Oracle 需要 CREATE USER + GRANT + QUOTA)。 + */ + public String[] getCreateSchemaIfNotExistsSql(String schemaName) { + return new String[]{ getCreateSchemaSql(schemaName) }; + } + + /** + * 返回幂等的删除 Schema SQL(IF EXISTS 语义)。 + */ + public String[] getDropSchemaIfExistsSql(String schemaName) { + return new String[]{ getDropSchemaSql(schemaName) }; + } + + /** + * 是否支持通过 SQL 自动创建 Schema。 + * Oracle/DM 等数据库的 Schema 等同于用户,需要 DBA 预先创建,返回 false。 + */ + public boolean supportsAutoCreateSchema() { + return true; + } + } diff --git a/flexmodel-engine/flexmodel-core/src/main/javacc/ModelParser.jj b/flexmodel-engine/flexmodel-core/src/main/javacc/ModelParser.jj index cfd6ee9a..6add9456 100644 --- a/flexmodel-engine/flexmodel-core/src/main/javacc/ModelParser.jj +++ b/flexmodel-engine/flexmodel-core/src/main/javacc/ModelParser.jj @@ -185,6 +185,64 @@ public class ModelParser { } + // Seed 对象,保存种子数据声明 + public static class Seed implements ASTNode { + public String modelName; + public List annotations = new ArrayList<>(); + public List> records = new ArrayList<>(); + public Seed(String modelName) { this.modelName = modelName; } + public void addRecord(Map record) { records.add(record); } + public void addAnnotation(Annotation ann) { annotations.add(ann); } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("seed ").append(modelName); + for (Annotation ann : annotations) { + sb.append(" ").append(ann.toString()); + } + sb.append(" {\n"); + for (Map record : records) { + sb.append(" ").append(mapToString(record)).append(",\n"); + } + sb.append("}"); + return sb.toString(); + } + + private String mapToString(Map map) { + StringBuilder sb = new StringBuilder(); + sb.append("{"); + boolean first = true; + for (Map.Entry entry : map.entrySet()) { + if (!first) sb.append(", "); + first = false; + sb.append(entry.getKey()).append(": "); + sb.append(valueToString(entry.getValue())); + } + sb.append("}"); + return sb.toString(); + } + + private String valueToString(Object value) { + if (value == null) return "null"; + if (value instanceof String) return "\"" + value + "\""; + if (value instanceof List) { + List lst = (List) value; + StringBuilder sb = new StringBuilder("["); + boolean first = true; + for (Object elem : lst) { + if (!first) sb.append(", "); + first = false; + sb.append(valueToString(elem)); + } + sb.append("]"); + return sb.toString(); + } + if (value instanceof Map) return mapToString((Map) value); + return value.toString(); + } + } + public static void main(String[] args) throws ParseException { ModelParser parser = new ModelParser(System.in); List ast = parser.CompilationUnit(); @@ -207,6 +265,10 @@ SKIP : { } /* 关键字和符号 */ TOKEN : { < MODEL: "model" > } TOKEN : { < ENUM: "enum" > } +TOKEN : { < SEED: "seed" > } +TOKEN : { < TRUE: "true" > } +TOKEN : { < FALSE: "false" > } +TOKEN : { < NULL: "null" > } TOKEN : { < AT: "@" > } TOKEN : { < COLON: ":" > } TOKEN : { < COMMA: "," > } @@ -217,11 +279,11 @@ TOKEN : { < LBRACE: "{" > } TOKEN : { < RBRACE: "}" > } TOKEN : { < LBRACKET: "[" > } TOKEN : { < RBRACKET: "]" > } -TOKEN : { < STRING_LITERAL: "\"" (~["\"", "\\"])* "\"" > } +TOKEN : { < STRING_LITERAL: "\"" ( ~["\"", "\\"] | "\\" ["\"", "\\", "n", "r", "t", "b", "f", "/"] )* "\"" > } TOKEN : { < INTEGER_LITERAL: (["0"-"9"])+ > } -TOKEN : { < TRUE: "true" > } -TOKEN : { < FALSE: "false" > } TOKEN : { < IDENTIFIER: (["a"-"z", "A"-"Z", "_"]) (["a"-"z", "A"-"Z", "0"-"9", "_"])* > } +TOKEN : { < MINUS: "-" > } +TOKEN : { < DOT: "." > } /* 入口产生式,返回 AST 节点列表 */ List CompilationUnit() : { List astList = new ArrayList(); Object node; } @@ -229,6 +291,7 @@ List CompilationUnit() : { List astList = new ArrayList(); Object node; } ( node = ModelDeclaration() { astList.add(node); } | node = EnumDeclaration() { astList.add(node); } + | node = SeedDeclaration() { astList.add(node); } )* { return astList; } } @@ -397,3 +460,102 @@ String Identifier() : { Token t; } { t = { return t.image; } } + +/* ========== Seed 数据声明相关产生式 ========== */ + +/* 解析 seed 声明,返回 Seed 对象 */ +Seed SeedDeclaration() : { + String modelName; + Seed seed; + Annotation ann; +} +{ + modelName = Identifier() + { seed = new Seed(modelName); } + ( ann = SeedAnnotationDecl() { seed.addAnnotation(ann); } )* + + ( SeedRecordList(seed) )? + + { return seed; } +} + +/* Seed 专用注解产生式 */ +Annotation SeedAnnotationDecl() : { String annName; Annotation ann; } +{ + annName = Identifier() + { + ann = new Annotation(annName); + } + ( AnnotationArguments(ann) )? + { return ann; } +} + +/* 解析种子记录列表 */ +void SeedRecordList(Seed seed) : { Map record; } +{ + record = SeedRecord() { seed.addRecord(record); } + ( LOOKAHEAD( ) record = SeedRecord() { seed.addRecord(record); } )* + ( )? +} + +/* 解析单条种子记录 { key: value, ... } */ +Map SeedRecord() : { + Map record = new LinkedHashMap(); +} +{ + + ( SeedPairList(record) )? + + { return record; } +} + +/* 解析键值对列表 */ +void SeedPairList(Map map) : { String key; Object value; } +{ + key = SeedKey() value = SeedValue() { map.put(key, value); } + ( LOOKAHEAD( ( | ) ) key = SeedKey() value = SeedValue() { map.put(key, value); } )* + ( )? +} + +/* 解析种子键名,支持标识符和字符串字面量 */ +String SeedKey() : { Token t; } +{ + t = { return t.image; } + | t = { return t.image.substring(1, t.image.length()-1); } +} + +/* 解析种子值,支持多种类型 */ +Object SeedValue() : { Token t; Token t2; Object s; String id; } +{ + LOOKAHEAD( ) s = FunctionCall() { return s; } + | t = { return t.image.substring(1, t.image.length()-1); } + | LOOKAHEAD( ) t = t2 = { return -Double.parseDouble(t.image + "." + t2.image); } + | LOOKAHEAD( ) t = { return -Long.parseLong(t.image); } + | LOOKAHEAD( ) t = t2 = { return Double.parseDouble(t.image + "." + t2.image); } + | t = { return Long.parseLong(t.image); } + | t = { return Boolean.TRUE; } + | t = { return Boolean.FALSE; } + | { return null; } + | s = SeedArray() { return s; } + | s = SeedObject() { return s; } +} + +/* 解析种子数组值 */ +List SeedArray() : { List list = new ArrayList(); Object elem; } +{ + + ( elem = SeedValue() { list.add(elem); } ( elem = SeedValue() { list.add(elem); } )* ( )? )? + + { return list; } +} + +/* 解析种子嵌套对象值 */ +Map SeedObject() : { + Map map = new LinkedHashMap(); +} +{ + + ( SeedPairList(map) )? + + { return map; } +} diff --git a/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/IDLDemo.java b/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/FmlDemo.java similarity index 77% rename from flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/IDLDemo.java rename to flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/FmlDemo.java index 76b6dfb2..e76c43a8 100644 --- a/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/IDLDemo.java +++ b/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/FmlDemo.java @@ -8,16 +8,16 @@ import java.util.List; /** - * IDL解析功能演示 + * FML解析功能演示 * * @author cjbi */ -public class IDLDemo { +public class FmlDemo { public static void main(String[] args) { try { - // 测试IDL字符串 - String idlString = """ + // 测试FML字符串 + String fmlString = """ // 用户模型 model User { id: String @id @default(uuid()), @@ -35,13 +35,13 @@ enum UserStatus { } """; - System.out.println("=== IDL解析演示 ==="); - System.out.println("原始IDL:"); - System.out.println(idlString); + System.out.println("=== FML解析演示 ==="); + System.out.println("原始FML:"); + System.out.println(fmlString); System.out.println(); - // 解析IDL - ModelParser parser = new ModelParser(new StringReader(idlString)); + // 解析FML + ModelParser parser = new ModelParser(new StringReader(fmlString)); List ast = parser.CompilationUnit(); System.out.println("解析结果:"); @@ -57,15 +57,15 @@ enum UserStatus { if (schemaObject != null) { System.out.println("类型: " + schemaObject.getClass().getSimpleName()); System.out.println("名称: " + schemaObject.getName()); - System.out.println("IDL: " + schemaObject.getIdl()); + System.out.println("FML: " + schemaObject.getFml()); System.out.println(); } } - System.out.println("=== IDL解析成功 ==="); + System.out.println("=== FML解析成功 ==="); } catch (Exception e) { - System.err.println("IDL解析失败: " + e.getMessage()); + System.err.println("FML解析失败: " + e.getMessage()); e.printStackTrace(); } } diff --git a/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/IDLParserTest.java b/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/FmlParserTest.java similarity index 92% rename from flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/IDLParserTest.java rename to flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/FmlParserTest.java index f0e7d531..dc7c1ce9 100644 --- a/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/IDLParserTest.java +++ b/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/FmlParserTest.java @@ -12,15 +12,15 @@ import static org.junit.jupiter.api.Assertions.*; /** - * 测试IDL解析功能 + * 测试FML解析功能 * * @author cjbi */ -public class IDLParserTest { +public class FmlParserTest { @Test void testParseSimpleModel() throws Exception { - String idlString = """ + String fmlString = """ model User { id: String @id @default(uuid()), name: String @length(255), @@ -30,7 +30,7 @@ void testParseSimpleModel() throws Exception { } """; - ModelParser parser = new ModelParser(new StringReader(idlString)); + ModelParser parser = new ModelParser(new StringReader(fmlString)); List ast = parser.CompilationUnit(); assertNotNull(ast); @@ -57,7 +57,7 @@ void testParseSimpleModel() throws Exception { @Test void testParseModelWithEnum() throws Exception { - String idlString = """ + String fmlString = """ enum UserStatus { ACTIVE, INACTIVE, @@ -71,7 +71,7 @@ enum UserStatus { } """; - ModelParser parser = new ModelParser(new StringReader(idlString)); + ModelParser parser = new ModelParser(new StringReader(fmlString)); List ast = parser.CompilationUnit(); assertNotNull(ast); @@ -99,7 +99,7 @@ enum UserStatus { @Test void testParseModelWithRelations() throws Exception { - String idlString = """ + String fmlString = """ model Post { id: String @id @default(uuid()), title: String, @@ -115,7 +115,7 @@ void testParseModelWithRelations() throws Exception { } """; - ModelParser parser = new ModelParser(new StringReader(idlString)); + ModelParser parser = new ModelParser(new StringReader(fmlString)); List ast = parser.CompilationUnit(); assertNotNull(ast); @@ -143,7 +143,7 @@ void testParseModelWithRelations() throws Exception { @Test void testASTNodeConverter() throws Exception { - String idlString = """ + String fmlString = """ model User { id: String @id @default(uuid()), name: String @length(255), @@ -151,7 +151,7 @@ void testASTNodeConverter() throws Exception { } """; - ModelParser parser = new ModelParser(new StringReader(idlString)); + ModelParser parser = new ModelParser(new StringReader(fmlString)); List ast = parser.CompilationUnit(); // 转换为SchemaObject @@ -177,7 +177,7 @@ void testASTNodeConverter() throws Exception { @Test void testParseInvalidSyntax() { - String invalidIdl = """ + String invalidFml = """ model User { id: String @id @default(uuid()), name: String, @@ -185,7 +185,7 @@ void testParseInvalidSyntax() { """; assertThrows(Exception.class, () -> { - ModelParser parser = new ModelParser(new StringReader(invalidIdl)); + ModelParser parser = new ModelParser(new StringReader(invalidFml)); parser.CompilationUnit(); }); } diff --git a/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/parser/ASTNodeConverterTest.java b/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/parser/ASTNodeConverterTest.java index f76bf23e..e36d23b3 100644 --- a/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/parser/ASTNodeConverterTest.java +++ b/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/parser/ASTNodeConverterTest.java @@ -20,7 +20,7 @@ public class ASTNodeConverterTest { @Test void test() throws ParseException { - InputStream is = this.getClass().getClassLoader().getResourceAsStream("sample_input.idl"); + InputStream is = this.getClass().getClassLoader().getResourceAsStream("sample_input.fml"); ModelParser modelParser = new ModelParser(is); List list = modelParser.CompilationUnit(); List objectList = new ArrayList<>(); diff --git a/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/parser/ModelParserTest.java b/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/parser/ModelParserTest.java index 90755652..43f25c98 100644 --- a/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/parser/ModelParserTest.java +++ b/flexmodel-engine/flexmodel-core/src/test/java/tech/wetech/flexmodel/parser/ModelParserTest.java @@ -14,7 +14,7 @@ public class ModelParserTest { @Test void test() throws ParseException { - InputStream is = this.getClass().getClassLoader().getResourceAsStream("sample_input.idl"); + InputStream is = this.getClass().getClassLoader().getResourceAsStream("sample_input.fml"); // 从标准输入解析,解析结果为 AST 节点列表 ModelParser parser = new ModelParser(is); List ast = parser.CompilationUnit(); diff --git a/flexmodel-engine/flexmodel-core/src/test/resources/sample_input.fml b/flexmodel-engine/flexmodel-core/src/test/resources/sample_input.fml new file mode 100644 index 00000000..3a43ab69 --- /dev/null +++ b/flexmodel-engine/flexmodel-core/src/test/resources/sample_input.fml @@ -0,0 +1,53 @@ +// 班级模型 +model Classes { + id: Long @id @default(autoIncrement()), + classCode? : String @length(255), + className? : String @length(255), +} + +// 学生模型 +model Student { + id: String @id @default(uuid()), + studentName? : String @length(255), + gender? : UserGender, + age? : Int, + classId? : Long, + score? : Float, + active? : Boolean @default("true"), + profile? : JSON, + createdAt? : DateTime @default(now()), +} + +// 性别枚举 +enum UserGender { + UNKNOWN, + MALE, + FEMALE +} + +// 班级种子数据 +seed Classes { + { classCode: "CLS001", className: "一班" }, + { classCode: "CLS002", className: "二班" }, + { classCode: "CLS003", className: "三班" }, +} + +// 学生种子数据(带注解) +seed Student @strategy("skip_exists") @match("studentName") { + { studentName: "张三", gender: "MALE", age: 18, score: 95.5, active: true }, + { studentName: "李四", gender: "FEMALE", age: 17, score: 88.0, active: true }, + { studentName: "王五", gender: "MALE", age: 19, score: null, active: false }, +} + +// 带嵌套对象和数组的种子数据 +seed Student { + { + studentName: "赵六", + age: 20, + profile: { + hobby: "编程", + level: 5, + skills: ["Java", "Python", "SQL"], + }, + }, +} diff --git a/flexmodel-engine/flexmodel-core/src/test/resources/sample_input.idl b/flexmodel-engine/flexmodel-core/src/test/resources/sample_input.idl deleted file mode 100644 index 6f432d79..00000000 --- a/flexmodel-engine/flexmodel-core/src/test/resources/sample_input.idl +++ /dev/null @@ -1,46 +0,0 @@ -// 班级 -model Classes { - id: String @id @default(uuid()), - classCode: String @unique @length(255), - className? : String @default("A班级"), - students: Student[] @relation(localField: "id", foreignField: "classId", cascadeDelete: true), -} - -// 学生 -model Student { - id : String @id @default(uuid()), - studentName? : String @length("255"), - gender? : UserGender, - interest? : User_interest[], - age? : Int, - classId? : Long, - studentClass: Classes @relation(localField: "classId", foreignField: "id"), - studentDetail: StudentDetail @relation(localField: "id", foreignField: "studentId", cascadeDelete: true), - createdAt? : DateTime @default(now()), - updatedAt? : DateTime @default(now()), - @index(name:"IDX_studentName", unique: false, fields: [classId, studentName: (sort: "desc")]), - @index(unique: "false", fields: [studentName]), - @index(unique: "false", fields: [classId]), -} - -// 学生详情 -model StudentDetail { - id : String @id @default(autoIncrement()), - studentId? : Long, - description? : String @length("255"), -} - -// 用户性别 -enum UserGender { - UNKNOWN, - MALE, - FEMALE -} - -// 用户爱好 -enum user_interest { - chang, - tiao, - rap, - daLanQiu -} diff --git a/flexmodel-engine/flexmodel-graphql/pom.xml b/flexmodel-engine/flexmodel-graphql/pom.xml index 994137f8..d2895444 100644 --- a/flexmodel-engine/flexmodel-graphql/pom.xml +++ b/flexmodel-engine/flexmodel-graphql/pom.xml @@ -54,7 +54,7 @@ org.codehaus.gmavenplus gmavenplus-plugin - 3.0.2 + 4.3.0 @@ -78,6 +78,7 @@ + 21 diff --git a/flexmodel-engine/flexmodel-graphql/src/main/groovy/dev/flexmodel/graphql/GraphQLSchemaGenerator.groovy b/flexmodel-engine/flexmodel-graphql/src/main/groovy/dev/flexmodel/graphql/GraphQLSchemaGenerator.groovy index 708c9f2f..60941b19 100644 --- a/flexmodel-engine/flexmodel-graphql/src/main/groovy/dev/flexmodel/graphql/GraphQLSchemaGenerator.groovy +++ b/flexmodel-engine/flexmodel-graphql/src/main/groovy/dev/flexmodel/graphql/GraphQLSchemaGenerator.groovy @@ -5,6 +5,7 @@ import dev.flexmodel.graphql.I18nUtil import dev.flexmodel.codegen.AbstractGenerator import dev.flexmodel.codegen.GenerationContext import dev.flexmodel.codegen.ModelField +import dev.flexmodel.codegen.StringUtils import dev.flexmodel.model.field.EnumRefField import dev.flexmodel.model.field.RelationField import dev.flexmodel.model.field.ScalarType @@ -28,15 +29,15 @@ class GraphQLSchemaGenerator extends AbstractGenerator { ] def comparisonMapping = [ - (ScalarType.STRING.getType()) : "String_comparison_exp", - (ScalarType.FLOAT.getType()) : "Float_comparison_exp", - (ScalarType.INT.getType()) : "Int_comparison_exp", - (ScalarType.LONG.getType()) : "Int_comparison_exp", - (ScalarType.BOOLEAN.getType()) : "Boolean_comparison_exp", - (ScalarType.DATETIME.getType()): "Date_comparison_exp", - (ScalarType.DATE.getType()) : "DateTime_comparison_exp", - (ScalarType.TIME.getType()) : "DateTime_comparison_exp", - (ScalarType.JSON.getType()) : "JSON_comparison_exp", + (ScalarType.STRING.getType()) : "StringComparisonExp", + (ScalarType.FLOAT.getType()) : "FloatComparisonExp", + (ScalarType.INT.getType()) : "IntComparisonExp", + (ScalarType.LONG.getType()) : "IntComparisonExp", + (ScalarType.BOOLEAN.getType()) : "BooleanComparisonExp", + (ScalarType.DATETIME.getType()): "DateComparisonExp", + (ScalarType.DATE.getType()) : "DateTimeComparisonExp", + (ScalarType.TIME.getType()) : "DateTimeComparisonExp", + (ScalarType.JSON.getType()) : "JSONComparisonExp", ] I18nUtil i18n = new I18nUtil() @@ -44,10 +45,11 @@ class GraphQLSchemaGenerator extends AbstractGenerator { def toGraphQLType(ModelField itt, GenerationContext context) { if (itt.isRelationField()) { def rf = itt.original as RelationField + def typeName = StringUtils.capitalize(StringUtils.snakeToCamel(rf.from)) if (rf.multiple) { - return "[${itt.modelClass.schemaName}_${rf.from}]" + return "[${typeName}]" } else { - return "${itt.modelClass.schemaName}_${rf.from}" + return "${typeName}" } } else if (itt.isBasicField()) { def f = itt.original as TypedField @@ -57,10 +59,11 @@ class GraphQLSchemaGenerator extends AbstractGenerator { return "${typeMapping[f.type]}" } else if (itt.isEnumField() && context.containsEnumClass((itt.original as EnumRefField).from)) { def ef = itt.original as EnumRefField + def typeName = StringUtils.capitalize(StringUtils.snakeToCamel(ef.from)) if (ef.multiple) { - return "[${itt.modelClass.schemaName}_${ef.from}]" + return "[${typeName}]" } else { - return "${itt.modelClass.schemaName}_${ef.from}" + return "${typeName}" } } else { return "String" @@ -76,7 +79,7 @@ class GraphQLSchemaGenerator extends AbstractGenerator { context.enumClassList.each { out.println "" - out.println "enum ${it.schemaName}_${it.original.name} {" + out.println "enum ${it.shortClassName} {" it.elements.each { out.println " ${it}" } @@ -86,15 +89,19 @@ class GraphQLSchemaGenerator extends AbstractGenerator { // gen query out.println "\"${i18n.getString("gql.query.comment")}\"" out.println "type Query {" + if (context.modelClassList.isEmpty()) { + out.println " _health: String" + } context.modelClassList.each { - def key = "${it.schemaName}_${it.original.name}" + def key = it.shortClassName + def qkey = StringUtils.uncapitalize(key) out.println "" out.println " \"${i18n.getString("gql.query.find.comment", it.schemaName, it.original.name)}\"" - out.println " ${DataFetchers.FIND.keyFunc.apply(it.schemaName, it.original.name)}(" + out.println " ${DataFetchers.FIND.keyFunc.apply(it.schemaName, qkey)}(" out.println " \"${i18n.getString("gql.query.where.comment")}\"" - out.println " where: ${key}_bool_exp" + out.println " where: ${key}BoolExp" out.println " \"${i18n.getString("gql.query.order_by.comment")}\"" - out.println " order_by: ${key}_order_by" + out.println " orderBy: ${key}OrderBy" out.println " \"${i18n.getString("gql.query.size.comment")}\"" out.println " size: Int" out.println " \"${i18n.getString("gql.query.page.comment")}\"" @@ -102,65 +109,70 @@ class GraphQLSchemaGenerator extends AbstractGenerator { out.println " ): [${key}!]!" out.println "" out.println " \"${i18n.getString("gql.query.aggregate.comment", it.schemaName, it.original.name)}\"" - out.println " ${DataFetchers.AGGREGATE.keyFunc.apply(it.schemaName, it.original.name)}(" + out.println " ${DataFetchers.AGGREGATE.keyFunc.apply(it.schemaName, qkey)}(" out.println " \"${i18n.getString("gql.query.where.comment")}\"" - out.println " where: ${key}_bool_exp" + out.println " where: ${key}BoolExp" out.println " \"${i18n.getString("gql.query.order_by.comment")}\"" - out.println " order_by: ${key}_order_by" + out.println " orderBy: ${key}OrderBy" out.println " \"${i18n.getString("gql.query.size.comment")}\"" out.println " size: Int" out.println " \"${i18n.getString("gql.query.page.comment")}\"" out.println " page: Int" - out.println " ): ${key}_aggregate!" + out.println " ): ${key}Aggregate!" out.println "" - out.println " \"${i18n.getString("gql.query.find_one.comment", it.schemaName, it.original.name)}\"" - out.println " ${DataFetchers.FIND_ONE.keyFunc.apply(it.schemaName, it.original.name)}(" - out.println " \"filter the rows returned\"" - out.println " where: ${key}_bool_exp" - out.println " ): ${key}" + if (it.idField) { + out.println " \"${i18n.getString("gql.query.by_id.comment", it.schemaName, it.original.name)}\"" + out.println " ${DataFetchers.BY_ID.keyFunc.apply(it.schemaName, qkey)}(" + out.println " id: ID!" + out.println " ): ${key}" + } } out.println "}" // gen mutation out.println "" out.println "\"${i18n.getString("gql.mutation.comment")}\"" out.println "type Mutation {" + if (context.modelClassList.isEmpty()) { + out.println " _noop: String" + } context.modelClassList.each { - def key = "${it.schemaName}_${it.original.name}" + def key = it.shortClassName + def qkey = StringUtils.uncapitalize(key) out.println "" out.println " \"${i18n.getString("gql.mutation.delete.comment", it.schemaName, it.original.name)}\"" - out.println " ${DataFetchers.MUTATION_DELETE.keyFunc.apply(it.schemaName, it.original.name)}(" + out.println " ${DataFetchers.MUTATION_DELETE.keyFunc.apply(it.schemaName, qkey)}(" out.println " \"${i18n.getString("gql.mutation.delete.filter.comment")}\"" - out.println " where: ${key}_bool_exp!" - out.println " ): mutation_response" + out.println " where: ${key}BoolExp!" + out.println " ): MutationResponse" if (it.idField) { out.println "" out.println " \"${i18n.getString("gql.mutation.delete_by_id.comment", it.schemaName, it.original.name)}\"" - out.println " ${DataFetchers.MUTATION_DELETE_BY_ID.keyFunc.apply(it.schemaName, it.original.name)}(" + out.println " ${DataFetchers.MUTATION_DELETE_BY_ID.keyFunc.apply(it.schemaName, qkey)}(" out.println " id: ID!" out.println " ): ${key}" out.println "" out.println " \"${i18n.getString("gql.mutation.update_by_id.comment", it.schemaName, it.original.name)}\"" - out.println " ${DataFetchers.MUTATION_UPDATE_BY_ID.keyFunc.apply(it.schemaName, it.original.name)}(" - out.println " _set: ${key}_set_input" + out.println " ${DataFetchers.MUTATION_UPDATE_BY_ID.keyFunc.apply(it.schemaName, qkey)}(" + out.println " set: ${key}SetInput" out.println " id: ID!" out.println " ): ${key}" } out.println "" out.println " \"${i18n.getString("gql.mutation.create.comment", it.schemaName, it.original.name)}\"" - out.println " ${DataFetchers.MUTATION_CREATE.keyFunc.apply(it.schemaName, it.original.name)}(" - out.println " data: ${key}_insert_input" + out.println " ${DataFetchers.MUTATION_CREATE.keyFunc.apply(it.schemaName, qkey)}(" + out.println " data: ${key}InsertInput" out.println " ): ${key}" out.println "" out.println " \"${i18n.getString("gql.mutation.update.comment", it.schemaName, it.original.name)}\"" - out.println " ${DataFetchers.MUTATION_UPDATE.keyFunc.apply(it.schemaName, it.original.name)}(" - out.println " _set: ${key}_set_input" - out.println " where: ${key}_bool_exp!" - out.println " ): mutation_response" + out.println " ${DataFetchers.MUTATION_UPDATE.keyFunc.apply(it.schemaName, qkey)}(" + out.println " set: ${key}SetInput" + out.println " where: ${key}BoolExp!" + out.println " ): MutationResponse" } out.println "}" out.println "" context.modelClassList.each { - def key = "${it.schemaName}_${it.original.name}" + def key = it.shortClassName out.println " \"${i18n.getString("gql.type.model.comment", it.schemaName, it.original.name)}\"" out.println "type ${key} {" it.allFields.each { @@ -171,17 +183,17 @@ class GraphQLSchemaGenerator extends AbstractGenerator { out.println "}" out.println "" "\"${i18n.getString("gql.query.aggregate.selection.comment", key)}\"" - out.println "type ${key}_aggregate {" - out.println " _count(distinct: Boolean, field: ${key}_select_field): Int!" + out.println "type ${key}Aggregate {" + out.println " _count(distinct: Boolean, field: ${key}SelectField): Int!" out.println " _max: ${key}!" out.println " _min: ${key}!" out.println " _sum: ${key}!" - out.println " _avg: ${key}_avg_fields!" + out.println " _avg: ${key}AvgFields!" out.println " _join: Query" out.println " _join_mutation: Mutation" out.println "}" out.println "" - out.println "type ${key}_avg_fields {" + out.println "type ${key}AvgFields {" it.allFields.each { if (!it.isRelationField()) { out.println " ${it.name}: Float" @@ -192,36 +204,35 @@ class GraphQLSchemaGenerator extends AbstractGenerator { } context.modelClassList.each { out.println "" - def schemaName = it.schemaName - def key = "${it.schemaName}_${it.original.name}" + def key = it.shortClassName // gen input model out.println "\"${i18n.getString("gql.bool_expr.comment", key)}\"" - out.println "input ${key}_bool_exp {" - out.println " _and: [${key}_bool_exp!]" - out.println " _or: [${key}_bool_exp!]" + out.println "input ${key}BoolExp {" + out.println " and: [${key}BoolExp!]" + out.println " or: [${key}BoolExp!]" it.allFields.each { if (!it.isRelationField() && !it.isEnumField()) { TypedField f = it.original as TypedField out.println " ${it.name}: ${comparisonMapping[f.type]}" } else if (it.isEnumField() && context.containsEnumClass((it.original as EnumRefField).from)) { EnumRefField enumField = it.original as EnumRefField - out.println " ${it.name}: ${schemaName}_${enumField.from}_comparison_exp" + out.println " ${it.name}: ${StringUtils.capitalize(StringUtils.snakeToCamel(enumField.from))}ComparisonExp" } else { - out.println " ${it.name}: String_comparison_exp" + out.println " ${it.name}: StringComparisonExp" } } out.println "}" out.println "" out.println "\"${i18n.getString("gql.order_by.comment", key)}\"" - out.println "input ${key}_order_by {" + out.println "input ${key}OrderBy {" it.allFields.each { if (!it.isRelationField()) { - out.println " ${it.name}: order_by" + out.println " ${it.name}: OrderBy" } } out.println "}" out.println "" - out.println "input ${key}_insert_input {" + out.println "input ${key}InsertInput {" it.allFields.each { if (!it.isRelationField()) { out.println " ${it.name}: ${toGraphQLType(it, context)}" @@ -229,7 +240,7 @@ class GraphQLSchemaGenerator extends AbstractGenerator { } out.println "}" out.println "" - out.println "input ${key}_set_input {" + out.println "input ${key}SetInput {" it.allFields.each { if (!it.isRelationField()) { out.println " ${it.name}: ${toGraphQLType(it, context)}" @@ -238,9 +249,9 @@ class GraphQLSchemaGenerator extends AbstractGenerator { out.println "}" } context.modelClassList.each { - def key = "${it.schemaName}_${it.original.name}" + def key = it.shortClassName out.println "" - out.println "enum ${key}_select_field {" + out.println "enum ${key}SelectField {" it.allFields.each { if (!it.isRelationField()) { out.println " ${it.name}" @@ -263,7 +274,7 @@ class GraphQLSchemaGenerator extends AbstractGenerator { out.println "scalar Time" out.println "" out.println "\"${i18n.getString("gql.comparison_exp.comment", "Int")}\"" - out.println "input Int_comparison_exp {" + out.println "input IntComparisonExp {" out.println " _eq: Int" out.println " _ne: Int" out.println " _gt: Int" @@ -275,7 +286,7 @@ class GraphQLSchemaGenerator extends AbstractGenerator { out.println "}" out.println "" out.println "\"${i18n.getString("gql.comparison_exp.comment", "Float")}\"" - out.println "input Float_comparison_exp {" + out.println "input FloatComparisonExp {" out.println " _eq: Float" out.println " _ne: Float" out.println " _gt: Float" @@ -287,7 +298,7 @@ class GraphQLSchemaGenerator extends AbstractGenerator { out.println "}" out.println "" out.println "\"${i18n.getString("gql.comparison_exp.comment", "String")}\"" - out.println "input String_comparison_exp {" + out.println "input StringComparisonExp {" out.println " _eq: String" out.println " _ne: String" out.println " _in: [String!]" @@ -299,7 +310,7 @@ class GraphQLSchemaGenerator extends AbstractGenerator { out.println "}" out.println "" out.println "\"${i18n.getString("gql.comparison_exp.comment", "JSON")}\"" - out.println "input JSON_comparison_exp {" + out.println "input JSONComparisonExp {" out.println " _eq: String" out.println " _ne: String" out.println " _in: [String!]" @@ -311,13 +322,13 @@ class GraphQLSchemaGenerator extends AbstractGenerator { out.println "}" out.println "" out.println "\"${i18n.getString("gql.comparison_exp.comment", "Boolean")}\"" - out.println "input Boolean_comparison_exp {" + out.println "input BooleanComparisonExp {" out.println " _eq: Boolean" out.println " _ne: Boolean" out.println "}" out.println "" out.println "\"${i18n.getString("gql.comparison_exp.comment", "Date")}\"" - out.println "input Date_comparison_exp {" + out.println "input DateComparisonExp {" out.println " _eq: Date" out.println " _ne: Date" out.println " _gt: Date" @@ -330,7 +341,7 @@ class GraphQLSchemaGenerator extends AbstractGenerator { out.println "}" out.println "" out.println "\"${i18n.getString("gql.comparison_exp.comment", "DateTime")}\"" - out.println "input DateTime_comparison_exp {" + out.println "input DateTimeComparisonExp {" out.println " _eq: DateTime" out.println " _ne: DateTime" out.println " _gt: DateTime" @@ -343,7 +354,7 @@ class GraphQLSchemaGenerator extends AbstractGenerator { out.println "}" out.println "" out.println "\"${i18n.getString("gql.comparison_exp.comment", "Time")}\"" - out.println "input Time_comparison_exp {" + out.println "input TimeComparisonExp {" out.println " _eq: Time" out.println " _ne: Time" out.println " _gt: Time" @@ -358,17 +369,17 @@ class GraphQLSchemaGenerator extends AbstractGenerator { context.enumClassList.each { out.println "" out.println "\"${i18n.getString("gql.comparison_exp.comment", "EnumRef")}\"" - out.println "input ${it.schemaName}_${it.original.name}_comparison_exp {" - out.println " _eq: ${it.schemaName}_${it.original.name}" - out.println " _ne: ${it.schemaName}_${it.original.name}" - out.println " _in: [${it.schemaName}_${it.original.name}!]" - out.println " _nin: [${it.schemaName}_${it.original.name}!]" + out.println "input ${it.shortClassName}ComparisonExp {" + out.println " _eq: ${it.shortClassName}" + out.println " _ne: ${it.shortClassName}" + out.println " _in: [${it.shortClassName}!]" + out.println " _nin: [${it.shortClassName}!]" out.println "}" out.println "" } out.println "" out.println "\"${i18n.getString("gql.enum.order_by.comment")}\"" - out.println "enum order_by {" + out.println "enum OrderBy {" out.println " \"${i18n.getString("gql.enum.order_by.asc.comment")}\"" out.println " asc" out.println " \"${i18n.getString("gql.enum.order_by.desc.comment")}\"" @@ -376,9 +387,9 @@ class GraphQLSchemaGenerator extends AbstractGenerator { out.println "}" out.println "" out.println "\"${i18n.getString("gql.mutation.response.comment")}\"" - out.println "type mutation_response {" + out.println "type MutationResponse {" out.println " \"${i18n.getString("gql.mutation.response.affected_rows.comment")}\"" - out.println " affected_rows: Int!" + out.println " affectedRows: Int!" out.println " _join: Query" out.println " _join_mutation: Mutation" out.println "}" diff --git a/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/DataFetchers.java b/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/DataFetchers.java index 046ab6d4..9b4a9fba 100644 --- a/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/DataFetchers.java +++ b/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/DataFetchers.java @@ -1,6 +1,7 @@ package dev.flexmodel.graphql; import graphql.schema.DataFetcher; +import dev.flexmodel.codegen.StringUtils; import dev.flexmodel.session.SessionFactory; import java.util.function.BiFunction; @@ -9,14 +10,14 @@ * @author cjbi */ public enum DataFetchers { - FIND((schema, model) -> schema + "_list" + "_" + model, FlexmodelListDataFetcher::new, true), - FIND_ONE((schema, model) -> schema + "_find_one" + "_" + model, FlexmodelFindOneDataFetcher::new, true), - AGGREGATE((schema, model) -> schema + "_aggregate" + "_" + model, FlexmodelAggregateDataFetcher::new, true), - MUTATION_DELETE((schema, model) -> schema + "_" + "delete_" + model, FlexmodelMutationDeleteDataFetcher::new, false), - MUTATION_DELETE_BY_ID((schema, model) -> schema + "_" + "delete_" + model + "_by_id", FlexmodelMutationDeleteByIdDataFetcher::new, false), - MUTATION_CREATE((schema, model) -> schema + "_" + "create_" + model, FlexmodelMutationCreateDataFetcher::new, false), - MUTATION_UPDATE((schema, model) -> schema + "_" + "update_" + model, FlexmodelMutationUpdateDataFetcher::new, false), - MUTATION_UPDATE_BY_ID((schema, model) -> schema + "_" + "update_" + model + "_by_id", FlexmodelMutationUpdateByIdDataFetcher::new, false); + FIND((schema, model) -> model, FlexmodelListDataFetcher::new, true), + BY_ID((schema, model) -> model + "ById", FlexmodelByIdDataFetcher::new, true), + AGGREGATE((schema, model) -> model + "Aggregate", FlexmodelAggregateDataFetcher::new, true), + MUTATION_DELETE((schema, model) -> "delete" + StringUtils.capitalize(model), FlexmodelMutationDeleteDataFetcher::new, false), + MUTATION_DELETE_BY_ID((schema, model) -> "delete" + StringUtils.capitalize(model) + "ById", FlexmodelMutationDeleteByIdDataFetcher::new, false), + MUTATION_CREATE((schema, model) -> "create" + StringUtils.capitalize(model), FlexmodelMutationCreateDataFetcher::new, false), + MUTATION_UPDATE((schema, model) -> "update" + StringUtils.capitalize(model), FlexmodelMutationUpdateDataFetcher::new, false), + MUTATION_UPDATE_BY_ID((schema, model) -> "update" + StringUtils.capitalize(model) + "ById", FlexmodelMutationUpdateByIdDataFetcher::new, false); private final BiFunction keyFunc; private final DataFetcherFunc dataFetcherFunc; diff --git a/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelAbstractDataFetcher.java b/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelAbstractDataFetcher.java index b1037bc3..fae1eebd 100644 --- a/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelAbstractDataFetcher.java +++ b/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelAbstractDataFetcher.java @@ -33,10 +33,10 @@ public abstract class FlexmodelAbstractDataFetcher implements DataFetcher protected static final String PAGE_NUMBER = "page"; protected static final String PAGE_SIZE = "size"; - protected static final String ORDER_BY = "order_by"; + protected static final String ORDER_BY = "orderBy"; protected static final String WHERE = "where"; protected static final String ID = "id"; - protected static final String AFFECTED_ROWS = "affected_rows"; + protected static final String AFFECTED_ROWS = "affectedRows"; protected static final String AGG_COUNT = "_count"; protected static final String AGG_MAX = "_max"; protected static final String AGG_MIN = "_min"; diff --git a/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelFindOneDataFetcher.java b/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelByIdDataFetcher.java similarity index 60% rename from flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelFindOneDataFetcher.java rename to flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelByIdDataFetcher.java index 50f34e62..48b76e43 100644 --- a/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelFindOneDataFetcher.java +++ b/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelByIdDataFetcher.java @@ -2,7 +2,6 @@ import graphql.schema.DataFetchingEnvironment; import graphql.schema.SelectedField; -import dev.flexmodel.JsonUtils; import dev.flexmodel.model.EntityDefinition; import dev.flexmodel.model.field.RelationField; import dev.flexmodel.model.field.TypedField; @@ -14,27 +13,24 @@ import java.util.List; import java.util.Map; -import static dev.flexmodel.query.Query.field; +import static dev.flexmodel.query.Expressions.field; +import dev.flexmodel.query.Expressions; +import dev.flexmodel.query.Query; /** * @author cjbi */ -public class FlexmodelFindOneDataFetcher extends FlexmodelAbstractDataFetcher> { +public class FlexmodelByIdDataFetcher extends FlexmodelAbstractDataFetcher> { - public FlexmodelFindOneDataFetcher(String schemaName, String modelName, SessionFactory sessionFactory) { + public FlexmodelByIdDataFetcher(String schemaName, String modelName, SessionFactory sessionFactory) { super(schemaName, modelName, sessionFactory); } @Override public Map get(DataFetchingEnvironment env) { - return findRootData(env); - } - - private Map findRootData(DataFetchingEnvironment env) { + Object id = getArgument(env, ID); List selectedFields = env.getSelectionSet().getImmediateFields(); - Map where = getArgument(env, WHERE); - final String filter = where != null ? JsonUtils.toJsonString(where) : null; try (Session session = sessionFactory.createSession(schemaName)) { EntityDefinition entity = (EntityDefinition) session.schema().getModel(modelName); TypedField idField = entity.findIdField().orElseThrow(); @@ -43,7 +39,7 @@ private Map findRootData(DataFetchingEnvironment env) { List> list = session.dsl() .select(projection -> { - projection.field(idField.getName(), field(entity.getName() + "." + idField.getName())); + projection.field(idField.getName(), Query.field(entity.getName() + "." + idField.getName())); for (SelectedField selectedField : selectedFields) { TypedField flexModelField = entity.getField(selectedField.getName()); if (flexModelField == null) { @@ -53,12 +49,12 @@ private Map findRootData(DataFetchingEnvironment env) { relationFields.add(secondaryRelationField); continue; } - projection.field(selectedField.getName(), field(flexModelField.getModelName() + "." + flexModelField.getName())); + projection.field(selectedField.getName(), Query.field(flexModelField.getModelName() + "." + flexModelField.getName())); } return projection; }) .from(entity.getName()) - .where(filter) + .where(Expressions.field(entity.getName() + "." + idField.getName()).eq(id)) .page(1, 1) .execute(); @@ -66,14 +62,13 @@ private Map findRootData(DataFetchingEnvironment env) { return null; } Map resultData = new HashMap<>(list.stream().findFirst().orElseThrow()); - for (RelationField sencondaryRelationField : relationFields) { - Object secondaryId = resultData.get(entity.findIdField().map(TypedField::getName).orElseThrow()); - List> relationDataList = findRelationDataList(session, env, null, sencondaryRelationField.getFrom(), sencondaryRelationField, secondaryId); - resultData.put(sencondaryRelationField.getName(), sencondaryRelationField.isMultiple() ? relationDataList : relationDataList.stream().findFirst().orElse(null)); + for (RelationField secondaryRelationField : relationFields) { + Object secondaryId = resultData.get(idField.getName()); + List> relationDataList = findRelationDataList(session, env, null, secondaryRelationField.getFrom(), secondaryRelationField, secondaryId); + resultData.put(secondaryRelationField.getName(), secondaryRelationField.isMultiple() ? relationDataList : relationDataList.stream().findFirst().orElse(null)); } return resultData; } - } } diff --git a/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelGraphQL.java b/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelGraphQL.java index bedf4d74..cb2fb4c0 100644 --- a/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelGraphQL.java +++ b/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelGraphQL.java @@ -14,6 +14,7 @@ import dev.flexmodel.codegen.EnumClass; import dev.flexmodel.codegen.GenerationContext; import dev.flexmodel.codegen.ModelClass; +import dev.flexmodel.codegen.StringUtils; import dev.flexmodel.model.EntityDefinition; import dev.flexmodel.model.EnumDefinition; import dev.flexmodel.model.SchemaObject; @@ -32,7 +33,7 @@ public class FlexmodelGraphQL { private final Logger log = LoggerFactory.getLogger(FlexmodelGraphQL.class); - public GraphQL generateGraphQLWithSchemaObject(SessionFactory sf, List includeSchemaNames) { + public GraphQL generateGraphQLWithSchemaObject(SessionFactory sf, String schemaName) { GraphQLSchemaGenerator generator = new GraphQLSchemaGenerator(); GenerationContext context = new GenerationContext(); Map> queryDataFetchers = new HashMap<>(); @@ -43,41 +44,38 @@ public GraphQL generateGraphQLWithSchemaObject(SessionFactory sf, List i "_join", (DataFetcher) environment -> Map.of(), "_join_mutation", (DataFetcher) environment -> Map.of() ); - joinDataFetchers.put("mutation_response", joinMap); + joinDataFetchers.put("MutationResponse", joinMap); - for (String schemaName : sf.getSchemaNames()) { - if (!includeSchemaNames.contains(schemaName)) { - log.debug("Generate GraphQL,Ignore schema: {}", schemaName); - continue; - } - log.debug("Generate graphQL schema: {}", schemaName); - List models = sf.getModels(schemaName); - for (SchemaObject model : models) { - if (model instanceof EntityDefinition entity) { - log.debug("Generate graphQL model: {}", model.getName()); - context.getModelClassList().add(ModelClass.buildModelClass("", schemaName, entity)); - joinDataFetchers.put(schemaName + "_" + model.getName(), joinMap); - joinDataFetchers.put(schemaName + "_" + model.getName() + "_aggregate", joinMap); - for (DataFetchers fetchType : DataFetchers.values()) { - if (fetchType.isQuery()) { - queryDataFetchers.put( - fetchType.getKeyFunc().apply(schemaName, model.getName()), - fetchType.getDataFetcherFunc().apply(schemaName, model.getName(), sf)); - } - if (fetchType.isMutation()) { - mutationDataFetchers.put( - fetchType.getKeyFunc().apply(schemaName, model.getName()), - fetchType.getDataFetcherFunc().apply(schemaName, model.getName(), sf)); - } + log.debug("Generate graphQL schema: {}", schemaName); + List models = sf.getModels(schemaName); + for (SchemaObject model : models) { + if (model instanceof EntityDefinition entity) { + log.debug("Generate graphQL model: {}", model.getName()); + String pascalName = StringUtils.capitalize(StringUtils.snakeToCamel(model.getName())); + String camelName = StringUtils.uncapitalize(pascalName); + context.getModelClassList().add(ModelClass.buildModelClass("", schemaName, entity)); + joinDataFetchers.put(pascalName, joinMap); + joinDataFetchers.put(pascalName + "Aggregate", joinMap); + + for (DataFetchers fetchType : DataFetchers.values()) { + if (fetchType.isQuery()) { + queryDataFetchers.put( + fetchType.getKeyFunc().apply(schemaName, camelName), + fetchType.getDataFetcherFunc().apply(schemaName, model.getName(), sf)); + } + if (fetchType.isMutation()) { + mutationDataFetchers.put( + fetchType.getKeyFunc().apply(schemaName, camelName), + fetchType.getDataFetcherFunc().apply(schemaName, model.getName(), sf)); } - } else if (model instanceof EnumDefinition andEnum) { - log.debug("Generate graphQL model: {}", model.getName()); - context.getEnumClassList().add(EnumClass.buildEnumClass("", schemaName, andEnum)); - } else { - log.debug("Ignore model: {}", model.getName()); - // 暂时忽略非实体类型 } + } else if (model instanceof EnumDefinition andEnum) { + log.debug("Generate graphQL model: {}", model.getName()); + context.getEnumClassList().add(EnumClass.buildEnumClass("", schemaName, andEnum)); + } else { + log.debug("Ignore model: {}", model.getName()); + // 暂时忽略非实体类型 } } diff --git a/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelMutationUpdateByIdDataFetcher.java b/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelMutationUpdateByIdDataFetcher.java index 0478d46c..b5da3cd7 100644 --- a/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelMutationUpdateByIdDataFetcher.java +++ b/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelMutationUpdateByIdDataFetcher.java @@ -22,7 +22,7 @@ public FlexmodelMutationUpdateByIdDataFetcher(String schemaName, String modelNam @Override public Map get(DataFetchingEnvironment environment) throws Exception { Object id = getArgument(environment, ID); - Map setValue = getArgument(environment, "_set"); + Map setValue = getArgument(environment, "set"); assert setValue != null; try (Session session = sessionFactory.createSession(schemaName)) { diff --git a/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelMutationUpdateDataFetcher.java b/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelMutationUpdateDataFetcher.java index e00b8657..92355499 100644 --- a/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelMutationUpdateDataFetcher.java +++ b/flexmodel-engine/flexmodel-graphql/src/main/java/dev/flexmodel/graphql/FlexmodelMutationUpdateDataFetcher.java @@ -19,7 +19,7 @@ public FlexmodelMutationUpdateDataFetcher(String schemaName, String modelName, S @Override public Map get(DataFetchingEnvironment environment) throws Exception { Map where = getArgument(environment, WHERE); - Map setValue = getArgument(environment, "_set"); + Map setValue = getArgument(environment, "set"); final String filter = where != null ? JsonUtils.toJsonString(where) : null; assert setValue != null; try (Session session = sessionFactory.createSession(schemaName)) { diff --git a/flexmodel-engine/flexmodel-graphql/src/main/resources/i18n/messages.properties b/flexmodel-engine/flexmodel-graphql/src/main/resources/i18n/messages.properties index 18c9fcfd..01f2b006 100644 --- a/flexmodel-engine/flexmodel-graphql/src/main/resources/i18n/messages.properties +++ b/flexmodel-engine/flexmodel-graphql/src/main/resources/i18n/messages.properties @@ -3,7 +3,7 @@ gql.query.where.comment=Filter the rows returned gql.query.order_by.comment=Sort the rows by one or more fields gql.query.size.comment=Specify the max returned records per page (default to 30) gql.query.page.comment=Specify the max returned records per page (default to 30) -gql.query.find_one.comment=Find Single row from “{0}.{1}” +gql.query.by_id.comment=Find a single row by ID from "{0}.{1}" gql.query.find.comment=Find multiple rows from “{0}.{1}” gql.query.aggregate.comment=Aggregate query “{0}.{1}” gql.query.aggregate.selection.comment=Aggregated selection of \\\"{0}\\\" diff --git a/flexmodel-engine/flexmodel-graphql/src/main/resources/i18n/messages_zh_CN.properties b/flexmodel-engine/flexmodel-graphql/src/main/resources/i18n/messages_zh_CN.properties index 28a30b92..d78a7747 100644 --- a/flexmodel-engine/flexmodel-graphql/src/main/resources/i18n/messages_zh_CN.properties +++ b/flexmodel-engine/flexmodel-graphql/src/main/resources/i18n/messages_zh_CN.properties @@ -3,7 +3,7 @@ gql.query.where.comment=过滤返回的行 gql.query.order_by.comment=按一个或多个字段对行进行排序 gql.query.size.comment=指定每页返回的最大记录数(默认值为 30) gql.query.page.comment=指定每页返回的最大记录数(默认值为 30) -gql.query.find_one.comment=从“{0}.{1}”中查询单条数据 +gql.query.by_id.comment=根据ID从“{0}.{1}”中查询单条数据 gql.query.find.comment=从“{0}.{1}”中查询多条数据 gql.query.aggregate.comment=从“{0}.{1}”中聚合查询数据 gql.query.aggregate.selection.comment=对“{0}”的聚合选择 diff --git a/flexmodel-engine/flexmodel-graphql/src/test/java/dev/flexmodel/graphql/GraphQLProviderTest.java b/flexmodel-engine/flexmodel-graphql/src/test/java/dev/flexmodel/graphql/GraphQLProviderTest.java index 4f86467f..8713d5f3 100644 --- a/flexmodel-engine/flexmodel-graphql/src/test/java/dev/flexmodel/graphql/GraphQLProviderTest.java +++ b/flexmodel-engine/flexmodel-graphql/src/test/java/dev/flexmodel/graphql/GraphQLProviderTest.java @@ -34,31 +34,31 @@ void testQuery() { createTeacherData(session, teacherEntityName); FlexmodelGraphQL graphQLProvider = new FlexmodelGraphQL(); - GraphQL graphQL = graphQLProvider.generateGraphQLWithSchemaObject(sessionFactory, sessionFactory.getSchemaNames()); + GraphQL graphQL = graphQLProvider.generateGraphQLWithSchemaObject(sessionFactory, "system"); // 创建查询 String query = """ query { - classes: system_list_testQueryClasses( + classes: testQueryClasses( page: 1, size:1, - where: {classCode: {_eq: "C_001"}, _and: [{className: {_eq: "一年级1班"}}, {_or: [{classCode: { _eq: "C_002"}}]}]} + where: {classCode: {_eq: "C_001"}, and: [{className: {_eq: "一年级1班"}}, {or: [{classCode: { _eq: "C_002"}}]}]} ) { id, classCode, className, students { name: studentName } } - students: system_list_testQueryStudent( + students: testQueryStudent( size: 3 page: 1 - order_by: {classId: asc, id: desc} + orderBy: {classId: asc, id: desc} ) { id, studentName } - teachers: system_list_testQueryTeacher { + teachers: testQueryTeacher { id, teacherName } - aggregate: system_aggregate_testQueryStudent { + aggregate: testQueryStudentAggregate { _count } - aggregate2: system_aggregate_testQueryStudent { + aggregate2: testQueryStudentAggregate { total: _count(distinct: true, field: id) _max { id, age @@ -73,17 +73,17 @@ void testQuery() { age } } - system_list_testQueryStudent { + testQueryStudent { age classId gender id studentName _join { - system_aggregate_Student { + testQueryStudentAggregate { _count } - system_list_testQueryStudent(size:10, page:1) { + testQueryStudent(size:10, page:1) { age classId gender @@ -120,17 +120,17 @@ void testDirective() { createTeacherData(session, teacherEntityName); FlexmodelGraphQL graphQLProvider = new FlexmodelGraphQL(); - GraphQL graphQL = graphQLProvider.generateGraphQLWithSchemaObject(sessionFactory, sessionFactory.getSchemaNames()); + GraphQL graphQL = graphQLProvider.generateGraphQLWithSchemaObject(sessionFactory, "system"); String query = """ query { - list: system_list_testDirectiveStudent { + list: testDirectiveStudent { classId studentName } - total: system_aggregate_testDirectiveStudent @transform(get: "_count") { + total: testDirectiveStudentAggregate @transform(get: "_count") { _count } - avgAge: system_aggregate_testDirectiveStudent @transform(get: "_avg.age") { + avgAge: testDirectiveStudentAggregate @transform(get: "_avg.age") { _avg { age } @@ -166,23 +166,23 @@ void testJoin() { createTeacherData(session, teacherEntityName); FlexmodelGraphQL graphQLProvider = new FlexmodelGraphQL(); - GraphQL graphQL = graphQLProvider.generateGraphQLWithSchemaObject(sessionFactory, sessionFactory.getSchemaNames()); + GraphQL graphQL = graphQLProvider.generateGraphQLWithSchemaObject(sessionFactory, "system"); String query = """ - query ($classId: Int = 1, $studentId: Int @internal) { - class: system_find_one_testJoinClasses(where: { id: { _eq: $classId } }) { + query ($classId: Int = 1, $classById: ID = 1, $studentId: Int @internal) { + class: testJoinClassesById(id: $classById) { className id _join { - students: system_list_testJoinStudent(where: { classId: { _eq: $classId } }) { + students: testJoinStudent(where: { classId: { _eq: $classId } }) { id @export(as: "studentId") studentName _join { - detail: system_find_one_testJoinStudentDetail(where: { studentId: { _eq: $studentId } }) { + detail: testJoinStudentDetail(size: 1, where: { studentId: { _eq: $studentId } }) { description } } } - total: system_aggregate_testJoinStudent(where: { classId: { _eq: $classId } }) { + total: testJoinStudentAggregate(where: { classId: { _eq: $classId } }) { _count } } @@ -216,18 +216,18 @@ void testMutation() { createTeacherData(session, teacherEntityName); FlexmodelGraphQL graphQLProvider = new FlexmodelGraphQL(); - GraphQL graphQL = graphQLProvider.generateGraphQLWithSchemaObject(sessionFactory, sessionFactory.getSchemaNames()); + GraphQL graphQL = graphQLProvider.generateGraphQLWithSchemaObject(sessionFactory, "system"); // 创建查询 String query = """ mutation { - class: system_create_testMutationClasses(data:{className: "测试班级", classCode: "TestC"}) { + class: createTestMutationClasses(data:{className: "测试班级", classCode: "TestC"}) { classCode } - course: system_create_testMutationCourse(data: {courseName: "测试课程", courseNo: "Test_CC"}) { + course: createTestMutationCourse(data: {courseName: "测试课程", courseNo: "Test_CC"}) { courseName courseNo } - student: system_create_testMutationStudent(data: {studentName: "张三丰", gender: MALE, age: 200, classId: 1, remark: {test:"aa"}}) { + student: createTestMutationStudent(data: {studentName: "张三丰", gender: MALE, age: 200, classId: 1, remark: {test:"aa"}}) { id remark } @@ -241,10 +241,10 @@ void testMutation() { Assertions.assertNotNull(data.get("student")); String query2 = """ mutation MyMutation($studentId: ID!, $courseNo: ID!) { - class: system_delete_testMutationCourse_by_id(id: $courseNo) { + class: deleteTestMutationCourseById(id: $courseNo) { courseNo } - student: system_update_testMutationStudent_by_id(_set: {age: 199, remark: {test: "bb"}}, id: $studentId) { + student: updateTestMutationStudentById(set: {age: 199, remark: {test: "bb"}}, id: $studentId) { id } } diff --git a/flexmodel-engine/flexmodel-quarkus/README.md b/flexmodel-engine/flexmodel-quarkus/README.md deleted file mode 100644 index 6c33e5ba..00000000 --- a/flexmodel-engine/flexmodel-quarkus/README.md +++ /dev/null @@ -1,293 +0,0 @@ -# FlexModel Quarkus扩展 - -FlexModel Quarkus扩展提供了在Quarkus应用中集成FlexModel Session管理的完整解决方案,支持自动Session生命周期管理、事务管理和异步操作中的上下文传播。 - -## 功能特性 - -- **自动Session管理**: 通过`@SessionManaged`注解自动管理Session的生命周期 -- **事务管理**: 通过`@Transactional`注解自动管理事务边界 -- **异步支持**: 自动在Mutiny、CompletableFuture等异步操作中传播Session上下文 -- **CDI集成**: 完全集成Quarkus CDI容器,支持依赖注入 -- **零配置**: 扩展自动注册所有必要的组件,无需手动配置 - -## 快速开始 - -### 1. 添加依赖 - -在`pom.xml`中添加依赖: - -```xml - - dev.flexmodel - flexmodel-quarkus - 0.0.1-SNAPSHOT - - - - - io.smallrye - smallrye-context-propagation - -``` - -### 2. 配置SessionFactory - -创建SessionFactory的Producer: - -```java -@ApplicationScoped -public class SessionConfig { - - @Produces - @ApplicationScoped - public SessionFactory sessionFactory() { - HikariDataSource dataSource = new HikariDataSource(); - dataSource.setJdbcUrl("jdbc:sqlite:file::memory:?cache=shared"); - - return SessionFactory.builder() - .setDefaultDataSourceProvider(new JdbcDataSourceProvider("system", dataSource)) - .build(); - } -} -``` - -### 3. 使用注解 - -#### @SessionManaged - -用于标记需要自动Session管理的方法或类: - -```java -@Path("/users") -@SessionManaged -public class UserResource { - - @Inject - private Session session; - - @GET - public Response getAllUsers() { - // Session已自动创建,可以直接使用 - List> users = session.data().find("users", Query.Builder.create().build()); - return Response.ok(users).build(); - // 方法结束时Session自动销毁 - } - - @POST - @SessionManaged(schema = "custom") // 指定特定的schema - public Response createUser(Map userData) { - // 使用指定的schema创建Session - session.data().insert("users", userData); - return Response.ok().build(); - } -} -``` - -#### @Transactional - -用于自动管理事务,必须配合`@SessionManaged`使用: - -```java -@ApplicationScoped -@SessionManaged -public class UserService { - - @Inject - private Session session; - - @Transactional - public void createUser(Map userData) { - // 事务已自动开启 - session.data().insert("users", userData); - // 方法正常返回时自动提交,异常时自动回滚 - } - - @Transactional(readOnly = true) - public List> getAllUsers() { - // 只读事务 - return session.data().find("users", Query.Builder.create().build()); - } -} -``` - -## 异步操作支持 - -扩展通过`smallrye-context-propagation`自动支持在异步操作中传播Session上下文,无需额外配置: - -### Mutiny示例 - -```java -@SessionManaged -public class AsyncUserService { - - @Inject - private Session session; - - @Inject - private QuarkusSessionManager sessionManager; - - public Uni>> getAllUsersAsync() { - // Session上下文会自动传播到异步操作中 - return Uni.createFrom().item(() -> { - // 在新线程中可以访问Session - Session asyncSession = sessionManager.getCurrentSession(); - return asyncSession.data().find("users", Query.Builder.create().build()); - }); - } - - @Transactional - public Uni createUserAsync(Map userData) { - // 事务和Session都会自动传播 - return Uni.createFrom().item(() -> { - Session asyncSession = sessionManager.getCurrentSession(); - asyncSession.data().insert("users", userData); - return null; - }); - } -} -``` - -### CompletableFuture示例 - -```java -@SessionManaged -public class AsyncService { - - @Inject - private QuarkusSessionManager sessionManager; - - @Transactional - public CompletableFuture processAsync() { - return CompletableFuture.supplyAsync(() -> { - // Session上下文自动传播 - Session session = sessionManager.getCurrentSession(); - session.data().insert("items", itemData); - return null; - }); - } -} -``` - -## 注解详解 - -### @SessionManaged - -**作用**: 标记需要自动Session管理的方法或类 - -**属性**: -- `schema()`: 指定要使用的schema名称,默认为空字符串(使用默认schema) - -**使用级别**: -- 类级别:类中所有方法都会自动管理Session -- 方法级别:只有标记的方法会管理Session,会覆盖类级别的设置 - -**注意事项**: -- Session在方法执行前创建,执行后销毁 -- 支持嵌套调用,不会重复创建Session -- 自动激活RequestContext,确保CDI Bean可用 - -### @Transactional - -**作用**: 自动管理事务边界 - -**属性**: -- `readOnly()`: 是否为只读事务,默认为`false` - -**使用级别**: -- 类级别:类中所有方法都使用事务管理 -- 方法级别:只有标记的方法使用事务管理 - -**注意事项**: -- 必须配合`@SessionManaged`使用 -- 方法正常返回时自动提交事务 -- 方法抛出异常时自动回滚事务 -- 支持嵌套事务(但当前实现为简化版) - -## 核心组件 - -### QuarkusSessionManager - -继承自`SessionManager`,集成CDI容器: - -```java -@ApplicationScoped -public class QuarkusSessionManager extends SessionManager { - @Inject - public QuarkusSessionManager(SessionFactory sessionFactory) { - super(sessionFactory); - } -} -``` - -### SessionProvider - -CDI提供者,用于注入Session: - -```java -@Inject -private Session session; -``` - -### SessionContextPropagator - -上下文传播器,自动在异步操作间传播Session状态,无需手动配置。 - -## 最佳实践 - -1. **使用注解**: 优先使用`@SessionManaged`和`@Transactional`注解,而不是手动管理 -2. **事务边界**: 使用`@Transactional`明确事务边界,避免手动管理事务 -3. **异步操作**: 在异步操作中,Session上下文会自动传播,可以直接使用 -4. **嵌套调用**: 支持嵌套调用,不会重复创建Session -5. **异常处理**: `@Transactional`会自动处理异常并回滚事务 - -## 技术原理 - -### 上下文传播机制 - -扩展实现了`ThreadContextProvider`接口,在异步操作切换线程时自动: -1. 捕获当前Session状态(schema列表和lastUsedSchema) -2. 在新线程中恢复Session状态 -3. 通过SessionManager重新获取Session实例 - -### RequestContext激活 - -`SessionInterceptor`自动激活RequestContext,确保在异步操作中可以: -1. 访问CDI Bean -2. 注入依赖 -3. 使用CDI的`@RequestScoped`等作用域 - -### 拦截器优先级 - -- `SessionInterceptor`: `APPLICATION + 100` (先执行,创建Session) -- `TransactionalInterceptor`: `APPLICATION + 50` (后执行,管理事务) - -## 故障排查 - -### Session未创建 - -确保方法或类上使用了`@SessionManaged`注解。 - -### 事务未生效 - -确保: -1. 方法或类上使用了`@Transactional`注解 -2. 同时使用了`@SessionManaged`注解 -3. Session已经创建 - -### 异步操作中无法访问Session - -确保: -1. 添加了`smallrye-context-propagation`依赖 -2. 使用了支持上下文传播的异步操作(如Mutiny、CompletableFuture) -3. 方法上有`@SessionManaged`注解 - -## 版本兼容性 - -- Quarkus: 3.13.2+ -- Java: 21+ -- FlexModel Core: 0.0.1-SNAPSHOT - -## 许可证 - -与FlexModel项目相同的许可证。 - diff --git a/flexmodel-engine/flexmodel-quarkus/pom.xml b/flexmodel-engine/flexmodel-quarkus/pom.xml deleted file mode 100644 index 27c27292..00000000 --- a/flexmodel-engine/flexmodel-quarkus/pom.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - 4.0.0 - - dev.flexmodel - flexmodel-engine - 0.0.1-SNAPSHOT - - flexmodel-quarkus - jar - - - 3.13.0 - 21 - UTF-8 - UTF-8 - quarkus-bom - io.quarkus.platform - 3.13.2 - - - - - - ${quarkus.platform.group-id} - ${quarkus.platform.artifact-id} - ${quarkus.platform.version} - pom - import - - - - - - - - dev.flexmodel - flexmodel-core - ${project.version} - - - - - io.quarkus - quarkus-arc - - - io.quarkus - quarkus-rest - - - io.quarkus - quarkus-core - - - - - io.smallrye - smallrye-context-propagation - - - - - io.quarkus - quarkus-extension-processor - ${quarkus.platform.version} - provided - - - io.quarkus - quarkus-arc-deployment - provided - - - io.quarkus - quarkus-core-deployment - provided - - - - - org.slf4j - slf4j-api - - - - - - - maven-compiler-plugin - ${compiler-plugin.version} - - true - - - io.quarkus - quarkus-extension-processor - ${quarkus.platform.version} - - - - - - - diff --git a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/extension/FlexmodelQuarkusProcessor.java b/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/extension/FlexmodelQuarkusProcessor.java deleted file mode 100644 index de9d99c6..00000000 --- a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/extension/FlexmodelQuarkusProcessor.java +++ /dev/null @@ -1,36 +0,0 @@ -package dev.flexmodel.quarkus.extension; - -import io.quarkus.arc.deployment.AdditionalBeanBuildItem; -import io.quarkus.deployment.annotations.BuildStep; -import io.quarkus.deployment.builditem.FeatureBuildItem; - -/** - * FlexModel Quarkus扩展的构建时处理器 - * - * 该处理器在构建时注册必要的Bean和功能 - * - * @author cjbi - */ -public class FlexmodelQuarkusProcessor { - - private static final String FEATURE = "flexmodel-quarkus"; - - @BuildStep - FeatureBuildItem feature() { - return new FeatureBuildItem(FEATURE); - } - - @BuildStep - AdditionalBeanBuildItem registerBeans() { - // 注册Session相关的Bean - return AdditionalBeanBuildItem.builder() - .addBeanClasses( - "dev.flexmodel.quarkus.session.QuarkusSessionManager", - "dev.flexmodel.quarkus.session.SessionInterceptor", -// "dev.flexmodel.quarkus.session.TransactionalInterceptor", - "dev.flexmodel.quarkus.session.SessionProvider" - ) - .setUnremovable() - .build(); - } -} diff --git a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/QuarkusSessionManager.java b/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/QuarkusSessionManager.java deleted file mode 100644 index c73b2ef7..00000000 --- a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/QuarkusSessionManager.java +++ /dev/null @@ -1,65 +0,0 @@ -package dev.flexmodel.quarkus.session; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import dev.flexmodel.session.Session; -import dev.flexmodel.session.SessionFactory; -import dev.flexmodel.session.SessionManager; - -/** - * Quarkus Session管理器 - * 继承通用SessionManager,集成CDI容器 - * - * 该管理器与上下文传播机制集成,支持在异步操作中自动传递Session状态 - * - * @author cjbi - */ -@ApplicationScoped -public class QuarkusSessionManager extends SessionManager { - - /** - * 构造函数,通过CDI注入SessionFactory - */ - @Inject - public QuarkusSessionManager(SessionFactory sessionFactory) { - super(sessionFactory); - } - - /** - * 获取当前Session(不创建新的) - * 如果当前没有活跃的Session,返回null - * - * @return 当前Session,如果不存在则返回null - */ - public Session getCurrentSessionOrNull() { - String currentSchema = getLastUsedSchema(); - if (currentSchema == null) { - currentSchema = getSessionFactory().getDefaultSchema(); - } - return getSession(currentSchema); -// if (hasActiveSession(currentSchema)) { -// return getSession(currentSchema); -// } -// return null; - } - - /** - * 获取最后使用的schema名称 - * 使用反射访问protected字段 - */ - @SuppressWarnings("unchecked") - private String getLastUsedSchema() { - try { - java.lang.reflect.Field field = SessionManager.class.getDeclaredField("lastUsedSchemaHolder"); - field.setAccessible(true); - ThreadLocal holder = (ThreadLocal) field.get(this); - if (holder != null) { - return holder.get(); - } - } catch (Exception e) { - // 忽略 - } - return null; - } -} - diff --git a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/SessionContext.java b/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/SessionContext.java deleted file mode 100644 index d59c41cd..00000000 --- a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/SessionContext.java +++ /dev/null @@ -1,199 +0,0 @@ -package dev.flexmodel.quarkus.session; - -import dev.flexmodel.session.Session; -import dev.flexmodel.session.SessionManager; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/** - * Session上下文 - * 用于在异步操作中传播Session状态 - * - * 由于Session实例本身可能包含不可序列化的资源(如数据库连接), - * 这里只存储Session的标识符(schema名称),在实际使用时通过 - * SessionManager重新获取Session实例。 - * - * @author cjbi - */ -public class SessionContext implements Serializable { - - private static final long serialVersionUID = 1L; - - /** - * 活跃的Session schema名称集合 - * 每个schema对应一个Session实例 - */ - private final Set activeSchemas; - - /** - * 最近使用的schema名称 - */ - private final String lastUsedSchema; - - /** - * 私有构造函数 - */ - private SessionContext(Set activeSchemas, String lastUsedSchema) { - this.activeSchemas = activeSchemas; - this.lastUsedSchema = lastUsedSchema; - } - - /** - * 从SessionManager创建SessionContext - * - * @param sessionManager Session管理器 - * @return SessionContext实例,如果没有活跃的Session则返回null - */ - public static SessionContext from(SessionManager sessionManager) { - if (sessionManager == null || !sessionManager.hasActiveSession()) { - return null; - } - - // 获取所有活跃的schema名称 - // 注意:这里我们需要访问SessionManager的内部状态 - // 由于SessionManager使用ThreadLocal,我们需要通过反射或者提供一个公开方法 - // 这里我们先假设通过一种方式可以获取到这些信息 - - // 为了简化,我们可以通过尝试获取已知的Session来判断 - // 但更好的方法是让SessionManager提供一个方法来获取所有活跃的schema - Map sessionMap = getSessionMap(sessionManager); - String lastUsedSchema = getLastUsedSchema(sessionManager); - - if (sessionMap == null || sessionMap.isEmpty()) { - return null; - } - - return new SessionContext(sessionMap.keySet(), lastUsedSchema); - } - - /** - * 将SessionContext恢复到SessionManager - * - * @param sessionManager Session管理器 - * @param context SessionContext实例 - */ - public static void restoreTo(SessionManager sessionManager, SessionContext context) { - if (sessionManager == null || context == null) { - return; - } - - // 恢复Session到SessionManager的ThreadLocal中 - // 注意:这里的Session实例需要重新从SessionManager获取,而不是直接使用旧的实例 - // 因为旧的Session实例可能绑定到旧的线程 - - // 对于每个schema,通过SessionManager获取Session(如果不存在会创建) - Map sessionMap = getOrCreateSessionMap(sessionManager); - - for (String schema : context.activeSchemas) { - if (!sessionMap.containsKey(schema)) { - // 重新获取Session(如果已存在则复用,不存在则创建) - sessionManager.getSession(schema); - } - } - - // 恢复lastUsedSchema - if (context.lastUsedSchema != null) { - setLastUsedSchema(sessionManager, context.lastUsedSchema); - } - } - - /** - * 获取活跃的schema集合 - */ - public Set getActiveSchemas() { - return activeSchemas; - } - - /** - * 获取最近使用的schema - */ - public String getLastUsedSchema() { - return lastUsedSchema; - } - - /** - * 检查是否为空 - */ - public boolean isEmpty() { - return activeSchemas == null || activeSchemas.isEmpty(); - } - - /** - * 通过反射或公开方法获取SessionMap - * 这里使用反射访问protected字段,但更好的方法是在SessionManager中添加公开方法 - */ - @SuppressWarnings("unchecked") - private static Map getSessionMap(SessionManager sessionManager) { - try { - java.lang.reflect.Field field = SessionManager.class.getDeclaredField("sessionMapHolder"); - field.setAccessible(true); - ThreadLocal> holder = (ThreadLocal>) field.get(sessionManager); - if (holder != null) { - return holder.get(); - } - } catch (Exception e) { - // 如果反射失败,返回null - } - return null; - } - - /** - * 获取或创建SessionMap - */ - @SuppressWarnings("unchecked") - private static Map getOrCreateSessionMap(SessionManager sessionManager) { - try { - java.lang.reflect.Field field = SessionManager.class.getDeclaredField("sessionMapHolder"); - field.setAccessible(true); - ThreadLocal> holder = (ThreadLocal>) field.get(sessionManager); - if (holder == null) { - return null; - } - Map sessionMap = holder.get(); - if (sessionMap == null) { - sessionMap = new HashMap<>(); - holder.set(sessionMap); - } - return sessionMap; - } catch (Exception e) { - return null; - } - } - - /** - * 获取lastUsedSchema - */ - private static String getLastUsedSchema(SessionManager sessionManager) { - try { - java.lang.reflect.Field field = SessionManager.class.getDeclaredField("lastUsedSchemaHolder"); - field.setAccessible(true); - ThreadLocal holder = (ThreadLocal) field.get(sessionManager); - if (holder != null) { - return holder.get(); - } - } catch (Exception e) { - // 忽略 - } - return null; - } - - /** - * 设置lastUsedSchema - */ - private static void setLastUsedSchema(SessionManager sessionManager, String schema) { - try { - java.lang.reflect.Field field = SessionManager.class.getDeclaredField("lastUsedSchemaHolder"); - field.setAccessible(true); - ThreadLocal holder = (ThreadLocal) field.get(sessionManager); - if (holder != null) { - holder.set(schema); - } - } catch (Exception e) { - // 忽略 - } - } -} - diff --git a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/SessionContextPropagator.java b/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/SessionContextPropagator.java deleted file mode 100644 index a429d931..00000000 --- a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/SessionContextPropagator.java +++ /dev/null @@ -1,130 +0,0 @@ -package dev.flexmodel.quarkus.session; - -import io.quarkus.arc.Arc; -import org.eclipse.microprofile.context.spi.ThreadContextProvider; -import org.eclipse.microprofile.context.spi.ThreadContextSnapshot; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import dev.flexmodel.session.SessionManager; - -import java.util.Map; - -/** - * Session上下文传播器 - * 实现ThreadContextProvider接口,用于在异步操作中自动传播Session状态 - * - * 支持Mutiny、CompletableFuture等异步框架的上下文传播 - * - * 注意:ThreadContextProvider通过SPI机制实例化,不在CDI容器中, - * 因此通过Arc容器动态获取SessionManager实例 - * - * @author cjbi - */ -public class SessionContextPropagator implements ThreadContextProvider { - - private static final Logger log = LoggerFactory.getLogger(SessionContextPropagator.class); - - /** - * 上下文类型名称 - */ - @Override - public String getThreadContextType() { - return "FlexModel-Session"; - } - - /** - * 获取SessionManager实例 - * 通过Arc容器动态获取QuarkusSessionManager实例 - */ - private SessionManager getSessionManager() { - try { - QuarkusSessionManager manager = Arc.container().instance(QuarkusSessionManager.class).get(); - if (manager != null) { - return manager; - } - } catch (Exception e) { - log.debug("Failed to get QuarkusSessionManager from Arc container: {}", e.getMessage()); - } - - // 如果获取失败,尝试获取通用的SessionManager - try { - SessionManager manager = Arc.container().instance(SessionManager.class).get(); - if (manager != null) { - return manager; - } - } catch (Exception e) { - log.debug("Failed to get SessionManager from Arc container: {}", e.getMessage()); - } - - log.warn("No SessionManager found in CDI container, context propagation may not work"); - return null; - } - - /** - * 获取当前线程的上下文快照 - * 在异步操作开始前调用,捕获当前Session状态 - */ - @Override - public ThreadContextSnapshot currentContext(Map props) { - log.debug("Capturing Session context for propagation"); - - SessionManager sessionManager = getSessionManager(); - if (sessionManager == null) { - log.debug("No SessionManager available, returning empty context"); - return () -> { - log.debug("Restoring empty Session context (no SessionManager)"); - // 返回一个空的控制器(无操作) - return () -> {}; - }; - } - - SessionContext context = SessionContext.from(sessionManager); - - if (context == null || context.isEmpty()) { - log.debug("No active Session context to propagate"); - return () -> { - // 空上下文,不做任何操作 - log.debug("Restoring empty Session context"); - // 返回一个空的控制器(无操作) - return () -> {}; - }; - } - - log.debug("Captured Session context with schemas: {}, lastUsed: {}", - context.getActiveSchemas(), context.getLastUsedSchema()); - - // 需要在restore时重新获取SessionManager,因为它可能在不同线程中 - final SessionContext finalContext = context; - return () -> { - log.debug("Restoring Session context with schemas: {}, lastUsed: {}", - finalContext.getActiveSchemas(), finalContext.getLastUsedSchema()); - SessionManager manager = getSessionManager(); - if (manager != null) { - SessionContext.restoreTo(manager, finalContext); - } else { - log.warn("Cannot restore Session context: SessionManager not available"); - } - // 返回一个控制器,用于在上下文结束时清理 - return () -> { - log.debug("Ending Session context propagation"); - // 清理操作(如果需要) - }; - }; - } - - /** - * 获取清理后的上下文(空上下文) - * 在某些场景下,可能需要清除上下文 - */ - @Override - public ThreadContextSnapshot clearedContext(Map props) { - log.debug("Providing cleared Session context"); - return () -> { - // 清理上下文,不做任何操作 - log.debug("Session context cleared"); - // 返回一个空的控制器(无操作) - return () -> {}; - }; - } -} - diff --git a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/SessionInterceptor.java b/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/SessionInterceptor.java deleted file mode 100644 index 168a0950..00000000 --- a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/SessionInterceptor.java +++ /dev/null @@ -1,109 +0,0 @@ -package dev.flexmodel.quarkus.session; - -import io.quarkus.arc.Arc; -import jakarta.annotation.Priority; -import jakarta.inject.Inject; -import jakarta.interceptor.AroundInvoke; -import jakarta.interceptor.Interceptor; -import jakarta.interceptor.InvocationContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Session拦截器 - * 用于在方法执行前创建Session,在方法执行后销毁Session - * - * 该拦截器自动激活RequestContext,确保在异步操作中可以访问CDI Bean - * 支持通过上下文传播机制在异步操作中传递Session状态 - * - * @author cjbi - */ -@Interceptor -@SessionManaged -@Priority(Interceptor.Priority.APPLICATION + 100) -public class SessionInterceptor { - - private static final Logger log = LoggerFactory.getLogger(SessionInterceptor.class); - - @Inject - QuarkusSessionManager sessionManager; - - @AroundInvoke - public Object aroundInvoke(InvocationContext context) throws Exception { - log.debug("Session interceptor starting for method: {}", context.getMethod().getName()); - - // 检查是否已有活跃的Session(嵌套调用场景) - boolean hasActiveSession = sessionManager.hasActiveSession(); - - // 激活RequestContext,确保CDI上下文在异步操作中可用 - var requestContext = Arc.container().requestContext(); - boolean contextWasActive = requestContext.isActive(); - if (!contextWasActive) { - log.debug("Activating RequestContext"); - requestContext.activate(); - } - - try { - // 获取SessionManaged注解 - SessionManaged sessionManaged = context.getMethod().getAnnotation(SessionManaged.class); - if (sessionManaged == null) { - sessionManaged = context.getTarget().getClass().getAnnotation(SessionManaged.class); - } - - String schemaName = null; - if (sessionManaged != null && !sessionManaged.schema().isEmpty()) { - schemaName = sessionManaged.schema(); - } - - // 只有在没有活跃Session时才创建新的Session(避免嵌套调用时重复创建) - if (!hasActiveSession) { - if (schemaName != null) { - log.debug("Creating session for schema: {}", schemaName); - sessionManager.getSession(schemaName); - } else { - log.debug("Creating default session"); - sessionManager.getCurrentSession(); - } - } else { - log.debug("Session already active, reusing existing session"); - // 如果指定了schema但已有Session,确保使用指定的schema - if (schemaName != null) { - sessionManager.getSession(schemaName); - } - } - - // 执行被拦截的方法 - Object result = context.proceed(); - - log.debug("Session interceptor completed successfully for method: {}", context.getMethod().getName()); - return result; - - } catch (Exception e) { - log.error("Session interceptor caught exception for method: {}", context.getMethod().getName(), e); - throw e; - } finally { - // 只有在没有活跃Session的情况下才清理(避免嵌套调用时过早清理) - // 这里我们需要检查当前线程中是否还有其他活跃的Session - // 简化处理:如果这是最外层的调用,清理所有Session - // 更精确的方法需要跟踪嵌套层级,这里先简化 - if (!hasActiveSession) { - log.debug("Closing all sessions after method: {}", context.getMethod().getName()); - sessionManager.closeAllSessions(); - } - - // 如果RequestContext是我们激活的,则取消激活 - if (!contextWasActive) { - var rc = Arc.container().requestContext(); - if (rc.isActive()) { - log.debug("Deactivating RequestContext"); - try { - rc.deactivate(); - } catch (Exception e) { - log.warn("Failed to deactivate RequestContext: {}", e.getMessage()); - } - } - } - } - } -} - diff --git a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/SessionManaged.java b/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/SessionManaged.java deleted file mode 100644 index 9b75c0b4..00000000 --- a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/SessionManaged.java +++ /dev/null @@ -1,30 +0,0 @@ -package dev.flexmodel.quarkus.session; - -import jakarta.interceptor.InterceptorBinding; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * SessionManaged注解 - * 用于标记需要自动Session管理的方法或类 - * - * 该注解会在方法执行前自动创建Session,在方法执行后自动销毁Session - * 支持在异步操作(如Mutiny)中自动传递Session上下文 - * - * @author cjbi - */ -@InterceptorBinding -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface SessionManaged { - - /** - * 指定要使用的模式名称 - * 如果不指定,将使用默认模式 - */ - String schema() default ""; -} - diff --git a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/TransactionalInterceptor.java b/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/TransactionalInterceptor.java deleted file mode 100644 index 6b326e95..00000000 --- a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/TransactionalInterceptor.java +++ /dev/null @@ -1,94 +0,0 @@ -//package dev.flexmodel.quarkus.session; -// -//import jakarta.annotation.Priority; -//import jakarta.inject.Inject; -//import jakarta.interceptor.AroundInvoke; -//import jakarta.interceptor.Interceptor; -//import jakarta.interceptor.InvocationContext; -//import jakarta.transaction.Transactional; -//import org.slf4j.Logger; -//import org.slf4j.LoggerFactory; -//import dev.flexmodel.session.Session; -// -///** -// * 事务拦截器 -// * 用于自动管理事务的生命周期 -// * -// * 该拦截器会在方法执行前开启事务,在方法正常返回时提交事务, -// * 在方法抛出异常时回滚事务 -// * -// * 注意: -// * 1. 使用此注解的方法必须同时使用@SessionManaged注解 -// * 2. TransactionalInterceptor的优先级应该低于SessionInterceptor, -// * 确保Session已经创建 -// * -// * @author cjbi -// */ -//@Interceptor -//@Transactional -//@Priority(Interceptor.Priority.APPLICATION + 50) -//public class TransactionalInterceptor { -// -// private static final Logger log = LoggerFactory.getLogger(TransactionalInterceptor.class); -// -// @Inject -// QuarkusSessionManager sessionManager; -// -// @AroundInvoke -// public Object aroundInvoke(InvocationContext context) throws Exception { -// log.debug("Transactional interceptor starting for method: {}", context.getMethod().getName()); -// -// // 获取Transactional注解 -// Transactional transactional = context.getMethod().getAnnotation(Transactional.class); -// if (transactional == null) { -// transactional = context.getTarget().getClass().getAnnotation(Transactional.class); -// } -// -// // 获取当前Session(应该已经由SessionInterceptor创建) -// Session session = sessionManager.getCurrentSessionOrNull(); -// if (session == null || session.isClosed()) { -// return context.proceed(); -// } -//// if (session == null) { -//// throw new IllegalStateException( -//// "No active Session found. Please ensure @SessionManaged annotation is present on the method or class."); -//// } -//// if (session.isClosed()) { -//// throw new IllegalStateException("Session is closed. Please ensure @SessionManaged annotation is present on the method or class."); -//// } -// // 检查是否已有活跃的事务(嵌套调用场景) -// // 注意:这里简化处理,假设Session的状态可以告诉我们是否有活跃事务 -// // 更精确的方法需要跟踪事务状态 -// boolean transactionStarted = false; -// try { -// // 开启事务 -// log.debug("Starting transaction for method: {}", context.getMethod().getName()); -// session.startTransaction(); -// transactionStarted = true; -// -// // 执行被拦截的方法 -// Object result = context.proceed(); -// -// // 提交事务 -// log.debug("Committing transaction for method: {}", context.getMethod().getName()); -// session.commit(); -// -// log.debug("Transactional interceptor completed successfully for method: {}", context.getMethod().getName()); -// return result; -// -// } catch (Exception e) { -// // 回滚事务 -// if (transactionStarted) { -// log.error("Rolling back transaction due to exception in method: {}", context.getMethod().getName(), e); -// try { -// session.rollback(); -// } catch (Exception rollbackException) { -// log.error("Failed to rollback transaction", rollbackException); -// // 不掩盖原始异常 -// } -// } -// throw e; -// } -// } -//} -// diff --git a/flexmodel-engine/flexmodel-quarkus/src/main/resources/META-INF/services/org.eclipse.microprofile.context.spi.ThreadContextProvider b/flexmodel-engine/flexmodel-quarkus/src/main/resources/META-INF/services/org.eclipse.microprofile.context.spi.ThreadContextProvider deleted file mode 100644 index 2083bacb..00000000 --- a/flexmodel-engine/flexmodel-quarkus/src/main/resources/META-INF/services/org.eclipse.microprofile.context.spi.ThreadContextProvider +++ /dev/null @@ -1,2 +0,0 @@ -dev.flexmodel.quarkus.session.SessionContextPropagator - diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/.gitignore b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/.gitignore deleted file mode 100644 index 91a800a1..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/.gitignore +++ /dev/null @@ -1,45 +0,0 @@ -#Maven -target/ -pom.xml.tag -pom.xml.releaseBackup -pom.xml.versionsBackup -release.properties -.flattened-pom.xml - -# Eclipse -.project -.classpath -.settings/ -bin/ - -# IntelliJ -.idea -*.ipr -*.iml -*.iws - -# NetBeans -nb-configuration.xml - -# Visual Studio Code -.vscode -.factorypath - -# OSX -.DS_Store - -# Vim -*.swp -*.swo - -# patch -*.orig -*.rej - -# Local environment -.env - -# Plugin directory -/.quarkus/cli/plugins/ -# TLS Certificates -.certs/ diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/.mvn/wrapper/.gitignore b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/.mvn/wrapper/.gitignore deleted file mode 100644 index e72f5e8b..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/.mvn/wrapper/.gitignore +++ /dev/null @@ -1 +0,0 @@ -maven-wrapper.jar diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/.mvn/wrapper/MavenWrapperDownloader.java b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index 84d1e60d..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.io.InputStream; -import java.net.Authenticator; -import java.net.PasswordAuthentication; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; - -public final class MavenWrapperDownloader -{ - private static final String WRAPPER_VERSION = "3.2.0"; - - private static final boolean VERBOSE = Boolean.parseBoolean( System.getenv( "MVNW_VERBOSE" ) ); - - public static void main( String[] args ) - { - log( "Apache Maven Wrapper Downloader " + WRAPPER_VERSION ); - - if ( args.length != 2 ) - { - System.err.println( " - ERROR wrapperUrl or wrapperJarPath parameter missing" ); - System.exit( 1 ); - } - - try - { - log( " - Downloader started" ); - final URL wrapperUrl = new URL( args[0] ); - final String jarPath = args[1].replace( "..", "" ); // Sanitize path - final Path wrapperJarPath = Paths.get( jarPath ).toAbsolutePath().normalize(); - downloadFileFromURL( wrapperUrl, wrapperJarPath ); - log( "Done" ); - } - catch ( IOException e ) - { - System.err.println( "- Error downloading: " + e.getMessage() ); - if ( VERBOSE ) - { - e.printStackTrace(); - } - System.exit( 1 ); - } - } - - private static void downloadFileFromURL( URL wrapperUrl, Path wrapperJarPath ) - throws IOException - { - log( " - Downloading to: " + wrapperJarPath ); - if ( System.getenv( "MVNW_USERNAME" ) != null && System.getenv( "MVNW_PASSWORD" ) != null ) - { - final String username = System.getenv( "MVNW_USERNAME" ); - final char[] password = System.getenv( "MVNW_PASSWORD" ).toCharArray(); - Authenticator.setDefault( new Authenticator() - { - @Override - protected PasswordAuthentication getPasswordAuthentication() - { - return new PasswordAuthentication( username, password ); - } - } ); - } - try ( InputStream inStream = wrapperUrl.openStream() ) - { - Files.copy( inStream, wrapperJarPath, StandardCopyOption.REPLACE_EXISTING ); - } - log( " - Downloader complete" ); - } - - private static void log( String msg ) - { - if ( VERBOSE ) - { - System.out.println( msg ); - } - } - -} diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/.mvn/wrapper/maven-wrapper.properties b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 10cbcb5e..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.8/apache-maven-3.9.8-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/README.md b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/README.md deleted file mode 100644 index cdc1393c..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/README.md +++ /dev/null @@ -1,301 +0,0 @@ -# FlexModel Quarkus 集成 - -这个模块提供了FlexModel与Quarkus框架的集成,实现了自动的Session生命周期管理。 - -## 功能特性 - -- **自动Session管理**: 在请求开始时自动创建Session,在请求结束时自动销毁Session -- **事务支持**: 支持手动事务管理(开始、提交、回滚) -- **CDI集成**: 通过CDI容器提供Session实例 -- **拦截器支持**: 使用注解标记需要Session管理的方法 - -## 核心组件 - -### 1. SessionManager (flexmodel-core) - -通用的Session管理器,使用ThreadLocal存储Session实例。 - -```java -public class SessionManager { - // 获取当前请求的Session - public Session getSession(String schemaName); - - public Session getSession(); // 使用默认模式 - - // 关闭当前请求的Session - public void closeSession(); - - // 检查Session状态 - public boolean hasActiveSession(); - - public Session getCurrentSession(); -} -``` - -### 2. QuarkusSessionManager - -Quarkus特定的Session管理器,继承自SessionManager,集成CDI容器。 - -```java - -@ApplicationScoped -public class QuarkusSessionManager extends SessionManager { - @Inject - public QuarkusSessionManager(SessionFactory sessionFactory) { - super(sessionFactory); - } -} -``` - -### 2. SessionManaged 注解 - -用于标记需要自动Session管理的方法或类。 - -```java -@SessionManaged // 类级别,所有方法都会自动管理Session -public class UserResource { - - @SessionManaged(schema = "custom") // 方法级别,指定模式 - public Response createUser() { - // 方法执行时会自动创建Session,执行完成后自动销毁 - } -} -``` - -### 3. SessionInterceptor - -拦截器,负责在方法执行前后管理Session生命周期。 - -### 4. SessionProvider - -CDI提供者,用于在容器中提供Session实例。 - -## 使用方法 - -### 1. 配置SessionFactory和SessionManager - -在应用启动时配置SessionFactory和SessionManager: - -```java - -@ApplicationScoped -public class SessionConfig { - - @Produces - @ApplicationScoped - public SessionFactory sessionFactory() { - HikariDataSource dataSource = new HikariDataSource(); - dataSource.setJdbcUrl("jdbc:sqlite:file::memory:?cache=shared"); - - return SessionFactory.builder() - .setDefaultDataSourceProvider(new JdbcDataSourceProvider("system", dataSource)) - .build(); - } - - // 可选:配置通用的SessionManager - @Produces - @ApplicationScoped - public SessionManager sessionManager(SessionFactory sessionFactory) { - return new SessionManager(sessionFactory); - } -} -``` - -### 2. 在REST资源中使用 - -```java - -@Path("/users") -@Produces(MediaType.APPLICATION_JSON) -@SessionManaged // 类级别Session管理 -public class UserResource { - - @Inject - private Session session; // 自动注入当前请求的Session - - @GET - public Response getAllUsers() { - // Session已自动创建 - List> users = session.data().find("users", Query.Builder.create().build()); - return Response.ok(users).build(); - // 方法结束时Session自动销毁 - } - - @POST - @SessionManaged(schema = "custom") // 方法级别,指定模式 - public Response createUser(Map userData) { - // 手动事务管理 - session.startTransaction(); - try { - int affectedRows = session.data().insert("users", userData); - session.commit(); - return Response.status(Response.Status.CREATED).build(); - } catch (Exception e) { - session.rollback(); - throw e; - } - } -} -``` - -### 3. 在服务类中使用 - -```java - -@ApplicationScoped -@SessionManaged -public class UserService { - - @Inject - private Session session; - - public List> getAllUsers() { - return session.data().find("users", Query.Builder.create().build()); - } - - public Map getUserById(String id) { - return session.data().findById("users", id); - } - - public Map createUser(Map userData) { - session.startTransaction(); - try { - int affectedRows = session.data().insert("users", userData); - session.commit(); - - Map result = new HashMap<>(); - result.put("message", "User created successfully"); - result.put("affectedRows", affectedRows); - return result; - } catch (Exception e) { - session.rollback(); - throw new RuntimeException("Failed to create user", e); - } - } -} -``` - -### 4. 在REST资源中使用服务层 - -```java - -@Path("/users") -@Produces(MediaType.APPLICATION_JSON) -@SessionManaged -public class UserResource { - - @Inject - private UserService userService; - - @GET - public Response getAllUsers() { - try { - List> users = userService.getAllUsers(); - return Response.ok(users).build(); - } catch (Exception e) { - return Response.serverError().entity("Error getting users: " + e.getMessage()).build(); - } - } - - @POST - public Response createUser(Map userData) { - try { - Map result = userService.createUser(userData); - return Response.status(Response.Status.CREATED).entity(result).build(); - } catch (Exception e) { - return Response.serverError().entity("Error creating user: " + e.getMessage()).build(); - } - } -} -``` - -## 事务管理 - -Session支持手动事务管理: - -```java -@SessionManaged -public class TransactionalService { - - @Inject - private Session session; - - public void performTransactionalOperation() { - session.startTransaction(); - try { - // 执行多个操作 - session.data().insert("users", user1); - session.data().insert("users", user2); - - session.commit(); // 提交事务 - } catch (Exception e) { - session.rollback(); // 回滚事务 - throw e; - } - } -} -``` - -## 配置选项 - -### 1. 默认模式 - -如果不指定模式,系统会使用第一个可用的模式作为默认值: - -```java -@SessionManaged // 使用默认模式 -public class DefaultSchemaService { - // ... -} -``` - -### 2. 指定模式 - -可以通过注解参数指定特定的模式: - -```java -@SessionManaged(schema = "user_schema") -public class UserSchemaService { - // ... -} -``` - -### 3. 方法级别覆盖 - -方法级别的注解会覆盖类级别的设置: - -```java -@SessionManaged(schema = "default") -public class MultiSchemaService { - - @SessionManaged(schema = "user_schema") // 覆盖类级别的设置 - public void userOperation() { - // 使用user_schema模式 - } - - public void defaultOperation() { - // 使用类级别的default模式 - } -} -``` - -## 最佳实践 - -1. **使用注解**: 优先使用`@SessionManaged`注解而不是手动管理Session -2. **继承设计**: 通过继承通用的SessionManager来复用代码,避免重复实现 -3. **分层架构**: 使用服务层封装业务逻辑,资源层处理HTTP请求 -4. **事务边界**: 在需要事务的方法中明确管理事务边界 -5. **异常处理**: 在事务操作中正确处理异常并回滚事务 -6. **资源清理**: 拦截器会自动清理Session,无需手动关闭 -7. **模式管理**: 合理规划和使用不同的数据模式 - -## 注意事项 - -1. Session是线程安全的,每个请求都有独立的Session实例 -2. 拦截器会自动处理Session的创建和销毁,避免内存泄漏 -3. 事务必须在同一个Session实例中完成 -4. 异常情况下Session会自动关闭,确保资源释放 - -## 示例项目 - -完整的示例代码请参考 `UserResource.java` 文件,展示了完整的CRUD操作和事务管理。 diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/mvnw b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/mvnw deleted file mode 100644 index 8d937f4c..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/mvnw +++ /dev/null @@ -1,308 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.2.0 -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "$(uname)" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME - else - JAVA_HOME="/Library/Java/Home"; export JAVA_HOME - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=$(java-config --jre-home) - fi -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --unix "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --unix "$CLASSPATH") -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && - JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="$(which javac)" - if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=$(which readlink) - if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then - if $darwin ; then - javaHome="$(dirname "\"$javaExecutable\"")" - javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" - else - javaExecutable="$(readlink -f "\"$javaExecutable\"")" - fi - javaHome="$(dirname "\"$javaExecutable\"")" - javaHome=$(expr "$javaHome" : '\(.*\)/bin') - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=$(cd "$wdir/.." || exit 1; pwd) - fi - # end of workaround - done - printf '%s' "$(cd "$basedir" || exit 1; pwd)" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - # Remove \r in case we run on Windows within Git Bash - # and check out the repository with auto CRLF management - # enabled. Otherwise, we may read lines that are delimited with - # \r\n and produce $'-Xarg\r' rather than -Xarg due to word - # splitting rules. - tr -s '\r\n' ' ' < "$1" - fi -} - -log() { - if [ "$MVNW_VERBOSE" = true ]; then - printf '%s\n' "$1" - fi -} - -BASE_DIR=$(find_maven_basedir "$(dirname "$0")") -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR -log "$MAVEN_PROJECTBASEDIR" - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" -if [ -r "$wrapperJarPath" ]; then - log "Found $wrapperJarPath" -else - log "Couldn't find $wrapperJarPath, downloading it ..." - - if [ -n "$MVNW_REPOURL" ]; then - wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - else - wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - fi - while IFS="=" read -r key value; do - # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) - safeValue=$(echo "$value" | tr -d '\r') - case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; - esac - done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" - log "Downloading from: $wrapperUrl" - - if $cygwin; then - wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") - fi - - if command -v wget > /dev/null; then - log "Found wget ... using wget" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - log "Found curl ... using curl" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - else - curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - fi - else - log "Falling back to using Java to download" - javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" - javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaSource=$(cygpath --path --windows "$javaSource") - javaClass=$(cygpath --path --windows "$javaClass") - fi - if [ -e "$javaSource" ]; then - if [ ! -e "$javaClass" ]; then - log " - Compiling MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/javac" "$javaSource") - fi - if [ -e "$javaClass" ]; then - log " - Running MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -# If specified, validate the SHA-256 sum of the Maven wrapper jar file -wrapperSha256Sum="" -while IFS="=" read -r key value; do - case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; - esac -done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" -if [ -n "$wrapperSha256Sum" ]; then - wrapperSha256Result=false - if command -v sha256sum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then - wrapperSha256Result=true - fi - elif command -v shasum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then - wrapperSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." - echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." - exit 1 - fi - if [ $wrapperSha256Result = false ]; then - echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 - echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 - echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 - exit 1 - fi -fi - -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --windows "$CLASSPATH") - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -# shellcheck disable=SC2086 # safe args -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/mvnw.cmd b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/mvnw.cmd deleted file mode 100644 index c4586b56..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/mvnw.cmd +++ /dev/null @@ -1,205 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.2.0 -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %WRAPPER_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file -SET WRAPPER_SHA_256_SUM="" -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B -) -IF NOT %WRAPPER_SHA_256_SUM%=="" ( - powershell -Command "&{"^ - "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ - "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ - " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ - " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ - " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ - " exit 1;"^ - "}"^ - "}" - if ERRORLEVEL 1 goto error -) - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/pom.xml b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/pom.xml deleted file mode 100644 index 56c1521f..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/pom.xml +++ /dev/null @@ -1,192 +0,0 @@ - - - 4.0.0 - - dev.flexmodel - flexmodel-integration-tests - 0.0.1-SNAPSHOT - - flexmodel-quarkus-it - - - 3.13.0 - 21 - UTF-8 - UTF-8 - quarkus-bom - io.quarkus.platform - 3.13.2 - true - 3.2.5 - - - - - - - ${quarkus.platform.group-id} - ${quarkus.platform.artifact-id} - ${quarkus.platform.version} - pom - import - - - - - - - com.zaxxer - HikariCP - compile - - - dev.flexmodel - flexmodel-core - ${project.version} - - - dev.flexmodel - flexmodel-codegen - ${project.version} - - - dev.flexmodel - flexmodel-quarkus - ${project.version} - - - io.quarkus - quarkus-arc - - - io.smallrye - smallrye-context-propagation - - - io.quarkus - quarkus-rest - - - io.quarkus - quarkus-rest-jackson - - - io.quarkus - quarkus-junit5 - test - - - io.rest-assured - rest-assured - test - - - org.xerial - sqlite-jdbc - - - - - - - dev.flexmodel - flexmodel-maven-plugin - ${project.version} - - - org.xerial - sqlite-jdbc - ${sqlite-jdbc.version} - - - - - generate-sources - - generate - - - - - - - - system - src/main/resources/import.idl - dev.flexmodel - - - - - - - ${quarkus.platform.group-id} - quarkus-maven-plugin - ${quarkus.platform.version} - true - - - - build - generate-code - generate-code-tests - native-image-agent - - - - - - maven-compiler-plugin - ${compiler-plugin.version} - - true - - - - maven-surefire-plugin - ${surefire-plugin.version} - - - org.jboss.logmanager.LogManager - ${maven.home} - - - - - maven-failsafe-plugin - ${surefire-plugin.version} - - - - integration-test - verify - - - - - - ${project.build.directory}/${project.build.finalName}-runner - org.jboss.logmanager.LogManager - ${maven.home} - - - - - - - - - native - - - native - - - - false - true - - - - diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/docker/Dockerfile.jvm b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/docker/Dockerfile.jvm deleted file mode 100644 index 46066833..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/docker/Dockerfile.jvm +++ /dev/null @@ -1,97 +0,0 @@ -#### -# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode -# -# Before building the container image run: -# -# ./mvnw package -# -# Then, build the image with: -# -# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/flexmodel-quarkus-it-jvm . -# -# Then run the container using: -# -# docker run -i --rm -p 8080:8080 quarkus/flexmodel-quarkus-it-jvm -# -# If you want to include the debug port into your docker image -# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005. -# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005 -# when running the container -# -# Then run the container using : -# -# docker run -i --rm -p 8080:8080 quarkus/flexmodel-quarkus-it-jvm -# -# This image uses the `run-java.sh` script to run the application. -# This scripts computes the command line to execute your Java application, and -# includes memory/GC tuning. -# You can configure the behavior using the following environment properties: -# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") -# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options -# in JAVA_OPTS (example: "-Dsome.property=foo") -# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is -# used to calculate a default maximal heap memory based on a containers restriction. -# If used in a container without any memory constraints for the container then this -# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio -# of the container available memory as set here. The default is `50` which means 50% -# of the available memory is used as an upper boundary. You can skip this mechanism by -# setting this value to `0` in which case no `-Xmx` option is added. -# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This -# is used to calculate a default initial heap memory based on the maximum heap memory. -# If used in a container without any memory constraints for the container then this -# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio -# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx` -# is used as the initial heap size. You can skip this mechanism by setting this value -# to `0` in which case no `-Xms` option is added (example: "25") -# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS. -# This is used to calculate the maximum value of the initial heap memory. If used in -# a container without any memory constraints for the container then this option has -# no effect. If there is a memory constraint then `-Xms` is limited to the value set -# here. The default is 4096MB which means the calculated value of `-Xms` never will -# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096") -# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output -# when things are happening. This option, if set to true, will set -# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true"). -# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example: -# true"). -# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787"). -# - CONTAINER_CORE_LIMIT: A calculated core limit as described in -# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2") -# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024"). -# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion. -# (example: "20") -# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking. -# (example: "40") -# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection. -# (example: "4") -# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus -# previous GC times. (example: "90") -# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20") -# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100") -# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should -# contain the necessary JRE command-line options to specify the required GC, which -# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC). -# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080") -# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080") -# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be -# accessed directly. (example: "foo.example.com,bar.example.com") -# -### -FROM registry.access.redhat.com/ubi8/openjdk-21:1.19 - -ENV LANGUAGE='en_US:en' - - -# We make four distinct layers so if there are application changes the library layers can be re-used -COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/ -COPY --chown=185 target/quarkus-app/*.jar /deployments/ -COPY --chown=185 target/quarkus-app/app/ /deployments/app/ -COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/ - -EXPOSE 8080 -USER 185 -ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" -ENV JAVA_APP_JAR="/deployments/quarkus-run.jar" - -ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ] - diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/docker/Dockerfile.legacy-jar b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/docker/Dockerfile.legacy-jar deleted file mode 100644 index 1ad66972..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/docker/Dockerfile.legacy-jar +++ /dev/null @@ -1,93 +0,0 @@ -#### -# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode -# -# Before building the container image run: -# -# ./mvnw package -Dquarkus.package.jar.type=legacy-jar -# -# Then, build the image with: -# -# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/flexmodel-quarkus-it-legacy-jar . -# -# Then run the container using: -# -# docker run -i --rm -p 8080:8080 quarkus/flexmodel-quarkus-it-legacy-jar -# -# If you want to include the debug port into your docker image -# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005. -# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005 -# when running the container -# -# Then run the container using : -# -# docker run -i --rm -p 8080:8080 quarkus/flexmodel-quarkus-it-legacy-jar -# -# This image uses the `run-java.sh` script to run the application. -# This scripts computes the command line to execute your Java application, and -# includes memory/GC tuning. -# You can configure the behavior using the following environment properties: -# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") -# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options -# in JAVA_OPTS (example: "-Dsome.property=foo") -# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is -# used to calculate a default maximal heap memory based on a containers restriction. -# If used in a container without any memory constraints for the container then this -# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio -# of the container available memory as set here. The default is `50` which means 50% -# of the available memory is used as an upper boundary. You can skip this mechanism by -# setting this value to `0` in which case no `-Xmx` option is added. -# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This -# is used to calculate a default initial heap memory based on the maximum heap memory. -# If used in a container without any memory constraints for the container then this -# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio -# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx` -# is used as the initial heap size. You can skip this mechanism by setting this value -# to `0` in which case no `-Xms` option is added (example: "25") -# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS. -# This is used to calculate the maximum value of the initial heap memory. If used in -# a container without any memory constraints for the container then this option has -# no effect. If there is a memory constraint then `-Xms` is limited to the value set -# here. The default is 4096MB which means the calculated value of `-Xms` never will -# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096") -# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output -# when things are happening. This option, if set to true, will set -# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true"). -# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example: -# true"). -# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787"). -# - CONTAINER_CORE_LIMIT: A calculated core limit as described in -# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2") -# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024"). -# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion. -# (example: "20") -# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking. -# (example: "40") -# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection. -# (example: "4") -# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus -# previous GC times. (example: "90") -# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20") -# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100") -# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should -# contain the necessary JRE command-line options to specify the required GC, which -# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC). -# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080") -# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080") -# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be -# accessed directly. (example: "foo.example.com,bar.example.com") -# -### -FROM registry.access.redhat.com/ubi8/openjdk-21:1.19 - -ENV LANGUAGE='en_US:en' - - -COPY target/lib/* /deployments/lib/ -COPY target/*-runner.jar /deployments/quarkus-run.jar - -EXPOSE 8080 -USER 185 -ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" -ENV JAVA_APP_JAR="/deployments/quarkus-run.jar" - -ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ] diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/docker/Dockerfile.native b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/docker/Dockerfile.native deleted file mode 100644 index c58b9a23..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/docker/Dockerfile.native +++ /dev/null @@ -1,27 +0,0 @@ -#### -# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode. -# -# Before building the container image run: -# -# ./mvnw package -Dnative -# -# Then, build the image with: -# -# docker build -f src/main/docker/Dockerfile.native -t quarkus/flexmodel-quarkus-it . -# -# Then run the container using: -# -# docker run -i --rm -p 8080:8080 quarkus/flexmodel-quarkus-it -# -### -FROM registry.access.redhat.com/ubi8/ubi-minimal:8.9 -WORKDIR /work/ -RUN chown 1001 /work \ - && chmod "g+rwX" /work \ - && chown 1001:root /work -COPY --chown=1001:root target/*-runner /work/application - -EXPOSE 8080 -USER 1001 - -ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/docker/Dockerfile.native-micro b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/docker/Dockerfile.native-micro deleted file mode 100644 index 4c01fcbc..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/docker/Dockerfile.native-micro +++ /dev/null @@ -1,30 +0,0 @@ -#### -# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode. -# It uses a micro base image, tuned for Quarkus native executables. -# It reduces the size of the resulting container image. -# Check https://quarkus.io/guides/quarkus-runtime-base-image for further information about this image. -# -# Before building the container image run: -# -# ./mvnw package -Dnative -# -# Then, build the image with: -# -# docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/flexmodel-quarkus-it . -# -# Then run the container using: -# -# docker run -i --rm -p 8080:8080 quarkus/flexmodel-quarkus-it -# -### -FROM quay.io/quarkus/quarkus-micro-image:2.0 -WORKDIR /work/ -RUN chown 1001 /work \ - && chmod "g+rwX" /work \ - && chown 1001:root /work -COPY --chown=1001:root target/*-runner /work/application - -EXPOSE 8080 -USER 1001 - -ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/java/dev/flexmodel/quarkus/config/SessionConfig.java b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/java/dev/flexmodel/quarkus/config/SessionConfig.java deleted file mode 100644 index 8b75fa9a..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/java/dev/flexmodel/quarkus/config/SessionConfig.java +++ /dev/null @@ -1,36 +0,0 @@ -package dev.flexmodel.quarkus.config; - -import com.zaxxer.hikari.HikariDataSource; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; -import dev.flexmodel.session.SessionFactory; -import dev.flexmodel.session.SessionManager; -import dev.flexmodel.sql.JdbcSchemaProvider; - -/** - * Session配置类 - * 配置SessionFactory和SessionManager - * - * @author cjbi - */ -@ApplicationScoped -public class SessionConfig { - - @Produces - @ApplicationScoped - public SessionFactory sessionFactory() { - HikariDataSource dataSource = new HikariDataSource(); - dataSource.setMaxLifetime(30000); - dataSource.setJdbcUrl("jdbc:sqlite:file::memory:?cache=shared"); - - return SessionFactory.builder() - .setDefaultSchemaProvider(new JdbcSchemaProvider("system", dataSource)) - .build(); - } - - @Produces - @ApplicationScoped - public SessionManager sessionManager(SessionFactory sessionFactory) { - return new SessionManager(sessionFactory); - } -} diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/java/dev/flexmodel/quarkus/resource/GreetingResource.java b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/java/dev/flexmodel/quarkus/resource/GreetingResource.java deleted file mode 100644 index 8ade3f5e..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/java/dev/flexmodel/quarkus/resource/GreetingResource.java +++ /dev/null @@ -1,18 +0,0 @@ -package dev.flexmodel.quarkus.resource; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import dev.flexmodel.quarkus.session.SessionManaged; - -@Path("/hello") -@SessionManaged -public class GreetingResource { - - @GET - @Produces(MediaType.TEXT_PLAIN) - public String hello() { - return "Hello from Quarkus REST"; - } -} diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/java/dev/flexmodel/quarkus/resource/UserResource.java b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/java/dev/flexmodel/quarkus/resource/UserResource.java deleted file mode 100644 index 6a5172d1..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/java/dev/flexmodel/quarkus/resource/UserResource.java +++ /dev/null @@ -1,108 +0,0 @@ -package dev.flexmodel.quarkus.resource; - -import io.smallrye.mutiny.Uni; -import jakarta.inject.Inject; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import dev.flexmodel.entity.FsUser; -import dev.flexmodel.quarkus.service.UserService; - -import java.util.List; -import java.util.Map; - -/** - * 用户资源示例 - * 展示如何使用Session管理系统 - * - * @author cjbi - */ -@Path("/users") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class UserResource { - - private static final Logger log = LoggerFactory.getLogger(UserResource.class); - - @Inject - UserService userService; - - /** - * 获取所有用户 - */ - @GET - public Uni>> getAllUsers() { - try { - return userService.getAllUsers(); - } catch (Exception e) { - log.error("Error getting users", e); - return Uni.createFrom().failure(e); - } - } - - /** - * 根据ID获取用户 - */ - @GET - @Path("/{id}") - public Response getUserById(@PathParam("id") String id) { - try { - Map user = userService.getUserById(id); - - if (user == null) { - return Response.status(Response.Status.NOT_FOUND).entity("User not found").build(); - } - - return Response.ok(user).build(); - } catch (Exception e) { - log.error("Error getting user by id: {}", id, e); - return Response.serverError().entity("Error getting user: " + e.getMessage()).build(); - } - } - - /** - * 创建新用户 - */ - @POST - public Response createUser(FsUser userData) { - try { - Map result = userService.createUser(userData); - return Response.status(Response.Status.CREATED).entity(result).build(); - } catch (Exception e) { - log.error("Error creating user", e); - return Response.serverError().entity("Error creating user: " + e.getMessage()).build(); - } - } - - /** - * 更新用户 - */ - @PUT - @Path("/{id}") - public Response updateUser(@PathParam("id") String id, FsUser userData) { - try { - Map result = userService.updateUser(id, userData); - return Response.ok(result).build(); - } catch (Exception e) { - log.error("Error updating user with id: {}", id, e); - return Response.serverError().entity("Error updating user: " + e.getMessage()).build(); - } - } - - /** - * 删除用户 - */ - @DELETE - @Path("/{id}") - public Response deleteUser(@PathParam("id") String id) { - try { - Map result = userService.deleteUser(id); - return Response.ok(result).build(); - } catch (Exception e) { - log.error("Error deleting user with id: {}", id, e); - return Response.serverError().entity("Error deleting user: " + e.getMessage()).build(); - } - } -} diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/java/dev/flexmodel/quarkus/service/UserService.java b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/java/dev/flexmodel/quarkus/service/UserService.java deleted file mode 100644 index a92c2d69..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/java/dev/flexmodel/quarkus/service/UserService.java +++ /dev/null @@ -1,96 +0,0 @@ -package dev.flexmodel.quarkus.service; - -import io.smallrye.mutiny.Uni; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.transaction.Transactional; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import dev.flexmodel.entity.FsUser; -import dev.flexmodel.quarkus.session.SessionManaged; -import dev.flexmodel.query.Query; -import dev.flexmodel.session.Session; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 用户服务示例 - * 展示如何使用新的@SessionManaged和@Transactional注解 - * - * @author cjbi - */ -@ApplicationScoped -@SessionManaged -public class UserService { - - private static final Logger log = LoggerFactory.getLogger(UserService.class); - - @Inject - Session session; - - /** - * 获取所有用户 - */ - public Uni>> getAllUsers() { - log.info("Getting all users using session: {}", session.getName()); - return Uni.createFrom().item(session.data().find("fs_user", Query.Builder.create().build())); - } - - /** - * 根据ID获取用户 - */ - public Map getUserById(String id) { - log.info("Getting user by id: {} using session: {}", id, session.getName()); - return session.data().findById("fs_user", id); - } - - /** - * 创建用户(使用@Transactional自动管理事务) - */ - @Transactional - public Map createUser(FsUser userData) { - log.info("Creating user using session: {}", session.getName()); - - int affectedRows = session.dsl().insertInto(FsUser.class).values(userData).execute(); - - Map result = new HashMap<>(); - result.put("message", "User created successfully"); - result.put("affectedRows", affectedRows); - result.put("user", userData); - return result; - } - - /** - * 更新用户(使用@Transactional自动管理事务) - */ - @Transactional - public Map updateUser(String id, FsUser userData) { - log.info("Updating user with id: {} using session: {}", id, session.getName()); - - int affectedRows = session.dsl().update(FsUser.class).values(userData).whereId(id).execute(); - - Map result = new HashMap<>(); - result.put("message", "User updated successfully"); - result.put("id", id); - result.put("affectedRows", affectedRows); - return result; - } - - /** - * 删除用户(使用@Transactional自动管理事务) - */ - @Transactional - public Map deleteUser(String id) { - log.info("Deleting user with id: {} using session: {}", id, session.getName()); - - int affectedRows = session.data().deleteById("fs_user", id); - - Map result = new HashMap<>(); - result.put("message", "User deleted successfully"); - result.put("id", id); - result.put("affectedRows", affectedRows); - return result; - } -} diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/resources/application.properties b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/resources/application.properties deleted file mode 100644 index e69de29b..00000000 diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/resources/import.idl b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/resources/import.idl deleted file mode 100644 index 807bef04..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/main/resources/import.idl +++ /dev/null @@ -1,124 +0,0 @@ -model fs_datasource { - name : String @id, - type? : DatasourceType, - config? : JSON, - createdAt? : DateTime @default(now()), - updatedAt? : DateTime @default(now()), - enabled : Boolean @comment("数据源") @default("true"), -} -model fs_api_definition { - id : String @id @unique @default(uuid()), - name : String @length("255"), - parentId? : String @length("255"), - type : ApiType, - method? : String @length("255"), - path? : String @length("255"), - createdAt : DateTime @default(now()), - updatedAt : DateTime @default(now()), - meta? : JSON, - enabled : Boolean @comment("是否开启") @default("true"), -} -//model fs_api_log { -// id : String @id @default(uuid()), -// level : LogLevel, -// uri : String @length("2000"), -// data : JSON, -// createdAt : DateTime @default(now()), -// @index(unique: "false", fields: [level]), -//} -model fs_api_request_log { - id : String @id @default(uuid()), - url : String @length("2000") @comment("请求地址"), - http_method: String @length("255") @comment("请求方法"), - path: String @length("1000") @comment("请求路径"), - request_body : JSON @comment("请求参数"), - request_headers: JSON @comment("请求头"), - status_code : Int, - response_time : Int, - client_ip?: String @length("45") @comment("IP地址"), - created_at : DateTime @default(now()), - is_success: Boolean @comment("是否成功") @default("true"), - error_message? : JSON @comment("异常信息"), - @index(fields: [created_at]), - @index(fields: [is_error]), - @index(fields: [endpoint, created_at]), - @index(fields: [status_code, created_at]) -} -model fs_identity_provider { - name : String @id, - createdAt : DateTime @default(now()), - provider? : JSON, - updatedAt : DateTime @default(now()), -} -model fs_config { - id : String @id @unique @default(uuid()), - key : String @comment("名称") @length("255"), - value? : String @length("255"), - createdAt : DateTime @default(now()), - updatedAt : DateTime @default(now()), - @comment("配置"), - @index(name:"IDX_CONFIG_KEY", unique: "true", fields: [key]), -} -model Teacher { - id : Long @id @default(autoIncrement()), - teacherName? : String @length("255"), - subject? : String @length("255"), -} -model Student { - id : Long @id @default(autoIncrement()), - studentName? : String @length("255"), - gender? : UserGender, - interest? : user_interest[], - age? : Int, - classId? : Long, - studentClass? : Classes @comment("班级") @relation(localField: "classId", foreignField: "id", cascadeDelete: "false"), - studentDetail? : StudentDetail @relation(localField: "id", foreignField: "studentId", cascadeDelete: "true"), - @index(name: "IDX_STUDENT_NAME",unique: "false", fields: [studentName]), - @index(name:"IDX_CLASS_ID", unique: "false", fields: [classId]), -} -model StudentDetail { - id : Long @id @default(autoIncrement()), - studentId? : Long, - student? : Student @comment("学生") @relation(localField: "studentId", foreignField: "id", cascadeDelete: "false"), - description? : String @length("255"), -} -model Classes { - id : Long @id @default(autoIncrement()), - classCode? : String @length("255"), - className? : String @length("255"), - students? : Student[] @relation(localField: "id", foreignField: "classId", cascadeDelete: "true"), -} -model Course { - courseNo : String @id @default(uuid()), - courseName? : String @length("255"), - @index(name:"IDX_COURSE_NO", unique: "false", fields: [courseNo]), -} -model fs_user { - id : String @id @default(uuid()), - username : String @length("255") @comment("用户名"), - avatar? : String @length("255") @comment("头像"), - password_hash : String @length("255") @comment("密码HASH"), - created_at : DateTime @default(now()) @comment("创建时间"), - updated_at : DateTime @default(now()) @comment("更新时间"), - @index(name:"IDX_USERNAME", unique: "true", fields: [username]), - @comment("用户") -} -enum ApiType { - FOLDER, - API -} -enum DatasourceType { - SYSTEM, - USER -} -enum UserGender { - UNKNOWN, - MALE, - FEMALE -} -enum user_interest { - chang, - tiao, - rap, - daLanQiu -} diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/test/java/tech/wetech/flexmodel/test/GreetingResourceIT.java b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/test/java/tech/wetech/flexmodel/test/GreetingResourceIT.java deleted file mode 100644 index 979ff0e0..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/test/java/tech/wetech/flexmodel/test/GreetingResourceIT.java +++ /dev/null @@ -1,8 +0,0 @@ -package dev.flexmodel.test; - -import io.quarkus.test.junit.QuarkusIntegrationTest; - -@QuarkusIntegrationTest -class GreetingResourceIT extends GreetingResourceTest { - // Execute the same tests but in packaged mode. -} diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/test/java/tech/wetech/flexmodel/test/GreetingResourceTest.java b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/test/java/tech/wetech/flexmodel/test/GreetingResourceTest.java deleted file mode 100644 index 4903d982..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/test/java/tech/wetech/flexmodel/test/GreetingResourceTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package dev.flexmodel.test; - -import io.quarkus.test.junit.QuarkusTest; -import org.junit.jupiter.api.Test; - -import static io.restassured.RestAssured.given; -import static org.hamcrest.Matchers.is; - -@QuarkusTest -class GreetingResourceTest { - @Test - void testHelloEndpoint() { - given() - .when().get("/hello") - .then() - .statusCode(200) - .body(is("Hello from Quarkus REST")); - } - -} diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/test/java/tech/wetech/flexmodel/test/UserResourceTest.java b/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/test/java/tech/wetech/flexmodel/test/UserResourceTest.java deleted file mode 100644 index 1a10b90e..00000000 --- a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/src/test/java/tech/wetech/flexmodel/test/UserResourceTest.java +++ /dev/null @@ -1,221 +0,0 @@ -package dev.flexmodel.test; - -import io.quarkus.test.junit.QuarkusTest; -import io.restassured.http.ContentType; -import org.junit.jupiter.api.*; - -import java.util.HashMap; -import java.util.Map; - -import static io.restassured.RestAssured.given; -import static org.hamcrest.Matchers.*; - -/** - * UserResource测试用例 - * 测试用户资源的CRUD操作 - * - * @author cjbi - */ -@QuarkusTest -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -class UserResourceTest { - - @BeforeEach - void setUp() { - // 每个测试前可以执行清理操作 - // 注意:这里假设使用内存数据库,每个测试之间数据会保留 - } - - @Test - @Order(1) - void testGetAllUsers_InitiallyEmpty() { - given() - .when().get("/users") - .then() - .statusCode(200) - .contentType(ContentType.JSON) - .body("", hasSize(0)); - } - - @Test - @Order(2) - void testCreateUser() { - Map userData = new HashMap<>(); - userData.put("username", "testuser"); - userData.put("avatar", "https://example.com/avatar.jpg"); - userData.put("password_hash", "hashedpassword123"); - - given() - .contentType(ContentType.JSON) - .body(userData) - .when().post("/users") - .then() - .statusCode(201) - .contentType(ContentType.JSON) - .body("message", is("User created successfully")) - .body("affectedRows", is(1)) - .body("user", notNullValue()) - .body("user.username", is("testuser")); - } - - @Test - @Order(3) - void testGetAllUsers_AfterCreation() { - given() - .when().get("/users") - .then() - .statusCode(200) - .contentType(ContentType.JSON) - .body("", isA(java.util.List.class)) - .body("size()", greaterThanOrEqualTo(1)); - } - - @Test - @Order(4) - void testGetUserById_Success() { - // 先创建一个用户用于测试 - Map userData = new HashMap<>(); - userData.put("username", "getuser" + System.currentTimeMillis()); - userData.put("password_hash", "hash123"); - - String userId = given() - .contentType(ContentType.JSON) - .body(userData) - .when().post("/users") - .then() - .statusCode(201) - .extract() - .path("user.id"); - - // 根据ID获取用户 - given() - .when().get("/users/" + userId) - .then() - .statusCode(200) - .contentType(ContentType.JSON) - .body("id", is(userId)) - .body("username", notNullValue()); - } - - @Test - @Order(5) - void testGetUserById_NotFound() { - given() - .when().get("/users/nonexistent-id-12345") - .then() - .statusCode(404) - .body(is("User not found")); - } - - @Test - @Order(6) - void testUpdateUser_Success() { - // 先创建一个用户 - Map userData = new HashMap<>(); - String username = "updateuser" + System.currentTimeMillis(); - userData.put("username", username); - userData.put("password_hash", "hash123"); - - String userId = given() - .contentType(ContentType.JSON) - .body(userData) - .when().post("/users") - .then() - .statusCode(201) - .extract() - .path("user.id"); - - // 更新用户 - Map updateData = new HashMap<>(); - updateData.put("username", username + "_updated"); - updateData.put("avatar", "https://example.com/new-avatar.jpg"); - - given() - .contentType(ContentType.JSON) - .body(updateData) - .when().put("/users/" + userId) - .then() - .statusCode(200) - .contentType(ContentType.JSON) - .body("message", is("User updated successfully")) - .body("id", is(userId)) - .body("affectedRows", is(1)); - - // 验证更新是否成功 - given() - .when().get("/users/" + userId) - .then() - .statusCode(200) - .body("username", is(username + "_updated")) - .body("avatar", is("https://example.com/new-avatar.jpg")); - } - - @Test - @Order(7) - void testDeleteUser_Success() { - // 先创建一个用户 - Map userData = new HashMap<>(); - userData.put("username", "deleteuser" + System.currentTimeMillis()); - userData.put("password_hash", "hash123"); - - String userId = given() - .contentType(ContentType.JSON) - .body(userData) - .when().post("/users") - .then() - .statusCode(201) - .extract() - .path("user.id"); - - // 删除用户 - given() - .when().delete("/users/" + userId) - .then() - .statusCode(200) - .contentType(ContentType.JSON) - .body("message", is("User deleted successfully")) - .body("id", is(userId)) - .body("affectedRows", is(1)); - - // 验证用户已被删除 - given() - .when().get("/users/" + userId) - .then() - .statusCode(404); - } - - @Test - @Order(8) - void testDeleteUser_NotFound() { - given() - .when().delete("/users/nonexistent-id-12345") - .then() - .statusCode(200) // 删除操作即使不存在也可能返回200 - .contentType(ContentType.JSON) - .body("affectedRows", is(0)); - } - - @Test - @Order(9) - void testCreateUser_WithAllFields() { - Map userData = new HashMap<>(); - userData.put("username", "fulluser" + System.currentTimeMillis()); - userData.put("avatar", "https://example.com/full-avatar.jpg"); - userData.put("password_hash", "fullpasswordhash"); - - given() - .contentType(ContentType.JSON) - .body(userData) - .when().post("/users") - .then() - .statusCode(201) - .contentType(ContentType.JSON) - .body("message", is("User created successfully")) - .body("affectedRows", is(1)) - .body("user.username", is(userData.get("username"))) - .body("user.avatar", is(userData.get("avatar"))) - .body("user.passwordHash", is(userData.get("passwordHash"))); - } - -} - diff --git a/flexmodel-engine/integration-tests/pom.xml b/flexmodel-engine/integration-tests/pom.xml index 93f9b478..14b14c51 100644 --- a/flexmodel-engine/integration-tests/pom.xml +++ b/flexmodel-engine/integration-tests/pom.xml @@ -27,7 +27,6 @@ flexmodel-core-tidb flexmodel-core-mongodb flexmodel-core-db2 - flexmodel-quarkus-it diff --git a/flexmodel-engine/pom.xml b/flexmodel-engine/pom.xml index 9a4a461e..85acc6d7 100644 --- a/flexmodel-engine/pom.xml +++ b/flexmodel-engine/pom.xml @@ -10,7 +10,6 @@ flexmodel-core flexmodel-graphql - flexmodel-quarkus integration-tests flexmodel-codegen flexmodel-maven-plugin diff --git a/flexmodel-engine/integration-tests/flexmodel-quarkus-it/.dockerignore b/flexmodel-server/.dockerignore similarity index 100% rename from flexmodel-engine/integration-tests/flexmodel-quarkus-it/.dockerignore rename to flexmodel-server/.dockerignore diff --git a/flexmodel-server/AGENTS.md b/flexmodel-server/AGENTS.md deleted file mode 100644 index 4313cfac..00000000 --- a/flexmodel-server/AGENTS.md +++ /dev/null @@ -1,83 +0,0 @@ -# Agent Definition: Quarkus Backend Specialist - -## 1. Persona (角色定义) - -你是一个资深的 Java 后端专家,精通 Quarkus 生态、微服务架构及代码质量规范,专注于领域驱动设计 (DDD) 和云原生应用开发。 - -## 2. Context (项目上下文) - -- **核心栈**: Java 21, Quarkus 3, Maven, SQLite (默认,支持可扩展)。 -- **架构模式**: 采用 DDD (领域驱动设计) 分层架构模式。 -- **目录规范**: - - `interfaces/`: 接口层 - 处理 REST API、协议适配 - - `application/`: 应用层 - 负责用例编排、DTO 转换、事务控制 - - `domain/`: 领域层 - 包含核心业务模型、领域服务 - - `infrastructure/`: 基础设施层 - 实现持久化、外部接口适配 - - `shared/`: 共享层 - 通用工具、基础类 -- **项目定位**: Flexmodel Server 是基于 Quarkus 3 的微服务项目,提供统一数据访问层和 API 设计平台。 - -## 3. Standards (开发标准) - -- **编码规范**: 遵循 Java 21 最佳实践,使用 2 个空格缩进。 -- **命名约定**: - - 类名: `PascalCase` (如 `ChatResource`, `BusinessException`) - - 方法名: `camelCase` (如 `sendMessage`, `getSettings`) - - 常量: `UPPER_SNAKE_CASE` (如 `ROOT_PATH`) - - 包名: 全小写 (如 `dev.flexmodel.interfaces.rest`) - - DTO 用于数据传输,Entity 对应数据库映射 -- **异常处理**: 必须继承 `BusinessException` 创建业务异常,异常类设计为抽象类,提供带消息和原因的构造函数。 -- **依赖注入**: 使用 CDI (Contexts and Dependency Injection),使用 `@ApplicationScoped` 和 `@Inject` 注解。 -- **代码简化**: 充分利用 Lombok 简化代码,减少样板代码。 - -## 4. Skills & Tools (技能与工具) - -- **单元测试**: 使用 JUnit 5 和 REST Assured。新增功能必须包含测试覆盖。 -- **测试注解**: 使用 `@QuarkusTest` 进行集成测试,使用 `@QuarkusTestResource` 配置测试资源。 -- **依赖管理**: 使用 Maven 进行管理,版本号统一在 `pom.xml` 中管理,优先使用 Quarkus BOM,第三方依赖需明确指定版本。 -- **API 文档**: 使用 OpenAPI / Swagger 生成 API 文档。 -- **工具库**: Lombok, GraphQL Java。 -- **静态分析**: 参考代码质量规范,保持代码一致性。 -- **日志**: 使用 `@Slf4j` 注解进行日志记录。 - -## 5. Workflows (工作流) - -- **新增 REST 资源**: - 1. 定义 DTO (数据传输对象) - 2. 在 domain 层创建领域模型和领域服务 - 3. 在 application 层编写应用服务,处理用例编排和 DTO 转换 - 4. 在 interfaces 层创建 REST Resource (Controller) - 5. 编写集成测试,使用 REST Assured 测试 API 端点 - 6. 验证功能并确保测试通过 - -- **代码重构**: - 1. 分析现状,理解现有代码结构 - 2. 运行现有测试,确保测试通过 - 3. 逐步优化,遵循 DDD 分层架构 - 4. 重新验证测试,确保功能正常 - -- **创建 REST API**: - - 基础路径通常为 `/api` - - 使用 HTTP 标准方法 (GET, POST, PUT, PATCH, DELETE) - - 必须支持 JSON (`MediaType.APPLICATION_JSON`) - - 适用时支持 SSE (Server-Sent Events) 流式输出 - - 使用注解: `@Path`, `@GET`, `@POST`, `@Produces`, `@Consumes` - -- **配置管理**: - - 使用 `@ConfigMapping`, `@WithName`, `@WithDefault` 注解 - - 配置说明需详细完整 - -## 6. Boundaries (行为边界) - -- **禁止事项**: - - 禁止在 interfaces 层 (REST Resource) 中编写业务逻辑,业务逻辑应在 application 或 domain 层。 - - 禁止引入未经团队审计的第三方库,依赖管理需通过 Maven 统一管理。 - - 修改数据库 Schema 前必须征求人类确认。 - - 禁止直接在业务层抛出原始异常,必须使用继承自 `BusinessException` 的业务异常。 - -- **必须遵守**: - - 代码注释、文档和提交信息推荐使用中文。 - - 生成代码后,应优先考虑通过编写测试用例来验证功能。 - - 保持与现有代码风格一致。 - - 类和方法添加 JavaDoc 注释,使用 `@author` 标记作者。 - - 测试方法名应具有描述性,测试数据和场景需包含中文注释说明。 - - 导入语句按字母顺序排列,类和方法之间空一行。 diff --git a/flexmodel-server/README.md b/flexmodel-server/README.md index 3385ed73..a8bfcd22 100644 --- a/flexmodel-server/README.md +++ b/flexmodel-server/README.md @@ -1,14 +1,14 @@ # Flexmodel Server -> **Flexmodel Server** 是基于 Quarkus 的后端服务实现,作为 Flexmodel 项目的服务端核心,遵循 DDD(领域驱动设计)架构,集成了数据访问、服务编排、任务调度、文件存储和身份认证等核心功能。 +> **Flexmodel Server** 是基于 Quarkus 的后端服务实现,作为 Flexmodel 项目的服务端核心,采用特性垂直分包架构,集成了数据访问、服务编排、任务调度、文件存储和身份认证等核心功能。 ## 🚀 核心特性 - **一站式后端能力**: 集成了身份认证 (Auth)、文件存储 (Storage)、任务调度 (Job) 及服务编排 (Flow)。 - **统一数据接口**: 抽象底层数据源差异,提供标准化的 REST 和 GraphQL 接口。 - **AI 赋能**: 内置 LangChain4j,提供流式对话能力 (SSE),支持构建智能应用。 -- **动态逻辑**: 支持基于 Groovy 的代码模板生成,实现灵活的业务逻辑扩展。 -- **DDD 架构**: 严格的分层架构(接口层、应用层、领域层、基础设施层),易于演进和维护。 +- **动态逻辑**: 支持基于 JavaScript 的脚本执行,实现灵活的业务逻辑扩展。 +- **特性垂直分包**: 按业务特性垂直分包,每个特性包内聚 Resource、Service、Repository、DTO,易于演进和维护。 ## 🛠️ 技术栈 @@ -16,17 +16,26 @@ - **AI 能力**: LangChain4j (OpenAI 兼容接口, StreamingChatModel) - **API 协议**: REST API, GraphQL, OpenAPI/Swagger UI - **持久化**: SQLite (默认演示) / 支持扩展多种关系型与 NoSQL 数据库 -- **其他**: Lombok, Groovy, Docker, Maven - -## 🏗️ 分层架构 - -项目采用 DDD 分层与按职责划分的包结构: - -- **接口层 (Interfaces)**: `dev.flexmodel.interfaces` - 提供 REST API 及协议适配。 -- **应用层 (Application)**: `dev.flexmodel.application` - 编排领域用例,处理 DTO、事务及业务流程。 -- **领域层 (Domain)**: `dev.flexmodel.domain` - 核心领域模型与领域服务,包含仓储接口。 -- **基础设施层 (Infrastructure)**: `dev.flexmodel.infrastructure` - 外部资源适配(数据库、调度、存储、AI)。 -- **公共与工具 (Shared)**: `dev.flexmodel.shared` - 通用工具类。 +- **其他**: Lombok, GraalVM JavaScript, Docker, Maven + +## 🏗️ 架构设计 + +项目采用特性垂直分包 (Feature-Based Packaging) 架构,按业务特性组织代码,每个特性包包含该特性所需的全部组件: + +- **`api/`**: API 管理 — 定义、运行时执行、文档生成、GraphQL +- **`flow/`**: 流程编排 — 流程定义、实例管理、执行引擎、插件、校验 +- **`auth/`**: 认证授权 — 用户、角色、资源、权限 +- **`modeling/`**: 数据建模 — 模型定义、字段管理 +- **`data/`**: 数据访问 — 记录 CRUD、查询 +- **`scheduling/`**: 任务调度 — 触发器、作业执行 +- **`storage/`**: 文件存储 — 本地、S3 +- **`ai/`**: AI 聊天 — LLM 集成、对话管理 +- **`settings/`**: 系统设置 +- **`metrics/`**: 监控指标 +- **`project/`**: 项目管理 +- **`idp/`**: 身份提供商 +- **`connect/`**: 数据源连接 +- **`common/`**: 共享基础设施 — 配置、工具类、全局异常、安全过滤器 ## 🚀 快速开始 diff --git a/flexmodel-server/mvnw b/flexmodel-server/mvnw index ba9212a0..bd8896bf 100755 --- a/flexmodel-server/mvnw +++ b/flexmodel-server/mvnw @@ -8,7 +8,7 @@ # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # -# https://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an @@ -19,7 +19,7 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.1 +# Apache Maven Wrapper startup batch script, version 3.3.4 # # Optional ENV vars # ----------------- @@ -97,14 +97,25 @@ die() { exit 1 } +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +scriptDir="$(dirname "$0")" +scriptName="$(basename "$0")" + # parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties while IFS="=" read -r key value; do case "${key-}" in - distributionUrl) distributionUrl="${value-}" ;; - distributionSha256Sum) distributionSha256Sum="${value-}" ;; + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; esac -done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" -[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" +done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" case "${distributionUrl##*/}" in maven-mvnd-*bin.*) @@ -122,7 +133,7 @@ maven-mvnd-*bin.*) distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" ;; maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; -*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; esac # apply MVNW_REPOURL and calculate MAVEN_HOME @@ -131,7 +142,8 @@ esac distributionUrlName="${distributionUrl##*/}" distributionUrlNameMain="${distributionUrlName%.*}" distributionUrlNameMain="${distributionUrlNameMain%-bin}" -MAVEN_HOME="$HOME/.m2/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" exec_maven() { unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : @@ -218,7 +230,7 @@ if [ -n "${distributionSha256Sum-}" ]; then echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 exit 1 elif command -v sha256sum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then distributionSha256Result=true fi elif command -v shasum >/dev/null; then @@ -243,8 +255,41 @@ if command -v unzip >/dev/null; then else tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" fi -printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" -mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +actualDistributionDir="" + +# First try the expected directory name (for regular distributions) +if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then + if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then + actualDistributionDir="$distributionUrlNameMain" + fi +fi + +# If not found, search for any directory with the Maven executable (for snapshots) +if [ -z "$actualDistributionDir" ]; then + # enable globbing to iterate over items + set +f + for dir in "$TMP_DOWNLOAD_DIR"/*; do + if [ -d "$dir" ]; then + if [ -f "$dir/bin/$MVN_CMD" ]; then + actualDistributionDir="$(basename "$dir")" + break + fi + fi + done + set -f +fi + +if [ -z "$actualDistributionDir" ]; then + verbose "Contents of $TMP_DOWNLOAD_DIR:" + verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" + die "Could not find Maven distribution directory in extracted archive" +fi + +verbose "Found extracted Maven distribution directory: $actualDistributionDir" +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" clean || : exec_maven "$@" diff --git a/flexmodel-server/mvnw.cmd b/flexmodel-server/mvnw.cmd index 406932da..92450f93 100644 --- a/flexmodel-server/mvnw.cmd +++ b/flexmodel-server/mvnw.cmd @@ -8,7 +8,7 @@ @REM "License"); you may not use this file except in compliance @REM with the License. You may obtain a copy of the License at @REM -@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM http://www.apache.org/licenses/LICENSE-2.0 @REM @REM Unless required by applicable law or agreed to in writing, @REM software distributed under the License is distributed on an @@ -19,7 +19,7 @@ @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.3.1 +@REM Apache Maven Wrapper startup batch script, version 3.3.4 @REM @REM Optional ENV vars @REM MVNW_REPOURL - repo url base for downloading maven distribution @@ -40,7 +40,7 @@ @SET __MVNW_ARG0_NAME__= @SET MVNW_USERNAME= @SET MVNW_PASSWORD= -@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) +@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) @echo Cannot start maven from wrapper >&2 && exit /b 1 @GOTO :EOF : end batch / begin powershell #> @@ -73,13 +73,30 @@ switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { # apply MVNW_REPOURL and calculate MAVEN_HOME # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ if ($env:MVNW_REPOURL) { - $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } - $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" + $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" } $distributionUrlName = $distributionUrl -replace '^.*/','' $distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' -$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" -$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' + +$MAVEN_M2_PATH = "$HOME/.m2" +if ($env:MAVEN_USER_HOME) { + $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" +} + +if (-not (Test-Path -Path $MAVEN_M2_PATH)) { + New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null +} + +$MAVEN_WRAPPER_DISTS = $null +if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { + $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" +} else { + $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" +} + +$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" +$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' $MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { @@ -131,7 +148,33 @@ if ($distributionSha256Sum) { # unzip and move Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null -Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +$actualDistributionDir = "" + +# First try the expected directory name (for regular distributions) +$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" +$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" +if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { + $actualDistributionDir = $distributionUrlNameMain +} + +# If not found, search for any directory with the Maven executable (for snapshots) +if (!$actualDistributionDir) { + Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { + $testPath = Join-Path $_.FullName "bin/$MVN_CMD" + if (Test-Path -Path $testPath -PathType Leaf) { + $actualDistributionDir = $_.Name + } + } +} + +if (!$actualDistributionDir) { + Write-Error "Could not find Maven distribution directory in extracted archive" +} + +Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null try { Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null } catch { diff --git a/flexmodel-server/pom.xml b/flexmodel-server/pom.xml index 6e9f8b43..e2237e08 100644 --- a/flexmodel-server/pom.xml +++ b/flexmodel-server/pom.xml @@ -6,15 +6,15 @@ flexmodel-server 0.0.1-SNAPSHOT - 3.14.0 - 21 + 3.15.0 + 25 UTF-8 UTF-8 quarkus-bom io.quarkus.platform - 3.27.0 + 3.33.1 true - 3.5.2 + 3.5.4 5.1.0 @@ -51,7 +51,6 @@ org.quartz-scheduler quartz - 2.5.0 com.auth0 @@ -79,11 +78,6 @@ flexmodel-graphql ${project.version} - - dev.flexmodel - flexmodel-quarkus - ${project.version} - io.quarkus quarkus-web-dependency-locator @@ -91,8 +85,8 @@ org.projectlombok lombok - 1.18.30 - provided + 1.18.44 + compile org.xerial @@ -102,7 +96,6 @@ com.mysql mysql-connector-j - 8.3.0 com.zaxxer @@ -137,7 +130,7 @@ io.quarkus - quarkus-junit5 + quarkus-junit test @@ -187,15 +180,21 @@ system - src/main/resources/schema.idl,src/main/resources/data.json + + src/main/resources/platform.fml, + src/main/resources/project.fml + dev.flexmodel.codegen ^f_ei_|^f_em_|^f_ dev_test - src/main/resources/dev_test_schema.idl,src/main/resources/dev_test_data.json + + src/main/resources/project.fml, + src/main/resources/dev_test.fml dev.flexmodel.test.codegen + ^f_ei_|^f_em_|^f_ @@ -222,6 +221,13 @@ ${compiler-plugin.version} true + + + org.projectlombok + lombok + 1.18.44 + + @@ -232,6 +238,7 @@ org.jboss.logmanager.LogManager ${maven.home} + @{argLine} @@ -251,35 +258,7 @@ org.jboss.logmanager.LogManager ${maven.home} - - - - org.codehaus.gmavenplus - gmavenplus-plugin - 3.0.2 - - - - addSources - addTestSources - generateStubs - compile - generateTestStubs - compileTests - removeStubs - removeTestStubs - - - - - - - ${project.basedir}/src/main/groovy - - **/*.groovy - - - + @{argLine} diff --git a/flexmodel-server/src/main/docker/Dockerfile.jvm b/flexmodel-server/src/main/docker/Dockerfile.jvm index cd9edb41..4a742d78 100644 --- a/flexmodel-server/src/main/docker/Dockerfile.jvm +++ b/flexmodel-server/src/main/docker/Dockerfile.jvm @@ -77,8 +77,10 @@ # - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be # accessed directly. (example: "foo.example.com,bar.example.com") # +# You can find more information about the UBI base runtime images and their configuration here: +# https://rh-openjdk.github.io/redhat-openjdk-containers/ ### -FROM registry.access.redhat.com/ubi9/openjdk-21:1.21 +FROM registry.access.redhat.com/ubi9/openjdk-25-runtime:1.24 ENV LANGUAGE='en_US:en' @@ -88,7 +90,6 @@ COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/ COPY --chown=185 target/quarkus-app/*.jar /deployments/ COPY --chown=185 target/quarkus-app/app/ /deployments/app/ COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/ -COPY --chown=185 docs/ /deployments/docs/ EXPOSE 8080 USER 185 diff --git a/flexmodel-server/src/main/docker/Dockerfile.legacy-jar b/flexmodel-server/src/main/docker/Dockerfile.legacy-jar index 7054d377..7f74a47a 100644 --- a/flexmodel-server/src/main/docker/Dockerfile.legacy-jar +++ b/flexmodel-server/src/main/docker/Dockerfile.legacy-jar @@ -77,8 +77,10 @@ # - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be # accessed directly. (example: "foo.example.com,bar.example.com") # +# You can find more information about the UBI base runtime images and their configuration here: +# https://rh-openjdk.github.io/redhat-openjdk-containers/ ### -FROM registry.access.redhat.com/ubi9/openjdk-21:1.21 +FROM registry.access.redhat.com/ubi9/openjdk-25-runtime:1.24 ENV LANGUAGE='en_US:en' diff --git a/flexmodel-server/src/main/docker/Dockerfile.native b/flexmodel-server/src/main/docker/Dockerfile.native index 9421b3fb..ea38eb7e 100644 --- a/flexmodel-server/src/main/docker/Dockerfile.native +++ b/flexmodel-server/src/main/docker/Dockerfile.native @@ -13,10 +13,10 @@ # # docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus # -# The ` registry.access.redhat.com/ubi9/ubi-minimal:9.5` base image is based on UBI 9. +# The ` registry.access.redhat.com/ubi9/ubi-minimal:9.7` base image is based on UBI 9. # To use UBI 8, switch to `quay.io/ubi8/ubi-minimal:8.10`. ### -FROM registry.access.redhat.com/ubi9/ubi-minimal:9.5 +FROM registry.access.redhat.com/ubi9/ubi-minimal:9.7 WORKDIR /work/ RUN chown 1001 /work \ && chmod "g+rwX" /work \ diff --git a/flexmodel-server/src/main/groovy/dev/flexmodel/ApiDefinitionGenerator.groovy b/flexmodel-server/src/main/groovy/dev/flexmodel/ApiDefinitionGenerator.groovy deleted file mode 100644 index 46b35715..00000000 --- a/flexmodel-server/src/main/groovy/dev/flexmodel/ApiDefinitionGenerator.groovy +++ /dev/null @@ -1,28 +0,0 @@ -package dev.flexmodel - -import dev.flexmodel.codegen.AbstractGenerator -import dev.flexmodel.codegen.GenerationContext -import dev.flexmodel.codegen.entity.ApiDefinition - -import static dev.flexmodel.model.field.ScalarType.* - -/** - * @author cjbi - */ -abstract class ApiDefinitionGenerator extends AbstractGenerator { - - protected def typeMapping = [ - (STRING.type) : "String", - (FLOAT.type) : "Float", - (INT.type) : "Int", - (LONG.type) : "Int", - (BOOLEAN.type) : "Boolean", - (DATETIME.type): "String", - (DATE.type) : "String", - (TIME.type) : "String", - (JSON.type) : "JSON", - ] - - abstract ApiDefinition createApiDefinition(String projectId, GenerationContext context) - -} diff --git a/flexmodel-server/src/main/groovy/dev/flexmodel/CreateApiDefinitionGenerator.groovy b/flexmodel-server/src/main/groovy/dev/flexmodel/CreateApiDefinitionGenerator.groovy deleted file mode 100644 index 5bf1e1e5..00000000 --- a/flexmodel-server/src/main/groovy/dev/flexmodel/CreateApiDefinitionGenerator.groovy +++ /dev/null @@ -1,68 +0,0 @@ -package dev.flexmodel - -import dev.flexmodel.codegen.GenerationContext -import dev.flexmodel.codegen.entity.ApiDefinition -import dev.flexmodel.codegen.enumeration.ApiType -import dev.flexmodel.model.field.TypedField - -/** - * @author cjbi - */ -class CreateApiDefinitionGenerator extends ApiDefinitionGenerator { - - @Override - void write(PrintWriter out, GenerationContext context) { - def schemaName = context.getModelClass().getSchemaName() - def modelName = context.getModelClass().getName() - out.println "mutation MyCreateMutation(" - context.getModelClass().getBasicFields().each { - if(it.isIdentity()){ - out.print "\$${it.name}: ID" - } else { - out.print "\$${it.name}: ${typeMapping[((TypedField) it.original).type]}" - } - if (context.modelClass.basicFields.last() != it) { - out.print(", ") - } - } - out.println ") {" - out.println " ${schemaName}_create_${modelName}(" - out.print " data: {" - context.getModelClass().getBasicFields().each { - out.print "${it.name}: \$${it.name}" - if (context.modelClass.basicFields.last() != it) { - out.print(", ") - } - } - out.print " }" - out.println ") {" - context.getModelClass().getBasicFields().each { - out.println " ${it.name}" - } - out.println " }" - out.println "}" - } - - @Override - ApiDefinition createApiDefinition(String projectId, GenerationContext context) { - ApiDefinition apiDefinition = new ApiDefinition() - apiDefinition.setProjectId(projectId) - apiDefinition.setParentId(context.getVariable("apiParentId")) - apiDefinition.setName("Create ${context.getModelClass().getName()} record") - apiDefinition.setType("API" as ApiType) - apiDefinition.setMethod("POST") - apiDefinition.setPath("/${context.getModelClass().getName()}") - - Map meta = [ - "auth" : false, - "execution": [ - "operationName": "MyCreateMutation", - "query" : generate(context).getFirst() - ] - ] - apiDefinition.setMeta(meta) - apiDefinition.setEnabled(true) - return apiDefinition - } - -} diff --git a/flexmodel-server/src/main/groovy/dev/flexmodel/DeleteApiDefinitionGenerator.groovy b/flexmodel-server/src/main/groovy/dev/flexmodel/DeleteApiDefinitionGenerator.groovy deleted file mode 100644 index 5c8fbf35..00000000 --- a/flexmodel-server/src/main/groovy/dev/flexmodel/DeleteApiDefinitionGenerator.groovy +++ /dev/null @@ -1,49 +0,0 @@ -package dev.flexmodel - -import dev.flexmodel.codegen.GenerationContext -import dev.flexmodel.codegen.entity.ApiDefinition -import dev.flexmodel.codegen.enumeration.ApiType -import dev.flexmodel.model.field.TypedField - -/** - * @author cjbi - */ -class DeleteApiDefinitionGenerator extends ApiDefinitionGenerator { - - @Override - void write(PrintWriter out, GenerationContext context) { - def schemaName = context.getModelClass().getSchemaName() - def modelName = context.getModelClass().getName() - def id = context.getVariable("idFieldOfPath") - def idField = context.getModelClass().getField(id as String) - out.println "mutation MyDeleteMutation(" - out.print "\$${idField.name}: ${typeMapping[((TypedField) idField.original).type]}" - out.println ") {" - out.println " ${schemaName}_delete_${modelName}(where: {${id}: {_eq: \$${id}} } ) {" - out.println " affected_rows" - out.println " }" - out.println "}" - } - - @Override - ApiDefinition createApiDefinition(String projectId, GenerationContext context) { - ApiDefinition apiDefinition = new ApiDefinition() - apiDefinition.setProjectId(projectId) - apiDefinition.setParentId(context.getVariable("apiParentId")) - apiDefinition.setName("Delete ${context.getModelClass().getName()} record") - apiDefinition.setType("API" as ApiType) - apiDefinition.setMethod("DELETE") - apiDefinition.setPath("/${context.getModelClass().getName()}/{id}") - - Map meta = [ - "auth" : false, - "execution": [ - "operationName": "MyDeleteMutation", - "query" : generate(context).getFirst(), - ] - ] - apiDefinition.setMeta(meta) - apiDefinition.setEnabled(true) - return apiDefinition - } -} diff --git a/flexmodel-server/src/main/groovy/dev/flexmodel/ListApiDefinitionGenerator.groovy b/flexmodel-server/src/main/groovy/dev/flexmodel/ListApiDefinitionGenerator.groovy deleted file mode 100644 index 7cdf8d84..00000000 --- a/flexmodel-server/src/main/groovy/dev/flexmodel/ListApiDefinitionGenerator.groovy +++ /dev/null @@ -1,48 +0,0 @@ -package dev.flexmodel - -import dev.flexmodel.codegen.GenerationContext -import dev.flexmodel.codegen.entity.ApiDefinition -import dev.flexmodel.codegen.enumeration.ApiType - -/** - * @author cjbi - */ -class ListApiDefinitionGenerator extends ApiDefinitionGenerator { - - @Override - void write(PrintWriter out, GenerationContext context) { - def schemaName = context.getModelClass().getSchemaName() - def modelName = context.getModelClass().getName() - out.println "query MyListQuery( \$where: ${schemaName}_${modelName}_bool_exp) {" - out.println " list: ${schemaName}_list_${modelName}(where: \$where) {" - context.getModelClass().getAllFields().each { - if (!it.isRelationField()) { - out.println " ${it.name}" - } - } - out.println " }" - out.println "}" - } - - @Override - ApiDefinition createApiDefinition(String projectId, GenerationContext context) { - ApiDefinition apiDefinition = new ApiDefinition() - apiDefinition.setProjectId(projectId) - apiDefinition.setParentId(context.getVariable("apiParentId")) - apiDefinition.setName("Fetch ${context.getModelClass().getName()} records list") - apiDefinition.setType("API" as ApiType) - apiDefinition.setMethod("GET") - apiDefinition.setPath("/${context.getModelClass().getName()}/list") - - Map meta = [ - "auth" : false, - "execution": [ - "operationName": "MyListQuery", - "query" : generate(context).getFirst(), - ] - ] - apiDefinition.setMeta(meta) - apiDefinition.setEnabled(true) - return apiDefinition - } -} diff --git a/flexmodel-server/src/main/groovy/dev/flexmodel/PaginationApiDefinitionGenerator.groovy b/flexmodel-server/src/main/groovy/dev/flexmodel/PaginationApiDefinitionGenerator.groovy deleted file mode 100644 index d3b7b2cb..00000000 --- a/flexmodel-server/src/main/groovy/dev/flexmodel/PaginationApiDefinitionGenerator.groovy +++ /dev/null @@ -1,51 +0,0 @@ -package dev.flexmodel - -import dev.flexmodel.codegen.GenerationContext -import dev.flexmodel.codegen.entity.ApiDefinition -import dev.flexmodel.codegen.enumeration.ApiType - -/** - * @author cjbi - */ -class PaginationApiDefinitionGenerator extends ApiDefinitionGenerator { - - @Override - void write(PrintWriter out, GenerationContext context) { - def schemaName = context.getModelClass().getSchemaName() - def modelName = context.getModelClass().getName() - out.println "query MyPaginationQuery( \$where: ${schemaName}_${modelName}_bool_exp, \$page: Int = 1, \$size: Int = 10) {" - out.println " list: ${schemaName}_list_${modelName}(where: \$where, page: \$page, size: \$size) {" - context.getModelClass().getAllFields().each { - if(!it.isRelationField()) { - out.println " ${it.name}" - } - } - out.println " }" - out.println " total: ${schemaName}_aggregate_${modelName}(where: \$where) @transform(get: \"_count\") {" - out.println " _count" - out.println " }" - out.println "}" - } - - @Override - ApiDefinition createApiDefinition(String projectId, GenerationContext context) { - ApiDefinition apiDefinition = new ApiDefinition() - apiDefinition.setProjectId(projectId) - apiDefinition.setParentId(context.getVariable("apiParentId")) - apiDefinition.setName("Fetch a paginated ${context.getModelClass().getName()} records list") - apiDefinition.setType("API" as ApiType) - apiDefinition.setMethod("GET") - apiDefinition.setPath("/${context.getModelClass().getName()}/page") - - Map meta = [ - "auth" : false, - "execution": [ - "operationName": "MyPaginationQuery", - "query" : generate(context).getFirst(), - ] - ] - apiDefinition.setMeta(meta) - apiDefinition.setEnabled(true) - return apiDefinition - } -} diff --git a/flexmodel-server/src/main/groovy/dev/flexmodel/UpdateApiDefinitionGenerator.groovy b/flexmodel-server/src/main/groovy/dev/flexmodel/UpdateApiDefinitionGenerator.groovy deleted file mode 100644 index 38ac5172..00000000 --- a/flexmodel-server/src/main/groovy/dev/flexmodel/UpdateApiDefinitionGenerator.groovy +++ /dev/null @@ -1,66 +0,0 @@ -package dev.flexmodel - -import dev.flexmodel.codegen.GenerationContext -import dev.flexmodel.codegen.entity.ApiDefinition -import dev.flexmodel.codegen.enumeration.ApiType -import dev.flexmodel.model.field.TypedField - -/** - * @author cjbi - */ -class UpdateApiDefinitionGenerator extends ApiDefinitionGenerator { - - @Override - void write(PrintWriter out, GenerationContext context) { - def schemaName = context.getModelClass().getSchemaName() - def modelName = context.getModelClass().getName() - def id = context.getVariable("idFieldOfPath") - def idField = context.getModelClass().getField(id as String) - out.println "mutation MyUpdateMutation(" - context.getModelClass().getBasicFields().each { - out.print "\$${it.name}: ${typeMapping[((TypedField) it.original).type]}" - if (context.modelClass.basicFields.last() != it) { - out.print(", ") - } - } - out.println ") {" - out.println " ${schemaName}_update_${modelName}(" - out.println " where: {${id}: {_eq: \$${id}} }, " - out.print " _set: {" - context.getModelClass().getBasicFields().each { - if (id != it.name) { - out.print "${it.name}: \$${it.name}" - if (context.modelClass.basicFields.last() != it) { - out.print(", ") - } - } - } - out.println "}" - out.println " ) {" - out.println " affected_rows" - out.println " }" - out.println "}" - } - - @Override - ApiDefinition createApiDefinition(String projectId, GenerationContext context) { - ApiDefinition apiDefinition = new ApiDefinition() - apiDefinition.setProjectId(projectId) - apiDefinition.setParentId(context.getVariable("apiParentId")) - apiDefinition.setName("Update ${context.getModelClass().getName()} record") - apiDefinition.setType("API" as ApiType) - apiDefinition.setMethod("PUT") - apiDefinition.setPath("/${context.getModelClass().getName()}/{id}") - - Map meta = [ - "auth" : false, - "execution": [ - "operationName": "MyUpdateMutation", - "query" : generate(context).getFirst(), - ] - ] - apiDefinition.setMeta(meta) - apiDefinition.setEnabled(true) - return apiDefinition - } -} diff --git a/flexmodel-server/src/main/groovy/dev/flexmodel/ViewApiDefinitionGenerator.groovy b/flexmodel-server/src/main/groovy/dev/flexmodel/ViewApiDefinitionGenerator.groovy deleted file mode 100644 index 763ca226..00000000 --- a/flexmodel-server/src/main/groovy/dev/flexmodel/ViewApiDefinitionGenerator.groovy +++ /dev/null @@ -1,51 +0,0 @@ -package dev.flexmodel - -import dev.flexmodel.codegen.GenerationContext -import dev.flexmodel.codegen.entity.ApiDefinition -import dev.flexmodel.codegen.enumeration.ApiType -import dev.flexmodel.model.field.TypedField - -/** - * @author cjbi - */ -class ViewApiDefinitionGenerator extends ApiDefinitionGenerator { - - @Override - void write(PrintWriter out, GenerationContext context) { - def schemaName = context.getModelClass().getSchemaName() - def modelName = context.getModelClass().getName() - def id = context.getVariable("idFieldOfPath") - def idField = context.getModelClass().getField(id as String) - out.println "query MyViewQuery( \$${id}: ${typeMapping[((TypedField) idField.original).type]} ) {" - out.println " ${schemaName}_find_one_${modelName}(where: {${id}: {_eq: \$${id}} }) {" - context.getModelClass().getAllFields().each { - if (!it.isRelationField()) { - out.println " ${it.name}" - } - } - out.println " }" - out.println "}" - } - - @Override - ApiDefinition createApiDefinition(String projectId, GenerationContext context) { - ApiDefinition apiDefinition = new ApiDefinition() - apiDefinition.setProjectId(projectId) - apiDefinition.setParentId(context.getVariable("apiParentId")) - apiDefinition.setName("Fetch a single ${context.getModelClass().getName()} record") - apiDefinition.setType("API" as ApiType) - apiDefinition.setMethod("GET") - apiDefinition.setPath("/${context.getModelClass().getName()}/{id}") - - Map meta = [ - "auth" : false, - "execution": [ - "operationName": "MyViewQuery", - "query" : generate(context).getFirst(), - ] - ] - apiDefinition.setMeta(meta) - apiDefinition.setEnabled(true) - return apiDefinition - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/AiChatConversationFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/ai/AiChatConversationFmRepository.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/AiChatConversationFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/ai/AiChatConversationFmRepository.java index 240c106a..e0f48b40 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/AiChatConversationFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/ai/AiChatConversationFmRepository.java @@ -1,9 +1,9 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.ai; +import dev.flexmodel.common.AbstractRepository; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.AiChatConversation; -import dev.flexmodel.domain.model.ai.AiChatConversationRepository; import dev.flexmodel.query.Direction; import dev.flexmodel.query.Predicate; import dev.flexmodel.session.Session; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/ai/AiChatConversationRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/ai/AiChatConversationRepository.java similarity index 92% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/ai/AiChatConversationRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/ai/AiChatConversationRepository.java index 3fc1cdd3..d07b36fa 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/ai/AiChatConversationRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/ai/AiChatConversationRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.ai; +package dev.flexmodel.ai; import dev.flexmodel.codegen.entity.AiChatConversation; import dev.flexmodel.query.Predicate; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/AiChatMessageFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/ai/AiChatMessageFmRepository.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/AiChatMessageFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/ai/AiChatMessageFmRepository.java index 629798dd..6c454226 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/AiChatMessageFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/ai/AiChatMessageFmRepository.java @@ -1,8 +1,8 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.ai; +import dev.flexmodel.common.AbstractRepository; import jakarta.enterprise.context.ApplicationScoped; import dev.flexmodel.codegen.entity.AiChatMessage; -import dev.flexmodel.domain.model.ai.AiChatMessageRepository; import dev.flexmodel.query.Direction; import dev.flexmodel.query.Predicate; import dev.flexmodel.session.Session; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/ai/AiChatMessageRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/ai/AiChatMessageRepository.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/ai/AiChatMessageRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/ai/AiChatMessageRepository.java index f43fd185..5dbaa021 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/ai/AiChatMessageRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/ai/AiChatMessageRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.ai; +package dev.flexmodel.ai; import dev.flexmodel.codegen.entity.AiChatMessage; import dev.flexmodel.query.Predicate; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/ai/AiChatService.java b/flexmodel-server/src/main/java/dev/flexmodel/ai/AiChatService.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/ai/AiChatService.java rename to flexmodel-server/src/main/java/dev/flexmodel/ai/AiChatService.java index d0b26a9c..f4fbe3ba 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/ai/AiChatService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/ai/AiChatService.java @@ -1,10 +1,10 @@ -package dev.flexmodel.domain.model.ai; +package dev.flexmodel.ai; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.AiChatConversation; import dev.flexmodel.codegen.entity.AiChatMessage; -import dev.flexmodel.shared.SessionContextHolder; +import dev.flexmodel.common.SessionContextHolder; import java.time.LocalDateTime; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/AiResource.java b/flexmodel-server/src/main/java/dev/flexmodel/ai/AiResource.java similarity index 85% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/AiResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/ai/AiResource.java index 6166bbca..3b443852 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/AiResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/ai/AiResource.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.ai; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -11,16 +11,15 @@ import jakarta.ws.rs.sse.Sse; import jakarta.ws.rs.sse.SseEventSink; import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.application.AiApplicationService; import dev.flexmodel.codegen.entity.AiChatConversation; import dev.flexmodel.codegen.entity.AiChatMessage; -import dev.flexmodel.domain.model.ai.llm.FlexmodelChatService; -import dev.flexmodel.interfaces.rest.response.ChatChoiceDelta; -import dev.flexmodel.interfaces.rest.response.ChatDelta; -import dev.flexmodel.interfaces.rest.response.ChatResponseDelta; -import dev.flexmodel.shared.SessionContextHolder; -import dev.flexmodel.shared.utils.JsonUtils; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.ai.llm.FlexmodelChatService; +import dev.flexmodel.common.config.web.response.ChatChoiceDelta; +import dev.flexmodel.common.config.web.response.ChatDelta; +import dev.flexmodel.common.config.web.response.ChatResponseDelta; +import dev.flexmodel.common.SessionContextHolder; +import dev.flexmodel.common.utils.JsonUtils; +import dev.flexmodel.common.utils.StringUtils; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -37,7 +36,7 @@ public class AiResource { Sse sse; @Inject - AiApplicationService aiApplicationService; + AiService aiService; @Inject FlexmodelChatService flexmodelChatService; @@ -48,27 +47,27 @@ public class AiResource { @Produces(MediaType.APPLICATION_JSON) public AiChatConversation createConversation(CreateConversationRequest request) { String title = request != null && request.title != null && !request.title.isBlank() ? request.title : "New Chat"; - return aiApplicationService.createConversation(title); + return aiService.createConversation(title); } @GET @Path("/chat/conversations") @Produces(MediaType.APPLICATION_JSON) public List getAllConversations() { - return aiApplicationService.getAllConversations(); + return aiService.getAllConversations(); } @GET @Path("/chat/conversations/{id}") @Produces(MediaType.APPLICATION_JSON) public AiChatConversation getConversation(@PathParam("id") String id) { - return aiApplicationService.getConversationById(id); + return aiService.getConversationById(id); } @DELETE @Path("/chat/conversations/{id}") public void deleteConversation(@PathParam("id") String id) { - aiApplicationService.deleteConversation(id); + aiService.deleteConversation(id); } @POST @@ -81,13 +80,13 @@ public Response sendMessage(SendMessageRequest request, @Context SseEventSink ev String projectId = SessionContextHolder.getProjectId(); // 会话不存在则创建会话 String conversationId = StringUtils.isBlank(request.conversationId) ? - aiApplicationService.createConversation(request.content).getId() : request.conversationId; + aiService.createConversation(request.content).getId() : request.conversationId; AiChatMessage userMsg = new AiChatMessage(); userMsg.setRole("user"); userMsg.setContent(request.content); userMsg.setConversationId(conversationId); userMsg.setProjectId(projectId); - aiApplicationService.saveMessage(userMsg); + aiService.saveMessage(userMsg); String requestId = UUID.randomUUID().toString(); try { flexmodelChatService.chat(conversationId, request.content) @@ -104,7 +103,7 @@ public Response sendMessage(SendMessageRequest request, @Context SseEventSink ev aiMsg.setContent(chatResponse.aiMessage().text()); aiMsg.setConversationId(conversationId); aiMsg.setProjectId(projectId); - aiApplicationService.saveMessage(aiMsg); + aiService.saveMessage(aiMsg); } sendDoneEvent(eventSink); }) diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/AiApplicationService.java b/flexmodel-server/src/main/java/dev/flexmodel/ai/AiService.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/application/AiApplicationService.java rename to flexmodel-server/src/main/java/dev/flexmodel/ai/AiService.java index fd0bab39..61fbd10d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/AiApplicationService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/ai/AiService.java @@ -1,15 +1,14 @@ -package dev.flexmodel.application; +package dev.flexmodel.ai; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.AiChatConversation; import dev.flexmodel.codegen.entity.AiChatMessage; -import dev.flexmodel.domain.model.ai.AiChatService; import java.util.List; @ApplicationScoped -public class AiApplicationService { +public class AiService { @Inject AiChatService aiChatService; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/llm/ChatMemoryConfig.java b/flexmodel-server/src/main/java/dev/flexmodel/ai/config/ChatMemoryConfig.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/llm/ChatMemoryConfig.java rename to flexmodel-server/src/main/java/dev/flexmodel/ai/config/ChatMemoryConfig.java index ee615e39..c18c6fc8 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/llm/ChatMemoryConfig.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/ai/config/ChatMemoryConfig.java @@ -1,4 +1,4 @@ -package dev.flexmodel.infrastructure.llm; +package dev.flexmodel.ai.config; import dev.langchain4j.memory.ChatMemory; import dev.langchain4j.memory.chat.MessageWindowChatMemory; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/llm/FlexmodelChatMemoryStore.java b/flexmodel-server/src/main/java/dev/flexmodel/ai/config/FlexmodelChatMemoryStore.java similarity index 97% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/llm/FlexmodelChatMemoryStore.java rename to flexmodel-server/src/main/java/dev/flexmodel/ai/config/FlexmodelChatMemoryStore.java index c447c603..9b6708f3 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/llm/FlexmodelChatMemoryStore.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/ai/config/FlexmodelChatMemoryStore.java @@ -1,4 +1,4 @@ -package dev.flexmodel.infrastructure.llm; +package dev.flexmodel.ai.config; import dev.langchain4j.data.message.ChatMessage; import dev.langchain4j.data.message.ChatMessageJsonCodec; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/ai/llm/FlexmodelChatService.java b/flexmodel-server/src/main/java/dev/flexmodel/ai/llm/FlexmodelChatService.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/ai/llm/FlexmodelChatService.java rename to flexmodel-server/src/main/java/dev/flexmodel/ai/llm/FlexmodelChatService.java index 22eb7ee9..1a87f562 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/ai/llm/FlexmodelChatService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/ai/llm/FlexmodelChatService.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.ai.llm; +package dev.flexmodel.ai.llm; import dev.langchain4j.service.*; import io.quarkiverse.langchain4j.RegisterAiService; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/ai/llm/ModelingTool.java b/flexmodel-server/src/main/java/dev/flexmodel/ai/llm/ModelingTool.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/ai/llm/ModelingTool.java rename to flexmodel-server/src/main/java/dev/flexmodel/ai/llm/ModelingTool.java index bafaff84..c877e40d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/ai/llm/ModelingTool.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/ai/llm/ModelingTool.java @@ -1,11 +1,11 @@ -package dev.flexmodel.domain.model.ai.llm; +package dev.flexmodel.ai.llm; import dev.langchain4j.agent.tool.P; import dev.langchain4j.agent.tool.Tool; import io.smallrye.common.annotation.NonBlocking; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import dev.flexmodel.domain.model.modeling.ModelService; +import dev.flexmodel.modeling.ModelService; import dev.flexmodel.model.SchemaObject; import java.util.List; @@ -66,7 +66,7 @@ public String getModelByName(@P("项目ID") String projectId, @P("数据源名 } try { return modelService.findModel(projectId, datasourceName.trim(), modelName.trim()) - .map(SchemaObject::getIdl) + .map(SchemaObject::getFml) .orElse("No model exists"); } catch (Exception e) { return String.format("Error retrieving model from datasource '%s': %s", datasourceName, e.getMessage()); @@ -74,14 +74,14 @@ public String getModelByName(@P("项目ID") String projectId, @P("数据源名 } @NonBlocking - @Tool("在指定数据源下面执行IDL语句") - public String modelingByIdl(@P("项目ID") String projectId, @P("数据源名称") String datasourceName, @P("模型IDL") String idl) { + @Tool("在指定数据源下面执行FML语句") + public String modelingByFml(@P("项目ID") String projectId, @P("数据源名称") String datasourceName, @P("模型FML") String fml) { if (datasourceName == null || datasourceName.trim().isEmpty()) { datasourceName = "dev_test"; // default datasource } - String replacedIdl = idl.replaceAll("\n", ""); + String replacedFml = fml.replaceAll("\n", ""); try { - modelService.importModels(projectId, datasourceName, replacedIdl, "idl"); + modelService.importModels(projectId, datasourceName, replacedFml, "fml"); // success return "success"; } catch (Exception e) { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ApiLogFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/api/ApiLogFmRepository.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ApiLogFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/api/ApiLogFmRepository.java index 52f53376..e9afd29d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ApiLogFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/api/ApiLogFmRepository.java @@ -1,10 +1,8 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.api; +import dev.flexmodel.common.AbstractRepository; import jakarta.enterprise.context.ApplicationScoped; import dev.flexmodel.codegen.entity.ApiRequestLog; -import dev.flexmodel.domain.model.api.ApiRequestLogRepository; -import dev.flexmodel.domain.model.api.LogApiRank; -import dev.flexmodel.domain.model.api.LogStat; import dev.flexmodel.query.Direction; import dev.flexmodel.query.Predicate; import dev.flexmodel.query.Query; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/ApiLogResource.java b/flexmodel-server/src/main/java/dev/flexmodel/api/ApiLogResource.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/ApiLogResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/api/ApiLogResource.java index 2b9e1400..20716431 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/ApiLogResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/api/ApiLogResource.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.api; import jakarta.inject.Inject; import jakarta.ws.rs.*; @@ -13,11 +13,9 @@ import org.eclipse.microprofile.openapi.annotations.parameters.Parameter; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.ApiRuntimeApplicationService; -import dev.flexmodel.application.dto.LogStatResponse; -import dev.flexmodel.application.dto.PageDTO; +import dev.flexmodel.api.dto.LogStatResponse; +import dev.flexmodel.common.dto.PageDTO; import dev.flexmodel.codegen.entity.ApiRequestLog; -import dev.flexmodel.domain.model.api.LogStat; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -32,7 +30,7 @@ public class ApiLogResource { @Inject - ApiRuntimeApplicationService apiRuntimeApplicationService; + ApiRequestLogService apiRequestLogService; @Parameter(name = "current", description = "当前页,默认值:1", examples = {@ExampleObject(value = "1")}, in = ParameterIn.QUERY) @Parameter(name = "pageSize", description = "第几页,默认值:15", examples = {@ExampleObject(value = "15")}, in = ParameterIn.QUERY) @@ -63,7 +61,7 @@ public PageDTO findApiLogs(@PathParam("projectId") String project @QueryParam("isSuccess") Boolean isSuccess ) { RequestResult result = parseQuery(dateRange, isSuccess); - return apiRuntimeApplicationService.findApiLogs(projectId, page, size, keyword, result.startDate(), result.endDate(), isSuccess); + return apiRequestLogService.findApiLogs(projectId, page, size, keyword, result.startDate(), result.endDate(), isSuccess); } @Parameter(name = "keyword", description = "关键字", in = ParameterIn.QUERY) @@ -88,7 +86,7 @@ public LogStatResponse stat(@PathParam("projectId") String projectId, @QueryParam("dateRange") String dateRange, @QueryParam("isSuccess") Boolean isSuccess) { RequestResult result = parseQuery(dateRange, isSuccess); - return apiRuntimeApplicationService.stat(projectId, keyword, result.startDate(), result.endDate(), isSuccess); + return apiRequestLogService.stat(projectId, keyword, result.startDate(), result.endDate(), isSuccess); } private static RequestResult parseQuery(String dateRange, Boolean isSuccess) { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiRateLimiterHolder.java b/flexmodel-server/src/main/java/dev/flexmodel/api/ApiRateLimiterHolder.java similarity index 97% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiRateLimiterHolder.java rename to flexmodel-server/src/main/java/dev/flexmodel/api/ApiRateLimiterHolder.java index b85961d2..adfe501b 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiRateLimiterHolder.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/api/ApiRateLimiterHolder.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.api; +package dev.flexmodel.api; import lombok.Getter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiRequestLogRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/api/ApiRequestLogRepository.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiRequestLogRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/api/ApiRequestLogRepository.java index 5a2d85e0..a5c3456f 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiRequestLogRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/api/ApiRequestLogRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.api; +package dev.flexmodel.api; import dev.flexmodel.codegen.entity.ApiRequestLog; import dev.flexmodel.query.Predicate; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/api/ApiRequestLogService.java b/flexmodel-server/src/main/java/dev/flexmodel/api/ApiRequestLogService.java new file mode 100644 index 00000000..1f7f15f7 --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/api/ApiRequestLogService.java @@ -0,0 +1,151 @@ +package dev.flexmodel.api; + +import dev.flexmodel.api.dto.LogStatResponse; +import dev.flexmodel.common.dto.PageDTO; +import dev.flexmodel.query.Expressions; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.context.control.ActivateRequestContext; +import jakarta.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import dev.flexmodel.codegen.entity.ApiRequestLog; +import dev.flexmodel.query.Predicate; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static dev.flexmodel.query.Expressions.field; + +/** + * @author cjbi + */ +@Slf4j +@ApplicationScoped +@ActivateRequestContext +public class ApiRequestLogService { + + @Inject + ApiRequestLogRepository apiLogRepository; + + public PageDTO findApiLogs(String projectId, int current, int pageSize, String keyword, LocalDateTime startDate, LocalDateTime endDate, Boolean isSuccess) { + List list = find(projectId, getCondition(keyword, startDate, endDate, isSuccess), current, pageSize); + long total = count(projectId, getCondition(keyword, startDate, endDate, isSuccess)); + return new PageDTO<>(list, total); + } + + public LogStatResponse stat(String projectId, String keyword, LocalDateTime startDate, LocalDateTime endDate, Boolean isSuccess) { + + LogStatResponse.ApiChart statDTO = null; + List dateList = new ArrayList<>(); + String fmt = "yyyy-MM-dd HH:00:00"; + if (startDate == null) { + startDate = LocalDateTime.now().minusDays(7); + } + if (endDate == null) { + endDate = LocalDateTime.now(); + } + if (ChronoUnit.DAYS.between(startDate, endDate) <= 1) { + fmt = "yyyy-MM-dd HH:00:00"; + LocalDateTime currentTime = startDate; + while (!currentTime.isAfter(endDate)) { + dateList.add(currentTime.format(DateTimeFormatter.ofPattern(fmt))); + currentTime = currentTime.plusHours(1); + } + } else if (ChronoUnit.DAYS.between(startDate, endDate) > 1 && ChronoUnit.DAYS.between(startDate, endDate) <= 7) { + fmt = "yyyy-MM-dd"; + LocalDateTime currentTime = startDate; + while (!currentTime.isAfter(endDate)) { + dateList.add(currentTime.format(DateTimeFormatter.ofPattern(fmt))); + currentTime = currentTime.plusDays(1); + } + + } else if (ChronoUnit.DAYS.between(startDate, endDate) > 7 && ChronoUnit.DAYS.between(startDate, endDate) <= 31) { + fmt = "yyyy-MM-dd"; + LocalDateTime currentTime = startDate; + while (!currentTime.isAfter(endDate)) { + dateList.add(currentTime.format(DateTimeFormatter.ofPattern(fmt))); + currentTime = currentTime.plusDays(1); + } + } else if (ChronoUnit.DAYS.between(startDate, endDate) > 31 && ChronoUnit.DAYS.between(startDate, endDate) <= 365) { + fmt = "yyyy-MM"; + LocalDateTime currentTime = startDate; + while (!currentTime.isAfter(endDate)) { + dateList.add(currentTime.format(DateTimeFormatter.ofPattern(fmt))); + currentTime = currentTime.plusMonths(1); + } + } else { + fmt = "yyyy"; + LocalDateTime currentTime = startDate; + while (!currentTime.isAfter(endDate)) { + dateList.add(currentTime.format(DateTimeFormatter.ofPattern(fmt))); + currentTime = currentTime.plusYears(1); + } + } + + Predicate condition = getCondition(keyword, startDate, endDate, isSuccess); + + Map successMap = stat(projectId, condition.and(field(ApiRequestLog::getIsSuccess).eq(true)), fmt).stream().collect(Collectors.toMap(LogStat::getDate, LogStat::getTotal)); + Map failMap = stat(projectId, condition.and(field(ApiRequestLog::getIsSuccess).eq(false)), fmt).stream().collect(Collectors.toMap(LogStat::getDate, LogStat::getTotal)); + statDTO = new LogStatResponse.ApiChart(); + List successData = new ArrayList<>(); + List failData = new ArrayList<>(); + for (String date : dateList) { + successData.add(successMap.getOrDefault(date, 0L)); + failData.add(failMap.getOrDefault(date, 0L)); + } + statDTO.setDateList(dateList); + statDTO.setSuccessData(successData); + statDTO.setFailData(failData); + + List stat = stat(projectId, condition, fmt); + + List apiRankList = ranking(projectId, condition); + + return LogStatResponse.builder().apiStatList(stat).apiRankingList(apiRankList).apiChart(statDTO).build(); + } + + private static Predicate getCondition(String keyword, LocalDateTime startDate, LocalDateTime endDate, Boolean isSuccess) { + Predicate condition = Expressions.TRUE; + if (keyword != null) { + condition = condition.and(field(ApiRequestLog::getRequestBody).contains(keyword)); + } + if (startDate != null && endDate != null) { + condition = condition.and(field(ApiRequestLog::getCreatedAt).between(startDate, endDate)); + } + if (isSuccess != null) { + condition = condition.and(field(ApiRequestLog::getIsSuccess).eq(isSuccess)); + } + return condition; + } + + public ApiRequestLog create(ApiRequestLog apiRequestLog) { + apiRequestLog.setCreatedAt(LocalDateTime.now()); + return apiLogRepository.save(apiRequestLog); + } + + public List find(String projectId, Predicate filter, Integer current, Integer pageSize) { + return apiLogRepository.find(projectId, filter, current, pageSize); + } + + public long count(String projectId, Predicate filter) { + return apiLogRepository.count(projectId, filter); + } + + public List stat(String projectId, Predicate filter, String fmt) { + return apiLogRepository.stat(projectId, filter, fmt); + } + + public List ranking(String projectId, Predicate filter) { + return apiLogRepository.ranking(projectId, filter); + } + + public void purgeOldLogs(int maxDays) { + log.info("Purging old logs older than {} days", maxDays); + LocalDateTime purgeDate = LocalDateTime.now().minusDays(maxDays); + apiLogRepository.delete(field(ApiRequestLog::getCreatedAt).lte(purgeDate)); + } +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/GraphQLManger.java b/flexmodel-server/src/main/java/dev/flexmodel/api/GraphQLManager.java similarity index 87% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/GraphQLManger.java rename to flexmodel-server/src/main/java/dev/flexmodel/api/GraphQLManager.java index df65cbe4..227c452d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/GraphQLManger.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/api/GraphQLManager.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.api; +package dev.flexmodel.api; import com.cronutils.utils.StringUtils; import graphql.ExecutionInput; @@ -17,21 +17,14 @@ * @author cjbi */ @ApplicationScoped -public class GraphQLManger { +public class GraphQLManager { - private GraphQL defaultGraphql; private final Map tenantGraphqlMap = new HashMap<>(); public GraphQL getGraphQL(String projectId) { - if (StringUtils.isEmpty(projectId)) { - return defaultGraphql; - } return tenantGraphqlMap.get(projectId); } - public void addDefaultGraphQL(GraphQL graphQL) { - defaultGraphql = graphQL; - } public void addGraphQL(String projectId, GraphQL graphQL) { tenantGraphqlMap.put(projectId, graphQL); diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/GraphQLResource.java b/flexmodel-server/src/main/java/dev/flexmodel/api/GraphQLResource.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/GraphQLResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/api/GraphQLResource.java index b6ea39cf..03f55a62 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/GraphQLResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/api/GraphQLResource.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.api; import graphql.ExecutionResult; import jakarta.inject.Inject; @@ -8,7 +8,6 @@ import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.domain.model.api.GraphQLManger; import java.util.Map; @@ -20,7 +19,7 @@ public class GraphQLResource { @Inject - GraphQLManger graphQLApplicationService; + GraphQLManager graphQLApplicationService; @Operation(summary = "执行GraphQL查询") @POST diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/LogApiRank.java b/flexmodel-server/src/main/java/dev/flexmodel/api/LogApiRank.java similarity index 79% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/LogApiRank.java rename to flexmodel-server/src/main/java/dev/flexmodel/api/LogApiRank.java index 4360240b..e73e81c6 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/LogApiRank.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/api/LogApiRank.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.api; +package dev.flexmodel.api; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/LogStat.java b/flexmodel-server/src/main/java/dev/flexmodel/api/LogStat.java similarity index 79% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/LogStat.java rename to flexmodel-server/src/main/java/dev/flexmodel/api/LogStat.java index ee4a051f..d2856696 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/LogStat.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/api/LogStat.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.api; +package dev.flexmodel.api; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/api/consumer/GraphQLEventConsumer.java b/flexmodel-server/src/main/java/dev/flexmodel/api/consumer/GraphQLEventConsumer.java new file mode 100644 index 00000000..d44ddb92 --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/api/consumer/GraphQLEventConsumer.java @@ -0,0 +1,73 @@ +package dev.flexmodel.api.consumer; + +import dev.flexmodel.graphql.FlexmodelGraphQL; +import io.quarkus.runtime.StartupEvent; +import io.quarkus.vertx.ConsumeEvent; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import dev.flexmodel.codegen.entity.Project; +import dev.flexmodel.api.GraphQLManager; +import dev.flexmodel.api.dto.GraphQLRefreshEvent; +import dev.flexmodel.project.ProjectService; +import dev.flexmodel.session.SessionFactory; + +import java.util.List; +import java.util.Map; + +import static java.util.stream.Collectors.*; + +/** + * 监听GraphQL变更事件 + * @author cjbi + */ +@Slf4j +@ApplicationScoped +public class GraphQLEventConsumer { + + @Inject + SessionFactory sf; + @Inject + GraphQLManager graphQLManger; + @Inject + ProjectService projectService; + + public void handle(@Observes StartupEvent startupEvent) { + consume(new GraphQLRefreshEvent()); + } + + @ConsumeEvent("graphql.refresh") + public void consume(GraphQLRefreshEvent event) { + long beginTime = System.currentTimeMillis(); + log.info("Received graphql message"); + List projects = projectService.findProjects(); + for (Project project : projects) { + refreshProject(project); + } + log.info("========== GraphQL init successful in {} ms!", System.currentTimeMillis() - beginTime); + } + + /** + * 刷新单个项目的 GraphQL Schema。 + * 用于新项目创建后同步注册 GraphQL,避免全量刷新。 + * + * @param project 项目 + */ + public void refreshProject(Project project) { + try { + String schemaName = project.getDatabaseName(); + log.info("Refreshing GraphQL for project '{}', schemaName='{}'", project.getId(), schemaName); + + FlexmodelGraphQL fg = new FlexmodelGraphQL(); + graphQLManger.addGraphQL( + project.getId(), + fg.generateGraphQLWithSchemaObject(sf, "system") + ); + log.info("GraphQL schema generated for project '{}', models={}", project.getId(), sf.getModels(schemaName).size()); + } catch (Exception e) { + log.warn("Failed to generate GraphQL for project '{}': {}", project.getId(), e.getMessage(), e); + } + } + +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/consumer/LogEventConsumer.java b/flexmodel-server/src/main/java/dev/flexmodel/api/consumer/LogEventConsumer.java similarity index 81% rename from flexmodel-server/src/main/java/dev/flexmodel/application/consumer/LogEventConsumer.java rename to flexmodel-server/src/main/java/dev/flexmodel/api/consumer/LogEventConsumer.java index 5ddc3856..bedfdbee 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/consumer/LogEventConsumer.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/api/consumer/LogEventConsumer.java @@ -1,10 +1,10 @@ -package dev.flexmodel.application.consumer; +package dev.flexmodel.api.consumer; import io.quarkus.vertx.ConsumeEvent; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.ApiRequestLog; -import dev.flexmodel.domain.model.api.ApiRequestLogService; +import dev.flexmodel.api.ApiRequestLogService; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/GraphQLRefreshEvent.java b/flexmodel-server/src/main/java/dev/flexmodel/api/dto/GraphQLRefreshEvent.java similarity index 75% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/GraphQLRefreshEvent.java rename to flexmodel-server/src/main/java/dev/flexmodel/api/dto/GraphQLRefreshEvent.java index fe823857..21cd4d6d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/GraphQLRefreshEvent.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/api/dto/GraphQLRefreshEvent.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.api.dto; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/LogStatResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/api/dto/LogStatResponse.java similarity index 78% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/LogStatResponse.java rename to flexmodel-server/src/main/java/dev/flexmodel/api/dto/LogStatResponse.java index fdb5ecee..f62a38a2 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/LogStatResponse.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/api/dto/LogStatResponse.java @@ -1,8 +1,8 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.api.dto; import lombok.*; -import dev.flexmodel.domain.model.api.LogApiRank; -import dev.flexmodel.domain.model.api.LogStat; +import dev.flexmodel.api.LogApiRank; +import dev.flexmodel.api.LogStat; import java.util.ArrayList; import java.util.List; @@ -16,7 +16,9 @@ @NoArgsConstructor @Builder public class LogStatResponse { + @Builder.Default private List apiStatList = new ArrayList<>(); + @Builder.Default private List apiRankingList = new ArrayList<>(); private ApiChart apiChart; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/ApiDefinitionApplicationService.java b/flexmodel-server/src/main/java/dev/flexmodel/application/ApiDefinitionApplicationService.java deleted file mode 100644 index af92e2ba..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/ApiDefinitionApplicationService.java +++ /dev/null @@ -1,148 +0,0 @@ -package dev.flexmodel.application; - -import io.vertx.mutiny.core.eventbus.EventBus; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.transaction.Transactional; -import dev.flexmodel.*; -import dev.flexmodel.application.dto.ApiDefinitionTreeDTO; -import dev.flexmodel.application.dto.GenerateAPIsDTO; -import dev.flexmodel.application.dto.GraphQLRefreshEvent; -import dev.flexmodel.codegen.GenerationContext; -import dev.flexmodel.codegen.ModelClass; -import dev.flexmodel.codegen.entity.ApiDefinition; -import dev.flexmodel.codegen.entity.ApiDefinitionHistory; -import dev.flexmodel.codegen.enumeration.ApiType; -import dev.flexmodel.domain.model.api.ApiDefinitionService; -import dev.flexmodel.model.EntityDefinition; -import dev.flexmodel.session.Session; -import dev.flexmodel.session.SessionFactory; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @author cjbi - */ -@ApplicationScoped -public class ApiDefinitionApplicationService { - - @Inject - ApiDefinitionService apiDefinitionService; - - @Inject - SessionFactory sessionFactory; - - @Inject - EventBus eventBus; - - private static final Map templateMap = new HashMap<>(); - - static { - templateMap.put("list", new ListApiDefinitionGenerator()); - templateMap.put("pagination", new PaginationApiDefinitionGenerator()); - templateMap.put("view", new ViewApiDefinitionGenerator()); - templateMap.put("create", new CreateApiDefinitionGenerator()); - templateMap.put("update", new UpdateApiDefinitionGenerator()); - templateMap.put("delete", new DeleteApiDefinitionGenerator()); - - } - - public List findApiDefinitionTree(String projectId) { - List list = apiDefinitionService.findList(projectId); - List root = list.stream() - .filter(apiDefinition -> apiDefinition.getParentId() == null) - .map(ApiDefinitionTreeDTO::new).toList(); - for (ApiDefinitionTreeDTO treeDTO : root) { - treeDTO.setChildren(getChildren(treeDTO, list)); - } - return root; - } - - /** - * 查询API定义历史 - * - * @param projectId - * @param apiDefinitionId - * @return - */ - public List findApiDefinitionHistories(String projectId, String apiDefinitionId) { - return apiDefinitionService.findApiDefinitionHistories(projectId, apiDefinitionId); - } - - private List getChildren(ApiDefinitionTreeDTO treeDTO, List list) { - List result = new ArrayList<>(); - for (ApiDefinition apiDefinition : list) { - if (treeDTO.getId().equals(apiDefinition.getParentId())) { - ApiDefinitionTreeDTO dto = new ApiDefinitionTreeDTO(apiDefinition); - dto.setChildren(getChildren(dto, list)); - result.add(dto); - } - } - return result; - } - - public ApiDefinition createApiDefinition(String projectId, ApiDefinition apiDefinition) { - return apiDefinitionService.create(apiDefinition); - } - - public ApiDefinition updateApiDefinition(String projectId, ApiDefinition apiDefinition) { - return apiDefinitionService.update(apiDefinition); - } - - public void deleteApiDefinition(String projectId, String id) { - apiDefinitionService.delete(projectId, id); - } - - @Transactional - public void generateAPIs(String projectId, GenerateAPIsDTO dto) { - List generateAPIs = dto.getGenerateAPIs(); - try (Session session = sessionFactory.createSession(dto.getDatasourceName())) { - EntityDefinition entity = (EntityDefinition) session.schema().getModel(dto.getModelName()); - ApiDefinition apiFolder = createApiFolder(projectId, dto); - for (String type : generateAPIs) { - ApiDefinitionGenerator apiDefinitionGenerator = templateMap.get(type); - if (apiDefinitionGenerator != null) { - ModelClass modelClass = ModelClass.buildModelClass(null, dto.getDatasourceName(), entity); - GenerationContext generationContext = new GenerationContext(); - generationContext.setModelClass(modelClass); - generationContext.putVariable("idFieldOfPath", dto.getIdFieldOfPath()); - generationContext.putVariable("apiParentId", apiFolder.getId()); - ApiDefinition apiDefinition = apiDefinitionGenerator.createApiDefinition(projectId, generationContext); - apiDefinition.setProjectId(projectId); - apiDefinitionService.create(apiDefinition); - } - } - } - eventBus.publish("graphql.refresh", new GraphQLRefreshEvent()); - } - - private ApiDefinition createApiFolder(String projectId, GenerateAPIsDTO dto) { - ApiDefinition folder = new ApiDefinition(); - folder.setParentId(null); - folder.setMethod(null); - folder.setPath(null); - folder.setName(dto.getApiFolder()); - folder.setEnabled(false); - folder.setType(ApiType.FOLDER); - folder.setProjectId(projectId); - return apiDefinitionService.create(folder); - } - - public ApiDefinition findApiDefinition(String projectId, String id) { - return apiDefinitionService.findApiDefinition(projectId, id); - } - - public ApiDefinitionHistory restoreApiDefinition(String projectId, String historyId) { - ApiDefinitionHistory apiDefinitionHistory = apiDefinitionService.findApiDefinitionHistory(projectId, historyId); - if (apiDefinitionHistory != null) { - ApiDefinition apiDefinition = JsonUtils.convertValue(apiDefinitionHistory, ApiDefinition.class); - apiDefinition.setId(apiDefinitionHistory.getApiDefinitionId()); - apiDefinition.setProjectId(projectId); - apiDefinitionService.update(apiDefinition); - } - return apiDefinitionHistory; - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/ApiRuntimeApplicationService.java b/flexmodel-server/src/main/java/dev/flexmodel/application/ApiRuntimeApplicationService.java deleted file mode 100644 index 0a4e9249..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/ApiRuntimeApplicationService.java +++ /dev/null @@ -1,482 +0,0 @@ -package dev.flexmodel.application; - -import dev.flexmodel.domain.model.api.*; -import graphql.ExecutionResult; -import io.netty.handler.codec.http.HttpResponseStatus; -import io.vertx.core.MultiMap; -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.http.HttpServerResponse; -import io.vertx.ext.web.RoutingContext; -import io.vertx.mutiny.core.eventbus.EventBus; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.context.control.ActivateRequestContext; -import jakarta.inject.Inject; -import jakarta.ws.rs.core.Request; -import org.slf4j.Logger; -import dev.flexmodel.application.consumer.SettingsEventConsumer; -import dev.flexmodel.application.dto.LogStatResponse; -import dev.flexmodel.application.dto.PageDTO; -import dev.flexmodel.domain.model.api.execution.ExecutionStrategy; -import dev.flexmodel.domain.model.api.execution.ExecutionStrategyFactory; -import dev.flexmodel.codegen.entity.ApiDefinition; -import dev.flexmodel.codegen.entity.ApiRequestLog; -import dev.flexmodel.codegen.entity.IdentityProvider; -import dev.flexmodel.codegen.enumeration.ApiType; -import dev.flexmodel.domain.model.data.DataService; -import dev.flexmodel.domain.model.flow.shared.util.RequestScriptContext; -import dev.flexmodel.domain.model.idp.IdentityProviderService; -import dev.flexmodel.domain.model.idp.provider.Provider; -import dev.flexmodel.domain.model.idp.provider.ValidateParam; -import dev.flexmodel.domain.model.idp.provider.ValidateResult; -import dev.flexmodel.domain.model.modeling.ModelService; -import dev.flexmodel.domain.model.auth.ProjectService; -import dev.flexmodel.domain.model.settings.Settings; -import dev.flexmodel.domain.model.settings.SettingsService; -import dev.flexmodel.query.Expressions; -import dev.flexmodel.query.Predicate; -import dev.flexmodel.shared.FlexmodelConfig; -import dev.flexmodel.shared.SessionContextHolder; -import dev.flexmodel.shared.matchers.UriTemplate; -import dev.flexmodel.shared.utils.JsonUtils; -import dev.flexmodel.shared.utils.PatternMatchUtils; - -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpHeaders; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.time.temporal.ChronoUnit; -import java.util.*; -import java.util.stream.Collectors; - -import static dev.flexmodel.query.Expressions.field; - -/** - * @author cjbi - */ -@SuppressWarnings("all") -@ActivateRequestContext -@ApplicationScoped -public class ApiRuntimeApplicationService { - - private static final Logger log = org.slf4j.LoggerFactory.getLogger(ApiRuntimeApplicationService.class); - @Inject - ApiDefinitionService apiDefinitionService; - - @Inject - IdentityProviderService identityProviderService; - - @Inject - ApiRequestLogService apiLogService; - - @Inject - ModelService modelService; - - @Inject - DataService dataService; - - @Inject - GraphQLManger graphQLManger; - - @Inject - SettingsService settingsService; - - @Inject - EventBus eventBus; - - @Inject - FlexmodelConfig config; - - @Inject - ExecutionStrategyFactory executionStrategyFactory; - - @Inject - Request request; - - @Inject - ProjectService projectService; - - public PageDTO findApiLogs(String projectId, int current, int pageSize, String keyword, LocalDateTime startDate, LocalDateTime endDate, Boolean isSuccess) { - List list = apiLogService.find(projectId, getCondition(keyword, startDate, endDate, isSuccess), current, pageSize); - long total = apiLogService.count(projectId, getCondition(keyword, startDate, endDate, isSuccess)); - return new PageDTO<>(list, total); - } - - public LogStatResponse stat(String projectId, String keyword, LocalDateTime startDate, LocalDateTime endDate, Boolean isSuccess) { - - LogStatResponse.ApiChart statDTO = null; - List dateList = new ArrayList<>(); - String fmt = "yyyy-MM-dd HH:00:00"; - if (startDate == null) { - startDate = LocalDateTime.now().minusDays(7); - } - if (endDate == null) { - endDate = LocalDateTime.now(); - } - if (ChronoUnit.DAYS.between(startDate, endDate) <= 1) { - fmt = "yyyy-MM-dd HH:00:00"; - LocalDateTime currentTime = startDate; - while (!currentTime.isAfter(endDate)) { - dateList.add(currentTime.format(DateTimeFormatter.ofPattern(fmt))); - currentTime = currentTime.plusHours(1); - } - } else if (ChronoUnit.DAYS.between(startDate, endDate) > 1 && ChronoUnit.DAYS.between(startDate, endDate) <= 7) { - fmt = "yyyy-MM-dd"; - LocalDateTime currentTime = startDate; - while (!currentTime.isAfter(endDate)) { - dateList.add(currentTime.format(DateTimeFormatter.ofPattern(fmt))); - currentTime = currentTime.plusDays(1); - } - - } else if (ChronoUnit.DAYS.between(startDate, endDate) > 7 && ChronoUnit.DAYS.between(startDate, endDate) <= 31) { - fmt = "yyyy-MM-dd"; - LocalDateTime currentTime = startDate; - while (!currentTime.isAfter(endDate)) { - dateList.add(currentTime.format(DateTimeFormatter.ofPattern(fmt))); - currentTime = currentTime.plusDays(1); - } - } else if (ChronoUnit.DAYS.between(startDate, endDate) > 31 && ChronoUnit.DAYS.between(startDate, endDate) <= 365) { - fmt = "yyyy-MM"; - LocalDateTime currentTime = startDate; - while (!currentTime.isAfter(endDate)) { - dateList.add(currentTime.format(DateTimeFormatter.ofPattern(fmt))); - currentTime = currentTime.plusMonths(1); - } - } else { - fmt = "yyyy"; - LocalDateTime currentTime = startDate; - while (!currentTime.isAfter(endDate)) { - dateList.add(currentTime.format(DateTimeFormatter.ofPattern(fmt))); - currentTime = currentTime.plusYears(1); - } - } - - Predicate condition = getCondition(keyword, startDate, endDate, isSuccess); - - Map successMap = apiLogService.stat(projectId, condition.and(field(ApiRequestLog::getIsSuccess).eq(true)), fmt).stream().collect(Collectors.toMap(LogStat::getDate, LogStat::getTotal)); - Map failMap = apiLogService.stat(projectId, condition.and(field(ApiRequestLog::getIsSuccess).eq(false)), fmt).stream().collect(Collectors.toMap(LogStat::getDate, LogStat::getTotal)); - statDTO = new LogStatResponse.ApiChart(); - List successData = new ArrayList<>(); - List failData = new ArrayList<>(); - for (String date : dateList) { - successData.add(successMap.getOrDefault(date, 0L)); - failData.add(failMap.getOrDefault(date, 0L)); - } - statDTO.setDateList(dateList); - statDTO.setSuccessData(successData); - statDTO.setFailData(failData); - - List stat = apiLogService.stat(projectId, condition, fmt); - - List apiRankList = apiLogService.ranking(projectId, condition); - - return LogStatResponse.builder().apiStatList(stat).apiRankingList(apiRankList).apiChart(statDTO).build(); - } - - private static Predicate getCondition(String keyword, LocalDateTime startDate, LocalDateTime endDate, Boolean isSuccess) { - Predicate condition = Expressions.TRUE; - if (keyword != null) { - condition = condition.and(field(ApiRequestLog::getRequestBody).contains(keyword)); - } - if (startDate != null && endDate != null) { - condition = condition.and(field(ApiRequestLog::getCreatedAt).between(startDate, endDate)); - } - if (isSuccess != null) { - condition = condition.and(field(ApiRequestLog::getIsSuccess).eq(isSuccess)); - } - return condition; - } - - @SuppressWarnings("all") - public void accept(RoutingContext routingContext) { - log(routingContext, () -> doRequest(routingContext)); - } - - private void doRequest(RoutingContext routingContext) { - boolean isMatching = false; - Map projectIdMap = new UriTemplate("/api/{projectId}/.*").match(new UriTemplate(routingContext.normalizedPath())); - String projectId = projectIdMap.get("projectId"); - SessionContextHolder.setProjectId(projectId); - List apis = apiDefinitionService.findAll(projectId); - Settings settings = settingsService.getSettings(); - // 从apiDefinition处理请求 - for (ApiDefinition apiDefinition : apis) { - if (apiDefinition.getType() != ApiType.API) { - continue; - } - ApiDefinitionMeta meta = JsonUtils.getInstance().convertValue(apiDefinition.getMeta(), ApiDefinitionMeta.class); - UriTemplate uriTemplate = new UriTemplate(config.apiRootPath() + "/{projectId}" + apiDefinition.getPath()); - Map pathParameters = uriTemplate.match(new UriTemplate(routingContext.normalizedPath())); - String method = routingContext.request().method().name(); - if (pathParameters != null && method.equals(apiDefinition.getMethod())) { - // 匹配成功 - isMatching = true; - log.debug("Matched request for api: {}", apiDefinition); - if (isRateLimiting(routingContext, apiDefinition, meta)) return; - boolean isAuth = meta.isAuth(); - if (isAuth) { - String identityProvider = meta.getIdentityProvider(); - checkToken(projectId, routingContext, identityProvider); - } - - ApiDefinitionMeta.Execution execution = meta.getExecution(); - - RequestScriptContext httpScriptContext = buildHttpScriptContext(projectId, routingContext); - try { - // 执行具体类型的请求 - ExecutionStrategy strategy = executionStrategyFactory.getStrategy(execution.getExecutionType()); - strategy.execute(apiDefinition, execution, pathParameters, httpScriptContext); - - int resStatus = httpScriptContext.getResponse().status(); - String resMessage = httpScriptContext.getResponse().message(); - Map resHeaders = httpScriptContext.getResponse().headers(); - Map resBody = httpScriptContext.getResponse().body(); - - // 添加headers - resHeaders.forEach((key, value) -> routingContext.response().putHeader(key, value)); - - routingContext.response() - .setStatusCode(resStatus) - .setStatusMessage(resMessage) - .putHeader("Content-Type", "application/json") - .end(JsonUtils.getInstance().stringify(resBody)); - } catch (Exception e) { - log.error("Execute executionStrategy error: {}", e.getMessage(), e); - sendBadRequestFail(routingContext, e.getMessage(), 500); - return; - } - break; - } - } - - // 从设置中的GraphQL端点处理请求 - if (!isMatching) { - UriTemplate uriTemplate = new UriTemplate(config.apiRootPath() + "/{projectId}" + settings.getSecurity().getGraphqlEndpointPath()); - Map pathParameters = uriTemplate.match(new UriTemplate(routingContext.normalizedPath())); - String method = routingContext.request().method().name(); - if (pathParameters != null && method.equals("POST")) { - isMatching = true; - log.debug("Matched graphql enpoint: {}", config.apiRootPath() + settings.getSecurity().getGraphqlEndpointPath()); - // 匹配成功 - if (isRateLimiting(routingContext, null, null)) return; - String identityProvider = settings.getSecurity().getGraphqlEndpointIdentityProvider(); - // 鉴权 - if (identityProvider != null) { - checkToken(projectId, routingContext, identityProvider); - } - String bodyString = routingContext.body().asString(); - Map body; - try { - body = (Map) JsonUtils.getInstance().parseToObject(bodyString, Map.class); - if (body.get("query") == null) { - sendBadRequestFail(routingContext, "query is required, e.g. { \"query\": \"query MyQuery { dev_test_aggregate_Classes { _count } }\" }", -1); - return; - } - } catch (Exception e) { - log.error("Parse body error: {}", e.getMessage(), e); - routingContext.fail(400); - sendBadRequestFail(routingContext, "Parse body error:" + e.getMessage(), -1); - return; - } - ExecutionResult result = graphQLManger.execute(SessionContextHolder.getProjectId(), (String) body.get("operationName"), (String) body.get("query"), (Map) body.get("variables")); - routingContext.response().putHeader("Content-Type", "application/json").end(JsonUtils.getInstance().stringify(result)); - } - } - - // 从设置中的Proxy处理请求 - if (!isMatching) { - String path = routingContext.request().path(); - for (Settings.Route route : settings.getProxy().getRoutes()) { - if (PatternMatchUtils.simpleMatch(config.apiRootPath() + route.getPath(), path)) { - isMatching = true; - if (isRateLimiting(routingContext, null, null)) return; - String targetUri = route.getTo() + path; - log.debug("Matched request for proxy: {}", targetUri); - // 转发请求 - forwardRequest(targetUri, routingContext.request()); - break; - } - } - } - - // 未找到地址 - if (!isMatching) { - routingContext.next(); - } - } - - private RequestScriptContext buildHttpScriptContext(String projectId, RoutingContext routingContext) { - RequestScriptContext requestScriptContext = new RequestScriptContext(projectId); - - RequestScriptContext.Request request = new RequestScriptContext.Request(routingContext.request().method().name(), - routingContext.normalizedPath(), multiMapToMap(routingContext.request().headers()), - routingContext.body().asPojo(Map.class), - multiMapToMap(routingContext.queryParams())); - requestScriptContext.setRequest(request); - return requestScriptContext; - } - - - private Map multiMapToMap(MultiMap multiMap) { - Map map = new HashMap<>(); - multiMap.forEach((key, value) -> { - map.put(key, value); - }); - return map; - } - - - private void forwardRequest(String targetUri, HttpServerRequest request) { - // 解析请求 URL 和目标地址 - - // 使用 JDK HttpClient 构建请求 - HttpClient client = HttpClient.newHttpClient(); - - // 构建 HttpRequest 请求 - HttpRequest.Builder requestBuilder = HttpRequest.newBuilder().uri(URI.create(targetUri)).method(request.method().toString(), HttpRequest.BodyPublishers.noBody()); - - - // 转发请求的 headers - for (Map.Entry header : request.headers().entries()) { - requestBuilder.header(header.getKey(), header.getValue()); - } - - // 转发请求的 HTTP 方法和 body - request.bodyHandler(body -> { - if (body.length() > 0) { - // 对于有请求体的请求(如 POST, PUT) - requestBuilder.method(request.method().toString(), HttpRequest.BodyPublishers.ofString(body.toString())); - } - - // 创建 HttpRequest - HttpRequest httpRequest = requestBuilder.build(); - - // 发送请求并获取响应 - client.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString()).thenApply(response -> { - // 处理目标服务器的响应并转发回客户端 - HttpServerResponse responseToClient = request.response(); - responseToClient.setStatusCode(response.statusCode()); - HttpHeaders headers = response.headers(); - // 设置 headers - headers.map().forEach((k, v) -> responseToClient.putHeader(k, v)); - // 设置body - responseToClient.end(response.body()); - return null; - }).exceptionally(e -> { - request.response().setStatusCode(500).end("Error forwarding request: " + e.getMessage()); - return null; - }); - }); - } - - private boolean isRateLimiting(RoutingContext routingContext, ApiDefinition apiDefinition, ApiDefinitionMeta meta) { - try { - Settings settings = settingsService.getSettings(); - if (settings.getSecurity().isRateLimitingEnabled()) { - log.debug("Global Rate limiting enabled."); - ApiRateLimiterHolder.ApiRateLimiter apiRateLimiter = ApiRateLimiterHolder.getApiRateLimiter(SettingsEventConsumer.GLOBAL_RATE_LIMIT_KEY, settings.getSecurity().getMaxRequestCount(), settings.getSecurity().getIntervalInSeconds()); - if (!apiRateLimiter.tryAcquire()) { - Map result = new HashMap<>(); - result.put("messasge", "Too many requests."); - result.put("code", -1); - result.put("success", false); - routingContext.response().putHeader("Content-Type", "application/json").end(JsonUtils.getInstance().stringify(result)); - return true; - } - } - boolean rateLimitingEnabled = meta.isRateLimitingEnabled(); - if (rateLimitingEnabled) { - log.debug("Rate limiting enabled for api: {}", apiDefinition); - int maxRequestCount = settings.getSecurity().getMaxRequestCount(); - int intervalInSeconds = settings.getSecurity().getIntervalInSeconds(); - maxRequestCount = meta.getMaxRequestCount(); - intervalInSeconds = meta.getIntervalInSeconds(); - ApiRateLimiterHolder.ApiRateLimiter apiRateLimiter = ApiRateLimiterHolder.getApiRateLimiter(apiDefinition.getMethod() + ":" + apiDefinition.getPath(), maxRequestCount, intervalInSeconds); - if (!apiRateLimiter.tryAcquire()) { - Map result = new HashMap<>(); - result.put("messasge", "Too many requests."); - result.put("code", -1); - result.put("success", false); - routingContext.response().putHeader("Content-Type", "application/json").end(JsonUtils.getInstance().stringify(result)); - return true; - } - } - } catch (Exception e) { - log.error("Rate limiting error: {}", e.getMessage(), e); - } - return false; - } - - private void sendAuthFail(RoutingContext routingContext, ValidateResult validateResult) { - Map result = new HashMap<>(); - result.put("messasge", validateResult.getMessage()); - result.put("code", -1); - result.put("success", validateResult.isSuccess()); - routingContext.response().setStatusCode(HttpResponseStatus.UNAUTHORIZED.code()).putHeader("Content-Type", "application/json").end(JsonUtils.getInstance().stringify(result)); - } - - private void sendNotFoundError(RoutingContext routingContext) { - Map result = new HashMap<>(); - result.put("messasge", "not found"); - result.put("code", -1); - result.put("success", false); - routingContext.response().setStatusCode(HttpResponseStatus.NOT_FOUND.code()).putHeader("Content-Type", "application/json").end(JsonUtils.getInstance().stringify(result)); - } - - private void sendBadRequestFail(RoutingContext routingContext, String msg, Integer code) { - Map result = new HashMap<>(); - result.put("messasge", msg); - result.put("code", code); - result.put("success", false); - routingContext.response().setStatusCode(HttpResponseStatus.BAD_REQUEST.code()).putHeader("Content-Type", "application/json").end(JsonUtils.getInstance().stringify(result)); - } - - public void log(RoutingContext routingContext, Runnable runnable) { - ApiRequestLog apiLog = new ApiRequestLog(); - long beginTime = System.currentTimeMillis(); - try { - apiLog.setHttpMethod(routingContext.request().method().name()); - apiLog.setUrl(routingContext.request().uri()); - apiLog.setPath(apiLog.getHttpMethod() + " " + routingContext.request().path()); - apiLog.setRequestHeaders(routingContext.request().headers()); - apiLog.setClientIp(routingContext.request().remoteAddress().host()); - runnable.run(); - } catch (Exception e) { - apiLog.setIsSuccess(false); - apiLog.setErrorMessage(JsonUtils.getInstance().stringify(e)); - throw e; - } finally { - apiLog.setStatusCode(routingContext.response().getStatusCode()); - apiLog.setResponseTime((int) (System.currentTimeMillis() - beginTime)); - eventBus.send("request.logging", apiLog); - } - - } - - public void checkToken(String projectId, RoutingContext routingContext, String providerName) { - String authorization = Objects.toString(routingContext.request().getHeader("Authorization"), ""); - String token = authorization.replace("Bearer", "").trim(); - if (providerName == null || token == null) { - log.warn("Check token required parameters is null, providerName={}, token={}", providerName, token); - } - IdentityProvider identityProvider = identityProviderService.find(providerName); - if (identityProvider == null) { - log.warn("IdentityProvider is null, providerName={}, token={}", providerName, token); - sendAuthFail(routingContext, new ValidateResult(false, "IdentityProvider is null")); - } - Provider provider = JsonUtils.getInstance().convertValue(identityProvider.getProvider(), Provider.class); - ValidateParam param = new ValidateParam(); - - param.setMethod(routingContext.request().method().name()); - param.setUrl(routingContext.request().path()); - param.setQuery(multiMapToMap(routingContext.request().params())); - param.setHeaders(multiMapToMap(routingContext.request().headers())); - ValidateResult result = provider.validate(projectId, param); - if (!result.isSuccess()) { - sendAuthFail(routingContext, result); - } - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/DataApplicationService.java b/flexmodel-server/src/main/java/dev/flexmodel/application/DataApplicationService.java deleted file mode 100644 index 83fb7ed4..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/DataApplicationService.java +++ /dev/null @@ -1,72 +0,0 @@ -package dev.flexmodel.application; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import dev.flexmodel.application.dto.PageDTO; -import dev.flexmodel.codegen.entity.Project; -import dev.flexmodel.domain.model.auth.ProjectService; -import dev.flexmodel.domain.model.data.DataService; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @author cjbi - */ -@ApplicationScoped -public class DataApplicationService { - - @Inject - DataService dataService; - - @Inject - ProjectService projectService; - - public PageDTO> findPagingRecords(String projectId, - String modelName, - int page, - int size, - String filter, - String sort, - boolean nestedQuery) { - Project project = projectService.findProject(projectId); - String datasourceName = project.getDatabaseName(); - List> list = dataService.findRecords(projectId, datasourceName, modelName, page, size, filter, sort, nestedQuery); - long total = dataService.countRecords(projectId, datasourceName, modelName, filter); - return new PageDTO<>(list, total); - } - - public Map findOneRecord(String projectId, String modelName, String id, boolean nestedQuery) { - Project project = projectService.findProject(projectId); - String datasourceName = project.getDatabaseName(); - return dataService.findOneRecord(projectId, datasourceName, modelName, id, nestedQuery); - } - - public Map createRecord(String projectId, String modelName, Map data) { - Project project = projectService.findProject(projectId); - String datasourceName = project.getDatabaseName(); - return dataService.createRecord(projectId, datasourceName, modelName, data); - } - - public Map updateRecord(String projectId, String modelName, Object id, Map data) { - Project project = projectService.findProject(projectId); - String datasourceName = project.getDatabaseName(); - return dataService.updateRecord(projectId, datasourceName, modelName, id, data); - } - - public void deleteRecord(String projectId, String modelName, Object id) { - Project project = projectService.findProject(projectId); - String datasourceName = project.getDatabaseName(); - dataService.deleteRecord(projectId, datasourceName, modelName, id); - } - - public Map updateRecordIgnoreNull(String projectId, String modelName, String id, Map record) { - Project project = projectService.findProject(projectId); - String datasourceName = project.getDatabaseName(); - Map oldData = dataService.findOneRecord(projectId, datasourceName, modelName, id, false); - Map mergeData = new HashMap<>(oldData); - mergeData.putAll(record); - return dataService.updateRecord(projectId, datasourceName, modelName, id, mergeData); - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/DocumentApplicationService.java b/flexmodel-server/src/main/java/dev/flexmodel/application/DocumentApplicationService.java deleted file mode 100644 index 602c3fd6..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/DocumentApplicationService.java +++ /dev/null @@ -1,496 +0,0 @@ -package dev.flexmodel.application; - -import graphql.language.*; -import graphql.parser.Parser; -import graphql.schema.*; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.JsonUtils; -import dev.flexmodel.codegen.entity.ApiDefinition; -import dev.flexmodel.codegen.entity.Project; -import dev.flexmodel.codegen.enumeration.ApiType; -import dev.flexmodel.domain.model.api.ApiDefinitionMeta; -import dev.flexmodel.domain.model.api.ApiDefinitionService; -import dev.flexmodel.domain.model.api.GraphQLManger; -import dev.flexmodel.domain.model.auth.ProjectService; -import dev.flexmodel.domain.model.modeling.ModelService; -import dev.flexmodel.domain.model.settings.Settings; -import dev.flexmodel.domain.model.settings.SettingsService; -import dev.flexmodel.model.EntityDefinition; -import dev.flexmodel.model.field.RelationField; -import dev.flexmodel.model.field.ScalarType; -import dev.flexmodel.model.field.TypedField; -import dev.flexmodel.shared.FlexmodelConfig; -import dev.flexmodel.shared.SessionContextHolder; -import dev.flexmodel.shared.matchers.UriTemplate; - -import java.util.*; -import java.util.stream.Collectors; - -import static dev.flexmodel.codegen.StringUtils.*; - -/** - * @author cjbi - */ -@ApplicationScoped -@Slf4j -@SuppressWarnings("all") -public class DocumentApplicationService { - - @Inject - ProjectService projectService; - - @Inject - ApiDefinitionService apiDefinitionService; - - @Inject - ModelService modelService; - - @Inject - GraphQLManger graphQLManager; - - @Inject - SettingsService settingsService; - - @Inject - FlexmodelConfig config; - - public static final Map TYPE_MAPPING = new HashMap<>(); - public static final String GRAPHQL_INTERNAL_DIRECTIVE = "internal"; - - static { - TYPE_MAPPING.put("ID", Map.of("type", "string")); - TYPE_MAPPING.put("String", Map.of("type", "string")); - TYPE_MAPPING.put("Int", Map.of("type", "integer", "format", "int32")); - TYPE_MAPPING.put("Float", Map.of("type", "number", "format", "double")); - TYPE_MAPPING.put("Boolean", Map.of("type", "boolean")); - TYPE_MAPPING.put("JSON", Map.of("type", "object")); - } - - public Map getOpenApi(String projectId) { - List apis = apiDefinitionService.findList(projectId); - Map openAPI = new HashMap<>(); - openAPI.put("openapi", "3.0.3"); - openAPI.put("info", buildInfo(projectId)); - openAPI.put("components", buildComponents(apis)); - openAPI.put("servers", List.of(Map.of("url", config.apiRootPath() + "/" + projectId))); - openAPI.put("schemas", List.of("https", "http")); - openAPI.put("tags", buildTags(apis)); - openAPI.put("paths", buildPaths(apis)); - return openAPI; - } - - private Map buildInfo(String projectId) { - Project project = projectService.findProject(projectId); - return Map.of( - "title", project.getName(), - "description", project.getDescription(), - "version:", "0.0.1" - ); - } - - private GraphQLFieldDefinition getGraphQLFieldDefinition(GraphQLSchema graphQLSchema, Field field) { - GraphQLFieldDefinition fieldDefinition = graphQLSchema.getQueryType().getFieldDefinition(field.getName()); - if (fieldDefinition == null) { - fieldDefinition = graphQLSchema.getMutationType().getFieldDefinition(field.getName()); - } - return fieldDefinition; - } - - private String getSanitizeName(ApiDefinition apiDefinition) { - return capitalize(snakeToCamel(sanitize(apiDefinition.getMethod().toLowerCase() + "_" + apiDefinition.getPath()))); - } - - private Map buildSchemas(List apis) { - Map definitions = new HashMap<>(); - String projectId = SessionContextHolder.getProjectId(); - - for (ApiDefinition api : apis) { - try { - if (api.getType() != ApiType.API) { - continue; - } - String sanitizeName = getSanitizeName(api); - ApiDefinitionMeta meta = JsonUtils.convertValue(api.getMeta(), ApiDefinitionMeta.class); - if (meta == null) { - continue; - } - ApiDefinitionMeta.Document document = meta.getDocument(); - if (meta.getDocument() != null) { - parseByJsonSchema(meta, definitions, sanitizeName); - } else { - GraphQLSchema graphQLSchema = graphQLManager.getGraphQL(projectId).getGraphQLSchema(); - parseByGrapQLSchema(meta, definitions, sanitizeName, graphQLSchema); - } - } catch (Exception e) { - log.error("Build api doc error: {}", e.getMessage(), e); - } - - } - return definitions; - } - - /** - * 解析JsonSchema - * - * @param meta - * @param definitions - * @param sanitizeName - */ - private void parseByJsonSchema(ApiDefinitionMeta meta, Map definitions, String sanitizeName) { - ApiDefinitionMeta.DocumentIO input = meta.getDocument().getInput(); - if (input != null) { - Map requestSchema = normalizeJsonSchema(input != null ? input.getSchema() : null); - if (requestSchema != null && !requestSchema.isEmpty()) { - definitions.put(sanitizeName + "Request", requestSchema); - } - } - ApiDefinitionMeta.DocumentIO output = meta.getDocument().getOutput(); - if (output != null) { - Map dataSchema = normalizeJsonSchema(output != null ? output.getSchema() : null); - if (dataSchema != null && !dataSchema.isEmpty()) { - Map responseWrapper = new HashMap<>(); - responseWrapper.put("type", "object"); - Map wrapperProps = new HashMap<>(); - wrapperProps.put("data", dataSchema); - responseWrapper.put("properties", wrapperProps); - definitions.put(sanitizeName + "Response", responseWrapper); - } - } - } - - /** - * 将 JSON Schema 做最小规范化,移除不被 OpenAPI 使用的元数据字段(例如 $schema), - * 其余结构(type/properties/required/items 等)保持透传。 - */ - private Map normalizeJsonSchema(Map schema) { - if (schema == null) { - return null; - } - Map normalized = new HashMap<>(schema); - normalized.remove("$schema"); - return normalized; - } - - private void parseByGrapQLSchema(ApiDefinitionMeta meta, Map definitions, String sanitizeName, GraphQLSchema graphQLSchema) { - ApiDefinitionMeta.Execution execution = meta.getExecution(); - String operationName = execution.getOperationName(); - String query = execution.getQuery(); - Map variables = execution.getVariables(); - Map headers = execution.getHeaders(); - - Parser parser = new Parser(); - Document document = parser.parse(query); - - // 3. 提取变量 - List variableDefinitions = getVariableDefinitions(document); - - Map requestType = new HashMap<>(); - Map properties = new HashMap<>(); - requestType.put("type", "object"); - requestType.put("properties", properties); - for (VariableDefinition variableDefinition : variableDefinitions) { - String variableName = variableDefinition.getName(); - String variableType = variableDefinition.getType().toString(); - Map propertyMap = new HashMap<>(); - properties.put(variableName, TYPE_MAPPING.getOrDefault(variableType, Map.of("type", "string"))); - } - definitions.put(sanitizeName + "Request", requestType); - - // 3. 提取返回参数 - List returnFields = document.getDefinitions().stream() - .filter(def -> def instanceof OperationDefinition) - .flatMap(def -> ((OperationDefinition) def).getSelectionSet().getSelections().stream()) - .filter(selection -> selection instanceof Field) - .map(selection -> (Field) selection) - .collect(Collectors.toList()); - - // 4. 输出返回参数信息 - for (Field field : returnFields) { - GraphQLFieldDefinition fieldDefinition = getGraphQLFieldDefinition(graphQLSchema, field); - if (fieldDefinition == null) { - continue; - } - GraphQLType originType = fieldDefinition.getType(); - boolean isList = false; - if (originType instanceof GraphQLNonNull graphQLNonNull) { - originType = graphQLNonNull.getOriginalWrappedType(); - } - if (originType instanceof GraphQLList graphQLList) { - isList = true; - originType = graphQLList.getOriginalWrappedType(); - } - if (originType instanceof GraphQLNonNull graphQLNonNull) { - originType = graphQLNonNull.getOriginalWrappedType(); - } - - Map responseType = new HashMap<>(); - Map wrapperProperties = new HashMap<>(); - Map typeProperties = new HashMap<>(); - - // 如果有子字段,可以进一步提取 - SelectionSet selectionSet = field.getSelectionSet(); - if (selectionSet != null) { - List subFields = selectionSet.getSelections().stream() - .filter(selection -> selection instanceof Field) - .map(selection -> (Field) selection) - .collect(Collectors.toList()); - for (Field subField : subFields) { - if (originType instanceof GraphQLObjectType) { - GraphQLObjectType objectType = (GraphQLObjectType) originType; - GraphQLFieldDefinition subFieldDefinition = objectType.getFieldDefinition(subField.getName()); - if (subFieldDefinition != null) { - GraphQLOutputType definitionType = subFieldDefinition.getType(); - if (definitionType instanceof GraphQLScalarType graphQLScalarType) { - typeProperties.put(subField.getName(), TYPE_MAPPING.get(graphQLScalarType.getName())); - } else { - log.error("Unkown definitionType: {}, sanitizeName={}", definitionType, sanitizeName); - } - } - } - } - } - - Map returnDataTypeMap = new HashMap<>(); - if (isList) { - returnDataTypeMap.put("type", "array"); - returnDataTypeMap.put("items", Map.of("type", "object", "properties", typeProperties)); - } else { - returnDataTypeMap.put("type", "object"); - returnDataTypeMap.put("properties", typeProperties); - } - wrapperProperties.put("data", returnDataTypeMap); - responseType.put("type", "object"); - responseType.put("properties", wrapperProperties); - definitions.put(sanitizeName + "Response", responseType); - } - } - - /** - * 提取变量 - * - * @param document - * @return - */ - private List getVariableDefinitions(Document document) { - return document.getDefinitions().stream() - .filter(def -> def instanceof OperationDefinition) - .flatMap(def -> ((OperationDefinition) def).getVariableDefinitions().stream() - .filter(f -> f.getDirectives(GRAPHQL_INTERNAL_DIRECTIVE).isEmpty()) - ) - .collect(Collectors.toList()); - } - - private String addModelDefinition(String datasourceName, String modelName, Map definitions) { - Map typeMapping = new HashMap<>(); - typeMapping.put(ScalarType.STRING.getType(), Map.of("type", "string")); - typeMapping.put(ScalarType.INT.getType(), Map.of("type", "integer", "format", "int32")); - typeMapping.put(ScalarType.LONG.getType(), Map.of("type", "integer", "format", "int64")); - typeMapping.put(ScalarType.FLOAT.getType(), Map.of("type", "number", "format", "double")); - typeMapping.put(ScalarType.BOOLEAN.getType(), Map.of("type", "boolean")); -// typeMapping.put("", Map.of("type", "array")); - typeMapping.put(ScalarType.JSON.getType(), Map.of("type", "object")); - EntityDefinition entity = (EntityDefinition) modelService.findModel(SessionContextHolder.getProjectId(), datasourceName, modelName).orElseThrow(); - if (entity == null) { - return null; - } - Map object = new HashMap<>(); - String refModelName = datasourceName + "." + entity.getName(); - if (definitions.containsKey(refModelName)) { - return "#/components/schemas/" + refModelName; - } - definitions.put(refModelName, object); - object.put("type", "object"); - Map properties = new HashMap<>(); - object.put("properties", properties); - for (TypedField field : entity.getFields()) { - if (field instanceof RelationField relationField) { - Map refProp = new HashMap<>(); - refProp.put("type", relationField.isMultiple() ? "array" : "object"); - refProp.put("items", Map.of("$ref", addModelDefinition(datasourceName, relationField.getFrom(), definitions))); - properties.put(field.getName(), refProp); - continue; - } - properties.put(field.getName(), typeMapping.getOrDefault(field.getType(), Map.of("type", "string"))); - } - return "#/components/schemas/" + refModelName; - } - - public Map buildComponents(List apis) { - Map components = new HashMap<>(); - components.put("securitySchemes", Map.of( - "bearerAuth", Map.of( - "type", "apiKey", - "name", "Authorization", - "in", "header" - ) - )); - components.put("schemas", buildSchemas(apis)); - return components; - } - - public List> buildTags(List apis) { - List> tags = new ArrayList<>(); - for (ApiDefinition api : apis) { - if (api.getType() == ApiType.FOLDER) { - Map tag = new HashMap<>(); - tag.put("name", api.getName()); - tag.put("description", api.getName()); - tags.add(tag); - } - } - return tags; - } - - public Map buildPaths(List apis) { - Map paths = new HashMap<>(); - for (ApiDefinition api : apis) { - try { - if (api.getType() != ApiType.API) { - continue; - } - String sanitizeName = getSanitizeName(api); - Map path = new HashMap<>(); - Map content = new HashMap<>(); - String tag = apis.stream() - .filter(a -> a.getId().equals(api.getParentId())) - .map(ApiDefinition::getName) - .findFirst() - .orElse(null); - if (tag != null) { - content.put("tags", List.of(tag)); - } - Map metaMap = (Map) api.getMeta(); - if (metaMap == null || metaMap.isEmpty()) { - continue; - } - ApiDefinitionMeta meta = JsonUtils.convertValue(metaMap, ApiDefinitionMeta.class); - content.put("summary", api.getName()); - content.put("operationId", api.getId()); - - // 接口是否鉴权 - boolean isAuth = meta.isAuth(); - if (isAuth) { - content.put("security", List.of(Map.of("bearerAuth", List.of()))); - } - path.put(api.getMethod().toLowerCase(), content); - if (paths.containsKey(api.getPath())) { - Map existPath = (Map) paths.get(api.getPath()); - existPath.put(api.getMethod().toLowerCase(), content); - } else { - paths.put(api.getPath(), path); - } - - Map responses = new HashMap<>(); - responses.put("200", buildResponse200(api)); - responses.put("400", Map.of("description", "invalid input")); - responses.put("404", Map.of("description", "not found")); - content.put("responses", responses); - - ApiDefinitionMeta.Execution execution = meta.getExecution(); - String operationName = execution.getOperationName(); - String query = execution.getQuery(); - Map variables = execution.getVariables(); - Map headers = execution.getHeaders(); - - if (meta.getExecution().getExecutionType().equals("graphql")) { - Parser parser = new Parser(); - Document document = parser.parse(query); - - boolean supportsBody = !(api.getMethod().equals("GET") || api.getMethod().equals("DELETE")); - content.put("parameters", buildParameters(api, meta, document, supportsBody)); - if (supportsBody) { - content.put("requestBody", - Map.of( - "required", true, - "description", "json body", - "content", - Map.of("application/json", - Map.of("schema", - Map.of("$ref", "#/components/schemas/" + sanitizeName + "Request"))))); - } - } - } catch (Exception e) { - log.error("Build api doc error: {}", e.getMessage(), e); - } - - } - // if graphql endpoint is enabled - String projectId = apis.isEmpty() ? "" : apis.get(0).getProjectId(); - Settings settings = settingsService.getSettings(); - Map graphqlPath = new HashMap<>(); - Map typeProperties = new HashMap<>(); - typeProperties.put("query", Map.of("type", "string")); - typeProperties.put("operationName", Map.of("type", "string")); - typeProperties.put("variables", Map.of("type", "object")); - graphqlPath.put("post", Map.of( - "summary", "GraphQL Endpoint", - "operationId", "GraphQL Endpoint", - "responses", Map.of("200", Map.of("description", "GraphQL response")), - "requestBody", Map.of( - "required", true, - "content", - Map.of("application/json", - Map.of("schema", Map.of("type", "object", "properties", typeProperties)))) - )); - paths.put(settings.getSecurity().getGraphqlEndpointPath(), graphqlPath); - - - return paths; - } - - private List> buildParameters(ApiDefinition apiDefinition, ApiDefinitionMeta meta, Document document, boolean supportsBody) { - // 遍历每一个操作定义,提取其中的变量定义 - List> parameters = new ArrayList<>(); - - Set pathNames = new UriTemplate(apiDefinition.getPath()).match(new UriTemplate(apiDefinition.getPath())).keySet(); - - for (String pathName : pathNames) { - parameters.add( - Map.of( - "name", pathName, - "in", "path", - "required", true, - "schema", Map.of("type", "string") - ) - ); - } - - if (!supportsBody && meta.getExecution().getExecutionType().equals("graphql")) { - // 3. 提取变量 - List variableDefinitions = getVariableDefinitions(document); - - // 4. 输出变量信息 - for (VariableDefinition variableDefinition : variableDefinitions) { - String variableName = variableDefinition.getName(); - String variableType = variableDefinition.getType().toString(); - if (pathNames.contains(variableName)) { - continue; - } - Map parameter = new HashMap<>(); - parameter.put("name", variableDefinition.getName()); - parameter.put("in", "query"); - parameter.put("description", ""); - parameter.put("required", variableDefinition.getType() instanceof NonNullType); - parameter.put("schema", Map.of("type", "string")); - parameters.add(parameter); - } - } - - return parameters; - } - - private Map buildResponse200(ApiDefinition api) { - String sanitizeName = getSanitizeName(api); - return Map.of( - "description", "successful operation", - "content", Map.of( - "application/json", - Map.of("schema", - Map.of("$ref", "#/components/schemas/" + sanitizeName + "Response"))) - ); - } - -} - diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/FlowApplicationService.java b/flexmodel-server/src/main/java/dev/flexmodel/application/FlowApplicationService.java deleted file mode 100644 index 719d6534..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/FlowApplicationService.java +++ /dev/null @@ -1,221 +0,0 @@ -package dev.flexmodel.application; - -import dev.flexmodel.application.dto.*; -import dev.flexmodel.domain.model.flow.dto.param.*; -import dev.flexmodel.domain.model.flow.dto.result.*; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.application.dto.*; -import dev.flexmodel.codegen.entity.FlowDefinition; -import dev.flexmodel.codegen.entity.FlowDeployment; -import dev.flexmodel.codegen.entity.FlowInstance; -import dev.flexmodel.domain.model.flow.dto.bo.ElementInstance; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstance; -import dev.flexmodel.domain.model.flow.dto.param.*; -import dev.flexmodel.domain.model.flow.dto.result.*; -import dev.flexmodel.domain.model.flow.service.FlowDefinitionService; -import dev.flexmodel.domain.model.flow.service.FlowDeploymentService; -import dev.flexmodel.domain.model.flow.service.FlowInstanceService; -import dev.flexmodel.domain.model.flow.service.ProcessService; -import dev.flexmodel.domain.model.flow.shared.common.FlowDeploymentStatus; -import dev.flexmodel.query.Expressions; -import dev.flexmodel.query.Predicate; -import dev.flexmodel.shared.utils.JsonUtils; -import dev.flexmodel.shared.utils.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * 流程编排应用服务 - * @author cjbi - */ -@Slf4j -@ApplicationScoped -public class FlowApplicationService { - - @Inject - ProcessService processService; - - @Inject - FlowInstanceService flowInstanceService; - - @Inject - FlowDefinitionService flowDefinitionService; - - @Inject - FlowDeploymentService flowDeploymentService; - - public List getHistoryUserTaskList(String projectId, String flowInstanceId, boolean effectiveForSubFlowInstance) { - return processService.getHistoryUserTaskList(projectId, flowInstanceId, effectiveForSubFlowInstance).getNodeInstanceList(); - } - - public List getHistoryElementList(String projectId, String flowInstanceId) { - return processService.getHistoryElementList(projectId, flowInstanceId).getElementInstanceList(); - } - - /** - * 获取流程模块列表 - */ - public PageDTO findFlowModuleList(FlowModuleListRequest request) { - log.info("获取流程模块列表,参数: {}", request); - Predicate predicate = Expressions.field(FlowDefinition::getIsDeleted).eq(false); - if (StringUtils.isNotBlank(request.getFlowModuleId())) { - predicate = predicate.and(Expressions.field(FlowDefinition::getFlowModuleId).eq(request.getFlowModuleId())); - } - if (StringUtils.isNotBlank(request.getFlowKey())) { - predicate = predicate.and(Expressions.field(FlowDefinition::getFlowKey).eq(request.getFlowKey())); - } - if (StringUtils.isNotBlank(request.getFlowName())) { - predicate = predicate.and(Expressions.field(FlowDefinition::getFlowName).contains(request.getFlowName())); - } - long count = flowDefinitionService.count(request.getProjectId(), predicate); - if (count == 0) { - return PageDTO.empty(); - } - - List list = flowDefinitionService.find(request.getProjectId(), predicate, request.getPage(), request.getSize()); - List flowModuleList = new ArrayList<>(); - for (FlowDefinition entity : list) { - FlowModuleResponse response = new FlowModuleResponse(entity); - long deploymentCount = flowDeploymentService.count(request.getProjectId(), Expressions.field( - FlowDeployment::getFlowModuleId).eq(entity.getFlowModuleId()) - .and(Expressions.field(FlowDeployment::getStatus).eq(FlowDeploymentStatus.DEPLOYED)) - ); - if (deploymentCount >= 1) { - //4 已发布 - response.setStatus(FlowModuleStatusEnum.PUBLISHED.getValue()); - } - flowModuleList.add(response); - } - return new PageDTO<>(flowModuleList, count); - } - - /** - * 获取流程实例列表 - */ - public PageDTO findFlowInstanceList(FlowInstanceListRequest request) { - log.info("获取流程实例列表,参数: {}", request); - Predicate predicate = Expressions.TRUE; - if (StringUtils.isNotBlank(request.getFlowInstanceId())) { - predicate = predicate.and(Expressions.field(FlowInstance::getFlowInstanceId).eq(request.getFlowInstanceId())); - } - if (StringUtils.isNotBlank(request.getFlowModuleId())) { - predicate = predicate.and(Expressions.field(FlowInstance::getFlowModuleId).eq(request.getFlowModuleId())); - } - if (StringUtils.isNotBlank(request.getFlowDeployId())) { - predicate = predicate.and(Expressions.field(FlowInstance::getFlowDeployId).eq(request.getFlowDeployId())); - } - if (request.getStatus() != null) { - predicate = predicate.and(Expressions.field(FlowInstance::getStatus).eq(request.getStatus())); - } - long count = flowInstanceService.count(request.getProjectId(), predicate); - if (count == 0) { - return PageDTO.empty(); - } - List list = flowInstanceService.find(request.getProjectId(), predicate, request.getPage(), request.getSize()).stream() - .map(entity -> { - FlowInstanceResponse response = JsonUtils.getInstance().convertValue(entity, FlowInstanceResponse.class); - FlowDeployment flowDeployment = flowDeploymentService.findByFlowDeployId(request.getProjectId(), entity.getFlowDeployId()); - if (flowDeployment != null) { - response.setFlowName(flowDeployment.getFlowName()); - response.setFlowKey(flowDeployment.getFlowKey()); - } - return response; - }).toList(); - return new PageDTO<>(list, count); - } - - /** - * 创建流程 - */ - public CreateFlowResult createFlow(CreateFlowParam createFlowParam) { - log.info("创建流程: {}", createFlowParam.getFlowName()); - return processService.createFlow(createFlowParam); - } - - /** - * 部署流程 - */ - public DeployFlowResult deployFlow(DeployFlowParam deployFlowParam) { - log.info("部署流程,流程模块ID: {}", deployFlowParam.getFlowModuleId()); - return processService.deployFlow(deployFlowParam); - } - - /** - * 更新流程 - */ - public UpdateFlowResult updateFlow(UpdateFlowParam updateFlowParam) { - log.info("更新流程,流程模块ID: {}", updateFlowParam.getFlowModuleId()); - return processService.updateFlow(updateFlowParam); - } - - public void deleteFlow(String projectId, String flowModuleId) { - log.info("删除流程,流程模块ID: {}", flowModuleId); - processService.deleteFlow(projectId, flowModuleId); - } - - /** - * 获取流程模块信息 - */ - public FlowModuleResult getFlowModule(GetFlowModuleParam getFlowModuleParam) { - log.info("获取流程模块信息,流程模块ID: {}, 流程部署ID: {}", - getFlowModuleParam.getFlowModuleId(), getFlowModuleParam.getFlowDeployId()); - return processService.getFlowModule(getFlowModuleParam); - } - - /** - * 启动流程实例 - */ - public StartProcessResult startProcess(StartProcessParam startProcessParam) { - log.info("启动流程实例,流程模块ID: {}, 流程部署ID: {}", - startProcessParam.getFlowModuleId(), startProcessParam.getFlowDeployId()); - return processService.startProcess(startProcessParam); - } - - /** - * 提交任务 - */ - public CommitTaskResult commitTask(CommitTaskParam commitTaskParam) { - log.info("提交任务,流程实例ID: {}, 任务实例ID: {}", - commitTaskParam.getFlowInstanceId(), commitTaskParam.getTaskInstanceId()); - return processService.commitTask(commitTaskParam); - } - - /** - * 回滚任务 - */ - public RollbackTaskResult rollbackTask(RollbackTaskParam rollbackTaskParam) { - log.info("回滚任务,流程实例ID: {}, 任务实例ID: {}", - rollbackTaskParam.getFlowInstanceId(), rollbackTaskParam.getTaskInstanceId()); - return processService.rollbackTask(rollbackTaskParam); - } - - /** - * 终止流程实例 - */ - public TerminateResult terminateProcess(String projectId, String flowInstanceId, boolean effectiveForSubFlowInstance) { - log.info("终止流程实例: {}, 对子流程实例生效: {}", flowInstanceId, effectiveForSubFlowInstance); - if (StringUtils.isBlank(flowInstanceId)) { - throw new IllegalArgumentException("流程实例ID不能为空"); - } - return processService.terminateProcess(projectId, flowInstanceId, effectiveForSubFlowInstance); - } - - /** - * 获取流程实例信息 - */ - public FlowInstance findFlowInstance(String projectId, String flowInstanceId) { - log.info("获取流程实例信息: {}", flowInstanceId); - if (StringUtils.isBlank(flowInstanceId)) { - throw new IllegalArgumentException("流程实例ID不能为空"); - } - return flowInstanceService.findById(projectId, flowInstanceId); - } - - public Map getInstanceData(String flowInstanceId, String instanceDataId, String dataId) { - return null; - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/IdentityProviderApplicationService.java b/flexmodel-server/src/main/java/dev/flexmodel/application/IdentityProviderApplicationService.java deleted file mode 100644 index 64d89623..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/IdentityProviderApplicationService.java +++ /dev/null @@ -1,38 +0,0 @@ -package dev.flexmodel.application; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import dev.flexmodel.codegen.entity.IdentityProvider; -import dev.flexmodel.domain.model.idp.IdentityProviderService; - -import java.util.List; - -/** - * @author cjbi - */ -@ApplicationScoped -public class IdentityProviderApplicationService { - - @Inject - IdentityProviderService identityProviderService; - - public List findAll(String projectId) { - return identityProviderService.findAll(); - } - - public IdentityProvider createProvider(String projectId, IdentityProvider identityProvider) { - return identityProviderService.create(identityProvider); - } - - public IdentityProvider updateProvider(String projectId, IdentityProvider identityProvider) { - return identityProviderService.update(identityProvider); - } - - public void deleteProvider(String id, String name) { - identityProviderService.delete(id); - } - - public IdentityProvider find(String identityProvider) { - return identityProviderService.find(identityProvider); - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/MetricsApplicationService.java b/flexmodel-server/src/main/java/dev/flexmodel/application/MetricsApplicationService.java deleted file mode 100644 index 341d1146..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/MetricsApplicationService.java +++ /dev/null @@ -1,958 +0,0 @@ -package dev.flexmodel.application; - -import dev.flexmodel.application.dto.*; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.application.dto.*; -import dev.flexmodel.codegen.entity.FlowDefinition; -import dev.flexmodel.codegen.entity.JobExecutionLog; -import dev.flexmodel.domain.model.api.ApiDefinitionService; -import dev.flexmodel.domain.model.api.ApiRequestLogService; -import dev.flexmodel.domain.model.flow.service.FlowDefinitionService; -import dev.flexmodel.domain.model.flow.service.FlowInstanceService; -import dev.flexmodel.domain.model.modeling.ModelService; -import dev.flexmodel.domain.model.schedule.JobExecutionLogService; -import dev.flexmodel.domain.model.schedule.TriggerService; -import dev.flexmodel.quarkus.session.SessionManaged; -import dev.flexmodel.query.Expressions; -import dev.flexmodel.shared.SessionContextHolder; - -import java.io.File; -import java.lang.management.*; -import java.net.InetAddress; -import java.net.InterfaceAddress; -import java.net.NetworkInterface; -import java.nio.file.FileStore; -import java.nio.file.FileSystems; -import java.text.DecimalFormat; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import static dev.flexmodel.query.Expressions.TRUE; - -/** - * @author cjbi - */ -@Slf4j -@ApplicationScoped -@SessionManaged -public class MetricsApplicationService { - - private final DecimalFormat decimalFormat = new DecimalFormat("#.##"); - @Inject - ApiDefinitionService apiDefinitionService; - @Inject - ApiRequestLogService apiLogService; - @Inject - ModelService modelService; - @Inject - FlowInstanceService flowInstanceService; - @Inject - FlowDefinitionService flowDefService; - @Inject - TriggerService triggerService; - @Inject - JobExecutionLogService jobExecutionLogService; - - public FmMetricsResponse getFmMetrics(String projectId) { - try { - Integer modelCount = modelService.count(projectId); - Integer customApiCount = apiDefinitionService.count(projectId); - long reqLogCount = apiLogService.count(projectId, TRUE); - long flowDefCount = flowDefService.count(projectId, Expressions.field(FlowDefinition::getIsDeleted).eq(false)); - long flowInsCount = flowInstanceService.count(projectId, TRUE); - long triggerCount = triggerService.count(projectId, TRUE); - long jobSuccessCount = jobExecutionLogService.count(Expressions.field(JobExecutionLog::getExecutionStatus).eq("SUCCESS")); - long jobFailureCount = jobExecutionLogService.count(Expressions.field(JobExecutionLog::getExecutionStatus).eq("FAILED")); - - return FmMetricsResponse.builder() - .dataSourceCount(-1) - .customApiCount(customApiCount) - .requestCount((int) reqLogCount) - .flowDefCount((int) flowDefCount) - .flowExecCount((int) flowInsCount) - .modelCount(modelCount) - .triggerTotalCount((int) triggerCount) - .jobSuccessCount((int) jobSuccessCount) - .jobFailureCount((int) jobFailureCount) - .build(); - - } catch (Exception e) { - log.error("get api fm metrics error", e); - throw new RuntimeException(e); - } - } - - public JvmMetricsResponse getJvmMetrics() { - try { - JvmMetricsResponse jvmInfo = new JvmMetricsResponse(); - - // JVM基本信息 - RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); - jvmInfo.setName(runtimeBean.getVmName()); - jvmInfo.setVersion(runtimeBean.getVmVersion()); - jvmInfo.setVendor(runtimeBean.getVmVendor()); - jvmInfo.setUptime(runtimeBean.getUptime()); - jvmInfo.setStartTime(runtimeBean.getStartTime()); - - // 类加载信息 - ClassLoadingMXBean classBean = ManagementFactory.getClassLoadingMXBean(); - jvmInfo.setLoadedClassCount(classBean.getLoadedClassCount()); - jvmInfo.setTotalLoadedClassCount(classBean.getTotalLoadedClassCount()); - jvmInfo.setUnloadedClassCount(classBean.getUnloadedClassCount()); - - // 垃圾回收信息 - List gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); - Map gcInfo = new HashMap<>(); - for (GarbageCollectorMXBean gcBean : gcBeans) { - JvmMetricsResponse.GarbageCollectorInfo gcDetails = new JvmMetricsResponse.GarbageCollectorInfo(); - gcDetails.setCollectionCount(gcBean.getCollectionCount()); - gcDetails.setCollectionTime(gcBean.getCollectionTime()); - gcInfo.put(gcBean.getName(), gcDetails); - } - jvmInfo.setGarbageCollectors(gcInfo); - - // 系统属性 - Map systemProperties = new HashMap<>(); - systemProperties.put("java.version", System.getProperty("java.version")); - systemProperties.put("java.vendor", System.getProperty("java.vendor")); - systemProperties.put("os.name", System.getProperty("os.name")); - systemProperties.put("os.version", System.getProperty("os.version")); - systemProperties.put("os.arch", System.getProperty("os.arch")); - jvmInfo.setSystemProperties(systemProperties); - - return jvmInfo; - } catch (Exception e) { - throw new RuntimeException("获取JVM信息失败: " + e.getMessage()); - } - } - - public CpuMetricsResponse getCpuMetrics() { - try { - CpuMetricsResponse cpuInfo = new CpuMetricsResponse(); - - OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); - - // CPU基本信息 - cpuInfo.setAvailableProcessors(osBean.getAvailableProcessors()); - cpuInfo.setArchitecture(osBean.getArch()); - cpuInfo.setName(osBean.getName()); - cpuInfo.setVersion(osBean.getVersion()); - - // CPU使用率(需要额外计算) - if (osBean instanceof com.sun.management.OperatingSystemMXBean) { - com.sun.management.OperatingSystemMXBean sunOsBean = - (com.sun.management.OperatingSystemMXBean) osBean; - - try { - cpuInfo.setSystemCpuLoad( - Double.parseDouble(decimalFormat.format(sunOsBean.getSystemCpuLoad() * 100))); - cpuInfo.setProcessCpuLoad( - Double.parseDouble(decimalFormat.format(sunOsBean.getProcessCpuLoad() * 100))); - } catch (Exception e) { - // 忽略CPU使用率获取失败 - cpuInfo.setSystemCpuLoad(0.0); - cpuInfo.setProcessCpuLoad(0.0); - } - - cpuInfo.setSystemLoadAverage(sunOsBean.getSystemLoadAverage()); - - try { - cpuInfo.setTotalPhysicalMemorySize(sunOsBean.getTotalPhysicalMemorySize()); - cpuInfo.setFreePhysicalMemorySize(sunOsBean.getFreePhysicalMemorySize()); - cpuInfo.setTotalSwapSpaceSize(sunOsBean.getTotalSwapSpaceSize()); - cpuInfo.setFreeSwapSpaceSize(sunOsBean.getFreeSwapSpaceSize()); - cpuInfo.setCommittedVirtualMemorySize(sunOsBean.getCommittedVirtualMemorySize()); - } catch (Exception e) { - // 忽略内存信息获取失败 - cpuInfo.setTotalPhysicalMemorySize(0L); - cpuInfo.setFreePhysicalMemorySize(0L); - cpuInfo.setTotalSwapSpaceSize(0L); - cpuInfo.setFreeSwapSpaceSize(0L); - cpuInfo.setCommittedVirtualMemorySize(0L); - } - } - - // 运行时信息 - Runtime runtime = Runtime.getRuntime(); - cpuInfo.setMaxMemory(runtime.maxMemory()); - cpuInfo.setTotalMemory(runtime.totalMemory()); - cpuInfo.setFreeMemory(runtime.freeMemory()); - cpuInfo.setUsedMemory(runtime.totalMemory() - runtime.freeMemory()); - - return cpuInfo; - } catch (Exception e) { - throw new RuntimeException("获取CPU信息失败: " + e.getMessage()); - } - } - - public MemoryMetricsResponse getMemoryMetrics() { - try { - MemoryMetricsResponse memoryInfo = new MemoryMetricsResponse(); - - MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); - - // 堆内存信息 - MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage(); - MemoryMetricsResponse.MemoryInfo heapInfo = new MemoryMetricsResponse.MemoryInfo(); - heapInfo.setInit(heapUsage.getInit()); - heapInfo.setUsed(heapUsage.getUsed()); - heapInfo.setCommitted(heapUsage.getCommitted()); - heapInfo.setMax(heapUsage.getMax()); - heapInfo.setUsagePercentage( - Double.parseDouble(decimalFormat.format((double) heapUsage.getUsed() / heapUsage.getCommitted() * 100))); - memoryInfo.setHeap(heapInfo); - - // 非堆内存信息 - MemoryUsage nonHeapUsage = memoryBean.getNonHeapMemoryUsage(); - MemoryMetricsResponse.MemoryInfo nonHeapInfo = new MemoryMetricsResponse.MemoryInfo(); - nonHeapInfo.setInit(nonHeapUsage.getInit()); - nonHeapInfo.setUsed(nonHeapUsage.getUsed()); - nonHeapInfo.setCommitted(nonHeapUsage.getCommitted()); - nonHeapInfo.setMax(nonHeapUsage.getMax()); - if (nonHeapUsage.getCommitted() > 0) { - nonHeapInfo.setUsagePercentage( - Double.parseDouble(decimalFormat.format((double) nonHeapUsage.getUsed() / nonHeapUsage.getCommitted() * 100))); - } else { - nonHeapInfo.setUsagePercentage(0); - } - memoryInfo.setNonHeap(nonHeapInfo); - - // 内存池详细信息 - List memoryPools = - ManagementFactory.getMemoryPoolMXBeans(); - Map memoryPoolsInfo = new HashMap<>(); - for (java.lang.management.MemoryPoolMXBean pool : memoryPools) { - MemoryMetricsResponse.MemoryPoolInfo poolInfo = new MemoryMetricsResponse.MemoryPoolInfo(); - MemoryUsage poolUsage = pool.getUsage(); - if (poolUsage != null) { - poolInfo.setInit(poolUsage.getInit()); - poolInfo.setUsed(poolUsage.getUsed()); - poolInfo.setCommitted(poolUsage.getCommitted()); - poolInfo.setMax(poolUsage.getMax()); - if (poolUsage.getCommitted() > 0) { - poolInfo.setUsagePercentage( - Double.parseDouble(decimalFormat.format((double) poolUsage.getUsed() / poolUsage.getCommitted() * 100))); - } else { - poolInfo.setUsagePercentage(0); - } - } - poolInfo.setType(pool.getType().toString()); - poolInfo.setMemoryManagerNames(String.join(", ", pool.getMemoryManagerNames())); - memoryPoolsInfo.put(pool.getName(), poolInfo); - } - memoryInfo.setMemoryPools(memoryPoolsInfo); - - return memoryInfo; - } catch (Exception e) { - throw new RuntimeException("获取内存信息失败: " + e.getMessage()); - } - } - - public ThreadMetricsResponse getThreadMetrics() { - try { - ThreadMetricsResponse threadInfo = new ThreadMetricsResponse(); - - ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); - - // 线程基本统计 - threadInfo.setThreadCount(threadBean.getThreadCount()); - threadInfo.setPeakThreadCount(threadBean.getPeakThreadCount()); - threadInfo.setDaemonThreadCount(threadBean.getDaemonThreadCount()); - threadInfo.setTotalStartedThreadCount(threadBean.getTotalStartedThreadCount()); - threadInfo.setCurrentThreadCpuTime(threadBean.getCurrentThreadCpuTime()); - threadInfo.setCurrentThreadUserTime(threadBean.getCurrentThreadUserTime()); - - // 线程状态统计 - Map threadStates = new HashMap<>(); - for (Thread.State state : Thread.State.values()) { - threadStates.put(state, 0); - } - - // 获取所有线程信息 - long[] threadIds = threadBean.getAllThreadIds(); - Map threadsDetails = new HashMap<>(); - - for (long threadId : threadIds) { - java.lang.management.ThreadInfo info = threadBean.getThreadInfo(threadId); - if (info != null) { - Thread.State state = info.getThreadState(); - threadStates.put(state, threadStates.get(state) + 1); - - // 线程详细信息 - ThreadMetricsResponse.ThreadDetailInfo threadDetail = new ThreadMetricsResponse.ThreadDetailInfo(); - threadDetail.setName(info.getThreadName()); - threadDetail.setState(state.toString()); - threadDetail.setBlockedTime(info.getBlockedTime()); - threadDetail.setBlockedCount(info.getBlockedCount()); - threadDetail.setWaitedTime(info.getWaitedTime()); - threadDetail.setWaitedCount(info.getWaitedCount()); - threadDetail.setCpuTime(threadBean.getThreadCpuTime(threadId)); - threadDetail.setUserTime(threadBean.getThreadUserTime(threadId)); - - if (info.getLockName() != null) { - threadDetail.setLockName(info.getLockName()); - } - if (info.getLockOwnerName() != null) { - threadDetail.setLockOwnerName(info.getLockOwnerName()); - } - - threadsDetails.put(String.valueOf(threadId), threadDetail); - } - } - - // 线程状态统计 - Map stateStats = new HashMap<>(); - for (Map.Entry entry : threadStates.entrySet()) { - stateStats.put(entry.getKey().toString(), entry.getValue()); - } - threadInfo.setThreadStates(stateStats); - threadInfo.setThreadDetails(threadsDetails); - - return threadInfo; - } catch (Exception e) { - throw new RuntimeException("获取线程信息失败: " + e.getMessage()); - } - } - - public DiskMetricsResponse getDiskMetrics() { - try { - DiskMetricsResponse diskInfo = new DiskMetricsResponse(); - - // 获取所有文件系统 - List fileStores = new ArrayList<>(); - for (FileStore fileStore : FileSystems.getDefault().getFileStores()) { - fileStores.add(fileStore); - } - Map fileSystemsInfo = new HashMap<>(); - - for (FileStore fileStore : fileStores) { - try { - DiskMetricsResponse.FileSystemInfo fsInfo = new DiskMetricsResponse.FileSystemInfo(); - - // 基本信息 - fsInfo.setName(fileStore.name()); - fsInfo.setType(fileStore.type()); - - // 容量信息 - long totalSpace = fileStore.getTotalSpace(); - long usableSpace = fileStore.getUsableSpace(); - long usedSpace = totalSpace - usableSpace; - - fsInfo.setTotalSpace(totalSpace); - fsInfo.setUsedSpace(usedSpace); - fsInfo.setUsableSpace(usableSpace); - fsInfo.setFreeSpace(fileStore.getUnallocatedSpace()); - - // 计算使用率 - if (totalSpace > 0) { - double usagePercentage = (double) usedSpace / totalSpace * 100; - fsInfo.setUsagePercentage( - Double.parseDouble(decimalFormat.format(usagePercentage))); - } else { - fsInfo.setUsagePercentage(0.0); - } - - // 文件系统属性 - fsInfo.setReadOnly(fileStore.isReadOnly()); - - // 存储单位转换 - fsInfo.setTotalSpaceGB(totalSpace / (1024.0 * 1024.0 * 1024.0)); - fsInfo.setUsedSpaceGB(usedSpace / (1024.0 * 1024.0 * 1024.0)); - fsInfo.setUsableSpaceGB(usableSpace / (1024.0 * 1024.0 * 1024.0)); - - fileSystemsInfo.put(fileStore.name(), fsInfo); - } catch (Exception e) { - // 跳过无法访问的文件系统 - continue; - } - } - - diskInfo.setFileSystems(fileSystemsInfo); - - // 根目录信息 - File root = File.listRoots()[0]; - DiskMetricsResponse.FileSystemInfo rootInfo = new DiskMetricsResponse.FileSystemInfo(); - rootInfo.setTotalSpace(root.getTotalSpace()); - rootInfo.setFreeSpace(root.getFreeSpace()); - rootInfo.setUsableSpace(root.getUsableSpace()); - rootInfo.setTotalSpaceGB(root.getTotalSpace() / (1024.0 * 1024.0 * 1024.0)); - rootInfo.setFreeSpaceGB(root.getFreeSpace() / (1024.0 * 1024.0 * 1024.0)); - rootInfo.setUsableSpaceGB(root.getUsableSpace() / (1024.0 * 1024.0 * 1024.0)); - - if (root.getTotalSpace() > 0) { - double usagePercentage = (double) (root.getTotalSpace() - root.getUsableSpace()) / root.getTotalSpace() * 100; - rootInfo.setUsagePercentage( - Double.parseDouble(decimalFormat.format(usagePercentage))); - } else { - rootInfo.setUsagePercentage(0.0); - } - - diskInfo.setRootDirectory(rootInfo); - - // 统计信息 - diskInfo.setTotalFileSystems(fileStores.size()); - diskInfo.setTotalSpace(root.getTotalSpace()); - diskInfo.setTotalUsableSpace(root.getUsableSpace()); - diskInfo.setTotalFreeSpace(root.getFreeSpace()); - - // 添加磁盘I/O信息 - DiskMetricsResponse.DiskIoInfo diskIoInfo = new DiskMetricsResponse.DiskIoInfo(); - - // 使用OperatingSystemMXBean获取磁盘I/O信息 - if (ManagementFactory.getOperatingSystemMXBean() instanceof com.sun.management.OperatingSystemMXBean) { - com.sun.management.OperatingSystemMXBean sunOsBean = - (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); - - try { - // 磁盘I/O统计 - diskIoInfo.setCommittedVirtualMemorySize(sunOsBean.getCommittedVirtualMemorySize()); - - // 尝试获取进程级别的I/O信息(如果可用) - DiskMetricsResponse.ProcessIoInfo processIo = new DiskMetricsResponse.ProcessIoInfo(); - processIo.setCommittedVirtualMemoryMB(sunOsBean.getCommittedVirtualMemorySize() / 1024 / 1024); - - diskIoInfo.setProcessIo(processIo); - } catch (Exception e) { - // 如果无法获取详细信息,提供基本信息 - diskIoInfo.setError("无法获取详细I/O信息: " + e.getMessage()); - } - } - - // 添加文件系统级别的统计 - DiskMetricsResponse.FileSystemStatsInfo fileSystemStats = new DiskMetricsResponse.FileSystemStatsInfo(); - try { - fileSystemStats.setTotalSpace(root.getTotalSpace()); - fileSystemStats.setFreeSpace(root.getFreeSpace()); - fileSystemStats.setUsableSpace(root.getUsableSpace()); - fileSystemStats.setLastModified(root.lastModified()); - - // 计算空间变化趋势(需要历史数据,这里提供当前状态) - fileSystemStats.setSpaceUtilization( - (root.getTotalSpace() - root.getUsableSpace()) * 100.0 / root.getTotalSpace()); - - diskIoInfo.setFileSystemStats(fileSystemStats); - } catch (Exception e) { - diskIoInfo.setFileSystemError("无法获取文件系统统计: " + e.getMessage()); - } - - // 添加JVM级别的I/O信息 - DiskMetricsResponse.JvmIoInfo jvmIo = new DiskMetricsResponse.JvmIoInfo(); - Runtime runtime = Runtime.getRuntime(); - jvmIo.setMaxMemory(runtime.maxMemory()); - jvmIo.setTotalMemory(runtime.totalMemory()); - jvmIo.setFreeMemory(runtime.freeMemory()); - jvmIo.setUsedMemory(runtime.totalMemory() - runtime.freeMemory()); - - diskIoInfo.setJvmIo(jvmIo); - - // 将磁盘I/O信息添加到磁盘信息中 - diskInfo.setDiskIo(diskIoInfo); - - return diskInfo; - } catch (Exception e) { - throw new RuntimeException("获取磁盘信息失败: " + e.getMessage()); - } - } - - public NetworkMetricsResponse getNetworkMetrics() { - try { - NetworkMetricsResponse networkInfo = new NetworkMetricsResponse(); - - // 并行处理网络接口信息和本机信息 - CompletableFuture> interfacesFuture = - CompletableFuture.supplyAsync(this::getNetworkInterfacesInfo); - - CompletableFuture localhostFuture = - CompletableFuture.supplyAsync(this::getLocalhostInfo); - - // 等待所有任务完成 - CompletableFuture.allOf(interfacesFuture, localhostFuture).join(); - - // 设置结果 - Map interfacesInfo = interfacesFuture.get(); - networkInfo.setInterfaces(interfacesInfo); - networkInfo.setTotalInterfaces(interfacesInfo.size()); - - try { - NetworkMetricsResponse.LocalhostInfo localInfo = localhostFuture.get(); - networkInfo.setLocalhost(localInfo); - } catch (Exception e) { - networkInfo.setLocalhostError("无法获取本机信息: " + e.getMessage()); - } - - // 网络统计信息 - NetworkMetricsResponse.NetworkStatsInfo networkStats = new NetworkMetricsResponse.NetworkStatsInfo(); - networkStats.setActiveInterfaces(interfacesInfo.size()); - networkStats.setTimestamp(System.currentTimeMillis()); - networkInfo.setStats(networkStats); - - return networkInfo; - } catch (Exception e) { - throw new RuntimeException("获取网络信息失败: " + e.getMessage()); - } - } - - private Map getNetworkInterfacesInfo() { - Map interfacesInfo = new HashMap<>(); - - try { - Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); - List interfaceList = new ArrayList<>(); - - // 先收集所有接口,避免在遍历时修改 - while (networkInterfaces.hasMoreElements()) { - interfaceList.add(networkInterfaces.nextElement()); - } - - // 并行处理网络接口 - List> futures = interfaceList.stream() - .map(networkInterface -> CompletableFuture.runAsync(() -> { - try { - NetworkMetricsResponse.NetworkInterfaceInfo interfaceInfo = processNetworkInterface(networkInterface); - synchronized (interfacesInfo) { - interfacesInfo.put(networkInterface.getName(), interfaceInfo); - } - } catch (Exception e) { - // 跳过无法访问的接口,记录日志但不影响其他接口 - System.err.println("处理网络接口 " + networkInterface.getName() + " 时出错: " + e.getMessage()); - } - })) - .collect(Collectors.toList()); - - // 等待所有接口处理完成 - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); - - } catch (Exception e) { - System.err.println("获取网络接口列表失败: " + e.getMessage()); - } - - return interfacesInfo; - } - - private NetworkMetricsResponse.NetworkInterfaceInfo processNetworkInterface(NetworkInterface networkInterface) { - NetworkMetricsResponse.NetworkInterfaceInfo interfaceInfo = new NetworkMetricsResponse.NetworkInterfaceInfo(); - - try { - // 基本信息(快速获取) - interfaceInfo.setName(networkInterface.getName()); - interfaceInfo.setDisplayName(networkInterface.getDisplayName()); - interfaceInfo.setUp(networkInterface.isUp()); - interfaceInfo.setLoopback(networkInterface.isLoopback()); - interfaceInfo.setVirtual(networkInterface.isVirtual()); - interfaceInfo.setPointToPoint(networkInterface.isPointToPoint()); - interfaceInfo.setSupportsMulticast(networkInterface.supportsMulticast()); - - // MAC地址 - byte[] macBytes = networkInterface.getHardwareAddress(); - if (macBytes != null) { - StringBuilder macAddress = new StringBuilder(); - for (int i = 0; i < macBytes.length; i++) { - macAddress.append(String.format("%02x%s", macBytes[i], (i < macBytes.length - 1) ? ":" : "")); - } - interfaceInfo.setMacAddress(macAddress.toString()); - } - - // MTU - interfaceInfo.setMtu(networkInterface.getMTU()); - } catch (Exception e) { - // 如果基本信息获取失败,设置默认值 - interfaceInfo.setName(networkInterface.getName()); - interfaceInfo.setDisplayName("unknown"); - interfaceInfo.setUp(false); - interfaceInfo.setLoopback(false); - interfaceInfo.setVirtual(false); - interfaceInfo.setPointToPoint(false); - interfaceInfo.setSupportsMulticast(false); - interfaceInfo.setMtu(0); - } - - // IP地址信息(避免DNS解析) - Map addressesInfo = new HashMap<>(); - List interfaceAddresses = networkInterface.getInterfaceAddresses(); - for (int i = 0; i < interfaceAddresses.size(); i++) { - InterfaceAddress address = interfaceAddresses.get(i); - NetworkMetricsResponse.AddressInfo addressInfo = new NetworkMetricsResponse.AddressInfo(); - - addressInfo.setAddress(address.getAddress().getHostAddress()); - // 避免DNS反向解析,直接使用IP地址作为主机名 - addressInfo.setHostName(address.getAddress().getHostAddress()); - addressInfo.setNetworkPrefixLength(address.getNetworkPrefixLength()); - - if (address.getBroadcast() != null) { - addressInfo.setBroadcast(address.getBroadcast().getHostAddress()); - } - - addressesInfo.put("address_" + i, addressInfo); - } - interfaceInfo.setAddresses(addressesInfo); - - // 父接口信息 - if (networkInterface.getParent() != null) { - interfaceInfo.setParent(networkInterface.getParent().getName()); - } - - // 子接口(简化处理,只获取名称) - Map subInterfaces = new HashMap<>(); - try { - Enumeration subInterfaceEnum = networkInterface.getSubInterfaces(); - int index = 0; - while (subInterfaceEnum.hasMoreElements() && index < 10) { // 限制子接口数量,避免过多 - NetworkInterface subInterface = subInterfaceEnum.nextElement(); - subInterfaces.put("sub_" + index, subInterface.getName()); - index++; - } - } catch (Exception e) { - // 忽略子接口获取失败 - } - interfaceInfo.setSubInterfaces(subInterfaces); - - return interfaceInfo; - } - - private NetworkMetricsResponse.LocalhostInfo getLocalhostInfo() { - NetworkMetricsResponse.LocalhostInfo localInfo = new NetworkMetricsResponse.LocalhostInfo(); - - try { - InetAddress localhost = InetAddress.getLocalHost(); - localInfo.setHostAddress(localhost.getHostAddress()); - localInfo.setLoopbackAddress(localhost.isLoopbackAddress()); - localInfo.setLinkLocalAddress(localhost.isLinkLocalAddress()); - localInfo.setSiteLocalAddress(localhost.isSiteLocalAddress()); - localInfo.setMulticastAddress(localhost.isMulticastAddress()); - - // 避免DNS解析,使用IP地址作为主机名 - localInfo.setHostName(localhost.getHostAddress()); - localInfo.setCanonicalHostName(localhost.getHostAddress()); - - } catch (Exception e) { - // 如果获取失败,提供默认值 - localInfo.setHostName("unknown"); - localInfo.setHostAddress("127.0.0.1"); - localInfo.setCanonicalHostName("127.0.0.1"); - localInfo.setLoopbackAddress(true); - localInfo.setLinkLocalAddress(false); - localInfo.setSiteLocalAddress(false); - localInfo.setMulticastAddress(false); - } - - return localInfo; - } - - public SystemSummaryResponse getSystemSummary() { - try { - SystemSummaryResponse summary = new SystemSummaryResponse(); - - // 系统基本信息 - RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); - OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); - MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); - ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); - - // 系统概览 - summary.setSystemTime(System.currentTimeMillis()); - summary.setUptime(runtimeBean.getUptime()); - summary.setAvailableProcessors(osBean.getAvailableProcessors()); - summary.setOsName(osBean.getName()); - summary.setOsVersion(osBean.getVersion()); - summary.setOsArch(osBean.getArch()); - - // 内存概览 - MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage(); - summary.setHeapUsedMB(heapUsage.getUsed() / 1024 / 1024); - summary.setHeapMaxMB(heapUsage.getMax() / 1024 / 1024); - summary.setHeapUsagePercentage( - Double.parseDouble(decimalFormat.format((double) heapUsage.getUsed() / heapUsage.getCommitted() * 100))); - - // 线程概览 - summary.setThreadCount(threadBean.getThreadCount()); - summary.setPeakThreadCount(threadBean.getPeakThreadCount()); - summary.setDaemonThreadCount(threadBean.getDaemonThreadCount()); - - // 磁盘概览 - File root = File.listRoots()[0]; - summary.setDiskTotalSpaceGB( - Double.parseDouble(decimalFormat.format(root.getTotalSpace() / (1024.0 * 1024.0 * 1024.0)))); - summary.setDiskUsableSpaceGB( - Double.parseDouble(decimalFormat.format(root.getUsableSpace() / (1024.0 * 1024.0 * 1024.0)))); - summary.setDiskFreeSpaceGB( - Double.parseDouble(decimalFormat.format(root.getFreeSpace() / (1024.0 * 1024.0 * 1024.0)))); - - if (root.getTotalSpace() > 0) { - double diskUsagePercentage = (double) (root.getTotalSpace() - root.getUsableSpace()) / root.getTotalSpace() * 100; - summary.setDiskUsagePercentage( - Double.parseDouble(decimalFormat.format(diskUsagePercentage))); - } else { - summary.setDiskUsagePercentage(0.0); - } - - // 网络概览 - try { - Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); - int activeInterfaces = 0; - int upInterfaces = 0; - - while (networkInterfaces.hasMoreElements()) { - NetworkInterface networkInterface = networkInterfaces.nextElement(); - activeInterfaces++; - if (networkInterface.isUp()) { - upInterfaces++; - } - } - - summary.setTotalNetworkInterfaces(activeInterfaces); - summary.setUpNetworkInterfaces(upInterfaces); - - // 获取本机IP - InetAddress localhost = InetAddress.getLocalHost(); - summary.setHostName(localhost.getHostName()); - summary.setHostAddress(localhost.getHostAddress()); - } catch (Exception e) { - summary.setNetworkError("无法获取网络信息: " + e.getMessage()); - } - - // JVM概览 - summary.setJvmName(runtimeBean.getVmName()); - summary.setJvmVersion(runtimeBean.getVmVersion()); - summary.setJvmVendor(runtimeBean.getVmVendor()); - - // 类加载概览 - ClassLoadingMXBean classBean = ManagementFactory.getClassLoadingMXBean(); - summary.setLoadedClassCount(classBean.getLoadedClassCount()); - summary.setTotalLoadedClassCount(classBean.getTotalLoadedClassCount()); - - // 垃圾回收概览 - List gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); - long totalGcCount = 0; - long totalGcTime = 0; - for (GarbageCollectorMXBean gcBean : gcBeans) { - totalGcCount += gcBean.getCollectionCount(); - totalGcTime += gcBean.getCollectionTime(); - } - summary.setTotalGcCount(totalGcCount); - summary.setTotalGcTime(totalGcTime); - - // CPU使用率(如果可用) - if (osBean instanceof com.sun.management.OperatingSystemMXBean) { - com.sun.management.OperatingSystemMXBean sunOsBean = - (com.sun.management.OperatingSystemMXBean) osBean; - try { - summary.setSystemCpuLoad( - Double.parseDouble(decimalFormat.format(sunOsBean.getSystemCpuLoad() * 100))); - summary.setProcessCpuLoad( - Double.parseDouble(decimalFormat.format(sunOsBean.getProcessCpuLoad() * 100))); - } catch (Exception e) { - summary.setSystemCpuLoad(0.0); - summary.setProcessCpuLoad(0.0); - } - } - - return summary; - } catch (Exception e) { - throw new RuntimeException("获取系统摘要失败: " + e.getMessage()); - } - } - - public PrometheusMetricsResponse getPrometheusMetrics() { - try { - // 使用Quarkus内置的Prometheus端点 - // 这里返回一个简单的指标格式,实际使用中建议直接使用Quarkus的/metrics端点 - StringBuilder metrics = new StringBuilder(); - - // 添加自定义指标 - addCustomMetrics(metrics); - - return PrometheusMetricsResponse.success(metrics.toString()); - } catch (Exception e) { - throw new RuntimeException("获取Prometheus指标失败: " + e.getMessage()); - } - } - - private void addCustomMetrics(StringBuilder metrics) { - try { - // 添加JVM指标 - RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); - ClassLoadingMXBean classBean = ManagementFactory.getClassLoadingMXBean(); - - metrics.append("# HELP jvm_uptime_seconds JVM uptime in seconds\n"); - metrics.append("# TYPE jvm_uptime_seconds gauge\n"); - metrics.append("jvm_uptime_seconds ").append(runtimeBean.getUptime() / 1000.0).append("\n"); - - metrics.append("# HELP jvm_classes_loaded Number of classes loaded\n"); - metrics.append("# TYPE jvm_classes_loaded gauge\n"); - metrics.append("jvm_classes_loaded ").append(classBean.getLoadedClassCount()).append("\n"); - - // 添加内存指标 - MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); - MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage(); - - metrics.append("# HELP jvm_memory_heap_used_bytes Heap memory used in bytes\n"); - metrics.append("# TYPE jvm_memory_heap_used_bytes gauge\n"); - metrics.append("jvm_memory_heap_used_bytes ").append(heapUsage.getUsed()).append("\n"); - - metrics.append("# HELP jvm_memory_heap_max_bytes Maximum heap memory in bytes\n"); - metrics.append("# TYPE jvm_memory_heap_max_bytes gauge\n"); - metrics.append("jvm_memory_heap_max_bytes ").append(heapUsage.getMax()).append("\n"); - - // 添加线程指标 - ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); - - metrics.append("# HELP jvm_threads_current Current number of threads\n"); - metrics.append("# TYPE jvm_threads_current gauge\n"); - metrics.append("jvm_threads_current ").append(threadBean.getThreadCount()).append("\n"); - - metrics.append("# HELP jvm_threads_peak Peak number of threads\n"); - metrics.append("# TYPE jvm_threads_peak gauge\n"); - metrics.append("jvm_threads_peak ").append(threadBean.getPeakThreadCount()).append("\n"); - - // 添加系统指标 - OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); - - metrics.append("# HELP system_cpu_available_processors Number of available processors\n"); - metrics.append("# TYPE system_cpu_available_processors gauge\n"); - metrics.append("system_cpu_available_processors ").append(osBean.getAvailableProcessors()).append("\n"); - - metrics.append("# HELP system_load_average System load average\n"); - metrics.append("# TYPE system_load_average gauge\n"); - metrics.append("system_load_average ").append(osBean.getSystemLoadAverage()).append("\n"); - - // 添加磁盘指标 - File root = File.listRoots()[0]; - metrics.append("# HELP disk_total_bytes Total disk space in bytes\n"); - metrics.append("# TYPE disk_total_bytes gauge\n"); - metrics.append("disk_total_bytes ").append(root.getTotalSpace()).append("\n"); - - metrics.append("# HELP disk_free_bytes Free disk space in bytes\n"); - metrics.append("# TYPE disk_free_bytes gauge\n"); - metrics.append("disk_free_bytes ").append(root.getFreeSpace()).append("\n"); - - metrics.append("# HELP disk_usable_bytes Usable disk space in bytes\n"); - metrics.append("# TYPE disk_usable_bytes gauge\n"); - metrics.append("disk_usable_bytes ").append(root.getUsableSpace()).append("\n"); - - metrics.append("# HELP disk_used_bytes Used disk space in bytes\n"); - metrics.append("# TYPE disk_used_bytes gauge\n"); - metrics.append("disk_used_bytes ").append(root.getTotalSpace() - root.getUsableSpace()).append("\n"); - - // 磁盘使用率 - if (root.getTotalSpace() > 0) { - double diskUsagePercentage = (double) (root.getTotalSpace() - root.getUsableSpace()) / root.getTotalSpace() * 100; - metrics.append("# HELP disk_usage_percentage Disk usage percentage\n"); - metrics.append("# TYPE disk_usage_percentage gauge\n"); - metrics.append("disk_usage_percentage ").append(diskUsagePercentage).append("\n"); - } - - // 网络指标 - try { - Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); - int activeInterfaces = 0; - int upInterfaces = 0; - - while (networkInterfaces.hasMoreElements()) { - NetworkInterface networkInterface = networkInterfaces.nextElement(); - activeInterfaces++; - if (networkInterface.isUp()) { - upInterfaces++; - } - } - - metrics.append("# HELP network_interfaces_total Total number of network interfaces\n"); - metrics.append("# TYPE network_interfaces_total gauge\n"); - metrics.append("network_interfaces_total ").append(activeInterfaces).append("\n"); - - metrics.append("# HELP network_interfaces_up Number of up network interfaces\n"); - metrics.append("# TYPE network_interfaces_up gauge\n"); - metrics.append("network_interfaces_up ").append(upInterfaces).append("\n"); - } catch (Exception e) { - metrics.append("# ERROR: Cannot get network info: ").append(e.getMessage()).append("\n"); - } - - } catch (Exception e) { - metrics.append("# ERROR: ").append(e.getMessage()).append("\n"); - } - } - - public AllMetricsResponse getAllMetrics() { - long startTime = System.currentTimeMillis(); - try { - String projectId = SessionContextHolder.getProjectId(); - // 并行获取所有指标 - CompletableFuture fmFuture = CompletableFuture.supplyAsync(() -> { - SessionContextHolder.setProjectId(projectId); - return getFmMetrics(projectId); - }); - - CompletableFuture jvmFuture = - CompletableFuture.supplyAsync(this::getJvmMetrics); - - CompletableFuture cpuFuture = - CompletableFuture.supplyAsync(this::getCpuMetrics); - - CompletableFuture memoryFuture = - CompletableFuture.supplyAsync(this::getMemoryMetrics); - - CompletableFuture threadsFuture = - CompletableFuture.supplyAsync(this::getThreadMetrics); - - CompletableFuture diskFuture = - CompletableFuture.supplyAsync(this::getDiskMetrics); - - CompletableFuture networkFuture = - CompletableFuture.supplyAsync(this::getNetworkMetrics); - - CompletableFuture summaryFuture = - CompletableFuture.supplyAsync(this::getSystemSummary); - - CompletableFuture prometheusFuture = - CompletableFuture.supplyAsync(this::getPrometheusMetrics); - - // 等待所有任务完成,设置超时时间为30秒 - CompletableFuture allFutures = CompletableFuture.allOf( - fmFuture, jvmFuture, cpuFuture, memoryFuture, threadsFuture, - diskFuture, networkFuture, summaryFuture, prometheusFuture - ); - - // 等待所有任务完成或超时 - allFutures.get(30, TimeUnit.SECONDS); - - // 获取结果 - FmMetricsResponse fm = fmFuture.get(); - JvmMetricsResponse jvm = jvmFuture.get(); - CpuMetricsResponse cpu = cpuFuture.get(); - MemoryMetricsResponse memory = memoryFuture.get(); - ThreadMetricsResponse threads = threadsFuture.get(); - DiskMetricsResponse disk = diskFuture.get(); - NetworkMetricsResponse network = networkFuture.get(); - SystemSummaryResponse summary = summaryFuture.get(); - PrometheusMetricsResponse prometheus = prometheusFuture.get(); - - long processingTime = System.currentTimeMillis() - startTime; - - return AllMetricsResponse.builder() - .fm(fm) - .jvm(jvm) - .cpu(cpu) - .memory(memory) - .threads(threads) - .disk(disk) - .network(network) - .summary(summary) - .prometheus(prometheus) - .processingTimeMs(processingTime) - .build(); - - } catch (Exception e) { - e.printStackTrace(); - long processingTime = System.currentTimeMillis() - startTime; - String errorMessage = "获取监控指标失败: " + e.getMessage(); - log.error(errorMessage); - AllMetricsResponse errorResponse = AllMetricsResponse.builder().error(errorMessage).build(); - errorResponse.setProcessingTimeMs(processingTime); - return errorResponse; - } - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/ProjectApplicationService.java b/flexmodel-server/src/main/java/dev/flexmodel/application/ProjectApplicationService.java deleted file mode 100644 index 54ee3df5..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/ProjectApplicationService.java +++ /dev/null @@ -1,65 +0,0 @@ -package dev.flexmodel.application; - -import dev.flexmodel.application.dto.ProjectListRequest; -import dev.flexmodel.application.dto.ProjectResponse; -import dev.flexmodel.codegen.entity.Project; -import dev.flexmodel.domain.model.api.ApiDefinitionService; -import dev.flexmodel.domain.model.auth.ProjectService; -import dev.flexmodel.domain.model.flow.service.FlowDeploymentService; -import dev.flexmodel.domain.model.storage.StorageService; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import java.util.List; -import java.util.Objects; - -/** - * @author cjbi - */ -@ApplicationScoped -public class ProjectApplicationService { - - @Inject - ProjectService projectService; - @Inject - ApiDefinitionService apiDefinitionService; - @Inject - FlowDeploymentService flowDeploymentService; - @Inject - StorageService storageService; - - public List findProjects(ProjectListRequest request) { - return projectService.findProjects().stream() - .map(project -> { - ProjectResponse response = ProjectResponse.fromProject(project); - if (Objects.equals(request.getIncldue(), "stats")) { - ProjectResponse.ProjectStats projectStats = new ProjectResponse.ProjectStats( - apiDefinitionService.count(project.getId()), - flowDeploymentService.count(project.getId()), - -1, - storageService.count(project.getId()) - ); - response.setStats(projectStats); - } - return response; - } - ).toList(); - } - - public Project findProject(String projectId) { - return projectService.findProject(projectId); - } - - public Project createProject(Project project) { - return projectService.createProject(project); - } - - public Project updateProject(Project project) { - return projectService.updateProject(project); - } - - public void deleteProject(String projectId) { - projectService.deleteProject(projectId); - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/SettingsApplicationService.java b/flexmodel-server/src/main/java/dev/flexmodel/application/SettingsApplicationService.java deleted file mode 100644 index 1ceb4769..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/SettingsApplicationService.java +++ /dev/null @@ -1,25 +0,0 @@ -package dev.flexmodel.application; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import dev.flexmodel.domain.model.settings.Settings; -import dev.flexmodel.domain.model.settings.SettingsService; - -/** - * @author cjbi - */ -@ApplicationScoped -public class SettingsApplicationService { - - @Inject - SettingsService settingsService; - - public Settings getSettings() { - return settingsService.getSettings(); - } - - public Settings saveSettings(Settings settings) { - return settingsService.saveSettings(settings); - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/consumer/ApiDefinitionChangedEventConsumer.java b/flexmodel-server/src/main/java/dev/flexmodel/application/consumer/ApiDefinitionChangedEventConsumer.java deleted file mode 100644 index 0bb8949e..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/consumer/ApiDefinitionChangedEventConsumer.java +++ /dev/null @@ -1,34 +0,0 @@ -package dev.flexmodel.application.consumer; - -import io.quarkus.vertx.ConsumeEvent; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.codegen.entity.ApiDefinition; -import dev.flexmodel.codegen.entity.ApiDefinitionHistory; -import dev.flexmodel.domain.model.api.ApiDefinitionChangedEvent; -import dev.flexmodel.domain.model.api.ApiDefinitionService; -import dev.flexmodel.shared.utils.JsonUtils; - -/** - * @author cjbi - */ -@Slf4j -@ApplicationScoped -public class ApiDefinitionChangedEventConsumer { - - @Inject - ApiDefinitionService apiDefinitionService; - - @ConsumeEvent("api.changed") - public void consume(ApiDefinitionChangedEvent event) { - log.info("ApiDefinitionChangedEvent: {}", event); - ApiDefinition apiDefinition = event.apiDefinition(); - ApiDefinitionHistory history = JsonUtils.getInstance().convertValue(apiDefinition, ApiDefinitionHistory.class); - history.setId(null); - history.setApiDefinitionId(apiDefinition.getId()); - apiDefinitionService.saveApiDefinitionHistory(history); - } - - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/consumer/GraphQLEventConsumer.java b/flexmodel-server/src/main/java/dev/flexmodel/application/consumer/GraphQLEventConsumer.java deleted file mode 100644 index 95fa282f..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/consumer/GraphQLEventConsumer.java +++ /dev/null @@ -1,52 +0,0 @@ -package dev.flexmodel.application.consumer; - -import io.quarkus.runtime.StartupEvent; -import io.quarkus.vertx.ConsumeEvent; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.event.Observes; -import jakarta.inject.Inject; -import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.codegen.entity.Project; -import dev.flexmodel.domain.model.api.GraphQLManger; -import dev.flexmodel.application.dto.GraphQLRefreshEvent; -import dev.flexmodel.domain.model.auth.ProjectService; -import dev.flexmodel.session.SessionFactory; - -import java.util.List; - -/** - * 监听GraphQL变更事件 - * @author cjbi - */ -@Slf4j -@ApplicationScoped -public class GraphQLEventConsumer { - - @Inject - SessionFactory sf; - @Inject - GraphQLManger graphQLManger; - @Inject - ProjectService projectService; - - public void handle(@Observes StartupEvent startupEvent) { - consume(new GraphQLRefreshEvent()); - } - - @ConsumeEvent("graphql.refresh") - public void consume(GraphQLRefreshEvent event) { - long beginTime = System.currentTimeMillis(); - log.info("Received graphql message"); - List projects = projectService.findProjects(); -// for (Project project : projects) { -// Map> dsMap = datasourceList.stream() -// .filter(f -> f.getProjectId() != null) -// .collect(groupingBy(Datasource::getProjectId, mapping(Datasource::getName, toList()))); -// FlexmodelGraphQL fg = new FlexmodelGraphQL(); -// graphQLManger.addDefaultGraphQL(fg.generateGraphQLWithSchemaObject(sf, sf.getSchemaNames())); -// dsMap.forEach((projectId, datasourceNames) -> graphQLManger.addGraphQL(projectId, fg.generateGraphQLWithSchemaObject(sf, datasourceNames))); -// } - log.info("========== GraphQL init successful in {} ms!", System.currentTimeMillis() - beginTime); - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/AllMetricsResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/application/dto/AllMetricsResponse.java deleted file mode 100644 index 2d11aa8d..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/AllMetricsResponse.java +++ /dev/null @@ -1,42 +0,0 @@ -package dev.flexmodel.application.dto; - -import lombok.*; - -/** - * 所有监控指标响应DTO - * 包含JVM、CPU、内存、线程、磁盘、网络等所有监控信息 - * - * @author cjbi - */ -@Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -@Builder -public class AllMetricsResponse { - - private JvmMetricsResponse jvm; - - private CpuMetricsResponse cpu; - - private MemoryMetricsResponse memory; - - private ThreadMetricsResponse threads; - - private DiskMetricsResponse disk; - - private NetworkMetricsResponse network; - - private SystemSummaryResponse summary; - - private PrometheusMetricsResponse prometheus; - - private FmMetricsResponse fm; - - private long timestamp; - - private long processingTimeMs; - - private String error; - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ApiDefinitionTreeDTO.java b/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ApiDefinitionTreeDTO.java deleted file mode 100644 index f20e8915..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ApiDefinitionTreeDTO.java +++ /dev/null @@ -1,37 +0,0 @@ -package dev.flexmodel.application.dto; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import dev.flexmodel.codegen.entity.ApiDefinition; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author cjbi - */ -@EqualsAndHashCode(callSuper = true) -@Data -public class ApiDefinitionTreeDTO extends ApiDefinition { - - private List children = new ArrayList<>(); - - public ApiDefinitionTreeDTO() { - } - - public ApiDefinitionTreeDTO(ApiDefinition apiDefinition) { - this.setId(apiDefinition.getId()); - this.setName(apiDefinition.getName()); - this.setParentId(apiDefinition.getParentId()); - this.setType(apiDefinition.getType()); - this.setMethod(apiDefinition.getMethod()); - this.setPath(apiDefinition.getPath()); - this.setMeta(apiDefinition.getMeta()); - this.setEnabled(apiDefinition.getEnabled()); - this.setCreatedBy(apiDefinition.getCreatedBy()); - this.setUpdatedBy(apiDefinition.getUpdatedBy()); - this.setCreatedAt(apiDefinition.getCreatedAt()); - this.setUpdatedAt(apiDefinition.getUpdatedAt()); - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/CpuMetricsResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/application/dto/CpuMetricsResponse.java deleted file mode 100644 index 56de5ea3..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/CpuMetricsResponse.java +++ /dev/null @@ -1,47 +0,0 @@ -package dev.flexmodel.application.dto; - -import lombok.Getter; -import lombok.Setter; - -/** - * CPU监控响应DTO - * - * @author cjbi - */ -@Getter -@Setter -public class CpuMetricsResponse { - - private int availableProcessors; - - private String architecture; - - private String name; - - private String version; - - private Double systemCpuLoad; - - private Double processCpuLoad; - - private Double systemLoadAverage; - - private Long totalPhysicalMemorySize; - - private Long freePhysicalMemorySize; - - private Long totalSwapSpaceSize; - - private Long freeSwapSpaceSize; - - private Long committedVirtualMemorySize; - - private long maxMemory; - - private long totalMemory; - - private long freeMemory; - - private long usedMemory; - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/DiskMetricsResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/application/dto/DiskMetricsResponse.java deleted file mode 100644 index bdc3fd4f..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/DiskMetricsResponse.java +++ /dev/null @@ -1,113 +0,0 @@ -package dev.flexmodel.application.dto; - -import lombok.Getter; -import lombok.Setter; - -import java.util.Map; - -/** - * 磁盘监控响应DTO - * - * @author cjbi - */ -@Getter -@Setter -public class DiskMetricsResponse { - - private Map fileSystems; - - private FileSystemInfo rootDirectory; - - private int totalFileSystems; - - private long totalSpace; - - private long totalUsableSpace; - - private long totalFreeSpace; - - private DiskIoInfo diskIo; - - @Getter - @Setter - public static class FileSystemInfo { - private String name; - - private String type; - - private long totalSpace; - - private long usedSpace; - - private long usableSpace; - - private long freeSpace; - - private double usagePercentage; - - private boolean isReadOnly; - - private double totalSpaceGB; - - private double usedSpaceGB; - - private double usableSpaceGB; - - private double freeSpaceGB; - - private Long lastModified; - - } - - @Getter - @Setter - public static class DiskIoInfo { - private long committedVirtualMemorySize; - - private ProcessIoInfo processIo; - - private FileSystemStatsInfo fileSystemStats; - - private JvmIoInfo jvmIo; - - private String error; - - private String fileSystemError; - - } - - @Getter - @Setter - public static class ProcessIoInfo { - private long committedVirtualMemoryMB; - - } - - @Getter - @Setter - public static class FileSystemStatsInfo { - private long totalSpace; - - private long freeSpace; - - private long usableSpace; - - private long lastModified; - - private double spaceUtilization; - - } - - @Getter - @Setter - public static class JvmIoInfo { - private long maxMemory; - - private long totalMemory; - - private long freeMemory; - - private long usedMemory; - - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/GenerateAPIsDTO.java b/flexmodel-server/src/main/java/dev/flexmodel/application/dto/GenerateAPIsDTO.java deleted file mode 100644 index e7206986..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/GenerateAPIsDTO.java +++ /dev/null @@ -1,30 +0,0 @@ -package dev.flexmodel.application.dto; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotEmpty; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; - -import java.util.List; - -/** - * @author cjbi - */ -@AllArgsConstructor -@Getter -@Setter -@ToString -public class GenerateAPIsDTO { - @NotBlank - private String datasourceName; - @NotBlank - private String modelName; - @NotBlank - private String apiFolder; - @NotBlank - private String idFieldOfPath; - @NotEmpty - private List generateAPIs; -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/JvmMetricsResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/application/dto/JvmMetricsResponse.java deleted file mode 100644 index a8b2273e..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/JvmMetricsResponse.java +++ /dev/null @@ -1,45 +0,0 @@ -package dev.flexmodel.application.dto; - -import lombok.Getter; -import lombok.Setter; - -import java.util.Map; - -/** - * JVM监控响应DTO - * - * @author cjbi - */ -@Getter -@Setter -public class JvmMetricsResponse { - - private String name; - - private String version; - - private String vendor; - - private long uptime; - - private long startTime; - - private int loadedClassCount; - - private long totalLoadedClassCount; - - private long unloadedClassCount; - - private Map garbageCollectors; - - private Map systemProperties; - - - @Getter - @Setter - public static class GarbageCollectorInfo { - private long collectionCount; - - private long collectionTime; - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/MemoryMetricsResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/application/dto/MemoryMetricsResponse.java deleted file mode 100644 index 9cd0014f..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/MemoryMetricsResponse.java +++ /dev/null @@ -1,56 +0,0 @@ -package dev.flexmodel.application.dto; - -import lombok.Getter; -import lombok.Setter; - -import java.util.Map; - -/** - * 内存监控响应DTO - * - * @author cjbi - */ -@Getter -@Setter -public class MemoryMetricsResponse { - - private MemoryInfo heap; - - private MemoryInfo nonHeap; - - private Map memoryPools; - - @Getter - @Setter - public static class MemoryInfo { - private long init; - - private long used; - - private long committed; - - private long max; - - private double usagePercentage; - - } - - @Getter - @Setter - public static class MemoryPoolInfo { - private long init; - - private long used; - - private long committed; - - private long max; - - private double usagePercentage; - - private String type; - - private String memoryManagerNames; - - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/NetworkMetricsResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/application/dto/NetworkMetricsResponse.java deleted file mode 100644 index 77ea68e2..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/NetworkMetricsResponse.java +++ /dev/null @@ -1,96 +0,0 @@ -package dev.flexmodel.application.dto; - -import lombok.Getter; -import lombok.Setter; - -import java.util.Map; - -/** - * 网络监控响应DTO - * - * @author cjbi - */ -@Getter -@Setter -public class NetworkMetricsResponse { - - private Map interfaces; - - private int totalInterfaces; - - private LocalhostInfo localhost; - - private NetworkStatsInfo stats; - - private String localhostError; - - @Getter - @Setter - public static class NetworkInterfaceInfo { - private String name; - - private String displayName; - - private boolean isUp; - - private boolean isLoopback; - - private boolean isVirtual; - - private boolean isPointToPoint; - - private boolean supportsMulticast; - - private String macAddress; - - private int mtu; - - private Map addresses; - - private String parent; - - private Map subInterfaces; - - } - - @Getter - @Setter - public static class AddressInfo { - private String address; - - private String hostName; - - private short networkPrefixLength; - - private String broadcast; - - } - - @Getter - @Setter - public static class LocalhostInfo { - private String hostName; - - private String hostAddress; - - private String canonicalHostName; - - private boolean isLoopbackAddress; - - private boolean isLinkLocalAddress; - - private boolean isSiteLocalAddress; - - private boolean isMulticastAddress; - - } - - @Getter - @Setter - public static class NetworkStatsInfo { - private int activeInterfaces; - - private long timestamp; - - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/OverviewDTO.java b/flexmodel-server/src/main/java/dev/flexmodel/application/dto/OverviewDTO.java deleted file mode 100644 index f3bb192b..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/OverviewDTO.java +++ /dev/null @@ -1,34 +0,0 @@ -package dev.flexmodel.application.dto; - -import lombok.Getter; -import lombok.Setter; -import dev.flexmodel.domain.model.api.LogApiRank; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author cjbi - */ -@Getter -@Setter -public class OverviewDTO { - - private int queryCount = 0; - private int mutationCount = 0; - private int subscribeCount = 0; - private int dataSourceCount = 0; - - private List apiRankingList = new ArrayList<>(); - - private ApiStatDTO apiStat; - - @Getter - @Setter - public static class ApiStatDTO { - private List dateList; - private List successData; - private List failData; - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/PrometheusMetricsResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/application/dto/PrometheusMetricsResponse.java deleted file mode 100644 index c59d8631..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/PrometheusMetricsResponse.java +++ /dev/null @@ -1,34 +0,0 @@ -package dev.flexmodel.application.dto; - -import lombok.Getter; -import lombok.Setter; - -/** - * Prometheus指标响应DTO - * - * @author cjbi - */ -@Getter -@Setter -public class PrometheusMetricsResponse { - - private String metrics; - - private String error; - - public PrometheusMetricsResponse() { - } - - public PrometheusMetricsResponse(String metrics, String error) { - this.metrics = metrics; - this.error = error; - } - - public static PrometheusMetricsResponse success(String metrics) { - return new PrometheusMetricsResponse(metrics, null); - } - - public static PrometheusMetricsResponse error(String error) { - return new PrometheusMetricsResponse(null, error); - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/SystemSummaryResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/application/dto/SystemSummaryResponse.java deleted file mode 100644 index d3f959ea..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/SystemSummaryResponse.java +++ /dev/null @@ -1,75 +0,0 @@ -package dev.flexmodel.application.dto; - -import lombok.Getter; -import lombok.Setter; - -/** - * 系统摘要响应DTO - * - * @author cjbi - */ -@Getter -@Setter -public class SystemSummaryResponse { - - private long systemTime; - - private long uptime; - - private int availableProcessors; - - private String osName; - - private String osVersion; - - private String osArch; - - private long heapUsedMB; - - private long heapMaxMB; - - private double heapUsagePercentage; - - private int threadCount; - - private int peakThreadCount; - - private int daemonThreadCount; - - private double diskTotalSpaceGB; - - private double diskUsableSpaceGB; - - private double diskFreeSpaceGB; - - private double diskUsagePercentage; - - private Integer totalNetworkInterfaces; - - private Integer upNetworkInterfaces; - - private String hostName; - - private String hostAddress; - - private String networkError; - - private String jvmName; - - private String jvmVersion; - - private String jvmVendor; - - private int loadedClassCount; - - private long totalLoadedClassCount; - - private long totalGcCount; - - private long totalGcTime; - - private Double systemCpuLoad; - - private Double processCpuLoad; - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ThreadMetricsResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ThreadMetricsResponse.java deleted file mode 100644 index f980ebb7..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ThreadMetricsResponse.java +++ /dev/null @@ -1,57 +0,0 @@ -package dev.flexmodel.application.dto; - -import lombok.Getter; -import lombok.Setter; - -import java.util.Map; - -/** - * 线程监控响应DTO - * - * @author cjbi - */ -@Getter -@Setter -public class ThreadMetricsResponse { - - private int threadCount; - - private int peakThreadCount; - - private int daemonThreadCount; - - private long totalStartedThreadCount; - - private long currentThreadCpuTime; - - private long currentThreadUserTime; - - private Map threadStates; - - private Map threadDetails; - - @Getter - @Setter - public static class ThreadDetailInfo { - private String name; - - private String state; - - private long blockedTime; - - private long blockedCount; - - private long waitedTime; - - private long waitedCount; - - private long cpuTime; - - private long userTime; - - private String lockName; - - private String lockOwnerName; - - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/AuthException.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/AuthException.java similarity index 71% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/AuthException.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/AuthException.java index b836c9ec..4f86550a 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/AuthException.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/AuthException.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.auth; +package dev.flexmodel.auth; -import dev.flexmodel.domain.model.BusinessException; +import dev.flexmodel.common.BusinessException; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/AuthResource.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/AuthResource.java similarity index 82% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/AuthResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/AuthResource.java index 87cc6c64..a7f07ef0 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/AuthResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/AuthResource.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.auth; import jakarta.annotation.security.PermitAll; import jakarta.inject.Inject; @@ -7,16 +7,12 @@ import jakarta.ws.rs.core.NewCookie; import jakarta.ws.rs.core.Response; import lombok.extern.slf4j.Slf4j; -import org.eclipse.microprofile.config.ConfigProvider; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.AuthApplicationService; import dev.flexmodel.codegen.entity.User; -import dev.flexmodel.interfaces.rest.jwt.JwtUtil; -import dev.flexmodel.interfaces.rest.response.UserinfoResponse; +import dev.flexmodel.common.config.web.jwt.JwtUtil; +import dev.flexmodel.common.config.web.response.UserinfoResponse; import java.time.Duration; -import java.util.HashMap; -import java.util.Map; /** * @author cjbi @@ -28,13 +24,13 @@ public class AuthResource { @Inject - AuthApplicationService authApplicationService; + AuthService authService; @POST @Path("/login") @PermitAll public Response login(LoginRequest req) { - User user = authApplicationService.login(req.username, req.password); + User user = authService.login(req.username, req.password); // 签发 accessToken String accessToken = JwtUtil.sign(user.getId(), Duration.ofDays(7)); // 签发 refreshToken @@ -61,7 +57,7 @@ public Response refresh(@CookieParam("refreshToken") String refreshToken) { try { String userId = JwtUtil.getClaim(refreshToken, JwtUtil.ACCOUNT); - User user = authApplicationService.getUser(userId); + User user = authService.getUser(userId); // 签发新 accessToken String newAccess = JwtUtil.sign(userId, Duration.ofMinutes(5)); @@ -94,7 +90,7 @@ public Response getUserInfo(@HeaderParam("Authorization") String authorization) try { String accessToken = authorization.replace("Bearer ", ""); String userId = JwtUtil.getClaim(accessToken, JwtUtil.ACCOUNT); - User user = authApplicationService.getUser(userId); + User user = authService.getUser(userId); return Response.ok(buildUserInfo(accessToken, user)).build(); } catch (Exception e) { return Response.status(Response.Status.UNAUTHORIZED).build(); @@ -107,7 +103,7 @@ private UserinfoResponse buildUserInfo(String accessToken, User user) { userinfo.setToken(accessToken); userinfo.setExpiresIn(300000L); userinfo.setUser(new UserinfoResponse.UserResponse(user.getId(), user.getName(), user.getEmail())); - userinfo.setPermissions(authApplicationService.findPermissions(user.getId())); + userinfo.setPermissions(authService.findPermissions(user.getId())); return userinfo; } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/AuthApplicationService.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/AuthService.java similarity index 97% rename from flexmodel-server/src/main/java/dev/flexmodel/application/AuthApplicationService.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/AuthService.java index e52ab065..ba1d6b88 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/AuthApplicationService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/AuthService.java @@ -1,9 +1,8 @@ -package dev.flexmodel.application; +package dev.flexmodel.auth; -import dev.flexmodel.application.dto.*; +import dev.flexmodel.auth.dto.*; import dev.flexmodel.codegen.entity.Resource; import dev.flexmodel.codegen.entity.Role; -import dev.flexmodel.domain.model.auth.*; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import lombok.extern.slf4j.Slf4j; @@ -20,7 +19,7 @@ */ @Slf4j @ApplicationScoped -public class AuthApplicationService { +public class AuthService { @Inject UserService userService; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ResourceFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceFmRepository.java similarity index 92% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ResourceFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceFmRepository.java index 2ef8b431..ba07fc25 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ResourceFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceFmRepository.java @@ -1,9 +1,8 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.auth; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.Resource; -import dev.flexmodel.domain.model.auth.ResourceRepository; import dev.flexmodel.session.Session; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/ResourceRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceRepository.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/ResourceRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceRepository.java index 25d6abac..2db9fba3 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/ResourceRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.auth; +package dev.flexmodel.auth; import dev.flexmodel.codegen.entity.Resource; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/ResourceResource.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceResource.java similarity index 80% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/ResourceResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceResource.java index 8ebc7a3f..f8d9f025 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/ResourceResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceResource.java @@ -1,7 +1,6 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.auth; -import dev.flexmodel.application.AuthApplicationService; -import dev.flexmodel.application.dto.ResourceTreeResponse; +import dev.flexmodel.auth.dto.ResourceTreeResponse; import jakarta.inject.Inject; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; @@ -11,7 +10,7 @@ import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.dto.ResourceResponse; +import dev.flexmodel.auth.dto.ResourceResponse; import java.util.List; @@ -22,7 +21,7 @@ public class ResourceResource { @Inject - AuthApplicationService authApplicationService; + AuthService authService; @APIResponse( name = "200", @@ -39,7 +38,7 @@ public class ResourceResource { @Operation(summary = "获取资源列表") @GET public List findAllResources() { - return authApplicationService.findAllResources(); + return authService.findAllResources(); } @APIResponse( @@ -58,7 +57,7 @@ public List findAllResources() { @GET @Path("/tree") public List findResourceTree() { - return authApplicationService.findResourceTree(); + return authService.findResourceTree(); } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/ResourceService.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceService.java similarity index 95% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/ResourceService.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceService.java index 211909af..a84eeb6b 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/ResourceService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceService.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.auth; +package dev.flexmodel.auth; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ResourceTemplateFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceTemplateFmRepository.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ResourceTemplateFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceTemplateFmRepository.java index fb36ee9d..6207e0ba 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ResourceTemplateFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceTemplateFmRepository.java @@ -1,9 +1,8 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.auth; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.ResourceTemplate; -import dev.flexmodel.domain.model.auth.ResourceTemplateRepository; import dev.flexmodel.session.Session; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/ResourceTemplateRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceTemplateRepository.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/ResourceTemplateRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceTemplateRepository.java index 5480c540..446fe529 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/ResourceTemplateRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/ResourceTemplateRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.auth; +package dev.flexmodel.auth; import dev.flexmodel.codegen.entity.ResourceTemplate; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/RoleFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/RoleFmRepository.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/RoleFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/RoleFmRepository.java index cfcb9074..b0d94c5d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/RoleFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/RoleFmRepository.java @@ -1,9 +1,8 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.auth; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.Role; -import dev.flexmodel.domain.model.auth.RoleRepository; import dev.flexmodel.session.Session; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/RoleRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/RoleRepository.java similarity index 86% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/RoleRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/RoleRepository.java index f4b4557c..1fceb4b5 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/RoleRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/RoleRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.auth; +package dev.flexmodel.auth; import dev.flexmodel.codegen.entity.Role; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/RoleResource.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/RoleResource.java similarity index 87% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/RoleResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/RoleResource.java index 95fbdd5b..e8ac21a9 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/RoleResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/RoleResource.java @@ -1,6 +1,5 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.auth; -import dev.flexmodel.application.AuthApplicationService; import jakarta.inject.Inject; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; @@ -14,8 +13,8 @@ import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.dto.RoleRequest; -import dev.flexmodel.application.dto.RoleResponse; +import dev.flexmodel.auth.dto.RoleRequest; +import dev.flexmodel.auth.dto.RoleResponse; import java.util.List; @@ -26,7 +25,7 @@ public class RoleResource { @Inject - AuthApplicationService authApplicationService; + AuthService authService; @APIResponse( name = "200", @@ -43,7 +42,7 @@ public class RoleResource { @Operation(summary = "获取角色列表") @GET public List findAll() { - return authApplicationService.findAllRoles(); + return authService.findAllRoles(); } @Parameter(name = "roleId", description = "角色ID", in = ParameterIn.PATH) @@ -51,7 +50,7 @@ public List findAll() { @GET @Path("/{roleId}") public RoleResponse findById(@PathParam("roleId") String roleId) { - return authApplicationService.findRoleById(roleId); + return authService.findRoleById(roleId); } @RequestBody( @@ -77,7 +76,7 @@ public RoleResponse findById(@PathParam("roleId") String roleId) { @Operation(summary = "创建角色") @POST public RoleResponse createRole(RoleRequest request) { - return authApplicationService.createRole(request); + return authService.createRole(request); } @RequestBody( @@ -106,7 +105,7 @@ public RoleResponse createRole(RoleRequest request) { @Path("/{roleId}") public RoleResponse updateRole(@PathParam("roleId") String roleId, RoleRequest request) { request.setId(roleId); - return authApplicationService.updateRole(request); + return authService.updateRole(request); } @Parameter(name = "roleId", description = "角色ID", in = ParameterIn.PATH) @@ -114,7 +113,7 @@ public RoleResponse updateRole(@PathParam("roleId") String roleId, RoleRequest r @DELETE @Path("/{roleId}") public void deleteRole(@PathParam("roleId") String roleId) { - authApplicationService.deleteRole(roleId); + authService.deleteRole(roleId); } @Schema( diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/RoleService.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/RoleService.java similarity index 97% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/RoleService.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/RoleService.java index ee9c4965..7592735b 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/RoleService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/RoleService.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.auth; +package dev.flexmodel.auth; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/SecurityUtil.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/SecurityUtil.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/SecurityUtil.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/SecurityUtil.java index 6324eb22..1e2b4e78 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/SecurityUtil.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/SecurityUtil.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.auth; +package dev.flexmodel.auth; import java.math.BigInteger; import java.security.MessageDigest; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/UserFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/UserFmRepository.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/UserFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/UserFmRepository.java index 50d5ef1a..2e982316 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/UserFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/UserFmRepository.java @@ -1,9 +1,8 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.auth; import jakarta.inject.Inject; import jakarta.inject.Singleton; import dev.flexmodel.codegen.entity.User; -import dev.flexmodel.domain.model.auth.UserRepository; import dev.flexmodel.session.Session; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/UserRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/UserRepository.java similarity index 87% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/UserRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/UserRepository.java index a7596034..fc8e4501 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/UserRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/UserRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.auth; +package dev.flexmodel.auth; import dev.flexmodel.codegen.entity.User; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/UserResource.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/UserResource.java similarity index 87% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/UserResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/UserResource.java index 929de190..fffdcbf1 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/UserResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/UserResource.java @@ -1,6 +1,5 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.auth; -import dev.flexmodel.application.AuthApplicationService; import jakarta.inject.Inject; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; @@ -14,8 +13,8 @@ import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.dto.UserRequest; -import dev.flexmodel.application.dto.UserResponse; +import dev.flexmodel.auth.dto.UserRequest; +import dev.flexmodel.auth.dto.UserResponse; import java.util.List; @@ -29,7 +28,7 @@ public class UserResource { @Inject - AuthApplicationService authApplicationService; + AuthService authService; @APIResponse( name = "200", @@ -46,7 +45,7 @@ public class UserResource { @Operation(summary = "获取用户列表") @GET public List findAll() { - return authApplicationService.findAllUsers(); + return authService.findAllUsers(); } @Parameter(name = "userId", description = "用户ID", in = ParameterIn.PATH) @@ -54,7 +53,7 @@ public List findAll() { @GET @Path("/{userId}") public UserResponse findById(@PathParam("userId") String userId) { - return authApplicationService.findUserById(userId); + return authService.findUserById(userId); } @RequestBody( @@ -80,7 +79,7 @@ public UserResponse findById(@PathParam("userId") String userId) { @Operation(summary = "创建用户") @POST public UserResponse createUser(UserRequest request) { - return authApplicationService.createUser(request); + return authService.createUser(request); } @RequestBody( @@ -109,7 +108,7 @@ public UserResponse createUser(UserRequest request) { @Path("/{userId}") public UserResponse updateUser(@PathParam("userId") String userId, UserRequest request) { request.setId(userId); - return authApplicationService.updateUser(request); + return authService.updateUser(request); } @Parameter(name = "userId", description = "用户ID", in = ParameterIn.PATH) @@ -117,7 +116,7 @@ public UserResponse updateUser(@PathParam("userId") String userId, UserRequest r @DELETE @Path("/{userId}") public void deleteUser(@PathParam("userId") String userId) { - authApplicationService.deleteUser(userId); + authService.deleteUser(userId); } @Schema( diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/UserService.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/UserService.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/UserService.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/UserService.java index 93730084..cbaa1c48 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/UserService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/UserService.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.auth; +package dev.flexmodel.auth; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ResourceResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/dto/ResourceResponse.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/ResourceResponse.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/dto/ResourceResponse.java index 94761c76..bf53c713 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ResourceResponse.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/dto/ResourceResponse.java @@ -1,11 +1,9 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.auth.dto; import lombok.Getter; import dev.flexmodel.codegen.entity.Resource; import lombok.Setter; -import java.util.List; - @Setter @Getter public class ResourceResponse { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ResourceTreeResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/dto/ResourceTreeResponse.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/ResourceTreeResponse.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/dto/ResourceTreeResponse.java index 6ac15de5..fb6e3c23 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ResourceTreeResponse.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/dto/ResourceTreeResponse.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.auth.dto; import lombok.Getter; import dev.flexmodel.codegen.entity.Resource; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/RoleRequest.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/dto/RoleRequest.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/RoleRequest.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/dto/RoleRequest.java index 89bc06c0..e310b86d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/RoleRequest.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/dto/RoleRequest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.auth.dto; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/RoleResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/dto/RoleResponse.java similarity index 98% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/RoleResponse.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/dto/RoleResponse.java index c1959f21..47ddcb86 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/RoleResponse.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/dto/RoleResponse.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.auth.dto; import lombok.Getter; import dev.flexmodel.codegen.entity.Role; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/UserRequest.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/dto/UserRequest.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/UserRequest.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/dto/UserRequest.java index cc9b1898..10174d86 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/UserRequest.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/dto/UserRequest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.auth.dto; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/UserResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/auth/dto/UserResponse.java similarity index 97% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/UserResponse.java rename to flexmodel-server/src/main/java/dev/flexmodel/auth/dto/UserResponse.java index c372905d..199d86f7 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/UserResponse.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/auth/dto/UserResponse.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.auth.dto; import lombok.Getter; import dev.flexmodel.codegen.entity.User; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/AbstractRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/common/AbstractRepository.java similarity index 84% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/AbstractRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/AbstractRepository.java index a6e6b07f..cb898cd6 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/AbstractRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/AbstractRepository.java @@ -1,8 +1,7 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.common; import dev.flexmodel.session.Session; import dev.flexmodel.session.SessionFactory; -import dev.flexmodel.shared.SessionContextHolder; import jakarta.inject.Inject; /** diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/AuditDataEventListener.java b/flexmodel-server/src/main/java/dev/flexmodel/common/AuditDataEventListener.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/application/AuditDataEventListener.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/AuditDataEventListener.java index a8790590..99adba1d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/AuditDataEventListener.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/AuditDataEventListener.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application; +package dev.flexmodel.common; import jakarta.enterprise.context.ApplicationScoped; import lombok.extern.slf4j.Slf4j; @@ -10,8 +10,7 @@ import dev.flexmodel.model.field.TypedField; import dev.flexmodel.query.Query; import dev.flexmodel.session.SessionFactory; -import dev.flexmodel.shared.SessionContextHolder; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.common.utils.JsonUtils; import java.time.LocalDateTime; import java.util.ArrayList; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/BusinessException.java b/flexmodel-server/src/main/java/dev/flexmodel/common/BusinessException.java similarity index 87% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/BusinessException.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/BusinessException.java index 1392ac15..a848c644 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/BusinessException.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/BusinessException.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model; +package dev.flexmodel.common; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/shared/Constants.java b/flexmodel-server/src/main/java/dev/flexmodel/common/Constants.java similarity index 79% rename from flexmodel-server/src/main/java/dev/flexmodel/shared/Constants.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/Constants.java index a981dc68..0734adea 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/shared/Constants.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/Constants.java @@ -1,4 +1,4 @@ -package dev.flexmodel.shared; +package dev.flexmodel.common; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/shared/FlexmodelConfig.java b/flexmodel-server/src/main/java/dev/flexmodel/common/FlexmodelConfig.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/shared/FlexmodelConfig.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/FlexmodelConfig.java index 3ee6cc18..efcc2286 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/shared/FlexmodelConfig.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/FlexmodelConfig.java @@ -1,4 +1,4 @@ -package dev.flexmodel.shared; +package dev.flexmodel.common; import io.smallrye.config.ConfigMapping; import io.smallrye.config.WithDefault; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/Jobs.java b/flexmodel-server/src/main/java/dev/flexmodel/common/Jobs.java similarity index 52% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/Jobs.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/Jobs.java index 97da5fa6..06a579a4 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/Jobs.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/Jobs.java @@ -1,11 +1,11 @@ -package dev.flexmodel.infrastructure; +package dev.flexmodel.common; import io.quarkus.scheduler.Scheduled; import jakarta.inject.Inject; -import dev.flexmodel.application.SettingsApplicationService; -import dev.flexmodel.domain.model.api.ApiRequestLogService; -import dev.flexmodel.domain.model.schedule.JobExecutionLogService; -import dev.flexmodel.domain.model.settings.Settings; +import dev.flexmodel.settings.SettingsService; +import dev.flexmodel.api.ApiRequestLogService; +import dev.flexmodel.scheduling.JobExecutionLogService; +import dev.flexmodel.settings.Settings; /** * @author cjbi @@ -13,7 +13,7 @@ public class Jobs { @Inject - SettingsApplicationService settingsApplicationService; + SettingsService settingsService; @Inject ApiRequestLogService apiLogService; @Inject @@ -21,7 +21,7 @@ public class Jobs { @Scheduled(cron = "0 0 1 * * ?") void purgeOldLogs() { - Settings settings = settingsApplicationService.getSettings(); + Settings settings = settingsService.getSettings(); apiLogService.purgeOldLogs(settings.getLog().getMaxDays()); jobExecutionLogService.purgeOldLogs(settings.getLog().getMaxDays()); } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/common/SchemaInitializer.java b/flexmodel-server/src/main/java/dev/flexmodel/common/SchemaInitializer.java new file mode 100644 index 00000000..fd2df9fc --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/SchemaInitializer.java @@ -0,0 +1,32 @@ +package dev.flexmodel.common; + +import dev.flexmodel.session.SessionFactory; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import lombok.extern.slf4j.Slf4j; + +/** + * 使用 project.fml 模板初始化新 Schema 的表结构。 + *

    + * 新建物理 Schema 后,调用此组件在其中创建所有预定义表(flow、trigger、storage 等)。 + * + * @author cjbi + */ +@ApplicationScoped +@Slf4j +public class SchemaInitializer { + + @Inject + SessionFactory sessionFactory; + + /** + * 在指定 Schema 中执行 project.fml,初始化项目级表结构。 + * + * @param schemaName 目标 Schema 名称 + */ + public void init(String schemaName) { + log.info("Initializing schema '{}' with project.fml template", schemaName); + sessionFactory.loadScript(schemaName, "project.fml"); + log.info("Schema '{}' initialized successfully", schemaName); + } +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/shared/SessionContextHolder.java b/flexmodel-server/src/main/java/dev/flexmodel/common/SessionContextHolder.java similarity index 97% rename from flexmodel-server/src/main/java/dev/flexmodel/shared/SessionContextHolder.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/SessionContextHolder.java index 8f6a5694..480afe7d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/shared/SessionContextHolder.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/SessionContextHolder.java @@ -1,4 +1,4 @@ -package dev.flexmodel.shared; +package dev.flexmodel.common; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/SessionDatasourceImpl.java b/flexmodel-server/src/main/java/dev/flexmodel/common/SessionDatasourceImpl.java similarity index 60% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/SessionDatasourceImpl.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/SessionDatasourceImpl.java index be900af2..397402d7 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/SessionDatasourceImpl.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/SessionDatasourceImpl.java @@ -1,16 +1,14 @@ -package dev.flexmodel.infrastructure; +package dev.flexmodel.common; import com.zaxxer.hikari.HikariDataSource; import dev.flexmodel.SchemaProvider; import dev.flexmodel.codegen.entity.Project; -import dev.flexmodel.domain.model.connect.NativeQueryResult; -import dev.flexmodel.domain.model.connect.SessionDatasource; -import dev.flexmodel.infrastructure.session.SessionConfig; +import dev.flexmodel.connect.NativeQueryResult; +import dev.flexmodel.connect.SessionDatasource; +import dev.flexmodel.common.config.SessionConfig; import dev.flexmodel.session.Session; import dev.flexmodel.session.SessionFactory; -import dev.flexmodel.shared.FlexmodelConfig; -import dev.flexmodel.shared.SystemVariablesHolder; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.common.utils.StringUtils; import dev.flexmodel.sql.JdbcSchemaProvider; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -63,14 +61,47 @@ public List getPhysicsModelNames(Project project) { @Override public void add(Project project) { + registerSchema(project.getDatabaseName()); + } + + @Override + public void registerSchema(String schemaName) { try { - SchemaProvider schemaProvider = new JdbcSchemaProvider(project.getDatabaseName().equals("system")? "flexmodel" : project.getDatabaseName(), buildJdbcDataSource(project.getDatabaseName())); - sessionFactory.registerSchemaProvider(schemaProvider); + String actualSchemaName = "system".equals(schemaName) ? "flexmodel" : schemaName; + // 如果配置文件中有该数据源的显式配置,使用配置中的URL而非模板URL + FlexmodelConfig.DatasourceConfig configDs = flexmodelConfig.datasources().get(schemaName); + if (configDs != null) { + // 配置文件中已定义该数据源,如果SchemaProvider已注册则跳过 + if (sessionFactory.isSchemaExists(actualSchemaName)) { + log.info("SchemaProvider '{}' already registered from config, skipping dynamic registration", actualSchemaName); + return; + } + // 配置存在但SchemaProvider未注册,使用配置URL创建 + HikariDataSource ds = new HikariDataSource(); + ds.setMaxLifetime(30000); + ds.setJdbcUrl(configDs.url()); + ds.setUsername(configDs.username().orElse(null)); + ds.setPassword(configDs.password().orElse(null)); + SchemaProvider schemaProvider = new JdbcSchemaProvider(actualSchemaName, ds); + sessionFactory.registerSchemaProvider(schemaProvider); + log.info("Registered SchemaProvider '{}' from config URL: {}", actualSchemaName, configDs.url()); + } else { + // 配置文件中没有显式配置,使用projectUrlTemplate动态创建 + SchemaProvider schemaProvider = new JdbcSchemaProvider(actualSchemaName, buildJdbcDataSource(schemaName)); + sessionFactory.registerSchemaProvider(schemaProvider); + log.info("Registered SchemaProvider '{}' from template URL", actualSchemaName); + } } catch (Exception e) { log.error("Session dataSource create error: {}", e.getMessage(), e); } } + @Override + public void unregisterSchema(String schemaName) { + sessionFactory.unregisterSchemaProvider(schemaName); + log.info("Unregistered SchemaProvider '{}'", schemaName); + } + public DataSource buildJdbcDataSource(String databaseName) { FlexmodelConfig.DatasourceConfig datasource = flexmodelConfig.datasources().get("system"); String jdbcUrl = flexmodelConfig.projectUrlTemplate().replace("{{databaseName}}", databaseName); diff --git a/flexmodel-server/src/main/java/dev/flexmodel/shared/SystemVariablesHolder.java b/flexmodel-server/src/main/java/dev/flexmodel/common/SystemVariablesHolder.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/shared/SystemVariablesHolder.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/SystemVariablesHolder.java index d039fa5d..33f4a51e 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/shared/SystemVariablesHolder.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/SystemVariablesHolder.java @@ -1,4 +1,4 @@ -package dev.flexmodel.shared; +package dev.flexmodel.common; import org.eclipse.microprofile.config.ConfigProvider; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/session/SessionConfig.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/SessionConfig.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/session/SessionConfig.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/SessionConfig.java index 3ac982bc..ae08b403 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/session/SessionConfig.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/SessionConfig.java @@ -1,18 +1,18 @@ -package dev.flexmodel.infrastructure.session; +package dev.flexmodel.common.config; import com.zaxxer.hikari.HikariDataSource; -import dev.flexmodel.domain.model.connect.SessionDatasource; +import dev.flexmodel.connect.SessionDatasource; import io.quarkus.runtime.StartupEvent; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.event.Observes; import jakarta.enterprise.inject.Produces; import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.application.AuditDataEventListener; -import dev.flexmodel.application.TriggerDataChangedEventListener; +import dev.flexmodel.common.AuditDataEventListener; +import dev.flexmodel.scheduling.TriggerDataChangedEventListener; import dev.flexmodel.codegen.entity.Project; -import dev.flexmodel.domain.model.auth.ProjectService; +import dev.flexmodel.project.ProjectService; import dev.flexmodel.session.SessionFactory; -import dev.flexmodel.shared.FlexmodelConfig; +import dev.flexmodel.common.FlexmodelConfig; import dev.flexmodel.sql.JdbcSchemaProvider; import java.util.List; diff --git a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/SessionProvider.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/SessionProvider.java similarity index 63% rename from flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/SessionProvider.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/SessionProvider.java index 510a0429..12d58c16 100644 --- a/flexmodel-engine/flexmodel-quarkus/src/main/java/dev/flexmodel/quarkus/session/SessionProvider.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/SessionProvider.java @@ -1,20 +1,21 @@ -package dev.flexmodel.quarkus.session; +package dev.flexmodel.common.config; +import dev.flexmodel.session.Session; +import dev.flexmodel.session.SessionFactory; import jakarta.annotation.PreDestroy; import jakarta.enterprise.context.RequestScoped; import jakarta.enterprise.inject.Produces; import jakarta.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.session.Session; /** * Session提供者 * 用于在CDI容器中提供Session实例 - * + *

    * 该提供者通过QuarkusSessionManager获取当前Session,支持在异步操作中访问 * (通过上下文传播机制) - * + *

    * 注意:Session的生命周期由SessionInterceptor管理,此Provider只是提供访问入口 * * @author cjbi @@ -24,8 +25,11 @@ public class SessionProvider { private static final Logger log = LoggerFactory.getLogger(SessionProvider.class); + private final ThreadLocal sessionHolder = new ThreadLocal<>(); + @Inject - QuarkusSessionManager sessionManager; + SessionFactory sessionFactory; + /** * 提供默认Session @@ -38,14 +42,11 @@ public Session provideSession() { log.debug("Providing session via CDI"); // 获取当前Session(如果不存在会创建,但这应该由SessionInterceptor负责) - Session session = sessionManager.getCurrentSessionOrNull(); - - if (session == null) { - // 如果没有活跃的Session,尝试获取默认Session(这会创建新的Session) - // 这种情况应该很少发生,因为SessionInterceptor应该已经创建了Session - log.warn("No active session found, creating default session. " + - "Consider using @SessionManaged annotation on your method or class."); - session = sessionManager.getCurrentSession(); + Session session = sessionHolder.get(); + + if (session == null || session.isClosed()) { + session = sessionFactory.createSession(); + sessionHolder.set(session); } return session; @@ -53,7 +54,12 @@ public Session provideSession() { @PreDestroy public void destroy() { - sessionManager.closeAllSessions();; + Session session = sessionHolder.get(); + if (session != null) { + session.close(); + } + log.debug("Closing session via CDI"); + sessionHolder.remove(); } } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/exception/BusinessExceptionMapper.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/exception/BusinessExceptionMapper.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/exception/BusinessExceptionMapper.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/exception/BusinessExceptionMapper.java index b6a31038..81824932 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/exception/BusinessExceptionMapper.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/exception/BusinessExceptionMapper.java @@ -1,10 +1,10 @@ -package dev.flexmodel.interfaces.rest.exception; +package dev.flexmodel.common.config.web.exception; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.Provider; import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.domain.model.BusinessException; +import dev.flexmodel.common.BusinessException; import java.util.HashMap; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/exception/DefaultExceptionMapper.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/exception/DefaultExceptionMapper.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/exception/DefaultExceptionMapper.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/exception/DefaultExceptionMapper.java index fc19511e..4ea71c71 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/exception/DefaultExceptionMapper.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/exception/DefaultExceptionMapper.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest.exception; +package dev.flexmodel.common.config.web.exception; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/exception/JWTValidationExceptionMapper.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/exception/JWTValidationExceptionMapper.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/exception/JWTValidationExceptionMapper.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/exception/JWTValidationExceptionMapper.java index 46f948e7..58b78f24 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/exception/JWTValidationExceptionMapper.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/exception/JWTValidationExceptionMapper.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest.exception; +package dev.flexmodel.common.config.web.exception; import com.auth0.jwt.exceptions.JWTVerificationException; import jakarta.ws.rs.core.Response; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/exception/ValidationExceptionMapper.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/exception/ValidationExceptionMapper.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/exception/ValidationExceptionMapper.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/exception/ValidationExceptionMapper.java index fd1bb230..c6d0b891 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/exception/ValidationExceptionMapper.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/exception/ValidationExceptionMapper.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest.exception; +package dev.flexmodel.common.config.web.exception; import jakarta.validation.ConstraintViolationException; import jakarta.validation.ValidationException; @@ -11,7 +11,7 @@ import java.util.Map; import java.util.stream.Collectors; -import static dev.flexmodel.interfaces.rest.exception.DefaultExceptionMapper.getDefaultResponse; +import static dev.flexmodel.common.config.web.exception.DefaultExceptionMapper.getDefaultResponse; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/filter/AuthFilter.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/filter/AuthFilter.java similarity index 73% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/filter/AuthFilter.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/filter/AuthFilter.java index 82b6fb83..f815b6b0 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/filter/AuthFilter.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/filter/AuthFilter.java @@ -1,8 +1,9 @@ -package dev.flexmodel.interfaces.rest.filter; +package dev.flexmodel.common.config.web.filter; + -import dev.flexmodel.application.ProjectApplicationService; import dev.flexmodel.codegen.entity.Project; -import dev.flexmodel.session.Session; +import dev.flexmodel.idp.IdentityProviderService; +import dev.flexmodel.project.ProjectService; import jakarta.annotation.security.PermitAll; import jakarta.inject.Inject; import jakarta.ws.rs.container.ContainerRequestContext; @@ -11,16 +12,15 @@ import jakarta.ws.rs.core.Context; import jakarta.ws.rs.ext.Provider; import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.application.IdentityProviderApplicationService; -import dev.flexmodel.application.SettingsApplicationService; +import dev.flexmodel.settings.SettingsService; import dev.flexmodel.codegen.entity.IdentityProvider; -import dev.flexmodel.domain.model.auth.AuthException; -import dev.flexmodel.domain.model.idp.provider.ValidateParam; -import dev.flexmodel.domain.model.idp.provider.ValidateResult; -import dev.flexmodel.domain.model.settings.Settings; -import dev.flexmodel.interfaces.rest.jwt.JwtUtil; -import dev.flexmodel.shared.SessionContextHolder; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.auth.AuthException; +import dev.flexmodel.idp.provider.ValidateParam; +import dev.flexmodel.idp.provider.ValidateResult; +import dev.flexmodel.settings.Settings; +import dev.flexmodel.common.config.web.jwt.JwtUtil; +import dev.flexmodel.common.SessionContextHolder; +import dev.flexmodel.common.utils.JsonUtils; import java.io.IOException; import java.util.Collection; @@ -38,11 +38,11 @@ public class AuthFilter implements ContainerRequestFilter { @Context ResourceInfo resourceInfo; @Inject - SettingsApplicationService settingsApplicationService; + SettingsService settingsService; @Inject - IdentityProviderApplicationService identityProviderApplicationService; + IdentityProviderService identityProviderService; @Inject - ProjectApplicationService projectApplicationService; + ProjectService projectService; @Override public void filter(ContainerRequestContext requestContext) throws IOException { @@ -72,14 +72,14 @@ public void filter(ContainerRequestContext requestContext) throws IOException { * @return 是否验证成功 */ private boolean varifyWithIdp(String projectId, ContainerRequestContext requestContext) { - Settings.Security security = settingsApplicationService.getSettings().getSecurity(); + Settings.Security security = settingsService.getSettings().getSecurity(); String systemIdentityProvider = security.getSystemIdentityProvider(); - IdentityProvider identityProvider = identityProviderApplicationService.find(systemIdentityProvider); + IdentityProvider identityProvider = identityProviderService.find(systemIdentityProvider); if (identityProvider == null) { log.warn("system idp not found!"); return false; } - dev.flexmodel.domain.model.idp.provider.Provider provider = JsonUtils.getInstance().convertValue(identityProvider.getProvider(), dev.flexmodel.domain.model.idp.provider.Provider.class); + dev.flexmodel.idp.provider.Provider provider = JsonUtils.getInstance().convertValue(identityProvider.getProvider(), dev.flexmodel.idp.provider.Provider.class); ValidateParam param = new ValidateParam(); Map headers = new HashMap<>(); requestContext.getHeaders().forEach((k, v) -> headers.put(k, v.getFirst())); @@ -98,7 +98,7 @@ private void fillSessionContext(ContainerRequestContext requestContext) { .replaceFirst("Bearer ", ""); String userId = JwtUtil.getAccount(accessToken); if (projectId != null) { - Project project = projectApplicationService.findProject(projectId); + Project project = projectService.findProject(projectId); if (project == null) { throw new AuthException("Project not found"); } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/filter/LogFilter.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/filter/LogFilter.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/filter/LogFilter.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/filter/LogFilter.java index 933e7a2d..e30258c1 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/filter/LogFilter.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/filter/LogFilter.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest.filter; +package dev.flexmodel.common.config.web.filter; import io.vertx.mutiny.core.eventbus.EventBus; import jakarta.enterprise.inject.spi.CDI; @@ -9,10 +9,10 @@ import jakarta.ws.rs.container.ContainerResponseFilter; import jakarta.ws.rs.ext.Provider; import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.application.SettingsApplicationService; +import dev.flexmodel.settings.SettingsService; import dev.flexmodel.codegen.entity.ApiRequestLog; -import dev.flexmodel.domain.model.settings.Settings; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.settings.Settings; +import dev.flexmodel.common.utils.JsonUtils; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -27,7 +27,7 @@ public class LogFilter implements ContainerRequestFilter, ContainerResponseFilter { @Inject - SettingsApplicationService settingsApplicationService; + SettingsService settingsService; @Override public void filter(ContainerRequestContext requestContext) throws IOException { @@ -55,7 +55,7 @@ public void filter(ContainerRequestContext requestContext, ContainerResponseCont execTime = -1L; } CompletableFuture.runAsync(() -> { - Settings settings = settingsApplicationService.getSettings(); + Settings settings = settingsService.getSettings(); boolean isLoggingEnabled = settings.getLog().isConsoleLoggingEnabled(); boolean isLogRequest = requestContext.getUriInfo().getPath().startsWith("/v1/logs"); if (isLoggingEnabled && !isLogRequest) { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/json/RegisterCustomModuleCustomizer.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/json/RegisterCustomModuleCustomizer.java similarity index 74% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/json/RegisterCustomModuleCustomizer.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/json/RegisterCustomModuleCustomizer.java index 73589e88..93df7abf 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/json/RegisterCustomModuleCustomizer.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/json/RegisterCustomModuleCustomizer.java @@ -1,9 +1,9 @@ -package dev.flexmodel.interfaces.rest.json; +package dev.flexmodel.common.config.web.json; import com.fasterxml.jackson.databind.ObjectMapper; import io.quarkus.jackson.ObjectMapperCustomizer; import jakarta.inject.Singleton; -import dev.flexmodel.interfaces.rest.json.jackson.FlexmodelServerModule; +import dev.flexmodel.common.config.web.json.jackson.FlexmodelServerModule; @Singleton public class RegisterCustomModuleCustomizer implements ObjectMapperCustomizer { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/json/jackson/FlexmodelServerModule.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/json/jackson/FlexmodelServerModule.java new file mode 100644 index 00000000..71821c79 --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/json/jackson/FlexmodelServerModule.java @@ -0,0 +1,22 @@ +package dev.flexmodel.common.config.web.json.jackson; + +import dev.flexmodel.connect.database.Database; +import dev.flexmodel.idp.provider.Provider; +import dev.flexmodel.scheduling.config.TriggerConfig; +import dev.flexmodel.common.config.web.json.jackson.mixin.DatasourceDatabaseMixIn; +import dev.flexmodel.common.config.web.json.jackson.mixin.IdentityProviderProviderMixIn; +import dev.flexmodel.common.config.web.json.jackson.mixin.ScheduledTriggerConfigMixIn; +import dev.flexmodel.supports.jackson.FlexmodelCoreModule; + +/** + * @author cjbi + */ +public class FlexmodelServerModule extends FlexmodelCoreModule { + + public FlexmodelServerModule() { + super(); + this.setMixInAnnotation(Database.class, DatasourceDatabaseMixIn.class); + this.setMixInAnnotation(Provider.class, IdentityProviderProviderMixIn.class); + this.setMixInAnnotation(TriggerConfig.class, ScheduledTriggerConfigMixIn.class); + } +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/json/jackson/mixin/DatasourceDatabaseMixIn.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/json/jackson/mixin/DatasourceDatabaseMixIn.java similarity index 85% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/json/jackson/mixin/DatasourceDatabaseMixIn.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/json/jackson/mixin/DatasourceDatabaseMixIn.java index d69f006b..04b8c0b6 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/json/jackson/mixin/DatasourceDatabaseMixIn.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/json/jackson/mixin/DatasourceDatabaseMixIn.java @@ -1,9 +1,8 @@ -package dev.flexmodel.interfaces.rest.json.jackson.mixin; +package dev.flexmodel.common.config.web.json.jackson.mixin; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import dev.flexmodel.domain.model.connect.database.*; -import dev.flexmodel.domain.model.connect.database.*; +import dev.flexmodel.connect.database.*; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/json/jackson/mixin/IdentityProviderProviderMixIn.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/json/jackson/mixin/IdentityProviderProviderMixIn.java similarity index 70% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/json/jackson/mixin/IdentityProviderProviderMixIn.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/json/jackson/mixin/IdentityProviderProviderMixIn.java index 8c2d9104..50675f7b 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/json/jackson/mixin/IdentityProviderProviderMixIn.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/json/jackson/mixin/IdentityProviderProviderMixIn.java @@ -1,9 +1,9 @@ -package dev.flexmodel.interfaces.rest.json.jackson.mixin; +package dev.flexmodel.common.config.web.json.jackson.mixin; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import dev.flexmodel.domain.model.idp.provider.ScriptProvider; -import dev.flexmodel.domain.model.idp.provider.OIDCProvider; +import dev.flexmodel.idp.provider.ScriptProvider; +import dev.flexmodel.idp.provider.OIDCProvider; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/json/jackson/mixin/ScheduledTriggerConfigMixIn.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/json/jackson/mixin/ScheduledTriggerConfigMixIn.java similarity index 72% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/json/jackson/mixin/ScheduledTriggerConfigMixIn.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/json/jackson/mixin/ScheduledTriggerConfigMixIn.java index e5d8140f..66996807 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/json/jackson/mixin/ScheduledTriggerConfigMixIn.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/json/jackson/mixin/ScheduledTriggerConfigMixIn.java @@ -1,10 +1,10 @@ -package dev.flexmodel.interfaces.rest.json.jackson.mixin; +package dev.flexmodel.common.config.web.json.jackson.mixin; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import dev.flexmodel.domain.model.schedule.config.CronScheduledTriggerConfig; -import dev.flexmodel.domain.model.schedule.config.EventTriggerConfig; -import dev.flexmodel.domain.model.schedule.config.IntervalScheduledTriggerConfig; +import dev.flexmodel.scheduling.config.CronScheduledTriggerConfig; +import dev.flexmodel.scheduling.config.EventTriggerConfig; +import dev.flexmodel.scheduling.config.IntervalScheduledTriggerConfig; /** * 定时触发器配置 MixIn 类 diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/jwt/JwtUtil.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/jwt/JwtUtil.java similarity index 97% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/jwt/JwtUtil.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/jwt/JwtUtil.java index e946b050..db5f75eb 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/jwt/JwtUtil.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/jwt/JwtUtil.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest.jwt; +package dev.flexmodel.common.config.web.jwt; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/openapi/GlobalOpenAPIFilter.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/openapi/GlobalOpenAPIFilter.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/openapi/GlobalOpenAPIFilter.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/openapi/GlobalOpenAPIFilter.java index 76418205..db71061a 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/openapi/GlobalOpenAPIFilter.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/openapi/GlobalOpenAPIFilter.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest.openapi; +package dev.flexmodel.common.config.web.openapi; /** * @author cjbi @@ -16,6 +16,7 @@ /** * 此Filter用于全局设置OpenAPI文档,如添加响应、安全要求和参数验证等 */ +@SuppressWarnings("deprecation") @OpenApiFilter(OpenApiFilter.RunStage.BUILD) @Priority(1) public class GlobalOpenAPIFilter implements OASFilter { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/request/ChatRequest.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/request/ChatRequest.java similarity index 60% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/request/ChatRequest.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/request/ChatRequest.java index af1a1dfc..d9aa0594 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/request/ChatRequest.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/request/ChatRequest.java @@ -1,6 +1,6 @@ -package dev.flexmodel.interfaces.rest.request; +package dev.flexmodel.common.config.web.request; -import dev.flexmodel.interfaces.rest.response.ChatMessage; +import dev.flexmodel.common.config.web.response.ChatMessage; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/ChatChoiceDelta.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/ChatChoiceDelta.java similarity index 67% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/ChatChoiceDelta.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/ChatChoiceDelta.java index 1a761112..cb682aad 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/ChatChoiceDelta.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/ChatChoiceDelta.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest.response; +package dev.flexmodel.common.config.web.response; public record ChatChoiceDelta( Integer index, diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/ChatDelta.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/ChatDelta.java similarity index 57% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/ChatDelta.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/ChatDelta.java index c82517dd..e8d97de3 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/ChatDelta.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/ChatDelta.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest.response; +package dev.flexmodel.common.config.web.response; public record ChatDelta( String role, diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/ChatMessage.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/ChatMessage.java similarity index 58% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/ChatMessage.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/ChatMessage.java index be70f3e8..1c290f64 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/ChatMessage.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/ChatMessage.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest.response; +package dev.flexmodel.common.config.web.response; public record ChatMessage( String role, diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/ChatResponseDelta.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/ChatResponseDelta.java similarity index 80% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/ChatResponseDelta.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/ChatResponseDelta.java index 732dd045..b638c99e 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/ChatResponseDelta.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/ChatResponseDelta.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest.response; +package dev.flexmodel.common.config.web.response; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/ChatUsage.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/ChatUsage.java similarity index 69% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/ChatUsage.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/ChatUsage.java index 2bc992ea..411188fd 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/ChatUsage.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/ChatUsage.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest.response; +package dev.flexmodel.common.config.web.response; public record ChatUsage( Integer promptTokens, diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/UserinfoResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/UserinfoResponse.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/UserinfoResponse.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/UserinfoResponse.java index 88c26503..675acafb 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/response/UserinfoResponse.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/response/UserinfoResponse.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest.response; +package dev.flexmodel.common.config.web.response; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/vertx/StaticResourceHandler.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/vertx/StaticResourceHandler.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/vertx/StaticResourceHandler.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/web/vertx/StaticResourceHandler.java index 1ac6dff2..082759d5 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/vertx/StaticResourceHandler.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/web/vertx/StaticResourceHandler.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest.vertx; +package dev.flexmodel.common.config.web.vertx; import io.quarkus.runtime.StartupEvent; import io.vertx.ext.web.Router; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/ws/JsonRpcWebSocket.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/ws/JsonRpcWebSocket.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/ws/JsonRpcWebSocket.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/ws/JsonRpcWebSocket.java index 32263b58..812c2f19 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/ws/JsonRpcWebSocket.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/ws/JsonRpcWebSocket.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.ws; +package dev.flexmodel.common.config.ws; import jakarta.enterprise.context.ApplicationScoped; import jakarta.websocket.OnClose; @@ -7,9 +7,9 @@ import jakarta.websocket.Session; import jakarta.websocket.server.ServerEndpoint; import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.interfaces.ws.dto.JsonRpcRequest; -import dev.flexmodel.interfaces.ws.dto.JsonRpcResponse; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.common.config.ws.dto.JsonRpcRequest; +import dev.flexmodel.common.config.ws.dto.JsonRpcResponse; +import dev.flexmodel.common.utils.JsonUtils; import java.io.IOException; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/ws/LoggingConfig.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/ws/LoggingConfig.java similarity index 87% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/ws/LoggingConfig.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/ws/LoggingConfig.java index 6a593327..d00c6afc 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/ws/LoggingConfig.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/ws/LoggingConfig.java @@ -1,9 +1,9 @@ -package dev.flexmodel.interfaces.ws; +package dev.flexmodel.common.config.ws; import io.quarkus.runtime.StartupEvent; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.event.Observes; -import dev.flexmodel.shared.Constants; +import dev.flexmodel.common.Constants; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/ws/WebSocketLogHandler.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/ws/WebSocketLogHandler.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/ws/WebSocketLogHandler.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/ws/WebSocketLogHandler.java index edda30fe..5d525b17 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/ws/WebSocketLogHandler.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/ws/WebSocketLogHandler.java @@ -1,9 +1,9 @@ -package dev.flexmodel.interfaces.ws; +package dev.flexmodel.common.config.ws; import jakarta.websocket.Session; import lombok.extern.slf4j.Slf4j; import org.jboss.logmanager.ExtLogRecord; -import dev.flexmodel.interfaces.ws.dto.JsonRpcResponse; +import dev.flexmodel.common.config.ws.dto.JsonRpcResponse; import java.io.IOException; import java.util.HashMap; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/ws/dto/JsonRpcRequest.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/ws/dto/JsonRpcRequest.java similarity index 78% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/ws/dto/JsonRpcRequest.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/ws/dto/JsonRpcRequest.java index 7c0cd92e..1af1cff2 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/ws/dto/JsonRpcRequest.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/ws/dto/JsonRpcRequest.java @@ -1,8 +1,8 @@ -package dev.flexmodel.interfaces.ws.dto; +package dev.flexmodel.common.config.ws.dto; import lombok.Getter; import lombok.Setter; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.common.utils.JsonUtils; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/ws/dto/JsonRpcResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/common/config/ws/dto/JsonRpcResponse.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/ws/dto/JsonRpcResponse.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/config/ws/dto/JsonRpcResponse.java index f41400a3..a5837fce 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/ws/dto/JsonRpcResponse.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/config/ws/dto/JsonRpcResponse.java @@ -1,8 +1,8 @@ -package dev.flexmodel.interfaces.ws.dto; +package dev.flexmodel.common.config.ws.dto; import lombok.Getter; import lombok.Setter; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.common.utils.JsonUtils; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/PageDTO.java b/flexmodel-server/src/main/java/dev/flexmodel/common/dto/PageDTO.java similarity index 83% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/PageDTO.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/dto/PageDTO.java index 3ccb179d..e0f5d95d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/PageDTO.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/dto/PageDTO.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.common.dto; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/shared/matchers/AntPathMatcher.java b/flexmodel-server/src/main/java/dev/flexmodel/common/matchers/AntPathMatcher.java similarity index 99% rename from flexmodel-server/src/main/java/dev/flexmodel/shared/matchers/AntPathMatcher.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/matchers/AntPathMatcher.java index 7dbc55ba..0efe7489 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/shared/matchers/AntPathMatcher.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/matchers/AntPathMatcher.java @@ -14,11 +14,11 @@ * limitations under the License. */ -package dev.flexmodel.shared.matchers; +package dev.flexmodel.common.matchers; import graphql.Assert; import io.vertx.codegen.annotations.Nullable; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.common.utils.StringUtils; import java.util.*; import java.util.concurrent.ConcurrentHashMap; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/shared/matchers/PathMatcher.java b/flexmodel-server/src/main/java/dev/flexmodel/common/matchers/PathMatcher.java similarity index 99% rename from flexmodel-server/src/main/java/dev/flexmodel/shared/matchers/PathMatcher.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/matchers/PathMatcher.java index 21677c8c..7c659a52 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/shared/matchers/PathMatcher.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/matchers/PathMatcher.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dev.flexmodel.shared.matchers; +package dev.flexmodel.common.matchers; import java.util.Comparator; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/shared/matchers/UriTemplate.java b/flexmodel-server/src/main/java/dev/flexmodel/common/matchers/UriTemplate.java similarity index 99% rename from flexmodel-server/src/main/java/dev/flexmodel/shared/matchers/UriTemplate.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/matchers/UriTemplate.java index 3e918cd6..98da15c0 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/shared/matchers/UriTemplate.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/matchers/UriTemplate.java @@ -1,4 +1,4 @@ -package dev.flexmodel.shared.matchers; +package dev.flexmodel.common.matchers; import java.util.*; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/shared/utils/CollectionUtils.java b/flexmodel-server/src/main/java/dev/flexmodel/common/utils/CollectionUtils.java similarity index 95% rename from flexmodel-server/src/main/java/dev/flexmodel/shared/utils/CollectionUtils.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/utils/CollectionUtils.java index 9142e3b4..aa046849 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/shared/utils/CollectionUtils.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/utils/CollectionUtils.java @@ -1,4 +1,4 @@ -package dev.flexmodel.shared.utils; +package dev.flexmodel.common.utils; import java.util.Collection; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/shared/utils/JsonUtils.java b/flexmodel-server/src/main/java/dev/flexmodel/common/utils/JsonUtils.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/shared/utils/JsonUtils.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/utils/JsonUtils.java index 7e1569e3..a85bfcb7 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/shared/utils/JsonUtils.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/utils/JsonUtils.java @@ -1,11 +1,9 @@ -package dev.flexmodel.shared.utils; +package dev.flexmodel.common.utils; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.Module; -import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import dev.flexmodel.supports.jackson.FlexmodelCoreModule; @@ -73,6 +71,15 @@ public List parseToList(String json, Class clz) { return convertValueList(parseToObject(json, List.class), clz); } + public T updateValue(T target, Object source) { + try { + return jsonMapper.updateValue(target, source); + } catch (JsonMappingException e) { + e.printStackTrace(); + } + return target; + } + public T convertValue(Object fromValue, Class clz) { try { return jsonMapper.convertValue(fromValue, clz); diff --git a/flexmodel-server/src/main/java/dev/flexmodel/shared/utils/PatternMatchUtils.java b/flexmodel-server/src/main/java/dev/flexmodel/common/utils/PatternMatchUtils.java similarity index 98% rename from flexmodel-server/src/main/java/dev/flexmodel/shared/utils/PatternMatchUtils.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/utils/PatternMatchUtils.java index b4cef523..e4be9ded 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/shared/utils/PatternMatchUtils.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/utils/PatternMatchUtils.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dev.flexmodel.shared.utils; +package dev.flexmodel.common.utils; import io.vertx.codegen.annotations.Nullable; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/shared/utils/StringUtils.java b/flexmodel-server/src/main/java/dev/flexmodel/common/utils/StringUtils.java similarity index 99% rename from flexmodel-server/src/main/java/dev/flexmodel/shared/utils/StringUtils.java rename to flexmodel-server/src/main/java/dev/flexmodel/common/utils/StringUtils.java index d793ba94..bba8e180 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/shared/utils/StringUtils.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/common/utils/StringUtils.java @@ -1,4 +1,4 @@ -package dev.flexmodel.shared.utils; +package dev.flexmodel.common.utils; import java.util.*; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/ConnectException.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/ConnectException.java similarity index 77% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/ConnectException.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/ConnectException.java index d1e09e7b..ad65622a 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/ConnectException.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/ConnectException.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect; +package dev.flexmodel.connect; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/NativeQueryResult.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/NativeQueryResult.java similarity index 84% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/NativeQueryResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/NativeQueryResult.java index a5c1f053..e6679f75 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/NativeQueryResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/NativeQueryResult.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect; +package dev.flexmodel.connect; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/SessionDatasource.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/SessionDatasource.java similarity index 52% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/SessionDatasource.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/SessionDatasource.java index 334e2468..386bb16c 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/SessionDatasource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/SessionDatasource.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect; +package dev.flexmodel.connect; import dev.flexmodel.codegen.entity.Project; @@ -18,4 +18,18 @@ public interface SessionDatasource { NativeQueryResult executeNativeQuery(Project project, String statement, Map parameters); + /** + * 注册指定 Schema 的 SchemaProvider 到 SessionFactory。 + * + * @param schemaName Schema 名称 + */ + void registerSchema(String schemaName); + + /** + * 取消注册指定 Schema 的 SchemaProvider。 + * + * @param schemaName Schema 名称 + */ + void unregisterSchema(String schemaName); + } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/ValidateResult.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/ValidateResult.java similarity index 70% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/ValidateResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/ValidateResult.java index 48305ff7..32497084 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/ValidateResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/ValidateResult.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect; +package dev.flexmodel.connect; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/DB2.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/DB2.java similarity index 78% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/DB2.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/database/DB2.java index 9109c311..d8bd9864 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/DB2.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/DB2.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect.database; +package dev.flexmodel.connect.database; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/DM8.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/DM8.java similarity index 77% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/DM8.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/database/DM8.java index 43e68556..898d9305 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/DM8.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/DM8.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect.database; +package dev.flexmodel.connect.database; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/Database.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/Database.java similarity index 84% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/Database.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/database/Database.java index a1e9bb6e..e668b2d5 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/Database.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/Database.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect.database; +package dev.flexmodel.connect.database; import jakarta.validation.constraints.NotBlank; import lombok.Getter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/GBase.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/GBase.java similarity index 78% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/GBase.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/database/GBase.java index c73fd179..617edc9f 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/GBase.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/GBase.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect.database; +package dev.flexmodel.connect.database; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/MariaDB.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/MariaDB.java similarity index 78% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/MariaDB.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/database/MariaDB.java index 893efe8f..fb074d87 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/MariaDB.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/MariaDB.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect.database; +package dev.flexmodel.connect.database; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/MongoDB.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/MongoDB.java similarity index 71% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/MongoDB.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/database/MongoDB.java index ea86fe63..78fb1011 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/MongoDB.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/MongoDB.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect.database; +package dev.flexmodel.connect.database; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/MySQL.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/MySQL.java similarity index 78% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/MySQL.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/database/MySQL.java index 1582ee1c..870892a9 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/MySQL.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/MySQL.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect.database; +package dev.flexmodel.connect.database; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/Oracle.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/Oracle.java similarity index 78% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/Oracle.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/database/Oracle.java index de0bd114..7a7bde0b 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/Oracle.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/Oracle.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect.database; +package dev.flexmodel.connect.database; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/PostgreSQL.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/PostgreSQL.java similarity index 79% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/PostgreSQL.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/database/PostgreSQL.java index 7d6e6178..0d06df51 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/PostgreSQL.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/PostgreSQL.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect.database; +package dev.flexmodel.connect.database; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/SQLServer.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/SQLServer.java similarity index 79% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/SQLServer.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/database/SQLServer.java index 1486e075..eb24df98 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/SQLServer.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/SQLServer.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect.database; +package dev.flexmodel.connect.database; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/SQLite.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/SQLite.java similarity index 78% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/SQLite.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/database/SQLite.java index 25a80da2..bb664450 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/SQLite.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/SQLite.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect.database; +package dev.flexmodel.connect.database; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/TiDB.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/TiDB.java similarity index 78% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/TiDB.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/database/TiDB.java index 76a15a7e..bfa979b8 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/TiDB.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/TiDB.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect.database; +package dev.flexmodel.connect.database; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/UnknownDatabase.java b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/UnknownDatabase.java similarity index 72% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/UnknownDatabase.java rename to flexmodel-server/src/main/java/dev/flexmodel/connect/database/UnknownDatabase.java index 4c74318a..f33fc483 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/connect/database/UnknownDatabase.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/connect/database/UnknownDatabase.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.connect.database; +package dev.flexmodel.connect.database; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/DataFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/data/DataFmRepository.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/DataFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/data/DataFmRepository.java index 584da7fa..ad8417f1 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/DataFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/data/DataFmRepository.java @@ -1,10 +1,9 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.data; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import lombok.extern.slf4j.Slf4j; import dev.flexmodel.codegen.StringUtils; -import dev.flexmodel.domain.model.data.DataRepository; import dev.flexmodel.model.EntityDefinition; import dev.flexmodel.model.field.TypedField; import dev.flexmodel.query.DSLQueryBuilder; @@ -12,7 +11,7 @@ import dev.flexmodel.query.Query; import dev.flexmodel.session.Session; import dev.flexmodel.session.SessionFactory; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.common.utils.JsonUtils; import java.util.List; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/data/DataRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/data/DataRepository.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/data/DataRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/data/DataRepository.java index de63c2b5..4327772d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/data/DataRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/data/DataRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.data; +package dev.flexmodel.data; import java.util.List; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/data/DataService.java b/flexmodel-server/src/main/java/dev/flexmodel/data/DataService.java new file mode 100644 index 00000000..498e13fb --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/data/DataService.java @@ -0,0 +1,103 @@ +package dev.flexmodel.data; + +import dev.flexmodel.codegen.entity.Project; +import dev.flexmodel.common.dto.PageDTO; +import dev.flexmodel.project.ProjectService; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author cjbi + */ +@ApplicationScoped +public class DataService { + + @Inject + DataRepository dataRepository; + + @Inject + ProjectService projectService; + + public List> findRecords(String projectId, + String datasourceName, + String modelName, + Integer page, + Integer size, + String filter, + String sort, + boolean nestedQueryEnabled) { + return dataRepository.findRecords(projectId, datasourceName, modelName, page, size, filter, sort, nestedQueryEnabled); + } + + public long countRecords(String projectId, String datasourceName, String modelName, String filter) { + return dataRepository.countRecords(projectId, datasourceName, modelName, filter); + } + + public Map findOneRecord(String projectId, String datasourceName, String modelName, Object id, boolean nestedQuery) { + return dataRepository.findOneRecord(projectId, datasourceName, modelName, id, nestedQuery); + } + + public Map createRecord(String projectId, String datasourceName, String modelName, Map data) { + return dataRepository.createRecord(projectId, datasourceName, modelName, data); + } + + public Map updateRecord(String projectId, String datasourceName, String modelName, Object id, Map data) { + return dataRepository.updateRecord(projectId, datasourceName, modelName, id, data); + } + + public void deleteRecord(String projectId, String datasourceName, String modelName, Object id) { + dataRepository.deleteRecord(projectId, datasourceName, modelName, id); + } + + public PageDTO> findPagingRecords(String projectId, + String modelName, + int page, + int size, + String filter, + String sort, + boolean nestedQuery) { + Project project = projectService.findProject(projectId); + String datasourceName = project.getDatabaseName(); + List> list = dataRepository.findRecords(projectId, datasourceName, modelName, page, size, filter, sort, nestedQuery); + long total = dataRepository.countRecords(projectId, datasourceName, modelName, filter); + return new PageDTO<>(list, total); + } + + public Map findOneRecord(String projectId, String modelName, String id, boolean nestedQuery) { + Project project = projectService.findProject(projectId); + String datasourceName = project.getDatabaseName(); + return dataRepository.findOneRecord(projectId, datasourceName, modelName, id, nestedQuery); + } + + public Map createRecord(String projectId, String modelName, Map data) { + Project project = projectService.findProject(projectId); + String datasourceName = project.getDatabaseName(); + return dataRepository.createRecord(projectId, datasourceName, modelName, data); + } + + public Map updateRecord(String projectId, String modelName, Object id, Map data) { + Project project = projectService.findProject(projectId); + String datasourceName = project.getDatabaseName(); + return dataRepository.updateRecord(projectId, datasourceName, modelName, id, data); + } + + public void deleteRecord(String projectId, String modelName, Object id) { + Project project = projectService.findProject(projectId); + String datasourceName = project.getDatabaseName(); + dataRepository.deleteRecord(projectId, datasourceName, modelName, id); + } + + public Map updateRecordIgnoreNull(String projectId, String modelName, String id, Map record) { + Project project = projectService.findProject(projectId); + String datasourceName = project.getDatabaseName(); + Map oldData = dataRepository.findOneRecord(projectId, datasourceName, modelName, id, false); + Map mergeData = new HashMap<>(oldData); + mergeData.putAll(record); + return dataRepository.updateRecord(projectId, datasourceName, modelName, id, mergeData); + } + +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/RecordResource.java b/flexmodel-server/src/main/java/dev/flexmodel/data/RecordResource.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/RecordResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/data/RecordResource.java index 36f1214e..1408a7c6 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/RecordResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/data/RecordResource.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.data; import jakarta.inject.Inject; import jakarta.ws.rs.*; @@ -14,8 +14,7 @@ import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.DataApplicationService; -import dev.flexmodel.application.dto.PageDTO; +import dev.flexmodel.common.dto.PageDTO; import java.util.Map; /** @@ -28,7 +27,7 @@ public class RecordResource { @Inject - DataApplicationService dataApplicationService; + DataService dataService; @APIResponse( name = "200", @@ -67,7 +66,7 @@ public PageDTO> findPagingRecords( @QueryParam("nestedQuery") @DefaultValue("false") boolean nestedQuery, @QueryParam("sort") String sort ) { - return dataApplicationService.findPagingRecords(projectId, modelName, page, size, filter, sort, nestedQuery); + return dataService.findPagingRecords(projectId, modelName, page, size, filter, sort, nestedQuery); } @Parameter(name = "id", description = "ID", examples = {@ExampleObject(value = "1")}, in = ParameterIn.PATH) @@ -80,7 +79,7 @@ public Map findOneRecord( @PathParam("id") String id, @QueryParam("nestedQuery") @DefaultValue("false") boolean nestedQuery ) { - return dataApplicationService.findOneRecord(projectId, modelName, id, nestedQuery); + return dataService.findOneRecord(projectId, modelName, id, nestedQuery); } @@ -125,7 +124,7 @@ public Map createRecord( @PathParam("modelName") String modelName, Map record ) { - return dataApplicationService.createRecord(projectId, modelName, record); + return dataService.createRecord(projectId, modelName, record); } @RequestBody( @@ -173,7 +172,7 @@ public Map updateRecord( @PathParam("id") String id, Map record ) { - return dataApplicationService.updateRecord(projectId, modelName, id, record); + return dataService.updateRecord(projectId, modelName, id, record); } @RequestBody( @@ -220,7 +219,7 @@ public Map updateRecordIgnoreNull( @PathParam("id") String id, Map record ) { - return dataApplicationService.updateRecordIgnoreNull(projectId, modelName, id, record); + return dataService.updateRecordIgnoreNull(projectId, modelName, id, record); } @Parameter(name = "id", description = "ID", examples = {@ExampleObject(value = "1")}, in = ParameterIn.PATH) @@ -232,7 +231,7 @@ public void deleteRecord( @PathParam("modelName") String modelName, @PathParam("id") String id ) { - dataApplicationService.deleteRecord(projectId, modelName, id); + dataService.deleteRecord(projectId, modelName, id); } } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionChangedEvent.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionChangedEvent.java deleted file mode 100644 index c39367d9..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionChangedEvent.java +++ /dev/null @@ -1,10 +0,0 @@ -package dev.flexmodel.domain.model.api; - -import dev.flexmodel.codegen.entity.ApiDefinition; - -/** - * @author cjbi - */ -public record ApiDefinitionChangedEvent(ApiDefinition apiDefinition) { - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionException.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionException.java deleted file mode 100644 index ec063633..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionException.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.flexmodel.domain.model.api; - -/** - * @author cjbi - */ -public class ApiDefinitionException extends RuntimeException { - - public ApiDefinitionException(String message) { - super(message); - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionHistoryRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionHistoryRepository.java deleted file mode 100644 index 3b7f17c3..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionHistoryRepository.java +++ /dev/null @@ -1,30 +0,0 @@ -package dev.flexmodel.domain.model.api; - -import dev.flexmodel.codegen.entity.ApiDefinitionHistory; - -import java.util.List; - -/** - * @author cjbi - */ -public interface ApiDefinitionHistoryRepository { - /** - * 根据apiDefinitionId查询历史记录 - * - * @param projectId projectId - * @param apiDefinitionId apiDefinitionId - * @return apiDefinitionHistory - */ - List findByApiDefinitionId(String projectId, String apiDefinitionId); - - /** - * 保存历史记录 - * - * @param projectId projectId - * @param apiDefinitionHistory apiDefinitionHistory - * @return apiDefinitionHistory - */ - ApiDefinitionHistory save(String projectId, ApiDefinitionHistory apiDefinitionHistory); - - ApiDefinitionHistory findById(String projectId, String historyId); -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionMeta.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionMeta.java deleted file mode 100644 index 83a47850..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionMeta.java +++ /dev/null @@ -1,53 +0,0 @@ -package dev.flexmodel.domain.model.api; - -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; - -import java.util.Map; - -/** - * @author cjbi - */ -@Getter -@Setter -@ToString -public class ApiDefinitionMeta { - private boolean auth; - private String identityProvider; - private boolean rateLimitingEnabled; - private int maxRequestCount; - private int intervalInSeconds; - private Execution execution; - private Document document; - - @Getter - @Setter - public static class Execution { - private String preScript; - private String postScript; - private String executionType = "graphql"; - private String executionScript; - private String query; - private Map variables; - private String operationName; - private Map headers; - } - - @Getter - @Setter - public static class Document { - private DocumentIO input; - private DocumentIO output; - } - - @Getter - @Setter - public static class DocumentIO { - /** - * json schema 格式的数据 - */ - private Map schema; - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionRepository.java deleted file mode 100644 index 2b090ffb..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionRepository.java +++ /dev/null @@ -1,25 +0,0 @@ -package dev.flexmodel.domain.model.api; - -import dev.flexmodel.codegen.entity.ApiDefinition; - -import java.util.List; - -/** - * @author cjbi - */ -public interface ApiDefinitionRepository { - - void deleteByParentId(String projectId, String parentId); - - ApiDefinition findById(String projectId, String id); - - List findAll(String projectId); - - List findByProjectId(String projectId); - - ApiDefinition save(ApiDefinition record); - - void delete(String projectId, String id); - - Integer count(String projectId); -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionService.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionService.java deleted file mode 100644 index c741977b..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiDefinitionService.java +++ /dev/null @@ -1,88 +0,0 @@ -package dev.flexmodel.domain.model.api; - -import io.quarkus.cache.CacheInvalidateAll; -import io.quarkus.cache.CacheResult; -import io.vertx.mutiny.core.eventbus.EventBus; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import dev.flexmodel.codegen.entity.ApiDefinition; -import dev.flexmodel.codegen.entity.ApiDefinitionHistory; - -import java.time.LocalDateTime; -import java.util.List; - -/** - * @author cjbi - */ -@ApplicationScoped -public class ApiDefinitionService { - - @Inject - ApiDefinitionRepository apiDefinitionRepository; - - @Inject - ApiDefinitionHistoryRepository apiDefinitionHistoryRepository; - - @Inject - EventBus eventBus; - - @CacheResult(cacheName = "apiDefinitionList") - public List findList(String projectId) { - return apiDefinitionRepository.findByProjectId(projectId); - } - - public Integer count(String projectId) { - return apiDefinitionRepository.count(projectId); - } - - @CacheResult(cacheName = "apiDefinitionList") - public List findAll(String projectId) { - return apiDefinitionRepository.findAll(projectId); - } - - public List findApiDefinitionHistories(String projectId, String apiDefinitionId) { - return apiDefinitionHistoryRepository.findByApiDefinitionId(projectId, apiDefinitionId); - } - - public ApiDefinitionHistory saveApiDefinitionHistory(ApiDefinitionHistory apiDefinitionHistory) { - return apiDefinitionHistoryRepository.save(apiDefinitionHistory.getProjectId(), apiDefinitionHistory); - } - - @CacheInvalidateAll(cacheName = "apiDefinitionList") - public ApiDefinition create(ApiDefinition apiDefinition) { - if (apiDefinition.getName() == null || apiDefinition.getName().isEmpty()) { - throw new ApiDefinitionException("API name must not be null"); - } - ApiDefinition definition = apiDefinitionRepository.save(apiDefinition); - eventBus.publish("api.changed", new ApiDefinitionChangedEvent(definition)); - return definition; - } - - @CacheInvalidateAll(cacheName = "apiDefinitionList") - public ApiDefinition update(ApiDefinition apiDefinition) { - ApiDefinition older = apiDefinitionRepository.findById(apiDefinition.getProjectId(), apiDefinition.getId()); - if (older == null) { - return apiDefinition; - } - apiDefinition.setCreatedAt(older.getCreatedAt()); - apiDefinition.setUpdatedAt(LocalDateTime.now()); - ApiRateLimiterHolder.removeApiRateLimiter(apiDefinition.getMethod() + ":" + apiDefinition.getPath()); - ApiDefinition definition = apiDefinitionRepository.save(apiDefinition); - eventBus.publish("api.changed", new ApiDefinitionChangedEvent(definition)); - return definition; - } - - @CacheInvalidateAll(cacheName = "apiDefinitionList") - public void delete(String projectId, String id) { - apiDefinitionRepository.delete(projectId, id); - apiDefinitionRepository.deleteByParentId(projectId, id); - } - - public ApiDefinition findApiDefinition(String projectId, String id) { - return apiDefinitionRepository.findById(projectId, id); - } - - public ApiDefinitionHistory findApiDefinitionHistory(String projectId, String historyId) { - return apiDefinitionHistoryRepository.findById(projectId, historyId); - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiRequestLogService.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiRequestLogService.java deleted file mode 100644 index 46b17e3c..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/ApiRequestLogService.java +++ /dev/null @@ -1,52 +0,0 @@ -package dev.flexmodel.domain.model.api; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.context.control.ActivateRequestContext; -import jakarta.inject.Inject; -import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.codegen.entity.ApiRequestLog; -import dev.flexmodel.query.Predicate; - -import java.time.LocalDateTime; -import java.util.List; - -import static dev.flexmodel.query.Expressions.field; - -/** - * @author cjbi - */ -@Slf4j -@ApplicationScoped -@ActivateRequestContext -public class ApiRequestLogService { - - @Inject - ApiRequestLogRepository apiLogRepository; - - public ApiRequestLog create(ApiRequestLog apiRequestLog) { - apiRequestLog.setCreatedAt(LocalDateTime.now()); - return apiLogRepository.save(apiRequestLog); - } - - public List find(String projectId, Predicate filter, Integer current, Integer pageSize) { - return apiLogRepository.find(projectId, filter, current, pageSize); - } - - public long count(String projectId, Predicate filter) { - return apiLogRepository.count(projectId, filter); - } - - public List stat(String projectId, Predicate filter, String fmt) { - return apiLogRepository.stat(projectId, filter, fmt); - } - - public List ranking(String projectId, Predicate filter) { - return apiLogRepository.ranking(projectId, filter); - } - - public void purgeOldLogs(int maxDays) { - log.info("Purging old logs older than {} days", maxDays); - LocalDateTime purgeDate = LocalDateTime.now().minusDays(maxDays); - apiLogRepository.delete(field(ApiRequestLog::getCreatedAt).lte(purgeDate)); - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/execution/AbstractExecutionStrategy.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/execution/AbstractExecutionStrategy.java deleted file mode 100644 index 6719ebfe..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/execution/AbstractExecutionStrategy.java +++ /dev/null @@ -1,70 +0,0 @@ -package dev.flexmodel.domain.model.api.execution; - -import dev.flexmodel.session.SessionFactory; -import jakarta.inject.Inject; -import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.codegen.entity.ApiDefinition; -import dev.flexmodel.domain.model.api.ApiDefinitionMeta; -import dev.flexmodel.domain.model.flow.shared.util.RequestScriptContext; -import dev.flexmodel.domain.model.flow.shared.util.JavaScriptUtil; - -import java.util.HashMap; -import java.util.Map; - -/** - * @author cjbi - */ -@Slf4j -public abstract class AbstractExecutionStrategy implements ExecutionStrategy { - - - protected abstract Map doExecute(ApiDefinition apiDefinition, ApiDefinitionMeta.Execution execution, - Map pathParameters, RequestScriptContext httpScriptContext); - - @Override - public void execute(ApiDefinition apiDefinition, ApiDefinitionMeta.Execution execution, Map pathParameters, RequestScriptContext httpScriptContext) { - // 前置脚本 - preExecute(execution, httpScriptContext); - Map resMap = doExecute(apiDefinition, execution, pathParameters, httpScriptContext); - // 设置返回值 - httpScriptContext.setResponse(new RequestScriptContext.Response(200, "OK", new HashMap<>(), resMap)); - // 后置脚本 - postExecute(execution, httpScriptContext); - } - - protected void preExecute(ApiDefinitionMeta.Execution execution, RequestScriptContext httpScriptContext) { - - // 执行前置脚本 - String preScript = execution.getPreScript(); - if (preScript != null) { - try { - Map contextMap = httpScriptContext.buildContextMap(); - JavaScriptUtil.execute(preScript, Map.of(RequestScriptContext.SCRIPT_CONTEXT_KEY, contextMap)); - httpScriptContext.syncFromMap(contextMap); - } catch (Exception e) { - log.error("Execute pre script error: {}", e.getMessage()); - throw new IllegalArgumentException("Execute pre script error: " + e.getMessage()); - } finally { - JavaScriptUtil.cleanup(); - } - } - } - - protected void postExecute(ApiDefinitionMeta.Execution execution, RequestScriptContext httpScriptContext) { - // 执行后置脚本 - String postScript = execution.getPostScript(); - if (postScript != null) { - try { - Map contextMap = httpScriptContext.buildContextMap(); - JavaScriptUtil.execute(postScript, Map.of(RequestScriptContext.SCRIPT_CONTEXT_KEY, contextMap)); - httpScriptContext.syncFromMap(contextMap); - } catch (Exception e) { - log.error("Execute post script error: {}", e.getMessage()); - throw new IllegalArgumentException("Execute post script error: " + e.getMessage()); - } finally { - JavaScriptUtil.cleanup(); - } - } - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/execution/ExecutionStrategy.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/execution/ExecutionStrategy.java deleted file mode 100644 index 7b43e467..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/execution/ExecutionStrategy.java +++ /dev/null @@ -1,25 +0,0 @@ -package dev.flexmodel.domain.model.api.execution; - -import dev.flexmodel.codegen.entity.ApiDefinition; -import dev.flexmodel.domain.model.api.ApiDefinitionMeta; -import dev.flexmodel.domain.model.flow.shared.util.RequestScriptContext; - -import java.util.Map; - -public interface ExecutionStrategy { - /** - * Execute the specific execution type - * - * @param execution The execution configuration - * @param httpScriptContext The HTTP script context containing all necessary data - */ - void execute(ApiDefinition apiDefinition, ApiDefinitionMeta.Execution execution, - Map pathParameters, RequestScriptContext httpScriptContext); - - /** - * Get the execution type - * @return The execution type - */ - String getExecutionType(); - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/execution/ExecutionStrategyFactory.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/execution/ExecutionStrategyFactory.java deleted file mode 100644 index 5ba7cecd..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/execution/ExecutionStrategyFactory.java +++ /dev/null @@ -1,24 +0,0 @@ -package dev.flexmodel.domain.model.api.execution; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Instance; -import jakarta.inject.Inject; - -@ApplicationScoped -public class ExecutionStrategyFactory { - - @Inject - Instance strategies; - - public ExecutionStrategy getStrategy(String executionType) { - - // Find the matching strategy instance - for (ExecutionStrategy strategy : strategies) { - if (executionType.equals(strategy.getExecutionType())) { - return strategy; - } - } - - throw new IllegalStateException("Execution strategy not available: " + executionType); - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/execution/GraphQLExecutionStrategy.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/execution/GraphQLExecutionStrategy.java deleted file mode 100644 index 83518f6c..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/execution/GraphQLExecutionStrategy.java +++ /dev/null @@ -1,58 +0,0 @@ -package dev.flexmodel.domain.model.api.execution; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import dev.flexmodel.domain.model.api.GraphQLManger; -import dev.flexmodel.codegen.entity.ApiDefinition; -import dev.flexmodel.domain.model.api.ApiDefinitionMeta; -import dev.flexmodel.domain.model.flow.shared.util.RequestScriptContext; - -import java.util.HashMap; -import java.util.Map; - -@ApplicationScoped -public class GraphQLExecutionStrategy extends AbstractExecutionStrategy { - - @Inject - GraphQLManger graphQLManger; - - @Override - protected Map doExecute(ApiDefinition apiDefinition, ApiDefinitionMeta.Execution execution, - Map pathParameters, RequestScriptContext httpScriptContext) { - String projectId = apiDefinition.getProjectId(); - String method = httpScriptContext.getRequest().method(); - String operationName = execution.getOperationName(); - String query = execution.getQuery(); - Map defaultVariables = execution.getVariables(); - - Map executionData = new HashMap<>(); - if (defaultVariables != null) { - executionData.putAll(defaultVariables); - } - if ("GET".equals(method)) { - if (httpScriptContext.getRequest().query() != null && !httpScriptContext.getRequest().query().isEmpty()) { - executionData.putAll(httpScriptContext.getRequest().query()); - } - } else { - // Request body - if (httpScriptContext.getRequest().body() != null && !httpScriptContext.getRequest().body().isEmpty()) { - executionData.putAll(httpScriptContext.getRequest().body()); - } - } - // Path parameters - if (pathParameters != null) { - executionData.putAll(pathParameters); - } - - graphql.ExecutionResult result = graphQLManger.execute(projectId, operationName, query, executionData); - - Map resMap = new HashMap<>(); - resMap.put("data", result.getData()); - return resMap; - } - - @Override - public String getExecutionType() { - return "graphql"; - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/execution/ScriptExecutionStrategy.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/execution/ScriptExecutionStrategy.java deleted file mode 100644 index cecd805d..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/api/execution/ScriptExecutionStrategy.java +++ /dev/null @@ -1,40 +0,0 @@ -package dev.flexmodel.domain.model.api.execution; - -import jakarta.enterprise.context.ApplicationScoped; -import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.codegen.entity.ApiDefinition; -import dev.flexmodel.domain.model.api.ApiDefinitionMeta; -import dev.flexmodel.domain.model.flow.shared.util.RequestScriptContext; -import dev.flexmodel.domain.model.flow.shared.util.JavaScriptUtil; - -import java.util.HashMap; -import java.util.Map; - -/** - * @author cjbi - */ -@Slf4j -@ApplicationScoped -public class ScriptExecutionStrategy extends AbstractExecutionStrategy { - - @Override - protected Map doExecute(ApiDefinition apiDefinition, ApiDefinitionMeta.Execution execution, Map pathParameters, RequestScriptContext httpScriptContext) { - httpScriptContext.setResponse(new RequestScriptContext.Response(200, "OK", new HashMap<>(), new HashMap<>())); - try { - Map contextMap = httpScriptContext.buildContextMap(); - JavaScriptUtil.execute(execution.getExecutionScript(), Map.of(RequestScriptContext.SCRIPT_CONTEXT_KEY, contextMap)); - httpScriptContext.syncFromMap(contextMap); - return httpScriptContext.getResponse().body(); - } catch (Exception e) { - log.error("Execute script error: {}", e.getMessage(), e); - throw new IllegalArgumentException("Execute script error: " + e.getMessage()); - } finally { - JavaScriptUtil.cleanup(); - } - } - - @Override - public String getExecutionType() { - return "script"; - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/ProjectService.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/ProjectService.java deleted file mode 100644 index 08f71630..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/ProjectService.java +++ /dev/null @@ -1,59 +0,0 @@ -package dev.flexmodel.domain.model.auth; - -import dev.flexmodel.shared.SessionContextHolder; -import dev.flexmodel.shared.utils.StringUtils; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import dev.flexmodel.codegen.entity.Project; - -import java.util.List; - -/** - * @author cjbi - */ -@ApplicationScoped -public class ProjectService { - - @Inject - ProjectRepository tenantRepository; - - public List findProjects() { - return tenantRepository.findProjects(); - } - - public Project findProject(String projectId) { - return tenantRepository.findProject(projectId); - } - - public Project createProject(Project project) { - if (!StringUtils.isBlank(project.getId()) && findProject(project.getId()) != null) { - throw new IllegalArgumentException("项目ID已经存在"); - } - if (StringUtils.isBlank(project.getId())) { - project.setId(null); - } - project.setOwnerId(SessionContextHolder.getUserId()); - return tenantRepository.save(project); - } - - public Project updateProject(Project project) { - if ("default".equals(project.getId())) { - throw new IllegalArgumentException("默认项目不能修改"); - } - Project existingProject = findProject(project.getId()); - if (existingProject == null) { - throw new IllegalArgumentException("项目不存在"); - } - project.setCreatedAt(existingProject.getCreatedAt()); - project.setCreatedBy(existingProject.getCreatedBy()); - project.setOwnerId(existingProject.getOwnerId()); - return tenantRepository.save(project); - } - - public void deleteProject(String projectId) { - if ("default".equals(projectId)) { - throw new IllegalArgumentException("默认项目不能删除"); - } - tenantRepository.delete(projectId); - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/codegen/ZipService.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/codegen/ZipService.java deleted file mode 100644 index 9010eb88..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/codegen/ZipService.java +++ /dev/null @@ -1,45 +0,0 @@ -package dev.flexmodel.domain.model.codegen; - -import jakarta.enterprise.context.ApplicationScoped; -import lombok.extern.slf4j.Slf4j; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -/** - * @author cjbi - */ -@Slf4j -@ApplicationScoped -public class ZipService { - - /** - * 将目录下所有文件打包为 ZIP,写入 outputStream。 - */ - public void zipDirectory(String name, Path sourceDir, OutputStream outputStream) throws IOException { - try (ZipOutputStream zipOut = new ZipOutputStream(outputStream)) { - Files.walk(sourceDir) - .forEach(path -> { - Path rel = sourceDir.relativize(path); - String entryName = (name + "/" + rel.toString().replace(File.separatorChar, '/') - + (Files.isDirectory(path) ? "/" : "")).replace("//", "/"); - try { - zipOut.putNextEntry(new ZipEntry(entryName)); - if (Files.isRegularFile(path)) { - Files.copy(path, zipOut); - } - zipOut.closeEntry(); - } catch (IOException e) { - log.error("An error occurred in packaging file : {}", path, e); - } - }); - zipOut.finish(); - } - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/data/DataService.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/data/DataService.java deleted file mode 100644 index 2334bc26..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/data/DataService.java +++ /dev/null @@ -1,49 +0,0 @@ -package dev.flexmodel.domain.model.data; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import java.util.List; -import java.util.Map; - -/** - * @author cjbi - */ -@ApplicationScoped -public class DataService { - - @Inject - DataRepository dataRepository; - - public List> findRecords(String projectId, - String datasourceName, - String modelName, - Integer page, - Integer size, - String filter, - String sort, - boolean nestedQueryEnabled) { - return dataRepository.findRecords(projectId, datasourceName, modelName, page, size, filter, sort, nestedQueryEnabled); - } - - public long countRecords(String projectId, String datasourceName, String modelName, String filter) { - return dataRepository.countRecords(projectId, datasourceName, modelName, filter); - } - - public Map findOneRecord(String projectId, String datasourceName, String modelName, Object id, boolean nestedQuery) { - return dataRepository.findOneRecord(projectId, datasourceName, modelName, id, nestedQuery); - } - - public Map createRecord(String projectId, String datasourceName, String modelName, Map data) { - return dataRepository.createRecord(projectId, datasourceName, modelName, data); - } - - public Map updateRecord(String projectId, String datasourceName, String modelName, Object id, Map data) { - return dataRepository.updateRecord(projectId, datasourceName, modelName, id, data); - } - - public void deleteRecord(String projectId, String datasourceName, String modelName, Object id) { - dataRepository.deleteRecord(projectId, datasourceName, modelName, id); - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/ActivityNode.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/ActivityNode.java deleted file mode 100644 index ffbb53e4..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/ActivityNode.java +++ /dev/null @@ -1,4 +0,0 @@ -package dev.flexmodel.domain.model.flow.dto.model; - -public class ActivityNode extends FlowNode { -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/EndEvent.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/EndEvent.java deleted file mode 100644 index d220017e..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/EndEvent.java +++ /dev/null @@ -1,4 +0,0 @@ -package dev.flexmodel.domain.model.flow.dto.model; - -public class EndEvent extends EventNode { -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/EventNode.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/EventNode.java deleted file mode 100644 index 64e16e51..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/EventNode.java +++ /dev/null @@ -1,5 +0,0 @@ -package dev.flexmodel.domain.model.flow.dto.model; - -public class EventNode extends FlowNode { - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/FlowNode.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/FlowNode.java deleted file mode 100644 index 27f1b06c..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/FlowNode.java +++ /dev/null @@ -1,4 +0,0 @@ -package dev.flexmodel.domain.model.flow.dto.model; - -public class FlowNode extends FlowElement { -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/GatewayNode.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/GatewayNode.java deleted file mode 100644 index 15158781..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/GatewayNode.java +++ /dev/null @@ -1,4 +0,0 @@ -package dev.flexmodel.domain.model.flow.dto.model; - -public class GatewayNode extends FlowNode { -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/StartEvent.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/StartEvent.java deleted file mode 100644 index e5b2ee25..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/StartEvent.java +++ /dev/null @@ -1,4 +0,0 @@ -package dev.flexmodel.domain.model.flow.dto.model; - -public class StartEvent extends EventNode { -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/SubProcess.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/SubProcess.java deleted file mode 100644 index f60ecc7b..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/SubProcess.java +++ /dev/null @@ -1,4 +0,0 @@ -package dev.flexmodel.domain.model.flow.dto.model; - -public class SubProcess extends ActivityNode { -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/Task.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/Task.java deleted file mode 100644 index 7cb335dd..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/Task.java +++ /dev/null @@ -1,4 +0,0 @@ -package dev.flexmodel.domain.model.flow.dto.model; - -public class Task extends ActivityNode { -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/UserTask.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/UserTask.java deleted file mode 100644 index 668cf000..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/UserTask.java +++ /dev/null @@ -1,4 +0,0 @@ -package dev.flexmodel.domain.model.flow.dto.model; - -public class UserTask extends Task { -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/ExpressionCalculatorPlugin.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/ExpressionCalculatorPlugin.java deleted file mode 100644 index 744edf42..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/ExpressionCalculatorPlugin.java +++ /dev/null @@ -1,7 +0,0 @@ -package dev.flexmodel.domain.model.flow.plugin; - -import dev.flexmodel.domain.model.flow.shared.util.ExpressionCalculator; - -public interface ExpressionCalculatorPlugin extends Plugin { - ExpressionCalculator getExpressionCalculator(); -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/IdGeneratorPlugin.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/IdGeneratorPlugin.java deleted file mode 100644 index 66192ce0..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/IdGeneratorPlugin.java +++ /dev/null @@ -1,7 +0,0 @@ -package dev.flexmodel.domain.model.flow.plugin; - -import dev.flexmodel.domain.model.flow.shared.util.IdGenerator; - -public interface IdGeneratorPlugin extends Plugin { - IdGenerator getIdGenerator(); -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/FlowDefinitionService.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/FlowDefinitionService.java deleted file mode 100644 index 0e0a71df..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/FlowDefinitionService.java +++ /dev/null @@ -1,28 +0,0 @@ -package dev.flexmodel.domain.model.flow.service; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import dev.flexmodel.codegen.entity.FlowDefinition; -import dev.flexmodel.domain.model.flow.repository.FlowDefinitionRepository; -import dev.flexmodel.query.Predicate; - -import java.util.List; - -/** - * @author cjbi - */ -@ApplicationScoped -public class FlowDefinitionService { - - @Inject - FlowDefinitionRepository flowDefinitionRepository; - - public List find(String projectId, Predicate filter, Integer page, Integer size) { - return flowDefinitionRepository.find(projectId, filter, page, size); - } - - public long count(String projectId, Predicate filter) { - return flowDefinitionRepository.count(projectId, filter); - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/GroovyUtil.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/GroovyUtil.java deleted file mode 100644 index 8c9eed38..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/GroovyUtil.java +++ /dev/null @@ -1,64 +0,0 @@ -package dev.flexmodel.domain.model.flow.shared.util; - -import groovy.lang.Binding; -import groovy.lang.GroovyShell; -import groovy.lang.MissingPropertyException; -import groovy.lang.Script; -import org.codehaus.groovy.runtime.InvokerHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.shared.utils.StringUtils; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class GroovyUtil { - - protected static final Logger LOGGER = LoggerFactory.getLogger(GroovyUtil.class); - - private static final Map> SCRIPT_CLASS_CACHE = new ConcurrentHashMap<>(); - - private GroovyUtil() { - } - - public static Object execute(String expression, Map dataMap) throws Exception { - if (StringUtils.isBlank(expression)) { - LOGGER.warn("calculate: expression is empty"); - return null; - } - try { - Binding binding = createBinding(dataMap); - Script shell = createScript(expression, binding); - Object resultObject = shell.run(); - LOGGER.info("calculate.||expression={}||resultObject={}", expression, resultObject); - return resultObject; - } catch (MissingPropertyException mpe) { - LOGGER.warn("calculate MissingPropertyException.||expression={}||dataMap={}", expression, dataMap); - throw new ProcessException(ErrorEnum.MISSING_DATA.getErrNo(), mpe.getMessage()); - } - } - - private static Script createScript(String groovyExpression, Binding binding) { - Script script; - if (SCRIPT_CLASS_CACHE.containsKey(groovyExpression)) { - Class scriptClass = SCRIPT_CLASS_CACHE.get(groovyExpression); - script = InvokerHelper.createScript(scriptClass, binding); - } else { - script = new GroovyShell(binding).parse(groovyExpression); - SCRIPT_CLASS_CACHE.put(groovyExpression, script.getClass()); - } - return script; - } - - private static Binding createBinding(Map infos) { - Binding binding = new Binding(); - if (!infos.isEmpty()) { - for (Map.Entry entry : infos.entrySet()) { - binding.setVariable(entry.getKey(), entry.getValue()); - } - } - return binding; - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/TriggerService.java b/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/TriggerService.java deleted file mode 100644 index c2d3d4bd..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/TriggerService.java +++ /dev/null @@ -1,39 +0,0 @@ -package dev.flexmodel.domain.model.schedule; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import dev.flexmodel.codegen.entity.Trigger; -import dev.flexmodel.query.Predicate; - -import java.util.List; - -/** - * @author cjbi - */ -@ApplicationScoped -public class TriggerService { - - @Inject - TriggerRepository triggerRepository; - - public Trigger findById(String projectId, String id) { - return triggerRepository.findById(projectId, id); - } - - public Trigger save(String projectId, Trigger trigger) { - return triggerRepository.save(projectId, trigger); - } - - public void deleteById(String projectId, String id) { - triggerRepository.deleteById(projectId, id); - } - - public long count(String projectId, Predicate filter) { - return triggerRepository.count(projectId, filter); - } - - public List find(String projectId, Predicate filter, Integer page, Integer size) { - return triggerRepository.find(projectId, filter, page, size); - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/FlowDefinitionResource.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/FlowDefinitionResource.java new file mode 100644 index 00000000..b41eee30 --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/FlowDefinitionResource.java @@ -0,0 +1,317 @@ +package dev.flexmodel.flow; + +import dev.flexmodel.common.dto.PageDTO; +import dev.flexmodel.flow.dto.FlowModuleListRequest; +import dev.flexmodel.flow.dto.FlowModuleResponse; +import dev.flexmodel.flow.dto.param.*; +import dev.flexmodel.flow.dto.result.*; +import jakarta.inject.Inject; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import lombok.Getter; +import lombok.Setter; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.enums.ParameterIn; +import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; +import org.eclipse.microprofile.openapi.annotations.media.Content; +import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.media.SchemaProperty; +import org.eclipse.microprofile.openapi.annotations.parameters.Parameter; +import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.eclipse.microprofile.openapi.annotations.tags.Tag; +import dev.flexmodel.flow.service.FlowDefinitionService; + +/** + * 流程定义管理 + * + * @author cjbi + */ +@Tag(name = "服务编排-流程定义", description = "流程模块的增删改查与部署管理") +@Path("/v1/projects/{projectId}/flows") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class FlowDefinitionResource { + + @Inject + FlowDefinitionService flowDefinitionService; + + @Operation(summary = "获取流程列表") + @APIResponse( + name = "200", + responseCode = "200", + description = "OK", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = FlowModuleListResponseSchema.class + ) + )}) + @GET + public PageDTO findFlowList( + @PathParam("projectId") String projectId, + @Parameter(name = "flowKey", description = "流程模块ID", in = ParameterIn.QUERY) + @QueryParam("flowModuleId") String flowModuleId, + @QueryParam("flowKey") String flowKey, + @Parameter(name = "flowName", description = "流程名称", in = ParameterIn.QUERY) + @QueryParam("flowName") String flowName, + @Parameter(name = "page", description = "页码", in = ParameterIn.QUERY) + @QueryParam("page") @DefaultValue("1") Integer page, + @Parameter(name = "size", description = "每页大小", in = ParameterIn.QUERY) + @QueryParam("size") @DefaultValue("20") Integer size) { + FlowModuleListRequest request = new FlowModuleListRequest(); + request.setProjectId(projectId); + request.setFlowModuleId(flowModuleId); + request.setFlowKey(flowKey); + request.setFlowName(flowName); + request.setPage(page); + request.setSize(size); + return flowDefinitionService.findFlowModuleList(request); + } + + @Operation(summary = "创建流程") + @POST + @RequestBody( + name = "请求体", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = CreateFlowParamSchema.class + ) + )} + ) + @APIResponse( + name = "200", + responseCode = "200", + description = "OK", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = CreateFlowResultSchema.class + ) + )}) + public CreateFlowResult createFlow(@PathParam("projectId") String projectId, CreateFlowParam createFlowParam) { + createFlowParam.setProjectId(projectId); + createFlowParam.setCaller("admin"); + createFlowParam.setOperator("admin"); + return flowDefinitionService.createFlow(createFlowParam); + } + + @Operation(summary = "更新流程") + @PUT + @Path("/{flowModuleId}") + @RequestBody( + name = "请求体", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = UpdateFlowParamSchema.class + ) + )} + ) + @APIResponse( + name = "200", + responseCode = "200", + description = "OK", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = UpdateFlowResultSchema.class + ) + )}) + public UpdateFlowResult updateFlow( + @PathParam("projectId") String projectId, + @Parameter(name = "flowModuleId", description = "流程模块ID", in = ParameterIn.PATH) + @PathParam("flowModuleId") String flowModuleId, + UpdateFlowParam updateFlowParam) { + updateFlowParam.setFlowModuleId(flowModuleId); + updateFlowParam.setProjectId(projectId); + updateFlowParam.setCaller(updateFlowParam.getCaller()); + updateFlowParam.setOperator(updateFlowParam.getOperator()); + return flowDefinitionService.updateFlow(updateFlowParam); + } + + @DELETE + @Path("/{flowModuleId}") + public void deleteFlow(@PathParam("projectId") String projectId, @Parameter(name = "flowModuleId", description = "流程模块ID", in = ParameterIn.PATH) + @PathParam("flowModuleId") String flowModuleId) { + flowDefinitionService.deleteFlow(projectId, flowModuleId); + } + + @Operation(summary = "获取流程模块信息") + @APIResponse( + name = "200", + responseCode = "200", + description = "OK", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = FlowModuleResultSchema.class + ) + )}) + @GET + @Path("/{flowModuleId}") + public FlowModuleResult getFlowModule( + @PathParam("projectId") String projectId, + @Parameter(name = "flowModuleId", description = "流程模块ID", in = ParameterIn.PATH) + @PathParam("flowModuleId") String flowModuleId, + @Parameter(name = "flowDeployId", description = "流程部署ID", in = ParameterIn.QUERY) + @QueryParam("flowDeployId") String flowDeployId) { + GetFlowModuleParam param = new GetFlowModuleParam(); + param.setProjectId(projectId); + param.setFlowModuleId(flowModuleId); + param.setFlowDeployId(flowDeployId); + return flowDefinitionService.getFlowModule(param); + } + + @Operation(summary = "部署流程") + @POST + @Path("/{flowModuleId}/deploy") + @RequestBody( + name = "请求体", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = DeployFlowParamSchema.class + ) + )} + ) + @APIResponse( + name = "200", + responseCode = "200", + description = "OK", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = DeployFlowResultSchema.class + ) + )}) + public DeployFlowResult deployFlow( + @PathParam("projectId") String projectId, + @Parameter(name = "flowModuleId", description = "流程模块ID", in = ParameterIn.PATH) + @PathParam("flowModuleId") String flowModuleId, + DeployFlowParam deployFlowParam) { + deployFlowParam.setProjectId(projectId); + deployFlowParam.setFlowModuleId(flowModuleId); + deployFlowParam.setCaller("admin"); + deployFlowParam.setOperator("admin"); + return flowDefinitionService.deployFlow(deployFlowParam); + } + + // ==================== OpenAPI Schema 定义 ==================== + + @Schema( + properties = { + @SchemaProperty(name = "flowKey", examples = {"order_process"}, description = "流程键"), + @SchemaProperty(name = "flowName", examples = {"订单处理流程"}, description = "流程名称"), + @SchemaProperty(name = "remark", examples = {"处理订单的完整业务流程"}, description = "备注"), + @SchemaProperty(name = "projectId", examples = {"default"}, description = "项目ID"), + @SchemaProperty(name = "caller", examples = {"admin"}, description = "调用者"), + @SchemaProperty(name = "operator", examples = {"admin"}, description = "操作者") + } + ) + public static class CreateFlowParamSchema extends CreateFlowParam { + public CreateFlowParamSchema() { + super("default", "admin"); + } + } + + @Schema( + properties = { + @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), + @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), + @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID") + } + ) + public static class CreateFlowResultSchema extends CreateFlowResult { + } + + @Schema( + properties = { + @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID"), + @SchemaProperty(name = "projectId", examples = {"default"}, description = "项目ID"), + @SchemaProperty(name = "caller", examples = {"admin"}, description = "调用者"), + @SchemaProperty(name = "operator", examples = {"admin"}, description = "操作者") + } + ) + public static class DeployFlowParamSchema extends DeployFlowParam { + public DeployFlowParamSchema() { + super("default", "admin"); + } + } + + @Schema( + properties = { + @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID"), + @SchemaProperty(name = "projectId", examples = {"default"}, description = "项目ID"), + @SchemaProperty(name = "caller", examples = {"admin"}, description = "调用者"), + @SchemaProperty(name = "operator", examples = {"admin"}, description = "操作者") + } + ) + public static class UpdateFlowParamSchema extends DeployFlowParam { + public UpdateFlowParamSchema() { + super("default", "admin"); + } + } + + @Schema( + properties = { + @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), + @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), + @SchemaProperty(name = "flowDeployId", examples = {"flow_deploy_001"}, description = "流程部署ID"), + @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID") + } + ) + public static class DeployFlowResultSchema extends DeployFlowResult { + } + + @Schema( + properties = { + @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), + @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), + } + ) + public static class UpdateFlowResultSchema extends UpdateFlowResult { + } + + @Schema( + properties = { + @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), + @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), + @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID"), + @SchemaProperty(name = "flowDeployId", examples = {"flow_deploy_001"}, description = "流程部署ID") + } + ) + public static class FlowModuleResultSchema extends FlowModuleResult { + } + + @Schema( + properties = { + @SchemaProperty(name = "list", description = "流程模块列表", type = SchemaType.ARRAY), + @SchemaProperty(name = "total", examples = {"100"}, description = "总记录数") + } + ) + @Getter + @Setter + public static class FlowModuleListResponseSchema { + private java.util.List list; + private Long total; + } + + @Schema( + properties = { + @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID"), + @SchemaProperty(name = "flowName", examples = {"订单处理流程"}, description = "流程名称"), + @SchemaProperty(name = "flowKey", examples = {"order_process"}, description = "流程键"), + @SchemaProperty(name = "status", examples = {"4"}, description = "状态:1-草稿,2-设计,3-测试,4-已发布"), + @SchemaProperty(name = "remark", examples = {"处理订单的完整业务流程"}, description = "备注"), + @SchemaProperty(name = "projectId", examples = {"default"}, description = "项目ID"), + @SchemaProperty(name = "caller", examples = {"admin"}, description = "调用者"), + @SchemaProperty(name = "operator", examples = {"admin"}, description = "操作者"), + @SchemaProperty(name = "modifyTime", description = "修改时间", readOnly = true) + } + ) + public static class FlowModuleResponseSchema extends FlowModuleResponse { + } + +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/FlowExecutionResource.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/FlowExecutionResource.java new file mode 100644 index 00000000..359fd4e5 --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/FlowExecutionResource.java @@ -0,0 +1,313 @@ +package dev.flexmodel.flow; + +import dev.flexmodel.flow.dto.param.*; +import dev.flexmodel.flow.dto.result.*; +import jakarta.inject.Inject; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.enums.ParameterIn; +import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; +import org.eclipse.microprofile.openapi.annotations.media.Content; +import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.media.SchemaProperty; +import org.eclipse.microprofile.openapi.annotations.parameters.Parameter; +import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.eclipse.microprofile.openapi.annotations.tags.Tag; +import dev.flexmodel.flow.service.FlowExecutionService; +import dev.flexmodel.flow.dto.bo.ElementInstance; +import dev.flexmodel.flow.dto.bo.NodeInstance; +import dev.flexmodel.flow.dto.result.InstanceDataListResult; + +import java.util.List; + +/** + * 流程执行操作 + * + * @author cjbi + */ +@Tag(name = "服务编排-流程执行", description = "流程启动、任务提交/回滚及执行历史查询") +@Path("/v1/projects/{projectId}/flows") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class FlowExecutionResource { + + @Inject + FlowExecutionService flowExecutionService; + + @Operation(summary = "启动流程实例") + @POST + @Path("/instances/start") + @RequestBody( + name = "请求体", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = StartProcessParamSchema.class + ) + )} + ) + @APIResponse( + name = "200", + responseCode = "200", + description = "OK", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = StartProcessResultSchema.class + ) + )}) + public StartProcessResult startProcess(@PathParam("projectId") String projectId, StartProcessParam startProcessParam) { + startProcessParam.setProjectId(projectId); + return flowExecutionService.startProcess(startProcessParam); + } + + @Operation(summary = "提交任务") + @POST + @Path("/instances/{flowInstanceId}/commit") + @RequestBody( + name = "请求体", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = CommitTaskParamSchema.class + ) + )} + ) + @APIResponse( + name = "200", + responseCode = "200", + description = "OK", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = CommitTaskResultSchema.class + ) + )}) + public CommitTaskResult commitTask( + @PathParam("projectId") String projectId, + @Parameter(name = "flowInstanceId", description = "流程实例ID", in = ParameterIn.PATH) + @PathParam("flowInstanceId") String flowInstanceId, + CommitTaskParam commitTaskParam) { + commitTaskParam.setProjectId(projectId); + commitTaskParam.setFlowInstanceId(flowInstanceId); + return flowExecutionService.commitTask(commitTaskParam); + } + + @Operation(summary = "回滚任务") + @POST + @Path("/instances/{flowInstanceId}/rollback") + @RequestBody( + name = "请求体", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = RollbackTaskParamSchema.class + ) + )} + ) + @APIResponse( + name = "200", + responseCode = "200", + description = "OK", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = RollbackTaskResultSchema.class + ) + )}) + public RollbackTaskResult rollbackTask( + @PathParam("projectId") String projectId, + @Parameter(name = "flowInstanceId", description = "流程实例ID", in = ParameterIn.PATH) + @PathParam("flowInstanceId") String flowInstanceId, + RollbackTaskParam rollbackTaskParam) { + rollbackTaskParam.setProjectId(projectId); + rollbackTaskParam.setFlowInstanceId(flowInstanceId); + return flowExecutionService.rollbackTask(rollbackTaskParam); + } + + @Operation(summary = "获取流程实例历史用户任务列表", description = "获取指定流程实例的历史用户任务列表,按处理时间倒序排列。包含活跃和已完成的任务,不包含已禁用的任务。") + @APIResponse( + name = "200", + responseCode = "200", + description = "成功返回历史用户任务列表", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + type = SchemaType.ARRAY, + implementation = NodeInstanceSchema.class + ) + )}) + @GET + @Path("/instances/{flowInstanceId}/user-tasks") + public List getHistoryUserTaskList( + @PathParam("projectId") String projectId, + @Parameter(name = "flowInstanceId", description = "流程实例ID", in = ParameterIn.PATH, required = true, example = "flow_inst_001") + @PathParam("flowInstanceId") String flowInstanceId, + @Parameter(name = "effectiveForSubFlowInstance", description = "是否对子流程实例生效", in = ParameterIn.QUERY, example = "true") + @QueryParam("effectiveForSubFlowInstance") @DefaultValue("true") boolean effectiveForSubFlowInstance) { + return flowExecutionService.getHistoryUserTaskList(projectId, flowInstanceId, effectiveForSubFlowInstance); + } + + @Operation(summary = "获取流程实例历史元素列表", description = "获取指定流程实例的历史元素列表,主要用于显示流程快照视图。包含流程中已执行的所有节点信息。") + @APIResponse( + name = "200", + responseCode = "200", + description = "成功返回历史元素列表", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + type = SchemaType.ARRAY, + implementation = ElementInstanceSchema.class + ) + )}) + @GET + @Path("/instances/{flowInstanceId}/elements") + public List getHistoryElementList( + @PathParam("projectId") String projectId, + @Parameter(name = "flowInstanceId", description = "流程实例ID", in = ParameterIn.PATH, required = true, example = "flow_inst_001") + @PathParam("flowInstanceId") String flowInstanceId) { + return flowExecutionService.getHistoryElementList(projectId, flowInstanceId); + } + + @Operation(summary = "获取流程实例元素实例数据") + @GET + @Path("/instances/{flowInstanceId}/data/{instanceDataId}") + public InstanceDataListResult getElementInstanceData(@PathParam("projectId") String projectId, + @PathParam("flowInstanceId") String flowInstanceId, + @PathParam("instanceDataId") String instanceDataId) { + return flowExecutionService.getInstanceData(projectId, flowInstanceId, instanceDataId); + } + + // ==================== OpenAPI Schema 定义 ==================== + + @Schema( + properties = { + @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID"), + @SchemaProperty(name = "flowDeployId", examples = {"flow_deploy_001"}, description = "流程部署ID"), + @SchemaProperty(name = "variables", description = "流程变量", type = SchemaType.ARRAY) + } + ) + public static class StartProcessParamSchema extends StartProcessParam { + } + + @Schema( + properties = { + @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), + @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), + @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), + @SchemaProperty(name = "status", examples = {"1"}, description = "状态"), + @SchemaProperty(name = "flowDeployId", examples = {"flow_deploy_001"}, description = "流程部署ID"), + @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID") + } + ) + public static class StartProcessResultSchema extends StartProcessResult { + } + + @Schema( + properties = { + @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), + @SchemaProperty(name = "nodeInstanceId", examples = {"node_inst_001"}, description = "节点实例ID"), + @SchemaProperty(name = "variables", description = "流程变量", type = SchemaType.ARRAY), + @SchemaProperty(name = "projectId", examples = {"default"}, description = "项目ID"), + @SchemaProperty(name = "caller", examples = {"admin"}, description = "调用者"), + @SchemaProperty(name = "operator", examples = {"admin"}, description = "操作者") + } + ) + public static class CommitTaskParamSchema extends CommitTaskParam { + } + + @Schema( + properties = { + @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), + @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), + @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), + @SchemaProperty(name = "status", examples = {"1"}, description = "状态") + } + ) + public static class CommitTaskResultSchema extends CommitTaskResult { + } + + @Schema( + properties = { + @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), + @SchemaProperty(name = "nodeInstanceId", examples = {"node_inst_001"}, description = "节点实例ID"), + @SchemaProperty(name = "projectId", examples = {"default"}, description = "项目ID"), + @SchemaProperty(name = "caller", examples = {"admin"}, description = "调用者"), + @SchemaProperty(name = "operator", examples = {"admin"}, description = "操作者") + } + ) + public static class RollbackTaskParamSchema extends RollbackTaskParam { + } + + @Schema( + properties = { + @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), + @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), + @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), + @SchemaProperty(name = "status", examples = {"1"}, description = "状态") + } + ) + public static class RollbackTaskResultSchema extends RollbackTaskResult { + } + + @Schema( + properties = { + @SchemaProperty(name = "nodeInstanceId", examples = {"node_inst_001"}, description = "节点实例ID"), + @SchemaProperty(name = "Key", examples = {"user_task_001"}, description = "模型键"), + @SchemaProperty(name = "modelName", examples = {"用户审批任务"}, description = "模型名称"), + @SchemaProperty(name = "status", examples = {"2"}, description = "节点状态:1-待处理,2-已完成,3-已跳过,4-已禁用"), + @SchemaProperty(name = "flowElementType", examples = {"1"}, description = "流程元素类型:1-用户任务,2-服务任务,3-网关,4-事件"), + @SchemaProperty(name = "properties", description = "节点属性", type = SchemaType.OBJECT), + @SchemaProperty(name = "subNodeResultList", description = "子节点执行结果列表", type = SchemaType.ARRAY), + @SchemaProperty(name = "subFlowInstanceIdList", description = "子流程实例ID列表", type = SchemaType.ARRAY), + @SchemaProperty(name = "subElementInstanceList", description = "子元素实例列表", type = SchemaType.ARRAY), + @SchemaProperty(name = "instanceDataId", examples = {"data_001"}, description = "实例数据ID"), + @SchemaProperty(name = "createTime", description = "创建时间", readOnly = true), + @SchemaProperty(name = "modifyTime", description = "修改时间", readOnly = true) + } + ) + public static class NodeInstanceSchema extends NodeInstance { + } + + @Schema( + properties = { + @SchemaProperty(name = "Key", examples = {"start_event_001"}, description = "键"), + @SchemaProperty(name = "name", examples = {"开始事件"}, description = "名称"), + @SchemaProperty(name = "status", examples = {"2"}, description = "元素状态:1-待处理,2-已完成,3-已跳过,4-已禁用"), + @SchemaProperty(name = "properties", description = "元素属性", type = SchemaType.OBJECT), + @SchemaProperty(name = "nodeInstanceId", examples = {"node_inst_001"}, description = "节点实例ID"), + @SchemaProperty(name = "subFlowInstanceIdList", description = "子流程实例ID列表", type = SchemaType.ARRAY), + @SchemaProperty(name = "subElementInstanceList", description = "子元素实例列表", type = SchemaType.ARRAY), + @SchemaProperty(name = "instanceDataId", examples = {"data_001"}, description = "实例数据ID") + } + ) + public static class ElementInstanceSchema extends ElementInstance { + } + + @Schema( + properties = { + @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), + @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), + @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), + @SchemaProperty(name = "status", examples = {"2"}, description = "流程状态:1-运行中,2-已完成,3-已终止,4-已暂停"), + @SchemaProperty(name = "nodeExecuteResults", description = "节点执行结果列表", type = SchemaType.ARRAY), + @SchemaProperty(name = "extendProperties", description = "扩展属性", type = SchemaType.OBJECT) + } + ) + public static class RuntimeResultSchema extends RuntimeResult { + } + + @Schema( + properties = { + @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), + @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), + @SchemaProperty(name = "activeTaskInstance", description = "活跃任务实例"), + @SchemaProperty(name = "variables", description = "流程变量列表", type = SchemaType.ARRAY) + } + ) + public static class NodeExecuteResultSchema extends RuntimeResult.NodeExecuteResult { + } + +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/FlowInstanceResource.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/FlowInstanceResource.java new file mode 100644 index 00000000..7fa54e99 --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/FlowInstanceResource.java @@ -0,0 +1,179 @@ +package dev.flexmodel.flow; + +import dev.flexmodel.common.dto.PageDTO; +import dev.flexmodel.flow.dto.FlowInstanceListRequest; +import dev.flexmodel.flow.dto.FlowInstanceResponse; +import dev.flexmodel.flow.dto.result.*; +import jakarta.inject.Inject; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import lombok.Getter; +import lombok.Setter; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.enums.ParameterIn; +import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; +import org.eclipse.microprofile.openapi.annotations.media.Content; +import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.media.SchemaProperty; +import org.eclipse.microprofile.openapi.annotations.parameters.Parameter; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.eclipse.microprofile.openapi.annotations.tags.Tag; +import dev.flexmodel.flow.service.FlowInstanceService; +import dev.flexmodel.codegen.entity.FlowInstance; +import dev.flexmodel.flow.common.ErrorEnum; + +/** + * 流程实例管理 + * + * @author cjbi + */ +@Tag(name = "服务编排-流程实例", description = "流程实例的查询与生命周期管理") +@Path("/v1/projects/{projectId}/flows") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class FlowInstanceResource { + + @Inject + FlowInstanceService flowInstanceService; + + @Operation(summary = "获取流程实例列表") + @APIResponse( + name = "200", + responseCode = "200", + description = "OK", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = FlowInstanceListResponseSchema.class + ) + )}) + @GET + @Path("/instances") + public PageDTO findFlowInstanceList( + @PathParam("projectId") String projectId, + @Parameter(name = "flowInstanceId", description = "流程实例ID", in = ParameterIn.QUERY) + @QueryParam("flowInstanceId") String flowInstanceId, + @Parameter(name = "flowModuleId", description = "流程模块ID", in = ParameterIn.QUERY) + @QueryParam("flowModuleId") String flowModuleId, + @Parameter(name = "flowDeployId", description = "流程部署ID", in = ParameterIn.QUERY) + @QueryParam("flowDeployId") String flowDeployId, + @Parameter(name = "status", description = "流程实例状态", in = ParameterIn.QUERY) + @QueryParam("status") Integer status, + @Parameter(name = "caller", description = "调用者", in = ParameterIn.QUERY) + @QueryParam("caller") String caller, + @Parameter(name = "page", description = "页码", in = ParameterIn.QUERY) + @QueryParam("page") @DefaultValue("1") Integer page, + @Parameter(name = "size", description = "每页大小", in = ParameterIn.QUERY) + @QueryParam("size") @DefaultValue("20") Integer size) { + FlowInstanceListRequest request = new FlowInstanceListRequest(); + request.setProjectId(projectId); + request.setFlowInstanceId(flowInstanceId); + request.setFlowModuleId(flowModuleId); + request.setFlowDeployId(flowDeployId); + request.setStatus(status); + request.setCaller(caller); + request.setPage(page); + request.setSize(size); + return flowInstanceService.findFlowInstanceList(request); + } + + @Operation(summary = "获取流程实例信息") + @APIResponse( + name = "200", + responseCode = "200", + description = "OK", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = FlowInstanceSchema.class + ) + )}) + @GET + @Path("/instances/{flowInstanceId}") + public FlowInstance getFlowInstance( + @PathParam("projectId") String projectId, + @Parameter(name = "flowInstanceId", description = "流程实例ID", in = ParameterIn.PATH) + @PathParam("flowInstanceId") String flowInstanceId) { + return flowInstanceService.findFlowInstance(projectId, flowInstanceId); + } + + @Operation(summary = "终止流程实例") + @POST + @Path("/instances/{flowInstanceId}/terminate") + @APIResponse( + name = "200", + responseCode = "200", + description = "OK", + content = {@Content( + mediaType = "application/json", + schema = @Schema( + implementation = TerminateResultSchema.class + ) + )}) + public TerminateResult terminateProcess( + @PathParam("projectId") String projectId, + @Parameter(name = "flowInstanceId", description = "流程实例ID", in = ParameterIn.PATH) + @PathParam("flowInstanceId") String flowInstanceId, + @Parameter(name = "effectiveForSubFlowInstance", description = "是否对子流程实例生效", in = ParameterIn.QUERY) + @QueryParam("effectiveForSubFlowInstance") @DefaultValue("true") boolean effectiveForSubFlowInstance) { + return flowInstanceService.terminateProcess(projectId, flowInstanceId, effectiveForSubFlowInstance); + } + + // ==================== OpenAPI Schema 定义 ==================== + + @Schema( + properties = { + @SchemaProperty(name = "list", description = "流程实例列表", type = SchemaType.ARRAY), + @SchemaProperty(name = "total", examples = {"100"}, description = "总记录数") + } + ) + @Getter + @Setter + public static class FlowInstanceListResponseSchema { + private java.util.List list; + private Long total; + } + + @Schema( + properties = { + @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), + @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID"), + @SchemaProperty(name = "flowDeployId", examples = {"flow_deploy_001"}, description = "流程部署ID"), + @SchemaProperty(name = "status", examples = {"1"}, description = "流程实例状态:1-运行中,2-已完成,3-已终止,4-已暂停"), + @SchemaProperty(name = "parentFlowInstanceId", examples = {"parent_inst_001"}, description = "父流程实例ID"), + @SchemaProperty(name = "projectId", examples = {"default"}, description = "项目ID"), + @SchemaProperty(name = "caller", examples = {"admin"}, description = "调用者"), + @SchemaProperty(name = "operator", examples = {"admin"}, description = "操作者"), + @SchemaProperty(name = "createTime", description = "创建时间", readOnly = true), + @SchemaProperty(name = "modifyTime", description = "修改时间", readOnly = true) + } + ) + @Getter + @Setter + public static class FlowInstanceSchema { + private String flowInstanceId; + private String flowModuleId; + private String flowDeployId; + private Integer status; + private String parentFlowInstanceId; + private String tenant; + private String caller; + private java.time.LocalDateTime createTime; + private java.time.LocalDateTime modifyTime; + } + + @Schema( + properties = { + @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), + @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), + @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), + @SchemaProperty(name = "status", examples = {"1"}, description = "状态") + } + ) + public static class TerminateResultSchema extends TerminateResult { + public TerminateResultSchema() { + super(ErrorEnum.SUCCESS); + } + } + +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/Constants.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/Constants.java similarity index 97% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/Constants.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/Constants.java index deea0004..f11a1a11 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/Constants.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/Constants.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; public class Constants { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/DataType.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/DataType.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/DataType.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/DataType.java index cc3e68f7..f3b76b22 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/DataType.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/DataType.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; public enum DataType { T_STRING(1, "string"), diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/ErrorEnum.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/ErrorEnum.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/ErrorEnum.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/ErrorEnum.java index 5f6d4705..f3ff8593 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/ErrorEnum.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/ErrorEnum.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; public enum ErrorEnum { @@ -56,11 +56,10 @@ public enum ErrorEnum { MISSING_DATA(4015, "Miss data"), SAVE_FLOW_INSTANCE_FAILED(4016, "Save flowInstance failed"), SAVE_INSTANCE_DATA_FAILED(4017, "Save instanceData failed"), - GROOVY_CALCULATE_FAILED(4018, "Groovy calculate failed"), - GET_CALL_ACTIVITY_MODEL_FAILED(4019, "Get CallActivity model failed"), - NO_RECEIVE_SUB_FLOW_INSTANCE(4020, "Do not receive subFlowInstanceId"), - UPDATE_INSTANCE_DATA_FAILED(4021, "Update instanceData failed"), - SERVICE_TASK_EXECUTION_FAILED(4022, "Service task execution failed"), + GET_CALL_ACTIVITY_MODEL_FAILED(4018, "Get CallActivity model failed"), + NO_RECEIVE_SUB_FLOW_INSTANCE(4019, "Do not receive subFlowInstanceId"), + UPDATE_INSTANCE_DATA_FAILED(4020, "Update instanceData failed"), + SERVICE_TASK_EXECUTION_FAILED(4021, "Service task execution failed"), //5000~5999 系统错误 diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/ExtendRuntimeContext.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/ExtendRuntimeContext.java similarity index 84% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/ExtendRuntimeContext.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/ExtendRuntimeContext.java index ce180444..e0671ea8 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/ExtendRuntimeContext.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/ExtendRuntimeContext.java @@ -1,8 +1,8 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstanceBO; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.TurboException; +import dev.flexmodel.flow.dto.bo.NodeInstanceBO; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.TurboException; import java.io.Serializable; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowDefinitionStatus.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowDefinitionStatus.java similarity index 83% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowDefinitionStatus.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowDefinitionStatus.java index 3062aac9..42725ebb 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowDefinitionStatus.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowDefinitionStatus.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; public class FlowDefinitionStatus { public static final int DEFAULT = 0; //数据库默认值 diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowDeploymentStatus.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowDeploymentStatus.java similarity index 79% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowDeploymentStatus.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowDeploymentStatus.java index aaadbbf7..e34c3143 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowDeploymentStatus.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowDeploymentStatus.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; public class FlowDeploymentStatus { public static final int DEFAULT = 0; //数据库默认值 diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowElementType.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowElementType.java similarity index 86% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowElementType.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowElementType.java index 97e7a5f4..4511e69f 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowElementType.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowElementType.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; public class FlowElementType { public static final int SEQUENCE_FLOW = 1; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowInstanceMappingType.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowInstanceMappingType.java similarity index 72% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowInstanceMappingType.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowInstanceMappingType.java index b698bd25..7cf29587 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowInstanceMappingType.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowInstanceMappingType.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; public class FlowInstanceMappingType { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowInstanceStatus.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowInstanceStatus.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowInstanceStatus.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowInstanceStatus.java index 8a4ef9ee..190af4c9 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowInstanceStatus.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowInstanceStatus.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; public class FlowInstanceStatus { public static final int DEFAULT = 0; //数据库默认值 diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowModuleEnum.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowModuleEnum.java similarity index 97% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowModuleEnum.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowModuleEnum.java index 41e73b30..c9f9c09c 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowModuleEnum.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowModuleEnum.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowModuleStatus.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowModuleStatus.java similarity index 82% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowModuleStatus.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowModuleStatus.java index 79e7458f..32ad1740 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/FlowModuleStatus.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/FlowModuleStatus.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; public class FlowModuleStatus { public static final int DEFAULT = 0; //数据库默认值 diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/InstanceDataType.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/InstanceDataType.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/InstanceDataType.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/InstanceDataType.java index 0ef5a901..2141df25 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/InstanceDataType.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/InstanceDataType.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; public class InstanceDataType { public static final int DEFAULT = 0; //数据库默认值 diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/NodeInstanceStatus.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/NodeInstanceStatus.java similarity index 85% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/NodeInstanceStatus.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/NodeInstanceStatus.java index 04fec2ec..3ffbdc44 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/NodeInstanceStatus.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/NodeInstanceStatus.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; public class NodeInstanceStatus { public static final int DEFAULT = 0; //数据库默认值 diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/NodeInstanceType.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/NodeInstanceType.java similarity index 82% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/NodeInstanceType.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/NodeInstanceType.java index a0998a73..17b37cb0 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/NodeInstanceType.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/NodeInstanceType.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; public class NodeInstanceType { public static final int DEFAULT = 0; //数据库默认值 diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/PluginTypeEnum.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/PluginTypeEnum.java similarity index 85% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/PluginTypeEnum.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/PluginTypeEnum.java index cd7d8358..9237d771 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/PluginTypeEnum.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/PluginTypeEnum.java @@ -1,7 +1,6 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; -import dev.flexmodel.domain.model.flow.plugin.*; -import dev.flexmodel.domain.model.flow.plugin.*; +import dev.flexmodel.flow.plugin.*; public enum PluginTypeEnum { EXPRESSION_CALCULATOR_PLUGIN("expressionCalculatorPlugin", ExpressionCalculatorPlugin.class), diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/ProcessStatus.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/ProcessStatus.java similarity index 77% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/ProcessStatus.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/ProcessStatus.java index f3199946..1f3ebb12 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/ProcessStatus.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/ProcessStatus.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; public class ProcessStatus { public static final int DEFAULT = 0; //数据库默认值 diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/RedisConstants.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/RedisConstants.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/RedisConstants.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/RedisConstants.java index 0902d361..a25fa951 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/RedisConstants.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/RedisConstants.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; public class RedisConstants { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/RuntimeContext.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/RuntimeContext.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/RuntimeContext.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/RuntimeContext.java index 4279026f..60ff9f45 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/common/RuntimeContext.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/RuntimeContext.java @@ -1,8 +1,8 @@ -package dev.flexmodel.domain.model.flow.shared.common; +package dev.flexmodel.flow.common; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstanceBO; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.dto.result.RuntimeResult; +import dev.flexmodel.flow.dto.bo.NodeInstanceBO; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.dto.result.RuntimeResult; import java.io.Serializable; import java.util.*; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/ExpressionCalculator.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/ExpressionCalculator.java similarity index 76% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/ExpressionCalculator.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/ExpressionCalculator.java index 6fd42365..b0e89b0d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/ExpressionCalculator.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/ExpressionCalculator.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.shared.util; +package dev.flexmodel.flow.common.util; -import dev.flexmodel.domain.model.flow.exception.ProcessException; +import dev.flexmodel.flow.exception.ProcessException; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/FlowModelUtil.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/FlowModelUtil.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/FlowModelUtil.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/FlowModelUtil.java index 64da1f2c..ef5e6a4d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/FlowModelUtil.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/FlowModelUtil.java @@ -1,14 +1,14 @@ -package dev.flexmodel.domain.model.flow.shared.util; +package dev.flexmodel.flow.common.util; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.common.utils.JsonUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.dto.model.FlowModel; -import dev.flexmodel.domain.model.flow.shared.common.Constants; -import dev.flexmodel.domain.model.flow.shared.common.FlowElementType; -import dev.flexmodel.shared.utils.CollectionUtils; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.dto.model.FlowModel; +import dev.flexmodel.flow.common.Constants; +import dev.flexmodel.flow.common.FlowElementType; +import dev.flexmodel.common.utils.CollectionUtils; +import dev.flexmodel.common.utils.StringUtils; import java.util.HashMap; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/IdGenerator.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/IdGenerator.java similarity index 52% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/IdGenerator.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/IdGenerator.java index 8b34fa40..c650f405 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/IdGenerator.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/IdGenerator.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.util; +package dev.flexmodel.flow.common.util; public interface IdGenerator { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/InstanceDataUtil.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/InstanceDataUtil.java similarity index 86% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/InstanceDataUtil.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/InstanceDataUtil.java index 00d36cef..210dce26 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/InstanceDataUtil.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/InstanceDataUtil.java @@ -1,7 +1,7 @@ -package dev.flexmodel.domain.model.flow.shared.util; +package dev.flexmodel.flow.common.util; -import dev.flexmodel.shared.utils.JsonUtils; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.common.utils.JsonUtils; +import dev.flexmodel.common.utils.StringUtils; import java.util.HashMap; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/JavaScriptUtil.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/JavaScriptUtil.java similarity index 95% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/JavaScriptUtil.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/JavaScriptUtil.java index 9a3fccf9..9d3e815a 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/JavaScriptUtil.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/JavaScriptUtil.java @@ -1,10 +1,10 @@ -package dev.flexmodel.domain.model.flow.shared.util; +package dev.flexmodel.flow.common.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.common.utils.StringUtils; import javax.script.*; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/MapToObjectConverter.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/MapToObjectConverter.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/MapToObjectConverter.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/MapToObjectConverter.java index dbef3a82..38a0e423 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/MapToObjectConverter.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/MapToObjectConverter.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.util; +package dev.flexmodel.flow.common.util; import java.lang.reflect.Field; import java.util.HashMap; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/PluginPropertiesUtil.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/PluginPropertiesUtil.java similarity index 97% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/PluginPropertiesUtil.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/PluginPropertiesUtil.java index a45c7b58..8accb9cc 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/PluginPropertiesUtil.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/PluginPropertiesUtil.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.util; +package dev.flexmodel.flow.common.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/RequestScriptContext.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/RequestScriptContext.java similarity index 95% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/RequestScriptContext.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/RequestScriptContext.java index d6dd20b8..5ca98dd4 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/RequestScriptContext.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/RequestScriptContext.java @@ -1,5 +1,6 @@ -package dev.flexmodel.domain.model.flow.shared.util; +package dev.flexmodel.flow.common.util; +import dev.flexmodel.common.utils.JsonUtils; import dev.flexmodel.query.Query; import dev.flexmodel.session.Session; import dev.flexmodel.session.SessionFactory; @@ -7,8 +8,7 @@ import lombok.Setter; import lombok.ToString; import org.slf4j.LoggerFactory; -import dev.flexmodel.JsonUtils; -import dev.flexmodel.shared.Constants; +import dev.flexmodel.common.Constants; import java.util.HashMap; import java.util.List; @@ -120,7 +120,7 @@ public Map buildContextMap() { */ @SuppressWarnings("all") public void syncFromMap(Map contextMap) { - JsonUtils.updateValue(this, contextMap); + JsonUtils.getInstance().updateValue(this, contextMap); } @@ -183,7 +183,7 @@ public List> find(String modelName, Map quer try (Session session = sessionFactory.createSession(datasourceName)) { Query query = new Query(); if (queryMap.containsKey("filter")) { - query.setFilter(dev.flexmodel.shared.utils.JsonUtils.getInstance().stringify(queryMap.get("filter"))); + query.setFilter(dev.flexmodel.common.utils.JsonUtils.getInstance().stringify(queryMap.get("filter"))); } return session.data().find(modelName, query); } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/SPIUtil.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/SPIUtil.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/SPIUtil.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/SPIUtil.java index af290e8d..44d92b1c 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/SPIUtil.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/SPIUtil.java @@ -1,8 +1,8 @@ -package dev.flexmodel.domain.model.flow.shared.util; +package dev.flexmodel.flow.common.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.plugin.Plugin; +import dev.flexmodel.flow.plugin.Plugin; import java.util.ArrayList; import java.util.Iterator; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/StrongUuidGenerator.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/StrongUuidGenerator.java similarity index 83% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/StrongUuidGenerator.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/StrongUuidGenerator.java index 92997eac..c66ff27d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/StrongUuidGenerator.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/StrongUuidGenerator.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.shared.util; +package dev.flexmodel.flow.common.util; import java.util.UUID; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/impl/GroovyExpressionCalculator.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/impl/JavaScriptExpressionCalculator.java similarity index 52% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/impl/GroovyExpressionCalculator.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/impl/JavaScriptExpressionCalculator.java index 79149368..bddd3d5c 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/shared/util/impl/GroovyExpressionCalculator.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/common/util/impl/JavaScriptExpressionCalculator.java @@ -1,19 +1,19 @@ -package dev.flexmodel.domain.model.flow.shared.util.impl; +package dev.flexmodel.flow.common.util.impl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.util.ExpressionCalculator; -import dev.flexmodel.domain.model.flow.shared.util.GroovyUtil; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.util.ExpressionCalculator; +import dev.flexmodel.flow.common.util.JavaScriptUtil; +import dev.flexmodel.common.utils.JsonUtils; import java.text.MessageFormat; import java.util.Map; -public class GroovyExpressionCalculator implements ExpressionCalculator { +public class JavaScriptExpressionCalculator implements ExpressionCalculator { - private static final Logger LOGGER = LoggerFactory.getLogger(GroovyExpressionCalculator.class); + private static final Logger LOGGER = LoggerFactory.getLogger(JavaScriptExpressionCalculator.class); @Override public Boolean calculate(String expression, Map dataMap) throws ProcessException { @@ -22,18 +22,18 @@ public Boolean calculate(String expression, Map dataMap) throws } Object result = null; try { - result = GroovyUtil.execute(expression, dataMap); + result = JavaScriptUtil.execute(expression, dataMap); if (result instanceof Boolean) { return (Boolean) result; } else { LOGGER.warn("the result of expression is not boolean.||expression={}||result={}||dataMap={}", expression, result, JsonUtils.getInstance().stringify(dataMap)); - throw new ProcessException(ErrorEnum.GROOVY_CALCULATE_FAILED.getErrNo(), "expression is not instanceof bool."); + throw new ProcessException(ErrorEnum.MISSING_DATA.getErrNo(), "expression is not instanceof bool."); } } catch (Exception e) { LOGGER.error("calculate expression failed.||message={}||expression={}||dataMap={}, ", e.getMessage(), expression, dataMap, e); - String groovyExFormat = "{0}: expression={1}"; - throw new ProcessException(ErrorEnum.GROOVY_CALCULATE_FAILED, MessageFormat.format(groovyExFormat, e.getMessage(), expression)); + String jsExFormat = "{0}: expression={1}"; + throw new ProcessException(ErrorEnum.MISSING_DATA, MessageFormat.format(jsExFormat, e.getMessage(), expression)); } finally { LOGGER.info("calculate expression.||expression={}||dataMap={}||result={}", expression, JsonUtils.getInstance().stringify(dataMap), result); } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/config/BusinessConfig.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/config/BusinessConfig.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/config/BusinessConfig.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/config/BusinessConfig.java index de4e51de..705b4b30 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/config/BusinessConfig.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/config/BusinessConfig.java @@ -1,8 +1,8 @@ -package dev.flexmodel.domain.model.flow.config; +package dev.flexmodel.flow.config; import jakarta.inject.Singleton; import org.eclipse.microprofile.config.inject.ConfigProperty; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.common.utils.JsonUtils; import java.util.Map; import java.util.Optional; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/config/PluginConfig.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/config/PluginConfig.java similarity index 80% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/config/PluginConfig.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/config/PluginConfig.java index 41ae209c..6d998502 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/config/PluginConfig.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/config/PluginConfig.java @@ -1,17 +1,17 @@ -package dev.flexmodel.domain.model.flow.config; +package dev.flexmodel.flow.config; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Produces; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.plugin.ExpressionCalculatorPlugin; -import dev.flexmodel.domain.model.flow.plugin.IdGeneratorPlugin; -import dev.flexmodel.domain.model.flow.plugin.manager.PluginManager; -import dev.flexmodel.domain.model.flow.shared.util.ExpressionCalculator; -import dev.flexmodel.domain.model.flow.shared.util.IdGenerator; -import dev.flexmodel.domain.model.flow.shared.util.StrongUuidGenerator; -import dev.flexmodel.domain.model.flow.shared.util.impl.GroovyExpressionCalculator; +import dev.flexmodel.flow.plugin.ExpressionCalculatorPlugin; +import dev.flexmodel.flow.plugin.IdGeneratorPlugin; +import dev.flexmodel.flow.plugin.manager.PluginManager; +import dev.flexmodel.flow.common.util.ExpressionCalculator; +import dev.flexmodel.flow.common.util.IdGenerator; +import dev.flexmodel.flow.common.util.StrongUuidGenerator; +import dev.flexmodel.flow.common.util.impl.JavaScriptExpressionCalculator; import java.util.List; import java.util.Optional; @@ -54,7 +54,7 @@ public ExpressionCalculator getExpressionCalculator(PluginManager pluginManager) LOGGER.info("Found expression calculator plugin: {}", expressionCalculatorPlugins.get(0).getName()); return expressionCalculatorPlugins.get(0).getExpressionCalculator(); } - return new GroovyExpressionCalculator(); + return new JavaScriptExpressionCalculator(); } /** diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/consumer/TriggerFlowEventConsumer.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/consumer/TriggerFlowEventConsumer.java similarity index 72% rename from flexmodel-server/src/main/java/dev/flexmodel/application/consumer/TriggerFlowEventConsumer.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/consumer/TriggerFlowEventConsumer.java index 1480c630..b06649ba 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/consumer/TriggerFlowEventConsumer.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/consumer/TriggerFlowEventConsumer.java @@ -1,14 +1,14 @@ -package dev.flexmodel.application.consumer; +package dev.flexmodel.flow.consumer; import io.quarkus.vertx.ConsumeEvent; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.application.FlowApplicationService; -import dev.flexmodel.domain.model.flow.dto.StartProcessParamEvent; -import dev.flexmodel.domain.model.flow.dto.result.StartProcessResult; -import dev.flexmodel.domain.model.schedule.JobExecutionLogService; -import dev.flexmodel.shared.SessionContextHolder; +import dev.flexmodel.flow.service.FlowExecutionService; +import dev.flexmodel.flow.dto.StartProcessParamEvent; +import dev.flexmodel.flow.dto.result.StartProcessResult; +import dev.flexmodel.scheduling.JobExecutionLogService; +import dev.flexmodel.common.SessionContextHolder; /** * @author cjbi @@ -18,7 +18,7 @@ public class TriggerFlowEventConsumer { @Inject - FlowApplicationService flowApplicationService; + FlowExecutionService flowExecutionService; @Inject JobExecutionLogService jobExecutionLogService; @@ -29,7 +29,7 @@ public void consume(StartProcessParamEvent param) { SessionContextHolder.setUserId(param.getUserId()); StartProcessResult result = null; try { - result = flowApplicationService.startProcess(param); + result = flowExecutionService.startProcess(param); log.info("flow.start.||startProcessParam={}||result={}", param, result); } catch (Exception e) { if (param.getEventId() != null) { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowInstanceListRequest.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowInstanceListRequest.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowInstanceListRequest.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowInstanceListRequest.java index be23b3f3..e03f0694 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowInstanceListRequest.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowInstanceListRequest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.flow.dto; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowInstanceResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowInstanceResponse.java similarity index 86% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowInstanceResponse.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowInstanceResponse.java index 5461106d..8272a118 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowInstanceResponse.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowInstanceResponse.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.flow.dto; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowModuleDetailResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowModuleDetailResponse.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowModuleDetailResponse.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowModuleDetailResponse.java index da6ff8ed..1374e0a6 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowModuleDetailResponse.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowModuleDetailResponse.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.flow.dto; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowModuleListRequest.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowModuleListRequest.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowModuleListRequest.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowModuleListRequest.java index 8d8e92d3..6f053786 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowModuleListRequest.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowModuleListRequest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.flow.dto; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowModuleResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowModuleResponse.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowModuleResponse.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowModuleResponse.java index b41575f5..720be210 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowModuleResponse.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowModuleResponse.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.flow.dto; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowModuleStatusEnum.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowModuleStatusEnum.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowModuleStatusEnum.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowModuleStatusEnum.java index 7a65a2ed..11dc46d7 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FlowModuleStatusEnum.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/FlowModuleStatusEnum.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.flow.dto; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/StartProcessParamEvent.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/StartProcessParamEvent.java similarity index 69% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/StartProcessParamEvent.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/StartProcessParamEvent.java index f8e5dc8c..b380d91b 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/StartProcessParamEvent.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/StartProcessParamEvent.java @@ -1,8 +1,8 @@ -package dev.flexmodel.domain.model.flow.dto; +package dev.flexmodel.flow.dto; import lombok.Getter; import lombok.Setter; -import dev.flexmodel.domain.model.flow.dto.param.StartProcessParam; +import dev.flexmodel.flow.dto.param.StartProcessParam; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/DataTransferBO.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/DataTransferBO.java similarity index 95% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/DataTransferBO.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/DataTransferBO.java index 1d4fec73..2775cd9f 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/DataTransferBO.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/DataTransferBO.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.bo; +package dev.flexmodel.flow.dto.bo; /** * The data transfer object is used in the scenario of parent to child diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/ElementInstance.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/ElementInstance.java similarity index 98% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/ElementInstance.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/ElementInstance.java index 3c3ee04f..09f654e0 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/ElementInstance.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/ElementInstance.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.bo; +package dev.flexmodel.flow.dto.bo; import java.util.List; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/FlowBasicInfo.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/FlowBasicInfo.java similarity index 95% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/FlowBasicInfo.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/FlowBasicInfo.java index c8b1273b..73d46305 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/FlowBasicInfo.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/FlowBasicInfo.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.bo; +package dev.flexmodel.flow.dto.bo; public class FlowBasicInfo { private String flowDeployId; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/FlowInfo.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/FlowInfo.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/FlowInfo.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/FlowInfo.java index 94535ae3..1a881558 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/FlowInfo.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/FlowInfo.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.bo; +package dev.flexmodel.flow.dto.bo; public class FlowInfo extends FlowBasicInfo { private String flowModel; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/FlowInstanceBO.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/FlowInstanceBO.java similarity index 97% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/FlowInstanceBO.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/FlowInstanceBO.java index 150c9a96..3713d123 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/FlowInstanceBO.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/FlowInstanceBO.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.bo; +package dev.flexmodel.flow.dto.bo; import java.util.HashMap; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/NodeInstance.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/NodeInstance.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/NodeInstance.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/NodeInstance.java index 1cd0fff2..a598d6c4 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/NodeInstance.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/NodeInstance.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.dto.bo; +package dev.flexmodel.flow.dto.bo; -import dev.flexmodel.domain.model.flow.dto.result.RuntimeResult; +import dev.flexmodel.flow.dto.result.RuntimeResult; import java.time.LocalDateTime; import java.util.HashMap; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/NodeInstanceBO.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/NodeInstanceBO.java similarity index 98% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/NodeInstanceBO.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/NodeInstanceBO.java index e94c88c9..237ddf86 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/bo/NodeInstanceBO.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/bo/NodeInstanceBO.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.bo; +package dev.flexmodel.flow.dto.bo; import java.io.Serializable; import java.util.HashMap; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/ActivityNode.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/ActivityNode.java new file mode 100644 index 00000000..de56ab3c --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/ActivityNode.java @@ -0,0 +1,4 @@ +package dev.flexmodel.flow.dto.model; + +public class ActivityNode extends FlowNode { +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/CallActivity.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/CallActivity.java similarity index 50% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/CallActivity.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/CallActivity.java index d89d007e..72fa704c 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/CallActivity.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/CallActivity.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.model; +package dev.flexmodel.flow.dto.model; public class CallActivity extends ActivityNode { } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/EndEvent.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/EndEvent.java new file mode 100644 index 00000000..2391e243 --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/EndEvent.java @@ -0,0 +1,4 @@ +package dev.flexmodel.flow.dto.model; + +public class EndEvent extends EventNode { +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/EventNode.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/EventNode.java new file mode 100644 index 00000000..29865bfd --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/EventNode.java @@ -0,0 +1,5 @@ +package dev.flexmodel.flow.dto.model; + +public class EventNode extends FlowNode { + +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/ExclusiveGateway.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/ExclusiveGateway.java similarity index 51% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/ExclusiveGateway.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/ExclusiveGateway.java index 1cfe3a2b..a649a910 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/ExclusiveGateway.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/ExclusiveGateway.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.model; +package dev.flexmodel.flow.dto.model; public class ExclusiveGateway extends GatewayNode { } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/FlowElement.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/FlowElement.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/FlowElement.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/FlowElement.java index e0c339f5..149d19af 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/FlowElement.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/FlowElement.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.model; +package dev.flexmodel.flow.dto.model; import java.io.Serializable; import java.util.HashMap; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/FlowModel.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/FlowModel.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/FlowModel.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/FlowModel.java index c066cd57..cc4c0812 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/FlowModel.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/FlowModel.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.model; +package dev.flexmodel.flow.dto.model; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/FlowNode.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/FlowNode.java new file mode 100644 index 00000000..af9757d2 --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/FlowNode.java @@ -0,0 +1,4 @@ +package dev.flexmodel.flow.dto.model; + +public class FlowNode extends FlowElement { +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/GatewayNode.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/GatewayNode.java new file mode 100644 index 00000000..bf469a5c --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/GatewayNode.java @@ -0,0 +1,4 @@ +package dev.flexmodel.flow.dto.model; + +public class GatewayNode extends FlowNode { +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/SequenceFlow.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/SequenceFlow.java similarity index 50% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/SequenceFlow.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/SequenceFlow.java index f2d50875..0b2d7d03 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/model/SequenceFlow.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/SequenceFlow.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.model; +package dev.flexmodel.flow.dto.model; public class SequenceFlow extends FlowElement { } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/StartEvent.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/StartEvent.java new file mode 100644 index 00000000..2314b9a7 --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/StartEvent.java @@ -0,0 +1,4 @@ +package dev.flexmodel.flow.dto.model; + +public class StartEvent extends EventNode { +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/SubProcess.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/SubProcess.java new file mode 100644 index 00000000..9aae7a50 --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/SubProcess.java @@ -0,0 +1,4 @@ +package dev.flexmodel.flow.dto.model; + +public class SubProcess extends ActivityNode { +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/Task.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/Task.java new file mode 100644 index 00000000..2ca861f4 --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/Task.java @@ -0,0 +1,4 @@ +package dev.flexmodel.flow.dto.model; + +public class Task extends ActivityNode { +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/UserTask.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/UserTask.java new file mode 100644 index 00000000..10913e1e --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/model/UserTask.java @@ -0,0 +1,4 @@ +package dev.flexmodel.flow.dto.model; + +public class UserTask extends Task { +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/CommitTaskParam.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/CommitTaskParam.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/CommitTaskParam.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/CommitTaskParam.java index 130eb0c3..afe4003d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/CommitTaskParam.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/CommitTaskParam.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.param; +package dev.flexmodel.flow.dto.param; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/CommonParam.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/CommonParam.java similarity index 92% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/CommonParam.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/CommonParam.java index f4de7a88..2c0aca0b 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/CommonParam.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/CommonParam.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.param; +package dev.flexmodel.flow.dto.param; public class CommonParam { private String projectId; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/CreateFlowParam.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/CreateFlowParam.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/CreateFlowParam.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/CreateFlowParam.java index 6cb8e22c..d6dfb3f1 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/CreateFlowParam.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/CreateFlowParam.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.param; +package dev.flexmodel.flow.dto.param; public class CreateFlowParam extends OperationParam { private String flowKey; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/DeployFlowParam.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/DeployFlowParam.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/DeployFlowParam.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/DeployFlowParam.java index c86a7af3..6d954bd5 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/DeployFlowParam.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/DeployFlowParam.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.param; +package dev.flexmodel.flow.dto.param; public class DeployFlowParam extends OperationParam { private String flowModuleId; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/GetFlowModuleParam.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/GetFlowModuleParam.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/GetFlowModuleParam.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/GetFlowModuleParam.java index 37a2c821..bde843a4 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/GetFlowModuleParam.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/GetFlowModuleParam.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.param; +package dev.flexmodel.flow.dto.param; public class GetFlowModuleParam { private String projectId; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/OperationParam.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/OperationParam.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/OperationParam.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/OperationParam.java index 8ba01300..1c5ee9c2 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/OperationParam.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/OperationParam.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.param; +package dev.flexmodel.flow.dto.param; public class OperationParam extends CommonParam { private String operator; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/RollbackTaskParam.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/RollbackTaskParam.java similarity index 54% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/RollbackTaskParam.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/RollbackTaskParam.java index 62c18b2f..fa85d4a9 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/RollbackTaskParam.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/RollbackTaskParam.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.param; +package dev.flexmodel.flow.dto.param; public class RollbackTaskParam extends RuntimeTaskParam { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/RuntimeTaskParam.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/RuntimeTaskParam.java similarity index 92% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/RuntimeTaskParam.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/RuntimeTaskParam.java index 2ae10b2e..f4efdcae 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/RuntimeTaskParam.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/RuntimeTaskParam.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.dto.param; +package dev.flexmodel.flow.dto.param; -import dev.flexmodel.domain.model.flow.shared.common.RuntimeContext; +import dev.flexmodel.flow.common.RuntimeContext; import java.util.HashMap; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/StartProcessParam.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/StartProcessParam.java similarity index 92% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/StartProcessParam.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/StartProcessParam.java index 11bab0e8..e7361405 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/StartProcessParam.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/StartProcessParam.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.dto.param; +package dev.flexmodel.flow.dto.param; -import dev.flexmodel.domain.model.flow.shared.common.RuntimeContext; +import dev.flexmodel.flow.common.RuntimeContext; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/UpdateFlowParam.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/UpdateFlowParam.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/UpdateFlowParam.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/UpdateFlowParam.java index f45db0bd..2a28e961 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/param/UpdateFlowParam.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/param/UpdateFlowParam.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.param; +package dev.flexmodel.flow.dto.param; public class UpdateFlowParam extends OperationParam { private String flowKey; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/CommitTaskResult.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/CommitTaskResult.java similarity index 52% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/CommitTaskResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/CommitTaskResult.java index 8ec66097..94b71694 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/CommitTaskResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/CommitTaskResult.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.result; +package dev.flexmodel.flow.dto.result; public class CommitTaskResult extends RuntimeResult { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/CommonResult.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/CommonResult.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/CommonResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/CommonResult.java index ec887b28..8e6fa70f 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/CommonResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/CommonResult.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.dto.result; +package dev.flexmodel.flow.dto.result; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; +import dev.flexmodel.flow.common.ErrorEnum; import java.io.Serializable; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/CreateFlowResult.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/CreateFlowResult.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/CreateFlowResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/CreateFlowResult.java index f85e8662..9fb85956 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/CreateFlowResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/CreateFlowResult.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.result; +package dev.flexmodel.flow.dto.result; public class CreateFlowResult extends CommonResult { private String flowModuleId; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/DeployFlowResult.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/DeployFlowResult.java similarity index 92% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/DeployFlowResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/DeployFlowResult.java index d35be448..f6686d46 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/DeployFlowResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/DeployFlowResult.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.result; +package dev.flexmodel.flow.dto.result; public class DeployFlowResult extends CommonResult { private String flowModuleId; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/ElementInstanceListResult.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/ElementInstanceListResult.java similarity index 77% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/ElementInstanceListResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/ElementInstanceListResult.java index 5c8ae198..381a8592 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/ElementInstanceListResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/ElementInstanceListResult.java @@ -1,7 +1,7 @@ -package dev.flexmodel.domain.model.flow.dto.result; +package dev.flexmodel.flow.dto.result; -import dev.flexmodel.domain.model.flow.dto.bo.ElementInstance; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; +import dev.flexmodel.flow.dto.bo.ElementInstance; +import dev.flexmodel.flow.common.ErrorEnum; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/FlowInstanceResult.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/FlowInstanceResult.java similarity index 78% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/FlowInstanceResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/FlowInstanceResult.java index 0247cb44..ed3fd8bf 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/FlowInstanceResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/FlowInstanceResult.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.dto.result; +package dev.flexmodel.flow.dto.result; -import dev.flexmodel.domain.model.flow.dto.bo.FlowInstanceBO; +import dev.flexmodel.flow.dto.bo.FlowInstanceBO; public class FlowInstanceResult extends CommonResult { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/FlowModuleResult.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/FlowModuleResult.java similarity index 97% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/FlowModuleResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/FlowModuleResult.java index d469c930..fc0c3605 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/FlowModuleResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/FlowModuleResult.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.result; +package dev.flexmodel.flow.dto.result; import java.time.LocalDateTime; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/InstanceDataListResult.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/InstanceDataListResult.java similarity index 81% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/InstanceDataListResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/InstanceDataListResult.java index c6f04fdc..4279a21b 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/InstanceDataListResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/InstanceDataListResult.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.dto.result; +package dev.flexmodel.flow.dto.result; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; +import dev.flexmodel.flow.common.ErrorEnum; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/NodeInstanceListResult.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/NodeInstanceListResult.java similarity index 76% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/NodeInstanceListResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/NodeInstanceListResult.java index 232c1438..2821bbaa 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/NodeInstanceListResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/NodeInstanceListResult.java @@ -1,7 +1,7 @@ -package dev.flexmodel.domain.model.flow.dto.result; +package dev.flexmodel.flow.dto.result; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstance; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; +import dev.flexmodel.flow.dto.bo.NodeInstance; +import dev.flexmodel.flow.common.ErrorEnum; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/NodeInstanceResult.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/NodeInstanceResult.java similarity index 79% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/NodeInstanceResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/NodeInstanceResult.java index 93a9f8c8..bc61e75a 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/NodeInstanceResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/NodeInstanceResult.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.dto.result; +package dev.flexmodel.flow.dto.result; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstance; +import dev.flexmodel.flow.dto.bo.NodeInstance; public class NodeInstanceResult extends CommonResult { private NodeInstance nodeInstance; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/RollbackTaskResult.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/RollbackTaskResult.java similarity index 53% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/RollbackTaskResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/RollbackTaskResult.java index ca6a6b60..88131ad8 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/RollbackTaskResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/RollbackTaskResult.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.result; +package dev.flexmodel.flow.dto.result; public class RollbackTaskResult extends RuntimeResult { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/RuntimeResult.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/RuntimeResult.java similarity index 95% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/RuntimeResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/RuntimeResult.java index 28821318..92c0cd68 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/RuntimeResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/RuntimeResult.java @@ -1,7 +1,7 @@ -package dev.flexmodel.domain.model.flow.dto.result; +package dev.flexmodel.flow.dto.result; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstance; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; +import dev.flexmodel.flow.dto.bo.NodeInstance; +import dev.flexmodel.flow.common.ErrorEnum; import java.util.ArrayList; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/StartProcessResult.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/StartProcessResult.java similarity index 92% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/StartProcessResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/StartProcessResult.java index 039d9f45..2c501f4a 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/StartProcessResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/StartProcessResult.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.result; +package dev.flexmodel.flow.dto.result; public class StartProcessResult extends RuntimeResult { private String flowDeployId; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/TerminateResult.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/TerminateResult.java similarity index 53% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/TerminateResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/TerminateResult.java index e44d14fc..68916125 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/TerminateResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/TerminateResult.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.dto.result; +package dev.flexmodel.flow.dto.result; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; +import dev.flexmodel.flow.common.ErrorEnum; public class TerminateResult extends RuntimeResult { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/UpdateFlowResult.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/UpdateFlowResult.java similarity index 51% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/UpdateFlowResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/UpdateFlowResult.java index 22011492..5ad15f5c 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/dto/result/UpdateFlowResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/dto/result/UpdateFlowResult.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.dto.result; +package dev.flexmodel.flow.dto.result; public class UpdateFlowResult extends CommonResult { } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/event/StartFlowEvent.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/event/StartFlowEvent.java similarity index 83% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/event/StartFlowEvent.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/event/StartFlowEvent.java index 9c1ada26..f12c732b 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/event/StartFlowEvent.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/event/StartFlowEvent.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.event; +package dev.flexmodel.flow.event; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/DefinitionException.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/exception/DefinitionException.java similarity index 66% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/DefinitionException.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/exception/DefinitionException.java index fa614ef8..2f0be5ad 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/DefinitionException.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/exception/DefinitionException.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.exception; +package dev.flexmodel.flow.exception; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; +import dev.flexmodel.flow.common.ErrorEnum; public class DefinitionException extends TurboException { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/ParamException.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/exception/ParamException.java similarity index 65% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/ParamException.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/exception/ParamException.java index 2c0c5e78..78cec805 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/ParamException.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/exception/ParamException.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.exception; +package dev.flexmodel.flow.exception; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; +import dev.flexmodel.flow.common.ErrorEnum; public class ParamException extends TurboException { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/ProcessException.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/exception/ProcessException.java similarity index 73% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/ProcessException.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/exception/ProcessException.java index b63ff121..7f95fad0 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/ProcessException.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/exception/ProcessException.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.exception; +package dev.flexmodel.flow.exception; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; +import dev.flexmodel.flow.common.ErrorEnum; public class ProcessException extends TurboException { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/ReentrantException.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/exception/ReentrantException.java similarity index 66% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/ReentrantException.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/exception/ReentrantException.java index 7affdc53..caf5b68f 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/ReentrantException.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/exception/ReentrantException.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.exception; +package dev.flexmodel.flow.exception; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; +import dev.flexmodel.flow.common.ErrorEnum; public class ReentrantException extends ProcessException { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/SuspendException.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/exception/SuspendException.java similarity index 74% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/SuspendException.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/exception/SuspendException.java index ed18ac05..6272a528 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/SuspendException.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/exception/SuspendException.java @@ -1,7 +1,7 @@ -package dev.flexmodel.domain.model.flow.exception; +package dev.flexmodel.flow.exception; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; +import dev.flexmodel.flow.common.ErrorEnum; public class SuspendException extends ProcessException { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/TurboException.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/exception/TurboException.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/TurboException.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/exception/TurboException.java index 63deb0bf..199976f6 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/exception/TurboException.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/exception/TurboException.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.exception; +package dev.flexmodel.flow.exception; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; +import dev.flexmodel.flow.common.ErrorEnum; import java.text.MessageFormat; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/ElementExecutor.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/ElementExecutor.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/ElementExecutor.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/executor/ElementExecutor.java index ce119523..0de741df 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/ElementExecutor.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/ElementExecutor.java @@ -1,24 +1,24 @@ -package dev.flexmodel.domain.model.flow.executor; +package dev.flexmodel.flow.executor; import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import dev.flexmodel.codegen.entity.NodeInstance; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstanceBO; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.exception.ReentrantException; -import dev.flexmodel.domain.model.flow.exception.SuspendException; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.common.FlowElementType; -import dev.flexmodel.domain.model.flow.shared.common.NodeInstanceStatus; -import dev.flexmodel.domain.model.flow.shared.common.RuntimeContext; -import dev.flexmodel.domain.model.flow.shared.util.ExpressionCalculator; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; -import dev.flexmodel.domain.model.flow.shared.util.InstanceDataUtil; -import dev.flexmodel.shared.utils.JsonUtils; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.flow.dto.bo.NodeInstanceBO; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.exception.ReentrantException; +import dev.flexmodel.flow.exception.SuspendException; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.FlowElementType; +import dev.flexmodel.flow.common.NodeInstanceStatus; +import dev.flexmodel.flow.common.RuntimeContext; +import dev.flexmodel.flow.common.util.ExpressionCalculator; +import dev.flexmodel.flow.common.util.FlowModelUtil; +import dev.flexmodel.flow.common.util.InstanceDataUtil; +import dev.flexmodel.common.utils.JsonUtils; +import dev.flexmodel.common.utils.StringUtils; import java.util.List; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/EndEventExecutor.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/EndEventExecutor.java similarity index 77% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/EndEventExecutor.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/executor/EndEventExecutor.java index 2155e636..1126d262 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/EndEventExecutor.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/EndEventExecutor.java @@ -1,16 +1,16 @@ -package dev.flexmodel.domain.model.flow.executor; +package dev.flexmodel.flow.executor; import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstanceBO; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.shared.common.Constants; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.common.NodeInstanceStatus; -import dev.flexmodel.domain.model.flow.shared.common.RuntimeContext; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; +import dev.flexmodel.flow.dto.bo.NodeInstanceBO; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.common.Constants; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.NodeInstanceStatus; +import dev.flexmodel.flow.common.RuntimeContext; +import dev.flexmodel.flow.common.util.FlowModelUtil; import java.text.MessageFormat; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/ExclusiveGatewayExecutor.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/ExclusiveGatewayExecutor.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/ExclusiveGatewayExecutor.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/executor/ExclusiveGatewayExecutor.java index 29485da6..3075e7cc 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/ExclusiveGatewayExecutor.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/ExclusiveGatewayExecutor.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.executor; +package dev.flexmodel.flow.executor; import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; @@ -6,17 +6,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import dev.flexmodel.codegen.entity.InstanceData; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstanceBO; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.shared.common.InstanceDataType; -import dev.flexmodel.domain.model.flow.shared.common.NodeInstanceStatus; -import dev.flexmodel.domain.model.flow.shared.common.RuntimeContext; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; -import dev.flexmodel.domain.model.flow.shared.util.InstanceDataUtil; -import dev.flexmodel.domain.model.flow.spi.HookService; -import dev.flexmodel.shared.utils.JsonUtils; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.flow.dto.bo.NodeInstanceBO; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.common.InstanceDataType; +import dev.flexmodel.flow.common.NodeInstanceStatus; +import dev.flexmodel.flow.common.RuntimeContext; +import dev.flexmodel.flow.common.util.FlowModelUtil; +import dev.flexmodel.flow.common.util.InstanceDataUtil; +import dev.flexmodel.flow.spi.HookService; +import dev.flexmodel.common.utils.JsonUtils; +import dev.flexmodel.common.utils.StringUtils; import java.time.LocalDateTime; import java.util.ArrayList; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/ExecutorFactory.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/ExecutorFactory.java similarity index 85% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/ExecutorFactory.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/executor/ExecutorFactory.java index 378ea95a..5e4927f0 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/ExecutorFactory.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/ExecutorFactory.java @@ -1,19 +1,19 @@ -package dev.flexmodel.domain.model.flow.executor; +package dev.flexmodel.flow.executor; import jakarta.annotation.PostConstruct; import jakarta.inject.Inject; import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.executor.callactivity.SyncSingleCallActivityExecutor; -import dev.flexmodel.domain.model.flow.plugin.ElementPlugin; -import dev.flexmodel.domain.model.flow.plugin.manager.PluginManager; -import dev.flexmodel.domain.model.flow.shared.common.Constants; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.common.FlowElementType; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.executor.callactivity.SyncSingleCallActivityExecutor; +import dev.flexmodel.flow.plugin.ElementPlugin; +import dev.flexmodel.flow.plugin.manager.PluginManager; +import dev.flexmodel.flow.common.Constants; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.FlowElementType; +import dev.flexmodel.flow.common.util.FlowModelUtil; import java.text.MessageFormat; import java.util.HashMap; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/FlowExecutor.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/FlowExecutor.java similarity index 97% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/FlowExecutor.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/executor/FlowExecutor.java index 5eda957a..cf6b5763 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/FlowExecutor.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/FlowExecutor.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.executor; +package dev.flexmodel.flow.executor; -import dev.flexmodel.domain.model.flow.shared.common.*; +import dev.flexmodel.flow.common.*; import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; import jakarta.inject.Singleton; @@ -10,17 +10,16 @@ import dev.flexmodel.codegen.entity.InstanceData; import dev.flexmodel.codegen.entity.NodeInstance; import dev.flexmodel.codegen.entity.NodeInstanceLog; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstanceBO; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.exception.ReentrantException; -import dev.flexmodel.domain.model.flow.repository.FlowInstanceRepository; -import dev.flexmodel.domain.model.flow.shared.common.*; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; -import dev.flexmodel.domain.model.flow.shared.util.InstanceDataUtil; -import dev.flexmodel.shared.utils.CollectionUtils; -import dev.flexmodel.shared.utils.JsonUtils; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.flow.dto.bo.NodeInstanceBO; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.exception.ReentrantException; +import dev.flexmodel.flow.repository.FlowInstanceRepository; +import dev.flexmodel.flow.common.util.FlowModelUtil; +import dev.flexmodel.flow.common.util.InstanceDataUtil; +import dev.flexmodel.common.utils.CollectionUtils; +import dev.flexmodel.common.utils.JsonUtils; +import dev.flexmodel.common.utils.StringUtils; import java.time.LocalDateTime; import java.util.ArrayList; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/RuntimeExecutor.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/RuntimeExecutor.java similarity index 76% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/RuntimeExecutor.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/executor/RuntimeExecutor.java index a045fa46..523f1a6a 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/RuntimeExecutor.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/RuntimeExecutor.java @@ -1,17 +1,16 @@ -package dev.flexmodel.domain.model.flow.executor; +package dev.flexmodel.flow.executor; -import dev.flexmodel.domain.model.flow.repository.*; +import dev.flexmodel.flow.repository.*; import jakarta.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.plugin.IdGeneratorPlugin; -import dev.flexmodel.domain.model.flow.plugin.manager.PluginManager; -import dev.flexmodel.domain.model.flow.repository.*; -import dev.flexmodel.domain.model.flow.shared.common.RuntimeContext; -import dev.flexmodel.domain.model.flow.shared.util.IdGenerator; -import dev.flexmodel.domain.model.flow.shared.util.StrongUuidGenerator; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.plugin.IdGeneratorPlugin; +import dev.flexmodel.flow.plugin.manager.PluginManager; +import dev.flexmodel.flow.common.RuntimeContext; +import dev.flexmodel.flow.common.util.IdGenerator; +import dev.flexmodel.flow.common.util.StrongUuidGenerator; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/SequenceFlowExecutor.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/SequenceFlowExecutor.java similarity index 68% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/SequenceFlowExecutor.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/executor/SequenceFlowExecutor.java index d5216ce4..acfcac60 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/SequenceFlowExecutor.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/SequenceFlowExecutor.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.executor; +package dev.flexmodel.flow.executor; import jakarta.inject.Singleton; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/ServiceTaskExecutor.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/ServiceTaskExecutor.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/ServiceTaskExecutor.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/executor/ServiceTaskExecutor.java index 86153392..424783e8 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/ServiceTaskExecutor.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/ServiceTaskExecutor.java @@ -1,23 +1,23 @@ -package dev.flexmodel.domain.model.flow.executor; +package dev.flexmodel.flow.executor; import jakarta.inject.Inject; import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import dev.flexmodel.codegen.entity.InstanceData; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstanceBO; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.common.InstanceDataType; -import dev.flexmodel.domain.model.flow.shared.common.NodeInstanceStatus; -import dev.flexmodel.domain.model.flow.shared.common.RuntimeContext; -import dev.flexmodel.domain.model.flow.shared.util.JavaScriptUtil; +import dev.flexmodel.flow.dto.bo.NodeInstanceBO; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.InstanceDataType; +import dev.flexmodel.flow.common.NodeInstanceStatus; +import dev.flexmodel.flow.common.RuntimeContext; +import dev.flexmodel.flow.common.util.JavaScriptUtil; import dev.flexmodel.query.Direction; import dev.flexmodel.query.Query; import dev.flexmodel.session.Session; import dev.flexmodel.session.SessionFactory; -import dev.flexmodel.shared.utils.JsonUtils; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.common.utils.JsonUtils; +import dev.flexmodel.common.utils.StringUtils; import java.time.LocalDateTime; import java.util.HashMap; @@ -76,7 +76,7 @@ protected void doExecute(RuntimeContext runtimeContext) throws ProcessException // 执行 CRUD 操作 result = executeAction(subType, null, nodeInstance, runtimeContext.getInstanceDataMap()); } else { - // 获取脚本内容(用于 groovy、js 等脚本类型) + // 获取脚本内容(用于 js、sql 等脚本类型) Object scriptObj = nodeInstance.get("script"); if (scriptObj == null) { LOGGER.error("doExecute: script is null.||nodeInstanceId={}||nodeKey={}||subType={}", diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/StartEventExecutor.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/StartEventExecutor.java similarity index 81% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/StartEventExecutor.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/executor/StartEventExecutor.java index 3fb7b031..b1572f91 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/StartEventExecutor.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/StartEventExecutor.java @@ -1,13 +1,13 @@ -package dev.flexmodel.domain.model.flow.executor; +package dev.flexmodel.flow.executor; import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstanceBO; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.common.NodeInstanceStatus; -import dev.flexmodel.domain.model.flow.shared.common.RuntimeContext; +import dev.flexmodel.flow.dto.bo.NodeInstanceBO; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.NodeInstanceStatus; +import dev.flexmodel.flow.common.RuntimeContext; import java.util.Collections; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/UserTaskExecutor.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/UserTaskExecutor.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/UserTaskExecutor.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/executor/UserTaskExecutor.java index b05d5247..fec11096 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/UserTaskExecutor.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/UserTaskExecutor.java @@ -1,18 +1,18 @@ -package dev.flexmodel.domain.model.flow.executor; +package dev.flexmodel.flow.executor; import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstanceBO; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.exception.SuspendException; -import dev.flexmodel.domain.model.flow.shared.common.Constants; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.common.NodeInstanceStatus; -import dev.flexmodel.domain.model.flow.shared.common.RuntimeContext; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.flow.dto.bo.NodeInstanceBO; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.exception.SuspendException; +import dev.flexmodel.flow.common.Constants; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.NodeInstanceStatus; +import dev.flexmodel.flow.common.RuntimeContext; +import dev.flexmodel.flow.common.util.FlowModelUtil; +import dev.flexmodel.common.utils.JsonUtils; import java.text.MessageFormat; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/callactivity/AbstractCallActivityExecutor.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/callactivity/AbstractCallActivityExecutor.java similarity index 83% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/callactivity/AbstractCallActivityExecutor.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/executor/callactivity/AbstractCallActivityExecutor.java index 7e3f25ea..98003370 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/callactivity/AbstractCallActivityExecutor.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/callactivity/AbstractCallActivityExecutor.java @@ -1,22 +1,22 @@ -package dev.flexmodel.domain.model.flow.executor.callactivity; +package dev.flexmodel.flow.executor.callactivity; import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.InstanceData; -import dev.flexmodel.domain.model.flow.config.BusinessConfig; -import dev.flexmodel.domain.model.flow.dto.bo.DataTransferBO; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.executor.ElementExecutor; -import dev.flexmodel.domain.model.flow.processor.RuntimeProcessor; -import dev.flexmodel.domain.model.flow.repository.FlowDeploymentRepository; -import dev.flexmodel.domain.model.flow.service.NodeInstanceService; -import dev.flexmodel.domain.model.flow.shared.common.Constants; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.common.InstanceDataType; -import dev.flexmodel.domain.model.flow.shared.common.RuntimeContext; -import dev.flexmodel.domain.model.flow.shared.util.InstanceDataUtil; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.flow.config.BusinessConfig; +import dev.flexmodel.flow.dto.bo.DataTransferBO; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.executor.ElementExecutor; +import dev.flexmodel.flow.processor.RuntimeProcessor; +import dev.flexmodel.flow.repository.FlowDeploymentRepository; +import dev.flexmodel.flow.service.NodeInstanceService; +import dev.flexmodel.flow.common.Constants; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.InstanceDataType; +import dev.flexmodel.flow.common.RuntimeContext; +import dev.flexmodel.flow.common.util.InstanceDataUtil; +import dev.flexmodel.common.utils.JsonUtils; import java.time.LocalDateTime; import java.util.HashMap; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/callactivity/SyncSingleCallActivityExecutor.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/callactivity/SyncSingleCallActivityExecutor.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/callactivity/SyncSingleCallActivityExecutor.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/executor/callactivity/SyncSingleCallActivityExecutor.java index 5ff90d30..61f9271d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/executor/callactivity/SyncSingleCallActivityExecutor.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/executor/callactivity/SyncSingleCallActivityExecutor.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.executor.callactivity; +package dev.flexmodel.flow.executor.callactivity; -import dev.flexmodel.domain.model.flow.shared.common.*; +import dev.flexmodel.flow.common.*; import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -8,22 +8,21 @@ import dev.flexmodel.codegen.entity.FlowInstance; import dev.flexmodel.codegen.entity.FlowInstanceMapping; import dev.flexmodel.codegen.entity.NodeInstance; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstanceBO; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.dto.param.CommitTaskParam; -import dev.flexmodel.domain.model.flow.dto.param.RollbackTaskParam; -import dev.flexmodel.domain.model.flow.dto.param.StartProcessParam; -import dev.flexmodel.domain.model.flow.dto.result.CommitTaskResult; -import dev.flexmodel.domain.model.flow.dto.result.RollbackTaskResult; -import dev.flexmodel.domain.model.flow.dto.result.RuntimeResult; -import dev.flexmodel.domain.model.flow.dto.result.StartProcessResult; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.exception.SuspendException; -import dev.flexmodel.domain.model.flow.shared.common.*; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; -import dev.flexmodel.domain.model.flow.shared.util.InstanceDataUtil; -import dev.flexmodel.shared.utils.CollectionUtils; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.flow.dto.bo.NodeInstanceBO; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.dto.param.CommitTaskParam; +import dev.flexmodel.flow.dto.param.RollbackTaskParam; +import dev.flexmodel.flow.dto.param.StartProcessParam; +import dev.flexmodel.flow.dto.result.CommitTaskResult; +import dev.flexmodel.flow.dto.result.RollbackTaskResult; +import dev.flexmodel.flow.dto.result.RuntimeResult; +import dev.flexmodel.flow.dto.result.StartProcessResult; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.exception.SuspendException; +import dev.flexmodel.flow.common.util.FlowModelUtil; +import dev.flexmodel.flow.common.util.InstanceDataUtil; +import dev.flexmodel.common.utils.CollectionUtils; +import dev.flexmodel.common.utils.JsonUtils; import java.text.MessageFormat; import java.time.LocalDateTime; @@ -221,7 +220,7 @@ private RuntimeResult buildCallActivityFirstUserTaskRuntimeResult(String project runtimeResult.setFlowInstanceId(subFlowInstance.getFlowInstanceId()); runtimeResult.setStatus(subFlowInstance.getStatus()); - dev.flexmodel.domain.model.flow.dto.bo.NodeInstance nodeInstance = JsonUtils.getInstance().convertValue(nodeInstancePO, dev.flexmodel.domain.model.flow.dto.bo.NodeInstance.class); + dev.flexmodel.flow.dto.bo.NodeInstance nodeInstance = JsonUtils.getInstance().convertValue(nodeInstancePO, dev.flexmodel.flow.dto.bo.NodeInstance.class); nodeInstance.setCreateTime(null); nodeInstance.setModifyTime(null); nodeInstance.setKey(nodeInstancePO.getNodeKey()); diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/ElementPlugin.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/ElementPlugin.java similarity index 56% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/ElementPlugin.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/ElementPlugin.java index 41b8b358..d611a35e 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/ElementPlugin.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/ElementPlugin.java @@ -1,7 +1,7 @@ -package dev.flexmodel.domain.model.flow.plugin; +package dev.flexmodel.flow.plugin; -import dev.flexmodel.domain.model.flow.executor.ElementExecutor; -import dev.flexmodel.domain.model.flow.validator.ElementValidator; +import dev.flexmodel.flow.executor.ElementExecutor; +import dev.flexmodel.flow.validator.ElementValidator; public interface ElementPlugin extends Plugin { String ELEMENT_TYPE_PREFIX = "turbo.plugin.element_type."; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/ExpressionCalculatorPlugin.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/ExpressionCalculatorPlugin.java new file mode 100644 index 00000000..1b9718ec --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/ExpressionCalculatorPlugin.java @@ -0,0 +1,7 @@ +package dev.flexmodel.flow.plugin; + +import dev.flexmodel.flow.common.util.ExpressionCalculator; + +public interface ExpressionCalculatorPlugin extends Plugin { + ExpressionCalculator getExpressionCalculator(); +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/IdGeneratorPlugin.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/IdGeneratorPlugin.java new file mode 100644 index 00000000..69ec14f0 --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/IdGeneratorPlugin.java @@ -0,0 +1,7 @@ +package dev.flexmodel.flow.plugin; + +import dev.flexmodel.flow.common.util.IdGenerator; + +public interface IdGeneratorPlugin extends Plugin { + IdGenerator getIdGenerator(); +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/ListenerPlugin.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/ListenerPlugin.java similarity index 52% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/ListenerPlugin.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/ListenerPlugin.java index 722b6dfc..e516eac4 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/ListenerPlugin.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/ListenerPlugin.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.plugin; +package dev.flexmodel.flow.plugin; public interface ListenerPlugin extends Plugin { } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/Plugin.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/Plugin.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/Plugin.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/Plugin.java index 9b221371..e80c3a65 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/Plugin.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/Plugin.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.plugin; +package dev.flexmodel.flow.plugin; public interface Plugin { // turbo插件开关配置格式建议统一为turbo.plugin.support.${pluginName} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/manager/AbstractPluginManager.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/manager/AbstractPluginManager.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/manager/AbstractPluginManager.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/manager/AbstractPluginManager.java index f07ed3be..7764295a 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/manager/AbstractPluginManager.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/manager/AbstractPluginManager.java @@ -1,9 +1,8 @@ -package dev.flexmodel.domain.model.flow.plugin.manager; +package dev.flexmodel.flow.plugin.manager; -import dev.flexmodel.domain.model.flow.plugin.*; -import dev.flexmodel.domain.model.flow.plugin.*; -import dev.flexmodel.domain.model.flow.shared.common.PluginTypeEnum; -import dev.flexmodel.domain.model.flow.shared.util.SPIUtil; +import dev.flexmodel.flow.plugin.*; +import dev.flexmodel.flow.common.PluginTypeEnum; +import dev.flexmodel.flow.common.util.SPIUtil; import java.util.ArrayList; import java.util.HashMap; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/manager/BasePlugin.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/manager/BasePlugin.java similarity index 85% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/manager/BasePlugin.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/manager/BasePlugin.java index 9601f0a7..4ac3a32f 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/manager/BasePlugin.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/manager/BasePlugin.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.plugin.manager; +package dev.flexmodel.flow.plugin.manager; /** * 插件可选依赖的 BeanProvider,用于从 CDI 获取运行期对象。 diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/manager/CdiBeanProvider.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/manager/CdiBeanProvider.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/manager/CdiBeanProvider.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/manager/CdiBeanProvider.java index d38bbe1e..53cb1361 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/manager/CdiBeanProvider.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/manager/CdiBeanProvider.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.plugin.manager; +package dev.flexmodel.flow.plugin.manager; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Instance; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/manager/DefaultPluginManager.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/manager/DefaultPluginManager.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/manager/DefaultPluginManager.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/manager/DefaultPluginManager.java index 7db70d69..d3452d72 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/manager/DefaultPluginManager.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/manager/DefaultPluginManager.java @@ -1,11 +1,10 @@ -package dev.flexmodel.domain.model.flow.plugin.manager; +package dev.flexmodel.flow.plugin.manager; -import dev.flexmodel.domain.model.flow.plugin.*; +import dev.flexmodel.flow.plugin.*; import jakarta.enterprise.context.ApplicationScoped; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.plugin.*; -import dev.flexmodel.domain.model.flow.shared.common.PluginTypeEnum; +import dev.flexmodel.flow.common.PluginTypeEnum; import java.util.*; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/manager/PluginManager.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/manager/PluginManager.java similarity index 71% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/manager/PluginManager.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/manager/PluginManager.java index 1040acbe..70496155 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/plugin/manager/PluginManager.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/plugin/manager/PluginManager.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.plugin.manager; +package dev.flexmodel.flow.plugin.manager; -import dev.flexmodel.domain.model.flow.plugin.Plugin; +import dev.flexmodel.flow.plugin.Plugin; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/processor/DefinitionProcessor.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/processor/DefinitionProcessor.java similarity index 85% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/processor/DefinitionProcessor.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/processor/DefinitionProcessor.java index 2fe9fcc1..1818b0f0 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/processor/DefinitionProcessor.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/processor/DefinitionProcessor.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.processor; +package dev.flexmodel.flow.processor; -import dev.flexmodel.domain.model.flow.dto.result.*; +import dev.flexmodel.flow.dto.result.*; import jakarta.annotation.PostConstruct; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -8,28 +8,27 @@ import org.slf4j.LoggerFactory; import dev.flexmodel.codegen.entity.FlowDefinition; import dev.flexmodel.codegen.entity.FlowDeployment; -import dev.flexmodel.domain.model.flow.dto.param.CreateFlowParam; -import dev.flexmodel.domain.model.flow.dto.param.DeployFlowParam; -import dev.flexmodel.domain.model.flow.dto.param.GetFlowModuleParam; -import dev.flexmodel.domain.model.flow.dto.param.UpdateFlowParam; -import dev.flexmodel.domain.model.flow.dto.result.*; -import dev.flexmodel.domain.model.flow.exception.DefinitionException; -import dev.flexmodel.domain.model.flow.exception.ParamException; -import dev.flexmodel.domain.model.flow.exception.TurboException; -import dev.flexmodel.domain.model.flow.plugin.IdGeneratorPlugin; -import dev.flexmodel.domain.model.flow.plugin.manager.PluginManager; -import dev.flexmodel.domain.model.flow.repository.FlowDefinitionRepository; -import dev.flexmodel.domain.model.flow.repository.FlowDeploymentRepository; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.common.FlowDefinitionStatus; -import dev.flexmodel.domain.model.flow.shared.common.FlowDeploymentStatus; -import dev.flexmodel.domain.model.flow.shared.common.FlowModuleEnum; -import dev.flexmodel.domain.model.flow.shared.util.IdGenerator; -import dev.flexmodel.domain.model.flow.shared.util.StrongUuidGenerator; -import dev.flexmodel.domain.model.flow.validator.ModelValidator; -import dev.flexmodel.domain.model.flow.validator.ParamValidator; -import dev.flexmodel.shared.utils.JsonUtils; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.flow.dto.param.CreateFlowParam; +import dev.flexmodel.flow.dto.param.DeployFlowParam; +import dev.flexmodel.flow.dto.param.GetFlowModuleParam; +import dev.flexmodel.flow.dto.param.UpdateFlowParam; +import dev.flexmodel.flow.exception.DefinitionException; +import dev.flexmodel.flow.exception.ParamException; +import dev.flexmodel.flow.exception.TurboException; +import dev.flexmodel.flow.plugin.IdGeneratorPlugin; +import dev.flexmodel.flow.plugin.manager.PluginManager; +import dev.flexmodel.flow.repository.FlowDefinitionRepository; +import dev.flexmodel.flow.repository.FlowDeploymentRepository; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.FlowDefinitionStatus; +import dev.flexmodel.flow.common.FlowDeploymentStatus; +import dev.flexmodel.flow.common.FlowModuleEnum; +import dev.flexmodel.flow.common.util.IdGenerator; +import dev.flexmodel.flow.common.util.StrongUuidGenerator; +import dev.flexmodel.flow.validator.ModelValidator; +import dev.flexmodel.flow.validator.ParamValidator; +import dev.flexmodel.common.utils.JsonUtils; +import dev.flexmodel.common.utils.StringUtils; import java.time.LocalDateTime; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/processor/RuntimeProcessor.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/processor/RuntimeProcessor.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/processor/RuntimeProcessor.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/processor/RuntimeProcessor.java index e82b9e25..ae415fee 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/processor/RuntimeProcessor.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/processor/RuntimeProcessor.java @@ -1,7 +1,7 @@ -package dev.flexmodel.domain.model.flow.processor; +package dev.flexmodel.flow.processor; -import dev.flexmodel.domain.model.flow.dto.result.*; -import dev.flexmodel.domain.model.flow.shared.common.*; +import dev.flexmodel.flow.common.*; +import dev.flexmodel.flow.dto.result.*; import jakarta.inject.Inject; import jakarta.inject.Singleton; import org.slf4j.Logger; @@ -10,33 +10,31 @@ import dev.flexmodel.codegen.entity.FlowInstance; import dev.flexmodel.codegen.entity.FlowInstanceMapping; import dev.flexmodel.codegen.entity.NodeInstance; -import dev.flexmodel.domain.model.flow.dto.bo.ElementInstance; -import dev.flexmodel.domain.model.flow.dto.bo.FlowInfo; -import dev.flexmodel.domain.model.flow.dto.bo.FlowInstanceBO; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstanceBO; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.dto.param.CommitTaskParam; -import dev.flexmodel.domain.model.flow.dto.param.RollbackTaskParam; -import dev.flexmodel.domain.model.flow.dto.param.StartProcessParam; -import dev.flexmodel.domain.model.flow.dto.result.*; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.exception.ReentrantException; -import dev.flexmodel.domain.model.flow.exception.TurboException; -import dev.flexmodel.domain.model.flow.executor.FlowExecutor; -import dev.flexmodel.domain.model.flow.repository.FlowDeploymentRepository; -import dev.flexmodel.domain.model.flow.repository.FlowInstanceMappingRepository; -import dev.flexmodel.domain.model.flow.repository.FlowInstanceRepository; -import dev.flexmodel.domain.model.flow.repository.NodeInstanceRepository; -import dev.flexmodel.domain.model.flow.service.FlowInstanceService; -import dev.flexmodel.domain.model.flow.service.InstanceDataService; -import dev.flexmodel.domain.model.flow.service.NodeInstanceService; -import dev.flexmodel.domain.model.flow.shared.common.*; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; -import dev.flexmodel.domain.model.flow.shared.util.InstanceDataUtil; -import dev.flexmodel.domain.model.flow.validator.ParamValidator; -import dev.flexmodel.shared.utils.CollectionUtils; -import dev.flexmodel.shared.utils.JsonUtils; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.flow.dto.bo.ElementInstance; +import dev.flexmodel.flow.dto.bo.FlowInfo; +import dev.flexmodel.flow.dto.bo.FlowInstanceBO; +import dev.flexmodel.flow.dto.bo.NodeInstanceBO; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.dto.param.CommitTaskParam; +import dev.flexmodel.flow.dto.param.RollbackTaskParam; +import dev.flexmodel.flow.dto.param.StartProcessParam; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.exception.ReentrantException; +import dev.flexmodel.flow.exception.TurboException; +import dev.flexmodel.flow.executor.FlowExecutor; +import dev.flexmodel.flow.repository.FlowDeploymentRepository; +import dev.flexmodel.flow.repository.FlowInstanceMappingRepository; +import dev.flexmodel.flow.repository.FlowInstanceRepository; +import dev.flexmodel.flow.repository.NodeInstanceRepository; +import dev.flexmodel.flow.service.FlowInstanceService; +import dev.flexmodel.flow.service.InstanceDataService; +import dev.flexmodel.flow.service.NodeInstanceService; +import dev.flexmodel.flow.common.util.FlowModelUtil; +import dev.flexmodel.flow.common.util.InstanceDataUtil; +import dev.flexmodel.flow.validator.ParamValidator; +import dev.flexmodel.common.utils.CollectionUtils; +import dev.flexmodel.common.utils.JsonUtils; +import dev.flexmodel.common.utils.StringUtils; import java.util.*; @@ -285,7 +283,7 @@ public NodeInstanceListResult getHistoryUserTaskList(String projectId, String fl } String flowDeployId = historyNodeInstanceList.get(0).getFlowDeployId(); Map flowElementMap = getFlowElementMap(projectId, flowDeployId); - List userTaskList = historyListResult.getNodeInstanceList(); + List userTaskList = historyListResult.getNodeInstanceList(); for (NodeInstance nodeInstancePO : historyNodeInstanceList) { if (!isEffectiveNodeInstance(nodeInstancePO.getStatus())) { continue; @@ -306,7 +304,7 @@ public NodeInstanceListResult getHistoryUserTaskList(String projectId, String fl } //build effective userTask instance - dev.flexmodel.domain.model.flow.dto.bo.NodeInstance nodeInstance = JsonUtils.getInstance().convertValue(nodeInstancePO, dev.flexmodel.domain.model.flow.dto.bo.NodeInstance.class); + dev.flexmodel.flow.dto.bo.NodeInstance nodeInstance = JsonUtils.getInstance().convertValue(nodeInstancePO, dev.flexmodel.flow.dto.bo.NodeInstance.class); FlowElement flowElement = FlowModelUtil.getFlowElement(flowElementMap, nodeInstancePO.getNodeKey()); nodeInstance.setKey(flowElement.getKey()); nodeInstance.setName(FlowModelUtil.getElementName(flowElement)); @@ -438,7 +436,7 @@ public NodeInstanceResult getNodeInstance(String projectId, String flowInstanceI NodeInstance nodeInstancePO = nodeInstanceService.selectByNodeInstanceId(projectId, flowInstanceId, nodeInstanceId, effectiveForSubFlowInstance); String flowDeployId = nodeInstancePO.getFlowDeployId(); Map flowElementMap = getFlowElementMap(projectId, flowDeployId); - dev.flexmodel.domain.model.flow.dto.bo.NodeInstance nodeInstance = JsonUtils.getInstance().convertValue(nodeInstancePO, dev.flexmodel.domain.model.flow.dto.bo.NodeInstance.class); + dev.flexmodel.flow.dto.bo.NodeInstance nodeInstance = JsonUtils.getInstance().convertValue(nodeInstancePO, dev.flexmodel.flow.dto.bo.NodeInstance.class); FlowElement flowElement = FlowModelUtil.getFlowElement(flowElementMap, nodeInstancePO.getNodeKey()); nodeInstance.setKey(flowElement.getKey()); nodeInstance.setName(FlowModelUtil.getElementName(flowElement)); @@ -575,8 +573,8 @@ private RuntimeResult fillRuntimeResult(RuntimeResult runtimeResult, RuntimeCont return runtimeResult; } - private dev.flexmodel.domain.model.flow.dto.bo.NodeInstance buildActiveTaskInstance(NodeInstanceBO nodeInstanceBO, RuntimeContext runtimeContext) { - dev.flexmodel.domain.model.flow.dto.bo.NodeInstance activeNodeInstance = JsonUtils.getInstance().convertValue(nodeInstanceBO, dev.flexmodel.domain.model.flow.dto.bo.NodeInstance.class); + private dev.flexmodel.flow.dto.bo.NodeInstance buildActiveTaskInstance(NodeInstanceBO nodeInstanceBO, RuntimeContext runtimeContext) { + dev.flexmodel.flow.dto.bo.NodeInstance activeNodeInstance = JsonUtils.getInstance().convertValue(nodeInstanceBO, dev.flexmodel.flow.dto.bo.NodeInstance.class); activeNodeInstance.setKey(nodeInstanceBO.getNodeKey()); FlowElement flowElement = runtimeContext.getFlowElementMap().get(nodeInstanceBO.getNodeKey()); activeNodeInstance.setName(FlowModelUtil.getElementName(flowElement)); diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/FlowDefinitionFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowDefinitionFmRepository.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/FlowDefinitionFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowDefinitionFmRepository.java index 4b6a0cdd..14418a29 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/FlowDefinitionFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowDefinitionFmRepository.java @@ -1,8 +1,8 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.flow.repository; +import dev.flexmodel.common.AbstractRepository; import jakarta.enterprise.context.ApplicationScoped; import dev.flexmodel.codegen.entity.FlowDefinition; -import dev.flexmodel.domain.model.flow.repository.FlowDefinitionRepository; import dev.flexmodel.query.Predicate; import dev.flexmodel.session.Session; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/FlowDefinitionRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowDefinitionRepository.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/FlowDefinitionRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowDefinitionRepository.java index 55cb53f1..0cf21b0d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/FlowDefinitionRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowDefinitionRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.repository; +package dev.flexmodel.flow.repository; import dev.flexmodel.codegen.entity.FlowDefinition; import dev.flexmodel.query.Predicate; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/FlowDeploymentFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowDeploymentFmRepository.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/FlowDeploymentFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowDeploymentFmRepository.java index 057802a0..d9bcc592 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/FlowDeploymentFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowDeploymentFmRepository.java @@ -1,8 +1,8 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.flow.repository; +import dev.flexmodel.common.AbstractRepository; import jakarta.enterprise.context.ApplicationScoped; import dev.flexmodel.codegen.entity.FlowDeployment; -import dev.flexmodel.domain.model.flow.repository.FlowDeploymentRepository; import dev.flexmodel.query.Predicate; import dev.flexmodel.session.Session; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/FlowDeploymentRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowDeploymentRepository.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/FlowDeploymentRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowDeploymentRepository.java index c82e1afa..54ab52b1 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/FlowDeploymentRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowDeploymentRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.repository; +package dev.flexmodel.flow.repository; import dev.flexmodel.codegen.entity.FlowDeployment; import dev.flexmodel.query.Predicate; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/FlowInstanceFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowInstanceFmRepository.java similarity index 95% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/FlowInstanceFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowInstanceFmRepository.java index c8a1b059..a786ebc2 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/FlowInstanceFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowInstanceFmRepository.java @@ -1,8 +1,8 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.flow.repository; +import dev.flexmodel.common.AbstractRepository; import jakarta.enterprise.context.ApplicationScoped; import dev.flexmodel.codegen.entity.FlowInstance; -import dev.flexmodel.domain.model.flow.repository.FlowInstanceRepository; import dev.flexmodel.query.Predicate; import dev.flexmodel.session.Session; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/FlowInstanceMappingFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowInstanceMappingFmRepository.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/FlowInstanceMappingFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowInstanceMappingFmRepository.java index 67b179b4..e3023ada 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/FlowInstanceMappingFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowInstanceMappingFmRepository.java @@ -1,8 +1,8 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.flow.repository; +import dev.flexmodel.common.AbstractRepository; import jakarta.enterprise.context.ApplicationScoped; import dev.flexmodel.codegen.entity.FlowInstanceMapping; -import dev.flexmodel.domain.model.flow.repository.FlowInstanceMappingRepository; import dev.flexmodel.session.Session; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/FlowInstanceMappingRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowInstanceMappingRepository.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/FlowInstanceMappingRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowInstanceMappingRepository.java index 105a396d..f5d3a9e3 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/FlowInstanceMappingRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowInstanceMappingRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.repository; +package dev.flexmodel.flow.repository; import dev.flexmodel.codegen.entity.FlowInstanceMapping; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/FlowInstanceRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowInstanceRepository.java similarity index 92% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/FlowInstanceRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowInstanceRepository.java index e4e5425f..1b637b6c 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/FlowInstanceRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/FlowInstanceRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.repository; +package dev.flexmodel.flow.repository; import dev.flexmodel.codegen.entity.FlowInstance; import dev.flexmodel.query.Predicate; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/InstanceDataFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/InstanceDataFmRepository.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/InstanceDataFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/repository/InstanceDataFmRepository.java index 7c865dc4..0872d36b 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/InstanceDataFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/InstanceDataFmRepository.java @@ -1,9 +1,9 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.flow.repository; +import dev.flexmodel.common.AbstractRepository; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.InstanceData; -import dev.flexmodel.domain.model.flow.repository.InstanceDataRepository; import dev.flexmodel.session.Session; import static dev.flexmodel.query.Expressions.field; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/InstanceDataRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/InstanceDataRepository.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/InstanceDataRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/repository/InstanceDataRepository.java index 62340659..0d035e11 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/InstanceDataRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/InstanceDataRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.repository; +package dev.flexmodel.flow.repository; import dev.flexmodel.codegen.entity.InstanceData; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/NodeInstanceFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/NodeInstanceFmRepository.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/NodeInstanceFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/repository/NodeInstanceFmRepository.java index 5c1feef2..1b75b6d1 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/NodeInstanceFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/NodeInstanceFmRepository.java @@ -1,10 +1,10 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.flow.repository; +import dev.flexmodel.common.AbstractRepository; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.NodeInstance; -import dev.flexmodel.domain.model.flow.repository.NodeInstanceRepository; -import dev.flexmodel.domain.model.flow.shared.common.NodeInstanceStatus; +import dev.flexmodel.flow.common.NodeInstanceStatus; import dev.flexmodel.session.Session; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/NodeInstanceLogFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/NodeInstanceLogFmRepository.java similarity index 83% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/NodeInstanceLogFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/repository/NodeInstanceLogFmRepository.java index ab2dd48f..09e96caa 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/NodeInstanceLogFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/NodeInstanceLogFmRepository.java @@ -1,9 +1,8 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.flow.repository; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.NodeInstanceLog; -import dev.flexmodel.domain.model.flow.repository.NodeInstanceLogRepository; import dev.flexmodel.session.Session; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/NodeInstanceLogRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/NodeInstanceLogRepository.java similarity index 80% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/NodeInstanceLogRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/repository/NodeInstanceLogRepository.java index dcaa27a6..65b8601b 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/NodeInstanceLogRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/NodeInstanceLogRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.repository; +package dev.flexmodel.flow.repository; import dev.flexmodel.codegen.entity.NodeInstanceLog; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/NodeInstanceRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/NodeInstanceRepository.java similarity index 95% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/NodeInstanceRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/repository/NodeInstanceRepository.java index 05de5849..f65e3d5a 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/repository/NodeInstanceRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/repository/NodeInstanceRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.repository; +package dev.flexmodel.flow.repository; import dev.flexmodel.codegen.entity.NodeInstance; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/service/FlowDefinitionService.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/FlowDefinitionService.java new file mode 100644 index 00000000..707acbaa --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/FlowDefinitionService.java @@ -0,0 +1,125 @@ +package dev.flexmodel.flow.service; + +import dev.flexmodel.common.dto.PageDTO; +import dev.flexmodel.flow.dto.*; +import dev.flexmodel.flow.dto.param.*; +import dev.flexmodel.flow.dto.result.*; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import dev.flexmodel.codegen.entity.FlowDefinition; +import dev.flexmodel.codegen.entity.FlowDeployment; +import dev.flexmodel.flow.repository.FlowDefinitionRepository; +import dev.flexmodel.flow.common.FlowDeploymentStatus; +import dev.flexmodel.query.Expressions; +import dev.flexmodel.query.Predicate; +import dev.flexmodel.common.utils.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * 流程定义服务 + * + * @author cjbi + */ +@Slf4j +@ApplicationScoped +public class FlowDefinitionService { + + @Inject + FlowDefinitionRepository flowDefinitionRepository; + + @Inject + ProcessService processService; + + @Inject + FlowDeploymentService flowDeploymentService; + + public List find(String projectId, Predicate filter, Integer page, Integer size) { + return flowDefinitionRepository.find(projectId, filter, page, size); + } + + public long count(String projectId, Predicate filter) { + return flowDefinitionRepository.count(projectId, filter); + } + + /** + * 获取流程模块列表 + */ + public PageDTO findFlowModuleList(FlowModuleListRequest request) { + log.info("获取流程模块列表,参数: {}", request); + Predicate predicate = Expressions.field(FlowDefinition::getIsDeleted).eq(false); + if (StringUtils.isNotBlank(request.getFlowModuleId())) { + predicate = predicate.and(Expressions.field(FlowDefinition::getFlowModuleId).eq(request.getFlowModuleId())); + } + if (StringUtils.isNotBlank(request.getFlowKey())) { + predicate = predicate.and(Expressions.field(FlowDefinition::getFlowKey).eq(request.getFlowKey())); + } + if (StringUtils.isNotBlank(request.getFlowName())) { + predicate = predicate.and(Expressions.field(FlowDefinition::getFlowName).contains(request.getFlowName())); + } + long count = count(request.getProjectId(), predicate); + if (count == 0) { + return PageDTO.empty(); + } + + List list = find(request.getProjectId(), predicate, request.getPage(), request.getSize()); + List flowModuleList = new ArrayList<>(); + for (FlowDefinition entity : list) { + FlowModuleResponse response = new FlowModuleResponse(entity); + long deploymentCount = flowDeploymentService.count(request.getProjectId(), Expressions.field( + FlowDeployment::getFlowModuleId).eq(entity.getFlowModuleId()) + .and(Expressions.field(FlowDeployment::getStatus).eq(FlowDeploymentStatus.DEPLOYED)) + ); + if (deploymentCount >= 1) { + //4 已发布 + response.setStatus(FlowModuleStatusEnum.PUBLISHED.getValue()); + } + flowModuleList.add(response); + } + return new PageDTO<>(flowModuleList, count); + } + + /** + * 创建流程 + */ + public CreateFlowResult createFlow(CreateFlowParam createFlowParam) { + log.info("创建流程: {}", createFlowParam.getFlowName()); + return processService.createFlow(createFlowParam); + } + + /** + * 部署流程 + */ + public DeployFlowResult deployFlow(DeployFlowParam deployFlowParam) { + log.info("部署流程,流程模块ID: {}", deployFlowParam.getFlowModuleId()); + return processService.deployFlow(deployFlowParam); + } + + /** + * 更新流程 + */ + public UpdateFlowResult updateFlow(UpdateFlowParam updateFlowParam) { + log.info("更新流程,流程模块ID: {}", updateFlowParam.getFlowModuleId()); + return processService.updateFlow(updateFlowParam); + } + + /** + * 删除流程 + */ + public void deleteFlow(String projectId, String flowModuleId) { + log.info("删除流程,流程模块ID: {}", flowModuleId); + processService.deleteFlow(projectId, flowModuleId); + } + + /** + * 获取流程模块信息 + */ + public FlowModuleResult getFlowModule(GetFlowModuleParam getFlowModuleParam) { + log.info("获取流程模块信息,流程模块ID: {}, 流程部署ID: {}", + getFlowModuleParam.getFlowModuleId(), getFlowModuleParam.getFlowDeployId()); + return processService.getFlowModule(getFlowModuleParam); + } + +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/FlowDeploymentService.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/FlowDeploymentService.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/FlowDeploymentService.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/service/FlowDeploymentService.java index 8f383b49..70b56875 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/FlowDeploymentService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/FlowDeploymentService.java @@ -1,9 +1,9 @@ -package dev.flexmodel.domain.model.flow.service; +package dev.flexmodel.flow.service; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.FlowDeployment; -import dev.flexmodel.domain.model.flow.repository.FlowDeploymentRepository; +import dev.flexmodel.flow.repository.FlowDeploymentRepository; import dev.flexmodel.query.Expressions; import dev.flexmodel.query.Predicate; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/flow/service/FlowExecutionService.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/FlowExecutionService.java new file mode 100644 index 00000000..031d275e --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/FlowExecutionService.java @@ -0,0 +1,74 @@ +package dev.flexmodel.flow.service; + +import dev.flexmodel.flow.dto.bo.ElementInstance; +import dev.flexmodel.flow.dto.bo.NodeInstance; +import dev.flexmodel.flow.dto.param.*; +import dev.flexmodel.flow.dto.result.*; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 流程执行服务 + * + * @author cjbi + */ +@Slf4j +@ApplicationScoped +public class FlowExecutionService { + + @Inject + ProcessService processService; + + /** + * 启动流程实例 + */ + public StartProcessResult startProcess(StartProcessParam startProcessParam) { + log.info("启动流程实例,流程模块ID: {}, 流程部署ID: {}", + startProcessParam.getFlowModuleId(), startProcessParam.getFlowDeployId()); + return processService.startProcess(startProcessParam); + } + + /** + * 提交任务 + */ + public CommitTaskResult commitTask(CommitTaskParam commitTaskParam) { + log.info("提交任务,流程实例ID: {}, 任务实例ID: {}", + commitTaskParam.getFlowInstanceId(), commitTaskParam.getTaskInstanceId()); + return processService.commitTask(commitTaskParam); + } + + /** + * 回滚任务 + */ + public RollbackTaskResult rollbackTask(RollbackTaskParam rollbackTaskParam) { + log.info("回滚任务,流程实例ID: {}, 任务实例ID: {}", + rollbackTaskParam.getFlowInstanceId(), rollbackTaskParam.getTaskInstanceId()); + return processService.rollbackTask(rollbackTaskParam); + } + + /** + * 获取流程实例历史用户任务列表 + */ + public List getHistoryUserTaskList(String projectId, String flowInstanceId, boolean effectiveForSubFlowInstance) { + return processService.getHistoryUserTaskList(projectId, flowInstanceId, effectiveForSubFlowInstance).getNodeInstanceList(); + } + + /** + * 获取流程实例历史元素列表 + */ + public List getHistoryElementList(String projectId, String flowInstanceId) { + return processService.getHistoryElementList(projectId, flowInstanceId).getElementInstanceList(); + } + + /** + * 获取流程实例元素实例数据 + */ + public InstanceDataListResult getInstanceData(String projectId, String flowInstanceId, String instanceDataId) { + log.info("获取元素实例数据,流程实例ID: {}, 实例数据ID: {}", flowInstanceId, instanceDataId); + return processService.getInstanceData(projectId, flowInstanceId, instanceDataId); + } + +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/FlowInstanceService.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/FlowInstanceService.java similarity index 75% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/FlowInstanceService.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/service/FlowInstanceService.java index 584e3c4c..eabdd6b3 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/FlowInstanceService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/FlowInstanceService.java @@ -1,31 +1,43 @@ -package dev.flexmodel.domain.model.flow.service; +package dev.flexmodel.flow.service; +import dev.flexmodel.common.dto.PageDTO; +import dev.flexmodel.flow.dto.FlowInstanceListRequest; +import dev.flexmodel.flow.dto.FlowInstanceResponse; +import dev.flexmodel.flow.dto.result.*; +import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import dev.flexmodel.codegen.entity.FlowDeployment; import dev.flexmodel.codegen.entity.FlowInstance; import dev.flexmodel.codegen.entity.FlowInstanceMapping; import dev.flexmodel.codegen.entity.NodeInstance; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.repository.FlowDeploymentRepository; -import dev.flexmodel.domain.model.flow.repository.FlowInstanceMappingRepository; -import dev.flexmodel.domain.model.flow.repository.FlowInstanceRepository; -import dev.flexmodel.domain.model.flow.repository.NodeInstanceRepository; -import dev.flexmodel.domain.model.flow.shared.common.FlowElementType; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.repository.FlowDeploymentRepository; +import dev.flexmodel.flow.repository.FlowInstanceMappingRepository; +import dev.flexmodel.flow.repository.FlowInstanceRepository; +import dev.flexmodel.flow.repository.NodeInstanceRepository; +import dev.flexmodel.flow.common.FlowElementType; +import dev.flexmodel.flow.common.util.FlowModelUtil; +import dev.flexmodel.query.Expressions; import dev.flexmodel.query.Predicate; -import dev.flexmodel.shared.utils.CollectionUtils; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.common.utils.CollectionUtils; +import dev.flexmodel.common.utils.JsonUtils; +import dev.flexmodel.common.utils.StringUtils; import java.util.*; -@Singleton +@ApplicationScoped public class FlowInstanceService { protected static final Logger LOGGER = LoggerFactory.getLogger(FlowInstanceService.class); + @Inject + ProcessService processService; + + @Inject + FlowDeploymentService flowDeploymentService; + @Inject NodeInstanceRepository nodeInstanceRepository; @@ -201,6 +213,63 @@ public FlowInstance findById(String projectId, String flowInstanceId) { return flowInstanceRepository.selectByFlowInstanceId(projectId, flowInstanceId); } + /** + * 获取流程实例列表 + */ + public PageDTO findFlowInstanceList(FlowInstanceListRequest request) { + LOGGER.info("获取流程实例列表,参数: {}", request); + Predicate predicate = Expressions.TRUE; + if (StringUtils.isNotBlank(request.getFlowInstanceId())) { + predicate = predicate.and(Expressions.field(FlowInstance::getFlowInstanceId).eq(request.getFlowInstanceId())); + } + if (StringUtils.isNotBlank(request.getFlowModuleId())) { + predicate = predicate.and(Expressions.field(FlowInstance::getFlowModuleId).eq(request.getFlowModuleId())); + } + if (StringUtils.isNotBlank(request.getFlowDeployId())) { + predicate = predicate.and(Expressions.field(FlowInstance::getFlowDeployId).eq(request.getFlowDeployId())); + } + if (request.getStatus() != null) { + predicate = predicate.and(Expressions.field(FlowInstance::getStatus).eq(request.getStatus())); + } + long count = count(request.getProjectId(), predicate); + if (count == 0) { + return PageDTO.empty(); + } + List list = find(request.getProjectId(), predicate, request.getPage(), request.getSize()).stream() + .map(entity -> { + FlowInstanceResponse response = JsonUtils.getInstance().convertValue(entity, FlowInstanceResponse.class); + FlowDeployment flowDeployment = flowDeploymentService.findByFlowDeployId(request.getProjectId(), entity.getFlowDeployId()); + if (flowDeployment != null) { + response.setFlowName(flowDeployment.getFlowName()); + response.setFlowKey(flowDeployment.getFlowKey()); + } + return response; + }).toList(); + return new PageDTO<>(list, count); + } + + /** + * 获取流程实例信息 + */ + public FlowInstance findFlowInstance(String projectId, String flowInstanceId) { + LOGGER.info("获取流程实例信息: {}", flowInstanceId); + if (StringUtils.isBlank(flowInstanceId)) { + throw new IllegalArgumentException("流程实例ID不能为空"); + } + return findById(projectId, flowInstanceId); + } + + /** + * 终止流程实例 + */ + public TerminateResult terminateProcess(String projectId, String flowInstanceId, boolean effectiveForSubFlowInstance) { + LOGGER.info("终止流程实例: {}, 对子流程实例生效: {}", flowInstanceId, effectiveForSubFlowInstance); + if (StringUtils.isBlank(flowInstanceId)) { + throw new IllegalArgumentException("流程实例ID不能为空"); + } + return processService.terminateProcess(projectId, flowInstanceId, effectiveForSubFlowInstance); + } + private static class FlowInstancePOJO { private String id; private NodeInstancePOJO belongNodeInstance; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/InstanceDataService.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/InstanceDataService.java similarity index 87% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/InstanceDataService.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/service/InstanceDataService.java index 2b9d50b1..9626c161 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/InstanceDataService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/InstanceDataService.java @@ -1,13 +1,12 @@ -package dev.flexmodel.domain.model.flow.service; +package dev.flexmodel.flow.service; -import dev.flexmodel.domain.model.flow.repository.*; +import dev.flexmodel.flow.repository.*; import jakarta.inject.Inject; import jakarta.inject.Singleton; import dev.flexmodel.codegen.entity.*; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.repository.*; -import dev.flexmodel.domain.model.flow.shared.common.FlowElementType; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.common.FlowElementType; +import dev.flexmodel.flow.common.util.FlowModelUtil; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/NodeInstanceService.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/NodeInstanceService.java similarity index 81% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/NodeInstanceService.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/service/NodeInstanceService.java index e57653a1..9de330d6 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/NodeInstanceService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/NodeInstanceService.java @@ -1,16 +1,16 @@ -package dev.flexmodel.domain.model.flow.service; +package dev.flexmodel.flow.service; import jakarta.inject.Inject; import jakarta.inject.Singleton; import dev.flexmodel.codegen.entity.FlowDeployment; import dev.flexmodel.codegen.entity.FlowInstance; import dev.flexmodel.codegen.entity.NodeInstance; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.repository.FlowDeploymentRepository; -import dev.flexmodel.domain.model.flow.repository.FlowInstanceRepository; -import dev.flexmodel.domain.model.flow.repository.NodeInstanceRepository; -import dev.flexmodel.domain.model.flow.shared.common.FlowElementType; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.repository.FlowDeploymentRepository; +import dev.flexmodel.flow.repository.FlowInstanceRepository; +import dev.flexmodel.flow.repository.NodeInstanceRepository; +import dev.flexmodel.flow.common.FlowElementType; +import dev.flexmodel.flow.common.util.FlowModelUtil; import java.util.List; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/ProcessEngineImpl.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/ProcessEngineImpl.java similarity index 92% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/ProcessEngineImpl.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/service/ProcessEngineImpl.java index 4f18b8fb..ef3d98e2 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/ProcessEngineImpl.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/ProcessEngineImpl.java @@ -1,14 +1,14 @@ -package dev.flexmodel.domain.model.flow.service; +package dev.flexmodel.flow.service; -import dev.flexmodel.domain.model.flow.dto.param.*; -import dev.flexmodel.domain.model.flow.dto.result.*; -import dev.flexmodel.shared.SessionContextHolder; +import dev.flexmodel.flow.dto.param.*; +import dev.flexmodel.flow.dto.param.*; +import dev.flexmodel.flow.dto.result.*; +import dev.flexmodel.common.SessionContextHolder; import jakarta.inject.Inject; import jakarta.inject.Singleton; -import dev.flexmodel.domain.model.flow.dto.param.*; -import dev.flexmodel.domain.model.flow.dto.result.*; -import dev.flexmodel.domain.model.flow.processor.DefinitionProcessor; -import dev.flexmodel.domain.model.flow.processor.RuntimeProcessor; +import dev.flexmodel.flow.dto.result.*; +import dev.flexmodel.flow.processor.DefinitionProcessor; +import dev.flexmodel.flow.processor.RuntimeProcessor; @Singleton public class ProcessEngineImpl implements ProcessService { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/ProcessService.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/ProcessService.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/ProcessService.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/service/ProcessService.java index cdc7ade8..f0527124 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/service/ProcessService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/service/ProcessService.java @@ -1,17 +1,17 @@ -package dev.flexmodel.domain.model.flow.service; +package dev.flexmodel.flow.service; -import dev.flexmodel.domain.model.flow.dto.param.*; -import dev.flexmodel.domain.model.flow.dto.result.*; import dev.flexmodel.codegen.entity.FlowDeployment; import dev.flexmodel.codegen.entity.FlowInstance; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstance; -import dev.flexmodel.domain.model.flow.dto.model.EndEvent; -import dev.flexmodel.domain.model.flow.dto.model.FlowModel; -import dev.flexmodel.domain.model.flow.dto.model.StartEvent; -import dev.flexmodel.domain.model.flow.dto.model.UserTask; -import dev.flexmodel.domain.model.flow.dto.param.*; -import dev.flexmodel.domain.model.flow.dto.result.*; +import dev.flexmodel.flow.dto.bo.NodeInstance; +import dev.flexmodel.flow.dto.model.EndEvent; +import dev.flexmodel.flow.dto.model.FlowModel; +import dev.flexmodel.flow.dto.model.StartEvent; +import dev.flexmodel.flow.dto.model.UserTask; +import dev.flexmodel.flow.dto.param.*; +import dev.flexmodel.flow.dto.result.*; +import dev.flexmodel.flow.dto.param.*; +import dev.flexmodel.flow.dto.result.*; /** * The entrance of Turbo diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/spi/HookService.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/spi/HookService.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/spi/HookService.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/spi/HookService.java index ec0fc0ef..d6eadc34 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/spi/HookService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/spi/HookService.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.spi; +package dev.flexmodel.flow.spi; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/CallActivityValidator.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/CallActivityValidator.java similarity index 83% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/CallActivityValidator.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/validator/CallActivityValidator.java index a6f532fd..9d33d135 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/CallActivityValidator.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/CallActivityValidator.java @@ -1,26 +1,26 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import jakarta.inject.Inject; import jakarta.inject.Singleton; import dev.flexmodel.codegen.entity.FlowDefinition; -import dev.flexmodel.domain.model.flow.config.BusinessConfig; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.dto.model.FlowModel; -import dev.flexmodel.domain.model.flow.dto.param.CommonParam; -import dev.flexmodel.domain.model.flow.exception.DefinitionException; -import dev.flexmodel.domain.model.flow.repository.FlowDefinitionRepository; -import dev.flexmodel.domain.model.flow.shared.common.Constants; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.common.FlowElementType; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; +import dev.flexmodel.flow.config.BusinessConfig; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.dto.model.FlowModel; +import dev.flexmodel.flow.dto.param.CommonParam; +import dev.flexmodel.flow.exception.DefinitionException; +import dev.flexmodel.flow.repository.FlowDefinitionRepository; +import dev.flexmodel.flow.common.Constants; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.FlowElementType; +import dev.flexmodel.flow.common.util.FlowModelUtil; import java.util.*; -import static dev.flexmodel.domain.model.flow.shared.common.Constants.CALL_ACTIVITY_EXECUTE_TYPE.ASYNC; -import static dev.flexmodel.domain.model.flow.shared.common.Constants.CALL_ACTIVITY_EXECUTE_TYPE.SYNC; -import static dev.flexmodel.domain.model.flow.shared.common.Constants.CALL_ACTIVITY_INSTANCE_TYPE.MULTIPLE; -import static dev.flexmodel.domain.model.flow.shared.common.Constants.CALL_ACTIVITY_INSTANCE_TYPE.SINGLE; -import static dev.flexmodel.domain.model.flow.shared.common.Constants.ELEMENT_PROPERTIES.*; +import static dev.flexmodel.flow.common.Constants.CALL_ACTIVITY_EXECUTE_TYPE.ASYNC; +import static dev.flexmodel.flow.common.Constants.CALL_ACTIVITY_EXECUTE_TYPE.SYNC; +import static dev.flexmodel.flow.common.Constants.CALL_ACTIVITY_INSTANCE_TYPE.MULTIPLE; +import static dev.flexmodel.flow.common.Constants.CALL_ACTIVITY_INSTANCE_TYPE.SINGLE; +import static dev.flexmodel.flow.common.Constants.ELEMENT_PROPERTIES.*; @Singleton public class CallActivityValidator extends ElementValidator { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ElementValidator.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ElementValidator.java similarity index 80% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ElementValidator.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ElementValidator.java index 1261429b..1399229d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ElementValidator.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ElementValidator.java @@ -1,14 +1,14 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.dto.param.CommonParam; -import dev.flexmodel.domain.model.flow.exception.DefinitionException; -import dev.flexmodel.domain.model.flow.shared.common.Constants; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; -import dev.flexmodel.shared.utils.CollectionUtils; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.dto.param.CommonParam; +import dev.flexmodel.flow.exception.DefinitionException; +import dev.flexmodel.flow.common.Constants; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.util.FlowModelUtil; +import dev.flexmodel.common.utils.CollectionUtils; import java.text.MessageFormat; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ElementValidatorFactory.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ElementValidatorFactory.java similarity index 81% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ElementValidatorFactory.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ElementValidatorFactory.java index 16b34c8f..9adebcbc 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ElementValidatorFactory.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ElementValidatorFactory.java @@ -1,18 +1,18 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import jakarta.annotation.PostConstruct; import jakarta.inject.Inject; import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.plugin.ElementPlugin; -import dev.flexmodel.domain.model.flow.plugin.manager.PluginManager; -import dev.flexmodel.domain.model.flow.shared.common.Constants; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.common.FlowElementType; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.plugin.ElementPlugin; +import dev.flexmodel.flow.plugin.manager.PluginManager; +import dev.flexmodel.flow.common.Constants; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.FlowElementType; +import dev.flexmodel.flow.common.util.FlowModelUtil; import java.text.MessageFormat; import java.util.HashMap; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/EndEventValidator.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/EndEventValidator.java similarity index 76% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/EndEventValidator.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/validator/EndEventValidator.java index 6dc2757f..479b5f58 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/EndEventValidator.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/EndEventValidator.java @@ -1,11 +1,11 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.shared.utils.CollectionUtils; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.common.utils.CollectionUtils; import java.util.List; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ExclusiveGatewayValidator.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ExclusiveGatewayValidator.java similarity index 77% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ExclusiveGatewayValidator.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ExclusiveGatewayValidator.java index b8d690a3..f4842db7 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ExclusiveGatewayValidator.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ExclusiveGatewayValidator.java @@ -1,14 +1,14 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.DefinitionException; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; -import dev.flexmodel.shared.utils.CollectionUtils; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.DefinitionException; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.util.FlowModelUtil; +import dev.flexmodel.common.utils.CollectionUtils; +import dev.flexmodel.common.utils.StringUtils; import java.util.List; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/FlowModelValidator.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/FlowModelValidator.java similarity index 78% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/FlowModelValidator.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/validator/FlowModelValidator.java index 29cc39b4..b6b182d4 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/FlowModelValidator.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/FlowModelValidator.java @@ -1,19 +1,19 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import jakarta.inject.Inject; import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.dto.model.FlowModel; -import dev.flexmodel.domain.model.flow.dto.param.CommonParam; -import dev.flexmodel.domain.model.flow.exception.DefinitionException; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.shared.common.Constants; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.common.FlowElementType; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; -import dev.flexmodel.shared.utils.CollectionUtils; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.dto.model.FlowModel; +import dev.flexmodel.flow.dto.param.CommonParam; +import dev.flexmodel.flow.exception.DefinitionException; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.common.Constants; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.FlowElementType; +import dev.flexmodel.flow.common.util.FlowModelUtil; +import dev.flexmodel.common.utils.CollectionUtils; import java.text.MessageFormat; import java.util.HashMap; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ModelValidator.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ModelValidator.java similarity index 67% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ModelValidator.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ModelValidator.java index 96397c14..d1556cf3 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ModelValidator.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ModelValidator.java @@ -1,17 +1,17 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import jakarta.inject.Inject; import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.dto.model.FlowModel; -import dev.flexmodel.domain.model.flow.dto.param.CommonParam; -import dev.flexmodel.domain.model.flow.exception.DefinitionException; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; -import dev.flexmodel.shared.utils.CollectionUtils; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.flow.dto.model.FlowModel; +import dev.flexmodel.flow.dto.param.CommonParam; +import dev.flexmodel.flow.exception.DefinitionException; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.util.FlowModelUtil; +import dev.flexmodel.common.utils.CollectionUtils; +import dev.flexmodel.common.utils.StringUtils; @Singleton public class ModelValidator { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ParamValidator.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ParamValidator.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ParamValidator.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ParamValidator.java index ca7bd4b8..fd4175f8 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ParamValidator.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ParamValidator.java @@ -1,10 +1,9 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; -import dev.flexmodel.domain.model.flow.dto.param.*; -import dev.flexmodel.domain.model.flow.dto.param.*; -import dev.flexmodel.domain.model.flow.exception.ParamException; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.flow.dto.param.*; +import dev.flexmodel.flow.exception.ParamException; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.common.utils.StringUtils; public class ParamValidator { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/SequenceFlowValidator.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/SequenceFlowValidator.java similarity index 78% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/SequenceFlowValidator.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/validator/SequenceFlowValidator.java index 44f52d71..28a00d2e 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/SequenceFlowValidator.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/SequenceFlowValidator.java @@ -1,9 +1,9 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import jakarta.inject.Singleton; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.DefinitionException; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.DefinitionException; +import dev.flexmodel.flow.common.ErrorEnum; import java.util.List; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ServiceTaskValidator.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ServiceTaskValidator.java similarity index 68% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ServiceTaskValidator.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ServiceTaskValidator.java index f0e38230..3778110d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/ServiceTaskValidator.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/ServiceTaskValidator.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import jakarta.inject.Singleton; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/StartEventValidator.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/StartEventValidator.java similarity index 73% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/StartEventValidator.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/validator/StartEventValidator.java index 7121713e..c2d21390 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/StartEventValidator.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/StartEventValidator.java @@ -1,11 +1,11 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.shared.utils.CollectionUtils; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.common.utils.CollectionUtils; import java.util.List; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/UserTaskValidator.java b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/UserTaskValidator.java similarity index 67% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/UserTaskValidator.java rename to flexmodel-server/src/main/java/dev/flexmodel/flow/validator/UserTaskValidator.java index 34b1dd4e..fc0c18af 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/flow/validator/UserTaskValidator.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/flow/validator/UserTaskValidator.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import jakarta.inject.Singleton; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/IdentityProviderFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/idp/IdentityProviderFmRepository.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/IdentityProviderFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/idp/IdentityProviderFmRepository.java index 33212769..f84fd81a 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/IdentityProviderFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/idp/IdentityProviderFmRepository.java @@ -1,9 +1,8 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.idp; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.IdentityProvider; -import dev.flexmodel.domain.model.idp.IdentityProviderRepository; import dev.flexmodel.session.Session; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/IdentityProviderRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/idp/IdentityProviderRepository.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/IdentityProviderRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/idp/IdentityProviderRepository.java index f93b7338..09190c08 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/IdentityProviderRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/idp/IdentityProviderRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.idp; +package dev.flexmodel.idp; import dev.flexmodel.codegen.entity.IdentityProvider; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/IdentityProviderResource.java b/flexmodel-server/src/main/java/dev/flexmodel/idp/IdentityProviderResource.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/IdentityProviderResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/idp/IdentityProviderResource.java index fd31b9d4..44232f41 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/IdentityProviderResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/idp/IdentityProviderResource.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.idp; import jakarta.inject.Inject; import jakarta.ws.rs.*; @@ -13,7 +13,6 @@ import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.IdentityProviderApplicationService; import dev.flexmodel.codegen.entity.IdentityProvider; import java.util.List; @@ -28,7 +27,7 @@ public class IdentityProviderResource { @Inject - IdentityProviderApplicationService identityProviderApplicationService; + IdentityProviderService identityProviderService; @APIResponse( name = "200", @@ -45,7 +44,7 @@ public class IdentityProviderResource { @Operation(summary = "获取身份源列表") @GET public List findProviders(@PathParam("projectId") String projectId) { - return identityProviderApplicationService.findAll(projectId); + return identityProviderService.findAll(projectId); } @RequestBody( @@ -71,7 +70,7 @@ public List findProviders(@PathParam("projectId") String proje @Operation(summary = "创建身份源") @POST public IdentityProvider createProvider(@PathParam("projectId") String projectId, IdentityProvider identityProvider) { - return identityProviderApplicationService.createProvider(projectId, identityProvider); + return identityProviderService.createProvider(projectId, identityProvider); } @RequestBody( @@ -99,7 +98,7 @@ public IdentityProvider createProvider(@PathParam("projectId") String projectId, @PUT @Path("/{name}") public IdentityProvider updateProvider(@PathParam("projectId") String projectId, @PathParam("name") String name, IdentityProvider identityProvider) { - return identityProviderApplicationService.updateProvider(projectId, identityProvider); + return identityProviderService.updateProvider(projectId, identityProvider); } @Parameter(name = "name", description = "名称", in = ParameterIn.PATH) @@ -107,7 +106,7 @@ public IdentityProvider updateProvider(@PathParam("projectId") String projectId, @DELETE @Path("/{name}") public void deleteProvider(@PathParam("projectId") String projectId, @PathParam("name") String name) { - identityProviderApplicationService.deleteProvider(projectId, name); + identityProviderService.deleteProvider(projectId, name); } @Schema( diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/IdentityProviderService.java b/flexmodel-server/src/main/java/dev/flexmodel/idp/IdentityProviderService.java similarity index 69% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/IdentityProviderService.java rename to flexmodel-server/src/main/java/dev/flexmodel/idp/IdentityProviderService.java index 77e9b5cf..6e50dbbc 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/IdentityProviderService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/idp/IdentityProviderService.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.idp; +package dev.flexmodel.idp; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -22,11 +22,25 @@ public List findAll() { return identityProviderRepository.findAll(); } - public IdentityProvider create(IdentityProvider identityProvider) { + public void delete(String id) { + identityProviderRepository.delete(id); + } + + + public IdentityProvider find(String providerName) { + return identityProviderRepository.find(providerName); + } + + + public List findAll(String projectId) { + return identityProviderRepository.findAll(); + } + + public IdentityProvider createProvider(String projectId, IdentityProvider identityProvider) { return identityProviderRepository.save(identityProvider); } - public IdentityProvider update(IdentityProvider identityProvider) { + public IdentityProvider updateProvider(String projectId, IdentityProvider identityProvider) { IdentityProvider older = identityProviderRepository.find(identityProvider.getName()); if (older == null) { return identityProvider; @@ -35,12 +49,8 @@ public IdentityProvider update(IdentityProvider identityProvider) { return identityProviderRepository.save(identityProvider); } - public void delete(String id) { + public void deleteProvider(String id, String name) { identityProviderRepository.delete(id); } - - public IdentityProvider find(String providerName) { - return identityProviderRepository.find(providerName); - } } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/provider/OIDCProvider.java b/flexmodel-server/src/main/java/dev/flexmodel/idp/provider/OIDCProvider.java similarity index 97% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/provider/OIDCProvider.java rename to flexmodel-server/src/main/java/dev/flexmodel/idp/provider/OIDCProvider.java index f00066cb..623f9351 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/provider/OIDCProvider.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/idp/provider/OIDCProvider.java @@ -1,10 +1,10 @@ -package dev.flexmodel.domain.model.idp.provider; +package dev.flexmodel.idp.provider; import com.cronutils.utils.StringUtils; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.common.utils.JsonUtils; import java.io.IOException; import java.net.URI; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/provider/Provider.java b/flexmodel-server/src/main/java/dev/flexmodel/idp/provider/Provider.java similarity index 74% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/provider/Provider.java rename to flexmodel-server/src/main/java/dev/flexmodel/idp/provider/Provider.java index 380a77aa..d358d078 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/provider/Provider.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/idp/provider/Provider.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.idp.provider; +package dev.flexmodel.idp.provider; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/provider/ScriptProvider.java b/flexmodel-server/src/main/java/dev/flexmodel/idp/provider/ScriptProvider.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/provider/ScriptProvider.java rename to flexmodel-server/src/main/java/dev/flexmodel/idp/provider/ScriptProvider.java index 0efac790..a6861795 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/provider/ScriptProvider.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/idp/provider/ScriptProvider.java @@ -1,12 +1,12 @@ -package dev.flexmodel.domain.model.idp.provider; +package dev.flexmodel.idp.provider; import dev.flexmodel.session.SessionFactory; import jakarta.enterprise.inject.spi.CDI; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.domain.model.flow.shared.util.JavaScriptUtil; -import dev.flexmodel.domain.model.flow.shared.util.RequestScriptContext; +import dev.flexmodel.flow.common.util.JavaScriptUtil; +import dev.flexmodel.flow.common.util.RequestScriptContext; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/provider/ValidateParam.java b/flexmodel-server/src/main/java/dev/flexmodel/idp/provider/ValidateParam.java similarity index 84% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/provider/ValidateParam.java rename to flexmodel-server/src/main/java/dev/flexmodel/idp/provider/ValidateParam.java index 259453c0..afb002bb 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/provider/ValidateParam.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/idp/provider/ValidateParam.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.idp.provider; +package dev.flexmodel.idp.provider; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/provider/ValidateResult.java b/flexmodel-server/src/main/java/dev/flexmodel/idp/provider/ValidateResult.java similarity index 85% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/provider/ValidateResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/idp/provider/ValidateResult.java index c9686490..c15d81be 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/idp/provider/ValidateResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/idp/provider/ValidateResult.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.idp.provider; +package dev.flexmodel.idp.provider; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ApiDefinitionFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ApiDefinitionFmRepository.java deleted file mode 100644 index 98ef51ca..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ApiDefinitionFmRepository.java +++ /dev/null @@ -1,81 +0,0 @@ -package dev.flexmodel.infrastructure.persistence; - -import jakarta.enterprise.context.ApplicationScoped; -import dev.flexmodel.codegen.entity.ApiDefinition; -import dev.flexmodel.domain.model.api.ApiDefinitionRepository; -import dev.flexmodel.session.Session; - -import java.util.List; - -import static dev.flexmodel.query.Expressions.field; - -@ApplicationScoped -public class ApiDefinitionFmRepository extends AbstractRepository implements ApiDefinitionRepository { - - @Override - public void deleteByParentId(String projectId, String parentId) { - try (Session session = getProjectSession(projectId)) { - session.dsl() - .deleteFrom(ApiDefinition.class) - .where(field(ApiDefinition::getProjectId).eq(projectId).and(field(ApiDefinition::getParentId).eq(parentId))) - .execute(); - } - } - - @Override - public ApiDefinition findById(String projectId, String id) { - try (Session session = getProjectSession(projectId)) { - return session.dsl() - .selectFrom(ApiDefinition.class) - .where(field(ApiDefinition::getProjectId).eq(projectId).and(field(ApiDefinition::getId).eq(id))) - .executeOne(); - } - } - - @Override - public List findAll(String projectId) { - try (Session session = getProjectSession(projectId)) { - return session.dsl() - .selectFrom(ApiDefinition.class) - .where(field(ApiDefinition::getProjectId).eq(projectId)) - .execute(); - } - } - - @Override - public List findByProjectId(String projectId) { - try (Session session = getProjectSession(projectId)) { - return session.dsl() - .selectFrom(ApiDefinition.class) - .where(field(ApiDefinition::getProjectId).eq(projectId)) - .execute(); - } - } - - @Override - public ApiDefinition save(ApiDefinition record) { - try (Session session = getProjectSession(record.getProjectId())) { - session.dsl().mergeInto(ApiDefinition.class).values(record).execute(); - } - return record; - } - - @Override - public void delete(String projectId, String id) { - try (Session session = getProjectSession(projectId)) { - session.dsl().deleteFrom(ApiDefinition.class) - .where(field(ApiDefinition::getProjectId).eq(projectId).and(field(ApiDefinition::getId).eq(id))) - .execute(); - } - } - - @Override - public Integer count(String projectId) { - try (Session session = getProjectSession(projectId)) { - return (int) session.dsl().selectFrom(ApiDefinition.class) - .where(field(ApiDefinition::getProjectId).eq(projectId)) - .count(); - } - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ApiDefinitionHistoryFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ApiDefinitionHistoryFmRepository.java deleted file mode 100644 index 3f6b1836..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ApiDefinitionHistoryFmRepository.java +++ /dev/null @@ -1,43 +0,0 @@ -package dev.flexmodel.infrastructure.persistence; - -import jakarta.enterprise.context.ApplicationScoped; -import dev.flexmodel.codegen.entity.ApiDefinitionHistory; -import dev.flexmodel.domain.model.api.ApiDefinitionHistoryRepository; -import dev.flexmodel.session.Session; - -import java.util.List; - -import static dev.flexmodel.query.Expressions.field; - -@ApplicationScoped -public class ApiDefinitionHistoryFmRepository extends AbstractRepository implements ApiDefinitionHistoryRepository { - - @Override - public List findByApiDefinitionId(String projectId, String apiDefinitionId) { - try (Session session = getProjectSession(projectId)) { - return session.dsl().selectFrom(ApiDefinitionHistory.class) - .where(field(ApiDefinitionHistory::getProjectId).eq(projectId).and(field(ApiDefinitionHistory::getApiDefinitionId).eq(apiDefinitionId))) - .orderByDesc(ApiDefinitionHistory::getCreatedAt) - .execute(); - } - } - - @Override - public ApiDefinitionHistory save(String projectId, ApiDefinitionHistory apiDefinitionHistory) { - try (Session session = getProjectSession(projectId)) { - session.dsl().insertInto(ApiDefinitionHistory.class) - .values(apiDefinitionHistory) - .execute(); - } - return apiDefinitionHistory; - } - - @Override - public ApiDefinitionHistory findById(String projectId, String historyId) { - try (Session session = getProjectSession(projectId)) { - return session.dsl().selectFrom(ApiDefinitionHistory.class) - .where(field(ApiDefinitionHistory::getProjectId).eq(projectId).and(field(ApiDefinitionHistory::getId).eq(historyId))) - .executeOne(); - } - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/ApiDefinitionResource.java b/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/ApiDefinitionResource.java deleted file mode 100644 index e9f574a6..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/ApiDefinitionResource.java +++ /dev/null @@ -1,206 +0,0 @@ -package dev.flexmodel.interfaces.rest; - -import jakarta.inject.Inject; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; -import org.eclipse.microprofile.openapi.annotations.Operation; -import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; -import org.eclipse.microprofile.openapi.annotations.media.Content; -import org.eclipse.microprofile.openapi.annotations.media.Schema; -import org.eclipse.microprofile.openapi.annotations.media.SchemaProperty; -import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; -import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; -import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.ApiDefinitionApplicationService; -import dev.flexmodel.application.dto.ApiDefinitionTreeDTO; -import dev.flexmodel.application.dto.GenerateAPIsDTO; -import dev.flexmodel.codegen.entity.ApiDefinition; -import dev.flexmodel.codegen.entity.ApiDefinitionHistory; - -import java.util.List; - - -/** - * @author cjbi - */ -@Tag(name = "接口定义", description = "接口定义管理") -@Path("/v1/projects/{projectId}/apis") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class ApiDefinitionResource { - - @Inject - ApiDefinitionApplicationService apiDesignApplicationService; - - @Operation(summary = "获取接口定义列表") - @APIResponse( - name = "200", - responseCode = "200", - description = "OK", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = ApiDefinitionTreeSchema.class - ) - )}) - @GET - public List findApiList(@PathParam("projectId") String projectId) { - return apiDesignApplicationService.findApiDefinitionTree(projectId); - } - - @GET - @Path("/{apiDefinitionId}/histories") - public List findApiDefinitionHistories(@PathParam("projectId") String projectId, @PathParam("apiDefinitionId") String apiDefinitionId) { - return apiDesignApplicationService.findApiDefinitionHistories(projectId, apiDefinitionId); - } - - @Operation(summary = "恢复接口定义") - @POST - @Path("/{apiDefinitionId}/histories/{historyId}/restore") - public ApiDefinitionHistory restoreApiDefinition(@PathParam("projectId") String projectId, @PathParam("historyId") String historyId, @PathParam("apiDefinitionId") String apiDefinitionId) { - return apiDesignApplicationService.restoreApiDefinition(projectId, historyId); - } - - @Operation(summary = "创建接口定义") - @POST - @RequestBody( - name = "请求体", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = ApiDefinitionSchema.class - ) - )} - ) - @APIResponse( - name = "200", - responseCode = "200", - description = "OK", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = ApiDefinitionSchema.class - ) - )}) - public ApiDefinition create(@PathParam("projectId") String projectId, ApiDefinition apiDefinition) { - apiDefinition.setProjectId(projectId); - return apiDesignApplicationService.createApiDefinition(projectId, apiDefinition); - } - - @Operation(summary = "更新接口定义") - @PUT - @Path("/{id}") - @RequestBody( - name = "请求体", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = ApiDefinitionSchema.class - ) - )} - ) - @APIResponse( - name = "200", - responseCode = "200", - description = "OK", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = ApiDefinitionSchema.class - ) - )}) - public ApiDefinition update(@PathParam("projectId") String projectId, @PathParam("id") String id, ApiDefinition apiDefinition) { - apiDefinition.setId(id); - apiDefinition.setProjectId(projectId); - return apiDesignApplicationService.updateApiDefinition(projectId, apiDefinition); - } - - @Operation(summary = "更新接口定义(局部更新)") - @PATCH - @Path("/{id}") - @RequestBody( - name = "请求体", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = ApiDefinitionSchema.class - ) - )} - ) - @APIResponse( - name = "200", - responseCode = "200", - description = "OK", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = ApiDefinitionSchema.class - ) - )}) - public ApiDefinition updateIgnoreNull(@PathParam("projectId") String projectId, @PathParam("id") String id, ApiDefinition request) { - request.setId(id); - ApiDefinition record = apiDesignApplicationService.findApiDefinition(projectId, id); - if (request.getName() != null) { - record.setName(request.getName()); - } - if (request.getEnabled() != null) { - record.setEnabled(request.getEnabled()); - } - apiDesignApplicationService.updateApiDefinition(projectId, record); - return record; - } - - @Operation(summary = "删除接口定义") - @DELETE - @Path("/{id}") - public void delete(@PathParam("projectId") String projectId, @PathParam("id") String id) { - apiDesignApplicationService.deleteApiDefinition(projectId, id); - } - - @Operation(summary = "根据模型生成接口定义") - @POST - @Path("/generate") - public void generateAPIs(@PathParam("projectId") String projectId, GenerateAPIsDTO dto) { - apiDesignApplicationService.generateAPIs(projectId, dto); - } - - @Schema( - properties = { - @SchemaProperty(name = "id", examples = {"-1"}, description = "唯一标识"), - @SchemaProperty(name = "type", description = "类型, FOLDER: 文件夹;API: 接口"), - @SchemaProperty(name = "path", description = "路径"), - @SchemaProperty(name = "meta", description = "元数据,存放接口定义,例如graphql定义"), - @SchemaProperty(name = "name", description = "名称"), - @SchemaProperty(name = "createdAt", description = "创建时间", readOnly = true), - @SchemaProperty(name = "updatedAt", description = "更新时间", readOnly = true), - @SchemaProperty(name = "parentId", description = "上级ID"), - @SchemaProperty(name = "enabled", description = "是否开启", defaultValue = "true"), - @SchemaProperty(name = "method", description = "HTTP请求方法", examples = {"GET"}), - @SchemaProperty(name = "children", description = "子节点", type = SchemaType.ARRAY), - @SchemaProperty(name = "projectId", description = "项目ID", readOnly = true) - } - ) - public static class ApiDefinitionTreeSchema extends ApiDefinitionTreeDTO { - - } - - @Schema( - properties = { - @SchemaProperty(name = "id", examples = {"-1"}, description = "唯一标识"), - @SchemaProperty(name = "type", description = "类型, FOLDER: 文件夹;API: 接口"), - @SchemaProperty(name = "path", description = "路径"), - @SchemaProperty(name = "meta", description = "元数据,存放接口定义,例如graphql定义"), - @SchemaProperty(name = "name", description = "名称"), - @SchemaProperty(name = "createdAt", description = "创建时间", readOnly = true), - @SchemaProperty(name = "updatedAt", description = "更新时间", readOnly = true), - @SchemaProperty(name = "parentId", description = "上级ID"), - @SchemaProperty(name = "enabled", description = "是否开启", defaultValue = "true"), - @SchemaProperty(name = "method", description = "HTTP请求方法", examples = {"GET"}), - @SchemaProperty(name = "projectId", description = "项目ID", readOnly = true) - } - ) - public static class ApiDefinitionSchema extends ApiDefinition { - - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/DocumentResource.java b/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/DocumentResource.java deleted file mode 100644 index 77cac31b..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/DocumentResource.java +++ /dev/null @@ -1,33 +0,0 @@ -package dev.flexmodel.interfaces.rest; - -import jakarta.annotation.security.PermitAll; -import jakarta.inject.Inject; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; -import org.eclipse.microprofile.openapi.annotations.Operation; -import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.DocumentApplicationService; - -import java.util.Map; - -/** - * @author cjbi - */ -@Tag(name = "接口文档", description = "接口文档管理") -@Path("/v1/projects/{projectId}/docs") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class DocumentResource { - - @Inject - DocumentApplicationService documentApplicationService; - - @Operation(summary = "获取接口文档") - @GET - @Path("/openapi.json") - @PermitAll - public Map getOpenApi(@PathParam("projectId") String projectId) { - return documentApplicationService.getOpenApi(projectId); - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/FlowResource.java b/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/FlowResource.java deleted file mode 100644 index d05beb2f..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/FlowResource.java +++ /dev/null @@ -1,736 +0,0 @@ -package dev.flexmodel.interfaces.rest; - -import dev.flexmodel.application.dto.*; -import dev.flexmodel.domain.model.flow.dto.param.*; -import dev.flexmodel.domain.model.flow.dto.result.*; -import jakarta.inject.Inject; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; -import lombok.Getter; -import lombok.Setter; -import org.eclipse.microprofile.openapi.annotations.Operation; -import org.eclipse.microprofile.openapi.annotations.enums.ParameterIn; -import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; -import org.eclipse.microprofile.openapi.annotations.media.Content; -import org.eclipse.microprofile.openapi.annotations.media.Schema; -import org.eclipse.microprofile.openapi.annotations.media.SchemaProperty; -import org.eclipse.microprofile.openapi.annotations.parameters.Parameter; -import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; -import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; -import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.FlowApplicationService; -import dev.flexmodel.application.dto.*; -import dev.flexmodel.codegen.entity.FlowInstance; -import dev.flexmodel.domain.model.flow.dto.bo.ElementInstance; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstance; -import dev.flexmodel.domain.model.flow.dto.param.*; -import dev.flexmodel.domain.model.flow.dto.result.*; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; - -import java.util.List; -import java.util.Map; - -/** - * @author cjbi - */ -@Tag(name = "服务编排", description = "服务编排管理") -@Path("/v1/projects/{projectId}/flows") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class FlowResource { - - @Inject - FlowApplicationService flowApplicationService; - - @Operation(summary = "获取流程实例历史用户任务列表", description = "获取指定流程实例的历史用户任务列表,按处理时间倒序排列。包含活跃和已完成的任务,不包含已禁用的任务。") - @APIResponse( - name = "200", - responseCode = "200", - description = "成功返回历史用户任务列表", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - type = SchemaType.ARRAY, - implementation = NodeInstanceSchema.class - ) - )}) - @GET - @Path("/instances/{flowInstanceId}/user-tasks") - public List getHistoryUserTaskList( - @PathParam("projectId") String projectId, - @Parameter(name = "flowInstanceId", description = "流程实例ID", in = ParameterIn.PATH, required = true, example = "flow_inst_001") - @PathParam("flowInstanceId") String flowInstanceId, - @Parameter(name = "effectiveForSubFlowInstance", description = "是否对子流程实例生效", in = ParameterIn.QUERY, example = "true") - @QueryParam("effectiveForSubFlowInstance") @DefaultValue("true") boolean effectiveForSubFlowInstance) { - return flowApplicationService.getHistoryUserTaskList(projectId, flowInstanceId, effectiveForSubFlowInstance); - } - - @Operation(summary = "获取流程实例历史元素列表", description = "获取指定流程实例的历史元素列表,主要用于显示流程快照视图。包含流程中已执行的所有节点信息。") - @APIResponse( - name = "200", - responseCode = "200", - description = "成功返回历史元素列表", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - type = SchemaType.ARRAY, - implementation = ElementInstanceSchema.class - ) - )}) - @GET - @Path("/instances/{flowInstanceId}/elements") - public List getHistoryElementList( - @PathParam("projectId") String projectId, - @Parameter(name = "flowInstanceId", description = "流程实例ID", in = ParameterIn.PATH, required = true, example = "flow_inst_001") - @PathParam("flowInstanceId") String flowInstanceId) { - return flowApplicationService.getHistoryElementList(projectId, flowInstanceId); - } - - @Operation(summary = "获取流程实例元素实例数据") - @Path("/instances/{flowInstanceId}/data/{instanceDataId}") - public Map getElementInstanceData(@PathParam("projectId") String projectId, - @PathParam("flowInstanceId") String flowInstanceId, - @PathParam("instanceDataId") String instanceDataId) { - return flowApplicationService.getInstanceData(projectId, flowInstanceId, instanceDataId); - } - - @Operation(summary = "获取流程列表") - @APIResponse( - name = "200", - responseCode = "200", - description = "OK", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = FlowModuleListResponseSchema.class - ) - )}) - @GET - public PageDTO findFlowList( - @PathParam("projectId") String projectId, - @Parameter(name = "flowKey", description = "流程模块ID", in = ParameterIn.QUERY) - @QueryParam("flowModuleId") String flowModuleId, - @QueryParam("flowKey") String flowKey, - @Parameter(name = "flowName", description = "流程名称", in = ParameterIn.QUERY) - @QueryParam("flowName") String flowName, - @Parameter(name = "page", description = "页码", in = ParameterIn.QUERY) - @QueryParam("page") @DefaultValue("1") Integer page, - @Parameter(name = "size", description = "每页大小", in = ParameterIn.QUERY) - @QueryParam("size") @DefaultValue("20") Integer size) { - FlowModuleListRequest request = new FlowModuleListRequest(); - request.setProjectId(projectId); - request.setFlowModuleId(flowModuleId); - request.setFlowKey(flowKey); - request.setFlowName(flowName); - request.setPage(page); - request.setSize(size); - return flowApplicationService.findFlowModuleList(request); - } - - @Operation(summary = "获取流程实例列表") - @APIResponse( - name = "200", - responseCode = "200", - description = "OK", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = FlowInstanceListResponseSchema.class - ) - )}) - @GET - @Path("/instances") - public PageDTO findFlowInstanceList( - @PathParam("projectId") String projectId, - @Parameter(name = "flowInstanceId", description = "流程实例ID", in = ParameterIn.QUERY) - @QueryParam("flowInstanceId") String flowInstanceId, - @Parameter(name = "flowModuleId", description = "流程模块ID", in = ParameterIn.QUERY) - @QueryParam("flowModuleId") String flowModuleId, - @Parameter(name = "flowDeployId", description = "流程部署ID", in = ParameterIn.QUERY) - @QueryParam("flowDeployId") String flowDeployId, - @Parameter(name = "status", description = "流程实例状态", in = ParameterIn.QUERY) - @QueryParam("status") Integer status, - @Parameter(name = "caller", description = "调用者", in = ParameterIn.QUERY) - @QueryParam("caller") String caller, - @Parameter(name = "page", description = "页码", in = ParameterIn.QUERY) - @QueryParam("page") @DefaultValue("1") Integer page, - @Parameter(name = "size", description = "每页大小", in = ParameterIn.QUERY) - @QueryParam("size") @DefaultValue("20") Integer size) { - FlowInstanceListRequest request = new FlowInstanceListRequest(); - request.setProjectId(projectId); - request.setFlowInstanceId(flowInstanceId); - request.setFlowModuleId(flowModuleId); - request.setFlowDeployId(flowDeployId); - request.setStatus(status); - request.setCaller(caller); - request.setPage(page); - request.setSize(size); - return flowApplicationService.findFlowInstanceList(request); - } - - @Operation(summary = "创建流程") - @POST - @RequestBody( - name = "请求体", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = CreateFlowParamSchema.class - ) - )} - ) - @APIResponse( - name = "200", - responseCode = "200", - description = "OK", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = CreateFlowResultSchema.class - ) - )}) - public CreateFlowResult createFlow(@PathParam("projectId") String projectId, CreateFlowParam createFlowParam) { - - createFlowParam.setProjectId(projectId); - createFlowParam.setCaller("admin"); - createFlowParam.setOperator("admin"); - return flowApplicationService.createFlow(createFlowParam); - } - - @Operation(summary = "部署流程") - @POST - @Path("/{flowModuleId}/deploy") - @RequestBody( - name = "请求体", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = DeployFlowParamSchema.class - ) - )} - ) - @APIResponse( - name = "200", - responseCode = "200", - description = "OK", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = DeployFlowResultSchema.class - ) - )}) - public DeployFlowResult deployFlow( - @PathParam("projectId") String projectId, - @Parameter(name = "flowModuleId", description = "流程模块ID", in = ParameterIn.PATH) - @PathParam("flowModuleId") String flowModuleId, - DeployFlowParam deployFlowParam) { - deployFlowParam.setProjectId(projectId); - deployFlowParam.setFlowModuleId(flowModuleId); - deployFlowParam.setCaller("admin"); - deployFlowParam.setOperator("admin"); - return flowApplicationService.deployFlow(deployFlowParam); - } - - @Operation(summary = "更新流程") - @PUT - @Path("/{flowModuleId}") - @RequestBody( - name = "请求体", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = UpdateFlowParamSchema.class - ) - )} - ) - @APIResponse( - name = "200", - responseCode = "200", - description = "OK", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = UpdateFlowResultSchema.class - ) - )}) - public UpdateFlowResult updateFlow( - @PathParam("projectId") String projectId, - @Parameter(name = "flowModuleId", description = "流程模块ID", in = ParameterIn.PATH) - @PathParam("flowModuleId") String flowModuleId, - UpdateFlowParam updateFlowParam) { - updateFlowParam.setFlowModuleId(flowModuleId); - updateFlowParam.setProjectId(projectId); - updateFlowParam.setCaller(updateFlowParam.getCaller()); - updateFlowParam.setOperator(updateFlowParam.getOperator()); - return flowApplicationService.updateFlow(updateFlowParam); - } - - @DELETE - @Path("/{flowModuleId}") - public void deleteFlow(@PathParam("projectId") String projectId, @Parameter(name = "flowModuleId", description = "流程模块ID", in = ParameterIn.PATH) - @PathParam("flowModuleId") String flowModuleId) { - flowApplicationService.deleteFlow(projectId, flowModuleId); - } - - @Operation(summary = "获取流程模块信息") - @APIResponse( - name = "200", - responseCode = "200", - description = "OK", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = FlowModuleResultSchema.class - ) - )}) - @GET - @Path("/{flowModuleId}") - public FlowModuleResult getFlowModule( - @PathParam("projectId") String projectId, - @Parameter(name = "flowModuleId", description = "流程模块ID", in = ParameterIn.PATH) - @PathParam("flowModuleId") String flowModuleId, - @Parameter(name = "flowDeployId", description = "流程部署ID", in = ParameterIn.QUERY) - @QueryParam("flowDeployId") String flowDeployId) { - GetFlowModuleParam param = new GetFlowModuleParam(); - param.setProjectId(projectId); - param.setFlowModuleId(flowModuleId); - param.setFlowDeployId(flowDeployId); - return flowApplicationService.getFlowModule(param); - } - - @Operation(summary = "启动流程实例") - @POST - @Path("/instances/start") - @RequestBody( - name = "请求体", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = StartProcessParamSchema.class - ) - )} - ) - @APIResponse( - name = "200", - responseCode = "200", - description = "OK", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = StartProcessResultSchema.class - ) - )}) - public StartProcessResult startProcess(@PathParam("projectId") String projectId, StartProcessParam startProcessParam) { - startProcessParam.setProjectId(projectId); - return flowApplicationService.startProcess(startProcessParam); - } - - @Operation(summary = "提交任务") - @POST - @Path("/instances/{flowInstanceId}/commit") - @RequestBody( - name = "请求体", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = CommitTaskParamSchema.class - ) - )} - ) - @APIResponse( - name = "200", - responseCode = "200", - description = "OK", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = CommitTaskResultSchema.class - ) - )}) - public CommitTaskResult commitTask( - @PathParam("projectId") String projectId, - @Parameter(name = "flowInstanceId", description = "流程实例ID", in = ParameterIn.PATH) - @PathParam("flowInstanceId") String flowInstanceId, - CommitTaskParam commitTaskParam) { - commitTaskParam.setProjectId(projectId); - commitTaskParam.setFlowInstanceId(flowInstanceId); - return flowApplicationService.commitTask(commitTaskParam); - } - - @Operation(summary = "回滚任务") - @POST - @Path("/instances/{flowInstanceId}/rollback") - @RequestBody( - name = "请求体", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = RollbackTaskParamSchema.class - ) - )} - ) - @APIResponse( - name = "200", - responseCode = "200", - description = "OK", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = RollbackTaskResultSchema.class - ) - )}) - public RollbackTaskResult rollbackTask( - @PathParam("projectId") String projectId, - @Parameter(name = "flowInstanceId", description = "流程实例ID", in = ParameterIn.PATH) - @PathParam("flowInstanceId") String flowInstanceId, - RollbackTaskParam rollbackTaskParam) { - rollbackTaskParam.setProjectId(projectId); - rollbackTaskParam.setFlowInstanceId(flowInstanceId); - return flowApplicationService.rollbackTask(rollbackTaskParam); - } - - @Operation(summary = "终止流程实例") - @POST - @Path("/instances/{flowInstanceId}/terminate") - @APIResponse( - name = "200", - responseCode = "200", - description = "OK", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = TerminateResultSchema.class - ) - )}) - public TerminateResult terminateProcess( - @PathParam("projectId") String projectId, - @Parameter(name = "flowInstanceId", description = "流程实例ID", in = ParameterIn.PATH) - @PathParam("flowInstanceId") String flowInstanceId, - @Parameter(name = "effectiveForSubFlowInstance", description = "是否对子流程实例生效", in = ParameterIn.QUERY) - @QueryParam("effectiveForSubFlowInstance") @DefaultValue("true") boolean effectiveForSubFlowInstance) { - return flowApplicationService.terminateProcess(projectId, flowInstanceId, effectiveForSubFlowInstance); - } - - @Operation(summary = "获取流程实例信息") - @APIResponse( - name = "200", - responseCode = "200", - description = "OK", - content = {@Content( - mediaType = "application/json", - schema = @Schema( - implementation = FlowInstanceSchema.class - ) - )}) - @GET - @Path("/instances/{flowInstanceId}") - public FlowInstance getFlowInstance( - @PathParam("projectId") String projectId, - @Parameter(name = "flowInstanceId", description = "流程实例ID", in = ParameterIn.PATH) - @PathParam("flowInstanceId") String flowInstanceId) { - return flowApplicationService.findFlowInstance(projectId, flowInstanceId); - } - - @Schema( - properties = { - @SchemaProperty(name = "flowKey", examples = {"order_process"}, description = "流程键"), - @SchemaProperty(name = "flowName", examples = {"订单处理流程"}, description = "流程名称"), - @SchemaProperty(name = "remark", examples = {"处理订单的完整业务流程"}, description = "备注"), - @SchemaProperty(name = "projectId", examples = {"default"}, description = "项目ID"), - @SchemaProperty(name = "caller", examples = {"admin"}, description = "调用者"), - @SchemaProperty(name = "operator", examples = {"admin"}, description = "操作者") - } - ) - public static class CreateFlowParamSchema extends CreateFlowParam { - public CreateFlowParamSchema() { - super("default", "admin"); - } - } - - @Schema( - properties = { - @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), - @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), - @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID") - } - ) - public static class CreateFlowResultSchema extends CreateFlowResult { - } - - @Schema( - properties = { - @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID"), - @SchemaProperty(name = "projectId", examples = {"default"}, description = "项目ID"), - @SchemaProperty(name = "caller", examples = {"admin"}, description = "调用者"), - @SchemaProperty(name = "operator", examples = {"admin"}, description = "操作者") - } - ) - public static class DeployFlowParamSchema extends DeployFlowParam { - public DeployFlowParamSchema() { - super("default", "admin"); - } - } - - @Schema( - properties = { - @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID"), - @SchemaProperty(name = "projectId", examples = {"default"}, description = "项目ID"), - @SchemaProperty(name = "caller", examples = {"admin"}, description = "调用者"), - @SchemaProperty(name = "operator", examples = {"admin"}, description = "操作者") - } - ) - public static class UpdateFlowParamSchema extends DeployFlowParam { - public UpdateFlowParamSchema() { - super("default", "admin"); - } - } - - @Schema( - properties = { - @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), - @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), - @SchemaProperty(name = "flowDeployId", examples = {"flow_deploy_001"}, description = "流程部署ID"), - @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID") - } - ) - public static class DeployFlowResultSchema extends DeployFlowResult { - } - - @Schema( - properties = { - @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), - @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), - } - ) - public static class UpdateFlowResultSchema extends UpdateFlowResult { - - } - - @Schema( - properties = { - @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), - @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), - @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID"), - @SchemaProperty(name = "flowDeployId", examples = {"flow_deploy_001"}, description = "流程部署ID") - } - ) - public static class FlowModuleResultSchema extends FlowModuleResult { - } - - @Schema( - properties = { - @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID"), - @SchemaProperty(name = "flowDeployId", examples = {"flow_deploy_001"}, description = "流程部署ID"), - @SchemaProperty(name = "variables", description = "流程变量", type = SchemaType.ARRAY) - } - ) - public static class StartProcessParamSchema extends StartProcessParam { - } - - @Schema( - properties = { - @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), - @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), - @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), - @SchemaProperty(name = "status", examples = {"1"}, description = "状态"), - @SchemaProperty(name = "flowDeployId", examples = {"flow_deploy_001"}, description = "流程部署ID"), - @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID") - } - ) - public static class StartProcessResultSchema extends StartProcessResult { - } - - @Schema( - properties = { - @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), - @SchemaProperty(name = "nodeInstanceId", examples = {"node_inst_001"}, description = "节点实例ID"), - @SchemaProperty(name = "variables", description = "流程变量", type = SchemaType.ARRAY), - @SchemaProperty(name = "projectId", examples = {"default"}, description = "项目ID"), - @SchemaProperty(name = "caller", examples = {"admin"}, description = "调用者"), - @SchemaProperty(name = "operator", examples = {"admin"}, description = "操作者") - } - ) - public static class CommitTaskParamSchema extends CommitTaskParam { - } - - @Schema( - properties = { - @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), - @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), - @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), - @SchemaProperty(name = "status", examples = {"1"}, description = "状态") - } - ) - public static class CommitTaskResultSchema extends CommitTaskResult { - } - - @Schema( - properties = { - @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), - @SchemaProperty(name = "nodeInstanceId", examples = {"node_inst_001"}, description = "节点实例ID"), - @SchemaProperty(name = "projectId", examples = {"default"}, description = "项目ID"), - @SchemaProperty(name = "caller", examples = {"admin"}, description = "调用者"), - @SchemaProperty(name = "operator", examples = {"admin"}, description = "操作者") - } - ) - public static class RollbackTaskParamSchema extends RollbackTaskParam { - } - - @Schema( - properties = { - @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), - @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), - @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), - @SchemaProperty(name = "status", examples = {"1"}, description = "状态") - } - ) - public static class RollbackTaskResultSchema extends RollbackTaskResult { - } - - @Schema( - properties = { - @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), - @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), - @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), - @SchemaProperty(name = "status", examples = {"1"}, description = "状态") - } - ) - public static class TerminateResultSchema extends TerminateResult { - public TerminateResultSchema() { - super(ErrorEnum.SUCCESS); - } - } - - @Schema( - properties = { - @SchemaProperty(name = "list", description = "流程模块列表", type = SchemaType.ARRAY), - @SchemaProperty(name = "total", examples = {"100"}, description = "总记录数") - } - ) - @Getter - @Setter - public static class FlowModuleListResponseSchema { - private java.util.List list; - private Long total; - } - - @Schema( - properties = { - @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID"), - @SchemaProperty(name = "flowName", examples = {"订单处理流程"}, description = "流程名称"), - @SchemaProperty(name = "flowKey", examples = {"order_process"}, description = "流程键"), - @SchemaProperty(name = "status", examples = {"4"}, description = "状态:1-草稿,2-设计,3-测试,4-已发布"), - @SchemaProperty(name = "remark", examples = {"处理订单的完整业务流程"}, description = "备注"), - @SchemaProperty(name = "projectId", examples = {"default"}, description = "项目ID"), - @SchemaProperty(name = "caller", examples = {"admin"}, description = "调用者"), - @SchemaProperty(name = "operator", examples = {"admin"}, description = "操作者"), - @SchemaProperty(name = "modifyTime", description = "修改时间", readOnly = true) - } - ) - public static class FlowModuleResponseSchema extends FlowModuleResponse { - } - - @Schema( - properties = { - @SchemaProperty(name = "list", description = "流程实例列表", type = SchemaType.ARRAY), - @SchemaProperty(name = "total", examples = {"100"}, description = "总记录数") - } - ) - @Getter - @Setter - public static class FlowInstanceListResponseSchema { - private java.util.List list; - private Long total; - - public FlowInstanceListResponseSchema() { - } - - } - - @Schema( - properties = { - @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), - @SchemaProperty(name = "flowModuleId", examples = {"flow_module_001"}, description = "流程模块ID"), - @SchemaProperty(name = "flowDeployId", examples = {"flow_deploy_001"}, description = "流程部署ID"), - @SchemaProperty(name = "status", examples = {"1"}, description = "流程实例状态:1-运行中,2-已完成,3-已终止,4-已暂停"), - @SchemaProperty(name = "parentFlowInstanceId", examples = {"parent_inst_001"}, description = "父流程实例ID"), - @SchemaProperty(name = "projectId", examples = {"default"}, description = "项目ID"), - @SchemaProperty(name = "caller", examples = {"admin"}, description = "调用者"), - @SchemaProperty(name = "operator", examples = {"admin"}, description = "操作者"), - @SchemaProperty(name = "createTime", description = "创建时间", readOnly = true), - @SchemaProperty(name = "modifyTime", description = "修改时间", readOnly = true) - } - ) - @Getter - @Setter - public static class FlowInstanceSchema { - private String flowInstanceId; - private String flowModuleId; - private String flowDeployId; - private Integer status; - private String parentFlowInstanceId; - private String tenant; - private String caller; - private java.time.LocalDateTime createTime; - private java.time.LocalDateTime modifyTime; - } - - @Schema( - properties = { - @SchemaProperty(name = "nodeInstanceId", examples = {"node_inst_001"}, description = "节点实例ID"), - @SchemaProperty(name = "Key", examples = {"user_task_001"}, description = "模型键"), - @SchemaProperty(name = "modelName", examples = {"用户审批任务"}, description = "模型名称"), - @SchemaProperty(name = "status", examples = {"2"}, description = "节点状态:1-待处理,2-已完成,3-已跳过,4-已禁用"), - @SchemaProperty(name = "flowElementType", examples = {"1"}, description = "流程元素类型:1-用户任务,2-服务任务,3-网关,4-事件"), - @SchemaProperty(name = "properties", description = "节点属性", type = SchemaType.OBJECT), - @SchemaProperty(name = "subNodeResultList", description = "子节点执行结果列表", type = SchemaType.ARRAY), - @SchemaProperty(name = "subFlowInstanceIdList", description = "子流程实例ID列表", type = SchemaType.ARRAY), - @SchemaProperty(name = "subElementInstanceList", description = "子元素实例列表", type = SchemaType.ARRAY), - @SchemaProperty(name = "instanceDataId", examples = {"data_001"}, description = "实例数据ID"), - @SchemaProperty(name = "createTime", description = "创建时间", readOnly = true), - @SchemaProperty(name = "modifyTime", description = "修改时间", readOnly = true) - } - ) - public static class NodeInstanceSchema extends NodeInstance { - } - - @Schema( - properties = { - @SchemaProperty(name = "Key", examples = {"start_event_001"}, description = "键"), - @SchemaProperty(name = "name", examples = {"开始事件"}, description = "名称"), - @SchemaProperty(name = "status", examples = {"2"}, description = "元素状态:1-待处理,2-已完成,3-已跳过,4-已禁用"), - @SchemaProperty(name = "properties", description = "元素属性", type = SchemaType.OBJECT), - @SchemaProperty(name = "nodeInstanceId", examples = {"node_inst_001"}, description = "节点实例ID"), - @SchemaProperty(name = "subFlowInstanceIdList", description = "子流程实例ID列表", type = SchemaType.ARRAY), - @SchemaProperty(name = "subElementInstanceList", description = "子元素实例列表", type = SchemaType.ARRAY), - @SchemaProperty(name = "instanceDataId", examples = {"data_001"}, description = "实例数据ID") - } - ) - public static class ElementInstanceSchema extends ElementInstance { - } - - @Schema( - properties = { - @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), - @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), - @SchemaProperty(name = "flowInstanceId", examples = {"flow_inst_001"}, description = "流程实例ID"), - @SchemaProperty(name = "status", examples = {"2"}, description = "流程状态:1-运行中,2-已完成,3-已终止,4-已暂停"), - @SchemaProperty(name = "nodeExecuteResults", description = "节点执行结果列表", type = SchemaType.ARRAY), - @SchemaProperty(name = "extendProperties", description = "扩展属性", type = SchemaType.OBJECT) - } - ) - public static class RuntimeResultSchema extends RuntimeResult { - } - - @Schema( - properties = { - @SchemaProperty(name = "errCode", examples = {"0"}, description = "错误码"), - @SchemaProperty(name = "errMsg", examples = {"success"}, description = "错误信息"), - @SchemaProperty(name = "activeTaskInstance", description = "活跃任务实例"), - @SchemaProperty(name = "variables", description = "流程变量列表", type = SchemaType.ARRAY) - } - ) - public static class NodeExecuteResultSchema extends RuntimeResult.NodeExecuteResult { - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/MetricsResource.java b/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/MetricsResource.java deleted file mode 100644 index ce105c42..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/MetricsResource.java +++ /dev/null @@ -1,327 +0,0 @@ -package dev.flexmodel.interfaces.rest; - -import dev.flexmodel.application.dto.*; -import jakarta.inject.Inject; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import org.eclipse.microprofile.openapi.annotations.Operation; -import org.eclipse.microprofile.openapi.annotations.media.Content; -import org.eclipse.microprofile.openapi.annotations.media.Schema; -import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; -import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement; -import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.MetricsApplicationService; -import dev.flexmodel.application.dto.*; - -import java.net.InterfaceAddress; -import java.net.NetworkInterface; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 系统监控资源类 - * 提供JVM、CPU、内存、线程、磁盘(含I/O)、网络等监控信息 - * - * @author cjbi - */ -@Path("/v1/projects/{projectId}/metrics") -@Tag(name = "系统监控", description = "系统监控相关接口,包括JVM、CPU、内存、线程、磁盘(含I/O)、网络等监控信息") -@SecurityRequirement(name = "BearerAuth") -public class MetricsResource { - @Inject - MetricsApplicationService metricsApplicationService; - - - @GET - @Path("/fm") - public FmMetricsResponse getFmMetrics(@PathParam("projectId") String projectId) { - return metricsApplicationService.getFmMetrics(projectId); - } - - /** - * JVM监控信息 - */ - @GET - @Path("/jvm") - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "获取JVM监控信息", - description = "返回JVM运行时的详细信息,包括类加载、垃圾回收、系统属性等" - ) - @APIResponse( - responseCode = "200", - description = "成功获取JVM信息", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = JvmMetricsResponse.class) - ) - ) - public JvmMetricsResponse getJvmMetrics() { - return metricsApplicationService.getJvmMetrics(); - } - - /** - * CPU监控信息 - */ - @GET - @Path("/cpu") - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "获取CPU监控信息", - description = "返回CPU使用率、系统负载、物理内存等系统资源信息" - ) - @APIResponse( - responseCode = "200", - description = "成功获取CPU信息", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = CpuMetricsResponse.class) - ) - ) - public CpuMetricsResponse getCpuMetrics() { - return metricsApplicationService.getCpuMetrics(); - } - - /** - * 内存监控信息 - */ - @GET - @Path("/memory") - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "获取内存监控信息", - description = "返回堆内存、非堆内存、内存池等详细内存使用情况" - ) - @APIResponse( - responseCode = "200", - description = "成功获取内存信息", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = MemoryMetricsResponse.class) - ) - ) - public MemoryMetricsResponse getMemoryMetrics() { - return metricsApplicationService.getMemoryMetrics(); - } - - /** - * 线程监控信息 - */ - @GET - @Path("/threads") - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "获取线程监控信息", - description = "返回线程数量、状态统计、线程详细信息等" - ) - @APIResponse( - responseCode = "200", - description = "成功获取线程信息", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = ThreadMetricsResponse.class) - ) - ) - public ThreadMetricsResponse getThreadMetrics() { - return metricsApplicationService.getThreadMetrics(); - } - - /** - * 磁盘监控信息 - */ - @GET - @Path("/disk") - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "获取磁盘监控信息", - description = "返回磁盘使用情况、文件系统信息、磁盘I/O统计等存储设备监控数据" - ) - @APIResponse( - responseCode = "200", - description = "成功获取磁盘信息", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = DiskMetricsResponse.class) - ) - ) - public DiskMetricsResponse getDiskMetrics() { - return metricsApplicationService.getDiskMetrics(); - } - - /** - * 网络监控信息 - */ - @GET - @Path("/network") - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "获取网络监控信息", - description = "返回网络接口信息、连接状态、IP地址等网络监控数据" - ) - @APIResponse( - responseCode = "200", - description = "成功获取网络信息", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = NetworkMetricsResponse.class) - ) - ) - public NetworkMetricsResponse getNetworkMetrics() { - return metricsApplicationService.getNetworkMetrics(); - } - - /** - * 处理单个网络接口(优化版本) - */ - private NetworkMetricsResponse.NetworkInterfaceInfo processNetworkInterface(NetworkInterface networkInterface) { - NetworkMetricsResponse.NetworkInterfaceInfo interfaceInfo = new NetworkMetricsResponse.NetworkInterfaceInfo(); - - try { - // 基本信息(快速获取) - interfaceInfo.setName(networkInterface.getName()); - interfaceInfo.setDisplayName(networkInterface.getDisplayName()); - interfaceInfo.setUp(networkInterface.isUp()); - interfaceInfo.setLoopback(networkInterface.isLoopback()); - interfaceInfo.setVirtual(networkInterface.isVirtual()); - interfaceInfo.setPointToPoint(networkInterface.isPointToPoint()); - interfaceInfo.setSupportsMulticast(networkInterface.supportsMulticast()); - - // MAC地址 - byte[] macBytes = networkInterface.getHardwareAddress(); - if (macBytes != null) { - StringBuilder macAddress = new StringBuilder(); - for (int i = 0; i < macBytes.length; i++) { - macAddress.append(String.format("%02x%s", macBytes[i], (i < macBytes.length - 1) ? ":" : "")); - } - interfaceInfo.setMacAddress(macAddress.toString()); - } - - // MTU - interfaceInfo.setMtu(networkInterface.getMTU()); - } catch (Exception e) { - // 如果基本信息获取失败,设置默认值 - interfaceInfo.setName(networkInterface.getName()); - interfaceInfo.setDisplayName("unknown"); - interfaceInfo.setUp(false); - interfaceInfo.setLoopback(false); - interfaceInfo.setVirtual(false); - interfaceInfo.setPointToPoint(false); - interfaceInfo.setSupportsMulticast(false); - interfaceInfo.setMtu(0); - } - - // IP地址信息(避免DNS解析) - Map addressesInfo = new HashMap<>(); - List interfaceAddresses = networkInterface.getInterfaceAddresses(); - for (int i = 0; i < interfaceAddresses.size(); i++) { - InterfaceAddress address = interfaceAddresses.get(i); - NetworkMetricsResponse.AddressInfo addressInfo = new NetworkMetricsResponse.AddressInfo(); - - addressInfo.setAddress(address.getAddress().getHostAddress()); - // 避免DNS反向解析,直接使用IP地址作为主机名 - addressInfo.setHostName(address.getAddress().getHostAddress()); - addressInfo.setNetworkPrefixLength(address.getNetworkPrefixLength()); - - if (address.getBroadcast() != null) { - addressInfo.setBroadcast(address.getBroadcast().getHostAddress()); - } - - addressesInfo.put("address_" + i, addressInfo); - } - interfaceInfo.setAddresses(addressesInfo); - - // 父接口信息 - if (networkInterface.getParent() != null) { - interfaceInfo.setParent(networkInterface.getParent().getName()); - } - - // 子接口(简化处理,只获取名称) - Map subInterfaces = new HashMap<>(); - try { - Enumeration subInterfaceEnum = networkInterface.getSubInterfaces(); - int index = 0; - while (subInterfaceEnum.hasMoreElements() && index < 10) { // 限制子接口数量,避免过多 - NetworkInterface subInterface = subInterfaceEnum.nextElement(); - subInterfaces.put("sub_" + index, subInterface.getName()); - index++; - } - } catch (Exception e) { - // 忽略子接口获取失败 - } - interfaceInfo.setSubInterfaces(subInterfaces); - - return interfaceInfo; - } - - /** - * 系统摘要信息 - */ - @GET - @Path("/summary") - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "获取系统摘要信息", - description = "返回系统运行状态的综合摘要,包括JVM、CPU、内存、线程等关键指标" - ) - @APIResponse( - responseCode = "200", - description = "成功获取系统摘要", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = SystemSummaryResponse.class) - ) - ) - public SystemSummaryResponse getSystemSummary() { - return metricsApplicationService.getSystemSummary(); - } - - /** - * Prometheus格式的指标导出 - */ - @GET - @Path("/prometheus") - @Produces(MediaType.TEXT_PLAIN) - @Operation( - summary = "获取Prometheus格式指标", - description = "返回Prometheus格式的监控指标数据,可用于Prometheus服务器采集" - ) - @APIResponse( - responseCode = "200", - description = "成功获取Prometheus指标", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = PrometheusMetricsResponse.class) - ) - ) - public PrometheusMetricsResponse getPrometheusMetrics() { - return metricsApplicationService.getPrometheusMetrics(); - } - - /** - * 获取所有监控指标 - */ - @GET - @Path("/all") - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "获取所有监控指标", - description = "获取JVM、CPU、内存、线程、磁盘、网络等所有监控信息,提供系统完整状态" - ) - @APIResponse( - responseCode = "200", - description = "成功获取所有监控指标", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = AllMetricsResponse.class) - ) - ) - public AllMetricsResponse getAllMetrics() { - return metricsApplicationService.getAllMetrics(); - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/json/jackson/FlexmodelServerModule.java b/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/json/jackson/FlexmodelServerModule.java deleted file mode 100644 index 0b968ca8..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/json/jackson/FlexmodelServerModule.java +++ /dev/null @@ -1,22 +0,0 @@ -package dev.flexmodel.interfaces.rest.json.jackson; - -import dev.flexmodel.domain.model.connect.database.Database; -import dev.flexmodel.domain.model.idp.provider.Provider; -import dev.flexmodel.domain.model.schedule.config.TriggerConfig; -import dev.flexmodel.interfaces.rest.json.jackson.mixin.DatasourceDatabaseMixIn; -import dev.flexmodel.interfaces.rest.json.jackson.mixin.IdentityProviderProviderMixIn; -import dev.flexmodel.interfaces.rest.json.jackson.mixin.ScheduledTriggerConfigMixIn; -import dev.flexmodel.supports.jackson.FlexmodelCoreModule; - -/** - * @author cjbi - */ -public class FlexmodelServerModule extends FlexmodelCoreModule { - - public FlexmodelServerModule() { - super(); - this.setMixInAnnotation(Database.class, DatasourceDatabaseMixIn.class); - this.setMixInAnnotation(Provider.class, IdentityProviderProviderMixIn.class); - this.setMixInAnnotation(TriggerConfig.class, ScheduledTriggerConfigMixIn.class); - } -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/vertx/FlexmodelRestAPIHandler.java b/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/vertx/FlexmodelRestAPIHandler.java deleted file mode 100644 index 09e2f8e7..00000000 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/vertx/FlexmodelRestAPIHandler.java +++ /dev/null @@ -1,62 +0,0 @@ -package dev.flexmodel.interfaces.rest.vertx; - -import dev.flexmodel.application.ProjectApplicationService; -import io.quarkus.runtime.StartupEvent; -import io.vertx.core.http.HttpMethod; -import io.vertx.ext.web.Router; -import io.vertx.ext.web.handler.BodyHandler; -import io.vertx.mutiny.core.eventbus.EventBus; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.event.Observes; -import jakarta.inject.Inject; -import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.application.ApiRuntimeApplicationService; -import dev.flexmodel.application.AuthApplicationService; -import dev.flexmodel.application.dto.GraphQLRefreshEvent; -import dev.flexmodel.application.dto.ProjectListRequest; -import dev.flexmodel.application.dto.ProjectResponse; -import dev.flexmodel.codegen.entity.Project; -import dev.flexmodel.shared.FlexmodelConfig; - -import java.util.List; - - -/** - * @author cjbi - */ -@Slf4j -@ApplicationScoped -public class FlexmodelRestAPIHandler { - - @Inject - ApiRuntimeApplicationService apiRuntimeApplicationService; - @Inject - EventBus eventBus; - @Inject - FlexmodelConfig config; - @Inject - ProjectApplicationService projectApplicationService; - - void handle(@Observes StartupEvent startupEvent, Router router) { - List projects = projectApplicationService.findProjects(new ProjectListRequest(null)); - for (Project project : projects) { - router.route() - .pathRegex(config.apiRootPath() + "/" + project.getId() + "/.*") - .handler(BodyHandler.create()) - .blockingHandler(apiRuntimeApplicationService::accept); - } - - router.route().pathRegex("/v1/datasources.*") - .handler(handle -> { - - handle.addEndHandler(v -> { - if (handle.request().method() != HttpMethod.GET) { - log.info(">>> Refreshing GraphQL schema..."); - eventBus.send("graphql.refresh", new GraphQLRefreshEvent()); - } - }); - handle.next(); - }); - } - -} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/metrics/MetricsResource.java b/flexmodel-server/src/main/java/dev/flexmodel/metrics/MetricsResource.java new file mode 100644 index 00000000..222dfbee --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/metrics/MetricsResource.java @@ -0,0 +1,31 @@ +package dev.flexmodel.metrics; + +import dev.flexmodel.metrics.dto.FmMetricsResponse; +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement; +import org.eclipse.microprofile.openapi.annotations.tags.Tag; + +/** + * 系统监控资源类 + * 提供JVM、CPU、内存、线程、磁盘(含I/O)、网络等监控信息 + * + * @author cjbi + */ +@Path("/v1/projects/{projectId}/metrics") +@Tag(name = "系统监控", description = "系统监控相关接口,包括JVM、CPU、内存、线程、磁盘(含I/O)、网络等监控信息") +@SecurityRequirement(name = "BearerAuth") +public class MetricsResource { + @Inject + MetricsService metricsService; + + + @GET + @Path("/fm") + public FmMetricsResponse getFmMetrics(@PathParam("projectId") String projectId) { + return metricsService.getFmMetrics(projectId); + } + +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/metrics/MetricsService.java b/flexmodel-server/src/main/java/dev/flexmodel/metrics/MetricsService.java new file mode 100644 index 00000000..dfd9d90a --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/metrics/MetricsService.java @@ -0,0 +1,67 @@ +package dev.flexmodel.metrics; + +import dev.flexmodel.metrics.dto.FmMetricsResponse; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import dev.flexmodel.codegen.entity.FlowDefinition; +import dev.flexmodel.codegen.entity.JobExecutionLog; +import dev.flexmodel.api.ApiRequestLogService; +import dev.flexmodel.flow.service.FlowDefinitionService; +import dev.flexmodel.flow.service.FlowInstanceService; +import dev.flexmodel.modeling.ModelService; +import dev.flexmodel.scheduling.JobExecutionLogService; +import dev.flexmodel.scheduling.TriggerService; +import dev.flexmodel.query.Expressions; + +import static dev.flexmodel.query.Expressions.TRUE; + +/** + * @author cjbi + */ +@Slf4j +@ApplicationScoped +public class MetricsService { + + @Inject + ApiRequestLogService apiLogService; + @Inject + ModelService modelService; + @Inject + FlowInstanceService flowInstanceService; + @Inject + FlowDefinitionService flowDefService; + @Inject + TriggerService triggerService; + @Inject + JobExecutionLogService jobExecutionLogService; + + public FmMetricsResponse getFmMetrics(String projectId) { + try { + Integer modelCount = modelService.count(projectId); + long reqLogCount = apiLogService.count(projectId, TRUE); + long flowDefCount = flowDefService.count(projectId, Expressions.field(FlowDefinition::getIsDeleted).eq(false)); + long flowInsCount = flowInstanceService.count(projectId, TRUE); + long triggerCount = triggerService.count(projectId, TRUE); + long jobSuccessCount = jobExecutionLogService.count(Expressions.field(JobExecutionLog::getExecutionStatus).eq("SUCCESS")); + long jobFailureCount = jobExecutionLogService.count(Expressions.field(JobExecutionLog::getExecutionStatus).eq("FAILED")); + + return FmMetricsResponse.builder() + .dataSourceCount(-1) + .customApiCount(-1) + .requestCount((int) reqLogCount) + .flowDefCount((int) flowDefCount) + .flowExecCount((int) flowInsCount) + .modelCount(modelCount) + .triggerTotalCount((int) triggerCount) + .jobSuccessCount((int) jobSuccessCount) + .jobFailureCount((int) jobFailureCount) + .build(); + + } catch (Exception e) { + log.error("get api fm metrics error", e); + throw new RuntimeException(e); + } + } + +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FmMetricsResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/metrics/dto/FmMetricsResponse.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/FmMetricsResponse.java rename to flexmodel-server/src/main/java/dev/flexmodel/metrics/dto/FmMetricsResponse.java index f5e9fd32..19d753e0 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FmMetricsResponse.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/metrics/dto/FmMetricsResponse.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.metrics.dto; import lombok.*; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ModelFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/modeling/ModelFmRepository.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ModelFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/modeling/ModelFmRepository.java index ffb20721..54b3489e 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/ModelFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/modeling/ModelFmRepository.java @@ -1,8 +1,7 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.modeling; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import dev.flexmodel.domain.model.modeling.ModelRepository; import dev.flexmodel.model.*; import dev.flexmodel.model.field.TypedField; import dev.flexmodel.parser.ASTNodeConverter; @@ -112,16 +111,16 @@ public List syncModels(String projectId, String datasourceName, Se public void importModels(String projectId, String datasourceName, String script, String type) { if (type.equals("JSON")) { sessionFactory.loadJSONString(datasourceName, script); - } else if (type.equals("IDL")) { - sessionFactory.loadIDLString(datasourceName, script); + } else if (type.equals("FML")) { + sessionFactory.loadFMLString(datasourceName, script); } else { - throw new RuntimeException("Unsupported type"); + throw new RuntimeException("Unsupported type: " + type + ", supported types: JSON, FML"); } } @Override - public List executeIdl(String projectId, String datasourceName, String idlString) throws ParseException { - ModelParser parser = new ModelParser(new StringReader(idlString)); + public List executeFml(String projectId, String datasourceName, String fmlString) throws ParseException { + ModelParser parser = new ModelParser(new StringReader(fmlString)); List ast = parser.CompilationUnit(); List schema = new ArrayList<>(); for (ModelParser.ASTNode obj : ast) { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/modeling/ModelRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/modeling/ModelRepository.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/modeling/ModelRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/modeling/ModelRepository.java index b2825d8c..c9648fc0 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/modeling/ModelRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/modeling/ModelRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.modeling; +package dev.flexmodel.modeling; import dev.flexmodel.model.IndexDefinition; import dev.flexmodel.model.SchemaObject; @@ -36,7 +36,7 @@ public interface ModelRepository { void importModels(String projectId, String datasourceName, String script, String type); - List executeIdl(String projectId, String datasourceName, String idl) throws ParseException; + List executeFml(String projectId, String datasourceName, String fml) throws ParseException; Integer count(String projectId); diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/modeling/ModelService.java b/flexmodel-server/src/main/java/dev/flexmodel/modeling/ModelService.java similarity index 92% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/modeling/ModelService.java rename to flexmodel-server/src/main/java/dev/flexmodel/modeling/ModelService.java index 18d7a37f..3ed1f351 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/modeling/ModelService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/modeling/ModelService.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.modeling; +package dev.flexmodel.modeling; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -74,7 +74,7 @@ public void importModels(String projectId, String datasourceName, String script, modelRepository.importModels(projectId, datasourceName, script, type); } - public List executeIdl(String projectId, String datasourceName, String idl) throws ParseException { - return modelRepository.executeIdl(projectId, datasourceName, idl); + public List executeFml(String projectId, String datasourceName, String fml) throws ParseException { + return modelRepository.executeFml(projectId, datasourceName, fml); } } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/ModelingResource.java b/flexmodel-server/src/main/java/dev/flexmodel/modeling/ModelingResource.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/ModelingResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/modeling/ModelingResource.java index ab5f44c0..d71d608b 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/ModelingResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/modeling/ModelingResource.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.modeling; import jakarta.inject.Inject; import jakarta.ws.rs.*; @@ -13,7 +13,6 @@ import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.ModelingApplicationService; import dev.flexmodel.model.*; import dev.flexmodel.model.field.TypedField; @@ -29,7 +28,7 @@ public class ModelingResource { @Inject - ModelingApplicationService modelingApplicationService; + ModelingService modelingService; @Operation(summary = "获取模型列表") @APIResponse( @@ -70,7 +69,7 @@ public class ModelingResource { }) @GET public List findModels(@PathParam("projectId") String projectId) { - return modelingApplicationService.findModels(projectId); + return modelingService.findModels(projectId); } @Operation(summary = "获取单个模型") @@ -113,7 +112,7 @@ public List findModels(@PathParam("projectId") String projectId) { @GET @Path("/{modelName}") public SchemaObject findModel(@PathParam("projectId") String projectId, @PathParam("modelName") String modelName) { - return modelingApplicationService.findModel(projectId, modelName); + return modelingService.findModel(projectId, modelName); } @RequestBody( @@ -188,16 +187,16 @@ public SchemaObject findModel(@PathParam("projectId") String projectId, @PathPar @Operation(summary = "创建模型") @POST public SchemaObject createModel(@PathParam("projectId") String projectId, SchemaObject model) { - return modelingApplicationService.createModel(projectId, model); + return modelingService.createModel(projectId, model); } @POST - @Path("/idl/execute") - public List executeIdl(@PathParam("projectId") String projectId, IdlRequest request) { + @Path("/fml/execute") + public List executeFml(@PathParam("projectId") String projectId, FmlRequest request) { try { - return modelingApplicationService.executeIdl(projectId, request.idl()); + return modelingService.executeFml(projectId, request.fml()); } catch (Exception e) { - throw new RuntimeException("IDL格式有误: " + e.getMessage()); + throw new RuntimeException("FML格式有误: " + e.getMessage()); } } @@ -275,7 +274,7 @@ public List executeIdl(@PathParam("projectId") String projectId, I @PUT @Path("/{modelName}") public SchemaObject modifyModel(@PathParam("projectId") String projectId, @PathParam("modelName") String modelName, SchemaObject model) { - return modelingApplicationService.modifyModel(projectId, modelName, model); + return modelingService.modifyModel(projectId, modelName, model); } @@ -284,7 +283,7 @@ public SchemaObject modifyModel(@PathParam("projectId") String projectId, @PathP @DELETE @Path("/{modelName}") public void dropModel(@PathParam("projectId") String projectId, @PathParam("modelName") String modelName) { - modelingApplicationService.dropModel(projectId, modelName); + modelingService.dropModel(projectId, modelName); } @RequestBody( @@ -310,7 +309,7 @@ public void dropModel(@PathParam("projectId") String projectId, @PathParam("mode @Path("/{modelName}/fields") public TypedField createField(@PathParam("projectId") String projectId, @PathParam("modelName") String modelName, TypedField field) { field.setModelName(modelName); - return modelingApplicationService.createField(projectId, field); + return modelingService.createField(projectId, field); } @RequestBody( @@ -338,7 +337,7 @@ public void dropModel(@PathParam("projectId") String projectId, @PathParam("mode public TypedField modifyField(@PathParam("projectId") String projectId, @PathParam("modelName") String modelName, @PathParam("fieldName") String fieldName, TypedField field) { field.setModelName(modelName); field.setName(fieldName); - return modelingApplicationService.modifyField(projectId, field); + return modelingService.modifyField(projectId, field); } @Parameter(name = "modelName", description = "模型名称", in = ParameterIn.PATH) @@ -347,7 +346,7 @@ public void dropModel(@PathParam("projectId") String projectId, @PathParam("mode @DELETE @Path("/{modelName}/fields/{fieldName}") public void dropField(@PathParam("projectId") String projectId, @PathParam("modelName") String modelName, @PathParam("fieldName") String fieldName) { - modelingApplicationService.dropField(projectId, modelName, fieldName); + modelingService.dropField(projectId, modelName, fieldName); } @RequestBody( @@ -383,7 +382,7 @@ public void dropField(@PathParam("projectId") String projectId, @PathParam("mode @Path("/{modelName}/indexes") public IndexDefinition createIndex(@PathParam("projectId") String projectId, @PathParam("modelName") String modelName, IndexDefinition index) { index.setModelName(modelName); - return modelingApplicationService.createIndex(projectId, index); + return modelingService.createIndex(projectId, index); } @RequestBody( @@ -421,7 +420,7 @@ public IndexDefinition createIndex(@PathParam("projectId") String projectId, @Pa public IndexDefinition modifyIndex(@PathParam("projectId") String projectId, @PathParam("modelName") String modelName, @PathParam("indexName") String indexName, IndexDefinition index) { index.setModelName(modelName); index.setName(indexName); - return modelingApplicationService.modifyIndex(projectId, index); + return modelingService.modifyIndex(projectId, index); } @Parameter(name = "modelName", description = "模型名称", in = ParameterIn.PATH) @@ -430,11 +429,11 @@ public IndexDefinition modifyIndex(@PathParam("projectId") String projectId, @Pa @DELETE @Path("/{modelName}/indexes/{indexName}") public void dropIndex(@PathParam("projectId") String projectId, @PathParam("modelName") String modelName, @PathParam("indexName") String indexName) { - modelingApplicationService.dropIndex(projectId, modelName, indexName); + modelingService.dropIndex(projectId, modelName, indexName); } - public record IdlRequest(String idl) { + public record FmlRequest(String fml) { } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/ModelingApplicationService.java b/flexmodel-server/src/main/java/dev/flexmodel/modeling/ModelingService.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/application/ModelingApplicationService.java rename to flexmodel-server/src/main/java/dev/flexmodel/modeling/ModelingService.java index 2ebd97b9..06b16e33 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/ModelingApplicationService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/modeling/ModelingService.java @@ -1,10 +1,9 @@ -package dev.flexmodel.application; +package dev.flexmodel.modeling; import dev.flexmodel.codegen.entity.Project; -import dev.flexmodel.domain.model.auth.ProjectService; +import dev.flexmodel.project.ProjectService; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import dev.flexmodel.domain.model.modeling.ModelService; import dev.flexmodel.model.*; import dev.flexmodel.model.field.TypedField; import dev.flexmodel.parser.impl.ParseException; @@ -16,7 +15,7 @@ * @author cjbi */ @ApplicationScoped -public class ModelingApplicationService { +public class ModelingService { @Inject ModelService modelService; @@ -100,8 +99,8 @@ public SchemaObject findModel(String projectId, String modelName) { return modelService.findModel(projectId, project.getDatabaseName(), modelName).orElseThrow(() -> new RuntimeException("Model not found")); } - public List executeIdl(String projectId, String idl) throws ParseException { + public List executeFml(String projectId, String fml) throws ParseException { Project project = projectService.findProject(projectId); - return modelService.executeIdl(projectId, project.getDatabaseName(), idl); + return modelService.executeFml(projectId, project.getDatabaseName(), fml); } } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/TenantFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/project/ProjectFmRepository.java similarity index 86% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/TenantFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/project/ProjectFmRepository.java index b8a10ae8..ac23cec5 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/TenantFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/project/ProjectFmRepository.java @@ -1,9 +1,8 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.project; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.Project; -import dev.flexmodel.domain.model.auth.ProjectRepository; import dev.flexmodel.query.Expressions; import dev.flexmodel.session.Session; @@ -15,7 +14,7 @@ * @author cjbi */ @ApplicationScoped -public class TenantFmRepository implements ProjectRepository { +public class ProjectFmRepository implements ProjectRepository { @Inject Session session; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/ProjectRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/project/ProjectRepository.java similarity index 87% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/ProjectRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/project/ProjectRepository.java index 3c10ce49..524bc3ca 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/auth/ProjectRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/project/ProjectRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.auth; +package dev.flexmodel.project; import dev.flexmodel.codegen.entity.Project; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/ProjectResource.java b/flexmodel-server/src/main/java/dev/flexmodel/project/ProjectResource.java similarity index 84% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/ProjectResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/project/ProjectResource.java index 7bfc9977..b9f5f50e 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/ProjectResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/project/ProjectResource.java @@ -1,6 +1,5 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.project; -import dev.flexmodel.application.ProjectApplicationService; import jakarta.inject.Inject; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; @@ -12,8 +11,8 @@ import org.eclipse.microprofile.openapi.annotations.parameters.Parameter; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.dto.ProjectListRequest; -import dev.flexmodel.application.dto.ProjectResponse; +import dev.flexmodel.project.dto.ProjectListRequest; +import dev.flexmodel.project.dto.ProjectResponse; import dev.flexmodel.codegen.entity.Project; import java.util.List; @@ -28,7 +27,7 @@ public class ProjectResource { @Inject - ProjectApplicationService projectApplicationService; + ProjectService projectService; @APIResponse( name = "200", @@ -47,7 +46,7 @@ public class ProjectResource { @Operation(summary = "获取项目列表") @GET public List findProjects(@QueryParam("include") String include) { - return projectApplicationService.findProjects(new ProjectListRequest(include)); + return projectService.findProjects(new ProjectListRequest(include)); } @APIResponse( @@ -67,7 +66,7 @@ public List findProjects(@QueryParam("include") String include) @GET @Path("/{projectId}") public Project findProject(@PathParam("projectId") String projectId) { - return projectApplicationService.findProject(projectId); + return projectService.findProject(projectId); } @APIResponse( @@ -86,7 +85,7 @@ public Project findProject(@PathParam("projectId") String projectId) { @Operation(summary = "创建项目") @POST public Project createProject(Project project) { - return projectApplicationService.createProject(project); + return projectService.createProject(project); } @APIResponse( @@ -110,7 +109,7 @@ public Project updateProject( @PathParam("projectId") String projectId, Project project) { project.setId(projectId); - return projectApplicationService.updateProject(project); + return projectService.updateProject(project); } @APIResponse( @@ -133,7 +132,7 @@ public Project patchProject( @Parameter(name = "projectId", in = ParameterIn.PATH, description = "项目ID", required = true) @PathParam("projectId") String projectId, Project project) { - Project existingProject = projectApplicationService.findProject(projectId); + Project existingProject = projectService.findProject(projectId); if (project.getName() != null) { existingProject.setName(project.getName()); } @@ -146,7 +145,7 @@ public Project patchProject( if (project.getOwnerId() != null) { existingProject.setOwnerId(project.getOwnerId()); } - return projectApplicationService.updateProject(existingProject); + return projectService.updateProject(existingProject); } @APIResponse( @@ -160,7 +159,7 @@ public Project patchProject( public void deleteProject( @Parameter(name = "projectId", in = ParameterIn.PATH, description = "项目ID", required = true) @PathParam("projectId") String projectId) { - projectApplicationService.deleteProject(projectId); + projectService.deleteProject(projectId); } } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/project/ProjectService.java b/flexmodel-server/src/main/java/dev/flexmodel/project/ProjectService.java new file mode 100644 index 00000000..9dfc81ff --- /dev/null +++ b/flexmodel-server/src/main/java/dev/flexmodel/project/ProjectService.java @@ -0,0 +1,160 @@ +package dev.flexmodel.project; + +import com.zaxxer.hikari.HikariDataSource; +import dev.flexmodel.api.consumer.GraphQLEventConsumer; +import dev.flexmodel.common.SchemaInitializer; +import dev.flexmodel.common.SessionContextHolder; +import dev.flexmodel.common.FlexmodelConfig; +import dev.flexmodel.common.config.SessionConfig; +import dev.flexmodel.common.utils.StringUtils; +import dev.flexmodel.connect.SessionDatasource; +import dev.flexmodel.flow.service.FlowDeploymentService; +import dev.flexmodel.project.dto.ProjectListRequest; +import dev.flexmodel.project.dto.ProjectResponse; +import dev.flexmodel.sql.JdbcSchemaManager; +import dev.flexmodel.sql.SchemaManager; +import dev.flexmodel.storage.StorageService; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import dev.flexmodel.codegen.entity.Project; + +import javax.sql.DataSource; +import java.util.List; +import java.util.Objects; +import java.util.regex.Pattern; + +/** + * @author cjbi + */ +@ApplicationScoped +public class ProjectService { + + /** 项目ID格式:以小写字母开头,由小写字母、数字和下划线组成,长度2~63个字符 */ + private static final Pattern PROJECT_ID_PATTERN = Pattern.compile("^[a-z][a-z0-9_]{1,62}$"); + + @Inject + ProjectRepository projectRepository; + + @Inject + FlowDeploymentService flowDeploymentService; + @Inject + StorageService storageService; + @Inject + SessionDatasource sessionDatasource; + @Inject + SchemaInitializer schemaInitializer; + @Inject + FlexmodelConfig flexmodelConfig; + @Inject + GraphQLEventConsumer graphQLEventConsumer; + + private final SchemaManager schemaManager = new JdbcSchemaManager(); + + public List findProjects() { + return projectRepository.findProjects(); + } + + public List findProjects(ProjectListRequest request) { + return projectRepository.findProjects().stream() + .map(project -> { + ProjectResponse response = ProjectResponse.fromProject(project); + if (Objects.equals(request.getIncldue(), "stats")) { + ProjectResponse.ProjectStats projectStats = new ProjectResponse.ProjectStats( + -1, + flowDeploymentService.count(project.getId()), + storageService.count(project.getId()) + ); + response.setStats(projectStats); + } + return response; + } + ).toList(); + } + public Project findProject(String projectId) { + return projectRepository.findProject(projectId); + } + + public Project createProject(Project project) { + if (StringUtils.isBlank(project.getId())) { + throw new IllegalArgumentException("项目ID不能为空"); + } + if (!PROJECT_ID_PATTERN.matcher(project.getId()).matches()) { + throw new IllegalArgumentException("项目ID格式不正确,需以小写字母开头,由小写字母、数字和下划线组成,长度2~63个字符"); + } + if (findProject(project.getId()) != null) { + throw new IllegalArgumentException("项目ID已经存在"); + } + // 设置 databaseName(若未指定则用 projectId) + if (StringUtils.isBlank(project.getDatabaseName())) { + project.setDatabaseName(project.getId()); + } + project.setOwnerId(SessionContextHolder.getUserId()); + + // 1. 创建物理 Schema + DataSource systemDs = getSystemDataSource(); + schemaManager.createSchema(systemDs, project.getDatabaseName()); + + // 2. 注册 SchemaProvider 到 SessionFactory(必须在初始化表结构之前) + sessionDatasource.registerSchema(project.getDatabaseName()); + + // 3. 用 project.fml 初始化表结构 + schemaInitializer.init(project.getDatabaseName()); + + // 4. 保存 f_project 记录 + Project saved = projectRepository.save(project); + + // 5. 为新项目生成 GraphQL Schema + graphQLEventConsumer.refreshProject(saved); + + return saved; + } + + public Project updateProject(Project project) { + if ("default".equals(project.getId())) { + throw new IllegalArgumentException("默认项目不能修改"); + } + Project existingProject = findProject(project.getId()); + if (existingProject == null) { + throw new IllegalArgumentException("项目不存在"); + } + project.setCreatedAt(existingProject.getCreatedAt()); + project.setCreatedBy(existingProject.getCreatedBy()); + project.setOwnerId(existingProject.getOwnerId()); + return projectRepository.save(project); + } + + public void deleteProject(String projectId) { + if ("default".equals(projectId)) { + throw new IllegalArgumentException("默认项目不能删除"); + } + Project project = findProject(projectId); + + // 1. 取消注册 SchemaProvider + sessionDatasource.unregisterSchema(project.getDatabaseName()); + + // 2. 删除物理 Schema + try { + DataSource systemDs = getSystemDataSource(); + schemaManager.dropSchema(systemDs, project.getDatabaseName()); + } catch (Exception e) { + // Schema 删除失败不影响记录删除,记录日志即可 + // 部分数据库(如 Oracle)可能无法自动删除 + } + + // 3. 删除 f_project 记录 + projectRepository.delete(projectId); + } + + /** + * 构建系统数据源,用于执行 Schema 管理 DDL。 + */ + private DataSource getSystemDataSource() { + FlexmodelConfig.DatasourceConfig config = flexmodelConfig.datasources().get(SessionConfig.SYSTEM_DS_KEY); + HikariDataSource ds = new HikariDataSource(); + ds.setMaxLifetime(30000); + ds.setJdbcUrl(config.url()); + ds.setUsername(config.username().orElse(null)); + ds.setPassword(config.password().orElse(null)); + return ds; + } +} diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ProjectListRequest.java b/flexmodel-server/src/main/java/dev/flexmodel/project/dto/ProjectListRequest.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/ProjectListRequest.java rename to flexmodel-server/src/main/java/dev/flexmodel/project/dto/ProjectListRequest.java index a1f5ac67..b2ae0b08 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ProjectListRequest.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/project/dto/ProjectListRequest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.project.dto; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ProjectResponse.java b/flexmodel-server/src/main/java/dev/flexmodel/project/dto/ProjectResponse.java similarity index 82% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/ProjectResponse.java rename to flexmodel-server/src/main/java/dev/flexmodel/project/dto/ProjectResponse.java index 44747267..0f1d293d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ProjectResponse.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/project/dto/ProjectResponse.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.project.dto; import lombok.Getter; import lombok.Setter; @@ -25,7 +25,7 @@ public static ProjectResponse fromProject(Project project) { return response; } - public record ProjectStats(Integer apiCount, Integer datasourceCount, Integer flowCount, Integer storageCount) { + public record ProjectStats(Integer apiCount, Integer flowCount, Integer storageCount) { } } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/JobExecutionLogFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/JobExecutionLogFmRepository.java similarity index 95% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/JobExecutionLogFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/JobExecutionLogFmRepository.java index ac5dc4e1..6b93f043 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/JobExecutionLogFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/JobExecutionLogFmRepository.java @@ -1,10 +1,10 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.scheduling; +import dev.flexmodel.common.AbstractRepository; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.control.ActivateRequestContext; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.JobExecutionLog; -import dev.flexmodel.domain.model.schedule.JobExecutionLogRepository; import dev.flexmodel.query.Predicate; import dev.flexmodel.session.Session; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/JobExecutionLogRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/JobExecutionLogRepository.java similarity index 95% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/JobExecutionLogRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/JobExecutionLogRepository.java index 79af761e..80da6e2d 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/JobExecutionLogRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/JobExecutionLogRepository.java @@ -1,9 +1,8 @@ -package dev.flexmodel.domain.model.schedule; +package dev.flexmodel.scheduling; import dev.flexmodel.codegen.entity.JobExecutionLog; import dev.flexmodel.query.Predicate; -import java.time.LocalDateTime; import java.util.List; /** diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/JobExecutionLogService.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/JobExecutionLogService.java similarity index 99% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/JobExecutionLogService.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/JobExecutionLogService.java index 15656bb6..e3dbcda4 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/JobExecutionLogService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/JobExecutionLogService.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.schedule; +package dev.flexmodel.scheduling; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.control.ActivateRequestContext; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/JobResource.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/JobResource.java similarity index 80% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/JobResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/JobResource.java index 81ec874a..ee965308 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/JobResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/JobResource.java @@ -1,11 +1,10 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.scheduling; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.*; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.JobApplicationService; -import dev.flexmodel.application.dto.PageDTO; +import dev.flexmodel.common.dto.PageDTO; import dev.flexmodel.codegen.entity.JobExecutionLog; import java.time.LocalDateTime; @@ -19,7 +18,7 @@ public class JobResource { @Inject - JobApplicationService jobApplicationService; + JobService jobService; @GET @Path("/logs") @@ -32,7 +31,7 @@ public PageDTO findLogPage(@PathParam("projectId") String proje @QueryParam("isSuccess") Boolean isSuccess, @QueryParam("page") @DefaultValue("1") Integer page, @QueryParam("size") @DefaultValue("20") Integer size) { - return jobApplicationService.findLogPage(projectId, triggerId, jobId, status, startTime, endTime, isSuccess, page, size); + return jobService.findLogPage(projectId, triggerId, jobId, status, startTime, endTime, isSuccess, page, size); } } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/JobApplicationService.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/JobService.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/application/JobApplicationService.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/JobService.java index 022b3b29..b6494495 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/JobApplicationService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/JobService.java @@ -1,11 +1,10 @@ -package dev.flexmodel.application; +package dev.flexmodel.scheduling; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.application.dto.PageDTO; +import dev.flexmodel.common.dto.PageDTO; import dev.flexmodel.codegen.entity.JobExecutionLog; -import dev.flexmodel.domain.model.schedule.JobExecutionLogService; import java.time.LocalDateTime; import java.util.List; @@ -18,7 +17,7 @@ */ @Slf4j @ApplicationScoped -public class JobApplicationService { +public class JobService { @Inject JobExecutionLogService jobExecutionLogService; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/TriggerDataChangedEventListener.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerDataChangedEventListener.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/application/TriggerDataChangedEventListener.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerDataChangedEventListener.java index e71c3551..e057da80 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/TriggerDataChangedEventListener.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerDataChangedEventListener.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application; +package dev.flexmodel.scheduling; import io.vertx.mutiny.core.eventbus.EventBus; import jakarta.enterprise.context.ApplicationScoped; @@ -6,16 +6,14 @@ import lombok.extern.slf4j.Slf4j; import dev.flexmodel.codegen.entity.JobExecutionLog; import dev.flexmodel.codegen.entity.Trigger; -import dev.flexmodel.domain.model.flow.dto.StartProcessParamEvent; -import dev.flexmodel.domain.model.schedule.JobExecutionLogService; -import dev.flexmodel.domain.model.schedule.TriggerService; +import dev.flexmodel.flow.dto.StartProcessParamEvent; import dev.flexmodel.event.ChangedEvent; import dev.flexmodel.event.EventListener; import dev.flexmodel.event.EventType; import dev.flexmodel.event.PreChangeEvent; import dev.flexmodel.query.Expressions; -import dev.flexmodel.shared.SessionContextHolder; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.common.SessionContextHolder; +import dev.flexmodel.common.utils.JsonUtils; import java.util.List; import java.util.Map; @@ -28,7 +26,7 @@ public class TriggerDataChangedEventListener implements EventListener { @Inject - TriggerService triggerService; + TriggerRepository triggerRepository; @Inject JobExecutionLogService jobExecutionLogService; @Inject @@ -52,7 +50,7 @@ public void onPreChange(PreChangeEvent event) { String groupName = event.getSchemaName() + "_" + event.getModelName(); String projectId = SessionContextHolder.getProjectId(); // 最多支持触发100个事件 - List triggers = triggerService.find(projectId, + List triggers = triggerRepository.find(projectId, Expressions.field(Trigger::getJobGroup).eq(groupName) .and(Expressions.field(Trigger::getState).eq(true)), 1, 100); @@ -99,7 +97,7 @@ public void onChanged(ChangedEvent event) { String groupName = event.getSchemaName() + "_" + event.getModelName(); String projectId = SessionContextHolder.getProjectId(); // 最多支持触发100个事件 - List triggers = triggerService.find(projectId, + List triggers = triggerRepository.find(projectId, Expressions.field(Trigger::getJobGroup).eq(groupName) .and(Expressions.field(Trigger::getState).eq(true)), 1, 100); diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/TriggerException.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerException.java similarity index 71% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/TriggerException.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerException.java index 3fc076e9..40454619 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/TriggerException.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerException.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.schedule; +package dev.flexmodel.scheduling; -import dev.flexmodel.domain.model.BusinessException; +import dev.flexmodel.common.BusinessException; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/TriggerFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerFmRepository.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/TriggerFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerFmRepository.java index e7a020c3..400a0743 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/TriggerFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerFmRepository.java @@ -1,8 +1,8 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.scheduling; +import dev.flexmodel.common.AbstractRepository; import jakarta.enterprise.context.ApplicationScoped; import dev.flexmodel.codegen.entity.Trigger; -import dev.flexmodel.domain.model.schedule.TriggerRepository; import dev.flexmodel.query.Predicate; import dev.flexmodel.session.Session; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/TriggerRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerRepository.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/TriggerRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerRepository.java index 361ab18d..a7b2cdb3 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/TriggerRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.schedule; +package dev.flexmodel.scheduling; import dev.flexmodel.codegen.entity.Trigger; import dev.flexmodel.query.Predicate; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/TriggerResource.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerResource.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/TriggerResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerResource.java index f500b62b..1e74c452 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/TriggerResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerResource.java @@ -1,14 +1,13 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.scheduling; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.*; import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.TriggerApplicationService; -import dev.flexmodel.application.dto.PageDTO; -import dev.flexmodel.application.dto.TriggerDTO; -import dev.flexmodel.application.dto.TriggerPageRequest; +import dev.flexmodel.common.dto.PageDTO; +import dev.flexmodel.scheduling.dto.TriggerDTO; +import dev.flexmodel.scheduling.dto.TriggerPageRequest; import dev.flexmodel.codegen.entity.Trigger; /** @@ -19,7 +18,7 @@ @Path("/v1/projects/{projectId}/triggers") public class TriggerResource { @Inject - TriggerApplicationService scheduleApplicationService; + TriggerService scheduleApplicationService; @Operation(summary = "获取单个触发器") @GET diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/TriggerApplicationService.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerService.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/application/TriggerApplicationService.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerService.java index 20f4cf22..2d55ee2a 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/TriggerApplicationService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/TriggerService.java @@ -1,28 +1,24 @@ -package dev.flexmodel.application; +package dev.flexmodel.scheduling; -import dev.flexmodel.domain.model.schedule.config.*; +import dev.flexmodel.scheduling.config.*; import io.vertx.mutiny.core.eventbus.EventBus; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import lombok.extern.slf4j.Slf4j; import org.quartz.*; -import dev.flexmodel.application.dto.PageDTO; -import dev.flexmodel.application.dto.TriggerDTO; -import dev.flexmodel.application.dto.TriggerPageRequest; -import dev.flexmodel.application.job.ScheduledFlowExecutionJob; +import dev.flexmodel.common.dto.PageDTO; +import dev.flexmodel.scheduling.dto.TriggerDTO; +import dev.flexmodel.scheduling.dto.TriggerPageRequest; +import dev.flexmodel.scheduling.job.ScheduledFlowExecutionJob; import dev.flexmodel.codegen.entity.FlowDeployment; import dev.flexmodel.codegen.entity.JobExecutionLog; import dev.flexmodel.codegen.entity.Trigger; -import dev.flexmodel.domain.model.flow.dto.StartProcessParamEvent; -import dev.flexmodel.domain.model.flow.service.FlowDeploymentService; -import dev.flexmodel.domain.model.schedule.JobExecutionLogService; -import dev.flexmodel.domain.model.schedule.TriggerException; -import dev.flexmodel.domain.model.schedule.TriggerService; -import dev.flexmodel.domain.model.schedule.config.*; +import dev.flexmodel.flow.dto.StartProcessParamEvent; +import dev.flexmodel.flow.service.FlowDeploymentService; import dev.flexmodel.query.Expressions; import dev.flexmodel.query.Predicate; -import dev.flexmodel.shared.SessionContextHolder; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.common.SessionContextHolder; +import dev.flexmodel.common.utils.JsonUtils; import java.time.LocalDateTime; import java.util.List; @@ -33,10 +29,10 @@ */ @Slf4j @ApplicationScoped -public class TriggerApplicationService { +public class TriggerService { @Inject - TriggerService triggerService; + TriggerRepository triggerRepository; @Inject FlowDeploymentService flowService; @Inject @@ -70,12 +66,12 @@ private TriggerDTO toTriggerDTO(Trigger trigger) { } public TriggerDTO findById(String projecjtId, String id) { - return toTriggerDTO(triggerService.findById(projecjtId, id)); + return toTriggerDTO(triggerRepository.findById(projecjtId, id)); } private String getJobGroup(Trigger trigger, TriggerConfig triggerConfig) { if (triggerConfig instanceof EventTriggerConfig eventTriggerConfig) { - return eventTriggerConfig.getDatasourceName() + "_" + eventTriggerConfig.getModelName(); + return trigger.getProjectId() + "_" + eventTriggerConfig.getModelName(); } else { if (triggerConfig instanceof ScheduledTriggerConfig) { FlowDeployment flowDeployment = flowService.findRecentByFlowModuleId(trigger.getProjectId(), trigger.getJobId()); @@ -91,7 +87,7 @@ private String getJobGroup(Trigger trigger, TriggerConfig triggerConfig) { public Trigger create(String projectId, Trigger trigger) { TriggerConfig triggerConfig = JsonUtils.getInstance().convertValue(trigger.getConfig(), TriggerConfig.class); trigger.setJobGroup(getJobGroup(trigger, triggerConfig)); - trigger = triggerService.save(projectId, trigger); + trigger = triggerRepository.save(projectId, trigger); // 规则校验 triggerConfig.validate(); if (triggerConfig instanceof ScheduledTriggerConfig scheduledTriggerConfig) { @@ -109,7 +105,7 @@ public Trigger create(String projectId, Trigger trigger) { // @Transactional public Trigger update(String projectId, Trigger req) { - Trigger record = triggerService.findById(projectId, req.getId()); + Trigger record = triggerRepository.findById(projectId, req.getId()); if (record == null) { throw new TriggerException("记录不存在"); } @@ -122,7 +118,7 @@ public Trigger update(String projectId, Trigger req) { // 规则校验 triggerConfig.validate(); req.setJobGroup(getJobGroup(req, triggerConfig)); - Trigger trigger = triggerService.save(projectId, req); + Trigger trigger = triggerRepository.save(projectId, req); if (triggerConfig instanceof ScheduledTriggerConfig scheduledTriggerConfig) { try { @@ -145,7 +141,7 @@ public Trigger update(String projectId, Trigger req) { } public void deleteById(String projectId, String id) { - Trigger record = triggerService.findById(projectId, id); + Trigger record = triggerRepository.findById(projectId, id); if (record != null) { // 实现定时任务调度 try { @@ -156,7 +152,7 @@ public void deleteById(String projectId, String id) { throw new TriggerException("删除定时任务失败: " + e.getMessage(), e); } } - triggerService.deleteById(projectId, id); + triggerRepository.deleteById(projectId, id); } public PageDTO findPage(String projectId, TriggerPageRequest request) { @@ -173,11 +169,11 @@ public PageDTO findPage(String projectId, TriggerPageRequest request if (request.getJobGroup() != null) { filter = filter.and(Expressions.field(Trigger::getJobGroup).eq(request.getJobGroup())); } - long total = triggerService.count(projectId, filter); + long total = triggerRepository.count(projectId, filter); if (total == 0) { return PageDTO.empty(); } - List triggers = triggerService.find(projectId, filter, request.getPage(), request.getSize()).stream() + List triggers = triggerRepository.find(projectId, filter, request.getPage(), request.getSize()).stream() .map(this::toTriggerDTO) .toList(); return new PageDTO<>(triggers, total); @@ -186,7 +182,7 @@ public PageDTO findPage(String projectId, TriggerPageRequest request public Trigger executeNow(String projectId, String id) { try { // 查找触发器 - Trigger trigger = triggerService.findById(projectId, id); + Trigger trigger = triggerRepository.findById(projectId, id); if (trigger == null) { throw new TriggerException("触发器不存在: " + id); } @@ -343,4 +339,7 @@ private org.quartz.Trigger createIntervalTrigger(TriggerBuilder getJobDetails(GroupMatcher matcher) throws JobPersistenceException { + try { + List jobDetails = jobRepository.findJobs(instanceName); + List list = new ArrayList<>(); + for (QrtzJobDetail jd : jobDetails) { + JobKey jobKey = new JobKey(jd.getJobName(), jd.getJobGroup()); + if (matcher.isMatch(jobKey)) { + try { + JobDetail jobDetail = deserializeJobDetail(jd); + // 叠加内存缓存的最新 JobDataMap(若存在) + JobDataMap cached = lastJobData.get(jobDetail.getKey()); + if (cached != null) { + jobDetail.getJobDataMap().putAll(cached); + } + list.add(jobDetail); + } catch (Exception ignored) { + } + } + } + return list; + } catch (Exception e) { + throw new JobPersistenceException("Failed to get job details", e); + } + } + @Override public void storeTrigger(OperableTrigger newTrigger, boolean replaceExisting) throws ObjectAlreadyExistsException, JobPersistenceException { try { @@ -448,6 +474,27 @@ public List getTriggersForJob(JobKey jobKey) throws JobPersiste } } + @Override + public List getTriggersByJobAndTriggerGroup(GroupMatcher jobMatcher, GroupMatcher triggerMatcher) throws JobPersistenceException { + try { + List triggers = jobRepository.findTriggers(instanceName); + List list = new ArrayList<>(); + for (QrtzTrigger t : triggers) { + JobKey jobKey = new JobKey(t.getJobName(), t.getJobGroup()); + TriggerKey triggerKey = new TriggerKey(t.getTriggerName(), t.getTriggerGroup()); + if (jobMatcher.isMatch(jobKey) && triggerMatcher.isMatch(triggerKey)) { + try { + list.add(deserializeTrigger(t)); + } catch (Exception ignored) { + } + } + } + return list; + } catch (Exception e) { + throw new JobPersistenceException("Failed to get triggers by job and trigger group", e); + } + } + @Override public Trigger.TriggerState getTriggerState(TriggerKey triggerKey) throws JobPersistenceException { try { diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/config/IntervalScheduledTriggerConfig.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/config/IntervalScheduledTriggerConfig.java similarity index 90% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/config/IntervalScheduledTriggerConfig.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/config/IntervalScheduledTriggerConfig.java index f00ac122..38213aaf 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/config/IntervalScheduledTriggerConfig.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/config/IntervalScheduledTriggerConfig.java @@ -1,8 +1,8 @@ -package dev.flexmodel.domain.model.schedule.config; +package dev.flexmodel.scheduling.config; import lombok.Getter; import lombok.Setter; -import dev.flexmodel.domain.model.schedule.TriggerException; +import dev.flexmodel.scheduling.TriggerException; /** * 间隔定时触发器配置类 diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/quartz/QuartzConfig.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/config/QuartzConfig.java similarity index 92% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/quartz/QuartzConfig.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/config/QuartzConfig.java index 9c88af50..a9338c01 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/quartz/QuartzConfig.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/config/QuartzConfig.java @@ -1,4 +1,4 @@ -package dev.flexmodel.infrastructure.quartz; +package dev.flexmodel.scheduling.config; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Produces; @@ -8,7 +8,7 @@ import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; import org.quartz.impl.StdSchedulerFactory; -import dev.flexmodel.application.job.ScheduledFlowExecutionJobListener; +import dev.flexmodel.scheduling.job.ScheduledFlowExecutionJobListener; import java.util.Properties; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/config/ScheduledTriggerConfig.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/config/ScheduledTriggerConfig.java similarity index 80% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/config/ScheduledTriggerConfig.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/config/ScheduledTriggerConfig.java index e16d0a36..2ab094d4 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/config/ScheduledTriggerConfig.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/config/ScheduledTriggerConfig.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.schedule.config; +package dev.flexmodel.scheduling.config; /** * 定时触发器配置抽象类 diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/config/TriggerConfig.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/config/TriggerConfig.java similarity index 82% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/config/TriggerConfig.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/config/TriggerConfig.java index 37d6663d..562eca60 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/schedule/config/TriggerConfig.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/config/TriggerConfig.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.schedule.config; +package dev.flexmodel.scheduling.config; /** * 触发器配置接口 diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/TriggerDTO.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/dto/TriggerDTO.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/TriggerDTO.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/dto/TriggerDTO.java index d9e12e69..2e2107d3 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/TriggerDTO.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/dto/TriggerDTO.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.scheduling.dto; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/TriggerPageRequest.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/dto/TriggerPageRequest.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/TriggerPageRequest.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/dto/TriggerPageRequest.java index a32f96f3..114f177a 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/TriggerPageRequest.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/dto/TriggerPageRequest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.scheduling.dto; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/job/ScheduledFlowExecutionJob.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/job/ScheduledFlowExecutionJob.java similarity index 93% rename from flexmodel-server/src/main/java/dev/flexmodel/application/job/ScheduledFlowExecutionJob.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/job/ScheduledFlowExecutionJob.java index c42d7644..676b6bb4 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/job/ScheduledFlowExecutionJob.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/job/ScheduledFlowExecutionJob.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.job; +package dev.flexmodel.scheduling.job; import io.vertx.mutiny.core.eventbus.EventBus; import jakarta.inject.Inject; @@ -6,8 +6,8 @@ import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; -import dev.flexmodel.domain.model.flow.dto.StartProcessParamEvent; -import dev.flexmodel.shared.SessionContextHolder; +import dev.flexmodel.flow.dto.StartProcessParamEvent; +import dev.flexmodel.common.SessionContextHolder; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/job/ScheduledFlowExecutionJobListener.java b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/job/ScheduledFlowExecutionJobListener.java similarity index 98% rename from flexmodel-server/src/main/java/dev/flexmodel/application/job/ScheduledFlowExecutionJobListener.java rename to flexmodel-server/src/main/java/dev/flexmodel/scheduling/job/ScheduledFlowExecutionJobListener.java index a8ddeffa..d25b5eb7 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/job/ScheduledFlowExecutionJobListener.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/scheduling/job/ScheduledFlowExecutionJobListener.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.job; +package dev.flexmodel.scheduling.job; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -7,7 +7,7 @@ import org.quartz.JobExecutionException; import org.quartz.JobListener; import dev.flexmodel.codegen.entity.JobExecutionLog; -import dev.flexmodel.domain.model.schedule.JobExecutionLogService; +import dev.flexmodel.scheduling.JobExecutionLogService; import java.io.PrintWriter; import java.io.StringWriter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/GlobalResource.java b/flexmodel-server/src/main/java/dev/flexmodel/settings/GlobalResource.java similarity index 85% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/GlobalResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/settings/GlobalResource.java index 30e4a7cc..347a3a22 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/GlobalResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/settings/GlobalResource.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.settings; import jakarta.annotation.security.PermitAll; import jakarta.inject.Inject; @@ -14,8 +14,8 @@ import org.eclipse.microprofile.openapi.annotations.media.SchemaProperty; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.SettingsApplicationService; -import dev.flexmodel.shared.FlexmodelConfig; +import dev.flexmodel.settings.SettingsService; +import dev.flexmodel.common.FlexmodelConfig; import java.util.Map; @@ -30,7 +30,7 @@ public class GlobalResource { @Inject - SettingsApplicationService settingsApplicationService; + SettingsService settingsService; @Inject FlexmodelConfig config; @@ -56,7 +56,7 @@ public class GlobalResource { @Path("/profile") @PermitAll public Map getProfile() { - return Map.of("settings", settingsApplicationService.getSettings(), + return Map.of("settings", settingsService.getSettings(), "apiRootPath", config.apiRootPath() ); } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/settings/Settings.java b/flexmodel-server/src/main/java/dev/flexmodel/settings/Settings.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/settings/Settings.java rename to flexmodel-server/src/main/java/dev/flexmodel/settings/Settings.java index 040e5d30..1fc8b988 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/settings/Settings.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/settings/Settings.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.settings; +package dev.flexmodel.settings; import lombok.Getter; import lombok.Setter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/settings/SettingsChanged.java b/flexmodel-server/src/main/java/dev/flexmodel/settings/SettingsChanged.java similarity index 82% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/settings/SettingsChanged.java rename to flexmodel-server/src/main/java/dev/flexmodel/settings/SettingsChanged.java index d5cf6f5e..f01ca63c 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/settings/SettingsChanged.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/settings/SettingsChanged.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.settings; +package dev.flexmodel.settings; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/SettingsFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/settings/SettingsFmRepository.java similarity index 88% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/SettingsFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/settings/SettingsFmRepository.java index 295e468a..8d2c0f67 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/SettingsFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/settings/SettingsFmRepository.java @@ -1,12 +1,10 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.settings; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import dev.flexmodel.codegen.entity.Config; -import dev.flexmodel.domain.model.settings.Settings; -import dev.flexmodel.domain.model.settings.SettingsRepository; import dev.flexmodel.session.Session; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.common.utils.JsonUtils; import java.util.HashMap; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/settings/SettingsRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/settings/SettingsRepository.java similarity index 75% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/settings/SettingsRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/settings/SettingsRepository.java index d47c747c..fd445f09 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/settings/SettingsRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/settings/SettingsRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.settings; +package dev.flexmodel.settings; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/SettingsResource.java b/flexmodel-server/src/main/java/dev/flexmodel/settings/SettingsResource.java similarity index 65% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/SettingsResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/settings/SettingsResource.java index 969dd572..72218269 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/SettingsResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/settings/SettingsResource.java @@ -1,12 +1,11 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.settings; import jakarta.inject.Inject; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.SettingsApplicationService; -import dev.flexmodel.domain.model.settings.Settings; +import dev.flexmodel.settings.SettingsService; /** * @author cjbi @@ -18,18 +17,18 @@ public class SettingsResource { @Inject - SettingsApplicationService settingsApplicationService; + SettingsService settingsService; @Operation(summary = "获取设置") @GET public Settings getSettings() { - return settingsApplicationService.getSettings(); + return settingsService.getSettings(); } @Operation(summary = "保存设置") @PATCH public Settings saveSettings(Settings settings) { - return settingsApplicationService.saveSettings(settings); + return settingsService.saveSettings(settings); } } diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/settings/SettingsService.java b/flexmodel-server/src/main/java/dev/flexmodel/settings/SettingsService.java similarity index 94% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/settings/SettingsService.java rename to flexmodel-server/src/main/java/dev/flexmodel/settings/SettingsService.java index 9b7e0be2..a9646f03 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/settings/SettingsService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/settings/SettingsService.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.settings; +package dev.flexmodel.settings; import io.quarkus.cache.CacheInvalidateAll; import io.quarkus.cache.CacheResult; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/consumer/SettingsEventConsumer.java b/flexmodel-server/src/main/java/dev/flexmodel/settings/consumer/SettingsEventConsumer.java similarity index 77% rename from flexmodel-server/src/main/java/dev/flexmodel/application/consumer/SettingsEventConsumer.java rename to flexmodel-server/src/main/java/dev/flexmodel/settings/consumer/SettingsEventConsumer.java index aa607a66..23b85290 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/consumer/SettingsEventConsumer.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/settings/consumer/SettingsEventConsumer.java @@ -1,10 +1,10 @@ -package dev.flexmodel.application.consumer; +package dev.flexmodel.settings.consumer; +import dev.flexmodel.settings.SettingsChanged; import io.quarkus.vertx.ConsumeEvent; import jakarta.enterprise.context.ApplicationScoped; import lombok.extern.slf4j.Slf4j; -import dev.flexmodel.domain.model.api.ApiRateLimiterHolder; -import dev.flexmodel.domain.model.settings.SettingsChanged; +import dev.flexmodel.api.ApiRateLimiterHolder; /** * @author cjbi diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FileItem.java b/flexmodel-server/src/main/java/dev/flexmodel/storage/FileItem.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/FileItem.java rename to flexmodel-server/src/main/java/dev/flexmodel/storage/FileItem.java index a53fc172..41bd7f6f 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/FileItem.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/storage/FileItem.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.storage; import lombok.Builder; import lombok.Data; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/StorageFmRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/storage/StorageFmRepository.java similarity index 95% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/StorageFmRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/storage/StorageFmRepository.java index f989eb58..59b7d43e 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/persistence/StorageFmRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/storage/StorageFmRepository.java @@ -1,8 +1,8 @@ -package dev.flexmodel.infrastructure.persistence; +package dev.flexmodel.storage; +import dev.flexmodel.common.AbstractRepository; import jakarta.enterprise.context.ApplicationScoped; import dev.flexmodel.codegen.entity.Storage; -import dev.flexmodel.domain.model.storage.StorageRepository; import dev.flexmodel.query.Predicate; import dev.flexmodel.session.Session; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/storage/StorageOperations.java b/flexmodel-server/src/main/java/dev/flexmodel/storage/StorageOperations.java similarity index 81% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/storage/StorageOperations.java rename to flexmodel-server/src/main/java/dev/flexmodel/storage/StorageOperations.java index fe3d7b51..299916fa 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/storage/StorageOperations.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/storage/StorageOperations.java @@ -1,6 +1,4 @@ -package dev.flexmodel.domain.model.storage; - -import dev.flexmodel.application.dto.FileItem; +package dev.flexmodel.storage; import java.io.InputStream; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/storage/StorageOperationsFactory.java b/flexmodel-server/src/main/java/dev/flexmodel/storage/StorageOperationsFactory.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/storage/StorageOperationsFactory.java rename to flexmodel-server/src/main/java/dev/flexmodel/storage/StorageOperationsFactory.java index 3399ac5b..8625b221 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/storage/StorageOperationsFactory.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/storage/StorageOperationsFactory.java @@ -1,10 +1,10 @@ -package dev.flexmodel.domain.model.storage; +package dev.flexmodel.storage; import dev.flexmodel.codegen.entity.Storage; import dev.flexmodel.codegen.enumeration.StorageType; -import dev.flexmodel.infrastructure.storage.LocalStorageOperations; -import dev.flexmodel.infrastructure.storage.S3StorageOperations; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.storage.config.LocalStorageOperations; +import dev.flexmodel.storage.config.S3StorageOperations; +import dev.flexmodel.common.utils.JsonUtils; import java.util.Map; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/storage/StorageRepository.java b/flexmodel-server/src/main/java/dev/flexmodel/storage/StorageRepository.java similarity index 91% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/storage/StorageRepository.java rename to flexmodel-server/src/main/java/dev/flexmodel/storage/StorageRepository.java index 594cb5f6..9b0fd0e8 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/storage/StorageRepository.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/storage/StorageRepository.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.storage; +package dev.flexmodel.storage; import dev.flexmodel.codegen.entity.Storage; import dev.flexmodel.query.Predicate; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/StorageResource.java b/flexmodel-server/src/main/java/dev/flexmodel/storage/StorageResource.java similarity index 98% rename from flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/StorageResource.java rename to flexmodel-server/src/main/java/dev/flexmodel/storage/StorageResource.java index cce4fb07..8925b5c6 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/interfaces/rest/StorageResource.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/storage/StorageResource.java @@ -1,4 +1,4 @@ -package dev.flexmodel.interfaces.rest; +package dev.flexmodel.storage; import jakarta.inject.Inject; import jakarta.validation.constraints.NotBlank; @@ -14,9 +14,7 @@ import org.eclipse.microprofile.openapi.annotations.parameters.Parameter; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import dev.flexmodel.application.dto.FileItem; import dev.flexmodel.codegen.entity.Storage; -import dev.flexmodel.domain.model.storage.StorageService; import java.io.InputStream; import java.util.List; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/storage/StorageService.java b/flexmodel-server/src/main/java/dev/flexmodel/storage/StorageService.java similarity index 97% rename from flexmodel-server/src/main/java/dev/flexmodel/domain/model/storage/StorageService.java rename to flexmodel-server/src/main/java/dev/flexmodel/storage/StorageService.java index 5a8fabca..90c1d656 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/domain/model/storage/StorageService.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/storage/StorageService.java @@ -1,8 +1,7 @@ -package dev.flexmodel.domain.model.storage; +package dev.flexmodel.storage; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import dev.flexmodel.application.dto.FileItem; import dev.flexmodel.codegen.entity.Storage; import java.io.InputStream; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/storage/LocalStorageOperations.java b/flexmodel-server/src/main/java/dev/flexmodel/storage/config/LocalStorageOperations.java similarity index 96% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/storage/LocalStorageOperations.java rename to flexmodel-server/src/main/java/dev/flexmodel/storage/config/LocalStorageOperations.java index e91b87bc..46bf87a3 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/storage/LocalStorageOperations.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/storage/config/LocalStorageOperations.java @@ -1,7 +1,7 @@ -package dev.flexmodel.infrastructure.storage; +package dev.flexmodel.storage.config; -import dev.flexmodel.application.dto.FileItem; -import dev.flexmodel.domain.model.storage.StorageOperations; +import dev.flexmodel.storage.FileItem; +import dev.flexmodel.storage.StorageOperations; import java.io.IOException; import java.io.InputStream; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/storage/S3StorageOperations.java b/flexmodel-server/src/main/java/dev/flexmodel/storage/config/S3StorageOperations.java similarity index 95% rename from flexmodel-server/src/main/java/dev/flexmodel/infrastructure/storage/S3StorageOperations.java rename to flexmodel-server/src/main/java/dev/flexmodel/storage/config/S3StorageOperations.java index 5c84ecea..a1318947 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/infrastructure/storage/S3StorageOperations.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/storage/config/S3StorageOperations.java @@ -1,7 +1,7 @@ -package dev.flexmodel.infrastructure.storage; +package dev.flexmodel.storage.config; -import dev.flexmodel.application.dto.FileItem; -import dev.flexmodel.domain.model.storage.StorageOperations; +import dev.flexmodel.storage.FileItem; +import dev.flexmodel.storage.StorageOperations; import java.io.InputStream; import java.util.ArrayList; diff --git a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ValidateStorageResult.java b/flexmodel-server/src/main/java/dev/flexmodel/storage/dto/ValidateStorageResult.java similarity index 89% rename from flexmodel-server/src/main/java/dev/flexmodel/application/dto/ValidateStorageResult.java rename to flexmodel-server/src/main/java/dev/flexmodel/storage/dto/ValidateStorageResult.java index 30a51e7c..07d5935a 100644 --- a/flexmodel-server/src/main/java/dev/flexmodel/application/dto/ValidateStorageResult.java +++ b/flexmodel-server/src/main/java/dev/flexmodel/storage/dto/ValidateStorageResult.java @@ -1,4 +1,4 @@ -package dev.flexmodel.application.dto; +package dev.flexmodel.storage.dto; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/flexmodel-server/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module b/flexmodel-server/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module index f15cf295..93573c51 100644 --- a/flexmodel-server/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module +++ b/flexmodel-server/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module @@ -1 +1 @@ -dev.flexmodel.interfaces.rest.json.jackson.FlexmodelServerModule +dev.flexmodel.common.config.web.json.jackson.FlexmodelServerModule diff --git a/flexmodel-server/src/main/resources/data.json b/flexmodel-server/src/main/resources/data.json deleted file mode 100644 index f813177e..00000000 --- a/flexmodel-server/src/main/resources/data.json +++ /dev/null @@ -1,676 +0,0 @@ -{ - "data": [ - { - "modelName": "f_project", - "values": [ - { - "id": "default", - "name": "系统默认", - "database_name": "system", - "description": "默认项目", - "owner_id": "admin", - "enabled": true - }, - { - "id": "dev_test", - "database_name": "dev_test", - "name": "开发测试", - "description": "开发测试项目", - "owner_id": "admin", - "enabled": true - } - ] - }, - { - "modelName": "f_user", - "values": [ - { - "id": "admin", - "name": "Admin", - "password_hash": "172eee54aa664e9dd0536b063796e54e", - "created_at": "2025-08-30 19:58:23.000", - "role_ids": "admin" - } - ] - }, - { - "modelName": "f_role", - "values": [ - { - "id": "admin", - "name": "管理员", - "description": "管理员拥有所有权限", - "resource_ids": "1" - }, - { - "id": "developer", - "name": "开发", - "description": "开发人员拥有项目管理权限", - "resource_ids": "100" - } - ] - }, - { - "modelName": "f_resource", - "values": [ - { - "id": 1, - "name": "所有资源", - "permission": "*", - "type": "system", - "parent_id": null - }, - { - "id": 100, - "name": "项目", - "permission": "project:*", - "type": "system", - "parent_id": 1 - }, - { - "id": 101, - "name": "查看项目", - "permission": "project:view", - "type": "system", - "parent_id": 100 - }, - { - "id": 102, - "name": "新增项目", - "permission": "project:create", - "type": "system", - "parent_id": 100 - }, - { - "id": 103, - "name": "删除项目", - "permission": "project:delete", - "type": "system", - "parent_id": 100 - }, - { - "id": 104, - "name": "项目详情", - "permission": "project:detail:*", - "type": "project", - "parent_id": 100 - }, - { - "id": 200, - "name": "成员", - "permission": "member:*", - "type": "system", - "parent_id": 1 - }, - { - "id": 201, - "name": "用户", - "permission": "member:user:*", - "type": "system", - "parent_id": 200 - }, - { - "id": 202, - "name": "新增用户", - "permission": "member:user:create", - "type": "system", - "parent_id": 201 - }, - { - "id": 203, - "name": "修改用户", - "permission": "member:user:update", - "type": "system", - "parent_id": 201 - }, - { - "id": 204, - "name": "删除用户", - "permission": "member:user:delete", - "type": "system", - "parent_id": 201 - }, - { - "id": 205, - "name": "角色", - "permission": "member:role:*", - "type": "system", - "parent_id": 200 - }, - { - "id": 206, - "name": "新增角色", - "permission": "member:role:create", - "type": "system", - "parent_id": 205 - }, - { - "id": 207, - "name": "修改角色", - "permission": "member:role:update", - "type": "system", - "parent_id": 205 - }, - { - "id": 208, - "name": "删除角色", - "permission": "member:role:delete", - "type": "system", - "parent_id": 205 - }, - { - "id": 300, - "name": "设置", - "permission": "settings:*", - "type": "system", - "parent_id": 1 - }, - { - "id": 301, - "name": "查看", - "permission": "settings:view", - "type": "system", - "parent_id": 300 - }, - { - "id": 302, - "name": "保存", - "permission": "settings:save", - "type": "system", - "parent_id": 300 - } - ] - }, - { - "modelName": "f_datasource", - "values": [ - { - "name": "system", - "type": "SYSTEM", - "config": { - "url": "${flexmodel.datasource.url}", - "dbKind": "${flexmodel.datasource.db-kind}", - "password": "${flexmodel.datasource.password}", - "username": "${flexmodel.datasource.username}" - }, - "project_id": "default" - }, - { - "name": "dev_test", - "type": "USER", - "config": { - "url": "jdbc:sqlite:file:sqlite_dev_test.db", - "dbKind": "sqlite", - "password": "", - "username": "" - }, - "project_id": "dev_test" - }, - { - "name": "sqlite_test", - "type": "USER", - "config": { - "url": "jdbc:sqlite:file::memory:?cache=shared", - "dbKind": "sqlite", - "password": "", - "username": "" - }, - "project_id": "dev_test" - } - ] - }, - { - "modelName": "f_em_flow_definition", - "values": [ - { - "flow_module_id": "22203aa0-5f25-4b8a-974d-e4288c1bbd18", - "flow_name": "日志归档流程", - "flow_key": "log_archive_task", - "flow_model": "{\"flowElementList\":[{\"key\":\"start-node\",\"type\":2,\"incoming\":[],\"outgoing\":[\"SequenceFlow_mgxfy945jnpgtk\"],\"properties\":{\"positionX\":-112,\"positionY\":96}},{\"key\":\"end-node\",\"type\":3,\"incoming\":[\"SequenceFlow_mgxgy62ycwn9ca\"],\"outgoing\":[],\"properties\":{\"positionX\":576,\"positionY\":80}},{\"key\":\"serviceTask_mgxfv7fk1v40d9\",\"type\":5,\"incoming\":[\"SequenceFlow_mgxfy945jnpgtk\"],\"outgoing\":[\"SequenceFlow_mgxgy4t2xqtz2x\"],\"properties\":{\"subType\":\"sql\",\"datasourceName\":\"system\",\"script\":\"create table if not exists `f_api_request_log_202510`\\r\\n(\\r\\n `id` varchar(255) not null,\\r\\n `url` varchar(2000) not null comment '请求地址',\\r\\n `http_method` varchar(255) not null comment '请求方法',\\r\\n `path` varchar(1000) not null comment '请求路径',\\r\\n `request_body` json not null comment '请求参数',\\r\\n `request_headers` json not null comment '请求头',\\r\\n `status_code` int not null,\\r\\n `response_time` int not null,\\r\\n `client_ip` varchar(45) default null comment 'ip地址',\\r\\n `created_at` datetime null,\\r\\n `is_success` bit(1) not null default false comment '是否成功',\\r\\n `error_message` json default null comment '异常信息',\\r\\n `project_id` varchar(255) default null comment '业务方标识',\\r\\n primary key (`id`),\\r\\n key `idx_api_request_log_202510_created_at` (`created_at`),\\r\\n key `idx_api_request_log_202510_is_error` (`is_success`)\\r\\n) comment ='api请求日志归档202510'\",\"name\":\"创建日志归档表\",\"positionX\":96,\"positionY\":80}},{\"key\":\"serviceTask_mgxgqm93or1gtt\",\"type\":5,\"incoming\":[\"SequenceFlow_mgxgy4t2xqtz2x\"],\"outgoing\":[\"SequenceFlow_mgxgy62ycwn9ca\"],\"properties\":{\"subType\":\"sql\",\"datasourceName\":\"system\",\"script\":\"INSERT INTO f_api_request_log_202510 (id, url, http_method, path, request_body, request_headers, status_code,\\r\\n response_time, created_at, client_ip, is_success, error_message,\\r\\n project_id)\\r\\nVALUES ('${context.data.id}','${context.data.url}', '${context.data.http_method}', '${context.data.path}', '{}', '{}',\\r\\n ${context.data.status_code}, '${context.data.response_time}','${context.data.created_at}', '${context.data.client_ip}', ${context.data.is_success}, '${context.data.error_message}', '${context.data.project_id}')\",\"name\":\"写入归档数据\",\"positionX\":336,\"positionY\":80}},{\"key\":\"SequenceFlow_mgxfy945jnpgtk\",\"type\":1,\"incoming\":[\"start-node\"],\"outgoing\":[\"serviceTask_mgxfv7fk1v40d9\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgxgy4t2xqtz2x\",\"type\":1,\"incoming\":[\"serviceTask_mgxfv7fk1v40d9\"],\"outgoing\":[\"serviceTask_mgxgqm93or1gtt\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgxgy62ycwn9ca\",\"type\":1,\"incoming\":[\"serviceTask_mgxgqm93or1gtt\"],\"outgoing\":[\"end-node\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}}]}", - "status": 2, - "create_time": "2025-10-19 19:51:42", - "modify_time": "2025-10-19 19:51:42", - "operator": "admin", - "remark": "通过sql执行日志归档", - "archive": 0, - "caller": "admin", - "is_deleted": false, - "project_id": "default", - "created_by": null, - "updated_by": null, - "created_at": "2025-10-19 19:51:42", - "updated_at": "2025-10-19 19:51:42" - }, - { - "flow_module_id": "5c41f37a-87a9-47af-bdba-44d0c27eda89", - "flow_name": "testFlowName_1757909108656", - "flow_key": "testFlowKey_1757909108656", - "flow_model": "{\"flowElementList\":[{\"key\":\"startEvent1\",\"type\":2,\"outgoing\":[\"sequenceFlow1\"]},{\"key\":\"sequenceFlow1\",\"type\":1,\"outgoing\":[\"userTask1\"],\"incoming\":[\"startEvent1\"]},{\"key\":\"userTask1\",\"type\":4,\"outgoing\":[\"sequenceFlow2\"],\"incoming\":[\"sequenceFlow1\"]},{\"key\":\"sequenceFlow2\",\"type\":1,\"outgoing\":[\"exclusiveGateway1\"],\"incoming\":[\"userTask1\"]},{\"key\":\"exclusiveGateway1\",\"type\":6,\"outgoing\":[\"sequenceFlow3\",\"sequenceFlow4\"],\"properties\":{\"hookInfoIds\":\"[1,2]\"},\"incoming\":[\"sequenceFlow2\"]},{\"key\":\"sequenceFlow3\",\"type\":1,\"outgoing\":[\"userTask2\"],\"properties\":{\"conditionsequenceflow\":\"a>1&&b==1\"},\"incoming\":[\"exclusiveGateway1\"]},{\"key\":\"sequenceFlow4\",\"type\":1,\"outgoing\":[\"userTask3\"],\"properties\":{\"defaultConditions\":\"true\"},\"incoming\":[\"exclusiveGateway1\"]},{\"key\":\"userTask2\",\"type\":4,\"outgoing\":[\"sequenceFlow5\"],\"incoming\":[\"sequenceFlow3\"]},{\"key\":\"userTask3\",\"type\":4,\"outgoing\":[\"sequenceFlow6\"],\"incoming\":[\"sequenceFlow4\"]},{\"key\":\"sequenceFlow5\",\"type\":1,\"outgoing\":[\"endEvent1\"],\"incoming\":[\"userTask2\"]},{\"key\":\"sequenceFlow6\",\"type\":1,\"outgoing\":[\"endEvent2\"],\"incoming\":[\"userTask3\"]},{\"key\":\"endEvent1\",\"type\":3,\"incoming\":[\"sequenceFlow5\"]},{\"key\":\"endEvent2\",\"type\":3,\"incoming\":[\"sequenceFlow6\"]}]}", - "status": 2, - "create_time": "2025-09-15 12:05:09.000", - "modify_time": "2025-09-15 12:05:09.000", - "operator": "testOperator", - "remark": "testRemark", - "archive": 0, - "caller": "testCaller", - "project_id": "dev_test" - }, - { - "flow_module_id": "9243be36-9ced-4413-acd5-5fc93a05c698", - "flow_name": "脚本测试", - "flow_key": "script_test", - "flow_model": "{\"flowElementList\":[{\"key\":\"start-node\",\"type\":2,\"incoming\":[],\"outgoing\":[\"SequenceFlow_miclvtzacagocb\"],\"properties\":{\"positionX\":-96,\"positionY\":64,\"name\":\"Start\"}},{\"key\":\"end-node\",\"type\":3,\"incoming\":[\"SequenceFlow_miclvvbzb9t82p\"],\"outgoing\":[],\"properties\":{\"positionX\":800,\"positionY\":48,\"name\":\"End\"}},{\"key\":\"serviceTask_miclvseffazfuf\",\"type\":5,\"incoming\":[\"SequenceFlow_miclvtzacagocb\"],\"outgoing\":[\"SequenceFlow_miclvvbzb9t82p\"],\"properties\":{\"subType\":\"script\",\"script\":\"\\\"hello world\\\";\",\"name\":\"\",\"positionX\":320,\"positionY\":48}},{\"key\":\"SequenceFlow_miclvtzacagocb\",\"type\":1,\"incoming\":[\"start-node\"],\"outgoing\":[\"serviceTask_miclvseffazfuf\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_miclvvbzb9t82p\",\"type\":1,\"incoming\":[\"serviceTask_miclvseffazfuf\"],\"outgoing\":[\"end-node\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}}]}", - "status": 2, - "create_time": "2025-10-14T11:23:02.659", - "modify_time": "2025-10-14T11:23:02.660", - "operator": "admin", - "remark": "Javascript脚本测试", - "archive": 0, - "caller": "admin", - "project_id": "dev_test" - }, - { - "flow_module_id": "da5835fe-e82a-447f-b614-c0ce9aaecb78", - "flow_name": "增删改查测试", - "flow_key": "crud_test", - "flow_model": "{\"flowElementList\":[{\"key\":\"start-node\",\"type\":2,\"incoming\":[],\"outgoing\":[\"SequenceFlow_mgoksf9skg7m1c\"],\"properties\":{\"positionX\":-496,\"positionY\":48}},{\"key\":\"end-node\",\"type\":3,\"incoming\":[\"SequenceFlow_mgolxly85affbh\"],\"outgoing\":[],\"properties\":{\"positionX\":1408,\"positionY\":48}},{\"key\":\"serviceTask_mgokolh6ottxgz\",\"type\":5,\"incoming\":[\"SequenceFlow_mgoksf9skg7m1c\"],\"outgoing\":[\"SequenceFlow_mgokv2z5j6tju7\"],\"properties\":{\"subType\":\"insert_record\",\"datasourceName\":\"dev_test\",\"modelName\":\"Teacher\",\"document\":[{\"field\":\"teacherName\",\"value\":\"张三丰\"},{\"field\":\"subject\",\"value\":\"太极\"}],\"resultPath\":\"teacherInsertAffectedRows\",\"name\":\"新增教师张三丰\",\"positionX\":-336,\"positionY\":32}},{\"key\":\"serviceTask_mgokspzb8h72r0\",\"type\":5,\"incoming\":[\"SequenceFlow_mgokv2z5j6tju7\"],\"outgoing\":[\"SequenceFlow_mgpv7i2gpvk0qg\"],\"properties\":{\"subType\":\"update_record\",\"datasourceName\":\"dev_test\",\"modelName\":\"Teacher\",\"document\":[{\"field\":\"subject\",\"value\":\"太极张三丰\"}],\"filter\":\"{\\\"teacherName\\\":{\\\"_eq\\\":\\\"张三丰\\\"}}\",\"resultPath\":\"teacherUpdateAffectedRows\",\"name\":\"更新教师张三丰\",\"positionX\":-112,\"positionY\":32}},{\"key\":\"serviceTask_mgokvj54kxi9pj\",\"type\":5,\"incoming\":[\"SequenceFlow_mgpvhe0tlgy2hs\"],\"outgoing\":[\"SequenceFlow_mgokyc4xwquno6\"],\"properties\":{\"subType\":\"query_record\",\"datasourceName\":\"dev_test\",\"modelName\":\"Student\",\"filter\":\"\",\"sort\":\"[{\\\"field\\\":\\\"id\\\",\\\"order\\\":\\\"desc\\\"}]\",\"page\":1,\"size\":1000,\"resultPath\":\"students\",\"name\":\"查询学生\",\"positionX\":544,\"positionY\":32}},{\"key\":\"serviceTask_mgoky18vc65fea\",\"type\":5,\"incoming\":[\"SequenceFlow_mgokyc4xwquno6\"],\"outgoing\":[\"SequenceFlow_mgolse1rjjms9t\"],\"properties\":{\"subType\":\"insert_record\",\"inputPath\":\"students\",\"datasourceName\":\"dev_test\",\"modelName\":\"Student\",\"document\":[{\"field\":\"studentName\",\"value\":\"${studentName}2\"},{\"field\":\"gender\",\"value\":\"${gender}\"},{\"field\":\"interest\",\"value\":\"${interest}\"},{\"field\":\"age\",\"value\":\"${age}\"},{\"field\":\"classId\",\"value\":\"${classId}\"}],\"resultPath\":\"studentInsertAffectedRows\",\"name\":\"新增学生\",\"positionX\":752,\"positionY\":32}},{\"key\":\"serviceTask_mgoli5cpsdyy77\",\"type\":5,\"incoming\":[\"SequenceFlow_mgolse1rjjms9t\"],\"outgoing\":[\"SequenceFlow_mgolsrsrj4yfkj\"],\"properties\":{\"subType\":\"update_record\",\"inputPath\":\"students\",\"datasourceName\":\"dev_test\",\"modelName\":\"Student\",\"document\":[{\"field\":\"classId\",\"value\":\"3\"}],\"filter\":\"{\\n \\\"studentName\\\":{\\\"_ends_with\\\":\\\"2\\\"}\\n}\",\"resultPath\":\"studentUpdateAffectedRows\",\"name\":\"更新学生信息\",\"positionX\":960,\"positionY\":32}},{\"key\":\"serviceTask_mgolsqgfgrdmat\",\"type\":5,\"incoming\":[\"SequenceFlow_mgolsrsrj4yfkj\"],\"outgoing\":[\"SequenceFlow_mgolxly85affbh\"],\"properties\":{\"subType\":\"delete_record\",\"resultPath\":\"studentDeleteAffectedRows\",\"name\":\"删除学生信息\",\"positionX\":1200,\"positionY\":32,\"datasourceName\":\"dev_test\",\"modelName\":\"Student\",\"filter\":\"{\\n \\\"studentName\\\":{\\\"_ends_with\\\":\\\"2\\\"}\\n}\"}},{\"key\":\"serviceTask_mgpv6wp7oavt4f\",\"type\":5,\"incoming\":[\"SequenceFlow_mgpv7i2gpvk0qg\"],\"outgoing\":[\"SequenceFlow_mgpvhb6p3dm76o\"],\"properties\":{\"subType\":\"query_record\",\"datasourceName\":\"dev_test\",\"modelName\":\"Teacher\",\"filter\":\"{\\\"teacherName\\\":{\\\"_eq\\\":\\\"张三丰\\\"}}\",\"resultPath\":\"teachers\",\"name\":\"查询教师张三丰\",\"positionX\":96,\"positionY\":32}},{\"key\":\"serviceTask_mgpvgobas8eee4\",\"type\":5,\"incoming\":[\"SequenceFlow_mgpvhb6p3dm76o\"],\"outgoing\":[\"SequenceFlow_mgpvhe0tlgy2hs\"],\"properties\":{\"subType\":\"delete_record\",\"datasourceName\":\"dev_test\",\"modelName\":\"Teacher\",\"filter\":\"{\\\"teacherName\\\":{\\\"_eq\\\":\\\"张三丰\\\"}}\",\"resultPath\":\"teacherDeleteAffectedRows\",\"name\":\"删除教师张三丰\",\"positionX\":320,\"positionY\":32}},{\"key\":\"SequenceFlow_mgoksf9skg7m1c\",\"type\":1,\"incoming\":[\"start-node\"],\"outgoing\":[\"serviceTask_mgokolh6ottxgz\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgokv2z5j6tju7\",\"type\":1,\"incoming\":[\"serviceTask_mgokolh6ottxgz\"],\"outgoing\":[\"serviceTask_mgokspzb8h72r0\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgokyc4xwquno6\",\"type\":1,\"incoming\":[\"serviceTask_mgokvj54kxi9pj\"],\"outgoing\":[\"serviceTask_mgoky18vc65fea\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgolse1rjjms9t\",\"type\":1,\"incoming\":[\"serviceTask_mgoky18vc65fea\"],\"outgoing\":[\"serviceTask_mgoli5cpsdyy77\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgolsrsrj4yfkj\",\"type\":1,\"incoming\":[\"serviceTask_mgoli5cpsdyy77\"],\"outgoing\":[\"serviceTask_mgolsqgfgrdmat\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgolxly85affbh\",\"type\":1,\"incoming\":[\"serviceTask_mgolsqgfgrdmat\"],\"outgoing\":[\"end-node\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgpv7i2gpvk0qg\",\"type\":1,\"incoming\":[\"serviceTask_mgokspzb8h72r0\"],\"outgoing\":[\"serviceTask_mgpv6wp7oavt4f\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgpvhb6p3dm76o\",\"type\":1,\"incoming\":[\"serviceTask_mgpv6wp7oavt4f\"],\"outgoing\":[\"serviceTask_mgpvgobas8eee4\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgpvhe0tlgy2hs\",\"type\":1,\"incoming\":[\"serviceTask_mgpvgobas8eee4\"],\"outgoing\":[\"serviceTask_mgokvj54kxi9pj\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}}]}", - "status": 2, - "create_time": "2025-09-15 12:05:09.000", - "modify_time": "2025-09-15 12:05:09.000", - "operator": "admin", - "remark": "增删改查测试", - "archive": 0, - "project_id": "dev_test" - } - ] - }, - { - "modelName": "f_em_flow_deployment", - "values": [ - { - "flow_deploy_id": "96933bb6-4e5a-43f2-9d0a-61b3fb7111fa", - "flow_module_id": "22203aa0-5f25-4b8a-974d-e4288c1bbd18", - "flow_name": "日志归档流程", - "flow_key": "log_archive_task", - "flow_model": "{\"flowElementList\":[{\"key\":\"start-node\",\"type\":2,\"incoming\":[],\"outgoing\":[\"SequenceFlow_mgxfy945jnpgtk\"],\"properties\":{\"positionX\":-112,\"positionY\":96}},{\"key\":\"end-node\",\"type\":3,\"incoming\":[\"SequenceFlow_mgxgy62ycwn9ca\"],\"outgoing\":[],\"properties\":{\"positionX\":576,\"positionY\":80}},{\"key\":\"serviceTask_mgxfv7fk1v40d9\",\"type\":5,\"incoming\":[\"SequenceFlow_mgxfy945jnpgtk\"],\"outgoing\":[\"SequenceFlow_mgxgy4t2xqtz2x\"],\"properties\":{\"subType\":\"sql\",\"datasourceName\":\"system\",\"script\":\"create table if not exists `f_api_request_log_202510`\\r\\n(\\r\\n `id` varchar(255) not null,\\r\\n `url` varchar(2000) not null comment '请求地址',\\r\\n `http_method` varchar(255) not null comment '请求方法',\\r\\n `path` varchar(1000) not null comment '请求路径',\\r\\n `request_body` json not null comment '请求参数',\\r\\n `request_headers` json not null comment '请求头',\\r\\n `status_code` int not null,\\r\\n `response_time` int not null,\\r\\n `client_ip` varchar(45) default null comment 'ip地址',\\r\\n `created_at` datetime null,\\r\\n `is_success` bit(1) not null default false comment '是否成功',\\r\\n `error_message` json default null comment '异常信息',\\r\\n `project_id` varchar(255) default null comment '业务方标识',\\r\\n primary key (`id`),\\r\\n key `idx_api_request_log_202510_created_at` (`created_at`),\\r\\n key `idx_api_request_log_202510_is_error` (`is_success`)\\r\\n) comment ='api请求日志归档202510'\",\"name\":\"创建日志归档表\",\"positionX\":96,\"positionY\":80}},{\"key\":\"serviceTask_mgxgqm93or1gtt\",\"type\":5,\"incoming\":[\"SequenceFlow_mgxgy4t2xqtz2x\"],\"outgoing\":[\"SequenceFlow_mgxgy62ycwn9ca\"],\"properties\":{\"subType\":\"sql\",\"datasourceName\":\"system\",\"script\":\"INSERT INTO f_api_request_log_202510 (id, url, http_method, path, request_body, request_headers, status_code,\\r\\n response_time, created_at, client_ip, is_success, error_message,\\r\\n project_id)\\r\\nVALUES ('${context.data.id}','${context.data.url}', '${context.data.http_method}', '${context.data.path}', '{}', '{}',\\r\\n ${context.data.status_code}, '${context.data.response_time}','${context.data.created_at}', '${context.data.client_ip}', ${context.data.is_success}, '${context.data.error_message}', '${context.data.project_id}')\",\"name\":\"写入归档数据\",\"positionX\":336,\"positionY\":80}},{\"key\":\"SequenceFlow_mgxfy945jnpgtk\",\"type\":1,\"incoming\":[\"start-node\"],\"outgoing\":[\"serviceTask_mgxfv7fk1v40d9\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgxgy4t2xqtz2x\",\"type\":1,\"incoming\":[\"serviceTask_mgxfv7fk1v40d9\"],\"outgoing\":[\"serviceTask_mgxgqm93or1gtt\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgxgy62ycwn9ca\",\"type\":1,\"incoming\":[\"serviceTask_mgxgqm93or1gtt\"],\"outgoing\":[\"end-node\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}}]}", - "status": 1, - "create_time": "2025-10-19 19:51:42", - "modify_time": "2025-10-19 19:51:42", - "operator": "admin", - "remark": "通过sql执行日志归档", - "archive": 0, - "caller": "admin", - "project_id": "default", - "created_by": null, - "updated_by": null, - "created_at": "2025-10-19 19:51:42", - "updated_at": "2025-10-19 19:51:42" - }, - { - "flow_deploy_id": "c2d6f2bb-0d7b-4eb0-81a6-5a72262740d4", - "flow_module_id": "5c41f37a-87a9-47af-bdba-44d0c27eda89", - "flow_name": "testFlowName_1757909108656", - "flow_key": "testFlowKey_1757909108656", - "flow_model": "{\"flowElementList\":[{\"key\":\"startEvent1\",\"type\":2,\"outgoing\":[\"sequenceFlow1\"]},{\"key\":\"sequenceFlow1\",\"type\":1,\"outgoing\":[\"userTask1\"],\"incoming\":[\"startEvent1\"]},{\"key\":\"userTask1\",\"type\":4,\"outgoing\":[\"sequenceFlow2\"],\"incoming\":[\"sequenceFlow1\"]},{\"key\":\"sequenceFlow2\",\"type\":1,\"outgoing\":[\"exclusiveGateway1\"],\"incoming\":[\"userTask1\"]},{\"key\":\"exclusiveGateway1\",\"type\":6,\"outgoing\":[\"sequenceFlow3\",\"sequenceFlow4\"],\"properties\":{\"hookInfoIds\":\"[1,2]\"},\"incoming\":[\"sequenceFlow2\"]},{\"key\":\"sequenceFlow3\",\"type\":1,\"outgoing\":[\"userTask2\"],\"properties\":{\"conditionsequenceflow\":\"a>1&&b==1\"},\"incoming\":[\"exclusiveGateway1\"]},{\"key\":\"sequenceFlow4\",\"type\":1,\"outgoing\":[\"userTask3\"],\"properties\":{\"defaultConditions\":\"true\"},\"incoming\":[\"exclusiveGateway1\"]},{\"key\":\"userTask2\",\"type\":4,\"outgoing\":[\"sequenceFlow5\"],\"incoming\":[\"sequenceFlow3\"]},{\"key\":\"userTask3\",\"type\":4,\"outgoing\":[\"sequenceFlow6\"],\"incoming\":[\"sequenceFlow4\"]},{\"key\":\"sequenceFlow5\",\"type\":1,\"outgoing\":[\"endEvent1\"],\"incoming\":[\"userTask2\"]},{\"key\":\"sequenceFlow6\",\"type\":1,\"outgoing\":[\"endEvent2\"],\"incoming\":[\"userTask3\"]},{\"key\":\"endEvent1\",\"type\":3,\"incoming\":[\"sequenceFlow5\"]},{\"key\":\"endEvent2\",\"type\":3,\"incoming\":[\"sequenceFlow6\"]}]}", - "status": 1, - "create_time": "2025-09-15 12:05:09.000", - "modify_time": "2025-09-15 12:05:09.000", - "operator": "testOperator", - "remark": "testRemark", - "archive": 0, - "caller": "testCaller", - "project_id": "dev_test" - }, - { - "flow_deploy_id": "fce9c1e9-57dd-483e-bba1-dd7cb5a53ca7", - "flow_module_id": "da5835fe-e82a-447f-b614-c0ce9aaecb78", - "flow_name": "增删改查测试", - "flow_key": "crud_test", - "flow_model": "{\"flowElementList\":[{\"key\":\"start-node\",\"type\":2,\"incoming\":[],\"outgoing\":[\"SequenceFlow_mgoksf9skg7m1c\"],\"properties\":{\"positionX\":-496,\"positionY\":48}},{\"key\":\"end-node\",\"type\":3,\"incoming\":[\"SequenceFlow_mgolxly85affbh\"],\"outgoing\":[],\"properties\":{\"positionX\":1408,\"positionY\":48}},{\"key\":\"serviceTask_mgokolh6ottxgz\",\"type\":5,\"incoming\":[\"SequenceFlow_mgoksf9skg7m1c\"],\"outgoing\":[\"SequenceFlow_mgokv2z5j6tju7\"],\"properties\":{\"subType\":\"insert_record\",\"datasourceName\":\"dev_test\",\"modelName\":\"Teacher\",\"document\":[{\"field\":\"teacherName\",\"value\":\"张三丰\"},{\"field\":\"subject\",\"value\":\"太极\"}],\"resultPath\":\"teacherInsertAffectedRows\",\"name\":\"新增教师张三丰\",\"positionX\":-336,\"positionY\":32}},{\"key\":\"serviceTask_mgokspzb8h72r0\",\"type\":5,\"incoming\":[\"SequenceFlow_mgokv2z5j6tju7\"],\"outgoing\":[\"SequenceFlow_mgpv7i2gpvk0qg\"],\"properties\":{\"subType\":\"update_record\",\"datasourceName\":\"dev_test\",\"modelName\":\"Teacher\",\"document\":[{\"field\":\"subject\",\"value\":\"太极张三丰\"}],\"filter\":\"{\\\"teacherName\\\":{\\\"_eq\\\":\\\"张三丰\\\"}}\",\"resultPath\":\"teacherUpdateAffectedRows\",\"name\":\"更新教师张三丰\",\"positionX\":-112,\"positionY\":32}},{\"key\":\"serviceTask_mgokvj54kxi9pj\",\"type\":5,\"incoming\":[\"SequenceFlow_mgpvhe0tlgy2hs\"],\"outgoing\":[\"SequenceFlow_mgokyc4xwquno6\"],\"properties\":{\"subType\":\"query_record\",\"datasourceName\":\"dev_test\",\"modelName\":\"Student\",\"filter\":\"\",\"sort\":\"[{\\\"field\\\":\\\"id\\\",\\\"order\\\":\\\"desc\\\"}]\",\"page\":1,\"size\":1000,\"resultPath\":\"students\",\"name\":\"查询学生\",\"positionX\":544,\"positionY\":32}},{\"key\":\"serviceTask_mgoky18vc65fea\",\"type\":5,\"incoming\":[\"SequenceFlow_mgokyc4xwquno6\"],\"outgoing\":[\"SequenceFlow_mgolse1rjjms9t\"],\"properties\":{\"subType\":\"insert_record\",\"inputPath\":\"students\",\"datasourceName\":\"dev_test\",\"modelName\":\"Student\",\"document\":[{\"field\":\"studentName\",\"value\":\"${studentName}2\"},{\"field\":\"gender\",\"value\":\"${gender}\"},{\"field\":\"interest\",\"value\":\"${interest}\"},{\"field\":\"age\",\"value\":\"${age}\"},{\"field\":\"classId\",\"value\":\"${classId}\"}],\"resultPath\":\"studentInsertAffectedRows\",\"name\":\"新增学生\",\"positionX\":752,\"positionY\":32}},{\"key\":\"serviceTask_mgoli5cpsdyy77\",\"type\":5,\"incoming\":[\"SequenceFlow_mgolse1rjjms9t\"],\"outgoing\":[\"SequenceFlow_mgolsrsrj4yfkj\"],\"properties\":{\"subType\":\"update_record\",\"inputPath\":\"students\",\"datasourceName\":\"dev_test\",\"modelName\":\"Student\",\"document\":[{\"field\":\"classId\",\"value\":\"3\"}],\"filter\":\"{\\n \\\"studentName\\\":{\\\"_ends_with\\\":\\\"2\\\"}\\n}\",\"resultPath\":\"studentUpdateAffectedRows\",\"name\":\"更新学生信息\",\"positionX\":960,\"positionY\":32}},{\"key\":\"serviceTask_mgolsqgfgrdmat\",\"type\":5,\"incoming\":[\"SequenceFlow_mgolsrsrj4yfkj\"],\"outgoing\":[\"SequenceFlow_mgolxly85affbh\"],\"properties\":{\"subType\":\"delete_record\",\"resultPath\":\"studentDeleteAffectedRows\",\"name\":\"删除学生信息\",\"positionX\":1200,\"positionY\":32,\"datasourceName\":\"dev_test\",\"modelName\":\"Student\",\"filter\":\"{\\n \\\"studentName\\\":{\\\"_ends_with\\\":\\\"2\\\"}\\n}\"}},{\"key\":\"serviceTask_mgpv6wp7oavt4f\",\"type\":5,\"incoming\":[\"SequenceFlow_mgpv7i2gpvk0qg\"],\"outgoing\":[\"SequenceFlow_mgpvhb6p3dm76o\"],\"properties\":{\"subType\":\"query_record\",\"datasourceName\":\"dev_test\",\"modelName\":\"Teacher\",\"filter\":\"{\\\"teacherName\\\":{\\\"_eq\\\":\\\"张三丰\\\"}}\",\"resultPath\":\"teachers\",\"name\":\"查询教师张三丰\",\"positionX\":96,\"positionY\":32}},{\"key\":\"serviceTask_mgpvgobas8eee4\",\"type\":5,\"incoming\":[\"SequenceFlow_mgpvhb6p3dm76o\"],\"outgoing\":[\"SequenceFlow_mgpvhe0tlgy2hs\"],\"properties\":{\"subType\":\"delete_record\",\"datasourceName\":\"dev_test\",\"modelName\":\"Teacher\",\"filter\":\"{\\\"teacherName\\\":{\\\"_eq\\\":\\\"张三丰\\\"}}\",\"resultPath\":\"teacherDeleteAffectedRows\",\"name\":\"删除教师张三丰\",\"positionX\":320,\"positionY\":32}},{\"key\":\"SequenceFlow_mgoksf9skg7m1c\",\"type\":1,\"incoming\":[\"start-node\"],\"outgoing\":[\"serviceTask_mgokolh6ottxgz\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgokv2z5j6tju7\",\"type\":1,\"incoming\":[\"serviceTask_mgokolh6ottxgz\"],\"outgoing\":[\"serviceTask_mgokspzb8h72r0\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgokyc4xwquno6\",\"type\":1,\"incoming\":[\"serviceTask_mgokvj54kxi9pj\"],\"outgoing\":[\"serviceTask_mgoky18vc65fea\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgolse1rjjms9t\",\"type\":1,\"incoming\":[\"serviceTask_mgoky18vc65fea\"],\"outgoing\":[\"serviceTask_mgoli5cpsdyy77\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgolsrsrj4yfkj\",\"type\":1,\"incoming\":[\"serviceTask_mgoli5cpsdyy77\"],\"outgoing\":[\"serviceTask_mgolsqgfgrdmat\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgolxly85affbh\",\"type\":1,\"incoming\":[\"serviceTask_mgolsqgfgrdmat\"],\"outgoing\":[\"end-node\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgpv7i2gpvk0qg\",\"type\":1,\"incoming\":[\"serviceTask_mgokspzb8h72r0\"],\"outgoing\":[\"serviceTask_mgpv6wp7oavt4f\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgpvhb6p3dm76o\",\"type\":1,\"incoming\":[\"serviceTask_mgpv6wp7oavt4f\"],\"outgoing\":[\"serviceTask_mgpvgobas8eee4\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_mgpvhe0tlgy2hs\",\"type\":1,\"incoming\":[\"serviceTask_mgpvgobas8eee4\"],\"outgoing\":[\"serviceTask_mgokvj54kxi9pj\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}}]}", - "status": 1, - "create_time": "2025-09-15 12:05:09.000", - "modify_time": "2025-09-15 12:05:09.000", - "operator": "admin", - "remark": "增删改查测试", - "archive": 0, - "caller": "admin", - "project_id": "dev_test" - }, - { - "flow_deploy_id": "1fe532ae-33c4-4f57-aabe-62640da4f185", - "flow_module_id": "9243be36-9ced-4413-acd5-5fc93a05c698", - "flow_name": "脚本测试", - "flow_key": "script_test", - "flow_model": "{\"flowElementList\":[{\"key\":\"start-node\",\"type\":2,\"incoming\":[],\"outgoing\":[\"SequenceFlow_miclvtzacagocb\"],\"properties\":{\"positionX\":-96,\"positionY\":64,\"name\":\"Start\"}},{\"key\":\"end-node\",\"type\":3,\"incoming\":[\"SequenceFlow_miclvvbzb9t82p\"],\"outgoing\":[],\"properties\":{\"positionX\":800,\"positionY\":48,\"name\":\"End\"}},{\"key\":\"serviceTask_miclvseffazfuf\",\"type\":5,\"incoming\":[\"SequenceFlow_miclvtzacagocb\"],\"outgoing\":[\"SequenceFlow_miclvvbzb9t82p\"],\"properties\":{\"subType\":\"script\",\"script\":\"\\\"hello world\\\";\",\"name\":\"\",\"positionX\":320,\"positionY\":48}},{\"key\":\"SequenceFlow_miclvtzacagocb\",\"type\":1,\"incoming\":[\"start-node\"],\"outgoing\":[\"serviceTask_miclvseffazfuf\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}},{\"key\":\"SequenceFlow_miclvvbzb9t82p\",\"type\":1,\"incoming\":[\"serviceTask_miclvseffazfuf\"],\"outgoing\":[\"end-node\"],\"properties\":{\"conditionsequenceflow\":\"\",\"defaultConditions\":\"false\"}}]}", - "status": 1, - "create_time": "2025-10-14T11:23:02.659", - "modify_time": "2025-10-14T11:23:02.660", - "operator": "admin", - "remark": "Javascript脚本测试", - "archive": 0, - "caller": "admin", - "project_id": "dev_test" - } - ] - }, - { - "modelName": "f_api_definition", - "values": [ - { - "id": "d421f1bb-6036-4114-bb7d-3cd6b15f3910", - "name": "Ping", - "parent_id": null, - "type": "API", - "method": "GET", - "path": "/ping", - "meta": { - "auth": false, - "document": { - "input": { - "schema": { - "type": "object", - "$schema": "http://json-schema.org/draft-04/schema#", - "properties": {} - } - }, - "output": { - "schema": { - "type": "object", - "$schema": "http://json-schema.org/draft-04/schema#", - "properties": { - "msg": { - "type": "string", - "title": "消息" - }, - "success": { - "type": "boolean", - "title": "是否成功" - } - } - } - } - }, - "execution": { - "executionType": "script", - "executionScript": "context.log.info('Simple test');\ncontext.response.body = {'msg': 'ok', success: true};" - }, - "rateLimitingEnabled": false - }, - "project_id": "default", - "created_by": "admin", - "updated_by": "", - "created_at": "2026-01-13 21:28:08", - "updated_at": "2026-01-26 11:09:38" - }, - { - "id": "01J2PAY0XJV4MHW0TDNEMSG03C", - "meta": {}, - "name": "【示例】学生接口", - "type": "FOLDER", - "created_at": "2024-07-13T23:21:09", - "updated_at": "2024-07-13T23:21:09", - "created_by": "admin", - "updated_by": "admin", - "project_id": "dev_test" - }, - { - "parent_id": "01J2PAY0XJV4MHW0TDNEMSG03C", - "meta": { - "auth": false, - "execution": { - "executionType": "graphql", - "query": "query MyQuery($order_by: dev_test_Classes_order_by = { id: asc }, $size: Int = 10, $page: Int = 1) {\n dev_test_list_Classes(order_by: $order_by, size: $size, page: $page) {\n classCode\n className\n id\n }\n}", - "variables": { - "order_by": { - "id": "desc" - } - }, - "operationName": "MyQuery" - } - }, - "name": "查询班级列表", - "path": "/Classes/list", - "id": "01J2PAY1M8T1R8HM979P4ASM9A", - "method": "GET", - "type": "API", - "created_at": "2024-07-13T23:21:09", - "updated_at": "2024-07-13T23:21:09", - "created_by": "admin", - "updated_by": "admin", - "project_id": "dev_test" - }, - { - "parent_id": "01J2PAY0XJV4MHW0TDNEMSG03C", - "meta": { - "auth": false, - "identityProvider": "demo", - "rateLimitingEnabled": true, - "maxRequestCount": 50, - "intervalInSeconds": 60, - "execution": { - "executionType": "graphql", - "query": "query MyQuery($id: Int) {\n dev_test_find_one_Classes(where: { id: { _eq: $id } }) {\n classCode\n className\n id\n }\n}", - "variables": { - "id": 1 - }, - "operationName": "MyQuery" - } - }, - "name": "查询单个班级", - "path": "/Classes/{id}", - "id": "01J2PAY1X3ZN529SQTKB8TG1Q5", - "method": "GET", - "type": "API", - "created_at": "2024-07-13T23:21:09", - "updated_at": "2024-07-13T23:21:09", - "created_by": "admin", - "updated_by": "admin", - "project_id": "dev_test" - }, - { - "parent_id": "01J2PAY0XJV4MHW0TDNEMSG03C", - "meta": { - "auth": false, - "execution": { - "executionType": "graphql", - "query": "mutation MyMutation($classCode: String, $className: String, $id: ID = \"\") {\n dev_test_create_Classes(\n data: { classCode: $classCode, className: $className, id: $id }\n ) {\n classCode\n className\n id\n }\n}", - "operationName": "MyMutation" - } - }, - "name": "创建班级", - "path": "/Classes", - "id": "01J2PAY2F3VK71GXV6BWXYEA5P", - "method": "POST", - "type": "API", - "created_at": "2024-07-13T23:21:09", - "updated_at": "2024-07-13T23:21:09", - "created_by": "admin", - "updated_by": "admin", - "project_id": "dev_test" - }, - { - "parent_id": "01J2PAY0XJV4MHW0TDNEMSG03C", - "meta": { - "auth": false, - "execution": { - "executionType": "graphql", - "query": "mutation MyMutation($classCode: String, $className: String, $id: ID) {\n dev_test_update_Classes_by_id(\n id: \"1\"\n _set: { classCode: $classCode, className: $className, id: $id }\n ) {\n classCode\n className\n id\n }\n}", - "operationName": "MyMutation" - } - }, - "name": "更新班级", - "path": "/Classes/{id}", - "id": "01J2PAY2RJ79JYB2GJP5K0AW5F", - "method": "PUT", - "type": "API", - "created_at": "2024-07-13T23:21:09", - "updated_at": "2024-07-13T23:21:09", - "created_by": "admin", - "updated_by": "admin", - "project_id": "dev_test" - }, - { - "parent_id": "01J2PAY0XJV4MHW0TDNEMSG03C", - "meta": { - "auth": false, - "execution": { - "executionType": "graphql", - "query": "mutation MyMutation($id: ID!) {\n dev_test_delete_Classes_by_id(id: $id) {\n classCode\n className\n id\n }\n}", - "operationName": "MyMutation" - } - }, - "name": "删除班级", - "path": "/Classes/{id}", - "id": "01J2PAY3W18T1BQJ5H5D8STGYT", - "method": "DELETE", - "type": "API", - "created_at": "2024-07-13T23:21:09", - "updated_at": "2024-07-13T23:21:09", - "created_by": "admin", - "updated_by": "admin", - "project_id": "dev_test" - } - ] - }, - { - "modelName": "f_identity_provider", - "values": [ - { - "name": "demo", - "project_id": "dev_test", - "provider": { - "type": "oidc", - "issuer": "http://localhost/issuer", - "client_id": "test_client_id", - "client_secret": "test_client_secret" - } - }, - { - "name": "default", - "created_at": "2024-07-13T23:21:09", - "updated_at": "2024-07-13T23:21:09", - "created_by": "admin", - "updated_by": "admin", - "project_id": "default", - "provider": { - "type": "script", - "script": "const request = context.request;\nconst response = context.response;\nconst log = context.log;\nconst jwtVerify = context.utils.jwtVerify;\n// Example: simple token check from header\nlog.info('identify context: {}', context);\nconst auth = request.headers['authorization'] || request.headers['Authorization'];\nif (!auth || !auth.startsWith('Bearer ')) {\n response.body = { success: false, message: 'Missing bearer token' };\n} else {\n const token = auth.substring('Bearer '.length);\n try {\n // verify jwt token\n jwtVerify(token);\n response.body = {success: true, message: 'ok'};\n } catch(e) {\n log.error('identify verify error: {}', e.message);\n response.body = {success: false, message: e.message };\n }\n}" - } - } - ] - }, - { - "modelName": "f_trigger", - "values": [ - { - "id": "4e8be2da-8ae7-4571-b347-61af5fdd3e9b", - "name": "请求日志归档任务", - "description": "写入日志归档表进行数据归档", - "type": "EVENT", - "config": { - "type": "event", - "modelName": "f_api_request_log", - "mutationTypes": [ - "create" - ], - "triggerTiming": "after", - "datasourceName": "system" - }, - "job_type": "FLOW", - "job_group": "system_f_api_request_log", - "job_id": "22203aa0-5f25-4b8a-974d-e4288c1bbd18", - "state": false, - "created_at": "2025-10-19 17:59:45", - "updated_at": "2025-10-19 20:38:24", - "created_by": null, - "updated_by": null, - "project_id": "default" - }, - { - "id": "bf492f37-1f01-4eb8-b76d-d319299b4d8e", - "name": "定时触发-间隔触发", - "description": "定时触发-间隔触发-备注", - "type": "SCHEDULED", - "config": { - "type": "interval", - "interval": 1, - "intervalUnit": "minute", - "repeatCount": 100 - }, - "job_id": "5c41f37a-87a9-47af-bdba-44d0c27eda89", - "job_type": "FLOW", - "job_group": "testFlowName_1757909108656", - "state": false, - "created_at": "2025-09-15 12:05:09.000", - "updated_at": "2025-09-15 12:05:09.000", - "project_id": "dev_test" - }, - { - "id": "d8c60d2a-19d8-4c3c-b370-96318733858f", - "name": "定时触发-Cron表达式", - "description": "定时触发-Cron表达式-备注", - "type": "SCHEDULED", - "config": { - "type": "cron", - "cronExpression": "0 0 * * * ? *" - }, - "job_id": "5c41f37a-87a9-47af-bdba-44d0c27eda89", - "job_type": "FLOW", - "job_group": "testFlowName_1757909108656", - "state": false, - "created_at": "2025-09-15 12:05:09.000", - "updated_at": "2025-09-15 12:05:09.000", - "project_id": "dev_test" - }, - { - "id": "9434666d-6b3b-417a-80e3-3352f40ded71", - "name": "事件触发-之前", - "description": "事件触发-之前-描述", - "type": "EVENT", - "config": { - "type": "event", - "datasourceName": "dev_test", - "modelName": "Student", - "mutationTypes": [ - "delete", - "update", - "create" - ], - "triggerTiming": "after" - }, - "job_id": "5c41f37a-87a9-47af-bdba-44d0c27eda89", - "job_type": "FLOW", - "job_group": "dev_test_Student", - "state": true, - "created_at": "2025-09-15 12:05:09.000", - "updated_at": "2025-09-15 12:05:09.000", - "project_id": "dev_test" - }, - { - "id": "f351b8d9-a450-4f2c-8fff-cf862d690352", - "name": "事件触发-之后", - "description": "事件触发-之后-描述", - "type": "EVENT", - "config": { - "type": "event", - "datasourceName": "dev_test", - "modelName": "Classes", - "mutationTypes": [ - "create", - "update", - "delete" - ], - "triggerTiming": "after" - }, - "job_id": "5c41f37a-87a9-47af-bdba-44d0c27eda89", - "job_type": "FLOW", - "job_group": "dev_test_Classes", - "state": true, - "created_at": "2025-09-15 12:05:09.000", - "updated_at": "2025-09-15 12:05:09.000", - "project_id": "dev_test" - } - ] - } - ] -} diff --git a/flexmodel-server/src/main/resources/dev_test.fml b/flexmodel-server/src/main/resources/dev_test.fml new file mode 100644 index 00000000..279ce467 --- /dev/null +++ b/flexmodel-server/src/main/resources/dev_test.fml @@ -0,0 +1,83 @@ +model Teacher { + id : Long @id @default(autoIncrement()), + teacherName? : String @length("255"), + subject? : String @length("255"), + @index(name:"IDX_TEACHER_NAME", unique: "false", fields: [teacherName]), + @comment("教师") +} +model Student { + id : Long @id @default(autoIncrement()), + studentName? : String @length("255"), + gender? : UserGender, + interest? : user_interest[], + age? : Int, + classId? : Long, + studentClass? : Classes @comment("班级") @relation(localField: "classId", foreignField: "id", cascadeDelete: "false"), + studentDetail? : StudentDetail @relation(localField: "id", foreignField: "studentId", cascadeDelete: "true"), + @index(name: "IDX_STUDENT_NAME",unique: "false", fields: [studentName]), + @index(name:"IDX_CLASS_ID", unique: "false", fields: [classId]), + @comment("学生") +} +model StudentDetail { + id : Long @id @default(autoIncrement()), + studentId? : Long, + student? : Student @comment("学生") @relation(localField: "studentId", foreignField: "id", cascadeDelete: "false"), + description? : String @length("255"), + @comment("学生详情") +} +model Classes { + id : Long @id @default(autoIncrement()), + classCode? : String @length("255"), + className? : String @length("255"), + students? : Student[] @relation(localField: "id", foreignField: "classId", cascadeDelete: "true"), + @index(name:"IDX_CLASS_CODE", unique: "false", fields: [classCode]), + @comment("班级") +} +model Course { + courseNo : String @id @default(uuid()), + courseName? : String @length("255"), + @index(name:"IDX_COURSE_NO", unique: "false", fields: [courseNo]), + @comment("课程") +} +enum UserGender { + UNKNOWN, + MALE, + FEMALE +} +enum user_interest { + chang, + tiao, + rap, + daLanQiu +} + +// ============================== +// 种子数据 (seed) +// ============================== + +seed Course { + {courseNo: "Math", courseName: "数学"}, + {courseNo: "YuWen", courseName: "语文"}, + {courseNo: "Eng", courseName: "英语"}, + {courseNo: "History", courseName: "历史"}, + {courseNo: "politics", courseName: "政治"}, +} + +seed Classes { + {id: 1, className: "一年级1班", classCode: "C_001"}, + {id: 2, className: "一年级2班", classCode: "C_002"}, + {id: 3, className: "二年级1班", classCode: "C_003"}, +} + +seed Student { + {id: 1, studentName: "张三", gender: "MALE", interest: ["chang", "tiao", "rap", "daLanQiu"], age: 10, classId: 1, studentDetail: {description: "张三的描述"}}, + {id: 2, studentName: "李四", gender: "FEMALE", interest: ["chang", "tiao"], age: 10, classId: 1, studentDetail: {description: "李四的描述"}}, + {id: 3, studentName: "王五", interest: ["daLanQiu"], gender: "MALE", age: 11, classId: 2, studentDetail: {description: "王五的描述"}}, +} + +seed Teacher { + {id: 1, teacherName: "张老师", subject: "数学", students: [{id: 1}, {id: 2}, {id: 3}]}, + {id: 2, teacherName: "李老师", subject: "语文", students: [{id: 1}, {id: 2}, {id: 3}]}, + {id: 3, teacherName: "王老师", subject: "英语", students: [{id: 1}, {id: 3}]}, +} + diff --git a/flexmodel-server/src/main/resources/platform.fml b/flexmodel-server/src/main/resources/platform.fml new file mode 100644 index 00000000..f947204a --- /dev/null +++ b/flexmodel-server/src/main/resources/platform.fml @@ -0,0 +1,276 @@ +model f_project { + id : String @id @default(uuid()), + name: String, + database_name: String, + description?: String, + enabled : Boolean @comment("是否启用") @default("true"), + owner_id?: String @comment("所有者 ID"), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + @comment("租户") +} +model f_user { + id : String @id @default(uuid()), + name? : String @length("255") @comment("名称"), + email? : String @length("255") @comment("邮箱"), + password_hash : String @length("255") @comment("密码HASH"), + role_ids: String @length("255") @comment("角色ID, 逗号分隔"), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + @index(name : "IDX_USERNAME", unique: "true", fields: [name]), + @index(name : "IDX_EMAIL", unique: "true", fields: [email]), + @comment("用户") +} +model f_role { + id : String @id @unique @default(uuid()), + name : String @length("255"), + description? : String @length("255"), + resource_ids?: String @length("2000") @comment("资源ID, 逗号分隔"), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + @index(name:"IDX_ROLE_NAME", unique: "true", fields: [name]), + @comment("角色") +} +model f_resource { + id: Long @id @default(autoIncrement()), + name : String @length("255"), + permission: String @length("255") @comment("权限标识"), + type: String @length("100") @comment("类型, system: 系统级, platform: 项目级"), + parent_id?: Long, + @comment("资源") +} +model f_resource_template { + id: Long @id @default(autoIncrement()), + name: String @length("255"), + permission: String @length("255") @comment("权限标识"), + parent_id?: Long, + @comment("资源模版") +} +model f_config { + id : String @id @unique @default(uuid()), + key : String @comment("名称") @length("255"), + value? : String @length("255"), + created_at : DateTime @default(now()), + updated_at : DateTime @default(now()), + @comment("配置"), + @index(name:"IDX_CONFIG_KEY", unique: "true", fields: [key]), + @comment("系统配置") +} + +// Quartz 持久化表模型(根据提供的表结构生成) +// 约定: +// 1) 每个模型均包含默认主键字段 id。 +// 2) 原表的 PRIMARY KEY(通常为复合键)用唯一索引实现,命名保持接近官方索引名。 +// 3) BLOB 字段以 JSON 存储;布尔型标志位(VARCHAR(1))以 Boolean 表示。 + +model f_qrtz_job_detail { + id : String @id @default(uuid()), + sched_name : String @length("120") @comment("调度器名称"), + job_name : String @length("190") @comment("任务名称"), + job_group : String @length("190") @comment("任务分组"), + description? : String @length("250") @comment("任务描述"), + job_class_name : String @length("250") @comment("任务实现类名"), + is_durable : Boolean @comment("是否持久化(原 VARCHAR(1))"), + is_nonconcurrent : Boolean @comment("是否不并发执行(原 VARCHAR(1))"), + is_update_data : Boolean @comment("执行后是否更新数据(原 VARCHAR(1))"), + requests_recovery : Boolean @comment("是否请求恢复(原 VARCHAR(1))"), + job_data? : JSON @comment("任务数据(原 BLOB)"), + @index(name:"UQ_QRTZ_JOB_DETAILS_PK", unique: "true", fields: [sched_name, job_name, job_group]), + @index(name:"IDX_QRTZ_J_REQ_RECOVERY", unique: "false", fields: [sched_name, requests_recovery]), + @index(name:"IDX_QRTZ_J_GRP", unique: "false", fields: [sched_name, job_group]), + @comment("Quartz 任务明细") +} + +model f_qrtz_trigger { + id : String @id @default(uuid()), + sched_name : String @length("120") @comment("调度器名称"), + trigger_name : String @length("190") @comment("触发器名称"), + trigger_group : String @length("190") @comment("触发器分组"), + job_name : String @length("190") @comment("关联任务名称"), + job_group : String @length("190") @comment("关联任务分组"), + description? : String @length("250") @comment("触发器描述"), + next_fire_time? : Long @comment("下次触发时间(毫秒)"), + prev_fire_time? : Long @comment("上次触发时间(毫秒)"), + priority? : Int @comment("优先级"), + trigger_state : String @length("16") @comment("触发器状态"), + trigger_type : String @length("8") @comment("触发器类型(如 CRON/SIMPLE)"), + start_time : Long @comment("开始时间(毫秒)"), + end_time? : Long @comment("结束时间(毫秒)"), + calendar_name? : String @length("190") @comment("日历名称"), + misfire_instr? : Int @comment("误触发指令(原 SMALLINT)"), + job_data? : JSON @comment("触发器数据(原 BLOB)"), + @index(name:"UQ_QRTZ_TRIGGERS_PK", unique: "true", fields: [sched_name, trigger_name, trigger_group]), + @index(name:"IDX_QRTZ_T_J", unique: "false", fields: [sched_name, job_name, job_group]), + @index(name:"IDX_QRTZ_T_JG", unique: "false", fields: [sched_name, job_group]), + @index(name:"IDX_QRTZ_T_C", unique: "false", fields: [sched_name, calendar_name]), + @index(name:"IDX_QRTZ_T_G", unique: "false", fields: [sched_name, trigger_group]), + @index(name:"IDX_QRTZ_T_STATE", unique: "false", fields: [sched_name, trigger_state]), + @index(name:"IDX_QRTZ_T_N_STATE", unique: "false", fields: [sched_name, trigger_name, trigger_group, trigger_state]), + @index(name:"IDX_QRTZ_T_N_G_STATE", unique: "false", fields: [sched_name, trigger_group, trigger_state]), + @index(name:"IDX_QRTZ_T_NEXT_FIRE_TIME", unique: "false", fields: [sched_name, next_fire_time]), + @index(name:"IDX_QRTZ_T_NFT_ST", unique: "false", fields: [sched_name, trigger_state, next_fire_time]), + @index(name:"IDX_QRTZ_T_NFT_MISFIRE", unique: "false", fields: [sched_name, misfire_instr, next_fire_time]), + @index(name:"IDX_QRTZ_T_NFT_ST_MISFIRE", unique: "false", fields: [sched_name, misfire_instr, next_fire_time, trigger_state]), + @index(name:"IDX_QRTZ_T_NFT_ST_MISFIRE_GRP", unique: "false", fields: [sched_name, misfire_instr, next_fire_time, trigger_group, trigger_state]), + @comment("Quartz 触发器") +} + +model f_qrtz_simple_trigger { + id : String @id @default(uuid()), + sched_name : String @length("120") @comment("调度器名称"), + trigger_name : String @length("190") @comment("触发器名称"), + trigger_group : String @length("190") @comment("触发器分组"), + repeat_count : Long @comment("重复次数"), + repeat_interval : Long @comment("重复间隔(毫秒)"), + times_triggered : Long @comment("已触发次数"), + @index(name:"UQ_QRTZ_SIMPLE_TRIGGERS_PK", unique: "true", fields: [sched_name, trigger_name, trigger_group]), + @comment("Quartz Simple 类型触发器明细") +} + +model f_qrtz_cron_trigger { + id : String @id @default(uuid()), + sched_name : String @length("120") @comment("调度器名称"), + trigger_name : String @length("190") @comment("触发器名称"), + trigger_group : String @length("190") @comment("触发器分组"), + cron_expression : String @length("120") @comment("CRON 表达式"), + time_zone_id? : String @length("80") @comment("时区标识"), + @index(name:"UQ_QRTZ_CRON_TRIGGERS_PK", unique: "true", fields: [sched_name, trigger_name, trigger_group]), + @comment("Quartz Cron 类型触发器明细") +} + +model f_qrtz_simprop_trigger { + id : String @id @default(uuid()), + sched_name : String @length("120") @comment("调度器名称"), + trigger_name : String @length("190") @comment("触发器名称"), + trigger_group : String @length("190") @comment("触发器分组"), + str_prop_1? : String @length("512") @comment("字符串属性1"), + str_prop_2? : String @length("512") @comment("字符串属性2"), + str_prop_3? : String @length("512") @comment("字符串属性3"), + int_prop_1? : Int @comment("整型属性1"), + int_prop_2? : Int @comment("整型属性2"), + long_prop_1? : Long @comment("长整型属性1"), + long_prop_2? : Long @comment("长整型属性2"), + dec_prop_1? : String @length("50") @comment("小数属性1(原 NUMERIC(13,4))"), + dec_prop_2? : String @length("50") @comment("小数属性2(原 NUMERIC(13,4))"), + bool_prop_1? : Boolean @comment("布尔属性1(原 VARCHAR(1))"), + bool_prop_2? : Boolean @comment("布尔属性2(原 VARCHAR(1))"), + @index(name:"UQ_QRTZ_SIMPROP_TRIGGERS_PK", unique: "true", fields: [sched_name, trigger_name, trigger_group]), + @comment("Quartz Simprop 类型触发器明细") +} + +model f_qrtz_blob_trigger { + id : String @id @default(uuid()), + sched_name : String @length("120") @comment("调度器名称"), + trigger_name : String @length("190") @comment("触发器名称"), + trigger_group : String @length("190") @comment("触发器分组"), + blob_data? : JSON @comment("触发器二进制数据(原 BLOB)"), + @index(name:"UQ_QRTZ_BLOB_TRIGGERS_PK", unique: "true", fields: [sched_name, trigger_name, trigger_group]), + @index(name:"IDX_QRTZ_BLOB_TRIG", unique: "false", fields: [sched_name, trigger_name, trigger_group]), + @comment("Quartz Blob 类型触发器明细") +} + +model f_qrtz_calendar { + id : String @id @default(uuid()), + sched_name : String @length("120") @comment("调度器名称"), + calendar_name : String @length("190") @comment("日历名称"), + calendar : String @comment("日历数据(原 BLOB)"), + @index(name:"UQ_QRTZ_CALENDARS_PK", unique: "true", fields: [sched_name, calendar_name]), + @comment("Quartz 日历") +} + +model f_qrtz_paused_trigger_grp { + id : String @id @default(uuid()), + sched_name : String @length("120") @comment("调度器名称"), + trigger_group : String @length("190") @comment("触发器分组"), + @index(name:"UQ_QRTZ_PAUSED_TRIGGER_GRPS_PK", unique: "true", fields: [sched_name, trigger_group]), + @comment("Quartz 已暂停触发器分组") +} + +model f_qrtz_fired_trigger { + id : String @id @default(uuid()), + sched_name : String @length("120") @comment("调度器名称"), + entry_id : String @length("95") @comment("触发记录条目ID"), + trigger_name : String @length("190") @comment("触发器名称"), + trigger_group : String @length("190") @comment("触发器分组"), + instance_name : String @length("190") @comment("调度实例名称"), + fired_time : Long @comment("实际触发时间(毫秒)"), + sched_time : Long @comment("计划时间(毫秒)"), + priority : Int @comment("优先级"), + state : String @length("16") @comment("状态"), + job_name? : String @length("190") @comment("任务名称"), + job_group? : String @length("190") @comment("任务分组"), + is_nonconcurrent? : Boolean @comment("是否不并发(原 VARCHAR(1))"), + requests_recovery? : Boolean @comment("是否请求恢复(原 VARCHAR(1))"), + @index(name:"UQ_QRTZ_FIRED_TRIGGERS_PK", unique: "true", fields: [sched_name, entry_id]), + @index(name:"IDX_QRTZ_FT_TRIG_INST_NAME", unique: "false", fields: [sched_name, instance_name]), + @index(name:"IDX_QRTZ_FT_INST_JOB_REQ_RCVRY", unique: "false", fields: [sched_name, instance_name, requests_recovery]), + @index(name:"IDX_QRTZ_FT_J_G", unique: "false", fields: [sched_name, job_name, job_group]), + @index(name:"IDX_QRTZ_FT_JG", unique: "false", fields: [sched_name, job_group]), + @index(name:"IDX_QRTZ_FT_T_G", unique: "false", fields: [sched_name, trigger_name, trigger_group]), + @index(name:"IDX_QRTZ_FT_TG", unique: "false", fields: [sched_name, trigger_group]), + @comment("Quartz 已触发触发器记录") +} + +model f_qrtz_scheduler_state { + id : String @id @default(uuid()), + sched_name : String @length("120") @comment("调度器名称"), + instance_name : String @length("190") @comment("调度实例名称"), + last_checkin_time : Long @comment("最后检查时间(毫秒)"), + checkin_interval : Long @comment("检查间隔(毫秒)"), + @index(name:"UQ_QRTZ_SCHEDULER_STATE_PK", unique: "true", fields: [sched_name, instance_name]), + @comment("Quartz 调度器状态") +} + +model f_qrtz_lock { + id : String @id @default(uuid()), + sched_name : String @length("120") @comment("调度器名称"), + lock_name : String @length("40") @comment("锁名称"), + @index(name:"UQ_QRTZ_LOCKS_PK", unique: "true", fields: [sched_name, lock_name]), + @comment("Quartz 锁") +} + +// ============================== +// 种子数据 (seed) +// ============================== + +seed f_project { + {id: "default", name: "系统默认", database_name: "system", description: "默认项目", owner_id: "admin", enabled: true}, + {id: "dev_test", database_name: "dev_test", name: "开发测试", description: "开发测试项目", owner_id: "admin", enabled: true}, +} + +seed f_user { + {id: "admin", name: "Admin", password_hash: "172eee54aa664e9dd0536b063796e54e", created_at: "2025-08-30 19:58:23.000", role_ids: "admin"}, +} + +seed f_role { + {id: "admin", name: "管理员", description: "管理员拥有所有权限", resource_ids: "1"}, + {id: "developer", name: "开发", description: "开发人员拥有项目管理权限", resource_ids: "100"}, +} + +seed f_resource { + {id: 1, name: "所有资源", permission: "*", type: "system", parent_id: null}, + {id: 100, name: "项目", permission: "project:*", type: "system", parent_id: 1}, + {id: 101, name: "查看项目", permission: "project:view", type: "system", parent_id: 100}, + {id: 102, name: "新增项目", permission: "project:create", type: "system", parent_id: 100}, + {id: 103, name: "删除项目", permission: "project:delete", type: "system", parent_id: 100}, + {id: 104, name: "项目详情", permission: "project:detail:*", type: "project", parent_id: 100}, + {id: 200, name: "成员", permission: "member:*", type: "system", parent_id: 1}, + {id: 201, name: "用户", permission: "member:user:*", type: "system", parent_id: 200}, + {id: 202, name: "新增用户", permission: "member:user:create", type: "system", parent_id: 201}, + {id: 203, name: "修改用户", permission: "member:user:update", type: "system", parent_id: 201}, + {id: 204, name: "删除用户", permission: "member:user:delete", type: "system", parent_id: 201}, + {id: 205, name: "角色", permission: "member:role:*", type: "system", parent_id: 200}, + {id: 206, name: "新增角色", permission: "member:role:create", type: "system", parent_id: 205}, + {id: 207, name: "修改角色", permission: "member:role:update", type: "system", parent_id: 205}, + {id: 208, name: "删除角色", permission: "member:role:delete", type: "system", parent_id: 205}, + {id: 300, name: "设置", permission: "settings:*", type: "system", parent_id: 1}, + {id: 301, name: "查看", permission: "settings:view", type: "system", parent_id: 300}, + {id: 302, name: "保存", permission: "settings:save", type: "system", parent_id: 300}, +} + diff --git a/flexmodel-server/src/main/resources/project.fml b/flexmodel-server/src/main/resources/project.fml new file mode 100644 index 00000000..4a38bb7d --- /dev/null +++ b/flexmodel-server/src/main/resources/project.fml @@ -0,0 +1,362 @@ +model f_storage { + name : String @id, + type? : StorageType, + config? : JSON, + enabled : Boolean @comment("是否启用") @default("true"), + project_id?: String @comment("项目ID"), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + @index(name: "IDX_PROJECT", fields: [project_id]), + @comment("文件存储") +} + +model f_api_request_log { + id : String @id @default(uuid()), + url : String @length("2000") @comment("请求地址"), + http_method: String @length("255") @comment("请求方法"), + path: String @length("1000") @comment("请求路径"), + request_body : JSON @comment("请求参数"), + request_headers : JSON @comment("请求头"), + status_code : Int, + response_time : Int, + client_ip?: String @length("45") @comment("IP地址"), + created_at : DateTime @default(now()), + is_success: Boolean @comment("是否成功") @default("true"), + error_message? : JSON @comment("异常信息"), + project_id?: String @comment("项目ID"), + @index(name: "IDX_API_REQUEST_LOG_CREATED_AT", fields: [created_at]), + @index(name: "IDX_API_REQUEST_LOG_IS_ERROR", fields: [is_success]), + @index(name: "IDX_API_REQUEST_LOG_PATH_CREATED_AT", fields: [path, created_at]), + @index(name: "IDX_API_REQUEST_LOG_STATUS_CREATED_AT", fields: [status_code, created_at]), + @index(name: "IDX_PROJECT", fields: [project_id]), + @comment("API请求日志") +} + +model f_identity_provider { + name : String @id, + provider? : JSON, + project_id?: String @comment("项目ID"), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + @index(name: "IDX_PROJECT", fields: [project_id]), + @comment("身份源") +} + +model f_ai_chat_memory { + id : String @id @default(uuid()), + messages : String @length("10000") @comment("消息"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + @comment("AI聊天记忆") +} + +model f_ai_chat_conversation { + id : String @id @default(uuid()), + title : String @length("255") @comment("标题"), + messages? : f_ai_chat_message[] @relation(localField: "id", foreignField: "conversation_id", cascadeDelete: "true"), + project_id?: String @comment("项目ID"), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + @index(name: "IDX_PROJECT", fields: [project_id]), + @comment("AI聊天会话") +} + +model f_ai_chat_message { + id : String @id @default(uuid()), + conversation_id : String @length("255") @comment("会话ID"), +// conversation? : f_ai_chat_conversation @comment("会话") @relation(localField: "conversation_id", foreignField: "id", cascadeDelete: false), + role: String @length("255") @comment("角色"), + content : String @length("4000") @comment("内容"), + project_id?: String @comment("项目ID"), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + @index(name:"IDX_CONVERSATION_ID", unique: false, fields: [conversation_id]), + @index(name: "IDX_PROJECT", fields: [project_id]), + @comment("AI聊天消息") +} + +model f_em_flow_definition { + id: Long @id @default(autoIncrement()), + flow_module_id: String @comment("流程模型id") @unique, + flow_name: String @comment("流程名称"), + flow_key: String @comment("流程业务标识"), + flow_model?: String @length(10000) @comment("表单定义"), + status: Int @default(0) @comment("状态(1.初始态 2.编辑中 3.已下线)"), + create_time: DateTime @default(now()) @comment("流程创建时间"), + modify_time: DateTime @default(now()) @comment("流程修改时间"), + operator: String @comment("操作人"), + remark: String @length(512) @comment("备注"), + archive: Int @default(0) @comment("归档状态(0未删除,1删除)"), + caller?: String @comment("调用方"), + is_deleted: Boolean @default(0) @comment("删除状态(0未删除,1已删除)"), + project_id?: String @comment("项目ID"), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + @index(name: "IDX_flow_define_module", fields: [flow_module_id]), + @index(name: "IDX_PROJECT", fields: [project_id]), + @comment("流程定义") +} + +model f_em_flow_deployment { + id: Long @id @default(autoIncrement()), + flow_deploy_id: String @comment("流程模型部署id") @unique, + flow_module_id: String @comment("流程模型id"), + flow_name: String @comment("流程名称"), + flow_key: String @comment("流程业务标识"), + flow_model: String @length(10000) @comment("表单定义"), + status: Int @default(0) @comment("状态(1.已部署 3.已下线)"), + create_time: DateTime @default(now()) @comment("流程创建时间"), + modify_time: DateTime @default(now()) @comment("流程修改时间"), + operator: String @comment("操作人"), + remark: String @length(512) @comment("备注"), + archive: Int @default(0) @comment("归档状态(0未删除,1删除)"), + caller?: String @comment("调用方"), + project_id?: String @comment("项目ID"), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + @index(name: "IDX_flow_deploy", fields: [flow_deploy_id]), + @index(name: "IDX_flow_module", fields: [flow_module_id]), + @index(name: "IDX_PROJECT", fields: [project_id]), + @comment("流程部署") +} + +model f_ei_flow_instance { + id: Long @id @default(autoIncrement()), + flow_instance_id: String @unique @comment("流程执行实例id"), + parent_flow_instance_id?: String @comment("父流程执行实例id"), + flow_deploy_id: String @comment("流程模型部署id"), + flow_module_id: String @comment("流程模型id"), + status: Int @default(0) @comment("状态(1.执行完成 2.执行中 3.执行终止(强制终止))"), + create_time: DateTime @default(now()) @comment("流程创建时间"), + modify_time: DateTime @default(now()) @comment("流程修改时间"), + archive: Int @default(0) @comment("归档状态(0未删除,1删除)"), + caller?: String @comment("调用方"), + project_id?: String @comment("项目ID"), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + @index(name: "IDX_flow_instance", fields: [flow_instance_id]), + @index(name: "IDX_PROJECT", fields: [project_id]), + @comment("流程执行实例") +} + +model f_ei_flow_instance_mapping { + id: Long @id @default(autoIncrement()), + flow_instance_id: String @comment("流程执行实例id"), + node_instance_id: String @comment("节点执行实例id"), + node_key: String @comment("节点唯一标识"), + sub_flow_instance_id: String @comment("子流程执行实例id"), + type: Int @default(0) @comment("状态(1.执行 2.回滚)"), + create_time: DateTime @default(now()) @comment("流程创建时间"), + modify_time: DateTime @default(now()) @comment("流程修改时间"), + archive: Int @default(0) @comment("归档状态(0未删除,1删除)"), + caller?: String @default("optimus-prime") @comment("调用方"), + project_id?: String @comment("项目ID"), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + @index(name: "IDX_ei_flow_node", fields: [flow_instance_id]), + @index(name: "IDX_PROJECT", fields: [project_id]), + @comment("父子流程实例映射") +} + +model f_ei_node_instance { + id: Long @id @default(autoIncrement()), + node_instance_id: String @unique @comment("节点执行实例id"), + flow_instance_id: String @comment("流程执行实例id"), + source_node_instance_id: String @comment("上一个节点执行实例id"), + instance_data_id: String @length(5000) @comment("实例数据id"), + flow_deploy_id: String @comment("流程模型部署id"), + node_key: String @comment("节点唯一标识"), + node_type: Int @default(0) @comment("流程类型"), + source_node_key: String @comment("上一个流程节点唯一标识"), + status: Int @default(0) @comment("状态(1.处理成功 2.处理中 3.处理失败 4.处理已撤销)"), + create_time: DateTime @default(now()) @comment("流程创建时间"), + modify_time: DateTime @default(now()) @comment("流程修改时间"), + archive: Int @default(0) @comment("归档状态(0未删除,1删除)"), + caller?: String @comment("调用方"), + project_id?: String @comment("项目ID"), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + @index(name: "IDX_node_instance_id", fields: [node_instance_id]), + @index(name: "IDX_fiid_sniid_nk", fields: [flow_instance_id, source_node_instance_id, node_key]), + @index(name: "IDX_PROJECT", fields: [project_id]), + @comment("节点执行实例") +} + +model f_ei_node_instance_log { + id: Long @id @default(autoIncrement()), + node_instance_id: String @comment("节点执行实例id"), + flow_instance_id: String @comment("流程执行实例id"), + instance_data_id: String @comment("实例数据id"), + node_key: String @comment("节点唯一标识"), + type: Int @default(0) @comment("操作类型(1.系统执行 2.任务提交 3.任务撤销)"), + status: Int @default(0) @comment("状态(1.处理成功 2.处理中 3.处理失败 4.处理已撤销)"), + create_time: DateTime @default(now()) @comment("流程创建时间"), + archive: Int @default(0) @comment("归档状态(0未删除,1删除)"), + caller?: String @comment("调用方"), + project_id?: String @comment("项目ID"), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + @index(name: "IDX_PROJECT", fields: [project_id]), + @comment("节点执行记录") +} + +model f_ei_instance_data { + id: Long @id @default(autoIncrement()), + node_instance_id: String @comment("节点执行实例id"), + flow_instance_id: String @comment("流程执行实例id"), + instance_data_id: String @unique @comment("实例数据id"), + flow_deploy_id: String @comment("流程模型部署id"), + flow_module_id: String @comment("流程模型id"), + node_key: String @comment("节点唯一标识"), + instance_data: String @length(5000) @comment("数据列表json"), + type: Int @default(0) @comment("操作类型(1.实例初始化 2.系统执行 3.系统主动获取 4.上游更新 5.任务提交 6.任务撤回)"), + create_time: DateTime @default(now()) @comment("流程创建时间"), + archive: Int @default(0) @comment("归档状态(0未删除,1删除)"), + caller?: String @comment("调用方"), + project_id?: String @comment("项目ID"), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + @index(name: "IDX_instance_data_id", fields: [instance_data_id]), + @index(name: "IDX_flow_instance", fields: [flow_instance_id]), + @index(name: "IDX_PROJECT", fields: [project_id]), + @comment("实例数据") +} + +model f_trigger { + id : String @id @default(uuid()), + name : String @comment("描述"), + description? : String @length("100") @comment("描述"), + type: TriggerType @comment("触发器类型"), + config: JSON @comment("触发器配置"), + job_type: String @length("50") @default("FLOW") @comment("任务的类型"), + job_group: String @length("50") @comment("任务的分组"), + job_id: String @length("50") @comment("任务的ID"), + state: Boolean @default(true) @comment("状态"), + @index(name:"UQ_TRIGGER_PK", unique: "true", fields: [id]), + created_at? : DateTime @default(now()), + updated_at? : DateTime @default(now()), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + project_id?: String @comment("项目ID"), + @index(name:"IDX_PROJECT", unique: false, fields: [project_id]), + @comment("触发器配置") +} + +model f_job_execution_log { + id : String @id @default(uuid()), + trigger_id : String @length("50") @comment("触发器ID"), + job_id : String @length("50") @comment("作业ID"), + job_group : String @length("50") @comment("作业分组"), + job_type : String @length("50") @comment("作业类型"), + job_name : String @length("255") @comment("作业名称"), + execution_status : String @length("20") @comment("执行状态(SUCCESS/FAILED/RUNNING)"), + start_time : DateTime @comment("开始执行时间"), + end_time? : DateTime @comment("结束执行时间"), + execution_duration? : Long @comment("执行时长(毫秒)"), + is_success : Boolean @default(false) @comment("是否执行成功"), + error_message? : String @length("2000") @comment("错误信息"), + error_stack_trace? : JSON @comment("错误堆栈信息"), + input_data? : JSON @comment("输入数据"), + output_data? : JSON @comment("输出数据"), + retry_count : Int @default(0) @comment("重试次数"), + max_retry_count : Int @default(0) @comment("最大重试次数"), + scheduler_name : String @length("120") @comment("调度器名称"), + instance_name : String @length("190") @comment("调度实例名称"), + fired_time : Long @comment("实际触发时间(毫秒)"), + scheduled_time : Long @comment("计划执行时间(毫秒)"), + project_id?: String @comment("项目ID"), + created_by?: String @comment("创建人"), + updated_by?: String @comment("更新人"), + created_at?: DateTime @default(now()) @comment("创建时间"), + updated_at?: DateTime @default(now()) @comment("更新时间"), + + @index(name:"IDX_JOB_EXEC_TRIGGER_ID", unique: false, fields: [trigger_id]), + @index(name:"IDX_JOB_EXEC_JOB_ID", unique: false, fields: [job_id]), + @index(name:"IDX_JOB_EXEC_SCHEDULER", unique: false, fields: [scheduler_name]), + @index(name:"IDX_JOB_EXEC_STATUS", unique: false, fields: [execution_status]), + @index(name:"IDX_JOB_EXEC_START_TIME", unique: false, fields: [start_time]), + @index(name:"IDX_JOB_EXEC_SUCCESS", unique: false, fields: [is_success]), + @index(name:"IDX_TENANT", unique: false, fields: [project_id]), + @index(name:"IDX_JOB_EXEC_COMPOSITE", unique: false, fields: [trigger_id, start_time]), + @comment("作业执行日志") +} + +enum TriggerType { + EVENT, + SCHEDULED +} + +enum ApiType { + FOLDER, + API +} + +enum DatasourceType { + SYSTEM, + USER +} + +enum StorageType { + S3, + LOCAL +} + +// ============================== +// 种子数据 (seed) +// ============================== + +seed f_datasource { + {name: "system", type: "SYSTEM", config: {url: "${flexmodel.datasource.url}", dbKind: "${flexmodel.datasource.db-kind}", password: "${flexmodel.datasource.password}", username: "${flexmodel.datasource.username}"}, project_id: "default"}, + {name: "dev_test", type: "USER", config: {url: "jdbc:sqlite:file:sqlite_dev_test.db", dbKind: "sqlite", password: "", username: ""}, project_id: "dev_test"}, + {name: "sqlite_test", type: "USER", config: {url: "jdbc:sqlite:file::memory:?cache=shared", dbKind: "sqlite", password: "", username: ""}, project_id: "dev_test"}, +} + +seed f_em_flow_definition { + {flow_module_id: "22203aa0-5f25-4b8a-974d-e4288c1bbd18", flow_name: "日志归档流程", flow_key: "log_archive_task", flow_model: "{\"flowElementList\":[{\"key\":\"start-node\",\"type\":2,\"incoming\":[],\"outgoing\":[\"SequenceFlow_mgxfy945jnpgtk\"],\"properties\":{\"positionX\":-112,\"positionY\":96}},{\"key\":\"end-node\",\"type\":3,\"incoming\":[\"SequenceFlow_mgxgy62ycwn9ca\"],\"outgoing\":[],\"properties\":{\"positionX\":576,\"positionY\":80}},{\"key\":\"serviceTask_mgxfv7fk1v40d9\",\"type\":5,\"incoming\":[\"SequenceFlow_mgxfy945jnpgtk\"],\"outgoing\":[\"SequenceFlow_mgxgy4t2xqtz2x\"],\"properties\":{\"subType\":\"sql\",\"datasourceName\":\"system\",\"script\":\"create table if no...[truncated]", status: 2, create_time: "2025-10-19 19:51:42", modify_time: "2025-10-19 19:51:42", operator: "admin", remark: "通过sql执行日志归档", archive: 0, caller: "admin", is_deleted: false, project_id: "default", created_by: null, updated_by: null, created_at: "2025-10-19 19:51:42", updated_at: "2025-10-19 19:51:42"}, + {flow_module_id: "5c41f37a-87a9-47af-bdba-44d0c27eda89", flow_name: "testFlowName_1757909108656", flow_key: "testFlowKey_1757909108656", flow_model: "{\"flowElementList\":[{\"key\":\"startEvent1\",\"type\":2,\"outgoing\":[\"sequenceFlow1\"]},{\"key\":\"sequenceFlow1\",\"type\":1,\"outgoing\":[\"userTask1\"],\"incoming\":[\"startEvent1\"]},{\"key\":\"userTask1\",\"type\":4,\"outgoing\":[\"sequenceFlow2\"],\"incoming\":[\"sequenceFlow1\"]},{\"key\":\"sequenceFlow2\",\"type\":1,\"outgoing\":[\"exclusiveGateway1\"],\"incoming\":[\"userTask1\"]},{\"key\":\"exclusiveGateway1\",\"type\":6,\"outgoing\":[\"sequenceFlow3\",\"sequenceFlow4\"],\"properties\":{\"hookInfoIds\":\"[1,2]\"},\"incoming\":[\"sequenceFlow2\"]},{\"key\":\"s...[truncated]", status: 2, create_time: "2025-09-15 12:05:09.000", modify_time: "2025-09-15 12:05:09.000", operator: "testOperator", remark: "testRemark", archive: 0, caller: "testCaller", project_id: "dev_test"}, + {flow_module_id: "9243be36-9ced-4413-acd5-5fc93a05c698", flow_name: "脚本测试", flow_key: "script_test", flow_model: "{\"flowElementList\":[{\"key\":\"start-node\",\"type\":2,\"incoming\":[],\"outgoing\":[\"SequenceFlow_miclvtzacagocb\"],\"properties\":{\"positionX\":-96,\"positionY\":64,\"name\":\"Start\"}},{\"key\":\"end-node\",\"type\":3,\"incoming\":[\"SequenceFlow_miclvvbzb9t82p\"],\"outgoing\":[],\"properties\":{\"positionX\":800,\"positionY\":48,\"name\":\"End\"}},{\"key\":\"serviceTask_miclvseffazfuf\",\"type\":5,\"incoming\":[\"SequenceFlow_miclvtzacagocb\"],\"outgoing\":[\"SequenceFlow_miclvvbzb9t82p\"],\"properties\":{\"subType\":\"script\",\"script\":\"\"hello world\\...[truncated]", status: 2, create_time: "2025-10-14T11:23:02.659", modify_time: "2025-10-14T11:23:02.660", operator: "admin", remark: "Javascript脚本测试", archive: 0, caller: "admin", project_id: "dev_test"}, + {flow_module_id: "da5835fe-e82a-447f-b614-c0ce9aaecb78", flow_name: "增删改查测试", flow_key: "crud_test", flow_model: "{\"flowElementList\":[{\"key\":\"start-node\",\"type\":2,\"incoming\":[],\"outgoing\":[\"SequenceFlow_mgoksf9skg7m1c\"],\"properties\":{\"positionX\":-496,\"positionY\":48}},{\"key\":\"end-node\",\"type\":3,\"incoming\":[\"SequenceFlow_mgolxly85affbh\"],\"outgoing\":[],\"properties\":{\"positionX\":1408,\"positionY\":48}},{\"key\":\"serviceTask_mgokolh6ottxgz\",\"type\":5,\"incoming\":[\"SequenceFlow_mgoksf9skg7m1c\"],\"outgoing\":[\"SequenceFlow_mgokv2z5j6tju7\"],\"properties\":{\"subType\":\"insert_record\",\"datasourceName\":\"dev_test\",\"modelName\":\"Te...[truncated]", status: 2, create_time: "2025-09-15 12:05:09.000", modify_time: "2025-09-15 12:05:09.000", operator: "admin", remark: "增删改查测试", archive: 0, project_id: "dev_test"}, +} + +seed f_em_flow_deployment { + {flow_deploy_id: "96933bb6-4e5a-43f2-9d0a-61b3fb7111fa", flow_module_id: "22203aa0-5f25-4b8a-974d-e4288c1bbd18", flow_name: "日志归档流程", flow_key: "log_archive_task", flow_model: "{\"flowElementList\":[{\"key\":\"start-node\",\"type\":2,\"incoming\":[],\"outgoing\":[\"SequenceFlow_mgxfy945jnpgtk\"],\"properties\":{\"positionX\":-112,\"positionY\":96}},{\"key\":\"end-node\",\"type\":3,\"incoming\":[\"SequenceFlow_mgxgy62ycwn9ca\"],\"outgoing\":[],\"properties\":{\"positionX\":576,\"positionY\":80}},{\"key\":\"serviceTask_mgxfv7fk1v40d9\",\"type\":5,\"incoming\":[\"SequenceFlow_mgxfy945jnpgtk\"],\"outgoing\":[\"SequenceFlow_mgxgy4t2xqtz2x\"],\"properties\":{\"subType\":\"sql\",\"datasourceName\":\"system\",\"script\":\"create table if no...[truncated]", status: 1, create_time: "2025-10-19 19:51:42", modify_time: "2025-10-19 19:51:42", operator: "admin", remark: "通过sql执行日志归档", archive: 0, caller: "admin", project_id: "default", created_by: null, updated_by: null, created_at: "2025-10-19 19:51:42", updated_at: "2025-10-19 19:51:42"}, + {flow_deploy_id: "c2d6f2bb-0d7b-4eb0-81a6-5a72262740d4", flow_module_id: "5c41f37a-87a9-47af-bdba-44d0c27eda89", flow_name: "testFlowName_1757909108656", flow_key: "testFlowKey_1757909108656", flow_model: "{\"flowElementList\":[{\"key\":\"startEvent1\",\"type\":2,\"outgoing\":[\"sequenceFlow1\"]},{\"key\":\"sequenceFlow1\",\"type\":1,\"outgoing\":[\"userTask1\"],\"incoming\":[\"startEvent1\"]},{\"key\":\"userTask1\",\"type\":4,\"outgoing\":[\"sequenceFlow2\"],\"incoming\":[\"sequenceFlow1\"]},{\"key\":\"sequenceFlow2\",\"type\":1,\"outgoing\":[\"exclusiveGateway1\"],\"incoming\":[\"userTask1\"]},{\"key\":\"exclusiveGateway1\",\"type\":6,\"outgoing\":[\"sequenceFlow3\",\"sequenceFlow4\"],\"properties\":{\"hookInfoIds\":\"[1,2]\"},\"incoming\":[\"sequenceFlow2\"]},{\"key\":\"s...[truncated]", status: 1, create_time: "2025-09-15 12:05:09.000", modify_time: "2025-09-15 12:05:09.000", operator: "testOperator", remark: "testRemark", archive: 0, caller: "testCaller", project_id: "dev_test"}, + {flow_deploy_id: "fce9c1e9-57dd-483e-bba1-dd7cb5a53ca7", flow_module_id: "da5835fe-e82a-447f-b614-c0ce9aaecb78", flow_name: "增删改查测试", flow_key: "crud_test", flow_model: "{\"flowElementList\":[{\"key\":\"start-node\",\"type\":2,\"incoming\":[],\"outgoing\":[\"SequenceFlow_mgoksf9skg7m1c\"],\"properties\":{\"positionX\":-496,\"positionY\":48}},{\"key\":\"end-node\",\"type\":3,\"incoming\":[\"SequenceFlow_mgolxly85affbh\"],\"outgoing\":[],\"properties\":{\"positionX\":1408,\"positionY\":48}},{\"key\":\"serviceTask_mgokolh6ottxgz\",\"type\":5,\"incoming\":[\"SequenceFlow_mgoksf9skg7m1c\"],\"outgoing\":[\"SequenceFlow_mgokv2z5j6tju7\"],\"properties\":{\"subType\":\"insert_record\",\"datasourceName\":\"dev_test\",\"modelName\":\"Te...[truncated]", status: 1, create_time: "2025-09-15 12:05:09.000", modify_time: "2025-09-15 12:05:09.000", operator: "admin", remark: "增删改查测试", archive: 0, caller: "admin", project_id: "dev_test"}, + {flow_deploy_id: "1fe532ae-33c4-4f57-aabe-62640da4f185", flow_module_id: "9243be36-9ced-4413-acd5-5fc93a05c698", flow_name: "脚本测试", flow_key: "script_test", flow_model: "{\"flowElementList\":[{\"key\":\"start-node\",\"type\":2,\"incoming\":[],\"outgoing\":[\"SequenceFlow_miclvtzacagocb\"],\"properties\":{\"positionX\":-96,\"positionY\":64,\"name\":\"Start\"}},{\"key\":\"end-node\",\"type\":3,\"incoming\":[\"SequenceFlow_miclvvbzb9t82p\"],\"outgoing\":[],\"properties\":{\"positionX\":800,\"positionY\":48,\"name\":\"End\"}},{\"key\":\"serviceTask_miclvseffazfuf\",\"type\":5,\"incoming\":[\"SequenceFlow_miclvtzacagocb\"],\"outgoing\":[\"SequenceFlow_miclvvbzb9t82p\"],\"properties\":{\"subType\":\"script\",\"script\":\"\"hello world\\...[truncated]", status: 1, create_time: "2025-10-14T11:23:02.659", modify_time: "2025-10-14T11:23:02.660", operator: "admin", remark: "Javascript脚本测试", archive: 0, caller: "admin", project_id: "dev_test"}, +} + +seed f_identity_provider { + {name: "demo", project_id: "dev_test", provider: {type: "oidc", issuer: "http://localhost/issuer", client_id: "test_client_id", client_secret: "test_client_secret"}}, + {name: "default", created_at: "2024-07-13T23:21:09", updated_at: "2024-07-13T23:21:09", created_by: "admin", updated_by: "admin", project_id: "default", provider: {type: "script", script: "const request = context.request;\nconst response = context.response;\nconst log = context.log;\nconst jwtVerify = context.utils.jwtVerify;\n// Example: simple token check from header\nlog.info('identify context: {}', context);\nconst auth = request.headers['authorization'] || request.headers['Authorization'];\nif (!auth || !auth.startsWith('Bearer ')) {\n response.body = { success: false, message: 'Missing bearer token' };\n} else {\n const token = auth.substring('Bearer '.length);\n try {\n // verify...[truncated]"}}, +} + +seed f_trigger { + {id: "4e8be2da-8ae7-4571-b347-61af5fdd3e9b", name: "请求日志归档任务", description: "写入日志归档表进行数据归档", type: "EVENT", config: {type: "event", modelName: "f_api_request_log", mutationTypes: ["create"], triggerTiming: "after", datasourceName: "system"}, job_type: "FLOW", job_group: "system_f_api_request_log", job_id: "22203aa0-5f25-4b8a-974d-e4288c1bbd18", state: false, created_at: "2025-10-19 17:59:45", updated_at: "2025-10-19 20:38:24", created_by: null, updated_by: null, project_id: "default"}, + {id: "bf492f37-1f01-4eb8-b76d-d319299b4d8e", name: "定时触发-间隔触发", description: "定时触发-间隔触发-备注", type: "SCHEDULED", config: {type: "interval", interval: 1, intervalUnit: "minute", repeatCount: 100}, job_id: "5c41f37a-87a9-47af-bdba-44d0c27eda89", job_type: "FLOW", job_group: "testFlowName_1757909108656", state: false, created_at: "2025-09-15 12:05:09.000", updated_at: "2025-09-15 12:05:09.000", project_id: "dev_test"}, + {id: "d8c60d2a-19d8-4c3c-b370-96318733858f", name: "定时触发-Cron表达式", description: "定时触发-Cron表达式-备注", type: "SCHEDULED", config: {type: "cron", cronExpression: "0 0 * * * ? *"}, job_id: "5c41f37a-87a9-47af-bdba-44d0c27eda89", job_type: "FLOW", job_group: "testFlowName_1757909108656", state: false, created_at: "2025-09-15 12:05:09.000", updated_at: "2025-09-15 12:05:09.000", project_id: "dev_test"}, + {id: "9434666d-6b3b-417a-80e3-3352f40ded71", name: "事件触发-之前", description: "事件触发-之前-描述", type: "EVENT", config: {type: "event", datasourceName: "dev_test", modelName: "Student", mutationTypes: ["delete", "update", "create"], triggerTiming: "after"}, job_id: "5c41f37a-87a9-47af-bdba-44d0c27eda89", job_type: "FLOW", job_group: "dev_test_Student", state: true, created_at: "2025-09-15 12:05:09.000", updated_at: "2025-09-15 12:05:09.000", project_id: "dev_test"}, + {id: "f351b8d9-a450-4f2c-8fff-cf862d690352", name: "事件触发-之后", description: "事件触发-之后-描述", type: "EVENT", config: {type: "event", datasourceName: "dev_test", modelName: "Classes", mutationTypes: ["create", "update", "delete"], triggerTiming: "after"}, job_id: "5c41f37a-87a9-47af-bdba-44d0c27eda89", job_type: "FLOW", job_group: "dev_test_Classes", state: true, created_at: "2025-09-15 12:05:09.000", updated_at: "2025-09-15 12:05:09.000", project_id: "dev_test"}, +} + diff --git a/flexmodel-server/src/main/resources/schema.idl b/flexmodel-server/src/main/resources/schema.fml similarity index 100% rename from flexmodel-server/src/main/resources/schema.idl rename to flexmodel-server/src/main/resources/schema.fml diff --git a/flexmodel-server/src/test/java/dev/flexmodel/SQLiteTestResource.java b/flexmodel-server/src/test/java/dev/flexmodel/SQLiteTestResource.java index 9a144731..791c05b9 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/SQLiteTestResource.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/SQLiteTestResource.java @@ -2,30 +2,60 @@ import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; import java.util.Map; +import java.util.UUID; /** * @author cjbi */ public class SQLiteTestResource implements QuarkusTestResourceLifecycleManager { + private File testDbFile; + private File testDevDbFile; + @Override public Map start() { - // 使用内存SQLite数据库进行测试 + // 为每次测试创建唯一的临时文件数据库,避免测试之间的状态污染 + String testId = UUID.randomUUID().toString().substring(0, 8); + testDbFile = createTempDbFile("flexmodel-test-" + testId + ".db"); + testDevDbFile = createTempDbFile("flexmodel-dev-test-" + testId + ".db"); + return Map.of( "flexmodel.datasource.db-kind", "sqlite", - "flexmodel.datasource.url", "jdbc:sqlite:file::memory:?cache=shared", -// "flexmodel.datasource.url", "jdbc:sqlite:file:sqlite.db", + "flexmodel.datasource.url", "jdbc:sqlite:file:" + testDbFile.getAbsolutePath(), "flexmodel.datasource.username", "", "flexmodel.datasource.password", "", - "SQLITE_URL", "jdbc:sqlite:file::memory:?cache=shared", -// "SQLITE_URL", "jdbc:sqlite:file:sqlite.db", + "SQLITE_URL", "jdbc:sqlite:file:" + testDbFile.getAbsolutePath(), "SQLITE_USERNAME", "", - "SQLITE_PASSWORD", ""); + "SQLITE_PASSWORD", "", + "flexmodel.datasource.dev_test.db-kind", "sqlite", + "flexmodel.datasource.dev_test.url", "jdbc:sqlite:file:" + testDevDbFile.getAbsolutePath()); + } + + private File createTempDbFile(String name) { + File tempDir = new File(System.getProperty("java.io.tmpdir"), "flexmodel-test"); + if (!tempDir.exists()) { + tempDir.mkdirs(); + } + File dbFile = new File(tempDir, name); + // 删除可能存在的旧文件 + if (dbFile.exists()) { + dbFile.delete(); + } + return dbFile; } @Override public void stop() { - // SQLite内存数据库会在JVM关闭时自动清理,无需手动停止 + // 清理临时数据库文件 + if (testDbFile != null && testDbFile.exists()) { + testDbFile.delete(); + } + if (testDevDbFile != null && testDevDbFile.exists()) { + testDevDbFile.delete(); + } } } diff --git a/flexmodel-server/src/test/java/dev/flexmodel/TestDataInitializer.java b/flexmodel-server/src/test/java/dev/flexmodel/TestDataInitializer.java new file mode 100644 index 00000000..93555623 --- /dev/null +++ b/flexmodel-server/src/test/java/dev/flexmodel/TestDataInitializer.java @@ -0,0 +1,52 @@ +package dev.flexmodel; + +import io.quarkus.runtime.StartupEvent; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Singleton; +import lombok.extern.slf4j.Slf4j; +import dev.flexmodel.session.SessionFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +/** + * 测试数据初始化器 + * 在测试启动时加载dev_test项目的schema和数据 + * + * @author cjbi + */ +@Singleton +@Slf4j +public class TestDataInitializer { + + private boolean initialized = false; + + void initTestData(@Observes StartupEvent event, SessionFactory sessionFactory) { + if (initialized) { + return; + } + + try { + log.info("Initializing test data for dev_test project..."); + + // 加载dev_test的schema和数据(FML格式) + try (InputStream fmlStream = getClass().getClassLoader() + .getResourceAsStream("dev_test.fml")) { + if (fmlStream == null) { + log.warn("dev_test.fml not found, skipping test data initialization"); + return; + } + String fmlContent = new String(fmlStream.readAllBytes(), StandardCharsets.UTF_8); + sessionFactory.loadFMLString("dev_test", fmlContent); + log.info("Loaded dev_test schema and data from FML"); + } + + initialized = true; + log.info("Test data initialization completed"); + } catch (IOException e) { + log.error("Failed to initialize test data", e); + throw new RuntimeException("Failed to initialize test data", e); + } + } +} diff --git a/flexmodel-server/src/test/java/dev/flexmodel/shared/matchers/UriTemplateTest.java b/flexmodel-server/src/test/java/dev/flexmodel/common/matchers/UriTemplateTest.java similarity index 84% rename from flexmodel-server/src/test/java/dev/flexmodel/shared/matchers/UriTemplateTest.java rename to flexmodel-server/src/test/java/dev/flexmodel/common/matchers/UriTemplateTest.java index ee52e7a7..fe99ad5b 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/shared/matchers/UriTemplateTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/common/matchers/UriTemplateTest.java @@ -1,6 +1,5 @@ -package dev.flexmodel.shared.matchers; +package dev.flexmodel.common.matchers; -import dev.flexmodel.shared.matchers.UriTemplate; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/shared/PatternMatchUtilsTest.java b/flexmodel-server/src/test/java/dev/flexmodel/common/utils/PatternMatchUtilsTest.java similarity index 88% rename from flexmodel-server/src/test/java/dev/flexmodel/shared/PatternMatchUtilsTest.java rename to flexmodel-server/src/test/java/dev/flexmodel/common/utils/PatternMatchUtilsTest.java index 4d446acb..c295de60 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/shared/PatternMatchUtilsTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/common/utils/PatternMatchUtilsTest.java @@ -1,8 +1,8 @@ -package dev.flexmodel.shared; +package dev.flexmodel.common.utils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import dev.flexmodel.shared.utils.PatternMatchUtils; +import dev.flexmodel.common.utils.PatternMatchUtils; /** * @author cjbi diff --git a/flexmodel-server/src/test/java/dev/flexmodel/shared/StringUtilsTest.java b/flexmodel-server/src/test/java/dev/flexmodel/common/utils/StringUtilsTest.java similarity index 89% rename from flexmodel-server/src/test/java/dev/flexmodel/shared/StringUtilsTest.java rename to flexmodel-server/src/test/java/dev/flexmodel/common/utils/StringUtilsTest.java index bde79855..32ee17af 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/shared/StringUtilsTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/common/utils/StringUtilsTest.java @@ -1,8 +1,8 @@ -package dev.flexmodel.shared; +package dev.flexmodel.common.utils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import dev.flexmodel.shared.utils.StringUtils; +import dev.flexmodel.common.utils.StringUtils; import java.util.Map; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/shared/EntityBuilder.java b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/EntityBuilder.java similarity index 99% rename from flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/shared/EntityBuilder.java rename to flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/EntityBuilder.java index 25b25f7a..f97de73f 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/shared/EntityBuilder.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/EntityBuilder.java @@ -1,12 +1,12 @@ -package dev.flexmodel.domain.model.flow.shared; +package dev.flexmodel.domain.model.flow; -import dev.flexmodel.domain.model.flow.dto.model.*; -import dev.flexmodel.domain.model.flow.dto.param.*; -import dev.flexmodel.domain.model.flow.shared.common.*; import dev.flexmodel.codegen.entity.*; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstanceBO; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.flow.common.*; +import dev.flexmodel.flow.dto.bo.NodeInstanceBO; +import dev.flexmodel.flow.dto.model.*; +import dev.flexmodel.flow.dto.param.*; +import dev.flexmodel.flow.common.util.FlowModelUtil; +import dev.flexmodel.common.utils.JsonUtils; import java.time.LocalDateTime; import java.util.*; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/executor/ExclusiveGatewayExecutorTest.java b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/executor/ExclusiveGatewayExecutorTest.java index b8ad1bef..2215fbb9 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/executor/ExclusiveGatewayExecutorTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/executor/ExclusiveGatewayExecutorTest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.executor; +package dev.flexmodel.flow.executor; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; @@ -8,12 +8,12 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import dev.flexmodel.SQLiteTestResource; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.dto.model.FlowModel; -import dev.flexmodel.domain.model.flow.shared.EntityBuilder; -import dev.flexmodel.domain.model.flow.shared.common.RuntimeContext; -import dev.flexmodel.domain.model.flow.shared.util.FlowModelUtil; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.dto.model.FlowModel; +import dev.flexmodel.domain.model.flow.EntityBuilder; +import dev.flexmodel.flow.common.RuntimeContext; +import dev.flexmodel.flow.common.util.FlowModelUtil; +import dev.flexmodel.common.utils.JsonUtils; import java.util.HashMap; import java.util.List; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/executor/ServiceTaskExecutorTest.java b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/executor/ServiceTaskExecutorTest.java index 62834367..9fbb3e35 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/executor/ServiceTaskExecutorTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/executor/ServiceTaskExecutorTest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.executor; +package dev.flexmodel.flow.executor; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; @@ -7,12 +7,12 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import dev.flexmodel.SQLiteTestResource; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstanceBO; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.domain.model.flow.shared.common.NodeInstanceStatus; -import dev.flexmodel.domain.model.flow.shared.common.RuntimeContext; +import dev.flexmodel.flow.dto.bo.NodeInstanceBO; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.flow.common.NodeInstanceStatus; +import dev.flexmodel.flow.common.RuntimeContext; import java.util.ArrayList; import java.util.HashMap; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/processor/DefinitionProcessorTest.java b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/processor/DefinitionProcessorTest.java index babdd24d..40787129 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/processor/DefinitionProcessorTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/processor/DefinitionProcessorTest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.processor; +package dev.flexmodel.flow.processor; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; @@ -7,16 +7,16 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import dev.flexmodel.SQLiteTestResource; -import dev.flexmodel.domain.model.flow.dto.param.CreateFlowParam; -import dev.flexmodel.domain.model.flow.dto.param.DeployFlowParam; -import dev.flexmodel.domain.model.flow.dto.param.GetFlowModuleParam; -import dev.flexmodel.domain.model.flow.dto.param.UpdateFlowParam; -import dev.flexmodel.domain.model.flow.dto.result.CreateFlowResult; -import dev.flexmodel.domain.model.flow.dto.result.DeployFlowResult; -import dev.flexmodel.domain.model.flow.dto.result.FlowModuleResult; -import dev.flexmodel.domain.model.flow.dto.result.UpdateFlowResult; -import dev.flexmodel.domain.model.flow.shared.EntityBuilder; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; +import dev.flexmodel.flow.dto.param.CreateFlowParam; +import dev.flexmodel.flow.dto.param.DeployFlowParam; +import dev.flexmodel.flow.dto.param.GetFlowModuleParam; +import dev.flexmodel.flow.dto.param.UpdateFlowParam; +import dev.flexmodel.flow.dto.result.CreateFlowResult; +import dev.flexmodel.flow.dto.result.DeployFlowResult; +import dev.flexmodel.flow.dto.result.FlowModuleResult; +import dev.flexmodel.flow.dto.result.UpdateFlowResult; +import dev.flexmodel.domain.model.flow.EntityBuilder; +import dev.flexmodel.flow.common.ErrorEnum; /** * @author cjbi diff --git a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/processor/RuntimeProcessorTest.java b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/processor/RuntimeProcessorTest.java index ccf82f85..415fc04a 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/processor/RuntimeProcessorTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/processor/RuntimeProcessorTest.java @@ -1,6 +1,6 @@ -package dev.flexmodel.domain.model.flow.processor; +package dev.flexmodel.flow.processor; -import dev.flexmodel.domain.model.flow.dto.result.*; +import dev.flexmodel.flow.dto.result.*; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; import jakarta.inject.Inject; @@ -9,15 +9,15 @@ import org.junit.jupiter.api.Test; import dev.flexmodel.SQLiteTestResource; import dev.flexmodel.codegen.entity.FlowDeployment; -import dev.flexmodel.domain.model.flow.dto.bo.ElementInstance; -import dev.flexmodel.domain.model.flow.dto.bo.NodeInstance; -import dev.flexmodel.domain.model.flow.dto.param.CommitTaskParam; -import dev.flexmodel.domain.model.flow.dto.param.RollbackTaskParam; -import dev.flexmodel.domain.model.flow.dto.param.StartProcessParam; -import dev.flexmodel.domain.model.flow.repository.FlowDeploymentRepository; -import dev.flexmodel.domain.model.flow.shared.EntityBuilder; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; -import dev.flexmodel.shared.utils.JsonUtils; +import dev.flexmodel.flow.dto.bo.ElementInstance; +import dev.flexmodel.flow.dto.bo.NodeInstance; +import dev.flexmodel.flow.dto.param.CommitTaskParam; +import dev.flexmodel.flow.dto.param.RollbackTaskParam; +import dev.flexmodel.flow.dto.param.StartProcessParam; +import dev.flexmodel.flow.repository.FlowDeploymentRepository; +import dev.flexmodel.domain.model.flow.EntityBuilder; +import dev.flexmodel.flow.common.ErrorEnum; +import dev.flexmodel.common.utils.JsonUtils; import java.util.HashMap; import java.util.Map; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/shared/util/GroovyUtilTest.java b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/shared/util/GroovyUtilTest.java deleted file mode 100644 index 93557914..00000000 --- a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/shared/util/GroovyUtilTest.java +++ /dev/null @@ -1,643 +0,0 @@ -package dev.flexmodel.domain.model.flow.shared.util; - -import dev.flexmodel.domain.model.flow.shared.util.GroovyUtil; -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.shared.common.ErrorEnum; - -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -@Slf4j -public class GroovyUtilTest { - - /** - * 测试空表达式和null表达式的情况 - */ - @Test - public void testEmptyExpression() throws Exception { - // 测试空字符串 - Object result1 = GroovyUtil.execute("", new HashMap<>()); - Assertions.assertNull(result1); - - // 测试null表达式 - Object result2 = GroovyUtil.execute(null, new HashMap<>()); - Assertions.assertNull(result2); - - // 测试空白字符串 - Object result3 = GroovyUtil.execute(" ", new HashMap<>()); - Assertions.assertNull(result3); - } - - /** - * 测试基本数学运算 - */ - @Test - public void testBasicCalculations() throws Exception { - Map dataMap = new HashMap<>(); - - // 测试加法 - Object result1 = GroovyUtil.execute("2 + 3", dataMap); - Assertions.assertEquals(5, result1); - - // 测试减法 - Object result2 = GroovyUtil.execute("10 - 4", dataMap); - Assertions.assertEquals(6, result2); - - // 测试乘法 - Object result3 = GroovyUtil.execute("3 * 4", dataMap); - Assertions.assertEquals(12, result3); - - // 测试除法 - Object result4 = GroovyUtil.execute("15 / 3", dataMap); - Assertions.assertEquals(5, Integer.valueOf(Objects.requireNonNull(result4).toString())); - - // 测试复杂表达式 - Object result5 = GroovyUtil.execute("(2 + 3) * 4 - 1", dataMap); - Assertions.assertEquals(19, result5); - } - - /** - * 测试逻辑运算 - */ - @Test - public void testLogicalOperations() throws Exception { - Map dataMap = new HashMap<>(); - - // 测试布尔运算 - Object result1 = GroovyUtil.execute("true && false", dataMap); - Assertions.assertEquals(false, result1); - - Object result2 = GroovyUtil.execute("true || false", dataMap); - Assertions.assertEquals(true, result2); - - // 测试比较运算 - Object result3 = GroovyUtil.execute("5 > 3", dataMap); - Assertions.assertEquals(true, result3); - - Object result4 = GroovyUtil.execute("5 == 5", dataMap); - Assertions.assertEquals(true, result4); - - Object result5 = GroovyUtil.execute("5 != 3", dataMap); - Assertions.assertEquals(true, result5); - } - - /** - * 测试变量绑定和数据传递 - */ - @Test - public void testVariableBinding() throws Exception { - Map dataMap = new HashMap<>(); - dataMap.put("a", 10); - dataMap.put("b", 20); - dataMap.put("name", "张三"); - dataMap.put("age", 25); - - // 测试数字变量 - Object result1 = GroovyUtil.execute("a + b", dataMap); - Assertions.assertEquals(30, result1); - - // 测试字符串变量 - Object result2 = GroovyUtil.execute("name + '的年龄是' + age", dataMap); - Assertions.assertEquals("张三的年龄是25", result2); - - // 测试条件判断 - Object result3 = GroovyUtil.execute("age > 18 ? '成年人' : '未成年人'", dataMap); - Assertions.assertEquals("成年人", result3); - } - - /** - * 测试字符串操作 - */ - @Test - public void testStringOperations() throws Exception { - Map dataMap = new HashMap<>(); - dataMap.put("str1", "Hello"); - dataMap.put("str2", "World"); - - // 测试字符串连接 - Object result1 = GroovyUtil.execute("str1 + ' ' + str2", dataMap); - Assertions.assertEquals("Hello World", result1); - - // 测试字符串方法 - Object result2 = GroovyUtil.execute("str1.toUpperCase()", dataMap); - Assertions.assertEquals("HELLO", result2); - - // 测试字符串长度 - Object result3 = GroovyUtil.execute("str1.length()", dataMap); - Assertions.assertEquals(5, result3); - - // 测试字符串包含 - Object result4 = GroovyUtil.execute("str1.contains('ell')", dataMap); - Assertions.assertEquals(true, result4); - } - - /** - * 测试缺失属性异常处理 - */ - @Test - public void testMissingPropertyException() { - Map dataMap = new HashMap<>(); - - // 测试访问不存在的变量 - ProcessException exception = Assertions.assertThrows(ProcessException.class, () -> { - GroovyUtil.execute("undefinedVariable", dataMap); - }); - - Assertions.assertEquals(ErrorEnum.MISSING_DATA.getErrNo(), exception.getErrNo()); - } - - /** - * 测试语法错误和运行时异常 - */ - @Test - public void testSyntaxErrors() { - Map dataMap = new HashMap<>(); - - // 测试语法错误 - 无效的变量声明 - Assertions.assertThrows(Exception.class, () -> { - GroovyUtil.execute("int i = i;", dataMap); - }); - - // 测试语法错误 - 无效的字符串比较 - Assertions.assertThrows(Exception.class, () -> { - GroovyUtil.execute("String String == '111';", dataMap); - }); - - // 测试语法错误 - 不存在的方法 - Assertions.assertThrows(Exception.class, () -> { - GroovyUtil.execute("String.equals111('123')", dataMap); - }); - - // 测试类型转换错误 - Assertions.assertThrows(Exception.class, () -> { - GroovyUtil.execute("int a = '123';", dataMap); - }); - - // 测试除零错误 - Assertions.assertThrows(Exception.class, () -> { - GroovyUtil.execute("1/0", dataMap); - }); - } - - /** - * 测试脚本缓存机制 - */ - @Test - public void testScriptCaching() throws Exception { - Map dataMap = new HashMap<>(); - String expression = "2 + 3"; - - // 第一次执行 - Object result1 = GroovyUtil.execute(expression, dataMap); - Assertions.assertEquals(5, result1); - - // 第二次执行相同表达式,应该使用缓存 - Object result2 = GroovyUtil.execute(expression, dataMap); - Assertions.assertEquals(5, result2); - - // 验证结果一致性 - Assertions.assertEquals(result1, result2); - } - - /** - * 测试边界情况和特殊场景 - */ - @Test - public void testEdgeCases() throws Exception { - Map dataMap = new HashMap<>(); - - // 测试null值处理 - dataMap.put("nullValue", null); - Object result1 = GroovyUtil.execute("nullValue == null", dataMap); - Assertions.assertEquals(true, result1); - - // 测试空字符串 - dataMap.put("emptyStr", ""); - Object result2 = GroovyUtil.execute("emptyStr.isEmpty()", dataMap); - Assertions.assertEquals(true, result2); - - // 测试负数 - Object result3 = GroovyUtil.execute("-5 + 3", dataMap); - Assertions.assertEquals(-2, result3); - - // 测试小数运算 - Object result4 = GroovyUtil.execute("3.14 * 2", dataMap); - Assertions.assertNotNull(result4); - Assertions.assertEquals(6.28, Double.parseDouble(result4.toString())); - - // 测试布尔值 - dataMap.put("flag", true); - Object result5 = GroovyUtil.execute("!flag", dataMap); - Assertions.assertEquals(false, result5); - } - - /** - * 测试复杂业务场景 - */ - @Test - public void testComplexBusinessScenarios() throws Exception { - Map dataMap = new HashMap<>(); - dataMap.put("price", 100.0); - dataMap.put("quantity", 5); - dataMap.put("discount", 0.1); - dataMap.put("taxRate", 0.08); - - // 计算总价:价格 * 数量 * (1 - 折扣) * (1 + 税率) - Object totalPrice = GroovyUtil.execute("price * quantity * (1 - discount) * (1 + taxRate)", dataMap); - Assertions.assertNotNull(totalPrice); - BigDecimal scale = new BigDecimal(totalPrice.toString()).setScale(2, RoundingMode.HALF_UP); - Assertions.assertEquals(486.00, scale.doubleValue()); - - // 测试条件判断 - dataMap.put("score", 85); - Object grade = GroovyUtil.execute("score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : 'D'", dataMap); - Assertions.assertEquals("B", grade); - } - - /** - * 测试数组和集合操作 - */ - @Test - public void testArrayAndCollectionOperations() throws Exception { - Map dataMap = new HashMap<>(); - dataMap.put("numbers", new int[]{1, 2, 3, 4, 5}); - - // 测试数组长度 - Object result1 = GroovyUtil.execute("numbers.length", dataMap); - Assertions.assertEquals(5, result1); - - // 测试数组元素访问 - Object result2 = GroovyUtil.execute("numbers[0]", dataMap); - Assertions.assertEquals(1, result2); - - // 测试数组求和 - Object result3 = GroovyUtil.execute("numbers.sum()", dataMap); - Assertions.assertEquals(15, result3); - } - - /** - * 测试多行代码执行 - */ - @Test - public void testMultiLineCodeExecution() throws Exception { - Map dataMap = new HashMap<>(); - dataMap.put("baseSalary", 5000); - dataMap.put("bonus", 1000); - dataMap.put("taxRate", 0.1); - - // 测试多行代码:计算税后工资 - String multiLineCode = """ - def grossSalary = baseSalary + bonus - def tax = grossSalary * taxRate - def netSalary = grossSalary - tax - return netSalary - """; - - Object result = GroovyUtil.execute(multiLineCode, dataMap); - Assertions.assertEquals(5400.0, result); - - // 测试多行代码:字符串处理 - dataMap.put("text", " Hello World "); - String stringProcessingCode = """ - def trimmed = text.trim() - def upper = trimmed.toUpperCase() - def words = upper.split(' ') - return words.length - """; - - Object wordCount = GroovyUtil.execute(stringProcessingCode, dataMap); - Assertions.assertEquals(2, wordCount); - } - - /** - * 测试复杂对象返回 - */ - @Test - public void testComplexObjectReturn() throws Exception { - Map dataMap = new HashMap<>(); - dataMap.put("name", "张三"); - dataMap.put("age", 30); - dataMap.put("salary", 8000); - - // 测试返回Map对象 - String mapReturnCode = """ - def person = [:] - person.name = name - person.age = age - person.salary = salary - person.category = age > 25 ? 'senior' : 'junior' - return person - """; - - Object result = GroovyUtil.execute(mapReturnCode, dataMap); - Assertions.assertNotNull(result); - Assertions.assertTrue(result instanceof Map); - - @SuppressWarnings("unchecked") - Map personMap = (Map) result; - Assertions.assertEquals("张三", personMap.get("name")); - Assertions.assertEquals(30, personMap.get("age")); - Assertions.assertEquals(8000, personMap.get("salary")); - Assertions.assertEquals("senior", personMap.get("category")); - - // 测试返回List对象 - String listReturnCode = """ - def numbers = [1, 2, 3, 4, 5] - def doubled = numbers.collect { it * 2 } - return doubled - """; - - Object listResult = GroovyUtil.execute(listReturnCode, dataMap); - Assertions.assertNotNull(listResult); - Assertions.assertTrue(listResult instanceof java.util.List); - - @SuppressWarnings("unchecked") - java.util.List doubledList = (java.util.List) listResult; - Assertions.assertEquals(5, doubledList.size()); - Assertions.assertEquals(2, doubledList.get(0)); - Assertions.assertEquals(10, doubledList.get(4)); - } - - /** - * 测试函数定义和执行 - */ - @Test - public void testFunctionDefinitionAndExecution() throws Exception { - Map dataMap = new HashMap<>(); - dataMap.put("radius", 5.0); - - // 测试函数定义和调用 - String functionCode = """ - def calculateArea(r) { - return Math.PI * r * r - } - - def calculateCircumference(r) { - return 2 * Math.PI * r - } - - def area = calculateArea(radius) - def circumference = calculateCircumference(radius) - - return [area: area, circumference: circumference] - """; - - Object result = GroovyUtil.execute(functionCode, dataMap); - Assertions.assertNotNull(result); - Assertions.assertTrue(result instanceof Map); - - @SuppressWarnings("unchecked") - Map circleData = (Map) result; - Assertions.assertTrue(circleData.containsKey("area")); - Assertions.assertTrue(circleData.containsKey("circumference")); - - double area = ((Number) circleData.get("area")).doubleValue(); - double circumference = ((Number) circleData.get("circumference")).doubleValue(); - - Assertions.assertEquals(78.54, area, 0.01); - Assertions.assertEquals(31.42, circumference, 0.01); - } - - /** - * 测试循环和条件控制流 - */ - @Test - public void testLoopsAndControlFlow() throws Exception { - Map dataMap = new HashMap<>(); - dataMap.put("maxNumber", 10); - - // 测试for循环 - String forLoopCode = """ - def sum = 0 - for (int i = 1; i <= maxNumber; i++) { - sum += i - } - return sum - """; - - Object sumResult = GroovyUtil.execute(forLoopCode, dataMap); - Assertions.assertEquals(55, sumResult); - - // 测试while循环和条件判断 - String whileLoopCode = """ - def number = 100 - def count = 0 - while (number > 1) { - number = number / 2 - count++ - } - return count - """; - - Object countResult = GroovyUtil.execute(whileLoopCode, dataMap); - Assertions.assertEquals(7, countResult); - - // 测试switch语句 - dataMap.put("grade", "B"); - String switchCode = """ - def score - switch (grade) { - case 'A': - score = 90 - break - case 'B': - score = 80 - break - case 'C': - score = 70 - break - default: - score = 60 - } - return score - """; - - Object scoreResult = GroovyUtil.execute(switchCode, dataMap); - Assertions.assertEquals(80, scoreResult); - } - - /** - * 测试集合和Map的高级操作 - */ - @Test - public void testAdvancedCollectionOperations() throws Exception { - Map dataMap = new HashMap<>(); - dataMap.put("numbers", java.util.Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); - - // 测试集合过滤和映射 - String filterMapCode = """ - def evenNumbers = numbers.findAll { it % 2 == 0 } - def squaredEvens = evenNumbers.collect { it * it } - def sum = squaredEvens.sum() - return [evenNumbers: evenNumbers, squaredEvens: squaredEvens, sum: sum] - """; - - Object result = GroovyUtil.execute(filterMapCode, dataMap); - Assertions.assertNotNull(result); - Assertions.assertTrue(result instanceof Map); - - @SuppressWarnings("unchecked") - Map processedData = (Map) result; - - @SuppressWarnings("unchecked") - java.util.List evenNumbers = (java.util.List) processedData.get("evenNumbers"); - @SuppressWarnings("unchecked") - java.util.List squaredEvens = (java.util.List) processedData.get("squaredEvens"); - Integer sum = (Integer) processedData.get("sum"); - - Assertions.assertEquals(5, evenNumbers.size()); - Assertions.assertEquals(2, evenNumbers.get(0)); - Assertions.assertEquals(4, squaredEvens.get(0)); - Assertions.assertEquals(220, sum); - - // 测试Map操作 - dataMap.put("scores", new HashMap() { - { - put("数学", 95); - put("语文", 88); - put("英语", 92); - } - }); - - String mapOperationCode = """ - def totalScore = 0 - def subjectCount = 0 - def averageScore = 0 - - scores.each { subject, score -> - totalScore += score - subjectCount++ - } - - if (subjectCount > 0) { - averageScore = totalScore / subjectCount - } - - return [totalScore: totalScore, subjectCount: subjectCount, averageScore: averageScore] - """; - - Object mapResult = GroovyUtil.execute(mapOperationCode, dataMap); - Assertions.assertNotNull(mapResult); - Assertions.assertTrue(mapResult instanceof Map); - - @SuppressWarnings("unchecked") - Map scoreData = (Map) mapResult; - Assertions.assertEquals(275, scoreData.get("totalScore")); - Assertions.assertEquals(3, scoreData.get("subjectCount")); - BigDecimal averageScore = new BigDecimal(scoreData.get("averageScore").toString()); - Assertions.assertEquals(91.6666666667, averageScore.doubleValue()); - } - - /** - * 测试异常处理和错误恢复 - */ - @Test - public void testExceptionHandlingAndRecovery() throws Exception { - Map dataMap = new HashMap<>(); - dataMap.put("dividend", 10); - dataMap.put("divisor", 0); - - // 测试try-catch异常处理 - String exceptionHandlingCode = """ - def result - try { - result = dividend / divisor - } catch (ArithmeticException e) { - result = "除零错误: " + e.getMessage() - } - return result - """; - - Object result = GroovyUtil.execute(exceptionHandlingCode, dataMap); - Assertions.assertNotNull(result); - Assertions.assertTrue(result.toString().contains("除零错误")); - - // 测试空值安全处理 - dataMap.put("nullableValue", null); - String nullSafetyCode = """ - def safeValue = nullableValue ?: "默认值" - def length = safeValue.length() - return [safeValue: safeValue, length: length] - """; - - Object nullResult = GroovyUtil.execute(nullSafetyCode, dataMap); - Assertions.assertNotNull(nullResult); - Assertions.assertTrue(nullResult instanceof Map); - - @SuppressWarnings("unchecked") - Map nullData = (Map) nullResult; - Assertions.assertEquals("默认值", nullData.get("safeValue")); - Assertions.assertEquals(3, nullData.get("length")); - } - - /** - * 测试性能和多线程安全 - */ - @Test - public void testPerformanceAndThreadSafety() throws Exception { - Map dataMap = new HashMap<>(); - dataMap.put("iterations", 1000); - - // 测试大量计算 - String performanceCode = """ - def startTime = System.currentTimeMillis() - def sum = 0 - for (int i = 0; i < iterations; i++) { - sum += i * i - } - def endTime = System.currentTimeMillis() - def duration = endTime - startTime - return [sum: sum, duration: duration] - """; - - Object result = GroovyUtil.execute(performanceCode, dataMap); - Assertions.assertNotNull(result); - Assertions.assertTrue(result instanceof Map); - - @SuppressWarnings("unchecked") - Map perfData = (Map) result; - Assertions.assertTrue((Integer) perfData.get("sum") > 0); - Assertions.assertTrue((Long) perfData.get("duration") >= 0); - } - - @Test - void testAuthenticate() throws Exception { - String script = """ - /** - * Identity Provider Groovy Script Template - * Implement authenticate(request) to return an object: - * [success: boolean, user: [id: string, name?: string, roles?: string[]], message?: string] - * You can read headers via request.headers and query via request.query - */ - def authenticate(request) { - // Example: simple token check from header - def auth = request.headers['authorization'] ?: request.headers['Authorization'] - if (!auth || !auth.startsWith('Bearer ')) { - return [success: false, message: 'Missing bearer token'] - } - def token = auth.replace('Bearer ','') - // TODO: verify token, fetch user, etc. - if (token == 'demo-token') { - return [success: true, user: [id: 'demo', name: 'Demo User', roles: ['user']]] - } - return [success: false, message: 'Invalid token'] - } - """; - script+="\nreturn authenticate(request)"; - Map dataMap = new HashMap<>(); - dataMap.put("request", Map.of("headers", Map.of("authorization", "Bearer demo-token"))); - - Object result = GroovyUtil.execute(script, dataMap); - Assertions.assertNotNull(result); - @SuppressWarnings("unchecked") - Map resultMap = Assertions.assertInstanceOf(Map.class, result); - Assertions.assertTrue((Boolean) resultMap.get("success")); - } - -} diff --git a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/shared/util/JavaScriptUtilTest.java b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/util/JavaScriptUtilTest.java similarity index 98% rename from flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/shared/util/JavaScriptUtilTest.java rename to flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/util/JavaScriptUtilTest.java index 8bd93b84..b22fc8ce 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/shared/util/JavaScriptUtilTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/util/JavaScriptUtilTest.java @@ -1,13 +1,15 @@ -package dev.flexmodel.domain.model.flow.shared.util; +package dev.flexmodel.domain.model.flow.util; import dev.flexmodel.SQLiteTestResource; +import dev.flexmodel.flow.common.util.JavaScriptUtil; +import dev.flexmodel.flow.common.util.RequestScriptContext; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import dev.flexmodel.domain.model.flow.exception.ProcessException; +import dev.flexmodel.flow.exception.ProcessException; import java.util.HashMap; import java.util.List; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/EndEventValidatorTest.java b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/EndEventValidatorTest.java index fa05eda1..e2226378 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/EndEventValidatorTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/EndEventValidatorTest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; @@ -7,9 +7,9 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import dev.flexmodel.SQLiteTestResource; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.DefinitionException; -import dev.flexmodel.domain.model.flow.shared.EntityBuilder; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.DefinitionException; +import dev.flexmodel.domain.model.flow.EntityBuilder; import java.util.ArrayList; import java.util.HashMap; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/ExclusiveGatewayValidatorTest.java b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/ExclusiveGatewayValidatorTest.java index ef3104fa..292bc360 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/ExclusiveGatewayValidatorTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/ExclusiveGatewayValidatorTest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; @@ -7,9 +7,9 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import dev.flexmodel.SQLiteTestResource; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.DefinitionException; -import dev.flexmodel.domain.model.flow.shared.EntityBuilder; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.DefinitionException; +import dev.flexmodel.domain.model.flow.EntityBuilder; import java.util.HashMap; import java.util.Map; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/FlowModelValidatorTest.java b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/FlowModelValidatorTest.java index e062ea45..d5778c36 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/FlowModelValidatorTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/FlowModelValidatorTest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import io.quarkus.test.common.QuarkusTestResource; @@ -8,14 +8,14 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import dev.flexmodel.SQLiteTestResource; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.dto.model.FlowModel; -import dev.flexmodel.domain.model.flow.dto.model.SequenceFlow; -import dev.flexmodel.domain.model.flow.dto.model.StartEvent; -import dev.flexmodel.domain.model.flow.exception.DefinitionException; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.shared.EntityBuilder; -import dev.flexmodel.domain.model.flow.shared.common.FlowElementType; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.dto.model.FlowModel; +import dev.flexmodel.flow.dto.model.SequenceFlow; +import dev.flexmodel.flow.dto.model.StartEvent; +import dev.flexmodel.flow.exception.DefinitionException; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.domain.model.flow.EntityBuilder; +import dev.flexmodel.flow.common.FlowElementType; import java.util.ArrayList; import java.util.List; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/ModelValidatorTest.java b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/ModelValidatorTest.java index 9486665b..c8c63fe2 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/ModelValidatorTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/ModelValidatorTest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import io.quarkus.test.common.QuarkusTestResource; @@ -8,9 +8,9 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import dev.flexmodel.SQLiteTestResource; -import dev.flexmodel.domain.model.flow.exception.DefinitionException; -import dev.flexmodel.domain.model.flow.exception.ProcessException; -import dev.flexmodel.domain.model.flow.shared.EntityBuilder; +import dev.flexmodel.flow.exception.DefinitionException; +import dev.flexmodel.flow.exception.ProcessException; +import dev.flexmodel.domain.model.flow.EntityBuilder; @Slf4j diff --git a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/SequenceFlowValidatorTest.java b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/SequenceFlowValidatorTest.java index 5eb4d7f9..f2e8cbbb 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/SequenceFlowValidatorTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/SequenceFlowValidatorTest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; @@ -7,9 +7,9 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import dev.flexmodel.SQLiteTestResource; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.DefinitionException; -import dev.flexmodel.domain.model.flow.shared.EntityBuilder; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.DefinitionException; +import dev.flexmodel.domain.model.flow.EntityBuilder; import java.util.ArrayList; import java.util.HashMap; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/StartEventValidatorTest.java b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/StartEventValidatorTest.java index eb348503..7baade44 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/StartEventValidatorTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/StartEventValidatorTest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; @@ -7,9 +7,9 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import dev.flexmodel.SQLiteTestResource; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.DefinitionException; -import dev.flexmodel.domain.model.flow.shared.EntityBuilder; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.DefinitionException; +import dev.flexmodel.domain.model.flow.EntityBuilder; import java.util.ArrayList; import java.util.HashMap; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/UserTaskValidatorTest.java b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/UserTaskValidatorTest.java index 813e40bb..9ebd9311 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/UserTaskValidatorTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/domain/model/flow/validator/UserTaskValidatorTest.java @@ -1,4 +1,4 @@ -package dev.flexmodel.domain.model.flow.validator; +package dev.flexmodel.flow.validator; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; @@ -7,9 +7,9 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import dev.flexmodel.SQLiteTestResource; -import dev.flexmodel.domain.model.flow.dto.model.FlowElement; -import dev.flexmodel.domain.model.flow.exception.DefinitionException; -import dev.flexmodel.domain.model.flow.shared.EntityBuilder; +import dev.flexmodel.flow.dto.model.FlowElement; +import dev.flexmodel.flow.exception.DefinitionException; +import dev.flexmodel.domain.model.flow.EntityBuilder; import java.util.HashMap; import java.util.Map; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/rest/AuthResourceTest.java b/flexmodel-server/src/test/java/dev/flexmodel/rest/AuthResourceTest.java index 5794fb45..fa3bb31d 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/rest/AuthResourceTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/rest/AuthResourceTest.java @@ -5,7 +5,7 @@ import io.restassured.http.ContentType; import org.junit.jupiter.api.Test; import dev.flexmodel.SQLiteTestResource; -import dev.flexmodel.interfaces.rest.jwt.JwtUtil; +import dev.flexmodel.common.config.web.jwt.JwtUtil; import java.time.Duration; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/rest/FlexmodelRestAPIResourceTest.java b/flexmodel-server/src/test/java/dev/flexmodel/rest/FlexmodelRestAPIResourceTest.java deleted file mode 100644 index 02abccc7..00000000 --- a/flexmodel-server/src/test/java/dev/flexmodel/rest/FlexmodelRestAPIResourceTest.java +++ /dev/null @@ -1,257 +0,0 @@ -package dev.flexmodel.rest; - -import io.quarkus.test.common.QuarkusTestResource; -import io.quarkus.test.junit.QuarkusTest; -import io.restassured.RestAssured; -import io.restassured.http.ContentType; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import dev.flexmodel.SQLiteTestResource; - -import java.util.Map; - -import static io.restassured.RestAssured.given; -import static org.hamcrest.Matchers.*; - -/** - * @author cjbi - */ -@QuarkusTest -@QuarkusTestResource(SQLiteTestResource.class) -public class FlexmodelRestAPIResourceTest { - - @BeforeAll - public static void beforeAll() { - RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); - } - - @Test - void testGET() { - // list - given() - .header("Authorization", TestTokenHelper.getAuthorizationHeader()) - .when() - .get("/api/dev_test/Classes/list") - .then() - .statusCode(200) - .body("size()", greaterThanOrEqualTo(1)) - .body("data.dev_test_list_Classes[0].classCode", notNullValue()); - // view - given() - .header("Authorization", TestTokenHelper.getAuthorizationHeader()) - .when() - .get("/api/dev_test/Classes/1") - .then() - .statusCode(200) - .body("data.dev_test_find_one_Classes.classCode", notNullValue()); - } - - @Test - void testPOST() { - RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); - given() - .header("Authorization", TestTokenHelper.getAuthorizationHeader()) - .when() - .contentType(ContentType.JSON) - .body(""" - { - "id": 999, - "classCode": "C_004", - "className": "三年级2班" - } - """) - .post("/api/dev_test/Classes") - .then() - .statusCode(200) - .body("data", notNullValue()); - } - - @Test - void testPUT() { - given() - .header("Authorization", TestTokenHelper.getAuthorizationHeader()) - .when() - .contentType(ContentType.JSON) - .body(""" - { - "id": 1, - "classCode": "C_10", - "className": "五年级3班" - } - """) - .put("/api/dev_test/Classes/1") - .then() - .statusCode(200) - .body("data", notNullValue()); - } - - @Test - void testDELETE() { - RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); - given() - .header("Authorization", TestTokenHelper.getAuthorizationHeader()) - .when() - .delete("/api/dev_test/Classes/1") - .then() - .statusCode(200) - .body("data", notNullValue()); - } - - @Test - void testGraphQL() { - - RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); - given() - .header("Authorization", TestTokenHelper.getAuthorizationHeader()) - .when() - .contentType(ContentType.JSON) - .body(""" - { - "query": "query { dev_test_list_Classes { classCode className } }" - } - """) - .post("/api/dev_test/graphql") - .then() - .statusCode(200) - .body("data.dev_test_list_Classes", notNullValue()); - } - - @Test - @SuppressWarnings("all") - void testGenerate() throws InterruptedException { - - String script = """ - model testGenerateStudent { - id : Long @id @default(autoIncrement()), - student_name? : String @length("255"), - gender? : String, - interest? : String, - age? : Int, - class_id? : Long, - @index(name: "IDX_STUDENT_NAME",unique: "false", fields: [student_name]), - @index(name:"IDX_CLASS_ID", unique: "false", fields: [class_id]), - @comment("学生") - } - """; - Map body = Map.of("type", "IDL", "script", script); - - given() - .header("Authorization", TestTokenHelper.getAuthorizationHeader()) - .when() - .contentType(ContentType.JSON) - .body(body) - .post(Resources.ROOT_PATH + "/projects/dev_test/datasources/dev_test/import") - .then() - .statusCode(204); - - given() - .header("Authorization", TestTokenHelper.getAuthorizationHeader()) - .when() - .contentType(ContentType.JSON) - .body(""" - { - "datasourceName":"dev_test", - "modelName":"testGenerateStudent", - "apiFolder":"testGenerateStudent", - "idFieldOfPath":"id", - "generateAPIs":["list", "pagination", "view", "create", "update", "delete"] - } - """) - .post(Resources.ROOT_PATH + "/projects/dev_test/apis/generate") - .then() - .statusCode(204); - - Thread.sleep(1000); - - // create - Map createRes = given() - .header("Authorization", TestTokenHelper.getAuthorizationHeader()) - .when() - .contentType(ContentType.JSON) - .body(""" - { - "student_name": "张三", - "gender": "男", - "interest": "读书,游戏,逛街", - "age": 18 - } - """) - .post("/api/dev_test/testGenerateStudent") - .then() - .statusCode(200) - .body( - "data.dev_test_create_testGenerateStudent.student_name", equalTo("张三"), - "data.dev_test_create_testGenerateStudent.gender", equalTo("男"), - "data.dev_test_create_testGenerateStudent.age", equalTo(18) - ).extract().as(Map.class); - - Map data = (Map) createRes.get("data"); - Map studentMap = (Map) data.get("dev_test_create_testGenerateStudent"); - - // list - given() - .header("Authorization", TestTokenHelper.getAuthorizationHeader()) - .when() - .contentType(ContentType.JSON) - .get("/api/dev_test/testGenerateStudent/list") - .then() - .statusCode(200) - .body("data.list.size()", greaterThanOrEqualTo(1)); - - // page - given() - .header("Authorization", TestTokenHelper.getAuthorizationHeader()) - .param("page", 1) - .param("size", 1) - .when() - .contentType(ContentType.JSON) - .get("/api/dev_test/testGenerateStudent/page") - .then() - .statusCode(200) - .body( - "data.list.size()", equalTo(1), - "data.total", greaterThanOrEqualTo(1) - ); - - // view - given() - .header("Authorization", TestTokenHelper.getAuthorizationHeader()) - .when() - .contentType(ContentType.JSON) - .get("/api/dev_test/testGenerateStudent/{id}", studentMap.get("id")) - .then() - .statusCode(200) - .body("data.dev_test_find_one_testGenerateStudent.id", equalTo(studentMap.get("id"))); - - given() - .header("Authorization", TestTokenHelper.getAuthorizationHeader()) - .when() - .contentType(ContentType.JSON) - .body(""" - { - "student_name": "张三丰", - "gender": "男", - "interest": "读书,打太极", - "age": 300 - } - """) - .put("/api/dev_test/testGenerateStudent/{id}", studentMap.get("id")) - .then() - .statusCode(200) - .body( - "data.dev_test_update_testGenerateStudent.affected_rows", equalTo(1) - ); - - // delete - given() - .header("Authorization", TestTokenHelper.getAuthorizationHeader()) - .when() - .contentType(ContentType.JSON) - .delete("/api/dev_test/testGenerateStudent/{id}", studentMap.get("id")) - .then() - .statusCode(200) - .body("data.dev_test_delete_testGenerateStudent.affected_rows", equalTo(1)); - - } - -} diff --git a/flexmodel-server/src/test/java/dev/flexmodel/rest/ModelResourceTest.java b/flexmodel-server/src/test/java/dev/flexmodel/rest/ModelResourceTest.java index 7a40ae33..0b493698 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/rest/ModelResourceTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/rest/ModelResourceTest.java @@ -3,6 +3,7 @@ import io.quarkus.test.junit.QuarkusTest; import io.restassured.http.ContentType; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeEach; import static io.restassured.RestAssured.given; import static org.hamcrest.Matchers.greaterThanOrEqualTo; @@ -13,12 +14,35 @@ @QuarkusTest class ModelResourceTest { + // 测试表名列表,用于清理 + private static final String[] TEST_TABLE_NAMES = { + "testCreateModelStudent", + "testDropModelStudent", + "testCreateFieldStudent", + "testModifyFieldStudent", + "testDropFieldStudent", + "testCreateIndexStudent", + "testModifyIndexStudent", + "testDropIndexStudent" + }; + + @BeforeEach + void cleanupTestModels() { + // 清理测试创建的模型 + for (String tableName : TEST_TABLE_NAMES) { + given() + .header("Authorization", TestTokenHelper.getAuthorizationHeader()) + .when() + .delete(Resources.ROOT_PATH + "/projects/dev_test/models/{modelName}", tableName); + } + } + @Test void testFindModels() { given() .header("Authorization", TestTokenHelper.getAuthorizationHeader()) .when() - .get(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models", "system") + .get(Resources.ROOT_PATH + "/projects/dev_test/models") .then() .statusCode(200) .body("size()", greaterThanOrEqualTo(1)); @@ -71,7 +95,7 @@ void testCreateModel() { ] } """) - .post(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models", "sqlite_test") + .post(Resources.ROOT_PATH + "/projects/dev_test/models") .then() .statusCode(200); } @@ -133,14 +157,14 @@ void testDropModel() { ] } """) - .post(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models", "sqlite_test") + .post(Resources.ROOT_PATH + "/projects/dev_test/models") .then() .statusCode(200); given() .header("Authorization", TestTokenHelper.getAuthorizationHeader()) .when() .contentType(ContentType.JSON) - .delete(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models/{modelName}", "sqlite_test", "testDropModel") + .delete(Resources.ROOT_PATH + "/projects/dev_test/models/{modelName}", "testDropModel") .then() .statusCode(204); } @@ -202,7 +226,7 @@ void testCreateField() { ] } """) - .post(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models", "sqlite_test") + .post(Resources.ROOT_PATH + "/projects/dev_test/models") .then() .statusCode(200); given() @@ -219,7 +243,7 @@ void testCreateField() { "length": 255 } """) - .post(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models/{modelName}/fields", "sqlite_test", "testCreateFieldStudent") + .post(Resources.ROOT_PATH + "/projects/dev_test/models/{modelName}/fields", "testCreateFieldStudent") .then() .statusCode(200); } @@ -280,7 +304,7 @@ void testModifyField() { ] } """) - .post(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models", "sqlite_test") + .post(Resources.ROOT_PATH + "/projects/dev_test/models") .then() .statusCode(200); given() @@ -297,8 +321,7 @@ void testModifyField() { "length": 500 } """) - .put(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models/{modelName}/fields/{fieldName}", - "sqlite_test", + .put(Resources.ROOT_PATH + "/projects/dev_test/models/{modelName}/fields/{fieldName}", "testModifyFieldStudent", "studentName") .then() @@ -363,14 +386,13 @@ void testDropField() { "indexes": [] } """) - .post(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models", "sqlite_test") + .post(Resources.ROOT_PATH + "/projects/dev_test/models") .then() .statusCode(200); given() .header("Authorization", TestTokenHelper.getAuthorizationHeader()) .when() - .delete(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models/{modelName}/fields/{fieldName}", - "sqlite_test", + .delete(Resources.ROOT_PATH + "/projects/dev_test/models/{modelName}/fields/{fieldName}", "testDropFieldStudent", "studentName") .then() @@ -433,9 +455,7 @@ void testCreateIndex() { ] } """) - .post(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models", - "sqlite_test" - ) + .post(Resources.ROOT_PATH + "/projects/dev_test/models") .then() .statusCode(200); given() @@ -455,8 +475,7 @@ void testCreateIndex() { "unique": false } """) - .post(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models/{modelName}/indexes", - "sqlite_test", + .post(Resources.ROOT_PATH + "/projects/dev_test/models/{modelName}/indexes", "testCreateIndexStudent" ) .then() @@ -530,9 +549,7 @@ void testModifyIndex() { }] } """) - .post(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models", - "sqlite_test" - ) + .post(Resources.ROOT_PATH + "/projects/dev_test/models") .then() .statusCode(200); given() @@ -552,8 +569,7 @@ void testModifyIndex() { "unique": true } """) - .put(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models/{modelName}/indexes/{indexName}", - "sqlite_test", + .put(Resources.ROOT_PATH + "/projects/dev_test/models/{modelName}/indexes/{indexName}", "testModifyIndexStudent", "IDX_gender_wedsd" ) @@ -628,17 +644,14 @@ void testDropIndex() { }] } """) - .post(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models", - "sqlite_test" - ) + .post(Resources.ROOT_PATH + "/projects/dev_test/models") .then() .statusCode(200); given() .header("Authorization", TestTokenHelper.getAuthorizationHeader()) .when() .contentType(ContentType.JSON) - .delete(Resources.ROOT_PATH + "/projects/dev_test/datasources/{datasourceName}/models/{modelName}/indexes/{indexName}", - "sqlite_test", + .delete(Resources.ROOT_PATH + "/projects/dev_test/models/{modelName}/indexes/{indexName}", "testModifyIndexStudent", "IDX_gender" ) diff --git a/flexmodel-server/src/test/java/dev/flexmodel/rest/RecordResourceTest.java b/flexmodel-server/src/test/java/dev/flexmodel/rest/RecordResourceTest.java index 1d51adf1..1be761a1 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/rest/RecordResourceTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/rest/RecordResourceTest.java @@ -4,16 +4,16 @@ import io.quarkus.test.junit.QuarkusTest; import io.restassured.RestAssured; import io.restassured.http.ContentType; -import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; import dev.flexmodel.SQLiteTestResource; -import dev.flexmodel.interfaces.rest.jwt.JwtUtil; +import dev.flexmodel.common.config.web.jwt.JwtUtil; import java.time.Duration; import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThanOrEqualTo; @@ -22,7 +22,6 @@ */ @QuarkusTest @QuarkusTestResource(SQLiteTestResource.class) -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) class RecordResourceTest { /** @@ -32,6 +31,18 @@ private String getTestToken() { return JwtUtil.sign("admin", Duration.ofMinutes(5)); } + @BeforeEach + void cleanupTestData() { + // 清理测试创建的记录(id = 100000) + given() + .header("Authorization", TestTokenHelper.getAuthorizationHeader()) + .when() + .delete(Resources.ROOT_PATH + "/projects/{projectId}/models/{modelName}/records/{recordId}", + "dev_test", "Student", 100000) + .then() + .statusCode(anyOf(equalTo(204), equalTo(404))); // 204成功删除,404记录不存在 + } + @Test void testFindPagingRecords() { given() @@ -40,7 +51,7 @@ void testFindPagingRecords() { .param("current", "1") .param("pageSize", "20") .param("nestedQuery", "true") - .get(Resources.ROOT_PATH + "/projects/{projectId}/datasources/{datasourceName}/models/{modelName}/records", "dev_test", "dev_test", "Classes") + .get(Resources.ROOT_PATH + "/projects/{projectId}/models/{modelName}/records", "dev_test", "Classes") .then() .statusCode(200) .body( @@ -68,7 +79,7 @@ void testCreateRecord() { } } """) - .post(Resources.ROOT_PATH + "/projects/{projectId}/datasources/{datasourceName}/models/{modelName}/records", "dev_test", "dev_test", "Student") + .post(Resources.ROOT_PATH + "/projects/{projectId}/models/{modelName}/records", "dev_test", "Student") .then() .statusCode(200); } @@ -92,10 +103,9 @@ void testUpdateRecord() { } } """) - .put(Resources.ROOT_PATH + "/projects/{projectId}/datasources/{datasourceName}/models/{modelName}/records/{recordId}", "dev_test", "dev_test", "Student", 100000) + .put(Resources.ROOT_PATH + "/projects/{projectId}/models/{modelName}/records/{recordId}", "dev_test", "Student", 100000) .then() .statusCode(200); - // todo 级联更新 } @Test @@ -108,7 +118,7 @@ void testFindOneRecord() { .param("current", "1") .param("pageSize", "20") .param("nestedQuery", "true") - .get(Resources.ROOT_PATH + "/projects/{projectId}/datasources/{datasourceName}/models/{modelName}/records/{recordId}", "dev_test", "dev_test", "Student", 100000) + .get(Resources.ROOT_PATH + "/projects/{projectId}/models/{modelName}/records/{recordId}", "dev_test", "Student", 100000) .then() .statusCode(200) .body( @@ -123,7 +133,7 @@ void testDeleteRecord() { given() .header("Authorization", TestTokenHelper.getAuthorizationHeader()) .when() - .delete(Resources.ROOT_PATH + "/projects/{projectId}/datasources/{datasourceName}/models/{modelName}/records/{recordId}", "dev_test", "dev_test", "Student", 100000) + .delete(Resources.ROOT_PATH + "/projects/{projectId}/models/{modelName}/records/{recordId}", "dev_test", "Student", 100000) .then() .statusCode(204); } diff --git a/flexmodel-server/src/test/java/dev/flexmodel/rest/SettingsResourceTest.java b/flexmodel-server/src/test/java/dev/flexmodel/rest/SettingsResourceTest.java index 4bebe43a..d6d37b0f 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/rest/SettingsResourceTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/rest/SettingsResourceTest.java @@ -4,8 +4,8 @@ import io.quarkus.test.junit.QuarkusTest; import org.junit.jupiter.api.Test; import dev.flexmodel.SQLiteTestResource; -import dev.flexmodel.domain.model.settings.Settings; -import dev.flexmodel.interfaces.rest.jwt.JwtUtil; +import dev.flexmodel.settings.Settings; +import dev.flexmodel.common.config.web.jwt.JwtUtil; import java.time.Duration; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/rest/TestTokenHelper.java b/flexmodel-server/src/test/java/dev/flexmodel/rest/TestTokenHelper.java index 2697ea4b..b0df1203 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/rest/TestTokenHelper.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/rest/TestTokenHelper.java @@ -1,6 +1,6 @@ package dev.flexmodel.rest; -import dev.flexmodel.interfaces.rest.jwt.JwtUtil; +import dev.flexmodel.common.config.web.jwt.JwtUtil; import java.time.Duration; diff --git a/flexmodel-server/src/test/java/dev/flexmodel/rest/TriggerResourceTest.java b/flexmodel-server/src/test/java/dev/flexmodel/rest/TriggerResourceTest.java index c76e0220..a95813ea 100644 --- a/flexmodel-server/src/test/java/dev/flexmodel/rest/TriggerResourceTest.java +++ b/flexmodel-server/src/test/java/dev/flexmodel/rest/TriggerResourceTest.java @@ -199,7 +199,6 @@ void testCreateEventTrigger() { "type": "EVENT", "config": { "type": "event", - "datasourceName": "dev_test", "modelName": "Student", "mutationTypes": ["create", "update"], "triggerTiming": "after" @@ -221,7 +220,6 @@ void testCreateEventTrigger() { .body("id", notNullValue()) .body("name", equalTo("测试事件触发")) .body("type", equalTo("EVENT")) - .body("config.datasourceName", equalTo("dev_test")) .body("config.modelName", equalTo("Student")) .body("config.triggerTiming", equalTo("after")); } @@ -388,7 +386,6 @@ void testValidateDifferentTriggerTypes() { .then() .statusCode(200) .body("type", equalTo("EVENT")) - .body("config.datasourceName", equalTo("dev_test")) .body("config.modelName", equalTo("Classes")) .body("config.mutationTypes", notNullValue()) .body("config.triggerTiming", equalTo("after")); diff --git a/flexmodel-server/src/main/resources/dev_test_schema.idl b/flexmodel-server/src/test/resources/dev_test.fml similarity index 100% rename from flexmodel-server/src/main/resources/dev_test_schema.idl rename to flexmodel-server/src/test/resources/dev_test.fml diff --git a/flexmodel-server/src/main/resources/dev_test_data.json b/flexmodel-server/src/test/resources/dev_test_data.json similarity index 100% rename from flexmodel-server/src/main/resources/dev_test_data.json rename to flexmodel-server/src/test/resources/dev_test_data.json diff --git a/flexmodel-ui b/flexmodel-ui index 82711afc..63ebd13d 160000 --- a/flexmodel-ui +++ b/flexmodel-ui @@ -1 +1 @@ -Subproject commit 82711afc5cde4ea41cd0a132601478391c34e376 +Subproject commit 63ebd13ddbfe8c788eafccdf3c7aaa072a7f6864 diff --git a/flexmodel-website b/flexmodel-website index 672d7362..9fb1f59d 160000 --- a/flexmodel-website +++ b/flexmodel-website @@ -1 +1 @@ -Subproject commit 672d7362ab1f18ed0ee30d146e8d2288bb6f36fa +Subproject commit 9fb1f59d385593d21c763fb596e4196bb7fa45fd diff --git a/init.sh b/init.sh new file mode 100755 index 00000000..3f59703d --- /dev/null +++ b/init.sh @@ -0,0 +1,31 @@ +#!/bin/bash +set -e + +echo "=== Flexmodel Harness Initialization ===" + +echo "--- Java version check ---" +java -version + +echo "" +echo "--- Clean and compile (all modules) ---" +mvn clean compile -q -pl '!flexmodel-engine/flexmodel-maven-plugin' +echo "OK: All modules compiled successfully" + +echo "" +echo "--- Engine module tests ---" +mvn test -pl flexmodel-engine -q +echo "OK: flexmodel-engine tests passed" + +echo "" +echo "=== Build Verification Complete ===" +echo "" +echo "Optional: Run full server tests (some tests may have known failures):" +echo " mvn clean test -pl flexmodel-server -am" +echo "" +echo "Next steps:" +echo "1. Read feature_list.json to see current feature state" +echo "2. Pick ONE unfinished feature to work on" +echo "3. Implement only that feature" +echo "4. Re-run verification before claiming done" +echo "" +echo "Dev mode: cd flexmodel-server && ./mvnw quarkus:dev" diff --git a/pom.xml b/pom.xml index b350b20c..85bef487 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ pom - 21 + 25 UTF-8 UTF-8 true diff --git a/progress.md b/progress.md new file mode 100644 index 00000000..3710d5c3 --- /dev/null +++ b/progress.md @@ -0,0 +1,51 @@ +# Session Progress Log + +## Current State + +**Last Updated:** YYYY-MM-DD HH:MM +**Session ID:** [optional] +**Active Feature:** [feat-XXX - Feature Name] + +## Status + +### What's Done + +- [x] [Completed item 1] +- [x] [Completed item 2] + +### What's In Progress + +- [ ] [Current work item] + - Details: [specific task] + - Blockers: [if any] + +### What's Next + +1. [Next action item] +2. [Following action item] + +## Blockers / Risks + +- [ ] [Blocker 1]: [description, impact] +- [ ] [Risk 1]: [description, mitigation] + +## Decisions Made + +- **[Decision 1]**: [description] + - Context: [why this decision was made] + - Alternatives considered: [what else was discussed] + +## Files Modified This Session + +- `path/to/file1.ts` - [brief description of change] +- `path/to/file2.ts` - [brief description of change] + +## Evidence of Completion + +- [ ] Tests pass: `[command and output]` +- [ ] Type check clean: `[command and output]` +- [ ] Manual verification: `[what was tested]` + +## Notes for Next Session + +[Free-form notes that will help the next session pick up context] diff --git a/session-handoff.md b/session-handoff.md new file mode 100644 index 00000000..d9168cb7 --- /dev/null +++ b/session-handoff.md @@ -0,0 +1,40 @@ +# Session Handoff + +## Current Objective + +- Goal: +- Current status: +- Branch / commit: + +## Completed This Session + +- [ ] + +## Verification Evidence + +| Check | Command | Result | Notes | +|---|---|---|---| +| | | | | + +## Files Changed + +- + +## Decisions Made + +- + +## Blockers / Risks + +- + +## Next Session Startup + +1. Read `AGENTS.md`. +2. Read `feature_list.json` and `progress.md`. +3. Review this handoff. +4. Run `./init.sh` or the documented verification command before editing. + +## Recommended Next Step + +- diff --git a/skills-lock.json b/skills-lock.json new file mode 100644 index 00000000..8a58b4ea --- /dev/null +++ b/skills-lock.json @@ -0,0 +1,11 @@ +{ + "version": 1, + "skills": { + "harness-creator": { + "source": "walkinglabs/learn-harness-engineering", + "sourceType": "github", + "skillPath": "skills/harness-creator/SKILL.md", + "computedHash": "a87a708b46d85f81eccfc1ea2b1d472328bb08e1a27f14c633de29bc0388fbe3" + } + } +}