@jahia/agentic 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/claude/.claude/rules/jahia.md +1 -37
- package/dist/claude/.claude/skills/jahia-cnd-author/SKILL.md +94 -0
- package/dist/claude/.claude/skills/jahia-cnd-author/references/cnd-area-types.md +55 -0
- package/dist/claude/.claude/skills/jahia-cnd-author/references/cnd-authoring-experience.md +92 -0
- package/dist/claude/.claude/skills/jahia-cnd-author/references/cnd-jahia-mixins.md +510 -0
- package/dist/claude/.claude/skills/jahia-cnd-author/references/cnd-modeling-decisions.md +87 -0
- package/dist/{opencode/.opencode/agents → claude/.claude/skills/jahia-cnd-author/references}/cnd-numbers-dates.md +32 -1
- package/dist/{opencode/.opencode/agents → claude/.claude/skills/jahia-cnd-author/references}/cnd-string-selectors.md +49 -10
- package/dist/claude/.claude/skills/jahia-cnd-author/references/cnd-syntax.md +119 -0
- package/dist/claude/.claude/skills/jahia-cnd-author/references/types-ts-mapping.md +73 -0
- package/dist/claude/.claude/skills/jahia-dev-accessibility/SKILL.md +5 -265
- package/dist/claude/.claude/skills/jahia-dev-build-component/SKILL.md +13 -8
- package/dist/claude/CLAUDE.md +2 -38
- package/dist/codex/.agents/skills/jahia-cnd-author/SKILL.md +94 -0
- package/dist/codex/.agents/skills/jahia-cnd-author/references/cnd-area-types.md +55 -0
- package/dist/codex/.agents/skills/jahia-cnd-author/references/cnd-authoring-experience.md +92 -0
- package/dist/codex/.agents/skills/jahia-cnd-author/references/cnd-jahia-mixins.md +510 -0
- package/dist/codex/.agents/skills/jahia-cnd-author/references/cnd-modeling-decisions.md +87 -0
- package/dist/{claude/.claude/agents → codex/.agents/skills/jahia-cnd-author/references}/cnd-numbers-dates.md +32 -1
- package/dist/{cursor/.cursor/agents → codex/.agents/skills/jahia-cnd-author/references}/cnd-string-selectors.md +49 -10
- package/dist/codex/.agents/skills/jahia-cnd-author/references/cnd-syntax.md +119 -0
- package/dist/codex/.agents/skills/jahia-cnd-author/references/types-ts-mapping.md +73 -0
- package/dist/codex/.agents/skills/jahia-dev-accessibility/SKILL.md +5 -265
- package/dist/codex/.agents/skills/jahia-dev-build-component/SKILL.md +13 -8
- package/dist/codex/AGENTS.md +2 -38
- package/dist/copilot/.agents/skills/jahia-cnd-author/SKILL.md +94 -0
- package/dist/copilot/.agents/skills/jahia-cnd-author/references/cnd-area-types.md +55 -0
- package/dist/copilot/.agents/skills/jahia-cnd-author/references/cnd-authoring-experience.md +92 -0
- package/dist/copilot/.agents/skills/jahia-cnd-author/references/cnd-jahia-mixins.md +510 -0
- package/dist/copilot/.agents/skills/jahia-cnd-author/references/cnd-modeling-decisions.md +87 -0
- package/dist/{cursor/.cursor/agents → copilot/.agents/skills/jahia-cnd-author/references}/cnd-numbers-dates.md +32 -1
- package/dist/{claude/.claude/agents → copilot/.agents/skills/jahia-cnd-author/references}/cnd-string-selectors.md +49 -10
- package/dist/copilot/.agents/skills/jahia-cnd-author/references/cnd-syntax.md +119 -0
- package/dist/copilot/.agents/skills/jahia-cnd-author/references/types-ts-mapping.md +73 -0
- package/dist/copilot/.agents/skills/jahia-dev-accessibility/SKILL.md +5 -265
- package/dist/copilot/.agents/skills/jahia-dev-build-component/SKILL.md +13 -8
- package/dist/copilot/AGENTS.md +2 -38
- package/dist/cursor/.agents/skills/jahia-cnd-author/SKILL.md +94 -0
- package/dist/cursor/.agents/skills/jahia-cnd-author/references/cnd-area-types.md +55 -0
- package/dist/cursor/.agents/skills/jahia-cnd-author/references/cnd-authoring-experience.md +92 -0
- package/dist/cursor/.agents/skills/jahia-cnd-author/references/cnd-child-nodes.md +74 -0
- package/dist/cursor/.agents/skills/jahia-cnd-author/references/cnd-jahia-mixins.md +510 -0
- package/dist/cursor/.agents/skills/jahia-cnd-author/references/cnd-modeling-decisions.md +87 -0
- package/dist/cursor/.agents/skills/jahia-cnd-author/references/cnd-numbers-dates.md +92 -0
- package/dist/cursor/.agents/skills/jahia-cnd-author/references/cnd-string-selectors.md +133 -0
- package/dist/cursor/.agents/skills/jahia-cnd-author/references/cnd-syntax.md +119 -0
- package/dist/cursor/.agents/skills/jahia-cnd-author/references/types-ts-mapping.md +73 -0
- package/dist/cursor/.agents/skills/jahia-dev-accessibility/SKILL.md +5 -265
- package/dist/cursor/.agents/skills/jahia-dev-build-component/SKILL.md +13 -8
- package/dist/cursor/.cursor/rules/jahia.mdc +1 -37
- package/dist/gemini/.agents/skills/jahia-cnd-author/SKILL.md +94 -0
- package/dist/gemini/.agents/skills/jahia-cnd-author/references/cnd-area-types.md +55 -0
- package/dist/gemini/.agents/skills/jahia-cnd-author/references/cnd-authoring-experience.md +92 -0
- package/dist/gemini/.agents/skills/jahia-cnd-author/references/cnd-child-nodes.md +74 -0
- package/dist/gemini/.agents/skills/jahia-cnd-author/references/cnd-jahia-mixins.md +510 -0
- package/dist/gemini/.agents/skills/jahia-cnd-author/references/cnd-modeling-decisions.md +87 -0
- package/dist/gemini/.agents/skills/jahia-cnd-author/references/cnd-numbers-dates.md +92 -0
- package/dist/gemini/.agents/skills/jahia-cnd-author/references/cnd-string-selectors.md +133 -0
- package/dist/gemini/.agents/skills/jahia-cnd-author/references/cnd-syntax.md +119 -0
- package/dist/gemini/.agents/skills/jahia-cnd-author/references/types-ts-mapping.md +73 -0
- package/dist/gemini/.agents/skills/jahia-dev-accessibility/SKILL.md +5 -265
- package/dist/gemini/.agents/skills/jahia-dev-build-component/SKILL.md +13 -8
- package/dist/gemini/AGENTS.md +2 -38
- package/dist/opencode/.agents/skills/jahia-cnd-author/SKILL.md +94 -0
- package/dist/opencode/.agents/skills/jahia-cnd-author/references/cnd-area-types.md +55 -0
- package/dist/opencode/.agents/skills/jahia-cnd-author/references/cnd-authoring-experience.md +92 -0
- package/dist/opencode/.agents/skills/jahia-cnd-author/references/cnd-child-nodes.md +74 -0
- package/dist/opencode/.agents/skills/jahia-cnd-author/references/cnd-jahia-mixins.md +510 -0
- package/dist/opencode/.agents/skills/jahia-cnd-author/references/cnd-modeling-decisions.md +87 -0
- package/dist/opencode/.agents/skills/jahia-cnd-author/references/cnd-numbers-dates.md +92 -0
- package/dist/opencode/.agents/skills/jahia-cnd-author/references/cnd-string-selectors.md +133 -0
- package/dist/opencode/.agents/skills/jahia-cnd-author/references/cnd-syntax.md +119 -0
- package/dist/opencode/.agents/skills/jahia-cnd-author/references/types-ts-mapping.md +73 -0
- package/dist/opencode/.agents/skills/jahia-dev-accessibility/SKILL.md +5 -265
- package/dist/opencode/.agents/skills/jahia-dev-build-component/SKILL.md +13 -8
- package/dist/opencode/AGENTS.md +2 -38
- package/dist/windsurf/.windsurf/rules/jahia.md +1 -37
- package/dist/windsurf/.windsurf/skills/jahia-cnd-author/SKILL.md +94 -0
- package/dist/windsurf/.windsurf/skills/jahia-cnd-author/references/cnd-area-types.md +55 -0
- package/dist/windsurf/.windsurf/skills/jahia-cnd-author/references/cnd-authoring-experience.md +92 -0
- package/dist/windsurf/.windsurf/skills/jahia-cnd-author/references/cnd-child-nodes.md +74 -0
- package/dist/windsurf/.windsurf/skills/jahia-cnd-author/references/cnd-jahia-mixins.md +510 -0
- package/dist/windsurf/.windsurf/skills/jahia-cnd-author/references/cnd-modeling-decisions.md +87 -0
- package/dist/windsurf/.windsurf/skills/jahia-cnd-author/references/cnd-numbers-dates.md +92 -0
- package/dist/windsurf/.windsurf/skills/jahia-cnd-author/references/cnd-string-selectors.md +133 -0
- package/dist/windsurf/.windsurf/skills/jahia-cnd-author/references/cnd-syntax.md +119 -0
- package/dist/windsurf/.windsurf/skills/jahia-cnd-author/references/types-ts-mapping.md +73 -0
- package/dist/windsurf/.windsurf/skills/jahia-dev-accessibility/SKILL.md +5 -265
- package/dist/windsurf/.windsurf/skills/jahia-dev-build-component/SKILL.md +13 -8
- package/dist/windsurf/AGENTS.md +2 -38
- package/package.json +1 -1
- package/dist/claude/.claude/agents/cnd-jahia-mixins.md +0 -113
- package/dist/claude/.claude/agents/jahia-cnd-author.md +0 -130
- package/dist/claude/.claude/agents/jahia-dev-worker.md +0 -264
- package/dist/claude/.claude/agents/jahia-reviewer.md +0 -105
- package/dist/claude/.claude/skills/jahia/SKILL.md +0 -148
- package/dist/claude/.claude/skills/jahia-content/SKILL.md +0 -157
- package/dist/claude/.claude/skills/jahia-content-create-content/SKILL.md +0 -359
- package/dist/claude/.claude/skills/jahia-content-explore-structure/SKILL.md +0 -255
- package/dist/claude/.claude/skills/jahia-content-media-upload/SKILL.md +0 -197
- package/dist/claude/.claude/skills/jahia-content-move-content/SKILL.md +0 -231
- package/dist/claude/.claude/skills/jahia-content-organize/SKILL.md +0 -209
- package/dist/claude/.claude/skills/jahia-content-publish/SKILL.md +0 -181
- package/dist/claude/.claude/skills/jahia-content-query-content/SKILL.md +0 -174
- package/dist/claude/.claude/skills/jahia-content-translate-content/SKILL.md +0 -226
- package/dist/claude/.claude/skills/jahia-dev/SKILL.md +0 -124
- package/dist/claude/.claude/skills/jahia-dev-apis/SKILL.md +0 -52
- package/dist/claude/.claude/skills/jahia-dev-apis/references/authentication.md +0 -484
- package/dist/claude/.claude/skills/jahia-dev-apis/references/graphql.md +0 -657
- package/dist/claude/.claude/skills/jahia-dev-apis/references/jcr-api.md +0 -465
- package/dist/claude/.claude/skills/jahia-dev-apis/references/security.md +0 -541
- package/dist/claude/.claude/skills/jahia-dev-cypress/SKILL.md +0 -265
- package/dist/claude/.claude/skills/jahia-dev-define-content-type/SKILL.md +0 -93
- package/dist/claude/.claude/skills/jahia-dev-define-content-type/references/modeling-decisions.md +0 -52
- package/dist/claude/.claude/skills/jahia-dev-java/SKILL.md +0 -110
- package/dist/claude/.claude/skills/jahia-dev-java/references/backend.md +0 -331
- package/dist/claude/.claude/skills/jahia-dev-java/references/content-types.md +0 -273
- package/dist/claude/.claude/skills/jahia-dev-java/references/modules.md +0 -218
- package/dist/claude/.claude/skills/jahia-dev-java/references/osgi.md +0 -208
- package/dist/claude/.claude/skills/jahia-dev-java/references/rendering.md +0 -191
- package/dist/claude/.claude/skills/jahia-dev-java/references/ui-extensions.md +0 -344
- package/dist/claude/.claude/skills/jahia-dev-osgi-module/SKILL.md +0 -297
- package/dist/claude/.claude/skills/jahia-dev-ui-extension/SKILL.md +0 -559
- package/dist/claude/.claude/skills/jahia-java-concurrency/SKILL.md +0 -308
- package/dist/claude/.claude/skills/jahia-java-jcr/SKILL.md +0 -153
- package/dist/claude/.claude/skills/jahia-java-osgi/SKILL.md +0 -134
- package/dist/claude/.claude/skills/jahia-java-persistence/SKILL.md +0 -177
- package/dist/claude/.claude/skills/jahia-java-security/SKILL.md +0 -84
- package/dist/claude/.claude/skills/jahia-orchestrate/SKILL.md +0 -148
- package/dist/claude/.claude/skills/jahia-orchestrate/scripts/verify-pages.mjs +0 -59
- package/dist/claude/.claude/skills/jahia-review-java/SKILL.md +0 -131
- package/dist/claude/.claude/skills/jahia-review-java/references/code-review-output.md +0 -121
- package/dist/codex/.agents/skills/jahia/SKILL.md +0 -148
- package/dist/codex/.agents/skills/jahia-content/SKILL.md +0 -157
- package/dist/codex/.agents/skills/jahia-content-create-content/SKILL.md +0 -359
- package/dist/codex/.agents/skills/jahia-content-explore-structure/SKILL.md +0 -255
- package/dist/codex/.agents/skills/jahia-content-media-upload/SKILL.md +0 -197
- package/dist/codex/.agents/skills/jahia-content-move-content/SKILL.md +0 -231
- package/dist/codex/.agents/skills/jahia-content-organize/SKILL.md +0 -209
- package/dist/codex/.agents/skills/jahia-content-publish/SKILL.md +0 -181
- package/dist/codex/.agents/skills/jahia-content-query-content/SKILL.md +0 -174
- package/dist/codex/.agents/skills/jahia-content-translate-content/SKILL.md +0 -226
- package/dist/codex/.agents/skills/jahia-dev/SKILL.md +0 -124
- package/dist/codex/.agents/skills/jahia-dev-apis/SKILL.md +0 -52
- package/dist/codex/.agents/skills/jahia-dev-apis/references/authentication.md +0 -484
- package/dist/codex/.agents/skills/jahia-dev-apis/references/graphql.md +0 -657
- package/dist/codex/.agents/skills/jahia-dev-apis/references/jcr-api.md +0 -465
- package/dist/codex/.agents/skills/jahia-dev-apis/references/security.md +0 -541
- package/dist/codex/.agents/skills/jahia-dev-cypress/SKILL.md +0 -265
- package/dist/codex/.agents/skills/jahia-dev-define-content-type/SKILL.md +0 -93
- package/dist/codex/.agents/skills/jahia-dev-define-content-type/references/modeling-decisions.md +0 -52
- package/dist/codex/.agents/skills/jahia-dev-java/SKILL.md +0 -110
- package/dist/codex/.agents/skills/jahia-dev-java/references/backend.md +0 -331
- package/dist/codex/.agents/skills/jahia-dev-java/references/content-types.md +0 -273
- package/dist/codex/.agents/skills/jahia-dev-java/references/modules.md +0 -218
- package/dist/codex/.agents/skills/jahia-dev-java/references/osgi.md +0 -208
- package/dist/codex/.agents/skills/jahia-dev-java/references/rendering.md +0 -191
- package/dist/codex/.agents/skills/jahia-dev-java/references/ui-extensions.md +0 -344
- package/dist/codex/.agents/skills/jahia-dev-osgi-module/SKILL.md +0 -297
- package/dist/codex/.agents/skills/jahia-dev-ui-extension/SKILL.md +0 -559
- package/dist/codex/.agents/skills/jahia-java-concurrency/SKILL.md +0 -308
- package/dist/codex/.agents/skills/jahia-java-jcr/SKILL.md +0 -153
- package/dist/codex/.agents/skills/jahia-java-osgi/SKILL.md +0 -134
- package/dist/codex/.agents/skills/jahia-java-persistence/SKILL.md +0 -177
- package/dist/codex/.agents/skills/jahia-java-security/SKILL.md +0 -84
- package/dist/codex/.agents/skills/jahia-orchestrate/SKILL.md +0 -148
- package/dist/codex/.agents/skills/jahia-orchestrate/scripts/verify-pages.mjs +0 -59
- package/dist/codex/.agents/skills/jahia-review-java/SKILL.md +0 -131
- package/dist/codex/.agents/skills/jahia-review-java/references/code-review-output.md +0 -121
- package/dist/codex/.codex/agents/cnd-child-nodes.toml +0 -3
- package/dist/codex/.codex/agents/cnd-jahia-mixins.toml +0 -3
- package/dist/codex/.codex/agents/cnd-numbers-dates.toml +0 -3
- package/dist/codex/.codex/agents/cnd-string-selectors.toml +0 -3
- package/dist/codex/.codex/agents/jahia-cnd-author.toml +0 -3
- package/dist/codex/.codex/agents/jahia-dev-worker.toml +0 -3
- package/dist/codex/.codex/agents/jahia-reviewer.toml +0 -3
- package/dist/copilot/.agents/skills/jahia/SKILL.md +0 -148
- package/dist/copilot/.agents/skills/jahia-content/SKILL.md +0 -157
- package/dist/copilot/.agents/skills/jahia-content-create-content/SKILL.md +0 -359
- package/dist/copilot/.agents/skills/jahia-content-explore-structure/SKILL.md +0 -255
- package/dist/copilot/.agents/skills/jahia-content-media-upload/SKILL.md +0 -197
- package/dist/copilot/.agents/skills/jahia-content-move-content/SKILL.md +0 -231
- package/dist/copilot/.agents/skills/jahia-content-organize/SKILL.md +0 -209
- package/dist/copilot/.agents/skills/jahia-content-publish/SKILL.md +0 -181
- package/dist/copilot/.agents/skills/jahia-content-query-content/SKILL.md +0 -174
- package/dist/copilot/.agents/skills/jahia-content-translate-content/SKILL.md +0 -226
- package/dist/copilot/.agents/skills/jahia-dev/SKILL.md +0 -124
- package/dist/copilot/.agents/skills/jahia-dev-apis/SKILL.md +0 -52
- package/dist/copilot/.agents/skills/jahia-dev-apis/references/authentication.md +0 -484
- package/dist/copilot/.agents/skills/jahia-dev-apis/references/graphql.md +0 -657
- package/dist/copilot/.agents/skills/jahia-dev-apis/references/jcr-api.md +0 -465
- package/dist/copilot/.agents/skills/jahia-dev-apis/references/security.md +0 -541
- package/dist/copilot/.agents/skills/jahia-dev-cypress/SKILL.md +0 -265
- package/dist/copilot/.agents/skills/jahia-dev-define-content-type/SKILL.md +0 -93
- package/dist/copilot/.agents/skills/jahia-dev-define-content-type/references/modeling-decisions.md +0 -52
- package/dist/copilot/.agents/skills/jahia-dev-java/SKILL.md +0 -110
- package/dist/copilot/.agents/skills/jahia-dev-java/references/backend.md +0 -331
- package/dist/copilot/.agents/skills/jahia-dev-java/references/content-types.md +0 -273
- package/dist/copilot/.agents/skills/jahia-dev-java/references/modules.md +0 -218
- package/dist/copilot/.agents/skills/jahia-dev-java/references/osgi.md +0 -208
- package/dist/copilot/.agents/skills/jahia-dev-java/references/rendering.md +0 -191
- package/dist/copilot/.agents/skills/jahia-dev-java/references/ui-extensions.md +0 -344
- package/dist/copilot/.agents/skills/jahia-dev-osgi-module/SKILL.md +0 -297
- package/dist/copilot/.agents/skills/jahia-dev-ui-extension/SKILL.md +0 -559
- package/dist/copilot/.agents/skills/jahia-java-concurrency/SKILL.md +0 -308
- package/dist/copilot/.agents/skills/jahia-java-jcr/SKILL.md +0 -153
- package/dist/copilot/.agents/skills/jahia-java-osgi/SKILL.md +0 -134
- package/dist/copilot/.agents/skills/jahia-java-persistence/SKILL.md +0 -177
- package/dist/copilot/.agents/skills/jahia-java-security/SKILL.md +0 -84
- package/dist/copilot/.agents/skills/jahia-orchestrate/SKILL.md +0 -148
- package/dist/copilot/.agents/skills/jahia-orchestrate/scripts/verify-pages.mjs +0 -59
- package/dist/copilot/.agents/skills/jahia-review-java/SKILL.md +0 -131
- package/dist/copilot/.agents/skills/jahia-review-java/references/code-review-output.md +0 -121
- package/dist/cursor/.agents/skills/jahia/SKILL.md +0 -148
- package/dist/cursor/.agents/skills/jahia-content/SKILL.md +0 -157
- package/dist/cursor/.agents/skills/jahia-content-create-content/SKILL.md +0 -359
- package/dist/cursor/.agents/skills/jahia-content-explore-structure/SKILL.md +0 -255
- package/dist/cursor/.agents/skills/jahia-content-media-upload/SKILL.md +0 -197
- package/dist/cursor/.agents/skills/jahia-content-move-content/SKILL.md +0 -231
- package/dist/cursor/.agents/skills/jahia-content-organize/SKILL.md +0 -209
- package/dist/cursor/.agents/skills/jahia-content-publish/SKILL.md +0 -181
- package/dist/cursor/.agents/skills/jahia-content-query-content/SKILL.md +0 -174
- package/dist/cursor/.agents/skills/jahia-content-translate-content/SKILL.md +0 -226
- package/dist/cursor/.agents/skills/jahia-dev/SKILL.md +0 -124
- package/dist/cursor/.agents/skills/jahia-dev-apis/SKILL.md +0 -52
- package/dist/cursor/.agents/skills/jahia-dev-apis/references/authentication.md +0 -484
- package/dist/cursor/.agents/skills/jahia-dev-apis/references/graphql.md +0 -657
- package/dist/cursor/.agents/skills/jahia-dev-apis/references/jcr-api.md +0 -465
- package/dist/cursor/.agents/skills/jahia-dev-apis/references/security.md +0 -541
- package/dist/cursor/.agents/skills/jahia-dev-cypress/SKILL.md +0 -265
- package/dist/cursor/.agents/skills/jahia-dev-define-content-type/SKILL.md +0 -93
- package/dist/cursor/.agents/skills/jahia-dev-define-content-type/references/modeling-decisions.md +0 -52
- package/dist/cursor/.agents/skills/jahia-dev-java/SKILL.md +0 -110
- package/dist/cursor/.agents/skills/jahia-dev-java/references/backend.md +0 -331
- package/dist/cursor/.agents/skills/jahia-dev-java/references/content-types.md +0 -273
- package/dist/cursor/.agents/skills/jahia-dev-java/references/modules.md +0 -218
- package/dist/cursor/.agents/skills/jahia-dev-java/references/osgi.md +0 -208
- package/dist/cursor/.agents/skills/jahia-dev-java/references/rendering.md +0 -191
- package/dist/cursor/.agents/skills/jahia-dev-java/references/ui-extensions.md +0 -344
- package/dist/cursor/.agents/skills/jahia-dev-osgi-module/SKILL.md +0 -297
- package/dist/cursor/.agents/skills/jahia-dev-ui-extension/SKILL.md +0 -559
- package/dist/cursor/.agents/skills/jahia-java-concurrency/SKILL.md +0 -308
- package/dist/cursor/.agents/skills/jahia-java-jcr/SKILL.md +0 -153
- package/dist/cursor/.agents/skills/jahia-java-osgi/SKILL.md +0 -134
- package/dist/cursor/.agents/skills/jahia-java-persistence/SKILL.md +0 -177
- package/dist/cursor/.agents/skills/jahia-java-security/SKILL.md +0 -84
- package/dist/cursor/.agents/skills/jahia-orchestrate/SKILL.md +0 -148
- package/dist/cursor/.agents/skills/jahia-orchestrate/scripts/verify-pages.mjs +0 -59
- package/dist/cursor/.agents/skills/jahia-review-java/SKILL.md +0 -131
- package/dist/cursor/.agents/skills/jahia-review-java/references/code-review-output.md +0 -121
- package/dist/cursor/.cursor/agents/cnd-jahia-mixins.md +0 -113
- package/dist/cursor/.cursor/agents/jahia-cnd-author.md +0 -130
- package/dist/cursor/.cursor/agents/jahia-dev-worker.md +0 -264
- package/dist/cursor/.cursor/agents/jahia-reviewer.md +0 -105
- package/dist/gemini/.agents/skills/jahia/SKILL.md +0 -148
- package/dist/gemini/.agents/skills/jahia-content/SKILL.md +0 -157
- package/dist/gemini/.agents/skills/jahia-content-create-content/SKILL.md +0 -359
- package/dist/gemini/.agents/skills/jahia-content-explore-structure/SKILL.md +0 -255
- package/dist/gemini/.agents/skills/jahia-content-media-upload/SKILL.md +0 -197
- package/dist/gemini/.agents/skills/jahia-content-move-content/SKILL.md +0 -231
- package/dist/gemini/.agents/skills/jahia-content-organize/SKILL.md +0 -209
- package/dist/gemini/.agents/skills/jahia-content-publish/SKILL.md +0 -181
- package/dist/gemini/.agents/skills/jahia-content-query-content/SKILL.md +0 -174
- package/dist/gemini/.agents/skills/jahia-content-translate-content/SKILL.md +0 -226
- package/dist/gemini/.agents/skills/jahia-dev/SKILL.md +0 -124
- package/dist/gemini/.agents/skills/jahia-dev-apis/SKILL.md +0 -52
- package/dist/gemini/.agents/skills/jahia-dev-apis/references/authentication.md +0 -484
- package/dist/gemini/.agents/skills/jahia-dev-apis/references/graphql.md +0 -657
- package/dist/gemini/.agents/skills/jahia-dev-apis/references/jcr-api.md +0 -465
- package/dist/gemini/.agents/skills/jahia-dev-apis/references/security.md +0 -541
- package/dist/gemini/.agents/skills/jahia-dev-cypress/SKILL.md +0 -265
- package/dist/gemini/.agents/skills/jahia-dev-define-content-type/SKILL.md +0 -93
- package/dist/gemini/.agents/skills/jahia-dev-define-content-type/references/modeling-decisions.md +0 -52
- package/dist/gemini/.agents/skills/jahia-dev-java/SKILL.md +0 -110
- package/dist/gemini/.agents/skills/jahia-dev-java/references/backend.md +0 -331
- package/dist/gemini/.agents/skills/jahia-dev-java/references/content-types.md +0 -273
- package/dist/gemini/.agents/skills/jahia-dev-java/references/modules.md +0 -218
- package/dist/gemini/.agents/skills/jahia-dev-java/references/osgi.md +0 -208
- package/dist/gemini/.agents/skills/jahia-dev-java/references/rendering.md +0 -191
- package/dist/gemini/.agents/skills/jahia-dev-java/references/ui-extensions.md +0 -344
- package/dist/gemini/.agents/skills/jahia-dev-osgi-module/SKILL.md +0 -297
- package/dist/gemini/.agents/skills/jahia-dev-ui-extension/SKILL.md +0 -559
- package/dist/gemini/.agents/skills/jahia-java-concurrency/SKILL.md +0 -308
- package/dist/gemini/.agents/skills/jahia-java-jcr/SKILL.md +0 -153
- package/dist/gemini/.agents/skills/jahia-java-osgi/SKILL.md +0 -134
- package/dist/gemini/.agents/skills/jahia-java-persistence/SKILL.md +0 -177
- package/dist/gemini/.agents/skills/jahia-java-security/SKILL.md +0 -84
- package/dist/gemini/.agents/skills/jahia-orchestrate/SKILL.md +0 -148
- package/dist/gemini/.agents/skills/jahia-orchestrate/scripts/verify-pages.mjs +0 -59
- package/dist/gemini/.agents/skills/jahia-review-java/SKILL.md +0 -131
- package/dist/gemini/.agents/skills/jahia-review-java/references/code-review-output.md +0 -121
- package/dist/opencode/.agents/skills/jahia/SKILL.md +0 -148
- package/dist/opencode/.agents/skills/jahia-content/SKILL.md +0 -157
- package/dist/opencode/.agents/skills/jahia-content-create-content/SKILL.md +0 -359
- package/dist/opencode/.agents/skills/jahia-content-explore-structure/SKILL.md +0 -255
- package/dist/opencode/.agents/skills/jahia-content-media-upload/SKILL.md +0 -197
- package/dist/opencode/.agents/skills/jahia-content-move-content/SKILL.md +0 -231
- package/dist/opencode/.agents/skills/jahia-content-organize/SKILL.md +0 -209
- package/dist/opencode/.agents/skills/jahia-content-publish/SKILL.md +0 -181
- package/dist/opencode/.agents/skills/jahia-content-query-content/SKILL.md +0 -174
- package/dist/opencode/.agents/skills/jahia-content-translate-content/SKILL.md +0 -226
- package/dist/opencode/.agents/skills/jahia-dev/SKILL.md +0 -124
- package/dist/opencode/.agents/skills/jahia-dev-apis/SKILL.md +0 -52
- package/dist/opencode/.agents/skills/jahia-dev-apis/references/authentication.md +0 -484
- package/dist/opencode/.agents/skills/jahia-dev-apis/references/graphql.md +0 -657
- package/dist/opencode/.agents/skills/jahia-dev-apis/references/jcr-api.md +0 -465
- package/dist/opencode/.agents/skills/jahia-dev-apis/references/security.md +0 -541
- package/dist/opencode/.agents/skills/jahia-dev-cypress/SKILL.md +0 -265
- package/dist/opencode/.agents/skills/jahia-dev-define-content-type/SKILL.md +0 -93
- package/dist/opencode/.agents/skills/jahia-dev-define-content-type/references/modeling-decisions.md +0 -52
- package/dist/opencode/.agents/skills/jahia-dev-java/SKILL.md +0 -110
- package/dist/opencode/.agents/skills/jahia-dev-java/references/backend.md +0 -331
- package/dist/opencode/.agents/skills/jahia-dev-java/references/content-types.md +0 -273
- package/dist/opencode/.agents/skills/jahia-dev-java/references/modules.md +0 -218
- package/dist/opencode/.agents/skills/jahia-dev-java/references/osgi.md +0 -208
- package/dist/opencode/.agents/skills/jahia-dev-java/references/rendering.md +0 -191
- package/dist/opencode/.agents/skills/jahia-dev-java/references/ui-extensions.md +0 -344
- package/dist/opencode/.agents/skills/jahia-dev-osgi-module/SKILL.md +0 -297
- package/dist/opencode/.agents/skills/jahia-dev-ui-extension/SKILL.md +0 -559
- package/dist/opencode/.agents/skills/jahia-java-concurrency/SKILL.md +0 -308
- package/dist/opencode/.agents/skills/jahia-java-jcr/SKILL.md +0 -153
- package/dist/opencode/.agents/skills/jahia-java-osgi/SKILL.md +0 -134
- package/dist/opencode/.agents/skills/jahia-java-persistence/SKILL.md +0 -177
- package/dist/opencode/.agents/skills/jahia-java-security/SKILL.md +0 -84
- package/dist/opencode/.agents/skills/jahia-orchestrate/SKILL.md +0 -148
- package/dist/opencode/.agents/skills/jahia-orchestrate/scripts/verify-pages.mjs +0 -59
- package/dist/opencode/.agents/skills/jahia-review-java/SKILL.md +0 -131
- package/dist/opencode/.agents/skills/jahia-review-java/references/code-review-output.md +0 -121
- package/dist/opencode/.opencode/agents/cnd-jahia-mixins.md +0 -113
- package/dist/opencode/.opencode/agents/jahia-cnd-author.md +0 -130
- package/dist/opencode/.opencode/agents/jahia-dev-worker.md +0 -264
- package/dist/opencode/.opencode/agents/jahia-reviewer.md +0 -105
- package/dist/windsurf/.windsurf/skills/jahia/SKILL.md +0 -148
- package/dist/windsurf/.windsurf/skills/jahia-content/SKILL.md +0 -157
- package/dist/windsurf/.windsurf/skills/jahia-content-create-content/SKILL.md +0 -359
- package/dist/windsurf/.windsurf/skills/jahia-content-explore-structure/SKILL.md +0 -255
- package/dist/windsurf/.windsurf/skills/jahia-content-media-upload/SKILL.md +0 -197
- package/dist/windsurf/.windsurf/skills/jahia-content-move-content/SKILL.md +0 -231
- package/dist/windsurf/.windsurf/skills/jahia-content-organize/SKILL.md +0 -209
- package/dist/windsurf/.windsurf/skills/jahia-content-publish/SKILL.md +0 -181
- package/dist/windsurf/.windsurf/skills/jahia-content-query-content/SKILL.md +0 -174
- package/dist/windsurf/.windsurf/skills/jahia-content-translate-content/SKILL.md +0 -226
- package/dist/windsurf/.windsurf/skills/jahia-dev/SKILL.md +0 -124
- package/dist/windsurf/.windsurf/skills/jahia-dev-apis/SKILL.md +0 -52
- package/dist/windsurf/.windsurf/skills/jahia-dev-apis/references/authentication.md +0 -484
- package/dist/windsurf/.windsurf/skills/jahia-dev-apis/references/graphql.md +0 -657
- package/dist/windsurf/.windsurf/skills/jahia-dev-apis/references/jcr-api.md +0 -465
- package/dist/windsurf/.windsurf/skills/jahia-dev-apis/references/security.md +0 -541
- package/dist/windsurf/.windsurf/skills/jahia-dev-cypress/SKILL.md +0 -265
- package/dist/windsurf/.windsurf/skills/jahia-dev-define-content-type/SKILL.md +0 -93
- package/dist/windsurf/.windsurf/skills/jahia-dev-define-content-type/references/modeling-decisions.md +0 -52
- package/dist/windsurf/.windsurf/skills/jahia-dev-java/SKILL.md +0 -110
- package/dist/windsurf/.windsurf/skills/jahia-dev-java/references/backend.md +0 -331
- package/dist/windsurf/.windsurf/skills/jahia-dev-java/references/content-types.md +0 -273
- package/dist/windsurf/.windsurf/skills/jahia-dev-java/references/modules.md +0 -218
- package/dist/windsurf/.windsurf/skills/jahia-dev-java/references/osgi.md +0 -208
- package/dist/windsurf/.windsurf/skills/jahia-dev-java/references/rendering.md +0 -191
- package/dist/windsurf/.windsurf/skills/jahia-dev-java/references/ui-extensions.md +0 -344
- package/dist/windsurf/.windsurf/skills/jahia-dev-osgi-module/SKILL.md +0 -297
- package/dist/windsurf/.windsurf/skills/jahia-dev-ui-extension/SKILL.md +0 -559
- package/dist/windsurf/.windsurf/skills/jahia-java-concurrency/SKILL.md +0 -308
- package/dist/windsurf/.windsurf/skills/jahia-java-jcr/SKILL.md +0 -153
- package/dist/windsurf/.windsurf/skills/jahia-java-osgi/SKILL.md +0 -134
- package/dist/windsurf/.windsurf/skills/jahia-java-persistence/SKILL.md +0 -177
- package/dist/windsurf/.windsurf/skills/jahia-java-security/SKILL.md +0 -84
- package/dist/windsurf/.windsurf/skills/jahia-orchestrate/SKILL.md +0 -148
- package/dist/windsurf/.windsurf/skills/jahia-orchestrate/scripts/verify-pages.mjs +0 -59
- package/dist/windsurf/.windsurf/skills/jahia-review-java/SKILL.md +0 -131
- package/dist/windsurf/.windsurf/skills/jahia-review-java/references/code-review-output.md +0 -121
- /package/dist/claude/.claude/{agents → skills/jahia-cnd-author/references}/cnd-child-nodes.md +0 -0
- /package/dist/{cursor/.cursor/agents → codex/.agents/skills/jahia-cnd-author/references}/cnd-child-nodes.md +0 -0
- /package/dist/{opencode/.opencode/agents → copilot/.agents/skills/jahia-cnd-author/references}/cnd-child-nodes.md +0 -0
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: jahia-java-concurrency
|
|
3
|
-
description: Thread safety patterns for Jahia Java backend development in a multi-threaded web application. Covers volatile, locking, atomic variables, thread-safe collections, immutability, and common pitfalls that cause data races, stale reads, and silent corruption. Load when implementing or reviewing any class that holds mutable state accessible from multiple threads — OSGi services, caches, static fields, background workers, event listeners.
|
|
4
|
-
allowed-tools: Read
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Concurrency and Thread Safety for Jahia Java Backend
|
|
8
|
-
|
|
9
|
-
In a Jahia webapp, every OSGi service is a singleton — its instance fields are shared across every concurrent request, publication job, event listener, and background thread. A field that looks fine in a single-threaded test can silently corrupt data or read stale values under real load.
|
|
10
|
-
|
|
11
|
-
This skill covers the correct patterns and the pitfalls. Both developers and reviewers use it.
|
|
12
|
-
|
|
13
|
-
> OSGi-specific concurrency (`@Modified` config reload, `@Reference` dynamic rebinding) is covered in `/jahia-java-osgi`. This skill covers the general Java concurrency model applicable to all backend code.
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## The three questions to ask about any mutable field
|
|
18
|
-
|
|
19
|
-
Before writing or reviewing any instance or static field in a service:
|
|
20
|
-
|
|
21
|
-
1. **Can it be written by more than one thread?** If yes → needs synchronization or an atomic type.
|
|
22
|
-
2. **Can it be read while another thread is writing it?** If yes → at minimum needs `volatile`.
|
|
23
|
-
3. **Are read + write part of a compound action** (check-then-act, read-modify-write)? If yes → `volatile` alone is not enough, needs a lock or an atomic with CAS.
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## Immutability — the first line of defence
|
|
28
|
-
|
|
29
|
-
### Correct approach
|
|
30
|
-
|
|
31
|
-
Prefer immutable objects. An immutable object needs no synchronization — it is inherently thread-safe.
|
|
32
|
-
|
|
33
|
-
- Make fields `final` wherever possible.
|
|
34
|
-
- Use `record` types for config/value objects (all fields are final by definition).
|
|
35
|
-
- Use `List.of()`, `Map.of()`, `Set.of()` for collections that do not change after construction.
|
|
36
|
-
- Return copies or unmodifiable views of mutable internal collections rather than the live reference.
|
|
37
|
-
|
|
38
|
-
### Pitfall
|
|
39
|
-
|
|
40
|
-
```java
|
|
41
|
-
// dangerous — caller can mutate the internal list
|
|
42
|
-
public List<String> getAllowedRoles() {
|
|
43
|
-
return allowedRoles; // returns live mutable reference
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Return `Collections.unmodifiableList(allowedRoles)` or `List.copyOf(allowedRoles)` instead.
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## `volatile` — correct use and limits
|
|
52
|
-
|
|
53
|
-
### Correct use
|
|
54
|
-
|
|
55
|
-
`volatile` guarantees **visibility**: a write to a `volatile` field is immediately visible to all subsequent reads in other threads. Use it when:
|
|
56
|
-
|
|
57
|
-
- One thread writes, many threads read (no compound action needed).
|
|
58
|
-
- The written value is a single reference or primitive (not two fields that must be updated atomically together).
|
|
59
|
-
|
|
60
|
-
```java
|
|
61
|
-
// correct — single writer (SCR @Modified), many readers
|
|
62
|
-
private volatile Config config;
|
|
63
|
-
|
|
64
|
-
@Activate @Modified
|
|
65
|
-
void activate(Cfg cfg) {
|
|
66
|
-
this.config = new Config(cfg); // atomic reference swap
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### Limits — volatile is NOT enough for compound actions
|
|
71
|
-
|
|
72
|
-
```java
|
|
73
|
-
// WRONG — read-modify-write is not atomic even with volatile
|
|
74
|
-
private volatile int counter = 0;
|
|
75
|
-
public void increment() {
|
|
76
|
-
counter++; // read, increment, write — three steps, not one
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Two threads can both read `counter = 5`, both compute `6`, and both write `6` — losing one increment. Use `AtomicInteger.incrementAndGet()` instead.
|
|
81
|
-
|
|
82
|
-
Similarly, volatile does not protect **two fields that must be consistent with each other**:
|
|
83
|
-
|
|
84
|
-
```java
|
|
85
|
-
// WRONG — reader can see updated 'host' with old 'port'
|
|
86
|
-
private volatile String host;
|
|
87
|
-
private volatile int port;
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
Bundle related fields into a single immutable record and swap the reference atomically (as shown in `/jahia-java-osgi`).
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## Atomic variables
|
|
95
|
-
|
|
96
|
-
Use `java.util.concurrent.atomic` for lock-free, thread-safe single-value updates:
|
|
97
|
-
|
|
98
|
-
| Need | Type |
|
|
99
|
-
|---|---|
|
|
100
|
-
| Thread-safe counter | `AtomicInteger` / `AtomicLong` |
|
|
101
|
-
| Thread-safe reference swap | `AtomicReference<T>` |
|
|
102
|
-
| Conditional update (compare-and-swap) | `AtomicReference.compareAndSet()` |
|
|
103
|
-
| Accumulator under high contention | `LongAdder` (more scalable than `AtomicLong` for pure counting) |
|
|
104
|
-
|
|
105
|
-
### Check-then-act with `compareAndSet`
|
|
106
|
-
|
|
107
|
-
```java
|
|
108
|
-
// correct — atomic conditional update
|
|
109
|
-
AtomicReference<State> stateRef = new AtomicReference<>(State.IDLE);
|
|
110
|
-
|
|
111
|
-
public boolean tryStart() {
|
|
112
|
-
return stateRef.compareAndSet(State.IDLE, State.RUNNING);
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
Two threads calling `tryStart()` concurrently: only one gets `true`. No lock needed.
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
## Synchronized blocks and `ReentrantLock`
|
|
121
|
-
|
|
122
|
-
### When to use
|
|
123
|
-
|
|
124
|
-
Use explicit locking when:
|
|
125
|
-
- The critical section spans multiple statements that must execute atomically.
|
|
126
|
-
- You need read/write distinction (`ReadWriteLock`).
|
|
127
|
-
- You need a timed or interruptible lock attempt (`ReentrantLock.tryLock(timeout)`).
|
|
128
|
-
|
|
129
|
-
### Correct approach
|
|
130
|
-
|
|
131
|
-
```java
|
|
132
|
-
// small, focused critical section
|
|
133
|
-
private final Object lock = new Object();
|
|
134
|
-
private List<String> items = new ArrayList<>();
|
|
135
|
-
|
|
136
|
-
public void addItem(String item) {
|
|
137
|
-
synchronized (lock) {
|
|
138
|
-
items.add(item);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
public List<String> snapshot() {
|
|
143
|
-
synchronized (lock) {
|
|
144
|
-
return List.copyOf(items); // return a copy, not the live list
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
### Pitfalls
|
|
150
|
-
|
|
151
|
-
- **Locking on `this`.** Callers can also `synchronized(service)` from outside, causing unexpected contention or deadlock. Prefer a private `final Object lock`.
|
|
152
|
-
- **Holding a lock during I/O or JCR calls.** A lock held while doing a JCR query or an HTTP call blocks all other threads waiting for it. Move I/O outside the critical section; only protect the state mutation.
|
|
153
|
-
- **Inconsistent lock object.** Two methods protecting the same state must use the same lock.
|
|
154
|
-
- **Deadlock.** Two threads each holding lock A and waiting for lock B. Always acquire multiple locks in the same fixed order. Prefer `tryLock(timeout)` and fail gracefully rather than block indefinitely.
|
|
155
|
-
|
|
156
|
-
### `ReadWriteLock` for read-heavy state
|
|
157
|
-
|
|
158
|
-
```java
|
|
159
|
-
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
|
|
160
|
-
private Map<String, String> cache = new HashMap<>();
|
|
161
|
-
|
|
162
|
-
public String get(String key) {
|
|
163
|
-
rwLock.readLock().lock();
|
|
164
|
-
try { return cache.get(key); }
|
|
165
|
-
finally { rwLock.readLock().unlock(); }
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
public void put(String key, String value) {
|
|
169
|
-
rwLock.writeLock().lock();
|
|
170
|
-
try { cache.put(key, value); }
|
|
171
|
-
finally { rwLock.writeLock().unlock(); }
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
Multiple readers proceed concurrently; a writer gets exclusive access. Worth the complexity only when reads heavily outnumber writes.
|
|
176
|
-
|
|
177
|
-
---
|
|
178
|
-
|
|
179
|
-
## Thread-safe collections
|
|
180
|
-
|
|
181
|
-
| Use case | Correct type | What NOT to use |
|
|
182
|
-
|---|---|---|
|
|
183
|
-
| Concurrent map (read-heavy or write-heavy) | `ConcurrentHashMap` | `HashMap` (not thread-safe), `Collections.synchronizedMap` (full lock on every op) |
|
|
184
|
-
| Concurrent list, infrequent writes | `CopyOnWriteArrayList` | `ArrayList`, `Collections.synchronizedList` |
|
|
185
|
-
| Concurrent queue / work queue | `LinkedBlockingQueue`, `ArrayBlockingQueue` | `LinkedList` |
|
|
186
|
-
| Set | `ConcurrentHashMap.newKeySet()` | `HashSet` |
|
|
187
|
-
| Cache with eviction | `Caffeine` or `Guava Cache` | `HashMap` with manual cleanup |
|
|
188
|
-
|
|
189
|
-
### Pitfall — compound actions on `ConcurrentHashMap`
|
|
190
|
-
|
|
191
|
-
```java
|
|
192
|
-
// WRONG — check-then-put is not atomic
|
|
193
|
-
if (!map.containsKey(key)) {
|
|
194
|
-
map.put(key, value);
|
|
195
|
-
}
|
|
196
|
-
// CORRECT
|
|
197
|
-
map.putIfAbsent(key, value);
|
|
198
|
-
// or for a more complex compute:
|
|
199
|
-
map.computeIfAbsent(key, k -> expensiveCreate(k));
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
Even `ConcurrentHashMap` does not make compound actions atomic unless you use the atomic methods (`putIfAbsent`, `computeIfAbsent`, `merge`, `compute`).
|
|
203
|
-
|
|
204
|
-
---
|
|
205
|
-
|
|
206
|
-
## Static fields
|
|
207
|
-
|
|
208
|
-
### Pitfall
|
|
209
|
-
|
|
210
|
-
Static fields are shared across all class loader instances — effectively global state in a webapp. A static mutable field is the most dangerous form of shared state: it is not scoped to a component lifecycle, so it outlives bundle reactivations and can carry stale state.
|
|
211
|
-
|
|
212
|
-
```java
|
|
213
|
-
// dangerous — static mutable state in a webapp
|
|
214
|
-
private static Map<String, Object> cache = new HashMap<>();
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
**Rule:** static fields in a Jahia module must be either:
|
|
218
|
-
- `final` and truly immutable (constants, loggers), or
|
|
219
|
-
- `volatile` / concurrent-typed with documented thread-safety, or
|
|
220
|
-
- `ThreadLocal` (thread-scoped, not shared).
|
|
221
|
-
|
|
222
|
-
If you need a cache or shared service state, use an OSGi `@Component` instance field — the OSGi lifecycle manages it correctly.
|
|
223
|
-
|
|
224
|
-
---
|
|
225
|
-
|
|
226
|
-
## `ThreadLocal`
|
|
227
|
-
|
|
228
|
-
`ThreadLocal` gives each thread its own isolated copy of a variable. Correct for per-request state (locale, user context, transaction context).
|
|
229
|
-
|
|
230
|
-
### Pitfall — thread pool reuse
|
|
231
|
-
|
|
232
|
-
Jahia uses thread pools. A `ThreadLocal` set during request A and not cleared will be visible during a later request B handled by the same thread:
|
|
233
|
-
|
|
234
|
-
```java
|
|
235
|
-
// always clean up in a finally block
|
|
236
|
-
threadLocal.set(value);
|
|
237
|
-
try {
|
|
238
|
-
doWork();
|
|
239
|
-
} finally {
|
|
240
|
-
threadLocal.remove(); // mandatory
|
|
241
|
-
}
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
Failing to call `remove()` is a P1 finding — stale user context or locale leaked to subsequent requests.
|
|
245
|
-
|
|
246
|
-
---
|
|
247
|
-
|
|
248
|
-
## JCR sessions are NOT thread-safe
|
|
249
|
-
|
|
250
|
-
A `JCRSessionWrapper` must never be shared across threads. Do not store a session as an instance field of an OSGi service and reuse it across requests.
|
|
251
|
-
|
|
252
|
-
```java
|
|
253
|
-
// WRONG — shared session across threads
|
|
254
|
-
@Component
|
|
255
|
-
public class MyService {
|
|
256
|
-
private JCRSessionWrapper session; // one session, all threads — crash under concurrency
|
|
257
|
-
}
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
Always obtain a fresh session per-thread (and per-locale where i18n matters) and close it in a `finally` block or via `JCRTemplate`.
|
|
261
|
-
|
|
262
|
-
---
|
|
263
|
-
|
|
264
|
-
## Lazy initialization
|
|
265
|
-
|
|
266
|
-
### Correct approach — `volatile` + double-checked locking
|
|
267
|
-
|
|
268
|
-
```java
|
|
269
|
-
private volatile ExpensiveObject instance;
|
|
270
|
-
|
|
271
|
-
public ExpensiveObject get() {
|
|
272
|
-
if (instance == null) { // first check (no lock)
|
|
273
|
-
synchronized (this) {
|
|
274
|
-
if (instance == null) { // second check (with lock)
|
|
275
|
-
instance = new ExpensiveObject();
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
return instance;
|
|
280
|
-
}
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
Without `volatile`, the JVM may publish a partially-constructed object due to instruction reordering. **`volatile` on the field is mandatory for double-checked locking to be correct.**
|
|
284
|
-
|
|
285
|
-
### Simpler alternative — holder idiom
|
|
286
|
-
|
|
287
|
-
```java
|
|
288
|
-
// no synchronization needed — class loading is inherently thread-safe
|
|
289
|
-
private static class Holder {
|
|
290
|
-
static final ExpensiveObject INSTANCE = new ExpensiveObject();
|
|
291
|
-
}
|
|
292
|
-
public static ExpensiveObject get() { return Holder.INSTANCE; }
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
---
|
|
296
|
-
|
|
297
|
-
## Review checklist
|
|
298
|
-
|
|
299
|
-
When reviewing any class in a Jahia module, check:
|
|
300
|
-
|
|
301
|
-
1. **Instance fields of `@Component` services** — are mutable ones `volatile`, atomic, or synchronized?
|
|
302
|
-
2. **Static mutable fields** — flag immediately; require justification and correct synchronization.
|
|
303
|
-
3. **Compound actions** — every check-then-act or read-modify-write on a shared field needs a lock or atomic CAS.
|
|
304
|
-
4. **Collections returned from getters** — are they copies or unmodifiable views?
|
|
305
|
-
5. **JCR sessions** — never stored as instance fields; always obtained and closed per-thread.
|
|
306
|
-
6. **`ThreadLocal`** — always cleaned up in a `finally` block.
|
|
307
|
-
7. **Locks** — held for the minimum possible time; no I/O inside a critical section.
|
|
308
|
-
8. **Undocumented thread-safety contract** — if the class is not internally thread-safe, its Javadoc must say so and name the required external synchronization.
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: jahia-java-jcr
|
|
3
|
-
description: JCR patterns for Jahia Java development — correct usage of sessions, workspaces, node operations, mixins, locks, and versioning. Covers both the right approach and the pitfalls that cause data loss, security gaps, or concurrency bugs. Load when implementing or reviewing any class that reads or writes the JCR.
|
|
4
|
-
allowed-tools: Read
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# JCR Patterns for Jahia Java
|
|
8
|
-
|
|
9
|
-
This skill covers how to use the JCR correctly in a Jahia Java module. Each section states the correct approach first, then the pitfall to avoid. Both developers and reviewers use this skill: developers to implement correctly from the start, reviewers to identify violations.
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Session lifecycle and workspace
|
|
14
|
-
|
|
15
|
-
### Correct approach
|
|
16
|
-
|
|
17
|
-
- **User session** (`JCRSessionWrapper` obtained from `JCRSessionFactory.getCurrentUserSession(workspace, locale)`) enforces ACLs. Use this for any operation that should respect the user's permissions.
|
|
18
|
-
- **System session** (`JCRTemplate.doExecuteWithSystemSession` or `JCRSessionFactory.getCurrentSystemSession`) bypasses ACLs. Use only when a permission check was performed earlier in the call chain and documented explicitly.
|
|
19
|
-
- **Workspace boundary.** `default` (edit workspace, where authors work) vs `live` (published, visitor-facing). Public-facing reads must use `live`. Admin UIs use `default`. Writes that must appear publicly go through `PublicationService` — never write to `live` directly unless you have a specific operational reason.
|
|
20
|
-
- **Locale.** `getCurrentUserSession(workspace, locale)` resolves i18n properties. Omitting the locale falls back to default — correct only if the caller truly does not need a specific locale.
|
|
21
|
-
|
|
22
|
-
### Pitfalls
|
|
23
|
-
|
|
24
|
-
- **System session without prior permission check.** When a system session performs an operation, trace back to where the target node ID came from. If it came from a user-session lookup with no further authorization check, the user-session lookup is the entire security boundary. Document this explicitly. If it is absent, it is a security finding.
|
|
25
|
-
- **Workspace mismatch.** Reading from `default` when rendering public pages, or writing to `live` when the intended target is `default`. Both produce silent wrong behavior.
|
|
26
|
-
- **Locale omission.** Calling without locale and reading `jcr:title` or any i18n property — the result is locale-nondeterministic.
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Node names — JSR-283 conformance
|
|
31
|
-
|
|
32
|
-
### Correct approach
|
|
33
|
-
|
|
34
|
-
Forbidden characters in a local name: `/ : [ ] | *`, plus whitespace-only names. Use `JCRContentUtils.escapeLocalNodeName` to sanitize any externally-supplied string before using it as a node name.
|
|
35
|
-
|
|
36
|
-
### Pitfall
|
|
37
|
-
|
|
38
|
-
Hand-rolled filename sanitization (regex replacements, `String.replace`) is almost always incomplete. The JSR-283 character set is non-obvious. Use the platform helper.
|
|
39
|
-
|
|
40
|
-
---
|
|
41
|
-
|
|
42
|
-
## Same-name siblings (SNS)
|
|
43
|
-
|
|
44
|
-
### Correct approach
|
|
45
|
-
|
|
46
|
-
Two children with the same name under the same parent are indexed `node[1]`, `node[2]`. If you need to find-or-create by name under concurrent load, either:
|
|
47
|
-
- Lock the parent node before the check-then-create sequence.
|
|
48
|
-
- Use a unique-by-construction name (UUID, slug+timestamp) and store the display name as a property.
|
|
49
|
-
|
|
50
|
-
### Pitfall
|
|
51
|
-
|
|
52
|
-
Unguarded find-or-create patterns under any concurrent caller (publication pipeline, event listener, HTTP endpoint) hit `ItemExistsException` or silently create a duplicate SNS node. Under guest endpoints this is a P1 finding.
|
|
53
|
-
|
|
54
|
-
---
|
|
55
|
-
|
|
56
|
-
## Mixin handling
|
|
57
|
-
|
|
58
|
-
### Correct approach
|
|
59
|
-
|
|
60
|
-
- Before setting properties specific to a mixin, call `node.addMixin("ns:myMixin")` if the node does not already have it.
|
|
61
|
-
- Use `node.isNodeType("ns:myMixin")` to classify behavior rather than switching on concrete node type strings from another module. This keeps the engine decoupled from specific UI modules.
|
|
62
|
-
- **Definition-level vs instance-level mixins.** Mixins applied in the CND definition are always present on every node of that type. Mixins added at runtime via `addMixin()` are instance-level — they must be captured and restored explicitly in any serialization/versioning path.
|
|
63
|
-
|
|
64
|
-
### Pitfalls
|
|
65
|
-
|
|
66
|
-
- Assuming a mixin is present because the content type "should" have it — this breaks when the content was created before the mixin was added to the definition.
|
|
67
|
-
- Hardcoded concrete node-type strings from another module (`fmdb:inputText`, `fmdb:textarea`). The correct pattern is classifying mixins in the engine's own CND.
|
|
68
|
-
- Serialization paths (export, versioning, diff) that capture `properties` but ignore `mixinNodeTypesNames` — instance-level mixin changes are silently lost on restore.
|
|
69
|
-
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
## Versioning and checkout
|
|
73
|
-
|
|
74
|
-
### Correct approach
|
|
75
|
-
|
|
76
|
-
Writing to a `mix:versionable` node requires a `checkout()` call first. After saving, call `checkin()` if the workflow requires it. Jahia's publication service handles this for standard publication flows — only write direct checkout/checkin in custom write paths.
|
|
77
|
-
|
|
78
|
-
### Pitfall
|
|
79
|
-
|
|
80
|
-
Writing to a versioned node without `checkout()` throws `VersionException`. Code that assumes the node is always in a checked-out state breaks whenever the publication service last left it checked in.
|
|
81
|
-
|
|
82
|
-
---
|
|
83
|
-
|
|
84
|
-
## Locking
|
|
85
|
-
|
|
86
|
-
### Correct approach
|
|
87
|
-
|
|
88
|
-
Respect existing locks before performing write operations. Before clearing a lock:
|
|
89
|
-
1. Check whether the lock is owned by the current operation or by an external caller (another user, a publication job, a workflow).
|
|
90
|
-
2. If the lock is external, **fail the operation** with a clear error — do not clear it silently and continue.
|
|
91
|
-
3. Document the thread-safety contract of any write path that involves locking.
|
|
92
|
-
|
|
93
|
-
### Pitfall
|
|
94
|
-
|
|
95
|
-
```java
|
|
96
|
-
// dangerous — clears locks unconditionally, continues even if clearing fails
|
|
97
|
-
JCRContentUtils.clearAllLocks(node);
|
|
98
|
-
restoreContent(node, version);
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
A node locked by an active publication job, a concurrent editor, or a workflow step is locked for a reason. Clearing it unconditionally can corrupt in-progress work. This is a P0 finding if the code ships to production; P1 if guarded by a feature flag that is off by default.
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## JCR event listeners
|
|
106
|
-
|
|
107
|
-
### Correct approach
|
|
108
|
-
|
|
109
|
-
Register listeners in `@Activate` and unregister in `@Deactivate`. Use `JCRObservationManager` or Jahia's `DefaultEventListener` base class. Keep listeners short — heavy work should be dispatched to a separate thread or scheduled task.
|
|
110
|
-
|
|
111
|
-
Event listener disabling via `JCRObservationManager.setAllEventListenersDisabled(true)` is **thread-local** in Jahia, not global. It is safe to use inside a request thread or a background thread without affecting other concurrent threads.
|
|
112
|
-
|
|
113
|
-
### Pitfalls
|
|
114
|
-
|
|
115
|
-
- Listeners registered but never unregistered — accumulate across reactivations, causing duplicate event processing.
|
|
116
|
-
- Blocking I/O or JCR writes inside a synchronous event listener — holds the observation thread and causes lag across the entire event queue.
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
## `RepositoryException` handling
|
|
121
|
-
|
|
122
|
-
### Correct approach
|
|
123
|
-
|
|
124
|
-
- On a **security gate** (checking node type, checking permission): if the check throws, fail closed. Do not let the operation continue.
|
|
125
|
-
- On a **data read**: if partial results would be misleading downstream, fail or return an empty result with a logged warning.
|
|
126
|
-
|
|
127
|
-
### Pitfall
|
|
128
|
-
|
|
129
|
-
```java
|
|
130
|
-
try {
|
|
131
|
-
requiresAuth = node.isNodeType("...");
|
|
132
|
-
} catch (RepositoryException e) {
|
|
133
|
-
log.warn(...);
|
|
134
|
-
return; // operation continues — fails open
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
Fail-open on a security gate is a P0 finding. Fail-open on a data read producing misleading partial state is P0 or P1 depending on downstream impact.
|
|
139
|
-
|
|
140
|
-
---
|
|
141
|
-
|
|
142
|
-
## JCR SQL2 queries
|
|
143
|
-
|
|
144
|
-
### Correct approach
|
|
145
|
-
|
|
146
|
-
- Scope queries with `ISDESCENDANTNODE(alias, '/sites/...')` — never query the entire repository.
|
|
147
|
-
- Use specific node types, not `nt:base`. Use `jmix:searchable` for broad content queries.
|
|
148
|
-
- Parameterize with bind variables, not string concatenation.
|
|
149
|
-
- Set a `LIMIT` on unbounded queries.
|
|
150
|
-
|
|
151
|
-
### Pitfall
|
|
152
|
-
|
|
153
|
-
`SELECT * FROM [nt:base]` against the full repository is a full-scan and blocks the query index. String-concatenated queries are a JCR injection vector (less critical than SQL injection but still wrong).
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: jahia-java-osgi
|
|
3
|
-
description: OSGi component patterns for Jahia Java development — correct usage of @Component lifecycle, @Reference, Export-Package, whiteboard services, and thread safety. Covers both the right approach and the pitfalls that cause NPEs, stale state, or leaked internals. Load when implementing or reviewing any class annotated with @Component, @Reference, or @Activate.
|
|
4
|
-
allowed-tools: Read
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# OSGi Component Patterns for Jahia Java
|
|
8
|
-
|
|
9
|
-
This skill covers how to write OSGi components correctly in a Jahia Java module. Each section states the correct approach first, then the pitfall to avoid. Both developers and reviewers use this skill.
|
|
10
|
-
|
|
11
|
-
For broader Java concurrency patterns (atomic variables, locking, thread-safe collections, `ThreadLocal`, JCR session threading) that apply beyond OSGi components, load `/jahia-java-concurrency`.
|
|
12
|
-
|
|
13
|
-
For a comprehensive OSGi reference (bundle lifecycle, Blueprint XML, Karaf tooling, service registry), load the `jahia-dev-java` skill and read `references/osgi.md`.
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Component state and configuration reload
|
|
18
|
-
|
|
19
|
-
### Correct approach
|
|
20
|
-
|
|
21
|
-
`@Component` services are singletons. Configuration is delivered via `@Activate` (on first start) and `@Modified` (on config change). `@Modified` runs on a different thread than service consumers.
|
|
22
|
-
|
|
23
|
-
The safe pattern for config reload:
|
|
24
|
-
|
|
25
|
-
```java
|
|
26
|
-
private volatile Config config;
|
|
27
|
-
|
|
28
|
-
record Config(String host, int port) {}
|
|
29
|
-
|
|
30
|
-
@Activate @Modified
|
|
31
|
-
public void activate(MyOsgiConfig cfg) {
|
|
32
|
-
this.config = new Config(cfg.host(), cfg.port());
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
public void doWork() {
|
|
36
|
-
var c = this.config; // snapshot once — atomic read
|
|
37
|
-
// use c.host(), c.port() ...
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
A single `volatile` write (the reference swap) is atomically visible to all readers. Readers snapshot the reference once at method entry and work with the snapshot — they never see a half-updated config.
|
|
42
|
-
|
|
43
|
-
### Pitfalls
|
|
44
|
-
|
|
45
|
-
- **Mutable fields updated in `@Activate`/`@Modified` without `volatile` or synchronization.** A consumer thread can read a field while `@Modified` is updating it — data race. P1 finding.
|
|
46
|
-
- **Multiple fields updated individually without synchronization.** Even with `volatile`, two separate field reads can see values from different config snapshots. Use a single `volatile Config` record, not individual `volatile String host; volatile int port`.
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
## Service references
|
|
51
|
-
|
|
52
|
-
### Correct approach
|
|
53
|
-
|
|
54
|
-
- `@Reference` fields are set by SCR before `@Activate`. Treat them as effectively final inside the component's methods.
|
|
55
|
-
- For **mandatory** references (`cardinality = MANDATORY`), the component will not activate if the service is absent — null checks are not needed.
|
|
56
|
-
- For **optional** references (`cardinality = OPTIONAL`), the field can be `null` — always guard.
|
|
57
|
-
- For **dynamic** references (`policy = ReferencePolicy.DYNAMIC`), the field can be replaced at runtime. Snapshot it at method entry: `var svc = this.myService;` then use `svc`. Reading the field twice risks NPE if the service is unregistered between reads.
|
|
58
|
-
|
|
59
|
-
### Pitfalls
|
|
60
|
-
|
|
61
|
-
- **Non-mandatory `@Reference` accessed without null guard.** P1 — NPE in production when the referenced bundle is not deployed.
|
|
62
|
-
- **Dynamic reference read twice without snapshot.** Between two reads the SCR may set the field to `null`. P1.
|
|
63
|
-
- **`policyOption = GREEDY`.** SCR rebinds to a higher-ranked service when one appears. Code holding a reference to the old service instance keeps using a deactivated service. Document this if intentional.
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
## Lifecycle side effects
|
|
68
|
-
|
|
69
|
-
### Correct approach
|
|
70
|
-
|
|
71
|
-
Every side effect created in `@Activate` must be undone in `@Deactivate`. Components can be deactivated and re-activated on config changes (depending on `@Modified` policy). Failing to undo side effects causes them to accumulate across activations.
|
|
72
|
-
|
|
73
|
-
Checklist:
|
|
74
|
-
- Thread started in `@Activate` → stopped in `@Deactivate` (interrupt + join).
|
|
75
|
-
- JCR event listener registered → unregistered.
|
|
76
|
-
- Scheduled task registered → cancelled.
|
|
77
|
-
- External connection opened → closed.
|
|
78
|
-
- Cache populated → cleared or reseeded.
|
|
79
|
-
|
|
80
|
-
### Pitfall
|
|
81
|
-
|
|
82
|
-
A listener registered in `@Activate` but never unregistered in `@Deactivate` survives deactivation, fires events for a component that is no longer active, and duplicates on next activation. P1.
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## Export-Package hygiene
|
|
87
|
-
|
|
88
|
-
### Correct approach
|
|
89
|
-
|
|
90
|
-
`Export-Package` in `pom.xml` defines what other bundles can import. It is the module's public API contract.
|
|
91
|
-
|
|
92
|
-
- Export only interfaces and types in a dedicated `api` or `spi` sub-package.
|
|
93
|
-
- Never export `*.impl`, `*.internal`, `*.actions` — the name signals private scope.
|
|
94
|
-
- Never re-export third-party packages.
|
|
95
|
-
- If the module advertises an SPI for external consumers, the SPI should live in a **separate Maven module** (`{name}-api`). Changing the runtime JAR then does not force a version bump on the API.
|
|
96
|
-
|
|
97
|
-
### Pitfall
|
|
98
|
-
|
|
99
|
-
Exporting implementation packages means any other bundle can import your internal classes. A refactor that renames or removes an internal class becomes a breaking change for dependent bundles. P1.
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## Whiteboard pattern services
|
|
104
|
-
|
|
105
|
-
Services registered as `@Component` — `Servlet`, `Filter`, `EventHandler`, GraphQL provider — are activated the moment the bundle starts. If the service is reachable over HTTP, it is as exposed as a `web.xml` servlet, with no extra protection by default. Apply the security mapping from `jahia-java-security` for every HTTP-reachable whiteboard service.
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
## Service locator anti-pattern
|
|
110
|
-
|
|
111
|
-
### Correct approach
|
|
112
|
-
|
|
113
|
-
Declare all dependencies as `@Reference` fields. SCR injects them before `@Activate`. The component's constructor or `@Activate` method has all dependencies available without any lookup.
|
|
114
|
-
|
|
115
|
-
### Pitfall
|
|
116
|
-
|
|
117
|
-
```java
|
|
118
|
-
// anti-pattern — service locator inside a method
|
|
119
|
-
MyService svc = (MyService) SpringContextSingleton.getBean("myService");
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
Service locator calls inside methods: hide the component's real dependencies, make the code impossible to unit-test, bypass SCR lifecycle guarantees, and can return stale or wrong beans after a context refresh. P2 in general code; P1 in a hot path or security-relevant method.
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
## Thread safety summary for reviewers
|
|
127
|
-
|
|
128
|
-
When reviewing an `@Component` service, ask:
|
|
129
|
-
|
|
130
|
-
1. Are there mutable instance fields? If yes — are they `volatile` or synchronized?
|
|
131
|
-
2. Does the component react to `@Modified`? If yes — do consumers snapshot config at method entry?
|
|
132
|
-
3. Are there `DYNAMIC` references? If yes — do callers snapshot the reference?
|
|
133
|
-
4. Does the component start threads, register listeners, or open connections? If yes — does `@Deactivate` undo all of them?
|
|
134
|
-
5. Does the component's Javadoc state its thread-safety contract? If the service is not internally safe, the caller must be told what external serialization is required.
|