diff --git a/.asf.yaml b/.asf.yaml index 5948afd1371..365032378b0 100644 --- a/.asf.yaml +++ b/.asf.yaml @@ -28,4 +28,6 @@ github: - JCR - JCRVLT - SLING - - FELIX \ No newline at end of file + - FELIX + protected_branches: + trunk: {} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000000..7b9108af5b0 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,100 @@ +# ~ 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. + +name: Build +on: + push: + branches: + - trunk + pull_request: + types: [opened, synchronize, reopened] +jobs: + build: + name: Maven Build + runs-on: ubuntu-latest + steps: + - name: Git clone + uses: actions/checkout@v6 + - name: Set up JDK 11 + uses: actions/setup-java@v5 + with: + java-version: 11 + distribution: temurin + cache: maven + server-id: apache.snapshots.https # Value of the distributionManagement/repository/id field of the pom.xml + server-username: MAVEN_APACHE_NEXUS_USERNAME # env variable for username in deploy + server-password: MAVEN_APACHE_NEXUS_PASSWORD # env variable for token in deploy + # sets environment variables to be used in subsequent steps: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable + - name: Set environment variables + shell: bash + run: | + if [ "${{github.ref}}" = "refs/heads/trunk" ] && [ "${{github.event_name}}" = "push" ] && [ "${{github.repository_owner}}" = "apache" ]; then + echo 'Running on main branch of the canonical repo' + echo "MVN_ADDITIONAL_OPTS=-DdeployAtEnd=true" >> $GITHUB_ENV + echo "MVN_GOAL=deploy" >> $GITHUB_ENV + echo "MAVEN_APACHE_NEXUS_USERNAME=${{ secrets.NEXUS_USER }}" >> $GITHUB_ENV + echo "MAVEN_APACHE_NEXUS_PASSWORD=${{ secrets.NEXUS_PW }}" >> $GITHUB_ENV + else + echo 'Running outside main branch/canonical repo' + echo "MVN_ADDITIONAL_OPTS=" >> $GITHUB_ENV + echo "MVN_GOAL=install" >> $GITHUB_ENV + fi + - name: Build + # executing ITs requires installing artifacts to the local repository + run: mvn -B ${{ env.MVN_GOAL }} ${{ env.MVN_ADDITIONAL_OPTS }} -Pcoverage,integrationTesting,javadoc -Dorg.ops4j.pax.url.mvn.repositories="https://repo1.maven.org/maven2@id=central" + - name: Upload build result + uses: actions/upload-artifact@v6 + with: + name: compiled-classes-and-coverage + # compare with https://docs.sonarsource.com/sonarqube-cloud/advanced-setup/languages/java/#java-analysis-and-bytecode + path: | + **/target/**/*.class + **/target/site/jacoco*/*.xml + + # execute analysis in a separate job for better visualization and usage of matrix builds + # https://docs.sonarsource.com/sonarcloud/advanced-setup/ci-based-analysis/sonarscanner-for-maven/#invoking-the-goal + sonar: + name: SonarQube Analysis + runs-on: ubuntu-latest + needs: build + # not supported on forks, https://portal.productboard.com/sonarsource/1-sonarqube-cloud/c/50-sonarcloud-analyzes-external-pull-request + if: ${{ github.repository == 'apache/jackrabbit' }} + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + - name: Set up JDK 21 + uses: actions/setup-java@v5 + with: + java-version: 21 + distribution: temurin + cache: maven + - name: Download compiled classes + uses: actions/download-artifact@v4 + with: + name: compiled-classes-and-coverage + - name: Cache SonarQube packages + uses: actions/cache@v5 + with: + path: ~/.sonar/cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + - name: Analyze with SonarQube + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any + SONAR_TOKEN: ${{ secrets.SONARCLOUD_TOKEN }} + run: SONAR_SCANNER_JAVA_OPTS="-Xmx8g" mvn -B org.sonarsource.scanner.maven:sonar-maven-plugin:5.5.0.6356:sonar -Dsonar.projectKey=apache_jackrabbit -Dsonar.organization=apache -Dsonar.scanner.skipJreProvisioning=true \ No newline at end of file diff --git a/.mvn/README.md b/.mvn/README.md new file mode 100644 index 00000000000..560e6560efe --- /dev/null +++ b/.mvn/README.md @@ -0,0 +1 @@ +Used for determining [`maven.multiModuleProjectDirectory`](https://issues.apache.org/jira/browse/MNG-5786). \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000000..ea0f93f6d9b --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,13 @@ +# Agent guidance + +This file is read by automated agents (security scanners, code +analyzers, AI assistants) operating on this repository. It points +them at the human-authored references they should consult before +producing output. + +## Security + +Security model: [SECURITY.md](./SECURITY.md) + +Agents that scan this repository should consult `SECURITY.md` and the +threat model it links before reporting issues. diff --git a/README.txt b/README.txt index 776b26e2d81..af7591e072f 100644 --- a/README.txt +++ b/README.txt @@ -65,3 +65,11 @@ Credits See http://jackrabbit.apache.org/jackrabbit-team.html for the list of Jackrabbit committers and main contributors. + +SonarQube Cloud +=========== + +The CI builds automatically checks the code with SonarQube Cloud. The results +are accessible at + + https://sonarcloud.io/project/overview?id=apache_jackrabbit diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 713529ec7a1..a98ec320652 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,44 +1,32 @@ -Release Notes -- Apache Jackrabbit -- Version 2.21.27-beta +Release Notes -- Apache Jackrabbit -- Version 2.23.5-beta Introduction ------------ -This is Apache Jackrabbit(TM) 2.21.27-beta, a fully compliant implementation of the +This is Apache Jackrabbit(TM) 2.23.5-beta, a fully compliant implementation of the Content Repository for Java(TM) Technology API, version 2.0 (JCR 2.0) as specified in the Java Specification Request 283 (JSR 283). -Apache Jackrabbit 2.21.27-beta is an unstable release cut directly from +Apache Jackrabbit 2.23.5-beta is an unstable release cut directly from Jackrabbit trunk, with a focus on new features and other -improvements. For production use we recommend the latest stable 2.20.x +improvements. For production use we recommend the latest stable 2.22.x release. -Changes in Jackrabbit 2.21.27-beta +Changes in Jackrabbit 2.23.5-beta ---------------------------------- -Task - - [JCR-4972] - Remove RMI support - [JCR-5028] - jackrabbit-jcr-rmi: remove - [JCR-5042] - jackrabbit-jcr-servlet: remove RMI support - [JCR-5044] - Update tomcat dependency to 9.0.87 - [JCR-5045] - Update commons-io dependency to 2.16.0 - [JCR-5046] - Update oak-jackrabbit-api.version.implemented in trunk to Oak 1.62.0 - [JCR-5047] - Update to jacoco version 0.8.12 - [JCR-5052] - Update commons-io dependency to 2.16.1 - [JCR-5053] - Update commons-cli dependency to 1.7.0 - [JCR-5054] - vfs-ext: update hadoop-hdfs-client dependency to 3.4.0 - [JCR-5055] - update Apache parent pom to version 32 - [JCR-5056] - Update maven-jar-plugin to 3.4.1 - [JCR-5057] - Update pmd-plugin dependency to 3.22.0 - [JCR-5058] - Update spotbugs-maven-plugin to 4.8.5.0 - [JCR-5059] - set baseline comparisonVersion to latest stable (2.20.16) - [JCR-5060] - Update oak-jackrabbit-api.version.used in trunk and 2.20 to Oak 1.22.20 - [JCR-5063] - Update build-helper-maven-plugin to version 3.6.0 - [JCR-5064] - Update mockito dependency to 5.12.0 - [JCR-5068] - update aws java sdk version to 1.12.730 - [JCR-5069] - Update commons-cli dependency to 1.8.0 - [JCR-5070] - Update tomcat dependency to 9.0.89 - [JCR-5071] - Update oak-jackrabbit-api.version.implemented in trunk to Oak 1.64.0 +** Sub-task + * [JCR-5244] - improve test coverage for HttpMultipartPost + +** Improvement + * [JCR-5249] - jackrabbit-spi-commons: add broken namepace names / prefixes to exception message + +** Task + * [JCR-5233] - commons-fileupload (1.6) restricts header size in upload parts + * [JCR-5242] - Update Jackrabbit Trunk to Oak 2.2.0 + * [JCR-5243] - Update oak-jackrabbit-api.version.used to Oak 1.22.24 + * [JCR-5246] - webapp: update tomcat dependency to 9.0.118 + * [JCR-5247] - update Apache parent pom to version 39 For more detailed information about all the changes in this and other @@ -86,4 +74,3 @@ Trademarks Apache Jackrabbit, Jackrabbit, Apache, the Apache feather logo, and the Apache Jackrabbit project logo are trademarks of The Apache Software Foundation. - diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..f249256a0e7 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,34 @@ + + +# Security Policy + +## Reporting a Vulnerability + +Apache Jackrabbit follows the [Apache Software Foundation security +process](https://www.apache.org/security/). Please report suspected +vulnerabilities privately to `security@apache.org` (the Jackrabbit PMC +is reachable via `private@jackrabbit.apache.org`). Do not open public +GitHub issues or pull requests for security reports. + +## Threat Model + +What the project treats as in scope and out of scope, the security +properties it provides and disclaims, the adversary model, and how +findings are triaged are documented in [THREAT_MODEL.md](./THREAT_MODEL.md). diff --git a/THREAT_MODEL.md b/THREAT_MODEL.md new file mode 100644 index 00000000000..285ae91a15c --- /dev/null +++ b/THREAT_MODEL.md @@ -0,0 +1,734 @@ + + +# Apache Jackrabbit Security Threat Model (draft) + +**Why a separate Jackrabbit model (not folded into Jackrabbit Oak).** +The Jackrabbit PMC owns three functionally distinct codebases. The +original `jackrabbit` (commonly "Jackrabbit 2.x" / jackrabbit-core) and +`jackrabbit-oak` share a JCR API contract but have different storage +architectures, different security stacks (Oak introduced a redesigned +`SecurityProvider`-based model; Jackrabbit-2 uses the older JR2 ACL + +JAAS plumbing), different threading models, and — most importantly — +different maintenance postures. Jackrabbit is in *maintenance mode* with +JCR-API and reference-implementation work still happening but no major +feature development; Oak is the active product. Triage rules and +"what's in scope" differ enough that one document would have to caveat +every claim. The Jackrabbit PMC has confirmed (`.asf.yaml` ties commits +to `oak-dev@jackrabbit.apache.org` for Oak and `jackrabbit-dev@…` for +this repo; they are run as one project but the codebases are +independent) that the two are independent codebases. Modelling them +separately is the more truthful representation. `jackrabbit-filevault` +also gets its own model because its trust boundary (untrusted zip +package → repository) is qualitatively different. + +## §1 Header + +- **Project:** Apache Jackrabbit (`apache/jackrabbit`) — the original / + legacy JCR implementation, distinct from Apache Jackrabbit Oak. + Includes jackrabbit-core (repository), jackrabbit-spi / + jackrabbit-spi2dav (SPI layer), jackrabbit-jcr-*, jackrabbit-webdav, + jackrabbit-jcr2dav, and the JCR API artefacts *(documented: + `README.txt`, repo top-level)*. +- **Commit / version binding:** drafted against `trunk`. A + vulnerability report against Jackrabbit version *N* should be + triaged against the model as it stood at *N* (release tag). +- **Date:** 2026-05-30. +- **Authors:** ASF Security team draft, awaiting Jackrabbit PMC review. +- **Status:** draft — under maintainer review. +- **Reporting cross-reference:** findings that may violate a §8 + property should be reported per the ASF Security Team disclosure + channel (`security@apache.org`) and the project's security mailing + list, before public disclosure. Findings under §3, §9, §11a + will be closed by Jackrabbit triagers citing this document. (The + Jackrabbit website hosts a CVE list at + `jackrabbit.apache.org/jcr/jackrabbit-security-reports.html` — + draft-time review of this URL did not produce a full enumeration + for this draft; §14 Q1 asks the PMC to confirm the CVE + history.) +- **Provenance legend:** *(documented)* — drawn from in-repo docs or + website docs with citation; *(maintainer)* — confirmed by a + Jackrabbit maintainer in response to this draft; *(inferred)* — + synthesised from code structure or domain knowledge, awaiting PMC + ratification (every *(inferred)* tag has a matching §14 question). +- **Draft confidence:** 14 documented / 0 maintainer / 32 inferred. + *(This model leans more heavily on inference than the Oak model + because jackrabbit-core's docs are older and less prescriptive + about modern security claims; many §8 properties need PMC + ratification.)* + +**About the project.** Apache Jackrabbit is "a fully conforming +implementation of the Content Repository for Java Technology API (JCR, +specified in JSR 170 and 283)" *(documented: `README.txt`)*. It +predates Apache Jackrabbit Oak and was the original JCR reference +implementation. The repository hosts: + +- **jackrabbit-core** — the legacy repository implementation (JR2 / + jackrabbit-2 storage architecture); +- **jackrabbit-spi** + **jackrabbit-spi-commons** + **jackrabbit-spi2dav** + + **jackrabbit-spi2jcr** — the SPI layer used as a bridge between + client and server when WebDAV is involved; +- **jackrabbit-jcr-commons**, **jackrabbit-jcr-server**, + **jackrabbit-jcr-tests**, **jackrabbit-jcr-client** — the JCR + client / server bindings and the JCR TCK harness; +- **jackrabbit-webdav** + **jackrabbit-jcr2dav** — WebDAV-over-JCR; +- **examples/jackrabbit-firsthops** — sample code. + +The maintenance posture is "in active maintenance, not active feature +development". Some users still run jackrabbit-2 production +repositories (especially the WebDAV-over-JCR stack) but the PMC's +forward-looking effort is on Oak *(inferred — §14 Q2)*. + +## §2 Scope and intended use + +### Intended use + +- **In-process JCR 2.0 (JSR 283) repository implementation** embedded + by a host application, *or* exposed through one of jackrabbit- + webdav / jackrabbit-jcr-server as a network + service *(documented: `README.txt`; module presence)*. Unlike Oak, + Jackrabbit *does* ship network bindings. +- **The JCR API artefacts and SPI layer** are reusable on their own + (callers depend on `javax.jcr.*` interfaces published from this + repo); they are also dependencies of Oak and of jackrabbit- + filevault. + +### Deployment shape + +Jackrabbit covers two distinct deployment shapes: + +1. **In-process JCR library** — same shape as Oak: a host application + instantiates a `Repository`, logs in, gets a `Session`, reads/writes. +2. **Network-exposed via jackrabbit-webdav + jackrabbit-jcr-server + + jackrabbit-jcr2dav** — the repository is fronted by a WebDAV + servlet; HTTP/WebDAV clients authenticate (usually via HTTP Basic + or Digest) and the servlet translates WebDAV verbs into JCR + operations. This brings authentication, HTTP parsing, and (in + 2.x) XML parsing for WebDAV bodies onto the in-model surface. + +This split is the most consequential modelling decision: the +in-process and the network-exposed deployments have different +adversary models (§7), different reachable surfaces (§4), and +different downstream responsibilities (§10). + +### Caller roles + +| Role | Trust level | Notes | +| --- | --- | --- | +| **Host application code (embedded mode)** | trusted | Holds the JCR `Repository` handle; chooses the security configuration. | +| **JCR session principal** | untrusted but authenticated | Identified via `Repository.login(Credentials)` against the configured `LoginModule`. | +| **System principal / admin user** | trusted | Default `admin`/`admin` ships with jackrabbit-core; widely cited as the "first thing to change in production" *(inferred — §14 Q3)*. | +| **WebDAV / HTTP client (network-exposed mode)** | untrusted | Reaches Jackrabbit through jackrabbit-webdav / jackrabbit-jcr-server. Carries HTTP Basic or Digest credentials. | +| **WebDAV operator / servlet container** | trusted | Configures Tomcat/Jetty, TLS, authentication realm, and chooses which JCR repository the servlet exposes. | +| **External resource referenced by WebDAV body (XML entities, etc.)** | untrusted control plane | jackrabbit-webdav historically parses XML bodies for `PROPFIND`, `LOCK`, `REPORT`; XXE-class concerns are in-model here *(inferred — §14 Q4)*. | +| **Persistence manager backend (filesystem / JDBC database)** | trusted | jackrabbit-core's persistence managers write to disk or to a relational DB the operator configures *(inferred — §14 Q5)*. | + +### Component-family table + +| Family | Representative entry | Touches outside the process? | In-model? | +| --- | --- | --- | --- | +| **JCR API artefacts** (`javax.jcr.*` published from `jackrabbit-jcr-commons`) | API surface | no | **yes** (consumer contract; almost no implementation though) | +| **jackrabbit-core** — repository implementation, JR2 persistence | `RepositoryImpl.login` | filesystem (PM, search index, data store) | **yes** | +| **jackrabbit-spi**, **jackrabbit-spi-commons**, **jackrabbit-spi2jcr**, **jackrabbit-spi2dav** | SPI bridge | depends on the SPI impl | **yes** | +| **jackrabbit-jcr-commons** | utilities | no | **yes** | +| **jackrabbit-jcr-server** | server-side glue | **yes — HTTP** | **yes** (network surface) | +| **jackrabbit-jcr-client** | client-side glue | **yes — HTTP** | **yes** for the client posture | +| **jackrabbit-webdav** | WebDAV protocol + XML handling | **yes — HTTP + XML parse** | **yes** (high security weight, XML / XXE-class) | +| **jackrabbit-jcr2dav** | WebDAV ↔ JCR adaptation | **yes — HTTP** | **yes** | +| **jackrabbit-jcr-tests** | JCR TCK | none | **out of model** — test harness *(§3)* | +| **examples/jackrabbit-firsthops** | sample app | varies | **out of model** *(§3)* | +| **jackrabbit-standalone** / **jackrabbit-standalone-components** *(inferred — §14 Q6)* | standalone server launcher | filesystem + HTTP | in-model only as a runner, not a security boundary | +| **jackrabbit-aws-ext** *(inferred — §14 Q6)* | S3 data-store extension | **yes — S3** | in-model for in-Jackrabbit code; cloud APIs trusted (§3) | + +A finding is in-model only if it lands in a row marked **yes**; see +§4 for per-component reachability tests. + +## §3 Out of scope (explicit non-goals) + +Reports requiring any of these will be closed with the cited +disposition: + +1. **Host application correctness (embedded mode) / servlet + container configuration (network mode).** Tomcat / Jetty + misconfiguration, missing TLS, missing HTTP-Basic realm — those are + operator / host issues *(inferred — §14 Q7)*. → `OUT-OF-MODEL: + adversary-not-in-scope`. +2. **Underlying persistence-manager correctness.** Jackrabbit-core's + PMs delegate to filesystem or JDBC; a hostile filesystem / hostile + database is not Jackrabbit's threat *(inferred — §14 Q5)*. → + `OUT-OF-MODEL: trusted-input`. +3. **Failing to rotate the default `admin`/`admin` user.** Documented + convention; operator responsibility *(inferred — §14 Q3)*. → + `OUT-OF-MODEL: non-default-build`. +4. **Code that ships but is not part of the supported product:** + `jackrabbit-jcr-tests/` (TCK harness), + `examples/jackrabbit-firsthops/`. → `OUT-OF-MODEL: + unsupported-component`. +5. **Issues that exist in `jackrabbit-oak`.** Oak has its own + threat model; cross-references not duplications. +6. **Issues in `jackrabbit-filevault`.** Filevault has its own + threat model. +7. **Build / release / SDLC hygiene.** Out of model per the SKILL. +8. **Java EE / J2EE container vulnerabilities** when jackrabbit-jcr- + server / jackrabbit-webdav is hosted under one. The container is + the operator's choice *(inferred — §14 Q8)*. → `OUT-OF-MODEL: + adversary-not-in-scope`. +9. **Maintenance-mode reality.** This repository is in active + maintenance for **bug** and **security** fixes but is not under + active feature development *(inferred — §14 Q2)*. A report that + "feature X would be more secure if implemented as Y" is, in + maintenance mode, more of a roadmap item than a triagable + security claim, *unless* it concerns an upgrade path to a fix. +10. **Side channels** (cache timing, JVM JIT, co-resident JVM + code). → `OUT-OF-MODEL: adversary-not-in-scope`. +11. **WebDAV semantics that the protocol requires.** WebDAV exposes + directory listing, file PUT, MOVE, COPY, etc. A complaint that + "this user can `PUT` and overwrite my file" is the JCR + authorisation model's call, not a WebDAV-layer bug. + +## §4 Trust boundaries and data flow + +Jackrabbit has up to six trust transitions a finding must land +inside to be in-model: + +| # | Transition | Authentication | Authorisation | +| --- | --- | --- | --- | +| B1 | Host code → `Repository.login(Credentials)` (embedded mode) | configured `LoginModule` chain via JAAS | `AccessManager` returned by the security configuration *(inferred — §14 Q9)* | +| B2 | HTTP client → jackrabbit-webdav (network mode) | HTTP Basic / Digest at the servlet layer | per-JCR-session, post-translation | +| B3 | JCR session principal → tree read | `Subject` established at B1/B2 | jackrabbit-core's `AccessManager` | +| B4 | JCR session principal → tree write | same | `AccessManager` evaluated on `Session.save()` | +| B5 | Jackrabbit → persistence manager (filesystem / JDBC) | backend-configured | backend ACLs | +| B6 | jackrabbit-webdav body parse | none (request body bytes) | n/a; the XML parser must be configured safely (XXE-class) *(inferred — §14 Q4)* | + +### Reachability preconditions per family + +A finding is in-model only if it meets the family's reachability test: + +- **jackrabbit-core**: reachable from a JCR session at B1 / B2 + with the principal carrying *less than* admin authority. +- **jackrabbit-webdav**: reachable from an HTTP request body or + header. XML-parse vulnerabilities (XXE, XML entity expansion, + DTDs) are in-model here; the WebDAV bodies are the highest- + blast-radius input on the network surface *(inferred — §14 Q4)*. +- **jackrabbit-jcr-server**: in-model for the request-routing and + authentication glue. +- **jackrabbit-spi**: in-model for the SPI bridge's own logic; the + underlying SPI implementation is per-deployment trusted. +- **jackrabbit-aws-ext** (S3 data store): in-model for in-Jackrabbit + code paths; the S3 backend itself is trusted. +- **examples / TCK**: out (§3 item 4). + +## §5 Assumptions about the environment + +- **Java 11+** at HEAD; Maven 3 build *(documented: `README.txt`)*. + JVM-conformant runtime; no SecurityManager required. +- **Servlet container** (Tomcat / Jetty) when running in network + mode. The container handles connection management, TLS, and + often HTTP Basic / Digest realms. +- **Persistence**. jackrabbit-core uses one of several PMs (bundle + PM, ObjectPersistenceManager, database PMs); each writes to a + filesystem directory or a JDBC database the operator configures + *(inferred — §14 Q5)*. +- **Data store**. jackrabbit-core can use the FileDataStore (local + files) or extensions (jackrabbit-aws-ext for S3); operator- + configured trusted *(inferred — §14 Q5)*. +- **Search**. Lucene-based search index on the filesystem under the + repository home. +- **Time** — `System.currentTimeMillis` for lock timeouts and + observation event timestamps; clock skew internal-only. +- **What Jackrabbit does NOT do to its host** *(predominantly + negative — §14 Q10)*: + - opens listening sockets *only* through jackrabbit-jcr-server + when it is deployed (in pure-library mode, none); + - installs **no** process-wide signal handlers; + - spawns **no** child processes from the core; + - reads system properties (`jackrabbit.*`, etc.) but not + arbitrary `LD_*` for security-relevant decisions; + - writes log entries through `slf4j`. + +## §5a Build-time and configuration variants + +| Knob / configuration | Default | Maintainer stance | Effect | +| --- | --- | --- | --- | +| `repository.xml` `Security` element — `LoginModule`, `AccessManager`, `WorkspaceAccessManager` | jackrabbit defaults (e.g. `SimpleSecurityManager` + `DefaultLoginModule` + `AccessManagerImpl`) *(inferred — §14 Q9)* | required for any meaningful security; misconfiguration voids §8 P1–P3 | what auth + authz Jackrabbit applies | +| Default `admin`/`admin` user | exists, full repository access *(inferred — §14 Q3)* | operator must rotate before production | `BY-DESIGN`; see §3 item 3 | +| jackrabbit-webdav exposure | not exposed unless the operator deploys it | deploying it brings network attack surface in-scope (B2/B6) | network mode trades library posture for service posture | +| XML parser configuration in jackrabbit-webdav | depends on JAXP defaults at the JVM level | **maintainer ruling required**: does jackrabbit-webdav harden its `DocumentBuilderFactory` against XXE / DTD / external-entity expansion, or does it rely on JVM defaults? *(inferred — §14 Q4)* | XXE-class behaviour | +| HTTP Basic vs Digest in jackrabbit-jcr-server | configurable | Digest preferred; Basic-without-TLS is a §11 misuse | which auth mechanism is on the WebDAV port | +| FileDataStore directory permissions | operator-controlled | operator responsibility | binary content readability | +| Persistence manager (bundle / object / database) | bundle PM is the common default *(inferred — §14 Q5)* | operator choice; all are trusted as backends | the choice changes nothing in the security envelope | +| `jackrabbit-aws-ext` S3 data store | optional | when enabled, S3 backend trust applies (§3 item 2) | cloud blob storage | +| Anonymous read (some `JCRRepositoryFactory` configs allow guest login) | configurable | maintainer ruling: is anonymous read a supported posture or a dev-time default? *(inferred — §14 Q11)* | whether `Repository.login(null, ws)` succeeds | + +**The insecure-default case.** The single most load-bearing knob is the +default `admin`/`admin` user. The model assumes the operator's posture +is "rotate or remove before production" — i.e. failing to rotate is +`OUT-OF-MODEL: non-default-build`. PMC must ratify this in §14 Q3. + +## §6 Assumptions about inputs + +### Per-entry-point trust table (in-process API + network) + +| Entry point | Parameter | Attacker-controllable in the model? | Caller must enforce | +| --- | --- | --- | --- | +| `Repository.login(Credentials)` | `Credentials` | **yes** (untrusted) | configured `LoginModule` does the work | +| `Session.getNode/Property(path)` | path | **yes** via the authenticated user, filtered through `AccessManager` | nothing | +| `Session.save()` | accumulated transient changes | **yes** via the authenticated user | nothing | +| `QueryManager.createQuery(stmt, lang)` | SQL2 / XPath / SQL1 | **yes** | Jackrabbit parses + plans + filters | +| `AccessControlManager.setPolicy` | policy bytes | only by callers with the right privileges | Jackrabbit gates | +| WebDAV `PROPFIND` request body | XML | **yes** (HTTP-network input) | per §5a, the XML parser must be hardened (XXE) *(inferred — §14 Q4)* | +| WebDAV `LOCK`, `REPORT` request bodies | XML | **yes** | same | +| WebDAV `PUT` body | bytes | **yes** | binary into a JCR property/binary value | +| WebDAV `MOVE`, `COPY` Destination header | URL | **yes** | parsed; URL-decoded path may not contain `..` after decode | +| WebDAV `If` header | conditional state | **yes** | parsed | +| HTTP Basic / Digest credentials | bytes | **yes** | configured by `jackrabbit-jcr-server` | +| Persistence-manager bytes | DB rows / filesystem bytes | **no** — backend is trusted | none | + +### Size / shape / rate + +- WebDAV / JCR-server accept arbitrary-length request bodies subject to + the servlet container's limits *(inferred — §14 Q12)*. +- Jackrabbit core imposes no enforced cap on tree depth, child + count, or query complexity *(inferred — §14 Q12)*. +- Lucene full-text query parsing is unbounded by default; a + pathological query can burn CPU *(inferred — §14 Q12)*. **No DoS + protection by default.** + +## §7 Adversary model + +### Actors + +| Actor | In scope? | Capabilities granted | +| --- | --- | --- | +| Authenticated end-user session (limited privileges) | **yes** | read/write the tree under JCR privileges; submit SQL2/XPath queries | +| Authenticated end-user session (broad privileges, non-admin) | partial | only privilege-envelope escapes are in scope | +| Unauthenticated HTTP / WebDAV peer reaching the network port | **yes** (when deployed) | TCP connect; HTTP requests; XML body parse; HTTP Basic/Digest auth attempts | +| Authenticated WebDAV client (HTTP Basic/Digest) | **yes** | same as authenticated JCR session via WebDAV translation | +| Cross-session adversary (one JCR session influencing another) | **yes** | through `AccessManager` cache or commit-hook side effects | +| Hostile persistence-manager backend (DB, FS) | **out of scope** — §3 item 2 | +| Hostile servlet container / operator | **out of scope** — §3 item 1 | +| Hostile XXE-supplying WebDAV body | **yes** (when WebDAV exposed) — *the* main XML-parse adversary | +| Same-JVM attacker code | **partial** — host's container is the boundary *(inferred — §14 Q13)* | +| Side-channel observer | **out of scope** *(§14 Q14)* | +| Quantum adversary | **out of scope** | + +The model does **not** include "authenticated-but-Byzantine peer" +(there is no consensus / replication in jackrabbit-core). + +## §8 Security properties the project provides + +### P1 — Authentication of JCR sessions through the configured `LoginModule` chain (embedded mode) + +- **Condition.** `repository.xml` `Security` element defines a + `LoginModule`; `Repository.login` invokes the configured JAAS chain. +- **Violation symptom.** A `Repository.login` call returns a `Session` + for credentials the configured chain should have rejected. +- **Severity.** Security-critical (`VALID`). +- *(inferred — §14 Q9)* + +### P2 — Authorisation of reads through `AccessManager` + +- **Condition.** Non-admin principal session; default `AccessManager` + configured. +- **Violation symptom.** `Session.getNode(path)` returns an item the + configured ACLs do not license. +- **Severity.** Security-critical (`VALID`). +- *(inferred — §14 Q9)* + +### P3 — Authorisation of writes through `AccessManager` on commit + +- **Condition.** Non-admin principal session; default `AccessManager`. +- **Violation symptom.** A `Session.save()` commits a change the + ACLs do not license. +- **Severity.** Security-critical (`VALID`). +- *(inferred — §14 Q9)* + +### P4 — HTTP Basic / Digest authentication at the WebDAV servlet boundary (network mode) + +- **Condition.** `jackrabbit-jcr-server` deployed; HTTP Basic or + Digest realm configured; the servlet container honours the realm. +- **Violation symptom.** A WebDAV request without valid credentials + reaches B2 trust transitions. +- **Severity.** Security-critical (`VALID`). + +### P5 — TLS confidentiality / integrity at the network surface (when configured) + +- **Condition.** Servlet container (Tomcat/Jetty) configured for + HTTPS; jackrabbit-webdav does not strip TLS. +- **Violation symptom.** Cleartext on the wire after TLS is + configured. +- **Severity.** Security-critical (`VALID`). +- *(inferred — §14 Q15)* + +### P6 — XML safety of jackrabbit-webdav body parses + +- **Condition.** `DocumentBuilderFactory` configured to disable + external entities, disallow DOCTYPEs (or restrict them safely), and + cap entity expansion. +- **Violation symptom.** A WebDAV body triggers XXE (file read, + SSRF), Billion-Laughs, or DTD-based remote-fetch. +- **Severity.** Security-critical (`VALID`) when reachable from an + unauthenticated or low-privilege HTTP peer. +- *(inferred — §14 Q4; this is the single highest-confidence-required + property for the network-exposed deployment)* + +### P7 — `Session` per-thread isolation and MVCC-like read consistency + +- **Condition.** Default jackrabbit-core MVCC layer; one `Session` per + thread. +- **Violation symptom.** Cross-session data leakage; a session reading + data committed after its login without an intentional refresh. +- **Severity.** Correctness by default; security-critical iff + cross-session leakage crosses an ACL boundary. +- *(inferred — §14 Q16)* + +### P8 — Memory safety of safe-Java core + +- **Condition.** JVM semantics; no `Unsafe` use in the core security + paths. +- **Violation symptom.** OOB / UAF / data race observable. +- **Severity.** Security-critical when reachable from §6 input. +- *(inferred — §14 Q17)* + +## §9 Security properties the project does NOT provide + +### 9.1 No defence against the host application / operator + +`SimpleCredentials("admin","admin")` always works against default +config. If the host hands those out, the host has lost. *(inferred — +§14 Q3)* + +### 9.2 No defence against a malicious persistence-manager backend + +JDBC / FileDataStore / FS / S3 are all trusted. *(inferred — +§14 Q5)* + +### 9.3 No defence against a malicious servlet-container operator + +Tomcat / Jetty operator owns the realm, the TLS posture, and the +deployment descriptor. *(inferred — §14 Q1)* + +### 9.4 No DoS protection against authenticated callers + +No enforced cap on query complexity, tree depth, child count, +transient state per session, or WebDAV body size. *(inferred — +§14 Q12)* + +### 9.5 No XXE / DTD / external-entity protection in WebDAV bodies (subject to confirmation) + +§8 P6 is the inverse — this is the disclaimer if §14 Q4 reveals +that jackrabbit-webdav does *not* harden its parser. + +### 9.6 No data-at-rest encryption at the Jackrabbit layer + +Delegated to PM / data-store backend. + +### 9.7 No constant-time comparison of authentication secrets + +Beyond what `LoginModule` / JCA helpers provide. *(inferred — +§14 Q18)* + +### 9.8 No defender stance against `loginAdministrative`-equivalent host paths + +If jackrabbit's `SimpleSecurityManager` was configured to grant +admin to any subject, that's the configuration speaking, not a bug. + +### False-friend properties (call out separately) + +- **Default `admin`/`admin` is *not* a deployed-by-default backdoor + — it is documented; the operator is expected to rotate.** Whether + failing to do so is `VALID` Jackrabbit or `OUT-OF-MODEL` + operator-config is §14 Q3. +- **HTTP Basic without TLS is *not* secure authentication.** + Credentials are base64 in cleartext. +- **HTTP Digest is *not* TLS substitute.** It protects the password + in transit, not the *content*. +- **WebDAV `LOCK` is an advisory locking primitive, not access + control.** A holder of `LOCK` does not become an authoriser. + +### Well-known attack classes the project does not defend against + +- **XXE / Billion-Laughs / DTD-fetch via WebDAV bodies** — *(inferred + — §14 Q4)*. +- **Authenticated-DoS** (pathological queries / tree shapes) — + §9.4. +- **HTTP Basic over plaintext** when `jackrabbit-jcr-server` is + exposed without TLS — `OUT-OF-MODEL: non-default-build` or + operator misconfiguration. +- **TOCTOU between ACL evaluation and tree write** — *(inferred — + §14 Q16)*. + +## §10 Downstream responsibilities + +The host application (and, in network mode, the operator) MUST: + +1. **Rotate or remove the default `admin`/`admin` user** before + exposing the repository to any non-trusted caller *(inferred — + §14 Q3)*. +2. **Configure a `LoginModule` and an `AccessManager`** that match + the production trust posture. The shipped defaults are intended + for demos. +3. **Wrap `jackrabbit-jcr-server` / jackrabbit-webdav with TLS** + (servlet container HTTPS). HTTP Basic over plaintext is not + acceptable production posture *(inferred — §14 Q15)*. +4. **Harden the XML parser configuration** if `jackrabbit-webdav` is + exposed (XXE, DTD, external-entity, billion-laughs) + *(inferred — §14 Q4)*. +5. **Apply admission control / rate limits** at the servlet + container / reverse-proxy layer; Jackrabbit does not. +6. **Restrict OS filesystem permissions** on `repository.home`, + persistence-manager directories, data-store directories, search + index, and any keystores. +7. **Track CVE advisories on this repo.** Maintenance-mode posture + means the security mailing list is the right channel for + reports; binary patches are not produced per Apache convention. +8. **Plan migration to Oak** if the deployment is greenfield or if + bug-fixes diverge — Oak is the active codebase *(inferred — + §14 Q2)*. + +## §11 Known misuse patterns + +- **Failing to rotate default `admin`/`admin`** before production. +- **Deploying jackrabbit-jcr-server / jackrabbit-webdav without + TLS.** HTTP Basic over plaintext is the default if the operator + does not flip a switch. +- **Exposing the WebDAV port directly without an authentication + realm.** WebDAV has no built-in auth; the servlet container does. +- **Treating Jackrabbit as the active codebase and not Oak.** For + greenfield deployments, Oak is the active product. +- **Using the SQL1 query language without auditing what callers can + submit.** SQL1 is more permissive than SQL2 / XPath. +- **WebDAV `PROPFIND` `Depth: infinity` against the root** — a + documented amplification vector for any WebDAV-fronted store + *(inferred — §14 Q12)*. +- **WebDAV `MOVE` / `COPY` with a `Destination` header pointing + outside the configured workspace.** ACL-bounded; the configured + ACL is the gate. + +## §11a Known non-findings (recurring false positives) + +- **"Default `admin`/`admin` user exists in the shipped + configuration."** Documented; operator must rotate per §10. → + `OUT-OF-MODEL: non-default-build` (subject to §14 Q3). +- **"HTTP Basic credentials sent in cleartext when + `jackrabbit-jcr-server` is exposed over HTTP."** Operator must + enable TLS *(inferred — §14 Q15)*. → `OUT-OF-MODEL: + non-default-build`. +- **"DoS via pathological SQL2 / XPath query."** No engine-level + cap *(inferred — §14 Q12)*. → `BY-DESIGN: property-disclaimed`. +- **"Hardcoded test password / keystore in + `examples/jackrabbit-firsthops/`, `jackrabbit-jcr-tests/`."** + Unsupported components. → `OUT-OF-MODEL: unsupported-component`. +- **"Tomcat / Jetty configuration weakness."** Container is the + operator's. → `OUT-OF-MODEL: adversary-not-in-scope`. +- **"Vulnerability X exists only in jackrabbit-oak."** Oak's + threat model and triage queue. → `OUT-OF-MODEL: + unsupported-component` (cross-reference Oak model). +- **"Vulnerability X exists only in jackrabbit-filevault."** + Filevault's threat model. → `OUT-OF-MODEL: + unsupported-component` (cross-reference filevault model). +- **"`PROPFIND Depth: infinity` is amplification."** WebDAV + protocol semantics; ACL-bounded. +- **"Authenticated user with `MODIFY_ACCESS_CONTROL` rewrote ACL to + grant self more privileges."** Documented privilege behaviour. → + `BY-DESIGN: property-disclaimed`. + +## §12 Conditions that would change this model + +- A new network listener in jackrabbit (currently only via + jackrabbit-jcr-server / jackrabbit-webdav when deployed). +- A change in the shipped default `LoginModule` / `AccessManager`. +- A change in the shipped default `admin`/`admin` posture + (e.g. randomised on first start). +- A change in jackrabbit-webdav's XML parser default hardening. +- A change in the project's maintenance posture (return to active + feature development). +- A vulnerability report that cannot be cleanly routed to one of the + §13 dispositions — that is evidence the model is incomplete. + +## §13 Triage dispositions + +A report against Jackrabbit receives exactly one of: + +| Disposition | Meaning | Licensed by | +| --- | --- | --- | +| `VALID` | Violates a §8 property via an in-scope §7 adversary using an in-scope §6 input. | §8, §6, §7 | +| `VALID-HARDENING` | No §8 violation, but a §11 misuse pattern can be made harder. Typically no CVE. | §11 | +| `OUT-OF-MODEL: trusted-input` | Requires attacker control of a §6 parameter the model marks trusted. | §6 | +| `OUT-OF-MODEL: adversary-not-in-scope` | Requires a §7 actor the model excludes. | §7 | +| `OUT-OF-MODEL: unsupported-component` | Lands in `jackrabbit-jcr-tests/`, `examples/`, or in Oak / filevault. | §3 | +| `OUT-OF-MODEL: non-default-build` | Manifests only under a discouraged or non-default §5a value (un-rotated `admin`, HTTP Basic without TLS). | §5a | +| `BY-DESIGN: property-disclaimed` | Concerns a §9 property the project explicitly does not provide. | §9 | +| `KNOWN-NON-FINDING` | Matches a §11a recurring false positive. | §11a | +| `MODEL-GAP` | Cannot be cleanly routed to any of the above — triggers §12 model revision. | §12 | + +## §14 Open questions for the maintainers + +### Wave 1 — scope, posture, defaults + +**Q1.** Confirm or correct the CVE inventory and the project's +disclosure history page at +`https://jackrabbit.apache.org/jcr/jackrabbit-security-reports.html`. +Specifically: what CVEs have been issued against jackrabbit-core / +jackrabbit-webdav in the last 5 years, and which patterns recur in +inbound reports that you close as not-a-bug? +*(maps to §1 reporting, §11a)* + +**Q2.** Maintenance posture. Proposed: "active for bug + security +fixes; not active for feature development; Oak is the recommended +codebase for new deployments". Confirm or correct. *(maps to +§3 item 9, §10 item 8)* + +**Q3.** The default `admin`/`admin` user. Proposed disposition for +"deployment X has not rotated the default `admin`": +`OUT-OF-MODEL: non-default-build`. Confirm — or has the project +moved to randomised first-start? *(maps to §5a, §10 item 1, +§11a)* + +**Q4.** **The XXE question.** Does `jackrabbit-webdav` ship +hardened XML parser configuration (disable external entities, +disallow DOCTYPE, cap entity expansion) for `PROPFIND`, `LOCK`, +`REPORT` body parsing? This is the highest-leverage single question +for the network-exposed deployment. If not, §8 P6 collapses into +§9.5 and §10 item 4 becomes a hard production requirement. +*(maps to §4 B6, §6 WebDAV rows, §8 P6, §9.5)* + +### Wave 2 — backends, environment + +**Q5.** Are persistence-manager backends (FileDataStore, bundle PM, +database PMs, S3 via jackrabbit-aws-ext) all modelled as trusted +backends — i.e. Jackrabbit does not defend against a malicious +backend? Proposed: yes. *(maps to §3 item 2, §9.2)* + +**Q6.** Module inventory: confirm or correct the list of supported +modules vs unsupported / sample / TCK / extension modules. In +particular: is `jackrabbit-standalone` / `jackrabbit-standalone-components` +still part of the repo (the README didn't reach it); is +`jackrabbit-aws-ext` an in-tree module or a separate artefact? *(maps +to §2 component family)* + +**Q7.** Servlet-container responsibility: confirmed that Tomcat / +Jetty configuration (TLS, HTTP Basic / Digest realm, request body +size caps, request timeouts) is out-of-model and the operator's +responsibility? *(maps to §3 item 1)* + +**Q8.** Java EE container vulnerabilities: confirmed out-of-model? +*(maps to §3 item 8)* + +### Wave 3 — `AccessManager`, login + +**Q9.** What is the *default* `LoginModule` / `AccessManager` in +the shipped `repository.xml` of jackrabbit-core? The §8 P1–P3 +properties hinge on this configuration; this draft uses generic +"configured `LoginModule` / `AccessManager`" placeholders. Please +state the concrete default class names and the JAAS app-name they +register under. *(maps to §5a, §8 P1–P3)* + +### Wave 4 — environment, MVCC, memory safety + +**Q10.** "What Jackrabbit does NOT do to its host" inventory: no +process-wide signal handlers, no child process spawn (outside +network-mode servlet container), no arbitrary `LD_*` consumption, +no on-disk persistence outside `repository.home`. Confirm any +inaccuracies. *(maps to §5)* + +**Q11.** Anonymous read posture. Is `Repository.login(null, ws)` +(guest login without credentials) supported in any default +configuration, or is it always disabled by default? *(maps to +§5a, §6, §7 unauthenticated row)* + +**Q12.** WebDAV / JCR / Lucene resource bounds. Confirmed that +Jackrabbit imposes **no** enforced cap on: +- WebDAV request body size beyond servlet container limits; +- JCR query complexity (Lucene-based); +- tree depth / child count; +- transient session state; +- `PROPFIND Depth: infinity` cost? + +If correct, all of these belong in §9.4 / §11a as `BY-DESIGN: +property-disclaimed`. *(maps to §6, §9.4)* + +**Q13.** Same-JVM attacker code (co-installed servlet, OSGi bundle, +servlet container's other webapps): confirmed out-of-model? The +host container is the security boundary. *(maps to §7, §9)* + +**Q14.** Side-channel adversaries: confirmed out-of-model? *(maps +to §3 item 10, §7, §9)* + +**Q15.** TLS: confirmed that TLS is **always** the servlet +container's job in network mode, never Jackrabbit's? *(maps to +§8 P5)* + +**Q16.** MVCC visibility: how does jackrabbit-core handle +cross-session refresh? Proposed: session reads the revision +captured at login, refreshable via `Session.refresh`. Confirm. +*(maps to §8 P7)* + +**Q17.** Memory safety of safe-Java: confirmed that the core +security paths use no `Unsafe` / JNI? *(maps to §8 P8)* + +**Q18.** Constant-time comparison of authentication secrets: +confirmed all delegated to JAAS / `LoginModule` / JCA, with no +Jackrabbit-internal `equals` on secrets? *(maps to §9.7)* + +### Wave 5 — meta + +**Q19.** Should this document live as `docs/threat-model.md` or +under `jackrabbit-jcr-commons/src/site/markdown/`? *(meta)* + +**Q20.** Is there an existing Jackrabbit threat-model document +(Confluence, JIRA, mailing-list summary, prior PMC discussion) that +this should reconcile with rather than supersede? *(meta — §3.1a)* + +**Q21.** §11a known-non-findings is currently 9 entries, mostly +operator-misconfiguration-shaped. Could the PMC contribute 3–5 +patterns the Jackrabbit triage queue sees recur in inbound reports +that you close as not-a-bug? Patterns like "WebDAV exposed without +TLS — operator misconfig, not Jackrabbit" and "DoS via huge +PROPFIND Depth-infinity — WebDAV semantics" would harden §11a +substantially. *(meta — §11a)* + +**Q22.** Should this Jackrabbit model cross-reference the (still-to- +be-drafted) `jackrabbit-oak` and `jackrabbit-filevault` models for +items §3 items 5–6? *(meta)* + +--- + +## Appendix: Existing security artefact → §x back-map + +Jackrabbit does not currently ship an in-repo `SECURITY.md`. The +de-facto security-policy artefacts are: + +- the website page + `https://jackrabbit.apache.org/jcr/jackrabbit-security-reports.html` + (CVE history; not fully readable at draft time — §14 Q1); +- the `README.txt` at the top level (project description, + Java / Maven requirements); +- the `.asf.yaml` (which routes notifications to + `jackrabbit-dev@…`). + +The back-map is sparse because the existing artefacts are mostly +process-only: + +| Source | Claim | Lands in | +| --- | --- | --- | +| `README.txt` | "fully conforming implementation of JCR (JSR 170 and 283)" | §2 intended use | +| `README.txt` | Java 11+, Maven 3 build | §5 | +| website security-reports page | CVE history (to be enumerated — §14 Q1) | §1 reporting cross-ref, §11a | +| `.asf.yaml` | notifications routed to `jackrabbit-dev@…` | §1 | diff --git a/jackrabbit-aws-ext/pom.xml b/jackrabbit-aws-ext/pom.xml index 723b82d0889..36b2dd44539 100644 --- a/jackrabbit-aws-ext/pom.xml +++ b/jackrabbit-aws-ext/pom.xml @@ -20,7 +20,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-aws-ext @@ -49,7 +49,7 @@ com.amazonaws aws-java-sdk-s3 - 1.12.730 + 1.12.791 org.apache.jackrabbit @@ -61,6 +61,7 @@ jackrabbit-data ${project.version} test-jar + test org.slf4j diff --git a/jackrabbit-core/pom.xml b/jackrabbit-core/pom.xml index 9ae65ce2d36..dfe031315d8 100644 --- a/jackrabbit-core/pom.xml +++ b/jackrabbit-core/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-core @@ -116,6 +116,11 @@ org.apache.jackrabbit.test.api.query.qom.NodeLocalNameTest#testPathLiteral org.apache.jackrabbit.test.api.query.qom.NodeLocalNameTest#testURILiteral org.apache.jackrabbit.core.version.ModifyNonVersionableCheckedOutTest#testNonVersionableCheckedOut org.apache.jackrabbit.core.version.ModifyNonVersionableCheckedOutTest#testModifyNonVersionableNodeWithCheckedOutProperty +org.apache.jackrabbit.core.AddMoveTest#testTopLevelAddRemove +org.apache.jackrabbit.core.config.SecurityConfigTest#testInvalidConfig +org.apache.jackrabbit.core.nodetype.CyclicNodeTypeRegistrationTest +org.apache.jackrabbit.core.query.lucene.SearchIndexConsistencyCheckTest#testDoubleCheckStressTest +org.apache.jackrabbit.core.version.RemoveAndAddVersionLabelXATest#testVersionLabel @@ -228,9 +233,9 @@ org.apache.jackrabbit.core.version.ModifyNonVersionableCheckedOutTest#testModify commons-io - commons-dbcp - commons-dbcp - 1.4 + org.apache.commons + commons-dbcp2 + 2.14.0 javax.jcr @@ -332,7 +337,7 @@ org.apache.jackrabbit.core.version.ModifyNonVersionableCheckedOutTest#testModify com.h2database h2 - 2.2.224 + 2.4.240 test @@ -357,7 +362,7 @@ org.apache.jackrabbit.core.version.ModifyNonVersionableCheckedOutTest#testModify Note: the ${config.db.name} database is dropped and re-created in the clean phase. --> - + mssql @@ -443,13 +448,13 @@ org.apache.jackrabbit.core.version.ModifyNonVersionableCheckedOutTest#testModify org.codehaus.mojo sql-maven-plugin - + net.sourceforge.jtds jtds @@ -541,13 +546,13 @@ org.apache.jackrabbit.core.version.ModifyNonVersionableCheckedOutTest#testModify - + net.sourceforge.jtds jtds diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/HierarchyManager.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/HierarchyManager.java index 7ba4245b5a0..f5b3c222ae5 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/HierarchyManager.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/HierarchyManager.java @@ -49,6 +49,7 @@ public interface HierarchyManager { * if there's no item at path. * @throws RepositoryException if an error occurs */ + @Deprecated ItemId resolvePath(Path path) throws RepositoryException; /** diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java index dbd40a4c8c1..322e9d699c7 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java @@ -467,6 +467,7 @@ private boolean canRead(ItemData parent, ItemId childId) throws RepositoryExcept * @param path path to the item to be checked * @return true if the specified item exists */ + @Deprecated public boolean itemExists(Path path) { try { sanityCheck(); @@ -544,6 +545,7 @@ NodeImpl getRootNode() throws RepositoryException { * @throws AccessDeniedException * @throws RepositoryException */ + @Deprecated public ItemImpl getItem(Path path) throws PathNotFoundException, AccessDeniedException, RepositoryException { ItemId id = hierMgr.resolvePath(path); diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java index 3519d9211d6..7f59ef4bb56 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java @@ -565,6 +565,7 @@ protected synchronized NodeImpl createChildNode(Name name, * @throws RepositoryException * @deprecated use #renameChildNode(NodeId, Name, boolean) */ + @Deprecated protected void renameChildNode(Name oldName, int index, NodeId id, Name newName) throws RepositoryException { @@ -3072,6 +3073,7 @@ public boolean isLocked() throws RepositoryException { * @throws RepositoryException if some other error occurs * @deprecated */ + @Deprecated protected void checkLock() throws LockException, RepositoryException { if (isNew()) { // a new node needs no check diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java index ce105bb7656..95e94d8f7e4 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java @@ -22,8 +22,6 @@ import java.io.OutputStream; import java.io.StringReader; import java.nio.charset.StandardCharsets; -import java.security.AccessControlContext; -import java.security.AccessController; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -80,6 +78,7 @@ import org.apache.jackrabbit.core.gc.GarbageCollector; import org.apache.jackrabbit.core.id.NodeId; import org.apache.jackrabbit.core.id.NodeIdFactory; +import org.apache.jackrabbit.core.jdkcompat.Java23Subject; import org.apache.jackrabbit.core.lock.LockManager; import org.apache.jackrabbit.core.lock.LockManagerImpl; import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry; @@ -1025,8 +1024,7 @@ private Session extendAuthentication(String workspaceName) Subject subject = null; try { - AccessControlContext acc = AccessController.getContext(); - subject = Subject.getSubject(acc); + subject = Java23Subject.getSubject(); } catch (SecurityException e) { log.warn("Can't check for preauthentication. Reason: {}", e.getMessage()); } diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SearchManager.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SearchManager.java index 05cd8fc4099..f98a9e2092c 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SearchManager.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SearchManager.java @@ -431,7 +431,7 @@ public NodeState next() { protected AbstractQueryImpl createQueryInstance() throws RepositoryException { try { String queryImplClassName = handler.getQueryClass(); - Object obj = Class.forName(queryImplClassName).newInstance(); + Object obj = Class.forName(queryImplClassName).getDeclaredConstructor().newInstance(); if (obj instanceof AbstractQueryImpl) { return (AbstractQueryImpl) obj; } else { diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java index 7a6dfd59a74..d413a245c81 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java @@ -738,6 +738,43 @@ public Node getNodeOrNull(String absPath) throws RepositoryException { } } + private static boolean isValidNamespaceName(String namespace) { + // the empty namespace and "internal" are valid as well, otherwise it always contains a colon (as it is a URI) + // compare with RFC 3986, Section 3 (https://datatracker.ietf.org/doc/html/rfc3986#section-3) + return namespace.isEmpty() || namespace.equals(Name.NS_REP_URI) || namespace.contains(":"); + } + + @Override + public String getExpandedName(Item item) throws RepositoryException { + String name = item.getName(); + int pos = name.indexOf(":"); + if (pos > 0) { + String prefix = name.substring(0, pos); + String uri = getNamespaceURI(prefix); + if (!isValidNamespaceName(uri)) { + throw new NamespaceException("Cannot determine expanded name for '" + name + + "' as registered namespace name '" + uri + "' is invalid"); + } + return "{" + uri + "}" + name.substring(pos + 1); + } + else { + return "{}" + name; + } + } + + @Override + public String getExpandedPath(Item item) throws RepositoryException { + StringBuilder result = new StringBuilder(); + String name; + do { + result.insert(0, "/" + getExpandedName(item)); + item = item.getParent(); + name = item.getName(); + // walk up to the root + } while (!name.isEmpty()); + return result.toString(); + } + //--------------------------------------------------------------< Session > /** * {@inheritDoc} diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/LockRecord.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/LockRecord.java index e29c3cf7f96..94dd49ca128 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/LockRecord.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/LockRecord.java @@ -166,6 +166,7 @@ public boolean isDeep() { * @return user id * @deprecated User {@link #getOwner()} instead. */ + @Deprecated public String getUserId() { return lockOwner; } diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java index 7801c01dacd..d0c78d61793 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java @@ -933,6 +933,7 @@ public FileSystem getFileSystem() throws RepositoryException { * @return repository name * @deprecated Use {@link SecurityConfig#getAppName()} instead. */ + @Deprecated public String getAppName() { return sec.getAppName(); } @@ -943,6 +944,7 @@ public String getAppName() { * @return access manager configuration * @deprecated Use {@link SecurityConfig#getAccessManagerConfig()} instead. */ + @Deprecated public AccessManagerConfig getAccessManagerConfig() { return sec.getAccessManagerConfig(); } @@ -954,6 +956,7 @@ public AccessManagerConfig getAccessManagerConfig() { * JAAS mechanism should be used. * @deprecated Use {@link SecurityConfig#getLoginModuleConfig()} instead. */ + @Deprecated public LoginModuleConfig getLoginModuleConfig() { return sec.getLoginModuleConfig(); } diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SimpleBeanFactory.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SimpleBeanFactory.java index d81230003f1..56dd2daa1bc 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SimpleBeanFactory.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SimpleBeanFactory.java @@ -17,6 +17,8 @@ package org.apache.jackrabbit.core.config; +import java.lang.reflect.InvocationTargetException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,12 +41,12 @@ public Object newInstance(Class klass, BeanConfig config) throws Configuratio } // Instantiate the object using the default constructor - return objectClass.newInstance(); + return objectClass.getDeclaredConstructor().newInstance(); } catch (ClassNotFoundException e) { throw new ConfigurationException( "Configured bean implementation class " + cname + " was not found.", e); - } catch (InstantiationException e) { + } catch (InstantiationException|IllegalArgumentException|InvocationTargetException|NoSuchMethodException|SecurityException e) { throw new ConfigurationException( "Configured bean implementation class " + cname + " can not be instantiated.", e); diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/db/JNDIDatabaseFileSystem.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/db/JNDIDatabaseFileSystem.java index 7d21a066fe5..93eb6698c0d 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/db/JNDIDatabaseFileSystem.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/db/JNDIDatabaseFileSystem.java @@ -35,6 +35,7 @@ * for the entire lifetime of the file system instance. The configured data * source should be prepared for this. */ +@Deprecated public class JNDIDatabaseFileSystem extends DatabaseFileSystem { /** diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jdkcompat/Java23Subject.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jdkcompat/Java23Subject.java new file mode 100644 index 00000000000..95ea967ee8d --- /dev/null +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jdkcompat/Java23Subject.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package org.apache.jackrabbit.core.jdkcompat; + +import javax.security.auth.Subject; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.util.concurrent.Callable; + +/** + * This class contains methods replacing the deprecated + * {@link Subject#getSubject(AccessControlContext)} + * and associated methods, which changed their behavior + * with Java 23 (@see https://inside.java/2024/07/08/quality-heads-up). + *

+ * Subset borrowed from org.apache.jackrabbit.oak.commons.jdkcompat + * (see JCR-5121 and OAK-11199). + */ +public class Java23Subject { + + static Method current; + + static { + try { + current = Subject.class.getMethod("current"); + } catch (NoSuchMethodException ignored) {} + } + + public static Subject getSubject() { + Subject result; + if (current != null) { + try { + result = (Subject) current.invoke(null); + } catch (InvocationTargetException | IllegalAccessException e) { + throw new SecurityException(e); + } + } else { + result = Subject.getSubject(AccessController.getContext()); + } + return result; + } +} diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jndi/RegistryHelper.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jndi/RegistryHelper.java index 5a8e406ce17..6784a70e2a1 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jndi/RegistryHelper.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jndi/RegistryHelper.java @@ -25,6 +25,8 @@ import org.apache.jackrabbit.api.JackrabbitRepository; +import static org.apache.jackrabbit.commons.JndiRepositoryFactory.JNDI_ENABLED; + /** * JNDI helper functionality. This class contains static utility * methods for binding and unbinding Jackrabbit repositories to and @@ -59,24 +61,28 @@ public static void registerRepository(Context ctx, String name, String repHomeDir, boolean overwrite) throws NamingException, RepositoryException { - Reference reference = new Reference( - Repository.class.getName(), - BindableRepositoryFactory.class.getName(), - null); // no classpath defined - reference.add(new StringRefAddr( - BindableRepository.CONFIGFILEPATH_ADDRTYPE, configFilePath)); - reference.add(new StringRefAddr( - BindableRepository.REPHOMEDIR_ADDRTYPE, repHomeDir)); + if (JNDI_ENABLED) { + Reference reference = new Reference( + Repository.class.getName(), + BindableRepositoryFactory.class.getName(), + null); // no classpath defined + reference.add(new StringRefAddr( + BindableRepository.CONFIGFILEPATH_ADDRTYPE, configFilePath)); + reference.add(new StringRefAddr( + BindableRepository.REPHOMEDIR_ADDRTYPE, repHomeDir)); - // always create instance by using BindableRepositoryFactory - // which maintains an instance cache; - // see http://issues.apache.org/jira/browse/JCR-411 for details - Object obj = new BindableRepositoryFactory().getObjectInstance( - reference, null, null, null); - if (overwrite) { - ctx.rebind(name, obj); + // always create instance by using BindableRepositoryFactory + // which maintains an instance cache; + // see http://issues.apache.org/jira/browse/JCR-411 for details + Object obj = new BindableRepositoryFactory().getObjectInstance( + reference, null, null, null); + if (overwrite) { + ctx.rebind(name, obj); + } else { + ctx.bind(name, obj); + } } else { - ctx.bind(name, obj); + throw new RepositoryException("JNDI is not enabled"); } } @@ -91,8 +97,10 @@ public static void registerRepository(Context ctx, String name, */ public static void unregisterRepository(Context ctx, String name) throws NamingException { - ((JackrabbitRepository) ctx.lookup(name)).shutdown(); - ctx.unbind(name); + if (JNDI_ENABLED) { + ((JackrabbitRepository) ctx.lookup(name)).shutdown(); + ctx.unbind(name); + } } } diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java index 786c92c1e60..2a0b71d7496 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java @@ -651,6 +651,7 @@ public String getDatabaseType() { * * @return the database type */ + @Deprecated public String getSchema() { return databaseType; } @@ -706,6 +707,7 @@ public void setDatabaseType(String databaseType) { * * @param databaseType the database type */ + @Deprecated public void setSchema(String databaseType) { this.databaseType = databaseType; } diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/JNDIDatabaseJournal.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/JNDIDatabaseJournal.java index fa4a0d24743..48b149fae60 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/JNDIDatabaseJournal.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/JNDIDatabaseJournal.java @@ -38,6 +38,7 @@ * for the entire lifetime of the journal instance. The configured data * source should be prepared for this. */ +@Deprecated public class JNDIDatabaseJournal extends DatabaseJournal { /** diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleDbPersistenceManager.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleDbPersistenceManager.java index 8d5a6cd0de8..86fdc7304aa 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleDbPersistenceManager.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleDbPersistenceManager.java @@ -296,6 +296,7 @@ public void setSchemaObjectPrefix(String schemaObjectPrefix) { * * @return the database type name. */ + @Deprecated public String getSchema() { return databaseType; } @@ -317,6 +318,7 @@ public String getDatabaseType() { * * @param databaseType database type name */ + @Deprecated public void setSchema(String databaseType) { this.databaseType = databaseType; } diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/AbstractQueryHandler.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/AbstractQueryHandler.java index 40502b033e9..7fc6088e8b1 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/AbstractQueryHandler.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/AbstractQueryHandler.java @@ -183,6 +183,7 @@ public String getQueryClass() { * * @param idleTime the query handler idle time. */ + @Deprecated public void setIdleTime(String idleTime) { log.warn("Parameter 'idleTime' is not supported anymore. " + "Please use 'maxIdleTime' in the repository configuration."); diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java index efc3c253abb..47d76cb40bf 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java @@ -665,6 +665,7 @@ protected void addURIValue(Document doc, String fieldName, URI internalValue) { * @deprecated Use {@link #addStringValue(Document, String, String, boolean) * addStringValue(Document, String, Object, boolean)} instead. */ + @Deprecated protected void addStringValue(Document doc, String fieldName, String internalValue) { addStringValue(doc, fieldName, internalValue, true, true, DEFAULT_BOOST, true); } @@ -702,6 +703,7 @@ protected void addStringValue(Document doc, String fieldName, * @param boost the boost value for this string field. * @deprecated use {@link #addStringValue(Document, String, String, boolean, boolean, float, boolean)} instead. */ + @Deprecated protected void addStringValue(Document doc, String fieldName, String internalValue, boolean tokenized, boolean includeInNodeIndex, float boost) { @@ -791,6 +793,7 @@ protected void addNameValue(Document doc, String fieldName, Name internalValue) * @return a lucene field. * @deprecated use {@link #createFulltextField(String, boolean, boolean, boolean)} instead. */ + @Deprecated protected Field createFulltextField(String value) { return createFulltextField(value, supportHighlighting, supportHighlighting); } @@ -804,6 +807,7 @@ protected Field createFulltextField(String value) { * @return a lucene field. * @deprecated use {@link #createFulltextField(String, boolean, boolean, boolean)} instead. */ + @Deprecated protected Field createFulltextField(String value, boolean store, boolean withOffsets) { @@ -855,6 +859,7 @@ protected Field createFulltextField(String value, * @return a lucene field. * @deprecated use {@link #createFulltextField(InternalValue, Metadata, boolean)} instead. */ + @Deprecated protected Fieldable createFulltextField( InternalValue value, Metadata metadata) { return createFulltextField(value, metadata, true); diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java index 6baef1fdbe7..ecb2ec0ad0d 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java @@ -92,7 +92,6 @@ import org.apache.lucene.document.Fieldable; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.MultiReader; -import org.apache.lucene.index.Payload; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermDocs; import org.apache.lucene.search.IndexSearcher; @@ -177,6 +176,7 @@ public class SearchIndex extends AbstractQueryHandler { * @deprecated this value is not used anymore. Instead the default value * is calculated as follows: 2 * Runtime.getRuntime().availableProcessors(). */ + @Deprecated public static final int DEFAULT_EXTRACTOR_POOL_SIZE = 0; /** @@ -932,7 +932,7 @@ public ExcerptProvider createExcerptProvider(Query query) throws IOException { ExcerptProvider ep; try { - ep = (ExcerptProvider) excerptProviderClass.newInstance(); + ep = (ExcerptProvider) excerptProviderClass.getDeclaredConstructor().newInstance(); } catch (Exception e) { throw Util.createIOException(e); } @@ -1306,7 +1306,7 @@ protected SynonymProvider createSynonymProvider() { SynonymProvider sp = null; if (synonymProviderClass != null) { try { - sp = (SynonymProvider) synonymProviderClass.newInstance(); + sp = (SynonymProvider) synonymProviderClass.getDeclaredConstructor().newInstance(); sp.initialize(createSynonymProviderConfigResource()); } catch (Exception e) { log.warn("Exception initializing synonym provider: " @@ -1330,7 +1330,7 @@ protected DirectoryManager createDirectoryManager() throw new IOException(directoryManagerClass + " is not a DirectoryManager implementation"); } - DirectoryManager df = (DirectoryManager) clazz.newInstance(); + DirectoryManager df = (DirectoryManager) clazz.getDeclaredConstructor().newInstance(); df.init(this); return df; } catch (IOException e) { @@ -1355,7 +1355,7 @@ protected RedoLogFactory createRedoLogFactory() throws IOException { throw new IOException(redoLogFactoryClass + " is not a RedoLogFactory implementation"); } - return (RedoLogFactory) clazz.newInstance(); + return (RedoLogFactory) clazz.getDeclaredConstructor().newInstance(); } catch (Exception e) { IOException ex = new IOException(); ex.initCause(e); @@ -1419,7 +1419,7 @@ protected SpellChecker createSpellChecker() { SpellChecker spCheck = null; if (spellCheckerClass != null) { try { - spCheck = (SpellChecker) spellCheckerClass.newInstance(); + spCheck = (SpellChecker) spellCheckerClass.getDeclaredConstructor().newInstance(); spCheck.init(this); } catch (Exception e) { log.warn("Exception initializing spell checker: " @@ -2101,6 +2101,7 @@ public int getMaxExtractLength() { * @param filterClasses comma separated list of class names * @deprecated */ + @Deprecated public void setTextFilterClasses(String filterClasses) { log.warn("The textFilterClasses configuration parameter has" + " been deprecated, and the configured value will" @@ -2114,6 +2115,7 @@ public void setTextFilterClasses(String filterClasses) { * @return class names of the text filters in use. * @deprecated */ + @Deprecated public String getTextFilterClasses() { return "deprectated"; } @@ -2419,7 +2421,7 @@ public String getSynonymProviderConfigPath() { public void setSimilarityClass(String className) { try { Class similarityClass = Class.forName(className); - similarity = (Similarity) similarityClass.newInstance(); + similarity = (Similarity) similarityClass.getDeclaredConstructor().newInstance(); } catch (Exception e) { log.warn("Invalid Similarity class: " + className, e); } diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/AccessManager.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/AccessManager.java index 3343bafe4d0..cc3f5cb6c1a 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/AccessManager.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/AccessManager.java @@ -36,18 +36,21 @@ public interface AccessManager { * READ permission constant * @deprecated */ + @Deprecated int READ = 1; /** * WRITE permission constant * @deprecated */ + @Deprecated int WRITE = 2; /** * REMOVE permission constant * @deprecated */ + @Deprecated int REMOVE = 4; /** @@ -102,6 +105,7 @@ void init(AMContext context, AccessControlProvider acProvider, * @throws RepositoryException it an error occurs * @deprecated */ + @Deprecated void checkPermission(ItemId id, int permissions) throws AccessDeniedException, ItemNotFoundException, RepositoryException; @@ -145,6 +149,7 @@ void checkPermission(ItemId id, int permissions) * @throws RepositoryException if another error occurs * @deprecated */ + @Deprecated boolean isGranted(ItemId id, int permissions) throws ItemNotFoundException, RepositoryException; diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java index d2b5237d491..767c3da6b20 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java @@ -77,6 +77,7 @@ public abstract class AbstractLoginModule implements LoginModule { * deprecated and will no longer be supported in a subsequent release. * See also JCR-3293 */ + @Deprecated private static final String PRE_AUTHENTICATED_ATTRIBUTE_OPTION = "trust_credentials_attribute"; private String principalProviderClassName; @@ -95,6 +96,7 @@ public abstract class AbstractLoginModule implements LoginModule { * has been deprecated and will no longer be available in a subsequent release. * See also JCR-3293 */ + @Deprecated private String preAuthAttributeName; @@ -759,6 +761,7 @@ public void setPrincipalProvider(String principalProvider) { * has been deprecated and will no longer be available in a subsequent release. * See also JCR-3293 */ + @Deprecated protected final String getPreAuthAttributeName() { return preAuthAttributeName; } @@ -783,6 +786,7 @@ protected final String getPreAuthAttributeName() { * has been deprecated and will no longer be available in a subsequent release. * See also JCR-3293 */ + @Deprecated protected boolean isPreAuthenticated(final Credentials creds) { final String preAuthAttrName = getPreAuthAttributeName(); boolean isPreAuth = preAuthAttrName != null diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java index c4370edb0db..8d5bd048361 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java @@ -51,6 +51,7 @@ public class CryptedSimpleCredentials implements Credentials { * @throws UnsupportedEncodingException * @deprecated */ + @Deprecated public CryptedSimpleCredentials(SimpleCredentials credentials) throws NoSuchAlgorithmException, UnsupportedEncodingException { userId = credentials.getUserID(); diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/token/TokenBasedAuthentication.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/token/TokenBasedAuthentication.java index d578d217727..60409e1d928 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/token/TokenBasedAuthentication.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/token/TokenBasedAuthentication.java @@ -58,6 +58,7 @@ public class TokenBasedAuthentication implements Authentication { * behavior of the {@code TokenBasedAuthentication}. Note that as of OAK 1.0 * this flag will no be supported. */ + @Deprecated public static final String PARAM_COMPAT = "TokenCompatMode"; private final TokenInfo tokenInfo; diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractCompiledPermissions.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractCompiledPermissions.java index fcb6d3d5ce0..939c5bed560 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractCompiledPermissions.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractCompiledPermissions.java @@ -159,6 +159,7 @@ public static class Result { /** * @deprecated */ + @Deprecated public Result(int allows, int denies, int allowPrivileges, int denyPrivileges) { this(allows, denies, PrivilegeBits.getInstance(allowPrivileges), PrivilegeBits.getInstance(denyPrivileges)); } @@ -178,6 +179,7 @@ public boolean grants(int permissions) { /** * @deprecated jackrabbit 2.3 (throws UnsupportedOperationException, use getPrivilegeBits instead) */ + @Deprecated public int getPrivileges() { throw new UnsupportedOperationException("use #getPrivilegeBits instead."); } diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/CompiledPermissions.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/CompiledPermissions.java index 57b9e92dd2d..cad868392bb 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/CompiledPermissions.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/CompiledPermissions.java @@ -62,6 +62,7 @@ public interface CompiledPermissions { * @throws RepositoryException if an error occurs * @deprecated Use {@link #getPrivilegeSet(Path)} instead. */ + @Deprecated int getPrivileges(Path absPath) throws RepositoryException; /** diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistry.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistry.java index 0114df4fe5c..8aa0d71273d 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistry.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistry.java @@ -183,6 +183,7 @@ public PrivilegeRegistry(NamespaceRegistry namespaceRegistry, FileSystem fs) * @deprecated Use {@link org.apache.jackrabbit.api.security.authorization.PrivilegeManager} instead. * @see org.apache.jackrabbit.api.JackrabbitWorkspace#getPrivilegeManager() */ + @Deprecated public PrivilegeRegistry(NameResolver resolver) { cacheDefinitions(createBuiltInPrivilegeDefinitions()); @@ -225,6 +226,7 @@ public void setEventChannel(PrivilegeEventChannel eventChannel) { * @return all registered privileges. * @deprecated Use {@link org.apache.jackrabbit.api.security.authorization.PrivilegeManager#getRegisteredPrivileges()} instead. */ + @Deprecated public Privilege[] getRegisteredPrivileges() { try { return new PrivilegeManagerImpl(this, resolver).getRegisteredPrivileges(); @@ -243,6 +245,7 @@ public Privilege[] getRegisteredPrivileges() { * @throws RepositoryException If another error occurs. * @deprecated Use {@link org.apache.jackrabbit.api.security.authorization.PrivilegeManager#getPrivilege(String)} instead. */ + @Deprecated public Privilege getPrivilege(String privilegeName) throws AccessControlException, RepositoryException { return new PrivilegeManagerImpl(this, resolver).getPrivilege(privilegeName); } @@ -258,6 +261,7 @@ public Privilege getPrivilege(String privilegeName) throws AccessControlExceptio * @see #getBits(Privilege[]) * @deprecated Use {@link PrivilegeManagerImpl#getPrivileges(PrivilegeBits)} instead. */ + @Deprecated public Privilege[] getPrivileges(int bits) { Set prvs = new PrivilegeManagerImpl(this, resolver).getPrivileges(PrivilegeBits.getInstance(bits)); return prvs.toArray(new Privilege[prvs.size()]); @@ -274,6 +278,7 @@ public Privilege[] getPrivileges(int bits) { * @see #getPrivileges(int) * @deprecated Use {@link PrivilegeManagerImpl#getBits(javax.jcr.security.Privilege...)} instead. */ + @Deprecated public static int getBits(Privilege[] privileges) throws AccessControlException { if (privileges == null || privileges.length == 0) { throw new AccessControlException("Privilege array is empty or null."); @@ -346,6 +351,7 @@ public static int calculatePermissions(PrivilegeBits privs, PrivilegeBits parent * @return the permissions granted evaluating the given privileges. * @deprecated Use {@link #calculatePermissions(PrivilegeBits, PrivilegeBits, boolean, boolean)} instead. */ + @Deprecated public static int calculatePermissions(int privs, int parentPrivs, boolean isAllow, boolean protectsPolicy) { return calculatePermissions((long) privs, (long) parentPrivs, isAllow, protectsPolicy); } diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/principal/ProviderRegistryImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/principal/ProviderRegistryImpl.java index 6a233db45f1..674a5e8c034 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/principal/ProviderRegistryImpl.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/principal/ProviderRegistryImpl.java @@ -16,6 +16,7 @@ */ package org.apache.jackrabbit.core.security.principal; +import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; @@ -128,17 +129,11 @@ private PrincipalProvider createProvider(Properties config) } try { - Class pc = Class.forName(className, true, BeanConfig.getDefaultClassLoader()); - PrincipalProvider pp = (PrincipalProvider) pc.newInstance(); + Class pc = Class.forName(className, true, BeanConfig.getDefaultClassLoader()); + PrincipalProvider pp = (PrincipalProvider) pc.getDeclaredConstructor().newInstance(); pp.init(config); return pp; - } catch (ClassNotFoundException e) { - throw new RepositoryException("Unable to create new principal provider.", e); - } catch (IllegalAccessException e) { - throw new RepositoryException("Unable to create new principal provider.", e); - } catch (InstantiationException e) { - throw new RepositoryException("Unable to create new principal provider.", e); - } catch (ClassCastException e) { + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { throw new RepositoryException("Unable to create new principal provider.", e); } } diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserConstants.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserConstants.java index a5d994d278d..7eecd91db74 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserConstants.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserConstants.java @@ -52,6 +52,7 @@ interface UserConstants { * rep:userId property redundant. It has been removed from the node type * definition. */ + @Deprecated Name P_USERID = NF.create(Name.NS_REP_URI, "userId"); Name P_PASSWORD = NF.create(Name.NS_REP_URI, "password"); Name P_DISABLED = NF.create(Name.NS_REP_URI, "disabled"); @@ -60,6 +61,7 @@ interface UserConstants { * @deprecated As of 2.0 group membership is stored with the group node. * @see #P_MEMBERS */ + @Deprecated Name P_GROUPS = NF.create(Name.NS_REP_URI, "groups"); Name P_MEMBERS = NF.create(Name.NS_REP_URI, "members"); diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java index cc50a886f43..7c415683f27 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java @@ -190,6 +190,7 @@ public class UserManagerImpl extends ProtectedItemModifier /** * @deprecated Use {@link #PARAM_COMPATIBLE_JR16} instead. */ + @Deprecated public static final String PARAM_COMPATIBILE_JR16 = "compatibleJR16"; /** diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/DOMBuilder.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/DOMBuilder.java index b0328fb4e25..ccf95acad61 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/DOMBuilder.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/DOMBuilder.java @@ -16,6 +16,7 @@ */ package org.apache.jackrabbit.core.util; +import org.apache.jackrabbit.commons.xml.XMLFactories; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -39,7 +40,7 @@ public final class DOMBuilder { /** Static factory for creating DOM DocumentBuilder instances. */ private static final DocumentBuilderFactory BUILDER_FACTORY = - DocumentBuilderFactory.newInstance(); + XMLFactories.safeDocumentBuilderFactory(); /** Static factory for creating document to output stream transformers. */ private static final TransformerFactory TRANSFORMER_FACTORY = diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/DOMWalker.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/DOMWalker.java index 9689f7cba7d..538f442f9b6 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/DOMWalker.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/DOMWalker.java @@ -16,6 +16,7 @@ */ package org.apache.jackrabbit.core.util; +import org.apache.jackrabbit.commons.xml.XMLFactories; import org.w3c.dom.Attr; import org.w3c.dom.CharacterData; import org.w3c.dom.Document; @@ -37,8 +38,7 @@ public final class DOMWalker { /** Static factory for creating stream to DOM transformers. */ - private static final DocumentBuilderFactory factory = - DocumentBuilderFactory.newInstance(); + private static final DocumentBuilderFactory factory = XMLFactories.safeDocumentBuilderFactory(); /** The DOM document being traversed by this walker. */ private final Document document; @@ -57,6 +57,8 @@ public final class DOMWalker { public DOMWalker(InputStream xml) throws IOException { try { DocumentBuilder builder = factory.newDocumentBuilder(); + // defense in depth: entity resolver that will break any document on purpose + builder.setEntityResolver(XMLFactories.nonResolvingEntityResolver()); document = builder.parse(xml); current = document.getDocumentElement(); } catch (IOException e) { diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLock.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLock.java index d9268a7c5a7..5f100a2916d 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLock.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLock.java @@ -98,6 +98,7 @@ public RepositoryLock() { * @throws RepositoryException if the canonical path of the directory * can not be determined */ + @Deprecated public RepositoryLock(String path) throws RepositoryException { init(path); } diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalFrozenVersionHistory.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalFrozenVersionHistory.java index 05d3c22ff94..df812e9253c 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalFrozenVersionHistory.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalFrozenVersionHistory.java @@ -55,6 +55,7 @@ InternalVersionHistory getVersionHistory() /** * @deprecated use {@link #getBaseVersion()} instead */ + @Deprecated InternalVersion getBaseVesion() throws VersionException; /** diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java index 26bdc9c9081..c2339f045e9 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java @@ -45,6 +45,7 @@ public interface VirtualItemStateProvider extends ItemStateManager { * @return the id of the root node of the virtual tree. * @deprecated use {@link #getVirtualRootIds()} instead. */ + @Deprecated NodeId getVirtualRootId(); /** diff --git a/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd b/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd index dfd785d6103..de80826add2 100644 --- a/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd +++ b/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd @@ -471,7 +471,7 @@ /** * Only nodes with mixin node type mix:lifecycle may participate in a lifecycle. * - * @peop jcr:lifecyclePolicy + * @prop jcr:lifecyclePolicy * This property is a reference to another node that contains * lifecycle policy information. The definition of the referenced * node is not specified. diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/JackrabbitSessionTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/JackrabbitSessionTest.java new file mode 100644 index 00000000000..55366a700ee --- /dev/null +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/JackrabbitSessionTest.java @@ -0,0 +1,136 @@ +/* + * 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. + */ +package org.apache.jackrabbit.api; + +import org.apache.jackrabbit.test.AbstractJCRTest; +import org.apache.jackrabbit.test.NotExecutableException; + +import javax.jcr.GuestCredentials; +import javax.jcr.Item; +import javax.jcr.NamespaceException; +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.RepositoryException; + +import java.util.UUID; + +import static org.mockito.Mockito.mock; + +// Borrowed from org.apache.jackrabbit.oak.jcr.session.JackrabbitSessionTest. +// Please keep in sync. + +public class JackrabbitSessionTest extends AbstractJCRTest { + + private JackrabbitSession s; + + @Override + protected void setUp() throws Exception { + super.setUp(); + if (superuser instanceof JackrabbitSession) { + s = (JackrabbitSession) superuser; + } else { + throw new NotExecutableException("JackrabbitSession expected"); + } + } + + public void testGetParentOrNullRootNode() throws Exception { + assertNull(s.getParentOrNull(s.getRootNode())); + } + + public void testGetParentOrNull() throws Exception { + Node n = s.getNode(testRoot); + assertEquivalentNode(n, s.getParentOrNull(n.getProperty(Property.JCR_PRIMARY_TYPE))); + assertEquivalentNode(n.getParent(), s.getParentOrNull(n)); + } + + private static void assertEquivalentNode(Node expected, Node result) throws Exception { + assertNotNull(result); + assertEquals(expected.getPath(), result.getPath()); + } + + // @Ignore("Jackrabbit does not check cross-Session request") + public void ignoreGetParentOrNullSessionMismatch() throws Exception { + JackrabbitSession guest = (JackrabbitSession) getHelper().getRepository().login(new GuestCredentials()); + try { + guest.getParentOrNull(s.getNode(testRoot)); + fail("RepositoryException expected"); + } catch (RepositoryException e) { + // success + } finally { + guest.logout(); + } + } + + // @Ignore("Jackrabbit does not check cross-Session request") + public void ignoreGetParentOrNullImplMismatch() { + try { + Item item = mock(Item.class); + s.getParentOrNull(item); + fail("RepositoryException expected"); + } catch (RepositoryException e) { + // success + } + } + + public void testGetExpandedName() throws RepositoryException { + // empty namespace uri + assertEquals("{}testroot", s.getExpandedName(testRootNode)); + Node n = testRootNode.addNode("test:bar"); + assertEquals("{http://www.apache.org/jackrabbit/test}bar", s.getExpandedName(n)); + // now remap namespace uri - should not affect expanded name + assertEquals("prefix 'test' has unexpected mapping", + "http://www.apache.org/jackrabbit/test", s.getNamespaceURI("test")); + s.setNamespacePrefix("test", "urn:foo"); + assertEquals("{http://www.apache.org/jackrabbit/test}bar", s.getExpandedName(n)); + // use special namespace uri + n = testRootNode.addNode("rep:bar"); + assertEquals("{internal}bar", s.getExpandedName(n)); + } + + public void testGetExpandedNameBrokenNamespace() throws RepositoryException { + String uuid = UUID.randomUUID().toString(); + String randomNamespacePrefix = "prefix-" + uuid; + // below is not a valid namespace a.k.a. namespace URI + String randomNamespaceName = "name-" + uuid; + + // register broken namespace prefix/name mapping + s.getWorkspace().getNamespaceRegistry().registerNamespace(randomNamespacePrefix, randomNamespaceName); + + try { + Node n = testRootNode.addNode(randomNamespacePrefix + ":qux"); + + // there is no expanded name, thus we expect an exception here + String result = s.getExpandedName(n); + fail("there is no expanded name in this case, so we expect the call to fail, however we get: " + result); + } catch (NamespaceException ex) { + // expected + } + //finally { + // not supported in Jackrabbit + // s.getWorkspace().getNamespaceRegistry().unregisterNamespace(randomNamespacePrefix); + // } + } + + public void testGetExpandedPath() throws RepositoryException { + assertEquals("/{}testroot", s.getExpandedPath(testRootNode)); + Node n = testRootNode.addNode("test:bar").addNode("rep:bar"); + assertEquals("/{}testroot/{http://www.apache.org/jackrabbit/test}bar/{internal}bar", s.getExpandedPath(n)); + // now remap namespace uri - should not affect expanded name + s.setNamespacePrefix("test", "urn:foo"); + assertEquals("/{}testroot/{http://www.apache.org/jackrabbit/test}bar/{internal}bar", s.getExpandedPath(n)); + } +} \ No newline at end of file diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/TestAll.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/TestAll.java index 3cf1e6e6d93..795d1244998 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/TestAll.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/TestAll.java @@ -37,6 +37,7 @@ public static Test suite() { suite.addTestSuite(JackrabbitNodeTest.class); suite.addTestSuite(JackrabbitObservationManagerTest.class); + suite.addTestSuite(JackrabbitSessionTest.class); return suite; } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/AbstractConcurrencyTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/AbstractConcurrencyTest.java index d3706f58726..ddcd61abc67 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/AbstractConcurrencyTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/AbstractConcurrencyTest.java @@ -153,11 +153,11 @@ protected long getOneYearAhead() { */ protected static void dumpStacks(Thread[] threads) { try { - Method m = Thread.class.getMethod("getStackTrace", null); + Method m = Thread.class.getMethod("getStackTrace", (Class[]) null); StringBuffer dumps = new StringBuffer(); for (int t = 0; t < threads.length; t++) { StackTraceElement[] elements = (StackTraceElement[]) m.invoke( - threads[t], null); + threads[t], (Object[]) null); dumps.append(threads[t].toString()).append('\n'); for (int i = 0; i < elements.length; i++) { dumps.append("\tat " + elements[i]).append('\n'); diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/AddMoveTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/AddMoveTest.java old mode 100644 new mode 100755 index db367258c86..424a48dd471 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/AddMoveTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/AddMoveTest.java @@ -81,12 +81,30 @@ public void testTopLevelAddMove() throws Exception { /** * Add a top level node and remove it. Exposes a bug in the {@code CachingHierarchyManager}, * reported in JCR-3368. + * Also exposes a bug reported in JCR-5205. */ public void testTopLevelAddRemove() throws Exception { Session session = getHelper().getReadWriteSession(); - session.getRootNode().addNode("foo").addNode("bar"); + Node rootNode = session.getRootNode(); + Node foo = rootNode.addNode("foo"); + //JCR-5205: note that the test doesn't fail if we add the following line + //foo = rootNode.getNode("foo"); + foo.addNode("bar"); session.save(); - session.getNode("/foo").remove(); + session.getNode("/foo").remove(); //JCR-5205: note that the test doesn't fail if we replace this line with the following + //foo.remove(); assertFalse(session.getRootNode().hasNode("foo/bar")); } + + public void testSecondLevelAddRemove() throws Exception { + Session session = getHelper().getReadWriteSession(); + Node rootNode = session.getRootNode(); + Node parent = rootNode.addNode("parent"); + Node foo = parent.addNode("foo"); + foo.addNode("bar"); + session.save(); + session.getNode("/parent/foo").remove(); + assertFalse(session.getRootNode().hasNode("parent/foo/bar")); + } + } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/LockedWrapperTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/LockedWrapperTest.java index 46103d56410..eb5af3e4a7b 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/LockedWrapperTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/LockedWrapperTest.java @@ -305,22 +305,25 @@ public Long call() throws RepositoryException, InterruptedException { } Node n = s.getNode(counterPath); - long value = new LockedWrapper() { + long value = 0; + synchronized (counter) { + value = new LockedWrapper() { - @Override - protected Long run(Node node) - throws RepositoryException { + @Override + protected Long run(Node node) + throws RepositoryException { - Property seqProp = node.getProperty("value"); - long value = seqProp.getLong(); - seqProp.setValue(++value); - s.save(); - return value; - } - }.with(n, false); + Property seqProp = node.getProperty("value"); + long value = seqProp.getLong(); + seqProp.setValue(++value); + s.save(); + return value; + } + }.with(n, false); - // check that the sequence is ok - assertEquals(counter.getAndIncrement(), value); + // check that the sequence is ok + assertEquals(counter.getAndIncrement(), value); + } // do a random wait Thread.sleep(random.nextInt(100)); diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/MoveTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/MoveTest.java old mode 100644 new mode 100755 index 6d39a275fc6..51e8d7ce8e7 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/MoveTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/MoveTest.java @@ -36,7 +36,7 @@ public void testMoveVisibilityAcrossSessions() throws RepositoryException { Session session2 = getHelper().getReadWriteSession(); if (session1.itemExists("/foo")) { - session1.removeItem("/foo"); + session1.getNode("/foo").remove(); session1.save(); } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/TestAll.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/TestAll.java index ef5ca389d4c..28713f1dc49 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/TestAll.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/TestAll.java @@ -83,6 +83,14 @@ public static Test suite() { suite.addTestSuite(RemoveAddNodeWithUUIDTest.class); suite.addTestSuite(MoveAtRootTest.class); + suite.addTestSuite(RepositoryCopierTest.class); + suite.addTestSuite(ReadWhileSaveTest.class); + suite.addTestSuite(MoveRemoveTest.class); + suite.addTestSuite(LockedWrapperTest.class); + suite.addTestSuite(MoveTest.class); + suite.addTestSuite(MoveAtRootTest.class); + suite.addTestSuite(AddMoveTest.class); + return suite; } } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/DbClusterTestJCR3162.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/DbClusterTestJCR3162.java index 93d36aeab05..c80d8725bbb 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/DbClusterTestJCR3162.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/DbClusterTestJCR3162.java @@ -30,14 +30,13 @@ import javax.jcr.query.Query; import javax.jcr.query.RowIterator; -import junit.framework.Assert; - import org.apache.commons.io.FileUtils; import org.apache.jackrabbit.JcrConstants; import org.apache.jackrabbit.commons.JcrUtils; import org.apache.jackrabbit.core.RepositoryImpl; import org.apache.jackrabbit.core.config.RepositoryConfig; import org.apache.jackrabbit.test.JUnitTest; +import org.junit.Assert; /** * Test for JCR3162 diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/TestAll.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/TestAll.java index 70538ff5f51..cb1ed62d90c 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/TestAll.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/TestAll.java @@ -39,6 +39,7 @@ public static Test suite() { suite.addTestSuite(ClusterRecordTest.class); suite.addTestSuite(ClusterSyncTest.class); + suite.addTestSuite(ClusterDescriptorTest.class); suite.addTestSuite(DbClusterTest.class); suite.addTestSuite(DbClusterTestJCR3162.class); suite.addTestSuite(FailUpdateOnJournalExceptionTest.class); diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/TestAll.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/TestAll.java index 27bee4dd4b3..7cc70cf6456 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/TestAll.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/TestAll.java @@ -40,6 +40,7 @@ public static Test suite() { suite.addTestSuite(RepositoryConfigTest.class); suite.addTestSuite(WorkspaceConfigTest.class); suite.addTestSuite(DataSourceConfigTest.class); + suite.addTestSuite(SecurityConfigTest.class); return suite; } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/DBDataStoreTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/DBDataStoreTest.java index 8152d197afa..d1b2c835249 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/DBDataStoreTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/DBDataStoreTest.java @@ -74,7 +74,9 @@ public void testGetRecord() throws Exception { try { assertNotNull(stream); for (int j = 0; j < data.length; j++) { - assertEquals((data[j]) & 0xff, stream.read()); + int b = stream.read(); + assertTrue("early EOF at position " + j + " of stream #" + i, b >= 0); + assertEquals("data should be equal on read of stream #" + i + " at position " + j, (data[j]) & 0xff, b); } assertEquals(-1, stream.read()); } finally { @@ -103,7 +105,7 @@ public void testDbInputStreamReset() throws Exception { // test integrity of replayed bytes byte[] replayedBytes = new byte[data.length]; int length = in.read(replayedBytes); - assertEquals(length, data.length); + assertEquals(data.length, length); for (int i = 0; i < data.length; i++) { log.append(i + " data: " + data[i] + " replayed: " + replayedBytes[i] + "\n"); @@ -175,7 +177,9 @@ public void testConcurrentRead() throws Exception { // verify the contents of all the streams, reading them in parallel for (int i = 0; i < data.length; i++) { for (int j = 0; j < streams.length; j++) { - assertEquals((data[i]) & 0xff, streams[j].read()); + int b = streams[j].read(); + assertTrue("early EOF at position " + i + " of stream #" + j, b >= 0); + assertEquals((data[i]) & 0xff, b); } } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestAll.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestAll.java index 8ac2b9f0d76..a1ac39129b6 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestAll.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestAll.java @@ -51,6 +51,7 @@ public static Test suite() { suite.addTestSuite(TestTwoGetStreams.class); suite.addTestSuite(WriteWhileReadingTest.class); suite.addTestSuite(GCSubtreeMoveTest.class); + suite.addTestSuite(ConsistencyCheckerImplTest.class); return suite; } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/RepositoryFactoryImplTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/RepositoryFactoryImplTest.java index 3d87ecd573e..ebc88392746 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/RepositoryFactoryImplTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/RepositoryFactoryImplTest.java @@ -27,6 +27,7 @@ import javax.naming.Context; import javax.jcr.RepositoryFactory; + import org.apache.jackrabbit.api.JackrabbitRepository; import org.apache.jackrabbit.commons.JcrUtils; import org.apache.jackrabbit.commons.JndiRepositoryFactory; @@ -135,12 +136,22 @@ public void testJNDI() throws Exception { parameters.put(Context.INITIAL_CONTEXT_FACTORY, DummyInitialContextFactory.class.getName()); parameters.put(Context.PROVIDER_URL, "localhost"); InitialContext context = new InitialContext(new Hashtable(parameters)); - RegistryHelper.registerRepository(context, name, - REPO_CONF.getAbsolutePath(), REPO_HOME.getAbsolutePath(), false); + try { + RegistryHelper.registerRepository(context, name, + REPO_CONF.getAbsolutePath(), REPO_HOME.getAbsolutePath(), false); + } catch (RepositoryException expected) {} try { parameters.put(JndiRepositoryFactory.JNDI_NAME, name); - repo = JcrUtils.getRepository(parameters); - checkRepository(repo); + try { + repo = JcrUtils.getRepository(parameters); + } catch (RepositoryException e) { + if (JndiRepositoryFactory.JNDI_ENABLED) { + fail("JNDI repository missing: " + e.getMessage()); + } + } + if (repo != null) { + checkRepository(repo); + } } finally { RegistryHelper.unregisterRepository(context, name); } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/daily/DailyIntegrationTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/daily/DailyIntegrationTest.java index d07a7d54324..560be7beb16 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/daily/DailyIntegrationTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/daily/DailyIntegrationTest.java @@ -22,6 +22,8 @@ import org.apache.jackrabbit.core.ConcurrencyTest; import org.apache.jackrabbit.core.ConcurrentAddMoveRemoveTest; import org.apache.jackrabbit.core.ConcurrentCheckinMixedTransactionTest; +import org.apache.jackrabbit.core.ConcurrentCyclicMoveTest; +import org.apache.jackrabbit.core.ConcurrentImportTest; import org.apache.jackrabbit.core.ConcurrentLoginTest; import org.apache.jackrabbit.core.ConcurrentNodeModificationTest; import org.apache.jackrabbit.core.ConcurrentReadWriteTest; @@ -30,6 +32,8 @@ import org.apache.jackrabbit.core.ConcurrentVersioningWithTransactionsTest; import org.apache.jackrabbit.core.LockTest; import org.apache.jackrabbit.core.ReadVersionsWhileModified; +import org.apache.jackrabbit.core.cache.ConcurrentCacheTest; +import org.apache.jackrabbit.core.cache.GrowingLRUMapTest; import org.apache.jackrabbit.core.integration.ConcurrentQueriesWithUpdatesTest; import org.apache.jackrabbit.core.query.lucene.LargeResultSetTest; import org.apache.jackrabbit.core.lock.ConcurrentLockingTest; @@ -62,6 +66,10 @@ public static Test suite() { suite.addTestSuite(ConcurrentLockingWithTransactionsTest.class); suite.addTestSuite(LargeResultSetTest.class); suite.addTestSuite(ConcurrentQueriesWithUpdatesTest.class); + suite.addTestSuite(ConcurrentImportTest.class); + suite.addTestSuite(ConcurrentCyclicMoveTest.class); + suite.addTestSuite(ConcurrentCacheTest.class); + suite.addTestSuite(GrowingLRUMapTest.class); return suite; } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/TestAll.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/TestAll.java index 043855b6349..42f4994a45d 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/TestAll.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/TestAll.java @@ -37,6 +37,7 @@ public static Test suite() { suite.addTestSuite(NodeTypesInContentTest.class); suite.addTestSuite(MixinTest.class); + suite.addTestSuite(CyclicNodeTypeRegistrationTest.class); return suite; } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/TestAll.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/TestAll.java index aa1b6af5aa3..5791815b05e 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/TestAll.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/TestAll.java @@ -69,6 +69,11 @@ public static Test suite() { suite.addTestSuite(SQL2OrderByTest.class); suite.addTestSuite(DescendantSelfAxisTest.class); + suite.addTestSuite(TextExtractorTest.class); + suite.addTestSuite(SQL2TooManyClausesTest.class); + suite.addTestSuite(QueryExtensionsTest.class); + suite.addTestSuite(LazyResultSetQueryTest.class); + return suite; } } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/ComparableArrayTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/ComparableArrayTest.java index 49507d6b796..f3229d004d2 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/ComparableArrayTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/ComparableArrayTest.java @@ -16,14 +16,15 @@ */ package org.apache.jackrabbit.core.query.lucene; -import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertEquals; import javax.jcr.RepositoryException; import org.apache.jackrabbit.core.query.lucene.SharedFieldCache.ComparableArray; +import org.apache.jackrabbit.test.JUnitTest; import org.junit.Test; -public class ComparableArrayTest { +public class ComparableArrayTest extends JUnitTest { /** * Test for JCR-2906 to make sure the SharedFieldCache arranges the entries diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/IndexingQueueTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/IndexingQueueTest.java index f06af8cc364..be7bada05b7 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/IndexingQueueTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/IndexingQueueTest.java @@ -150,7 +150,7 @@ public void testReaderUpToDate() throws Exception { try { FileUtil.delete(indexDir); } catch (IOException e) { - fail("Unable to delete index directory"); + fail("Unable to delete index directory '" + indexDir + "': " + e.getMessage()); } BlockingParser.unblock(); diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/TestAll.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/TestAll.java index fffd285b1c6..f0a942dbdfa 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/TestAll.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/TestAll.java @@ -54,6 +54,12 @@ public static Test suite() { suite.addTestSuite(IndexFormatVersionTest.class); suite.addTestSuite(SynonymProviderTest.class); + suite.addTestSuite(UtilTest.class); + suite.addTestSuite(SearchIndexTest.class); + suite.addTestSuite(IDFieldTest.class); + suite.addTestSuite(ComparableArrayTest.class); + suite.addTestSuite(SearchIndexConsistencyCheckTest.class); + return suite; } } \ No newline at end of file diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/directory/DirectoryManagerTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/directory/DirectoryManagerTest.java index 5651aaef3a9..1b80f02c2ba 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/directory/DirectoryManagerTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/directory/DirectoryManagerTest.java @@ -32,7 +32,7 @@ */ public class DirectoryManagerTest extends TestCase { - private static final Collection IMPLEMENTATIONS = Arrays.asList( + private static final Collection> IMPLEMENTATIONS = Arrays.asList( new Class[]{FSDirectoryManager.class, RAMDirectoryManager.class}); private static final SearchIndex INDEX = new SearchIndex(); @@ -91,9 +91,9 @@ public void call(DirectoryManager directoryManager) throws Exception { } private void execute(Callable callable) throws Exception { - for (Iterator it = IMPLEMENTATIONS.iterator(); it.hasNext(); ) { - Class clazz = (Class) it.next(); - DirectoryManager dirMgr = (DirectoryManager) clazz.newInstance(); + for (Iterator> it = IMPLEMENTATIONS.iterator(); it.hasNext(); ) { + Class clazz = it.next(); + DirectoryManager dirMgr = (DirectoryManager) clazz.getDeclaredConstructor().newInstance(); dirMgr.init(INDEX); try { callable.call(dirMgr); diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/token/TokenBasedLoginTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/token/TokenBasedLoginTest.java index 78d8194e3ea..2e54684e526 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/token/TokenBasedLoginTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/token/TokenBasedLoginTest.java @@ -16,6 +16,23 @@ */ package org.apache.jackrabbit.core.security.authentication.token; +import java.lang.Thread.UncaughtExceptionHandler; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import javax.jcr.LoginException; +import javax.jcr.Node; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.SimpleCredentials; + import org.apache.jackrabbit.api.JackrabbitSession; import org.apache.jackrabbit.api.security.authentication.token.TokenCredentials; import org.apache.jackrabbit.api.security.principal.ItemBasedPrincipal; @@ -26,18 +43,6 @@ import org.apache.jackrabbit.test.NotExecutableException; import org.apache.jackrabbit.test.RepositoryStub; -import javax.jcr.LoginException; -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.SimpleCredentials; -import java.security.Principal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Set; - /** * TokenBasedLoginTest... */ @@ -230,120 +235,69 @@ public void testLogin() throws RepositoryException { * Tests concurrent login on the Repository including token creation. * Test copied and slightly adjusted from org.apache.jackrabbit.core.ConcurrentLoginTest */ - public void testConcurrentLogin() throws RepositoryException, NotExecutableException { - final Exception[] exception = new Exception[1]; - List testRunner = new ArrayList(); - for (int i = 0; i < 10; i++) { - testRunner.add(new Thread(new Runnable() { - public void run() { - for (int i = 0; i < 100; i++) { - try { - SimpleCredentials sc = new SimpleCredentials(testuser.getID(), testuser.getID().toCharArray()); - sc.setAttribute(TokenBasedAuthentication.TOKEN_ATTRIBUTE, ""); - - Session s = getHelper().getRepository().login(sc); - try { - Set tcs = ((SessionImpl) s).getSubject().getPublicCredentials(TokenCredentials.class); - assertFalse(tcs.isEmpty()); - } finally { - s.logout(); - } - } catch (Exception e) { - exception[0] = e; - break; - } + public void testConcurrentLogin() throws Throwable { + assertParallelExecutionSucceeds(10, new JcrRunnable() { + public void run() throws RepositoryException { + for (int i = 0; i < 100; i++) { + SimpleCredentials sc = new SimpleCredentials(testuser.getID(), testuser.getID().toCharArray()); + sc.setAttribute(TokenBasedAuthentication.TOKEN_ATTRIBUTE, ""); + + Session s = getHelper().getRepository().login(sc); + try { + Set tcs = ((SessionImpl) s).getSubject().getPublicCredentials(TokenCredentials.class); + assertFalse(tcs.isEmpty()); + } finally { + s.logout(); } } - })); - } - - // start threads - for (Object aTestRunner : testRunner) { - ((Thread) aTestRunner).start(); - } - - // join threads - for (Object aTestRunner : testRunner) { - try { - ((Thread) aTestRunner).join(); - } catch (InterruptedException e) { - fail(e.toString()); } - } + }); - if (exception[0] != null) { - fail(exception[0].toString()); - } } /** * Tests concurrent login of 3 different users on the Repository including * token creation. * Test copied and slightly adjusted from org.apache.jackrabbit.core.ConcurrentLoginTest + * @throws InterruptedException */ - public void testConcurrentLoginOfDifferentUsers() throws RepositoryException, NotExecutableException { - final Exception[] exception = new Exception[1]; - List testRunner = new ArrayList(); - for (int i = 0; i < 10; i++) { - testRunner.add(new Thread(new Runnable() { - public void run() { - for (int i = 0; i < 100; i++) { - try { - SimpleCredentials c; - double rand = 3 * Math.random(); - int index = (int) Math.floor(rand); - switch (index) { - case 0: - c = new SimpleCredentials(testuser.getID(), testuser.getID().toCharArray()); - break; - case 1: - c = new SimpleCredentials(getHelper().getProperty(RepositoryStub.PROP_PREFIX + "." + RepositoryStub.PROP_SUPERUSER_NAME), getHelper().getProperty(RepositoryStub.PROP_PREFIX + "." + RepositoryStub.PROP_SUPERUSER_PWD).toCharArray()); - break; - default: - c = new SimpleCredentials(getHelper().getProperty(RepositoryStub.PROP_PREFIX + "." + RepositoryStub.PROP_READONLY_NAME), getHelper().getProperty(RepositoryStub.PROP_PREFIX + "." + RepositoryStub.PROP_READONLY_PWD).toCharArray()); - break; - } - c.setAttribute(TokenBasedAuthentication.TOKEN_ATTRIBUTE, ""); - Session s = getHelper().getRepository().login(c); - try { - Set tcs = ((SessionImpl) s).getSubject().getPublicCredentials(TokenCredentials.class); - assertFalse(tcs.isEmpty()); - } finally { - s.logout(); - } - } catch (Exception e) { - exception[0] = e; + public void testConcurrentLoginOfDifferentUsers() throws InterruptedException { + assertParallelExecutionSucceeds(10, new JcrRunnable() { + public void run() throws RepositoryException { + for (int i = 0; i < 100; i++) { + SimpleCredentials c; + double rand = 3 * Math.random(); + int index = (int) Math.floor(rand); + switch (index) { + case 0: + c = new SimpleCredentials(testuser.getID(), testuser.getID().toCharArray()); + break; + case 1: + c = new SimpleCredentials(getHelper().getProperty(RepositoryStub.PROP_PREFIX + "." + RepositoryStub.PROP_SUPERUSER_NAME), getHelper().getProperty(RepositoryStub.PROP_PREFIX + "." + RepositoryStub.PROP_SUPERUSER_PWD).toCharArray()); break; - } + default: + c = new SimpleCredentials(getHelper().getProperty(RepositoryStub.PROP_PREFIX + "." + RepositoryStub.PROP_READONLY_NAME), getHelper().getProperty(RepositoryStub.PROP_PREFIX + "." + RepositoryStub.PROP_READONLY_PWD).toCharArray()); + break; + } + c.setAttribute(TokenBasedAuthentication.TOKEN_ATTRIBUTE, ""); + Session s = getHelper().getRepository().login(c); + try { + Set tcs = ((SessionImpl) s).getSubject().getPublicCredentials(TokenCredentials.class); + assertFalse(tcs.isEmpty()); + } finally { + s.logout(); } } - })); - } - - // start threads - for (Object aTestRunner : testRunner) { - ((Thread) aTestRunner).start(); - } - - // join threads - for (Object aTestRunner : testRunner) { - try { - ((Thread) aTestRunner).join(); - } catch (InterruptedException e) { - fail(e.toString()); } - } - - if (exception[0] != null) { - fail(exception[0].toString()); - } + }); } /** * Tests concurrent login on the Repository including token creation. * Test copied and slightly adjusted from org.apache.jackrabbit.core.ConcurrentLoginTest + * @throws InterruptedException */ - public void testConcurrentLoginDifferentWorkspaces() throws RepositoryException, NotExecutableException { + public void testConcurrentLoginDifferentWorkspaces() throws RepositoryException, NotExecutableException, InterruptedException { final String testID = testuser.getID(); // check if test is executable @@ -367,53 +321,86 @@ public void testConcurrentLoginDifferentWorkspaces() throws RepositoryException, } } - final Exception[] exception = new Exception[1]; + assertParallelExecutionSucceeds(10, new JcrRunnable() { + public void run() throws RepositoryException { + for (int i = 0; i < 100; i++) { + double rand = wspNames.size() * Math.random(); + int index = (int) Math.floor(rand); + String wspName = wspNames.get(index); + + SimpleCredentials sc = new SimpleCredentials(testID, testID.toCharArray()); + sc.setAttribute(TokenBasedAuthentication.TOKEN_ATTRIBUTE, ""); + + Session s = getHelper().getRepository().login(sc, wspName); + try { + Set tcs = ((SessionImpl) s).getSubject().getPublicCredentials(TokenCredentials.class); + assertFalse(tcs.isEmpty()); + } finally { + s.logout(); + } + } + } + }); + } + + static class UncheckedRepositoryException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public UncheckedRepositoryException(RepositoryException e) { + super(e); + } + } + + /** + * Similar to {@link Runnable} but allows to throw {@link RepositoryException} in its {@link #run()} method. + */ + static interface JcrRunnable { + public void run() throws RepositoryException; + } + + private static void assertParallelExecutionSucceeds(int numThreads, JcrRunnable runnable) throws InterruptedException { List testRunner = new ArrayList(); - for (int i = 0; i < 10; i++) { + for (int i = 0; i < numThreads; i++) { testRunner.add(new Thread(new Runnable() { public void run() { - for (int i = 0; i < 100; i++) { - try { - double rand = wspNames.size() * Math.random(); - int index = (int) Math.floor(rand); - String wspName = wspNames.get(index); - - SimpleCredentials sc = new SimpleCredentials(testID, testID.toCharArray()); - sc.setAttribute(TokenBasedAuthentication.TOKEN_ATTRIBUTE, ""); - - Session s = getHelper().getRepository().login(sc, wspName); - try { - Set tcs = ((SessionImpl) s).getSubject().getPublicCredentials(TokenCredentials.class); - assertFalse(tcs.isEmpty()); - } finally { - s.logout(); - } - - } catch (Exception e) { - exception[0] = e; - break; - } + try { + runnable.run(); + } catch (RepositoryException e) { + throw new UncheckedRepositoryException(e); } } })); } + assertThreadExecutionSucceeds(testRunner); + } + /** + * Executes all given threads and waits for them to finish. Exception in any of the thread will make the calling thread die with an exception as well + * @param testRunner the threads to execute + * @throws InterruptedException + */ + private static void assertThreadExecutionSucceeds(Collection testRunner) throws InterruptedException { + Map threadExceptions = new ConcurrentHashMap<>(); // start threads - for (Object aTestRunner : testRunner) { - ((Thread) aTestRunner).start(); + for (Thread aTestRunner : testRunner) { + aTestRunner.setUncaughtExceptionHandler(new UncaughtExceptionHandler() { + public void uncaughtException(Thread t, Throwable e) { + threadExceptions.put(t.getName() + " (id " + t.getId() +")", e); + } + } ); + aTestRunner.start(); } // join threads - for (Object aTestRunner : testRunner) { - try { - ((Thread) aTestRunner).join(); - } catch (InterruptedException e) { - fail(e.toString()); - } + for (Thread aTestRunner : testRunner) { + aTestRunner.join(); } - if (exception[0] != null) { - fail(exception[0].toString()); + // only rethrow one exception (put the other ones as suppressed) + IllegalStateException mainException = threadExceptions.entrySet().stream().findFirst().map(e -> new IllegalStateException("Thread " + e.getKey() + " failed", e.getValue())).orElse(null); + if (mainException != null) { + threadExceptions.entrySet().stream().skip(1).forEach(e -> mainException.addSuppressed(new IllegalStateException("Thread " + e.getKey() + " failed", e.getValue()))); + throw mainException; } } } \ No newline at end of file diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/acl/TestAll.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/acl/TestAll.java index fcf16c39bc7..169ed1f8a05 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/acl/TestAll.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/acl/TestAll.java @@ -54,6 +54,8 @@ public static Test suite() { suite.addTestSuite(MoveTest.class); suite.addTestSuite(RestrictionTest.class); + suite.addTestSuite(ReadNodeTypeTest.class); + return suite; } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/TestAll.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/TestAll.java index f1dc824a98b..d9e0c18d9e2 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/TestAll.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/TestAll.java @@ -52,9 +52,14 @@ public static Test suite() { suite.addTestSuite(UserImporterTest.class); suite.addTestSuite(UserAccessControlProviderTest.class); - suite.addTestSuite(DefaultPrincipalProviderTest.class); + suite.addTestSuite(DefaultPrincipalProviderTest.class); suite.addTestSuite(PasswordUtilityTest.class); + +//TODO comsume time and memory +// suite.addTestSuite(MembershipCacheTest.class); +// suite.addTestSuite(MembershipCachePerfTest.class); + return suite; } } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImporterTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImporterTest.java index fc395505c4d..fa3db3d4687 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImporterTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImporterTest.java @@ -1671,6 +1671,16 @@ public Node getNodeOrNull(String absPath) throws RepositoryException { return null; } + @Override + public String getExpandedName(Item item) throws UnsupportedRepositoryOperationException { + throw new UnsupportedRepositoryOperationException("see JCR-5137"); + } + + @Override + public String getExpandedPath(Item item) throws UnsupportedRepositoryOperationException { + throw new UnsupportedRepositoryOperationException("see JCR-5137"); + } + public Repository getRepository() { return null; } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/TestAll.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/TestAll.java index 45f5adff4dd..03916ff421c 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/TestAll.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/TestAll.java @@ -34,6 +34,7 @@ public static Test suite() { TestSuite suite = new TestSuite("Utility tests"); suite.addTestSuite(RepositoryLockTest.class); suite.addTestSuite(CooperativeFileLockTest.class); + suite.addTestSuite(DOMWalkerTest.class); return suite; } } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/db/ConnectionFactoryTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/db/ConnectionFactoryTest.java index 46fbf6bcff8..e65c41f722a 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/db/ConnectionFactoryTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/db/ConnectionFactoryTest.java @@ -24,7 +24,7 @@ import junit.framework.TestCase; -import org.apache.commons.dbcp.BasicDataSource; +import org.apache.commons.dbcp2.BasicDataSource; import org.apache.derby.iapi.jdbc.EngineConnection; import org.apache.jackrabbit.core.config.ConfigurationException; import org.apache.jackrabbit.core.config.DataSourceConfig; @@ -146,7 +146,7 @@ public void testClose() throws Exception { } private void assertPoolDefaults(BasicDataSource ds, String validationQuery, int maxCons) { - assertEquals(maxCons, ds.getMaxActive()); + assertEquals(maxCons, ds.getMaxTotal()); assertEquals(validationQuery, ds.getValidationQuery()); assertTrue(ds.getDefaultAutoCommit()); assertFalse(ds.getTestOnBorrow()); diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/version/RemoveOrphanVersionHistoryTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/version/RemoveOrphanVersionHistoryTest.java index 6b94b095757..aa43c292ae5 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/version/RemoveOrphanVersionHistoryTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/version/RemoveOrphanVersionHistoryTest.java @@ -93,7 +93,7 @@ public void testWorkspaceRemoveOrphanVersionHistory() throws RepositoryException n.checkout(); Workspace defaultWorkspace = n.getSession().getWorkspace(); - Session otherWsSession = n.getSession().getRepository().login(new SimpleCredentials("superuser", "".toCharArray()), workspaceName); + Session otherWsSession = getHelper().getSuperuserSession(workspaceName); // Clone the node in another workspace otherWsSession.getWorkspace().clone(defaultWorkspace.getName(), n.getPath(), n.getPath(), false); Node otherWsRootNode = otherWsSession.getRootNode(); diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/version/TestAll.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/version/TestAll.java index 60fed324a2e..937ebc7736c 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/version/TestAll.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/version/TestAll.java @@ -40,6 +40,11 @@ public static Test suite() { suite.addTestSuite(RestoreNodeWithSNSTest.class); suite.addTestSuite(VersionIteratorImplTest.class); suite.addTestSuite(ModifyNonVersionableCheckedOutTest.class); + + suite.addTestSuite(RemoveVersionTest.class); + suite.addTestSuite(RemoveOrphanVersionHistoryTest.class); + suite.addTestSuite(RemoveAndAddVersionLabelXATest.class); + return suite; } } diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/xml/TestAll.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/xml/TestAll.java index bbf1b4f7cd5..1a6b531db85 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/xml/TestAll.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/xml/TestAll.java @@ -35,6 +35,7 @@ public static Test suite() { TestSuite suite = new TestSuite("XML format test cases"); suite.addTestSuite(DocumentViewTest.class); suite.addTestSuite(AccessControlImporterTest.class); + suite.addTestSuite(WorkspaceImporterTest.class); return suite; } diff --git a/jackrabbit-data/pom.xml b/jackrabbit-data/pom.xml index a1eaaa58320..08145079f9a 100644 --- a/jackrabbit-data/pom.xml +++ b/jackrabbit-data/pom.xml @@ -20,7 +20,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-data @@ -86,9 +86,9 @@ commons-io - commons-dbcp - commons-dbcp - 1.4 + org.apache.commons + commons-dbcp2 + 2.14.0 true diff --git a/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java b/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java index be80f83e3cb..fff2cb8d8cd 100644 --- a/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java +++ b/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java @@ -930,6 +930,7 @@ protected synchronized MessageDigest getDigest() throws DataStoreException { * @deprecated * @return the maximum number of connections. */ + @Deprecated public int getMaxConnections() { return -1; } @@ -938,9 +939,10 @@ public int getMaxConnections() { * Set the maximum number of concurrent connections in the pool. * At least 3 connections are required if the garbage collection process is used. * - *@deprecated + * @deprecated * @param maxConnections the new value */ + @Deprecated public void setMaxConnections(int maxConnections) { // no effect } diff --git a/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbInputStream.java b/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbInputStream.java index 3bc2f0c50b4..99a482c5760 100644 --- a/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbInputStream.java +++ b/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbInputStream.java @@ -18,6 +18,7 @@ import java.io.EOFException; import java.io.IOException; +import java.io.InputStream; import java.sql.ResultSet; import org.apache.commons.io.input.AutoCloseInputStream; @@ -40,6 +41,7 @@ public class DbInputStream extends AutoCloseInputStream { protected boolean endOfStream; protected ResultSet rs; + private InputStream initialStream; /** * Create a database input stream for the given identifier. @@ -52,6 +54,7 @@ protected DbInputStream(DbDataStore store, DataIdentifier identifier) { super(null); this.store = store; this.identifier = identifier; + this.initialStream = super.in; } /** @@ -63,13 +66,11 @@ protected void openStream() throws IOException { if (endOfStream) { throw new EOFException(); } - if (in == null) { + if (in == initialStream) { try { in = store.openStream(this, identifier); } catch (DataStoreException e) { - IOException e2 = new IOException(e.getMessage()); - e2.initCause(e); - throw e2; + throw new IOException(e.getMessage(), e); } } } @@ -121,9 +122,9 @@ public int read(byte[] b, int off, int len) throws IOException { * When the stream is consumed, the database objects held by the instance are closed. */ public void close() throws IOException { - if (in != null) { + if (in != initialStream) { in.close(); - in = null; + in = initialStream; // some additional database objects // may need to be closed if (rs != null) { diff --git a/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/RandomAccessOutputStream.java b/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/RandomAccessOutputStream.java index fd7c7bedd31..b5409086712 100644 --- a/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/RandomAccessOutputStream.java +++ b/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/RandomAccessOutputStream.java @@ -26,6 +26,7 @@ * * @deprecated this class should no longer be used */ +@Deprecated public abstract class RandomAccessOutputStream extends OutputStream { /** diff --git a/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/local/FileUtil.java b/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/local/FileUtil.java index 3fe4323198b..5f9b8309748 100644 --- a/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/local/FileUtil.java +++ b/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/local/FileUtil.java @@ -93,7 +93,7 @@ public static void delete(File f) throws IOException { } } if (!f.delete()) { - throw new IOException("Unable to delete " + f.getPath()); + throw new IOException("Unable to delete '" + f.getPath() + "'"); } } } diff --git a/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionFactory.java b/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionFactory.java index b5241e897c4..fe173111759 100644 --- a/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionFactory.java +++ b/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionFactory.java @@ -16,9 +16,11 @@ */ package org.apache.jackrabbit.core.util.db; +import java.lang.reflect.InvocationTargetException; import java.sql.Connection; import java.sql.Driver; import java.sql.SQLException; +import java.time.Duration; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -29,9 +31,9 @@ import javax.naming.NamingException; import javax.sql.DataSource; -import org.apache.commons.dbcp.BasicDataSource; -import org.apache.commons.dbcp.DelegatingConnection; -import org.apache.commons.pool.impl.GenericObjectPool; +import org.apache.commons.dbcp2.BasicDataSource; +import org.apache.commons.dbcp2.DelegatingConnection; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.apache.jackrabbit.core.config.DataSourceConfig; import org.apache.jackrabbit.core.config.DataSourceConfig.DataSourceDefinition; import org.apache.jackrabbit.util.Base64; @@ -101,7 +103,7 @@ public void registerDataSources(DataSourceConfig dsc) throws RepositoryException BasicDataSource bds = getDriverDataSource(driverClass, def.getUrl(), def.getUser(), def.getPassword()); if (def.getMaxPoolSize() > 0) { - bds.setMaxActive(def.getMaxPoolSize()); + bds.setMaxTotal(def.getMaxPoolSize()); } if (def.getValidationQuery() != null && !"".equals(def.getValidationQuery().trim())) { bds.setValidationQuery(def.getValidationQuery()); @@ -286,7 +288,7 @@ private DataSource getJndiDataSource( Class contextClass, String name) throws RepositoryException { try { - Object object = contextClass.newInstance().lookup(name); + Object object = contextClass.getDeclaredConstructor().newInstance().lookup(name); if (object instanceof DataSource) { return (DataSource) object; } else { @@ -294,10 +296,7 @@ private DataSource getJndiDataSource( "Object " + object + " with JNDI name " + name + " is not a JDBC DataSource"); } - } catch (InstantiationException e) { - throw new RepositoryException( - "Invalid JNDI context: " + contextClass.getName(), e); - } catch (IllegalAccessException e) { + } catch (InstantiationException|IllegalAccessException|IllegalArgumentException|InvocationTargetException|NoSuchMethodException|SecurityException e) { throw new RepositoryException( "Invalid JNDI context: " + contextClass.getName(), e); } catch (NamingException e) { @@ -328,7 +327,7 @@ private BasicDataSource getDriverDataSource( // The JDBC specification recommends the Class.forName // method without the .newInstance() method call, // but it is required after a Derby 'shutdown' - instance = (Driver) driverClass.newInstance(); + instance = (Driver) driverClass.getDeclaredConstructor().newInstance(); } catch (Throwable e) { // Ignore exceptions as there's no requirement for // a JDBC driver class to have a public default constructor @@ -336,7 +335,7 @@ private BasicDataSource getDriverDataSource( if (instance != null) { if (instance.jdbcCompliant()) { // JCR-3445 At the moment the PostgreSQL isn't compliant because it doesn't implement this method... - ds.setValidationQueryTimeout(3); + ds.setValidationQueryTimeout(Duration.ofSeconds(3)); } } ds.setDriverClassName(driverClass.getName()); @@ -348,14 +347,16 @@ private BasicDataSource getDriverDataSource( ds.setDefaultAutoCommit(true); ds.setTestOnBorrow(false); ds.setTestWhileIdle(true); - ds.setTimeBetweenEvictionRunsMillis(600000); // 10 Minutes - ds.setMinEvictableIdleTimeMillis(60000); // 1 Minute - ds.setMaxActive(-1); // unlimited - ds.setMaxIdle(GenericObjectPool.DEFAULT_MAX_IDLE + 10); + ds.setDurationBetweenEvictionRuns(Duration.ofMinutes(10)); + ds.setMinEvictableIdle(Duration.ofMinutes(1)); + ds.setMaxTotal(-1); // unlimited + ds.setMaxIdle(GenericObjectPoolConfig.DEFAULT_MAX_IDLE + 10); ds.setValidationQuery(guessValidationQuery(url)); ds.setAccessToUnderlyingConnectionAllowed(true); ds.setPoolPreparedStatements(Boolean.valueOf(System.getProperty(SYSTEM_PROPERTY_POOL_PREPARED_STATEMENTS, "true"))); ds.setMaxOpenPreparedStatements(-1); // unlimited + // this helps to discover unusable connections of a shut-down database without executing a validation query + ds.setCacheState(false); return ds; } diff --git a/jackrabbit-it-osgi/pom.xml b/jackrabbit-it-osgi/pom.xml index 3dd4b0b468b..6503f5edd6a 100644 --- a/jackrabbit-it-osgi/pom.xml +++ b/jackrabbit-it-osgi/pom.xml @@ -23,7 +23,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml @@ -32,7 +32,7 @@ true - 4.13.1 + 4.14.0 @@ -138,7 +138,7 @@ org.ops4j.pax.exam - pax-exam-container-forked + pax-exam-container-native ${pax.exam.version} test diff --git a/jackrabbit-it-osgi/src/test/java/org/apache/jackrabbit/osgi/OSGiIT.java b/jackrabbit-it-osgi/src/test/java/org/apache/jackrabbit/osgi/OSGiIT.java index 066656f8517..d30ac442e69 100644 --- a/jackrabbit-it-osgi/src/test/java/org/apache/jackrabbit/osgi/OSGiIT.java +++ b/jackrabbit-it-osgi/src/test/java/org/apache/jackrabbit/osgi/OSGiIT.java @@ -66,8 +66,9 @@ public Option[] configuration() throws IOException, URISyntaxException { mavenBundle("org.apache.felix", "org.apache.felix.fileinstall", "3.2.6"), mavenBundle("org.slf4j", "slf4j-api", "1.7.36"), mavenBundle("commons-logging", "commons-logging", "1.2"), - mavenBundle("ch.qos.logback", "logback-core", "1.2.11"), - mavenBundle("ch.qos.logback", "logback-classic", "1.2.11"), + mavenBundle("org.apache.tika", "tika-core", "2.4.1"), + mavenBundle("ch.qos.logback", "logback-core", "1.2.13"), + mavenBundle("ch.qos.logback", "logback-classic", "1.2.13"), frameworkProperty("repository.home").value("target"), systemProperties( systemProperty("logback.configurationFile") diff --git a/jackrabbit-it-osgi/src/test/java/org/apache/jackrabbit/osgi/slf4j2/Slf4j_v2_Tika_v2_4_OSGiIT.java b/jackrabbit-it-osgi/src/test/java/org/apache/jackrabbit/osgi/slf4j2/Slf4j_v2_Tika_v2_4_OSGiIT.java new file mode 100644 index 00000000000..b3371f8e328 --- /dev/null +++ b/jackrabbit-it-osgi/src/test/java/org/apache/jackrabbit/osgi/slf4j2/Slf4j_v2_Tika_v2_4_OSGiIT.java @@ -0,0 +1,154 @@ +/* + * 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. + */ +package org.apache.jackrabbit.osgi.slf4j2; + +import static org.junit.Assert.assertEquals; +import static org.ops4j.pax.exam.CoreOptions.bundle; +import static org.ops4j.pax.exam.CoreOptions.frameworkProperty; +import static org.ops4j.pax.exam.CoreOptions.junitBundles; +import static org.ops4j.pax.exam.CoreOptions.mavenBundle; +import static org.ops4j.pax.exam.CoreOptions.systemProperties; +import static org.ops4j.pax.exam.CoreOptions.systemProperty; +import static org.ops4j.pax.exam.CoreOptions.vmOption; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.MalformedURLException; +import java.net.URISyntaxException; + +import javax.inject.Inject; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.Configuration; +import org.ops4j.pax.exam.CoreOptions; +import org.ops4j.pax.exam.Option; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.options.DefaultCompositeOption; +import org.ops4j.pax.exam.options.SystemPropertyOption; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerClass; +import org.ops4j.pax.exam.util.PathUtils; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.Version; + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerClass.class) +public class Slf4j_v2_Tika_v2_4_OSGiIT { + + @Configuration + public Option[] configuration() throws IOException, URISyntaxException { + return CoreOptions.options( + junitBundles(), + mavenBundle("org.osgi", "org.osgi.service.log", "1.3.0"), + mavenBundle("org.apache.felix", "org.apache.felix.scr", "2.0.12"), + mavenBundle("org.apache.felix", "org.apache.felix.jaas", "1.0.2"), + mavenBundle("org.osgi", "org.osgi.dto", "1.0.0"), + mavenBundle("org.apache.felix", "org.apache.felix.configadmin", "1.8.16"), + mavenBundle("org.apache.felix", "org.apache.felix.fileinstall", "3.2.6"), + + //slf4j-api-2.0.7 requirement: + //[slf4j.api [24](R 24.0)] osgi.extender; (&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0))) + mavenBundle("org.ow2.asm", "asm", "9.5"), + mavenBundle("org.ow2.asm", "asm-tree", "9.5"), + mavenBundle("org.ow2.asm", "asm-analysis", "9.5"), + mavenBundle("org.ow2.asm", "asm-commons", "9.5"), + mavenBundle("org.ow2.asm", "asm-util", "9.5"), + mavenBundle("org.apache.aries.spifly", "org.apache.aries.spifly.dynamic.bundle", "1.3.6"), + + mavenBundle("org.slf4j", "slf4j-api", "2.0.7"), + mavenBundle("ch.qos.logback", "logback-core", "1.3.5"), + mavenBundle("ch.qos.logback", "logback-classic", "1.3.5"), + + mavenBundle("commons-logging", "commons-logging", "1.2"), + mavenBundle("org.apache.tika", "tika-core", "2.4.1"), + + frameworkProperty("repository.home").value("target"), + systemProperties( + systemProperty("logback.configurationFile") + .value("file:" + PathUtils.getBaseDir() + "/src/test/resources/logback-test.xml"), + new SystemPropertyOption("felix.fileinstall.dir").value(getConfigDir())), + jarBundles(), + jpmsOptions()); + } + + private Option jpmsOptions(){ + DefaultCompositeOption composite = new DefaultCompositeOption(); + if (Version.parseVersion(System.getProperty("java.specification.version")).getMajor() > 1){ + if (java.nio.file.Files.exists(java.nio.file.FileSystems.getFileSystem(URI.create("jrt:/")).getPath("modules", "java.se.ee"))){ + composite.add(vmOption("--add-modules=java.se.ee")); + } + composite.add(vmOption("--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.lang=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.lang.invoke=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.io=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.net=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.nio=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.util=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.util.jar=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.util.regex=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.util.zip=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/sun.nio.ch=ALL-UNNAMED")); + } + return composite; + } + + private String getConfigDir(){ + return new File(new File("src", "test"), "config").getAbsolutePath(); + } + + private Option jarBundles() throws MalformedURLException { + DefaultCompositeOption composite = new DefaultCompositeOption(); + for (File bundle : new File("target", "test-bundles").listFiles()) { + if (bundle.getName().endsWith(".jar") && bundle.isFile()) { + composite.add(bundle(bundle.toURI().toURL().toString())); + } + } + return composite; + } + + @Inject + private BundleContext context; + + @Test + public void bundleStates() { + for (Bundle bundle : context.getBundles()) { + assertEquals( + String.format("Bundle %s not active. have a look at the logs", bundle.toString()), + Bundle.ACTIVE, bundle.getState()); + } + } + + @Test + public void listBundles() { + for (Bundle bundle : context.getBundles()) { + System.out.println(bundle); + } + } + + @Test + public void listServices() throws InvalidSyntaxException { + for (ServiceReference reference + : context.getAllServiceReferences(null, null)) { + System.out.println(reference); + } + } +} diff --git a/jackrabbit-it-osgi/src/test/java/org/apache/jackrabbit/osgi/slf4j2/Slf4j_v2_Tika_v2_9_OSGiIT.java b/jackrabbit-it-osgi/src/test/java/org/apache/jackrabbit/osgi/slf4j2/Slf4j_v2_Tika_v2_9_OSGiIT.java new file mode 100644 index 00000000000..a814892f618 --- /dev/null +++ b/jackrabbit-it-osgi/src/test/java/org/apache/jackrabbit/osgi/slf4j2/Slf4j_v2_Tika_v2_9_OSGiIT.java @@ -0,0 +1,154 @@ +/* + * 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. + */ +package org.apache.jackrabbit.osgi.slf4j2; + +import static org.junit.Assert.assertEquals; +import static org.ops4j.pax.exam.CoreOptions.bundle; +import static org.ops4j.pax.exam.CoreOptions.frameworkProperty; +import static org.ops4j.pax.exam.CoreOptions.junitBundles; +import static org.ops4j.pax.exam.CoreOptions.mavenBundle; +import static org.ops4j.pax.exam.CoreOptions.systemProperties; +import static org.ops4j.pax.exam.CoreOptions.systemProperty; +import static org.ops4j.pax.exam.CoreOptions.vmOption; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.MalformedURLException; +import java.net.URISyntaxException; + +import javax.inject.Inject; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.Configuration; +import org.ops4j.pax.exam.CoreOptions; +import org.ops4j.pax.exam.Option; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.options.DefaultCompositeOption; +import org.ops4j.pax.exam.options.SystemPropertyOption; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerClass; +import org.ops4j.pax.exam.util.PathUtils; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.Version; + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerClass.class) +public class Slf4j_v2_Tika_v2_9_OSGiIT { + + @Configuration + public Option[] configuration() throws IOException, URISyntaxException { + return CoreOptions.options( + junitBundles(), + mavenBundle("org.osgi", "org.osgi.service.log", "1.3.0"), + mavenBundle("org.apache.felix", "org.apache.felix.scr", "2.0.12"), + mavenBundle("org.apache.felix", "org.apache.felix.jaas", "1.0.2"), + mavenBundle("org.osgi", "org.osgi.dto", "1.0.0"), + mavenBundle("org.apache.felix", "org.apache.felix.configadmin", "1.8.16"), + mavenBundle("org.apache.felix", "org.apache.felix.fileinstall", "3.2.6"), + + //slf4j-api-2.0.7 requirement: + //[slf4j.api [24](R 24.0)] osgi.extender; (&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0))) + mavenBundle("org.ow2.asm", "asm", "9.5"), + mavenBundle("org.ow2.asm", "asm-tree", "9.5"), + mavenBundle("org.ow2.asm", "asm-analysis", "9.5"), + mavenBundle("org.ow2.asm", "asm-commons", "9.5"), + mavenBundle("org.ow2.asm", "asm-util", "9.5"), + mavenBundle("org.apache.aries.spifly", "org.apache.aries.spifly.dynamic.bundle", "1.3.6"), + + mavenBundle("org.slf4j", "slf4j-api", "2.0.7"), + mavenBundle("ch.qos.logback", "logback-core", "1.3.5"), + mavenBundle("ch.qos.logback", "logback-classic", "1.3.5"), + + mavenBundle("commons-logging", "commons-logging", "1.2"), + mavenBundle("org.apache.tika", "tika-core", "2.9.4"), + + frameworkProperty("repository.home").value("target"), + systemProperties( + systemProperty("logback.configurationFile") + .value("file:" + PathUtils.getBaseDir() + "/src/test/resources/logback-test.xml"), + new SystemPropertyOption("felix.fileinstall.dir").value(getConfigDir())), + jarBundles(), + jpmsOptions()); + } + + private Option jpmsOptions(){ + DefaultCompositeOption composite = new DefaultCompositeOption(); + if (Version.parseVersion(System.getProperty("java.specification.version")).getMajor() > 1){ + if (java.nio.file.Files.exists(java.nio.file.FileSystems.getFileSystem(URI.create("jrt:/")).getPath("modules", "java.se.ee"))){ + composite.add(vmOption("--add-modules=java.se.ee")); + } + composite.add(vmOption("--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.lang=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.lang.invoke=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.io=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.net=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.nio=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.util=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.util.jar=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.util.regex=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/java.util.zip=ALL-UNNAMED")); + composite.add(vmOption("--add-opens=java.base/sun.nio.ch=ALL-UNNAMED")); + } + return composite; + } + + private String getConfigDir(){ + return new File(new File("src", "test"), "config").getAbsolutePath(); + } + + private Option jarBundles() throws MalformedURLException { + DefaultCompositeOption composite = new DefaultCompositeOption(); + for (File bundle : new File("target", "test-bundles").listFiles()) { + if (bundle.getName().endsWith(".jar") && bundle.isFile()) { + composite.add(bundle(bundle.toURI().toURL().toString())); + } + } + return composite; + } + + @Inject + private BundleContext context; + + @Test + public void bundleStates() { + for (Bundle bundle : context.getBundles()) { + assertEquals( + String.format("Bundle %s not active. have a look at the logs", bundle.toString()), + Bundle.ACTIVE, bundle.getState()); + } + } + + @Test + public void listBundles() { + for (Bundle bundle : context.getBundles()) { + System.out.println(bundle); + } + } + + @Test + public void listServices() throws InvalidSyntaxException { + for (ServiceReference reference + : context.getAllServiceReferences(null, null)) { + System.out.println(reference); + } + } +} diff --git a/jackrabbit-it-osgi/test-bundles.xml b/jackrabbit-it-osgi/test-bundles.xml index 26f9814835d..367af71f31a 100644 --- a/jackrabbit-it-osgi/test-bundles.xml +++ b/jackrabbit-it-osgi/test-bundles.xml @@ -36,7 +36,6 @@ org.apache.jackrabbit:jackrabbit-jcr-commons org.apache.jackrabbit:jackrabbit-spi org.apache.jackrabbit:jackrabbit-spi-commons - org.apache.tika:tika-core org.apache.httpcomponents:httpclient-osgi org.apache.httpcomponents:httpcore-osgi org.apache.jackrabbit:jackrabbit-webdav diff --git a/jackrabbit-jca/pom.xml b/jackrabbit-jca/pom.xml index c25b31bd109..8b8a43504cb 100644 --- a/jackrabbit-jca/pom.xml +++ b/jackrabbit-jca/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-jca diff --git a/jackrabbit-jcr-client/pom.xml b/jackrabbit-jcr-client/pom.xml index a1275783538..f46d7a57b11 100644 --- a/jackrabbit-jcr-client/pom.xml +++ b/jackrabbit-jcr-client/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-jcr-client diff --git a/jackrabbit-jcr-client/src/main/java/org/apache/jackrabbit/client/RepositoryFactoryImpl.java b/jackrabbit-jcr-client/src/main/java/org/apache/jackrabbit/client/RepositoryFactoryImpl.java index a8923f4adb4..924689a0795 100644 --- a/jackrabbit-jcr-client/src/main/java/org/apache/jackrabbit/client/RepositoryFactoryImpl.java +++ b/jackrabbit-jcr-client/src/main/java/org/apache/jackrabbit/client/RepositoryFactoryImpl.java @@ -65,7 +65,7 @@ public Repository getRepository(@SuppressWarnings("rawtypes") Map parameters) th Class repositoryFactoryClass = Class.forName(repositoryFactoryName, true, Thread.currentThread().getContextClassLoader()); - repositoryFactory = repositoryFactoryClass.newInstance(); + repositoryFactory = repositoryFactoryClass.getDeclaredConstructor().newInstance(); } catch (Exception e) { throw new RepositoryException(e); diff --git a/jackrabbit-jcr-commons/pom.xml b/jackrabbit-jcr-commons/pom.xml index c7230e8bccc..cc6850c4d8c 100644 --- a/jackrabbit-jcr-commons/pom.xml +++ b/jackrabbit-jcr-commons/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-jcr-commons diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/JcrConstants.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/JcrConstants.java index 3b15c90d876..6a4332eb9f8 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/JcrConstants.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/JcrConstants.java @@ -19,203 +19,214 @@ import javax.jcr.Session; /** - * This Interface defines some of the item names that are defined in the - * jcr spec 1.0, using the default prefixes 'jcr', 'nt' and 'mix'. Please note - * that those prefixes can by redefined by an application using the + * This interface defines some of the item names that are defined in the JCR Specification 1.0 in the qualified form, + * using the default prefixes {@code jcr}, {@code nt} and {@code mix}. + *

+ * Please note that those prefixes can by redefined by an application using the * {@link Session#setNamespacePrefix(String, String)} method. As a result, the * constants may not refer to the respective items. + *

+ * On the other hand, the constants in {@link javax.jcr.nodetype.NodeType}, + * {@link javax.jcr.Node}, {@link javax.jcr.Property} and {@link javax.jcr.Workspace} + * are more complete (covering JCR 2.0 + * as well) and also define names using expanded form, which is immune to session local + * remappings, so it is recommended to use those constants instead whenever possible. */ public interface JcrConstants { /** - * jcr:autoCreated + * Use {@link javax.jcr.Property#JCR_AUTOCREATED} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_AUTOCREATED = "jcr:autoCreated"; /** - * jcr:baseVersion + * Use {@link javax.jcr.Property#JCR_BASE_VERSION} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_BASEVERSION = "jcr:baseVersion"; - /** - * jcr:child - */ + public static final String JCR_CHILD = "jcr:child"; /** - * jcr:childNodeDefinition + * Use {@link javax.jcr.Node#JCR_CHILD_NODE_DEFINITION} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_CHILDNODEDEFINITION = "jcr:childNodeDefinition"; /** - * jcr:content + * Use {@link javax.jcr.Node#JCR_CONTENT} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_CONTENT = "jcr:content"; /** - * jcr:created + * Use {@link javax.jcr.Property#JCR_CREATED} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_CREATED = "jcr:created"; /** - * jcr:data + * Use {@link javax.jcr.Property#JCR_DATA} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_DATA = "jcr:data"; /** - * jcr:defaultPrimaryType + * Use {@link javax.jcr.Property#JCR_DEFAULT_PRIMARY_TYPE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_DEFAULTPRIMARYTYPE = "jcr:defaultPrimaryType"; /** - * jcr:defaultValues + * Use {@link javax.jcr.Property#JCR_DEFAULT_VALUES} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_DEFAULTVALUES = "jcr:defaultValues"; /** - * jcr:encoding + * Use {@link javax.jcr.Property#JCR_ENCODING} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_ENCODING = "jcr:encoding"; /** - * jcr:frozenMixinTypes + * Use {@link javax.jcr.Property#JCR_FROZEN_MIXIN_TYPES} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_FROZENMIXINTYPES = "jcr:frozenMixinTypes"; /** - * jcr:frozenNode + * Use {@link javax.jcr.Node#JCR_FROZEN_NODE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_FROZENNODE = "jcr:frozenNode"; /** - * jcr:frozenPrimaryType + * Use {@link javax.jcr.Property#JCR_FROZEN_PRIMARY_TYPE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_FROZENPRIMARYTYPE = "jcr:frozenPrimaryType"; /** - * jcr:frozenUuid + * Use {@link javax.jcr.Property#JCR_FROZEN_UUID} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_FROZENUUID = "jcr:frozenUuid"; /** - * jcr:hasOrderableChildNodes + * Use {@link javax.jcr.Property#JCR_HAS_ORDERABLE_CHILD_NODES} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_HASORDERABLECHILDNODES = "jcr:hasOrderableChildNodes"; /** - * jcr:isCheckedOut + * Use {@link javax.jcr.Property#JCR_IS_CHECKED_OUT} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_ISCHECKEDOUT = "jcr:isCheckedOut"; /** - * jcr:isMixin + * Use {@link javax.jcr.Property#JCR_IS_MIXIN} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_ISMIXIN = "jcr:isMixin"; /** - * jcr:language + * Use {@link javax.jcr.Property#JCR_LANGUAGE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_LANGUAGE = "jcr:language"; /** - * jcr:lastModified + * Use {@link javax.jcr.Property#JCR_LAST_MODIFIED} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_LASTMODIFIED = "jcr:lastModified"; /** - * jcr:lockIsDeep + * Use {@link javax.jcr.Property#JCR_LOCK_IS_DEEP} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_LOCKISDEEP = "jcr:lockIsDeep"; /** - * jcr:lockOwner + * Use {@link javax.jcr.Property#JCR_LOCK_OWNER} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_LOCKOWNER = "jcr:lockOwner"; /** - * jcr:mandatory + * Use {@link javax.jcr.Property#JCR_MANDATORY} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_MANDATORY = "jcr:mandatory"; /** - * jcr:mergeFailed + * Use {@link javax.jcr.Property#JCR_MERGE_FAILED} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_MERGEFAILED = "jcr:mergeFailed"; /** - * jcr:mimeType + * Use {@link javax.jcr.Property#JCR_MIMETYPE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_MIMETYPE = "jcr:mimeType"; /** - * jcr:mixinTypes + * Use {@link javax.jcr.Property#JCR_MIXIN_TYPES} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_MIXINTYPES = "jcr:mixinTypes"; /** - * jcr:multiple + * Use {@link javax.jcr.Property#JCR_MULTIPLE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_MULTIPLE = "jcr:multiple"; /** - * jcr:name + * Use {@link javax.jcr.Property#JCR_NAME} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_NAME = "jcr:name"; /** - * jcr:nodeTypeName + * Use {@link javax.jcr.Property#JCR_NODE_TYPE_NAME} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_NODETYPENAME = "jcr:nodeTypeName"; /** - * jcr:onParentVersion + * Use {@link javax.jcr.Property#JCR_ON_PARENT_VERSION} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_ONPARENTVERSION = "jcr:onParentVersion"; /** - * jcr:predecessors + * Use {@link javax.jcr.Property#JCR_PREDECESSORS} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_PREDECESSORS = "jcr:predecessors"; /** - * jcr:primaryItemName + * Use {@link javax.jcr.Property#JCR_PRIMARY_ITEM_NAME} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_PRIMARYITEMNAME = "jcr:primaryItemName"; /** - * jcr:primaryType + * Use {@link javax.jcr.Property#JCR_PRIMARY_TYPE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_PRIMARYTYPE = "jcr:primaryType"; /** - * jcr:propertyDefinition + * Use {@link javax.jcr.Node#JCR_PROPERTY_DEFINITION} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_PROPERTYDEFINITION = "jcr:propertyDefinition"; /** - * jcr:protected + * Use {@link javax.jcr.Property#JCR_PROTECTED} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_PROTECTED = "jcr:protected"; /** - * jcr:requiredPrimaryTypes + * Use {@link javax.jcr.Property#JCR_REQUIRED_PRIMARY_TYPES} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_REQUIREDPRIMARYTYPES = "jcr:requiredPrimaryTypes"; /** - * jcr:requiredType + * Use {@link javax.jcr.Property#JCR_REQUIRED_TYPE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_REQUIREDTYPE = "jcr:requiredType"; /** - * jcr:rootVersion + * Use {@link javax.jcr.Node#JCR_ROOT_VERSION} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_ROOTVERSION = "jcr:rootVersion"; /** * jcr:sameNameSiblings + * Use {@link javax.jcr.Property#JCR_SAME_NAME_SIBLINGS} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_SAMENAMESIBLINGS = "jcr:sameNameSiblings"; /** - * jcr:statement + * Use {@link javax.jcr.Property#JCR_STATEMENT} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_STATEMENT = "jcr:statement"; /** - * jcr:successors + * Use {@link javax.jcr.Property#JCR_SUCCESSORS} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_SUCCESSORS = "jcr:successors"; /** - * jcr:supertypes + * Use {@link javax.jcr.Property#JCR_SUPERTYPES} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_SUPERTYPES = "jcr:supertypes"; /** - * jcr:system + * Use {@link javax.jcr.Workspace#NAME_SYSTEM_NODE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_SYSTEM = "jcr:system"; /** - * jcr:uuid + * Use {@link javax.jcr.Property#JCR_TITLE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). + */ + public static final String JCR_TITLE = "jcr:title"; + /** + * Use {@link javax.jcr.Property#JCR_UUID} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_UUID = "jcr:uuid"; /** - * jcr:valueConstraints + * Use {@link javax.jcr.Property#JCR_VALUE_CONSTRAINTS} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_VALUECONSTRAINTS = "jcr:valueConstraints"; /** - * jcr:versionHistory + * Use {@link javax.jcr.Property#JCR_VERSION_HISTORY} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_VERSIONHISTORY = "jcr:versionHistory"; /** - * jcr:versionLabels + * Use {@link javax.jcr.Node#JCR_VERSION_LABELS} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_VERSIONLABELS = "jcr:versionLabels"; /** - * jcr:versionStorage + * Use {@link javax.jcr.Workspace#NAME_VERSION_STORAGE_NODE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_VERSIONSTORAGE = "jcr:versionStorage"; /** - * jcr:versionableUuid + * Use {@link javax.jcr.Property#JCR_VERSIONABLE_UUID} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String JCR_VERSIONABLEUUID = "jcr:versionableUuid"; @@ -229,75 +240,103 @@ public interface JcrConstants { public static final String JCR_SCORE = "jcr:score"; /** - * mix:lockable + * Use {@link javax.jcr.nodetype.NodeType#MIX_CREATED} whenever expanded JCR names are supported (e.g. in JCR API method parameters). + */ + public static final String MIX_CREATED = "mix:created"; + /** + * Use {@link javax.jcr.nodetype.NodeType#MIX_LANGUAGE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). + */ + public static final String MIX_LANGUAGE = "mix:language"; + /** + * Use {@link javax.jcr.nodetype.NodeType#MIX_LAST_MODIFIED} whenever expanded JCR names are supported (e.g. in JCR API method parameters). + */ + public static final String MIX_LAST_MODIFIED = "mix:lastModified"; + /** + * Use {@link javax.jcr.nodetype.NodeType#MIX_LIFECYCLE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). + */ + public static final String MIX_LIFECYCLE = "mix:lifecycle"; + /** + * Use {@link javax.jcr.nodetype.NodeType#MIX_LOCKABLE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String MIX_LOCKABLE = "mix:lockable"; /** - * mix:referenceable + * Use {@link javax.jcr.nodetype.NodeType#MIX_MIMETYPE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). + */ + public static final String MIX_MIMETYPE = "mix:mimetype"; + /** + * Use {@link javax.jcr.nodetype.NodeType#MIX_REFERENCEABLE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String MIX_REFERENCEABLE = "mix:referenceable"; /** - * mix:versionable + * Use {@link javax.jcr.nodetype.NodeType#MIX_SIMPLE_VERSIONABLE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). + */ + public static final String MIX_SIMPLE_VERSIONABLE = "mix:simpleVersionable"; + /** + * Use {@link javax.jcr.nodetype.NodeType#MIX_VERSIONABLE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String MIX_VERSIONABLE = "mix:versionable"; /** - * mix:shareable + * Use {@link javax.jcr.nodetype.NodeType#MIX_SHAREABLE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String MIX_SHAREABLE = "mix:shareable"; /** - * nt:base + * Use {@link javax.jcr.nodetype.NodeType#MIX_TITLE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). + */ + public static final String MIX_TITLE = "mix:title"; + /** + * Use {@link javax.jcr.nodetype.NodeType#NT_BASE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String NT_BASE = "nt:base"; /** - * nt:childNodeDefinition + * Use {@link javax.jcr.nodetype.NodeType#NT_CHILD_NODE_DEFINITION} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String NT_CHILDNODEDEFINITION = "nt:childNodeDefinition"; /** - * nt:file + * Use {@link javax.jcr.nodetype.NodeType#NT_FILE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String NT_FILE = "nt:file"; /** - * nt:folder + * Use {@link javax.jcr.nodetype.NodeType#NT_FOLDER} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String NT_FOLDER = "nt:folder"; /** - * nt:frozenNode + * Use {@link javax.jcr.nodetype.NodeType#NT_FROZEN_NODE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String NT_FROZENNODE = "nt:frozenNode"; /** - * nt:hierarchyNode + * Use {@link javax.jcr.nodetype.NodeType#NT_HIERARCHY_NODE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String NT_HIERARCHYNODE = "nt:hierarchyNode"; /** - * nt:linkedFile + * Use {@link javax.jcr.nodetype.NodeType#NT_LINKED_FILE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String NT_LINKEDFILE = "nt:linkedFile"; /** - * nt:nodeType + * Use {@link javax.jcr.nodetype.NodeType#NT_NODE_TYPE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String NT_NODETYPE = "nt:nodeType"; /** - * nt:propertyDefinition + * Use {@link javax.jcr.nodetype.NodeType#NT_PROPERTY_DEFINITION} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String NT_PROPERTYDEFINITION = "nt:propertyDefinition"; /** - * nt:query + * Use {@link javax.jcr.nodetype.NodeType#NT_QUERY} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String NT_QUERY = "nt:query"; /** - * nt:resource + * Use {@link javax.jcr.nodetype.NodeType#NT_RESOURCE} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String NT_RESOURCE = "nt:resource"; /** - * nt:unstructured + * Use {@link javax.jcr.nodetype.NodeType#NT_UNSTRUCTURED} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String NT_UNSTRUCTURED = "nt:unstructured"; /** - * nt:version + * Use {@link javax.jcr.nodetype.NodeType#NT_VERSION} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String NT_VERSION = "nt:version"; /** - * nt:versionHistory + * Use {@link javax.jcr.nodetype.NodeType#NT_VERSION_HISTORY} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String NT_VERSIONHISTORY = "nt:versionHistory"; /** @@ -305,7 +344,7 @@ public interface JcrConstants { */ public static final String NT_VERSIONLABELS = "nt:versionLabels"; /** - * nt:versionedChild + * Use {@link javax.jcr.nodetype.NodeType#NT_VERSIONED_CHILD} whenever expanded JCR names are supported (e.g. in JCR API method parameters). */ public static final String NT_VERSIONEDCHILD = "nt:versionedChild"; } diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/JndiRepositoryFactory.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/JndiRepositoryFactory.java index 92274df6f3f..83eca3032f7 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/JndiRepositoryFactory.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/JndiRepositoryFactory.java @@ -56,6 +56,11 @@ @SuppressWarnings({ "rawtypes", "unchecked" }) public class JndiRepositoryFactory implements RepositoryFactory { + /** + * Disabled by default, see JCR-5135 + */ + public static final boolean JNDI_ENABLED = Boolean.getBoolean("jackrabbit.jndi.enabled"); + /** * The JNDI name parameter name. */ @@ -64,29 +69,32 @@ public class JndiRepositoryFactory implements RepositoryFactory { public Repository getRepository(Map parameters) throws RepositoryException { - if (parameters == null) { - return null; // no default JNDI repository - } else { - Hashtable environment = new Hashtable(parameters); - if (environment.containsKey(JNDI_NAME)) { - String name = environment.remove(JNDI_NAME).toString(); - return getRepository(name, environment); - } else if (environment.containsKey(JcrUtils.REPOSITORY_URI)) { - Object parameter = environment.remove(JcrUtils.REPOSITORY_URI); - try { - URI uri = new URI(parameter.toString().trim()); - if ("jndi".equalsIgnoreCase(uri.getScheme())) { - return getRepository(uri, environment); - } else { - return null; // not a jndi: URI + if (JNDI_ENABLED) { + if (parameters == null) { + return null; // no default JNDI repository + } else { + Hashtable environment = new Hashtable(parameters); + if (environment.containsKey(JNDI_NAME)) { + String name = environment.remove(JNDI_NAME).toString(); + return getRepository(name, environment); + } else if (environment.containsKey(JcrUtils.REPOSITORY_URI)) { + Object parameter = environment.remove(JcrUtils.REPOSITORY_URI); + try { + URI uri = new URI(parameter.toString().trim()); + if ("jndi".equalsIgnoreCase(uri.getScheme())) { + return getRepository(uri, environment); + } else { + return null; // not a jndi: URI + } + } catch (URISyntaxException e) { + return null; // not a valid URI } - } catch (URISyntaxException e) { - return null; // not a valid URI + } else { + return null; // unknown parameters } - } else { - return null; // unknown parameters } } + return null; } private Repository getRepository(URI uri, Hashtable environment) diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/NamespaceHelper.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/NamespaceHelper.java index a5581185c5c..457463d9012 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/NamespaceHelper.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/NamespaceHelper.java @@ -16,8 +16,15 @@ */ package org.apache.jackrabbit.commons; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.HashMap; +import java.util.Locale; import java.util.Map; +import java.util.UUID; +import java.util.function.UnaryOperator; import javax.jcr.NamespaceException; import javax.jcr.NamespaceRegistry; @@ -53,6 +60,11 @@ public class NamespaceHelper { */ private final Session session; + /** + * Current namespace registry. + */ + private NamespaceRegistry namespaceRegistry; + /** * Creates a namespace helper for the given session. * @@ -60,6 +72,19 @@ public class NamespaceHelper { */ public NamespaceHelper(Session session) { this.session = session; + // will be set on lazily + this.namespaceRegistry = null; + } + + /** + Get the namespace registry; needs to be done on-demand because the constructor + does not allow RepositoryException + */ + private NamespaceRegistry getNamespaceRegistry() throws RepositoryException { + if (namespaceRegistry == null) { + namespaceRegistry = session.getWorkspace().getNamespaceRegistry(); + } + return namespaceRegistry; } /** @@ -72,22 +97,22 @@ public NamespaceHelper(Session session) { * @throws RepositoryException if the namespaces could not be retrieved */ public Map getNamespaces() throws RepositoryException { - Map namespaces = new HashMap(); + Map namespaces = new HashMap<>(); String[] prefixes = session.getNamespacePrefixes(); - for (String prefixe : prefixes) { - namespaces.put(prefixe, session.getNamespaceURI(prefixe)); + for (String prefix : prefixes) { + namespaces.put(prefix, session.getNamespaceURI(prefix)); } return namespaces; } /** * Returns the prefix mapped to the given namespace URI in the current - * session, or null if the namespace does not exist. + * session, or {@code null} if the namespace does not exist. * * @see Session#getNamespacePrefix(String) * @param uri namespace URI - * @return namespace prefix, or null - * @throws RepositoryException if the namespace could not be retrieved + * @return namespace prefix, or {@code null} + * @throws RepositoryException if the namespace prefix could not be retrieved */ public String getPrefix(String uri) throws RepositoryException { try { @@ -99,11 +124,11 @@ public String getPrefix(String uri) throws RepositoryException { /** * Returns the namespace URI mapped to the given prefix in the current - * session, or null if the namespace does not exist. + * session, or {@code null} if the namespace does not exist. * * @see Session#getNamespaceURI(String) * @param prefix namespace prefix - * @return namespace prefix, or null + * @return namespace prefix, or {@code null} * @throws RepositoryException if the namespace could not be retrieved */ public String getURI(String prefix) throws RepositoryException { @@ -126,7 +151,7 @@ public String getURI(String prefix) throws RepositoryException { */ public String getJcrName(String uri, String name) throws NamespaceException, RepositoryException { - if (uri != null && uri.length() > 0) { + if (uri != null && !uri.isEmpty()) { return session.getNamespacePrefix(uri) + ":" + name; } else { return name; @@ -144,6 +169,11 @@ public String getJcrName(String uri, String name) *

      *     node.getProperty(helper.getName("jcr:data"));
      * 
+ * Note that it is simpler to just use the expanded name wherever supported: + *
+     *     node.getProperty("http://www.jcp.org/jcr/1.0}data");
+     * 
+ * Also note the predefined constants in {@link org.apache.jackrabbit.JcrConstants}. * * @param name prefixed name using the standard JCR prefixes * @return prefixed name using the current session namespace mappings @@ -178,7 +208,7 @@ public String getJcrName(String name) /** * Safely registers the given namespace. If the namespace already exists, * then the prefix mapped to the namespace in the current session is - * returned. Otherwise the namespace is registered to the namespace + * returned. Otherwise, the namespace is registered to the namespace * registry. If the given prefix is already registered for some other * namespace or otherwise invalid, then another prefix is automatically * generated. After the namespace has been registered, the prefix mapped @@ -192,32 +222,36 @@ public String getJcrName(String name) */ public String registerNamespace(String prefix, String uri) throws RepositoryException { - NamespaceRegistry registry = - session.getWorkspace().getNamespaceRegistry(); + NamespaceRegistry registry = getNamespaceRegistry(); try { // Check if the namespace is registered registry.getPrefix(uri); } catch (NamespaceException e1) { - // Replace troublesome prefix hints - if (prefix == null || prefix.length() == 0 + // Throw away Troublesome prefix hints + if (prefix == null || prefix.isEmpty() || prefix.toLowerCase().startsWith("xml") || !XMLChar.isValidNCName(prefix)) { - prefix = "ns"; // ns, ns2, ns3, ns4, ... + prefix = null; } - // Loop until an unused prefix is found - try { - String base = prefix; - for (int i = 2; true; i++) { - registry.getURI(prefix); - prefix = base + i; - } - } catch (NamespaceException e2) { - // Exit the loop - } + if (prefix == null) { + prefix = suggestPrefix(uri, pref -> { + // prefix checker + try { + return registry.getURI(pref); + } catch (RepositoryException e) { + return null; + } + }); + } // Register the namespace - registry.registerNamespace(prefix, uri); + try { + registry.registerNamespace(prefix, uri); + } catch (NamespaceException ex) { + // likely prefix is already in use; retry with null prefix + return registerNamespace(null, uri); + } } return session.getNamespacePrefix(uri); @@ -231,10 +265,118 @@ public String registerNamespace(String prefix, String uri) * @throws RepositoryException if the namespaces could not be registered */ public void registerNamespaces(Map namespaces) throws RepositoryException { - for (Map.Entry stringStringEntry : namespaces.entrySet()) { - Map.Entry entry = stringStringEntry; + for (Map.Entry entry : namespaces.entrySet()) { registerNamespace(entry.getKey(), entry.getValue()); } } + // non-public supporting code + + // map with 'optimal' prefix mappings; hard-wired should be ok for now + private static final Map KNOWN_PREFIXES = + Map.of("http://creativecommons.org/ns#", "cc", + "http://purl.org/dc/terms/", "dc", + "http://ns.adobe.com/DICOM/", "DICOM", + "http://ns.adobe.com/exif/1.0/", "exif", + "http://ns.adobe.com/pdf/1.3/", "pdf", + "http://ns.adobe.com/pdfx/1.3/", "pdfx", + "http://ns.adobe.com/photoshop/1.0/", "photoshop", + "http://www.w3.org/1999/02/22-rdf-syntax-ns#", "rdf", + "http://ns.adobe.com/tiff/1.0/", "tiff", + "http://ns.adobe.com/xap/1.0/", "xmp"); + + + // suggest an available prefix for the provided namespace, based on a random UUID + // (last resort) + private static String devisePrefixByUUID(String namespace, UnaryOperator lookupNamespace) { + String prefix; + + do { + prefix = "u-" + UUID.randomUUID(); + } while (namespace.equals(lookupNamespace.apply(prefix))); + + return prefix; + } + + // compute SHA-256, null when NoSuchAlgorithmException + private static String getSha256(String namespace) { + try { + byte[] bytes = MessageDigest.getInstance("SHA-256").digest(namespace.getBytes(StandardCharsets.UTF_8)); + return new BigInteger(1, bytes).toString(16); + } catch (NoSuchAlgorithmException e) { + // this really, really should not happen + return null; + } + } + + // suggest an available prefix for the provided namespace, based on the sha-256 + // of the namespace name, and a final fallback to UUID based (while considering pre-existing mappings) + private static String devisePrefixTrySha256(String namespace, UnaryOperator lookupNamespace) { + + String sha = getSha256(namespace); + if (sha != null) { + for (int i = 7; i <= sha.length(); i++) { + String prefix = "s-" + sha.substring(0, i); + String lookedUpPrefix = lookupNamespace.apply(prefix); + if (lookedUpPrefix == null) { + // unused, so go ahead with this prefix + return prefix; + } + } + } + + // fallback to UUID + return devisePrefixByUUID(namespace, lookupNamespace); + } + + // suggest an available prefix for the provided namespace, based on the characters + // in the namespace name (while considering pre-existing mappings) + private static String devisePrefix(String namespace, UnaryOperator lookupNamespace) { + String prefix = namespace.toLowerCase(Locale.ENGLISH); + + // strip scheme when http(s) + if (prefix.startsWith("http://")) { + prefix = prefix.substring("http://".length()); + } else if (prefix.startsWith("https://")) { + prefix = prefix.substring("https://".length()); + } + + // strip common host name prefixes + if (prefix.startsWith("www.")) { + prefix = prefix.substring("www.".length()); + } else if (prefix.startsWith("ns.")) { + prefix = prefix.substring("ns.".length()); + } + + // replace characters not allowed in prefix (here: '\', '/' and :) + prefix = prefix.replaceAll("[\\/:]+", "-"); + + // strip trailing replacement character + while (prefix.endsWith("-")) { + prefix = prefix.substring(0, prefix.length() - 1); + } + + String lookedUpNamespace = lookupNamespace.apply(prefix); + if (lookedUpNamespace == null || lookedUpNamespace.equals(namespace)) { + return prefix; + } else { + return devisePrefixTrySha256(namespace, lookupNamespace); + } + } + + // suggest an available prefix for the provided namespace (while considering pre-existing mappings) + private static String suggestPrefix(String namespace, UnaryOperator lookupPrefix) { + // try hard-wired map + String known = KNOWN_PREFIXES.get(namespace); + + // lookup using supplied mapper as well + String lookedUpNamespace = known != null ? lookupPrefix.apply(known) : null; + + // return hardwired prefix if unused or mapper has the prefix mapped to the same namespace + if (known != null && (lookedUpNamespace == null || namespace.equals(lookedUpNamespace))) { + return known; + } else { + return devisePrefix(namespace, lookupPrefix); + } + } } diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/flat/FilterIterator.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/flat/FilterIterator.java index 8b18b423ae9..417b0e44d76 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/flat/FilterIterator.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/flat/FilterIterator.java @@ -26,6 +26,7 @@ * @param * @deprecated use {@link org.apache.jackrabbit.commons.iterator.FilterIterator} */ +@Deprecated public class FilterIterator extends org.apache.jackrabbit.commons.iterator.FilterIterator { /** diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/flat/SizedIterator.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/flat/SizedIterator.java index da083efcd24..364f1701973 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/flat/SizedIterator.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/flat/SizedIterator.java @@ -23,5 +23,6 @@ * @param the type of elements of this iterator * @deprecated use {@link org.apache.jackrabbit.commons.iterator.SizedIterator} */ +@Deprecated public interface SizedIterator extends org.apache.jackrabbit.commons.iterator.SizedIterator { } diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/json/JsonHandler.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/json/JsonHandler.java index 0f55db30c47..3b71a4fb278 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/json/JsonHandler.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/json/JsonHandler.java @@ -21,7 +21,9 @@ /** * The JSONHandler interface receives notifications from the * JsonParser. + * @deprecated use JSON Processing API instead. */ +@Deprecated(since="2.24.0") public interface JsonHandler { /** diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/json/JsonParser.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/json/JsonParser.java index 529d48690b6..2433e83e493 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/json/JsonParser.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/json/JsonParser.java @@ -29,7 +29,9 @@ * JsonParser parses and validates the JSON object passed upon * {@link #parse(String)} or {@link #parse(InputStream, String)} and notifies * the specified JsonHandler + * @deprecated use JSON Processing API instead. */ +@Deprecated(since="2.24.0") public class JsonParser { private static final String NULL = "null"; diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/package-info.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/package-info.java index 42b3b486607..7eb2a8d1414 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/package-info.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/package-info.java @@ -14,5 +14,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@org.osgi.annotation.versioning.Version("2.4.0") +@org.osgi.annotation.versioning.Version("2.5.0") package org.apache.jackrabbit.commons; diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/repository/JNDIRepository.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/repository/JNDIRepository.java index c8eff32952b..ffd94138f6c 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/repository/JNDIRepository.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/repository/JNDIRepository.java @@ -24,9 +24,13 @@ * does not need to exist when this class is instantiated. The JNDI entry * can also be replaced with another repository during the lifetime of an * instance of this class. + *

+ * This class is deprecated and will be removed in future releases. * * @since 1.4 + * @deprecated use {@link ProxyRepository} instead */ +@Deprecated(forRemoval = true) public class JNDIRepository extends ProxyRepository { /** @@ -38,5 +42,4 @@ public class JNDIRepository extends ProxyRepository { public JNDIRepository(Context context, String name) { super(new JNDIRepositoryFactory(context, name)); } - } diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/repository/JNDIRepositoryFactory.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/repository/JNDIRepositoryFactory.java index 15646532644..c211c44444f 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/repository/JNDIRepositoryFactory.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/repository/JNDIRepositoryFactory.java @@ -21,11 +21,17 @@ import javax.naming.Context; import javax.naming.NamingException; +import static org.apache.jackrabbit.commons.JndiRepositoryFactory.JNDI_ENABLED; + /** * Factory that looks up a repository from JNDI. + *

+ * This class is deprecated and will be removed in future releases. * * @since 1.4 + * @deprecated use {@link org.apache.jackrabbit.commons.JndiRepositoryFactory} instead */ +@Deprecated(forRemoval = true) public class JNDIRepositoryFactory implements RepositoryFactory { /** @@ -56,25 +62,28 @@ public JNDIRepositoryFactory(Context context, String name) { * @throws RepositoryException if the repository can not be found */ public Repository getRepository() throws RepositoryException { - try { - Object repository = context.lookup(name); - if (repository instanceof Repository) { - return (Repository) repository; - } else if (repository == null) { - throw new RepositoryException( - "Repository not found: The JNDI entry " - + name + " is null"); - } else { + if (JNDI_ENABLED) { + try { + Object repository = context.lookup(name); + if (repository instanceof Repository) { + return (Repository) repository; + } else if (repository == null) { + throw new RepositoryException( + "Repository not found: The JNDI entry " + + name + " is null"); + } else { + throw new RepositoryException( + "Invalid repository: The JNDI entry " + + name + " is an instance of " + + repository.getClass().getName()); + } + } catch (NamingException e) { throw new RepositoryException( - "Invalid repository: The JNDI entry " - + name + " is an instance of " - + repository.getClass().getName()); + "Repository not found: The JNDI entry " + name + + " could not be looked up", e); } - } catch (NamingException e) { - throw new RepositoryException( - "Repository not found: The JNDI entry " + name - + " could not be looked up", e); } + return null; } } diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/XMLFactories.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/XMLFactories.java new file mode 100755 index 00000000000..925e379562f --- /dev/null +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/XMLFactories.java @@ -0,0 +1,77 @@ +/* + * 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. + */ +package org.apache.jackrabbit.commons.xml; + +import org.xml.sax.EntityResolver; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.IOException; + +/** + * Factory for "safe" instances of XML parsers (wrt XXE etc.). + */ +public class XMLFactories { + + private XMLFactories() { + } + + /** + * @return a "safe" {@link DocumentBuilderFactory} + */ + public static DocumentBuilderFactory safeDocumentBuilderFactory() { + // see https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html + + javax.xml.parsers.DocumentBuilderFactory factory = javax.xml.parsers.DocumentBuilderFactory.newInstance(); + + factory.setIgnoringComments(false); + factory.setIgnoringElementContentWhitespace(true); + factory.setXIncludeAware(false); + + // Prevent XXE attacks by disabling external entity processing + factory.setExpandEntityReferences(false); + + String feature = null; + + try { + feature = XMLConstants.FEATURE_SECURE_PROCESSING; + factory.setFeature(feature, true); + feature = "http://apache.org/xml/features/disallow-doctype-decl"; + factory.setFeature(feature, true); + feature = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; + factory.setFeature(feature, false); + feature = "http://xml.org/sax/features/external-general-entities"; + factory.setFeature(feature, false); + feature = "http://xml.org/sax/features/external-parameter-entities"; + factory.setFeature(feature, false); + } catch (Exception ex) { + // abort if secure processing is not supported + throw new IllegalStateException("Secure processing feature '" + feature + "' not supported by the DocumentBuilderFactory: " + factory.getClass().getName(), ex); + } + return factory; + } + + /** + * @return an {@link EntityResolver} which will always cause a parse exception. + */ + public static EntityResolver nonResolvingEntityResolver() { + return (publicId, systemId) -> { + throw new IOException("This parser does not support resolution of external entities (publicId: " + publicId + + ", systemId: " + systemId + ")"); + }; + } +} diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/package-info.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/package-info.java index 28b80f00b30..ff032b7bc45 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/package-info.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/package-info.java @@ -14,5 +14,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@org.osgi.annotation.versioning.Version("2.2") +@org.osgi.annotation.versioning.Version("2.3") package org.apache.jackrabbit.commons.xml; diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/package-info.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/package-info.java index 26f32fe40f9..3dae34a6ab9 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/package-info.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/package-info.java @@ -14,5 +14,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@org.osgi.annotation.versioning.Version("2.2") +@org.osgi.annotation.versioning.Version("2.3") package org.apache.jackrabbit; diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/Base64.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/Base64.java index f6708899252..ae2925f5719 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/Base64.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/Base64.java @@ -27,9 +27,17 @@ import java.io.Writer; import java.io.BufferedWriter; import java.nio.charset.StandardCharsets; +import java.util.Arrays; /** * Base64 provides Base64 encoding/decoding of strings and streams. + *

+ * NOTE: the decoder accepts invalid input (such as non-trailing padding characters) + * and just returns broken output (see JCR-5227). + *

+ * See RFC 4648, Section 4. + *

+ * See {@link java.util.Base64} for a better JDK alternative. */ public class Base64 { @@ -46,9 +54,7 @@ public class Base64 { static { // initialize decoding table - for (int i = 0; i < DECODETABLE.length; i++) { - DECODETABLE[i] = 0x7f; - } + Arrays.fill(DECODETABLE, (byte) 0x7f); // build decoding table for (int i = 0; i < BASE64CHARS.length; i++) { DECODETABLE[BASE64CHARS[i]] = (byte) i; @@ -65,11 +71,10 @@ private Base64() { } /** - * Base64-decodes or -encodes (see {@link #decodeOrEncode(String)} + * Base64-decodes or -encodes (see {@link #decodeOrEncode(String)}) * all the given arguments and prints the results on separate lines * in standard output. * - * @since Apache Jackrabbit 2.3 * @param args command line arguments to be decoded or encoded */ public static void main(String[] args) { @@ -80,10 +85,9 @@ public static void main(String[] args) { /** * Base64-decodes or -encodes the given string, depending on whether - * or not it contains a "{base64}" prefix. If the string gets encoded, + * it contains a "{base64}" prefix. If the string gets encoded, * the "{base64}" prefix is added to it. * - * @since Apache Jackrabbit 2.3 * @param data string to be decoded or encoded * @return decoded or encoded string */ @@ -101,7 +105,6 @@ public static String decodeOrEncode(String data) { * If the given string is null, then null * is returned. * - * @since Apache Jackrabbit 2.3 * @param data string to be decoded, can be null * @return the given string, possibly decoded */ @@ -233,7 +236,6 @@ public static void encode(byte[] data, int off, int len, Writer writer) /** * Returns the base64 representation of UTF-8 encoded string. * - * @since Apache Jackrabbit 2.3 * @param data the string to be encoded * @return base64-encoding of the string */ @@ -254,7 +256,6 @@ public static String encode(String data) { * The given string is returned as-is if it doesn't contain a valid * base64 encoding. * - * @since Apache Jackrabbit 2.3 * @param data the base64-encoded data to be decoded * @return decoded string */ @@ -262,7 +263,7 @@ public static String decode(String data) { try { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); decode(data, buffer); - return new String(buffer.toByteArray(), StandardCharsets.UTF_8); + return buffer.toString(StandardCharsets.UTF_8); } catch (IllegalArgumentException e) { return data; } catch (IOException e) { // should never happen @@ -325,6 +326,20 @@ public static void decode(char[] chars, OutputStream out) decode(chars, 0, chars.length, out); } + // utility methods to decode into 1st, 2nd and 3rd position of output + + private static byte decodeFirst(int b0, int b1) { + return (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3); + } + + private static byte decodeSecond(int b1, int b2) { + return (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf); + } + + private static byte decodeThird(int b2, int b3) { + return (byte) (b2 << 6 & 0xc0 | b3 & 0x3f); + } + /** * Decode base64 encoded data. * @@ -358,16 +373,16 @@ public static void decode(char[] chars, int off, int len, OutputStream out) int b2 = DECODETABLE[chunk[2]]; int b3 = DECODETABLE[chunk[3]]; if (chunk[3] == BASE64PAD && chunk[2] == BASE64PAD) { - dec[0] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3); + dec[0] = decodeFirst(b0, b1); out.write(dec, 0, 1); } else if (chunk[3] == BASE64PAD) { - dec[0] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3); - dec[1] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf); + dec[0] = decodeFirst(b0, b1); + dec[1] = decodeSecond(b1, b2); out.write(dec, 0, 2); } else { - dec[0] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3); - dec[1] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf); - dec[2] = (byte) (b2 << 6 & 0xc0 | b3 & 0x3f); + dec[0] = decodeFirst(b0, b1); + dec[1] = decodeSecond(b1, b2); + dec[2] = decodeThird(b2, b3); out.write(dec, 0, 3); } posChunk = 0; @@ -376,5 +391,31 @@ public static void decode(char[] chars, int off, int len, OutputStream out) throw new IllegalArgumentException("specified data is not base64 encoded"); } } + + // if there is an incomplete chunk... + if (posChunk != 0) { + boolean lastCharWasPad = chunk[posChunk - 1] == BASE64PAD; + if (lastCharWasPad) { + throw new IllegalArgumentException("specified data is not base64 encoded (input ends with unexpected pad character"); + } + + // handle missing padding gracefully, inspired by + // https://datatracker.ietf.org/doc/html/rfc7515#appendix-C + + if (posChunk == 1) { + throw new IllegalArgumentException("specified data is not base64 encoded (extra non-pad character"); + } + + if (posChunk == 2) { + // no padding, input length == 2; add two pad characters + chunk[2] = BASE64PAD; + chunk[3] = BASE64PAD; + } else { + // no padding, input length == 3: add one pad character + chunk[3] = BASE64PAD; + } + + decode(chunk, out); + } } } diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/Text.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/Text.java index 0b860bc904f..b6afc77c1da 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/Text.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/Text.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.BitSet; import java.util.Properties; +import java.util.Set; /** * This Class provides some text related utilities @@ -41,6 +42,8 @@ private Text() { */ public static final char[] hexTable = "0123456789abcdef".toCharArray(); + private static final Set INVALID_JCR_LOCAL_NAME_CHARS = Set.of( '/', ':', '[', ']', '*', '|'); + /** * Calculate an MD5 hash of the string given. * @@ -466,6 +469,10 @@ public static String unescape(String string) { * char ::= nonspace | ' ' * nonspace ::= (* Any Unicode character except: '/', ':', '[', ']', '*', '|' or any whitespace character *) * + *

+ * Note that just using this method does not necessarily return a string which is a + * valid local name. + * You still have to take care of invalid XML characters. * * @param name the name to escape * @return the escaped name @@ -567,6 +574,31 @@ public static String unescapeIllegalJcrChars(String name) { return buffer.toString(); } + /** + * Checks if the given name is a valid JCR local name. + *

+ * Note that the return value of {@link #escapeIllegalJcrChars(String)} is not necessarily a valid local name. + * You still have to take care of invalid XML characters. + * + * @param localName the string value to check + * @return true if the name is valid, false otherwise. + * @see JCR 2.0 Spec, §3.2.2 Local Names + * @see #escapeIllegalJcrChars(String) + * @since 2.6.0 (Apache Jackrabbit 2.24.0) + */ + public static boolean isValidJcrLocalName(String localName) { + if (localName == null || localName.isEmpty()) { + return false; + } + // self or parent are invalid + if (localName.equals(".") || localName.equals("..")) { + return false; + } + return localName.chars().noneMatch(c -> + INVALID_JCR_LOCAL_NAME_CHARS.contains((char) c) || !XMLChar.isValid(c) + ); + } + /** * Returns the name part of the path. If the given path is already a name * (i.e. contains no slashes) it is returned. diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/package-info.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/package-info.java index ebb06936161..ccfc068b292 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/package-info.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/package-info.java @@ -14,5 +14,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@org.osgi.annotation.versioning.Version("2.5.0") +@org.osgi.annotation.versioning.Version("2.6.0") package org.apache.jackrabbit.util; diff --git a/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/JcrUtilsTest.java b/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/JcrUtilsTest.java index a6a867112be..e44224ee333 100644 --- a/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/JcrUtilsTest.java +++ b/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/JcrUtilsTest.java @@ -51,20 +51,52 @@ public void testGetRepository() throws Exception { "java.naming.factory.initial", "org.osjava.sj.memory.MemoryContextFactory"); parameters.put("org.osjava.sj.jndi.shared", "true"); - assertTrue(repository == JcrUtils.getRepository(parameters)); + + // JDNI ist disabled by default + if (JndiRepositoryFactory.JNDI_ENABLED) { + assertTrue(repository == JcrUtils.getRepository(parameters)); + } else { + try { + JcrUtils.getRepository(parameters); + fail("Repository lookup should fail and throw an exception"); + } catch (RepositoryException expected) {} + } // Test lookup with URI query parameters - assertTrue(repository == JcrUtils.getRepository( - "jndi://x" - + "?org.apache.jackrabbit.repository.jndi.name=repository" - + "&org.osjava.sj.jndi.shared=true" - + "&java.naming.factory.initial" - + "=org.osjava.sj.memory.MemoryContextFactory")); + // JDNI ist disabled by default + if (JndiRepositoryFactory.JNDI_ENABLED) { + assertTrue(repository == JcrUtils.getRepository( + "jndi://x" + + "?org.apache.jackrabbit.repository.jndi.name=repository" + + "&org.osjava.sj.jndi.shared=true" + + "&java.naming.factory.initial" + + "=org.osjava.sj.memory.MemoryContextFactory")); + } else { + try { + JcrUtils.getRepository( + "jndi://x" + + "?org.apache.jackrabbit.repository.jndi.name=repository" + + "&org.osjava.sj.jndi.shared=true" + + "&java.naming.factory.initial" + + "=org.osjava.sj.memory.MemoryContextFactory"); + fail("Repository lookup should fail and throw an exception"); + } catch (RepositoryException expected) {} + } // Test lookup with the custom JNDI URI format (JCR-2771) - assertTrue(repository == JcrUtils.getRepository( - "jndi://org.osjava.sj.memory.MemoryContextFactory/repository" - + "?org.osjava.sj.jndi.shared=true")); + // JDNI ist disabled by default + if (JndiRepositoryFactory.JNDI_ENABLED) { + assertTrue(repository == JcrUtils.getRepository( + "jndi://org.osjava.sj.memory.MemoryContextFactory/repository" + + "?org.osjava.sj.jndi.shared=true")); + } else { + try { + JcrUtils.getRepository( + "jndi://org.osjava.sj.memory.MemoryContextFactory/repository" + + "?org.osjava.sj.jndi.shared=true"); + fail("Repository lookup should fail and throw an exception"); + } catch (RepositoryException expected) {} + } try { JcrUtils.getRepository( diff --git a/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/NamespaceHelperTest.java b/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/NamespaceHelperTest.java new file mode 100644 index 00000000000..7db200b622a --- /dev/null +++ b/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/NamespaceHelperTest.java @@ -0,0 +1,362 @@ +/* + * 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. + */ +package org.apache.jackrabbit.commons; + +import junit.framework.TestCase; +import org.mockito.Mockito; + +import javax.jcr.NamespaceException; +import javax.jcr.NamespaceRegistry; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.Workspace; +import java.util.HashMap; +import java.util.Map; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +public class NamespaceHelperTest extends TestCase { + + private Session session; + + @Override + protected void setUp() throws Exception { + super.setUp(); + session = Mockito.mock(Session.class); + } + + public void testGetNamespaces() throws RepositoryException { + NamespaceHelper nsHelper = new NamespaceHelper(session); + + when(session.getNamespacePrefixes()).thenReturn(new String[0]); + Map map = nsHelper.getNamespaces(); + assertEquals(0, map.size()); + + when(session.getNamespacePrefixes()).thenReturn(new String[]{"foo"}); + map = nsHelper.getNamespaces(); + assertEquals(1, map.size()); + assertNull(map.get("foo")); + + when(session.getNamespacePrefixes()).thenReturn(new String[]{"foo", "bar"}); + when(session.getNamespaceURI("bar")).thenReturn("urn:test"); + map = nsHelper.getNamespaces(); + assertEquals(2, map.size()); + assertNull(map.get("foo")); + assertEquals("urn:test", map.get("bar")); + } + + public void testGetPrefix() throws RepositoryException { + NamespaceHelper nsHelper = new NamespaceHelper(session); + + String uri1 = "urn:test1"; + + when(session.getNamespacePrefix(uri1)).thenThrow(NamespaceException.class); + String prefix = nsHelper.getPrefix(uri1); + assertNull(prefix); + + String uri2 = "urn:test2"; + + when(session.getNamespacePrefix(uri2)).thenReturn("foo"); + prefix = nsHelper.getPrefix(uri2); + assertEquals("foo", prefix); + } + + public void testGetURI() throws RepositoryException { + NamespaceHelper nsHelper = new NamespaceHelper(session); + + String prefix1 = "prefix1"; + + when(session.getNamespaceURI(prefix1)).thenThrow(NamespaceException.class); + String uri = nsHelper.getURI(prefix1); + assertNull(uri); + + String prefix2 = "prefix2"; + + when(session.getNamespaceURI(prefix2)).thenReturn("foo:bar"); + uri = nsHelper.getURI(prefix2); + assertEquals("foo:bar", uri); + } + + public void testGetJcrName() throws RepositoryException { + NamespaceHelper nsHelper = new NamespaceHelper(session); + + when(session.getNamespacePrefix(NamespaceHelper.JCR)).thenReturn("jcr"); + assertEquals("jcr:xyz", nsHelper.getJcrName("jcr:xyz")); + + when(session.getNamespacePrefix(NamespaceHelper.MIX)).thenReturn("foo"); + assertEquals("foo:xyz", nsHelper.getJcrName("mix:xyz")); + + try { + when(session.getNamespacePrefix("urn:foo")).thenReturn("unknown"); + String shouldFail = nsHelper.getJcrName("foo:xyz"); + fail("getJcrName should fail for unknown prefix foo, but got: " + shouldFail); + } catch (IllegalArgumentException expected) { + // all good + } + + try { + when(session.getNamespacePrefix(NamespaceHelper.NT)).thenThrow(NamespaceException.class); + String shouldFail = nsHelper.getJcrName(NamespaceHelper.NT); + fail("getJcrName should fail for unknown prefix nt, but got: " + shouldFail); + } catch (IllegalArgumentException expected) { + // all good + } + } + + public void testGetJcrName2() throws RepositoryException { + NamespaceHelper nsHelper = new NamespaceHelper(session); + + assertEquals("foo", nsHelper.getJcrName(null, "foo")); + assertEquals("foo", nsHelper.getJcrName("", "foo")); + + when(session.getNamespacePrefix("urn:bar")).thenReturn("bar"); + assertEquals("bar:foo", nsHelper.getJcrName("urn:bar", "foo")); + } + + public void testRegisterNamespaceAlreadyRegistered() throws RepositoryException { + NamespaceHelper nsHelper = new NamespaceHelper(session); + + Workspace workspace = Mockito.mock(Workspace.class); + NamespaceRegistry nsReg = Mockito.mock(NamespaceRegistry.class); + + when(session.getWorkspace()).thenReturn(workspace); + when(workspace.getNamespaceRegistry()).thenReturn(nsReg); + + when(nsReg.getPrefix("foo:")).thenReturn("xyz"); + when(session.getNamespacePrefix("foo:")).thenReturn("xyz"); + String prefix = nsHelper.registerNamespace("bar", "foo:"); + assertEquals("xyz", prefix); + } + + public void testRegisterNamespaceDeriving() throws RepositoryException { + Workspace workspace = Mockito.mock(Workspace.class); + NamespaceRegistry nsReg = mockNamespaceRegistry(); + Session session = mockSessionWithoutSessionMappings(); + + when(session.getWorkspace()).thenReturn(workspace); + when(workspace.getNamespaceRegistry()).thenReturn(nsReg); + NamespaceHelper nsHelper = new NamespaceHelper(session); + + // check deriving from namespace name + assertEquals("example.com-foo", nsHelper.registerNamespace(null, "https://ns.example.com/foo")); + + // check deriving from namespace name with prefix already taken, hash used instead + assertEquals("s-12a490e", nsHelper.registerNamespace(null, "http://www.example.com/foo")); + + // nasty: computed hash already used as prefix + assertEquals("example.com-bar", nsHelper.registerNamespace(null, "http://www.example.com/bar")); + assertEquals("s-b2e675c", nsHelper.registerNamespace("s-b2e675c", "ouch:")); + // returned prefix uses the SHA, but one more character + assertEquals("s-b2e675c8", nsHelper.registerNamespace(null, "example.com/bar")); + } + + public void testRegisterNamespaceKnownMapping() throws RepositoryException { + Workspace workspace = Mockito.mock(Workspace.class); + NamespaceRegistry nsReg = mockNamespaceRegistry(); + Session session = mockSessionWithoutSessionMappings(); + + when(session.getWorkspace()).thenReturn(workspace); + when(workspace.getNamespaceRegistry()).thenReturn(nsReg); + NamespaceHelper nsHelper = new NamespaceHelper(session); + + // check deriving from namespace name + assertEquals("example.com-foo", nsHelper.registerNamespace(null, "https://ns.example.com/foo")); + } + + public void testRegisterNamespaceSimple() throws RepositoryException { + Workspace workspace = Mockito.mock(Workspace.class); + NamespaceRegistry nsReg = mockNamespaceRegistry(); + Session session = mockSessionWithoutSessionMappings(); + + when(session.getWorkspace()).thenReturn(workspace); + when(workspace.getNamespaceRegistry()).thenReturn(nsReg); + NamespaceHelper nsHelper = new NamespaceHelper(session); + + // simple cases + assertEquals("foo", nsHelper.registerNamespace("", "foo:")); + assertEquals("foo2", nsHelper.registerNamespace("", "foo2:")); + + // suggested prefix will be ignored because it is illegal, so a new prefix is generated + assertEquals("foo3", nsHelper.registerNamespace("xmlxxx", "foo3:")); + + // suggested prefix will be ignored because it is illegal, so a new prefix is generated + assertEquals("foo4", nsHelper.registerNamespace("123", "foo4:")); + + // suggested prefix will be ignored because it is illegal, however the namespace name already is mapped + assertEquals("foo3", nsHelper.registerNamespace("xmlxxx", "foo3:")); + + // null prefix, handled like illegal prefix, namespace name is new thus new prefix + assertEquals("foo6", nsHelper.registerNamespace(null, "foo6:")); + + // simple case: new namespace name, new prefix + assertEquals("bar", nsHelper.registerNamespace("bar", "bar:")); + + // suggested prefix already is mapped to a different namespace, derive new one based on namespace name + assertEquals("bar2", nsHelper.registerNamespace("bar", "bar2:")); + + // repeat + assertEquals("bar3", nsHelper.registerNamespace("bar", "bar3:")); + + // check invocation count for getNamespaceRegistry (JCR-5161) + Mockito.verify(workspace, Mockito.times(1)).getNamespaceRegistry(); + } + + public void testRegisterNamespacePreferredPrefixTaken() throws RepositoryException { + Workspace workspace = Mockito.mock(Workspace.class); + NamespaceRegistry nsReg = mockNamespaceRegistry(); + Session session = mockSessionWithoutSessionMappings(); + + when(session.getWorkspace()).thenReturn(workspace); + when(workspace.getNamespaceRegistry()).thenReturn(nsReg); + NamespaceHelper nsHelper = new NamespaceHelper(session); + + // nasty: registering a preferred namespace prefix, fall back to namespace name based prefix generation + assertEquals("xmp", nsHelper.registerNamespace("xmp", "xmp-ouch:")); + assertEquals("adobe.com-xap-1.0", nsHelper.registerNamespace(null, "http://ns.adobe.com/xap/1.0/")); + } + + public void testRegisterNamespaceImmutableMappings() throws RepositoryException { + Workspace workspace = Mockito.mock(Workspace.class); + NamespaceRegistry nsReg = mockNamespaceRegistry(); + Session session = mockSessionWithoutSessionMappings(); + + when(session.getWorkspace()).thenReturn(workspace); + when(workspace.getNamespaceRegistry()).thenReturn(nsReg); + NamespaceHelper nsHelper = new NamespaceHelper(session); + + // attempt to register over immutable mappings returns hardwired prefix + assertEquals("jcr", nsHelper.registerNamespace("wtf", NamespaceRegistry.NAMESPACE_JCR)); + assertEquals("xml", nsHelper.registerNamespace("", NamespaceRegistry.NAMESPACE_XML)); + } + + public void testRegisterNamespaceProblematicNames() throws RepositoryException { + Workspace workspace = Mockito.mock(Workspace.class); + NamespaceRegistry nsReg = mockNamespaceRegistry(); + Session session = mockSessionWithoutSessionMappings(); + + when(session.getWorkspace()).thenReturn(workspace); + when(workspace.getNamespaceRegistry()).thenReturn(nsReg); + NamespaceHelper nsHelper = new NamespaceHelper(session); + + // problematic trailing chars + assertEquals("urn-xyz", nsHelper.registerNamespace("", "urn:xyz::")); + // would be same prefix after removing trailing problems, thus falling back to hash + assertEquals("s-98cf7c3", nsHelper.registerNamespace("", "urn:xyz:::")); + } + + public void testRegisterMultipleNamespaces() throws RepositoryException { + Workspace workspace = Mockito.mock(Workspace.class); + NamespaceRegistry nsReg = mockNamespaceRegistry(); + Session session = mockSessionWithoutSessionMappings(); + + when(session.getWorkspace()).thenReturn(workspace); + when(workspace.getNamespaceRegistry()).thenReturn(nsReg); + NamespaceHelper nsHelper = new NamespaceHelper(session); + + Map input = Map.of("test1", "test1:", "test2", "test2", "", "test3:"); + nsHelper.registerNamespaces(input); + + // registered prefixes as suggested + assertEquals("test1", nsReg.getPrefix("test1:")); + + // test2 is invalid namespace name, but reluctantly accepted + assertEquals("test2", nsReg.getPrefix("test2")); + + // no prefix suggested, prefix derived from namespace name + assertEquals("test3", nsReg.getPrefix("test3:")); + } + + // poor man's namespace registry + + private Map pref2uri = new HashMap<>(); + private Map uri2pref = new HashMap<>(); + + private NamespaceRegistry mockNamespaceRegistry() throws RepositoryException { + NamespaceRegistry result = Mockito.mock(NamespaceRegistry.class); + + // defaults (incomplete) + pref2uri.put("xml", NamespaceRegistry.NAMESPACE_XML); + uri2pref.put(NamespaceRegistry.NAMESPACE_XML, "xml"); + pref2uri.put("jcr", NamespaceRegistry.NAMESPACE_JCR); + uri2pref.put(NamespaceRegistry.NAMESPACE_JCR, "jcr"); + + Mockito.doAnswer(invocation -> { + String rpref = invocation.getArgument(0); + String rname = invocation.getArgument(1); + if (null != uri2pref.get(rname)) { + throw new NamespaceException("namespace name '" + rname + "' already registered"); + } else if (null != pref2uri.get(rpref)) { + throw new NamespaceException("namespace prefix '" + rpref + "' already registered"); + } else { + pref2uri.put(rpref, rname); + uri2pref.put(rname, rpref); + return null; + } + }).when(result).registerNamespace(any(), any()); + + when(result.getPrefix(any())).thenAnswer(invocation -> { + String name = invocation.getArgument(0); + String found = uri2pref.get(name); + if (found != null) { + return found; + } else { + throw new NamespaceException("namespace name '" + name + "' not registered"); + } + }); + + when(result.getURI(any())).thenAnswer(invocation -> { + String prefix = invocation.getArgument(0); + String found = pref2uri.get(prefix); + if (found != null) { + return found; + } else { + throw new NamespaceException("namespace prefix '" + prefix + "' not registered"); + } + }); + + return result; + } + + private Session mockSessionWithoutSessionMappings() throws RepositoryException { + Session result = Mockito.mock(Session.class); + + // no session-local mappings + + when(result.getNamespacePrefix(any())).thenAnswer(invocation -> { + String namespace = invocation.getArgument(0); + String found = uri2pref.get(namespace); + if (found != null) { + return found; + } else { + throw new NamespaceException("no mapping found for namespace '" + namespace + "'"); + } + }); + + when(result.getNamespaceURI(any())).thenAnswer(invocation -> { + String prefix = invocation.getArgument(0); + String found = pref2uri.get(prefix); + if (found != null) { + return found; + } else { + throw new NamespaceException("no mapping found for prefix '" + prefix + "'"); + } + }); + + return result; + } +} diff --git a/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/Base64Test.java b/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/Base64Test.java index ac1b461d80b..c79ef15d90c 100644 --- a/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/Base64Test.java +++ b/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/Base64Test.java @@ -18,19 +18,20 @@ import junit.framework.TestCase; -import java.io.IOException; import java.io.StringWriter; import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; import java.util.Random; -import java.util.Arrays; + +import static org.junit.Assert.assertArrayEquals; /** * Test cases for Base64 encode / decode. */ public class Base64Test extends TestCase { - private Random _random = new Random(); + private final Random _random = new Random(); /** * @return Returns the _random. @@ -45,8 +46,7 @@ protected Random getRandom() { public void testWhitespace() throws Exception { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); Base64.decode(" d G\tV \tzdA\n= =\n", buffer); - byte[] data = buffer.toByteArray(); - assertEquals("test", new String(data, "US-ASCII")); + assertEquals("test", buffer.toString(StandardCharsets.US_ASCII)); } /** @@ -71,7 +71,7 @@ public void testBase64Streaming() throws Exception { baos = new ByteArrayOutputStream(); Base64.decode(new ByteArrayInputStream(encData), baos); byte[] decData = baos.toByteArray(); - assertTrue(Arrays.equals(data, decData)); + assertArrayEquals(data, decData); } private void base64RoundTrip() throws Exception { @@ -98,26 +98,71 @@ private void base64RoundTrip(byte[] ba) throws Exception { } } - public void testDecodeOrEncode() throws IOException { + public void testDecodeOrEncode() { assertEquals("", Base64.decodeOrEncode(Base64.decodeOrEncode(""))); assertEquals("test", Base64.decodeOrEncode(Base64.decodeOrEncode("test"))); assertEquals("{base64}dGVzdA==", Base64.decodeOrEncode("test")); assertEquals("test", Base64.decodeOrEncode("{base64}dGVzdA==")); } - public void testDecodeIfEncoded() throws IOException { - assertEquals(null, Base64.decodeIfEncoded(null)); + public void testDecodeIfEncoded() { + assertNull(Base64.decodeIfEncoded(null)); assertEquals("", Base64.decodeIfEncoded("")); assertEquals("", Base64.decodeIfEncoded("{base64}")); assertEquals("test", Base64.decodeIfEncoded("test")); assertEquals("test", Base64.decodeIfEncoded("{base64}dGVzdA==")); } - public void testStringEncodeDecode() throws IOException { + public void testStringEncodeDecode() { assertEquals("", Base64.decode(Base64.encode(""))); assertEquals("test", Base64.decode(Base64.encode("test"))); assertEquals("dGVzdA==", Base64.encode("test")); assertEquals("test", Base64.decode("dGVzdA==")); } + public void testStringDecodeNoPadding() { + // no padding variants tested in comparison to padded ones + // https://datatracker.ietf.org/doc/html/rfc4648#section-10 + + assertEquals("foob", Base64.decode("Zm9vYg==")); + assertEquals("foob", Base64.decode("Zm9vYg")); + + assertEquals("fooba", Base64.decode("Zm9vYmE=")); + assertEquals("fooba", Base64.decode("Zm9vYmE")); + } + + public void testStringDecodeBrokenPadding() { + // incorrect number of padding characters (when padding, the total + // length needs to be a multiple of 4) + + // confirming with jdk decoder + try { + java.util.Base64.getDecoder().decode("Zm9vYg"); + } catch (IllegalArgumentException expected) { + } + + // Jackrabbit API is weird; for broken input, it just returns + // the input + assertEquals("Zm9vYg=", Base64.decode("Zm9vYg=")); + } + + public void testStringIllegalExtraChar() { + // last (4 byte) chunk of length 1 + // test with pad and non-pad + + // confirming with jdk decoder + try { + java.util.Base64.getDecoder().decode("extra"); + } catch (IllegalArgumentException expected) { + } + try { + java.util.Base64.getDecoder().decode("extr="); + } catch (IllegalArgumentException expected) { + } + + // Jackrabbit API is weird; for broken input, it just returns + // the input + assertEquals("extra", Base64.decode("extra")); + assertEquals("extr=", Base64.decode("extr=")); + } } \ No newline at end of file diff --git a/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/TextTest.java b/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/TextTest.java index 1375aff26ff..6d034c3834c 100644 --- a/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/TextTest.java +++ b/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/TextTest.java @@ -202,4 +202,14 @@ public void testEscapeXML() { public void testEscapeHTML() { assertEquals("&<>'"", Text.encodeIllegalHTMLCharacters("&<>'\"")); } + + public void testIsValidJcrLocalName() { + assertTrue(Text.isValidJcrLocalName("valid%Name..\n\r test.\"'")); + assertFalse(Text.isValidJcrLocalName("invalid|name")); + assertFalse(Text.isValidJcrLocalName("some:name")); + // containing non XML characters (unicode control character) + assertFalse(Text.isValidJcrLocalName("\u000FinvalidName")); + assertFalse(Text.isValidJcrLocalName("..")); + assertFalse(Text.isValidJcrLocalName(".")); + } } diff --git a/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/xml/XMLFactoriesTest.java b/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/xml/XMLFactoriesTest.java new file mode 100755 index 00000000000..519b9328601 --- /dev/null +++ b/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/xml/XMLFactoriesTest.java @@ -0,0 +1,84 @@ +/* + * 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. + */ +package org.apache.jackrabbit.xml; + +import org.apache.jackrabbit.commons.xml.XMLFactories; +import org.junit.Test; +import org.w3c.dom.Document; +import org.xml.sax.EntityResolver; +import org.xml.sax.SAXParseException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; +import java.util.UUID; + +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +public class XMLFactoriesTest { + + String randomName = UUID.randomUUID().toString(); + + String xxeXml = + "\n" + + " ]>\n" + + "&xxe;"; + + @Test + // verify that default builder is vulnerable + public void testDefaultParserDoesResolveExternalEntities() throws Exception { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = null; + + try (ByteArrayInputStream input = new ByteArrayInputStream(xxeXml.getBytes())) { + doc = db.parse(input); + } catch (FileNotFoundException expected) { + assertTrue("FileNotFoundException message should contain file name '" + + randomName + "', but was: '" + expected.getMessage() + "'", expected.getMessage().contains(randomName)); + } + + assertNull("There should be no doc: " + doc, doc); + } + + @Test + // verify that utility builder is not vulnerable + public void testParserDoesNotResolveExternalEntities() throws Exception { + DocumentBuilderFactory dbf = XMLFactories.safeDocumentBuilderFactory(); + + DocumentBuilder db = dbf.newDocumentBuilder(); + + try (ByteArrayInputStream input = new ByteArrayInputStream(xxeXml.getBytes())) { + db.parse(input); + } catch (SAXParseException expected) { + // all good + } + } + + @Test + public void testSafeEntityResolver() { + EntityResolver test = XMLFactories.nonResolvingEntityResolver(); + assertThrows(Exception.class, () -> test.resolveEntity("-//The Apache Software Foundation//DTD Jackrabbit 1.6//EN" , + "http://jackrabbit.apache.org/dtd/repository-1.6.dtd")); + } +} diff --git a/jackrabbit-jcr-server/pom.xml b/jackrabbit-jcr-server/pom.xml index e77160aa379..500842ef6de 100644 --- a/jackrabbit-jcr-server/pom.xml +++ b/jackrabbit-jcr-server/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-jcr-server @@ -34,6 +34,12 @@ WebDAV server implementations for JCR bundle + + false + 0.10 + 0.09 + + diff --git a/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/ProtectedRemoveManager.java b/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/ProtectedRemoveManager.java index f6e3f785a54..3e85135c688 100644 --- a/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/ProtectedRemoveManager.java +++ b/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/ProtectedRemoveManager.java @@ -21,6 +21,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; @@ -91,14 +92,10 @@ ProtectedItemRemoveHandler createHandler(String className) { if (!className.isEmpty()) { Class irHandlerClass = Class.forName(className); if (ProtectedItemRemoveHandler.class.isAssignableFrom(irHandlerClass)) { - irHandler = (ProtectedItemRemoveHandler) irHandlerClass.newInstance(); + irHandler = (ProtectedItemRemoveHandler) irHandlerClass.getDeclaredConstructor().newInstance(); } } - } catch (ClassNotFoundException e) { - log.error(e.getMessage(), e); - } catch (InstantiationException e) { - log.error(e.getMessage(), e); - } catch (IllegalAccessException e) { + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { log.error(e.getMessage(), e); } return irHandler; diff --git a/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/util/HttpMultipartPost.java b/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/util/HttpMultipartPost.java index 26b1cb7c54e..30ca4e831d0 100644 --- a/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/util/HttpMultipartPost.java +++ b/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/util/HttpMultipartPost.java @@ -45,6 +45,10 @@ class HttpMultipartPost { private final Map> nameToItems = new LinkedHashMap>(); private final Set fileParamNames = new HashSet(); + // <= 0 (default -1) -> Jackrabbit applies 4096 (overrides cfup 1.6's current 512-byte default); + // positive -> exact value in bytes. Set to 512 to restore the library's own default. + private final int PARTHEADERSIZEMAX = Integer.getInteger("jackrabbit-server-PartHeaderSizeMax", -1); + private boolean initialized; HttpMultipartPost(HttpServletRequest request, File tmpDir) throws IOException { @@ -65,6 +69,12 @@ private void extractMultipart(HttpServletRequest request, File tmpDir) } ServletFileUpload upload = new ServletFileUpload(getFileItemFactory(tmpDir)); + if (PARTHEADERSIZEMAX > 0) { + upload.setPartHeaderSizeMax(PARTHEADERSIZEMAX); + } else { + // override the default limit of 512 in commons-fileupload 1.6 + upload.setPartHeaderSizeMax(4096); + } // make sure the content disposition headers are read with the charset // specified in the request content type (or UTF-8 if no charset is specified). // see JCR @@ -246,18 +256,6 @@ String[] getParameterValues(String name) { } } - /** - * Returns a set of the file parameter names. An empty set if - * no file parameters were present in the request. - * - * @return an set of file item names representing the file - * parameters available with the request. - */ - Set getFileParameterNames() { - checkInitialized(); - return fileParamNames; - } - /** * Returns an array of input streams for uploaded file parameters. * diff --git a/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/JcrValueType.java b/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/JcrValueType.java index 9d941c551d5..5f119377ee1 100644 --- a/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/JcrValueType.java +++ b/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/JcrValueType.java @@ -20,6 +20,7 @@ * * @deprecated As of Jackrabbit 2.2. Please Use {@link org.apache.jackrabbit.commons.webdav.JcrValueType} instead. */ +@Deprecated public final class JcrValueType extends org.apache.jackrabbit.commons.webdav.JcrValueType { } \ No newline at end of file diff --git a/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/property/LengthsProperty.java b/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/property/LengthsProperty.java index fb1ef82a90b..ebd1b9bce12 100644 --- a/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/property/LengthsProperty.java +++ b/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/property/LengthsProperty.java @@ -23,7 +23,7 @@ import org.w3c.dom.Element; /** - * LengthsProperty extends {@link org.apache.jackrabbit.webdav.property.DavProperty} providing + * {@code LengthsProperty} extends {@link org.apache.jackrabbit.webdav.property.DavProperty} providing * utilities to handle the multiple lengths of the property item represented * by this resource. */ @@ -32,7 +32,7 @@ public class LengthsProperty extends AbstractDavProperty implements Item private final long[] value; /** - * Create a new LengthsProperty from the given long array. + * Create a new {@code LengthsProperty} from the given long array. * * @param lengths as retrieved from the JCR property */ @@ -42,10 +42,10 @@ public LengthsProperty(long[] lengths) { } /** - * Returns an array of {@link long}s representing the value of this + * Returns an array of {@code long}s representing the value of this * property. * - * @return an array of {@link long}s + * @return an array of {@code long}s */ public long[] getValue() { return value; diff --git a/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/simple/ResourceConfig.java b/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/simple/ResourceConfig.java index 1292b129ce3..defe7a522bb 100644 --- a/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/simple/ResourceConfig.java +++ b/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/simple/ResourceConfig.java @@ -351,7 +351,7 @@ private static Object buildClassFromConfig(Element parent) { String className = DomUtil.getAttribute(classElem, "name", null); if (className != null) { Class c = Class.forName(className); - instance = c.newInstance(); + instance = c.getDeclaredConstructor().newInstance(); } else { log.error("Invalid configuration: missing 'class' element"); } diff --git a/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/util/RequestDataTest.java b/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/util/RequestDataTest.java new file mode 100755 index 00000000000..36d59c55a3c --- /dev/null +++ b/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/util/RequestDataTest.java @@ -0,0 +1,249 @@ +/* + * 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. + */ +package org.apache.jackrabbit.server.util; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.collections4.IteratorUtils; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.io.File; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.*; + +import javax.servlet.ServletInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +@RunWith(MockitoJUnitRunner.class) +public class RequestDataTest { + + @Rule + public TemporaryFolder tempFolder = new TemporaryFolder(); + + @Mock + private HttpServletRequest mockRequest; + + /** + * Helper to wrap raw multipart text bytes cleanly into a mock ServletInputStream. + */ + private ServletInputStream createServletInputStream(final byte[] payload) { + final ByteArrayInputStream bais = new ByteArrayInputStream(payload); + return new ServletInputStream() { + @Override + public int read() { + return bais.read(); + } + + @Override + public boolean isFinished() { + return bais.available() == 0; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(javax.servlet.ReadListener readListener) { + throw new UnsupportedOperationException("Non-blocking I/O not implemented in mock"); + } + }; + } + + /** + * Verifies standard parsing works smoothly using the clean temp directory assignment. + */ + @Test + public void getParameterWithStandardRequest() throws Exception { + File testTmpDir = tempFolder.newFolder("jackrabbit_standard_tmp"); + + // ONLY stub what is actually called by RequestData for a standard request + // when(mockRequest.getParameter("param1")).thenReturn("value1"); + when(mockRequest.getParameterValues("param1")).thenReturn(new String[]{"value1"}); + + RequestData requestData = new RequestData(mockRequest, testTmpDir); + + try { + String[] values = requestData.getParameterValues("param1"); + assertNotNull("Parameter array should not be null", values); + assertEquals("Value mismatch", "value1", values[0]); + } finally { + requestData.dispose(); + } + } + + /** + * Test multipart POST requests consisting of multiple body parameters. + */ + @Test + public void testMultipartPostWithMultipleParts() throws Exception { + File testTmpDir = tempFolder.newFolder("jackrabbit_multi_parts"); + + String boundary = "----MockBoundary123"; + String body = "--" + boundary + "\r\n" + + "Content-Disposition: form-data; name=\"textField\"\r\n\r\n" + + "textValue\r\n" + + "--" + boundary + "\r\n" + + "Content-Disposition: form-data; name=\"fileField\"; filename=\"test.txt\"\r\n" + + "Content-Type: text/plain\r\n\r\n" + + "Hello World Item Data\r\n" + + "--" + boundary + "--\r\n"; + byte[] payloadBytes = body.getBytes(StandardCharsets.UTF_8); + + // For multipart requests, these methods are genuinely called by Jackrabbit's parser + when(mockRequest.getMethod()).thenReturn("POST"); + when(mockRequest.getContentType()).thenReturn("multipart/form-data; boundary=" + boundary); + lenient().when(mockRequest.getCharacterEncoding()).thenReturn("UTF-8"); + when(mockRequest.getInputStream()).thenReturn(createServletInputStream(payloadBytes)); + + RequestData requestData = new RequestData(mockRequest, testTmpDir); + try { + assertEquals("textValue", requestData.getParameter("textField")); + assertNotNull("Multipart file field must map", requestData.getParameter("fileField")); + assertEquals(Set.of("fileField", "textField"), IteratorUtils.toSet(requestData.getParameterNames())); + assertEquals(List.of("text/plain"), Arrays.asList(requestData.getParameterTypes("fileField"))); + assertNull(requestData.getParameterTypes("textField")[0]); + assertEquals(1, requestData.getParameterTypes("textField").length); + + InputStream[] streams = requestData.getFileParameters("fileField"); + assertEquals(1, streams.length); + assertEquals("Hello World Item Data", new String(streams[0].readAllBytes(), StandardCharsets.UTF_8)); + + assertNull("Multipart file field must map", requestData.getParameter("x")); + assertNull(requestData.getFileParameters("x")); + assertNull(requestData.getParameterTypes("x")); + assertNull(requestData.getParameterValues("x")); + } finally { + requestData.dispose(); + } + } + + /** + * Test data parsing performance against inflated MIME/Header padding sizes. + */ + // @Test + public void testMultipartPostWithLargeHeaders() throws Exception { + File testTmpDir = tempFolder.newFolder("jackrabbit_large_headers"); + String boundary = "----MockBoundaryLargeHeaders"; + + String body = "--" + boundary + "\r\n" + + "Content-Disposition: form-data; name=\"payloadField\"\r\n" + + "X-Long-Header: " + "X-Header-Padding-Data-String-".repeat(1000) + "\r\n\r\n" + + "ShortBodyContent\r\n" + + "--" + boundary + "--\r\n"; + byte[] payloadBytes = body.getBytes(StandardCharsets.UTF_8); + + when(mockRequest.getMethod()).thenReturn("POST"); + when(mockRequest.getContentType()).thenReturn("multipart/form-data; boundary=" + boundary); + lenient().when(mockRequest.getCharacterEncoding()).thenReturn("UTF-8"); + when(mockRequest.getInputStream()).thenReturn(createServletInputStream(payloadBytes)); + + RequestData requestData = new RequestData(mockRequest, testTmpDir); + try { + assertEquals("ShortBodyContent", requestData.getParameter("payloadField")); + } finally { + requestData.dispose(); + } + } + + private void buildRequestWithFilenameOfVaryingLength(int length) throws IOException { + String boundary = "----MockBoundaryLongFilename"; + + String longFilename = "0123456789".repeat(length / 10) + ".tmp"; + + String body = "--" + boundary + "\r\n" + + "Content-Disposition: form-data; name=\"fileUpload\"; filename=\"" + longFilename + "\"\r\n" + + "Content-Type: application/octet-stream\r\n\r\n" + + "FileContentStreamData\r\n" + + "--" + boundary + "--\r\n"; + byte[] payloadBytes = body.getBytes(StandardCharsets.UTF_8); + + when(mockRequest.getMethod()).thenReturn("POST"); + when(mockRequest.getContentType()).thenReturn("multipart/form-data; boundary=" + boundary); + lenient().when(mockRequest.getCharacterEncoding()).thenReturn("UTF-8"); + when(mockRequest.getInputStream()).thenReturn(createServletInputStream(payloadBytes)); + } + + // test default limits in commons-fileuploads + + @Test + public void testMultipartPostWithShorterFilename() throws Exception { + buildRequestWithFilenameOfVaryingLength(400); + File testTmpDir = tempFolder.newFolder("jackrabbit_long_filename"); + RequestData requestData = new RequestData(mockRequest, testTmpDir); + try { + assertTrue( + requestData.getParameter("fileUpload").length() > 350); + } finally { + requestData.dispose(); + } + } + + @Test(expected = IOException.class) + public void testMultipartPostWithExtremelyLongFilename() throws Exception { + // header bytes ~= filename length + ~107; at 5000 chars this far exceeds the 4096 default + buildRequestWithFilenameOfVaryingLength(5000); + File testTmpDir = tempFolder.newFolder("jackrabbit_long_filename"); + new RequestData(mockRequest, testTmpDir); // must throw IOException + } + + @Test + public void testMultipartPostWithLongFilenameUnderNewDefault() throws Exception { + buildRequestWithFilenameOfVaryingLength(3800); // above 512, below 4096 + File testTmpDir = tempFolder.newFolder("jackrabbit_medium_filename"); + RequestData requestData = new RequestData(mockRequest, testTmpDir); + try { + assertTrue(requestData.getParameter("fileUpload").length() > 3800); + } finally { + requestData.dispose(); + } + } + + @Test + public void testMultipartPostWithExtremelyLongFilenameWithHigherConfig() throws Exception { + try { + System.setProperty("jackrabbit-server-PartHeaderSizeMax", "8192"); + buildRequestWithFilenameOfVaryingLength(7500); + File testTmpDir = tempFolder.newFolder("jackrabbit_long_filename"); + RequestData requestData = new RequestData(mockRequest, testTmpDir); + try { + assertTrue( + requestData.getParameter("fileUpload").length() > 7500); + } finally { + requestData.dispose(); + } + } finally { + System.clearProperty("jackrabbit-server-PartHeaderSizeMax"); + } + } +} \ No newline at end of file diff --git a/jackrabbit-jcr-servlet/pom.xml b/jackrabbit-jcr-servlet/pom.xml index b02b2476ee5..d8e46174998 100644 --- a/jackrabbit-jcr-servlet/pom.xml +++ b/jackrabbit-jcr-servlet/pom.xml @@ -22,7 +22,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml diff --git a/jackrabbit-jcr-tests/pom.xml b/jackrabbit-jcr-tests/pom.xml index e9d769dcfcf..9f97b8e5212 100644 --- a/jackrabbit-jcr-tests/pom.xml +++ b/jackrabbit-jcr-tests/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-jcr-tests diff --git a/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/AbstractJCRTest.java b/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/AbstractJCRTest.java index 5cc11714610..f3227e4e2cb 100644 --- a/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/AbstractJCRTest.java +++ b/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/AbstractJCRTest.java @@ -32,7 +32,6 @@ import javax.jcr.ValueFactory; import javax.jcr.nodetype.NoSuchNodeTypeException; import javax.jcr.nodetype.NodeDefinition; -import javax.jcr.nodetype.ConstraintViolationException; import javax.jcr.nodetype.NodeType; import javax.jcr.nodetype.PropertyDefinition; import javax.jcr.retention.RetentionManager; @@ -897,7 +896,7 @@ protected Node cleanUpTestRoot(Session s) throws RepositoryException { // try to remove child try { child.remove(); - } catch (ConstraintViolationException e) { + } catch (RepositoryException e) { log.println("unable to remove node: " + child.getPath()); } } diff --git a/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/RepositoryFactoryTest.java b/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/RepositoryFactoryTest.java index 2f39caedca2..16a7c1f55ba 100644 --- a/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/RepositoryFactoryTest.java +++ b/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/RepositoryFactoryTest.java @@ -47,7 +47,7 @@ protected RepositoryFactory getRepositoryFactory() fail("Property '" + RepositoryStub.REPOSITORY_FACTORY + "' is not defined."); } else { try { - return (RepositoryFactory) Class.forName(className).newInstance(); + return (RepositoryFactory) Class.forName(className).getDeclaredConstructor().newInstance(); } catch (Exception e) { fail(e.toString()); } diff --git a/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/SysViewContentHandler.java b/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/SysViewContentHandler.java index ca3e88a1c95..46af661eea4 100644 --- a/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/SysViewContentHandler.java +++ b/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/SysViewContentHandler.java @@ -20,6 +20,7 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.apache.jackrabbit.test.AbstractJCRTest; +import org.junit.Assert; import javax.jcr.nodetype.NodeType; import javax.jcr.Session; @@ -45,8 +46,6 @@ import java.util.Iterator; import java.util.Map; -import junit.framework.Assert; - /** * ContentHandler implementation which checks if the system view export of * a node tree is compliant to the specification. diff --git a/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/TreeComparator.java b/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/TreeComparator.java index 590819a6861..0b8daba3328 100644 --- a/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/TreeComparator.java +++ b/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/TreeComparator.java @@ -28,12 +28,14 @@ import javax.jcr.Value; import javax.jcr.PathNotFoundException; import javax.jcr.nodetype.NodeTypeManager; + +import org.junit.Assert; + import javax.jcr.nodetype.NodeTypeIterator; import javax.jcr.nodetype.NodeType; import java.util.Calendar; -import java.io.ByteArrayInputStream; -import junit.framework.Assert; +import java.io.ByteArrayInputStream; /** * TreeComparator compares two trees. This allows re-use for diff --git a/jackrabbit-jcr2dav/pom.xml b/jackrabbit-jcr2dav/pom.xml index 74fa2a3c30d..195d3a9bd33 100644 --- a/jackrabbit-jcr2dav/pom.xml +++ b/jackrabbit-jcr2dav/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-jcr2dav diff --git a/jackrabbit-jcr2spi/pom.xml b/jackrabbit-jcr2spi/pom.xml index 8b66758433e..2d5c2cc6233 100644 --- a/jackrabbit-jcr2spi/pom.xml +++ b/jackrabbit-jcr2spi/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-jcr2spi @@ -42,8 +42,8 @@ - org.apache.jackrabbit.jcr2spi;version=${project.version};include:=Jcr2spiRepositoryFactory, - org.apache.jackrabbit.jcr2spi.config;version=${project.version} + org.apache.jackrabbit.jcr2spi;include:=Jcr2spiRepositoryFactory, + org.apache.jackrabbit.jcr2spi.config @@ -95,6 +95,11 @@ + + org.osgi + org.osgi.annotation + provided + javax.jcr jcr @@ -128,10 +133,6 @@ org.apache.commons commons-collections4 - - commons-io - commons-io - concurrent concurrent diff --git a/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/Jcr2spiRepositoryFactory.java b/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/Jcr2spiRepositoryFactory.java index b4e00ee3894..7200b74fc4e 100644 --- a/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/Jcr2spiRepositoryFactory.java +++ b/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/Jcr2spiRepositoryFactory.java @@ -191,7 +191,7 @@ private static RepositoryServiceFactory getServiceFactory(Map parameters) serviceFactoryClass = Class.forName(serviceFactoryName); } - Object serviceFactory = serviceFactoryClass.newInstance(); + Object serviceFactory = serviceFactoryClass.getDeclaredConstructor().newInstance(); if (serviceFactory instanceof RepositoryServiceFactory) { log.debug("Found RepositoryServiceFactory {}", serviceFactory); @@ -248,7 +248,7 @@ public int getPollTimeout() { public T getConfiguration(String name, T defaultValue) { if (parameters.containsKey(name)) { Object value = parameters.get(name); - Class clazz = (defaultValue == null) + Class clazz = (defaultValue == null) ? value.getClass() : defaultValue.getClass(); if (clazz.isAssignableFrom(value.getClass())) { diff --git a/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/RepositoryImpl.java b/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/RepositoryImpl.java index 712cb5cbe2c..5dd6d9ce71c 100644 --- a/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/RepositoryImpl.java +++ b/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/RepositoryImpl.java @@ -243,7 +243,7 @@ public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtabl } String repositoryConfigClassName = (String)((StringRefAddr)rclas).getContent(); - Object rof = Class.forName(configFactoryClassName).newInstance(); + Object rof = Class.forName(configFactoryClassName).getDeclaredConstructor().newInstance(); if (! (rof instanceof ObjectFactory)) { throw new Exception(rof + " must implement ObjectFactory"); diff --git a/test/performance/jackrabbit10/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java b/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/config/package-info.java similarity index 76% rename from test/performance/jackrabbit10/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java rename to jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/config/package-info.java index 861fe48e062..3e033b1cfca 100644 --- a/test/performance/jackrabbit10/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java +++ b/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/config/package-info.java @@ -14,15 +14,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.jackrabbit.performance; - -import org.testng.annotations.Test; - -public class PerformanceTest extends AbstractPerformanceTest { - - @Test - public void testPerformance() throws Exception { - testPerformance("1.0"); - } - -} +@org.osgi.annotation.versioning.Version("2.22.4") +package org.apache.jackrabbit.jcr2spi.config; \ No newline at end of file diff --git a/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/CopyOfAbstractLinkedList.java b/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/CopyOfAbstractLinkedList.java deleted file mode 100644 index 2b45bb7a475..00000000000 --- a/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/CopyOfAbstractLinkedList.java +++ /dev/null @@ -1,1123 +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. - */ -package org.apache.jackrabbit.jcr2spi.hierarchy; - -/* - * This is a copy of org.apache.commons.collections4.list.AbstractLinkedList - * with dependencies inlined and two methods changed for JDK 21 conformance; - * see https://issues.apache.org/jira/browse/COLLECTIONS-842 and https://issues.apache.org/jira/browse/JCR-4940 - */ - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.lang.reflect.Array; -import java.util.AbstractList; -import java.util.Collection; -import java.util.ConcurrentModificationException; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.NoSuchElementException; -import java.util.Objects; - -/** - * An abstract implementation of a linked list which provides numerous points for - * subclasses to override. - *

- * Overridable methods are provided to change the storage node and to change how - * nodes are added to and removed. Hopefully, all you need for unusual subclasses - * is here. - *

- * - * @param the type of elements in this list - * @since 3.0 - */ -abstract class CopyOfAbstractLinkedList implements List { - - /* - * Implementation notes: - * - a standard circular doubly-linked list - * - a marker node is stored to mark the start and the end of the list - * - node creation and removal always occurs through createNode() and - * removeNode(). - * - a modification count is kept, with the same semantics as - * {@link java.util.LinkedList}. - * - respects {@link AbstractList#modCount} - */ - - /** - * A {@link Node} which indicates the start and end of the list and does not - * hold a value. The value of {@code next} is the first item in the - * list. The value of {@code previous} is the last item in the list. - */ - transient Node header; - - /** The size of the list */ - transient int size; - - /** Modification count for iterators */ - transient int modCount; - - /** - * Constructor that does nothing (intended for deserialization). - *

- * If this constructor is used by a serializable subclass then the init() - * method must be called. - */ - protected CopyOfAbstractLinkedList() { - } - - /** - * Constructs a list copying data from the specified collection. - * - * @param coll the collection to copy - */ - protected CopyOfAbstractLinkedList(final Collection coll) { - init(); - addAll(coll); - } - - /** - * The equivalent of a default constructor, broken out so it can be called - * by any constructor and by {@code readObject}. - * Subclasses which override this method should make sure they call super, - * so the list is initialized properly. - */ - protected void init() { - header = createHeaderNode(); - } - - - @Override - public int size() { - return size; - } - - @Override - public boolean isEmpty() { - return size() == 0; - } - - @Override - public E get(final int index) { - final Node node = getNode(index, false); - return node.getValue(); - } - - - @Override - public Iterator iterator() { - return listIterator(); - } - - @Override - public ListIterator listIterator() { - return new LinkedListIterator<>(this, 0); - } - - @Override - public ListIterator listIterator(final int fromIndex) { - return new LinkedListIterator<>(this, fromIndex); - } - - - @Override - public int indexOf(final Object value) { - int i = 0; - for (Node node = header.next; node != header; node = node.next) { - if (isEqualValue(node.getValue(), value)) { - return i; - } - i++; - } - return INDEX_NOT_FOUND; - } - - @Override - public int lastIndexOf(final Object value) { - int i = size - 1; - for (Node node = header.previous; node != header; node = node.previous) { - if (isEqualValue(node.getValue(), value)) { - return i; - } - i--; - } - return INDEX_NOT_FOUND; - } - - @Override - public boolean contains(final Object value) { - return indexOf(value) != -1; - } - - @Override - public boolean containsAll(final Collection coll) { - for (final Object o : coll) { - if (!contains(o)) { - return false; - } - } - return true; - } - - - @Override - public Object[] toArray() { - return toArray(new Object[size]); - } - - @Override - @SuppressWarnings("unchecked") - public T[] toArray(T[] array) { - // Extend the array if needed - if (array.length < size) { - final Class componentType = array.getClass().getComponentType(); - array = (T[]) Array.newInstance(componentType, size); - } - // Copy the values into the array - int i = 0; - for (Node node = header.next; node != header; node = node.next, i++) { - array[i] = (T) node.getValue(); - } - // Set the value after the last value to null - if (array.length > size) { - array[size] = null; - } - return array; - } - - /** - * Gets a sublist of the main list. - * - * @param fromIndexInclusive the index to start from - * @param toIndexExclusive the index to end at - * @return the new sublist - */ - @Override - public List subList(final int fromIndexInclusive, final int toIndexExclusive) { - return new LinkedSubList<>(this, fromIndexInclusive, toIndexExclusive); - } - - - @Override - public boolean add(final E value) { - addLast(value); - return true; - } - - @Override - public void add(final int index, final E value) { - final Node node = getNode(index, true); - addNodeBefore(node, value); - } - - @Override - public boolean addAll(final Collection coll) { - return addAll(size, coll); - } - - @Override - public boolean addAll(final int index, final Collection coll) { - final Node node = getNode(index, true); - for (final E e : coll) { - addNodeBefore(node, e); - } - return true; - } - - - @Override - public E remove(final int index) { - final Node node = getNode(index, false); - final E oldValue = node.getValue(); - removeNode(node); - return oldValue; - } - - @Override - public boolean remove(final Object value) { - for (Node node = header.next; node != header; node = node.next) { - if (isEqualValue(node.getValue(), value)) { - removeNode(node); - return true; - } - } - return false; - } - - /** - * {@inheritDoc} - *

- * This implementation iterates over the elements of this list, checking each element in - * turn to see if it's contained in {@code coll}. If it's contained, it's removed - * from this list. As a consequence, it is advised to use a collection type for - * {@code coll} that provides a fast (e.g. O(1)) implementation of - * {@link Collection#contains(Object)}. - */ - @Override - public boolean removeAll(final Collection coll) { - boolean modified = false; - final Iterator it = iterator(); - while (it.hasNext()) { - if (coll.contains(it.next())) { - it.remove(); - modified = true; - } - } - return modified; - } - - - /** - * {@inheritDoc} - *

- * This implementation iterates over the elements of this list, checking each element in - * turn to see if it's contained in {@code coll}. If it's not contained, it's removed - * from this list. As a consequence, it is advised to use a collection type for - * {@code coll} that provides a fast (e.g. O(1)) implementation of - * {@link Collection#contains(Object)}. - */ - @Override - public boolean retainAll(final Collection coll) { - boolean modified = false; - final Iterator it = iterator(); - while (it.hasNext()) { - if (!coll.contains(it.next())) { - it.remove(); - modified = true; - } - } - return modified; - } - - @Override - public E set(final int index, final E value) { - final Node node = getNode(index, false); - final E oldValue = node.getValue(); - updateNode(node, value); - return oldValue; - } - - @Override - public void clear() { - removeAllNodes(); - } - - - public E getFirst() { - final Node node = header.next; - if (node == header) { - throw new NoSuchElementException(); - } - return node.getValue(); - } - - public E getLast() { - final Node node = header.previous; - if (node == header) { - throw new NoSuchElementException(); - } - return node.getValue(); - } - - public void addFirst(final E o) { - addNodeAfter(header, o); - } - - public void addLast(final E o) { - addNodeBefore(header, o); - } - - public E removeFirst() { - final Node node = header.next; - if (node == header) { - throw new NoSuchElementException(); - } - final E oldValue = node.getValue(); - removeNode(node); - return oldValue; - } - - public E removeLast() { - final Node node = header.previous; - if (node == header) { - throw new NoSuchElementException(); - } - final E oldValue = node.getValue(); - removeNode(node); - return oldValue; - } - - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof List)) { - return false; - } - final List other = (List) obj; - if (other.size() != size()) { - return false; - } - final ListIterator it1 = listIterator(); - final ListIterator it2 = other.listIterator(); - while (it1.hasNext() && it2.hasNext()) { - if (!Objects.equals(it1.next(), it2.next())) { - return false; - } - } - return !(it1.hasNext() || it2.hasNext()); - } - - @Override - public int hashCode() { - int hashCode = 1; - for (final E e : this) { - hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode()); - } - return hashCode; - } - - @Override - public String toString() { - if (isEmpty()) { - return "[]"; - } - final StringBuilder buf = new StringBuilder(16 * size()); - buf.append(DEFAULT_TOSTRING_PREFIX); - - final Iterator it = iterator(); - boolean hasNext = it.hasNext(); - while (hasNext) { - final Object value = it.next(); - buf.append(value == this ? "(this Collection)" : value); - hasNext = it.hasNext(); - if (hasNext) { - buf.append(", "); - } - } - buf.append(DEFAULT_TOSTRING_SUFFIX); - return buf.toString(); - } - - /** - * Compares two values for equals. - * This implementation uses the equals method. - * Subclasses can override this to match differently. - * - * @param value1 the first value to compare, may be null - * @param value2 the second value to compare, may be null - * @return true if equal - */ - protected boolean isEqualValue(final Object value1, final Object value2) { - return Objects.equals(value1, value2); - } - - /** - * Updates the node with a new value. - * This implementation sets the value on the node. - * Subclasses can override this to record the change. - * - * @param node node to update - * @param value new value of the node - */ - protected void updateNode(final Node node, final E value) { - node.setValue(value); - } - - /** - * Creates a new node with previous, next and element all set to null. - * This implementation creates a new empty Node. - * Subclasses can override this to create a different class. - * - * @return newly created node - */ - protected Node createHeaderNode() { - return new Node<>(); - } - - /** - * Creates a new node with the specified properties. - * This implementation creates a new Node with data. - * Subclasses can override this to create a different class. - * - * @param value value of the new node - * @return a new node containing the value - */ - protected Node createNode(final E value) { - return new Node<>(value); - } - - /** - * Creates a new node with the specified object as its - * {@code value} and inserts it before {@code node}. - *

- * This implementation uses {@link #createNode(Object)} and - * {@link #addNode(CopyOfAbstractLinkedList.Node,CopyOfAbstractLinkedList.Node)}. - * - * @param node node to insert before - * @param value value of the newly added node - * @throws NullPointerException if {@code node} is null - */ - protected void addNodeBefore(final Node node, final E value) { - final Node newNode = createNode(value); - addNode(newNode, node); - } - - /** - * Creates a new node with the specified object as its - * {@code value} and inserts it after {@code node}. - *

- * This implementation uses {@link #createNode(Object)} and - * {@link #addNode(CopyOfAbstractLinkedList.Node,CopyOfAbstractLinkedList.Node)}. - * - * @param node node to insert after - * @param value value of the newly added node - * @throws NullPointerException if {@code node} is null - */ - protected void addNodeAfter(final Node node, final E value) { - final Node newNode = createNode(value); - addNode(newNode, node.next); - } - - /** - * Inserts a new node into the list. - * - * @param nodeToInsert new node to insert - * @param insertBeforeNode node to insert before - * @throws NullPointerException if either node is null - */ - protected void addNode(final Node nodeToInsert, final Node insertBeforeNode) { - Objects.requireNonNull(nodeToInsert, "nodeToInsert"); - Objects.requireNonNull(insertBeforeNode, "insertBeforeNode"); - nodeToInsert.next = insertBeforeNode; - nodeToInsert.previous = insertBeforeNode.previous; - insertBeforeNode.previous.next = nodeToInsert; - insertBeforeNode.previous = nodeToInsert; - size++; - modCount++; - } - - /** - * Removes the specified node from the list. - * - * @param node the node to remove - * @throws NullPointerException if {@code node} is null - */ - protected void removeNode(final Node node) { - Objects.requireNonNull(node, "node"); - node.previous.next = node.next; - node.next.previous = node.previous; - size--; - modCount++; - } - - /** - * Removes all nodes by resetting the circular list marker. - */ - protected void removeAllNodes() { - header.next = header; - header.previous = header; - size = 0; - modCount++; - } - - /** - * Gets the node at a particular index. - * - * @param index the index, starting from 0 - * @param endMarkerAllowed whether or not the end marker can be returned if - * startIndex is set to the list's size - * @return the node at the given index - * @throws IndexOutOfBoundsException if the index is less than 0; equal to - * the size of the list and endMakerAllowed is false; or greater than the - * size of the list - */ - protected Node getNode(final int index, final boolean endMarkerAllowed) throws IndexOutOfBoundsException { - // Check the index is within the bounds - if (index < 0) { - throw new IndexOutOfBoundsException("Couldn't get the node: " + - "index (" + index + ") less than zero."); - } - if (!endMarkerAllowed && index == size) { - throw new IndexOutOfBoundsException("Couldn't get the node: " + - "index (" + index + ") is the size of the list."); - } - if (index > size) { - throw new IndexOutOfBoundsException("Couldn't get the node: " + - "index (" + index + ") greater than the size of the " + - "list (" + size + ")."); - } - // Search the list and get the node - Node node; - if (index < size / 2) { - // Search forwards - node = header.next; - for (int currentIndex = 0; currentIndex < index; currentIndex++) { - node = node.next; - } - } else { - // Search backwards - node = header; - for (int currentIndex = size; currentIndex > index; currentIndex--) { - node = node.previous; - } - } - return node; - } - - /** - * Creates an iterator for the sublist. - * - * @param subList the sublist to get an iterator for - * @return a new iterator on the given sublist - */ - protected Iterator createSubListIterator(final LinkedSubList subList) { - return createSubListListIterator(subList, 0); - } - - /** - * Creates a list iterator for the sublist. - * - * @param subList the sublist to get an iterator for - * @param fromIndex the index to start from, relative to the sublist - * @return a new list iterator on the given sublist - */ - protected ListIterator createSubListListIterator(final LinkedSubList subList, final int fromIndex) { - return new LinkedSubListIterator<>(subList, fromIndex); - } - - /** - * Serializes the data held in this object to the stream specified. - *

- * The first serializable subclass must call this method from - * {@code writeObject}. - * - * @param outputStream the stream to write the object to - * @throws IOException if anything goes wrong - */ - protected void doWriteObject(final ObjectOutputStream outputStream) throws IOException { - // Write the size so we know how many nodes to read back - outputStream.writeInt(size()); - for (final E e : this) { - outputStream.writeObject(e); - } - } - - /** - * Deserializes the data held in this object to the stream specified. - *

- * The first serializable subclass must call this method from - * {@code readObject}. - * - * @param inputStream the stream to read the object from - * @throws IOException if any error occurs while reading from the stream - * @throws ClassNotFoundException if a class read from the stream can not be loaded - */ - @SuppressWarnings("unchecked") - protected void doReadObject(final ObjectInputStream inputStream) throws IOException, ClassNotFoundException { - init(); - final int size = inputStream.readInt(); - for (int i = 0; i < size; i++) { - add((E) inputStream.readObject()); - } - } - - /** - * A node within the linked list. - *

- * From Commons Collections 3.1, all access to the {@code value} property - * is via the methods on this class. - */ - protected static class Node { - - /** A pointer to the node before this node */ - protected Node previous; - /** A pointer to the node after this node */ - protected Node next; - /** The object contained within this node */ - protected E value; - - /** - * Constructs a new header node. - */ - protected Node() { - previous = this; - next = this; - } - - /** - * Constructs a new node. - * - * @param value the value to store - */ - protected Node(final E value) { - this.value = value; - } - - /** - * Constructs a new node. - * - * @param previous the previous node in the list - * @param next the next node in the list - * @param value the value to store - */ - protected Node(final Node previous, final Node next, final E value) { - this.previous = previous; - this.next = next; - this.value = value; - } - - /** - * Gets the value of the node. - * - * @return the value - * @since 3.1 - */ - protected E getValue() { - return value; - } - - /** - * Sets the value of the node. - * - * @param value the value - * @since 3.1 - */ - protected void setValue(final E value) { - this.value = value; - } - - /** - * Gets the previous node. - * - * @return the previous node - * @since 3.1 - */ - protected Node getPreviousNode() { - return previous; - } - - /** - * Sets the previous node. - * - * @param previous the previous node - * @since 3.1 - */ - protected void setPreviousNode(final Node previous) { - this.previous = previous; - } - - /** - * Gets the next node. - * - * @return the next node - * @since 3.1 - */ - protected Node getNextNode() { - return next; - } - - /** - * Sets the next node. - * - * @param next the next node - * @since 3.1 - */ - protected void setNextNode(final Node next) { - this.next = next; - } - } - - /** - * A list iterator over the linked list. - * - * @param the type of elements in this iterator. - */ - protected static class LinkedListIterator implements ListIterator, CopyOfOrderedIterator { - - /** The parent list */ - protected final CopyOfAbstractLinkedList parent; - - /** - * The node that will be returned by {@link #next()}. If this is equal - * to {@link CopyOfAbstractLinkedList#header} then there are no more values to return. - */ - protected Node next; - - /** - * The index of {@link #next}. - */ - protected int nextIndex; - - /** - * The last node that was returned by {@link #next()} or {@link - * #previous()}. Set to {@code null} if {@link #next()} or {@link - * #previous()} haven't been called, or if the node has been removed - * with {@link #remove()} or a new node added with {@link #add(Object)}. - * Should be accessed through {@link #getLastNodeReturned()} to enforce - * this behavior. - */ - protected Node current; - - /** - * The modification count that the list is expected to have. If the list - * doesn't have this count, then a - * {@link java.util.ConcurrentModificationException} may be thrown by - * the operations. - */ - protected int expectedModCount; - - /** - * Create a ListIterator for a list. - * - * @param parent the parent list - * @param fromIndex the index to start at - * @throws IndexOutOfBoundsException if fromIndex is less than 0 or greater than the size of the list - */ - protected LinkedListIterator(final CopyOfAbstractLinkedList parent, final int fromIndex) - throws IndexOutOfBoundsException { - this.parent = parent; - this.expectedModCount = parent.modCount; - this.next = parent.getNode(fromIndex, true); - this.nextIndex = fromIndex; - } - - /** - * Checks the modification count of the list is the value that this - * object expects. - * - * @throws ConcurrentModificationException If the list's modification - * count isn't the value that was expected. - */ - protected void checkModCount() { - if (parent.modCount != expectedModCount) { - throw new ConcurrentModificationException(); - } - } - - /** - * Gets the last node returned. - * - * @return the last node returned - * @throws IllegalStateException If {@link #next()} or {@link #previous()} haven't been called, - * or if the node has been removed with {@link #remove()} or a new node added with {@link #add(Object)}. - */ - protected Node getLastNodeReturned() throws IllegalStateException { - if (current == null) { - throw new IllegalStateException(); - } - return current; - } - - @Override - public boolean hasNext() { - return next != parent.header; - } - - @Override - public E next() { - checkModCount(); - if (!hasNext()) { - throw new NoSuchElementException("No element at index " + nextIndex + "."); - } - final E value = next.getValue(); - current = next; - next = next.next; - nextIndex++; - return value; - } - - @Override - public boolean hasPrevious() { - return next.previous != parent.header; - } - - @Override - public E previous() { - checkModCount(); - if (!hasPrevious()) { - throw new NoSuchElementException("Already at start of list."); - } - next = next.previous; - final E value = next.getValue(); - current = next; - nextIndex--; - return value; - } - - @Override - public int nextIndex() { - return nextIndex; - } - - @Override - public int previousIndex() { - // not normally overridden, as relative to nextIndex() - return nextIndex() - 1; - } - - @Override - public void remove() { - checkModCount(); - if (current == next) { - // remove() following previous() - next = next.next; - parent.removeNode(getLastNodeReturned()); - } else { - // remove() following next() - parent.removeNode(getLastNodeReturned()); - nextIndex--; - } - current = null; - expectedModCount++; - } - - @Override - public void set(final E obj) { - checkModCount(); - getLastNodeReturned().setValue(obj); - } - - @Override - public void add(final E obj) { - checkModCount(); - parent.addNodeBefore(next, obj); - current = null; - nextIndex++; - expectedModCount++; - } - - } - - /** - * A list iterator over the linked sub list. - * - * @param the type of elements in this iterator. - */ - protected static class LinkedSubListIterator extends LinkedListIterator { - - /** The sub list */ - protected final LinkedSubList sub; - - protected LinkedSubListIterator(final LinkedSubList sub, final int startIndex) { - super(sub.parent, startIndex + sub.offset); - this.sub = sub; - } - - @Override - public boolean hasNext() { - return nextIndex() < sub.size; - } - - @Override - public boolean hasPrevious() { - return previousIndex() >= 0; - } - - @Override - public int nextIndex() { - return super.nextIndex() - sub.offset; - } - - @Override - public void add(final E obj) { - super.add(obj); - sub.expectedModCount = parent.modCount; - sub.size++; - } - - @Override - public void remove() { - super.remove(); - sub.expectedModCount = parent.modCount; - sub.size--; - } - } - - /** - * The sublist implementation for CopyOfAbstractLinkedList. - * - * @param the type of elements in this list. - */ - protected static class LinkedSubList extends AbstractList { - /** The main list */ - CopyOfAbstractLinkedList parent; - /** Offset from the main list */ - int offset; - /** Sublist size */ - int size; - /** Sublist modCount */ - int expectedModCount; - - protected LinkedSubList(final CopyOfAbstractLinkedList parent, final int fromIndex, final int toIndex) { - if (fromIndex < 0) { - throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); - } - if (toIndex > parent.size()) { - throw new IndexOutOfBoundsException("toIndex = " + toIndex); - } - if (fromIndex > toIndex) { - throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); - } - this.parent = parent; - this.offset = fromIndex; - this.size = toIndex - fromIndex; - this.expectedModCount = parent.modCount; - } - - @Override - public int size() { - checkModCount(); - return size; - } - - @Override - public E get(final int index) { - rangeCheck(index, size); - checkModCount(); - return parent.get(index + offset); - } - - @Override - public void add(final int index, final E obj) { - rangeCheck(index, size + 1); - checkModCount(); - parent.add(index + offset, obj); - expectedModCount = parent.modCount; - size++; - modCount++; - } - - @Override - public E remove(final int index) { - rangeCheck(index, size); - checkModCount(); - final E result = parent.remove(index + offset); - expectedModCount = parent.modCount; - size--; - modCount++; - return result; - } - - @Override - public boolean addAll(final Collection coll) { - return addAll(size, coll); - } - - @Override - public boolean addAll(final int index, final Collection coll) { - rangeCheck(index, size + 1); - final int cSize = coll.size(); - if (cSize == 0) { - return false; - } - - checkModCount(); - parent.addAll(offset + index, coll); - expectedModCount = parent.modCount; - size += cSize; - modCount++; - return true; - } - - @Override - public E set(final int index, final E obj) { - rangeCheck(index, size); - checkModCount(); - return parent.set(index + offset, obj); - } - - @Override - public void clear() { - checkModCount(); - final Iterator it = iterator(); - while (it.hasNext()) { - it.next(); - it.remove(); - } - } - - @Override - public Iterator iterator() { - checkModCount(); - return parent.createSubListIterator(this); - } - - @Override - public ListIterator listIterator(final int index) { - rangeCheck(index, size + 1); - checkModCount(); - return parent.createSubListListIterator(this, index); - } - - @Override - public List subList(final int fromIndexInclusive, final int toIndexExclusive) { - return new LinkedSubList<>(parent, fromIndexInclusive + offset, toIndexExclusive + offset); - } - - protected void rangeCheck(final int index, final int beyond) { - if (index < 0 || index >= beyond) { - throw new IndexOutOfBoundsException("Index '" + index + "' out of bounds for size '" + size + "'"); - } - } - - protected void checkModCount() { - if (parent.modCount != expectedModCount) { - throw new ConcurrentModificationException(); - } - } - } - - // inlined dependencies from commons-collections - - private interface CopyOfOrderedIterator extends Iterator { - - /** - * Checks to see if there is a previous element that can be iterated to. - * - * @return {@code true} if the iterator has a previous element - */ - boolean hasPrevious(); - - /** - * Gets the previous element from the container. - * - * @return the previous element in the iteration - * @throws java.util.NoSuchElementException if the iteration is finished - */ - E previous(); - - } - - /** - * The index value when an element is not found in a collection or array: {@code -1}. - */ - private static final int INDEX_NOT_FOUND = -1; - - /** - * Default prefix used while converting an Iterator to its String representation. - */ - private static final String DEFAULT_TOSTRING_PREFIX = "["; - - /** - * Default suffix used while converting an Iterator to its String representation. - */ - private static final String DEFAULT_TOSTRING_SUFFIX = "]"; -} diff --git a/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/LinkedEntries.java b/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/LinkedEntries.java index 67c5b154a6e..1c4a5b957b2 100644 --- a/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/LinkedEntries.java +++ b/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/LinkedEntries.java @@ -22,6 +22,7 @@ import java.util.Iterator; import java.util.NoSuchElementException; +import org.apache.commons.collections4.list.AbstractLinkedListJava21; import org.apache.jackrabbit.spi.Name; import org.apache.jackrabbit.spi.Path; @@ -30,7 +31,7 @@ * LinkNode which links the entries of the list. */ @SuppressWarnings("rawtypes") -class LinkedEntries extends CopyOfAbstractLinkedList { +class LinkedEntries extends AbstractLinkedListJava21 { private Node header; private volatile int modCount; @@ -165,7 +166,7 @@ void reorderNode(LinkedEntries.LinkNode insert, LinkedEntries.LinkNode before) { * * @param value a child node entry. * @return a wrapping {@link LinkedEntries.LinkNode}. - * @see CopyOfAbstractLinkedList#createNode(Object) + * @see AbstractLinkedListJava21#createNode(Object) */ @Override protected Node createNode(Object value) { @@ -174,7 +175,7 @@ protected Node createNode(Object value) { /** * @return a new LinkNode. - * @see CopyOfAbstractLinkedList#createHeaderNode() + * @see AbstractLinkedListJava21#createHeaderNode() */ @Override protected Node createHeaderNode() { diff --git a/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/EffectiveNodeType.java b/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/EffectiveNodeType.java index 210c11ee103..5c551656ebe 100644 --- a/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/EffectiveNodeType.java +++ b/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/EffectiveNodeType.java @@ -106,6 +106,7 @@ public void checkAddNodeConstraints(Name name, QNodeTypeDefinition nodeTypeDefin * @deprecated Use {@link #hasRemoveNodeConstraint(Name)} and * {@link #hasRemovePropertyConstraint(Name)} respectively. */ + @Deprecated public void checkRemoveItemConstraints(Name name) throws ConstraintViolationException; /** diff --git a/test/performance/jackrabbit11/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java b/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/package-info.java similarity index 76% rename from test/performance/jackrabbit11/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java rename to jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/package-info.java index 11a7ccebb50..fe15ce17a21 100644 --- a/test/performance/jackrabbit11/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java +++ b/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/package-info.java @@ -14,15 +14,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.jackrabbit.performance; - -import org.testng.annotations.Test; - -public class PerformanceTest extends AbstractPerformanceTest { - - @Test - public void testPerformance() throws Exception { - testPerformance("1.1"); - } - -} +@org.osgi.annotation.versioning.Version("2.22.4") +package org.apache.jackrabbit.jcr2spi; \ No newline at end of file diff --git a/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/security/authorization/AccessControlProviderStub.java b/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/security/authorization/AccessControlProviderStub.java index 23ace3a6c02..fcb2c2b8cd8 100644 --- a/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/security/authorization/AccessControlProviderStub.java +++ b/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/security/authorization/AccessControlProviderStub.java @@ -69,7 +69,7 @@ public static AccessControlProvider newInstance(RepositoryConfig config) throws try { Class acProviderClass = Class.forName(className); if (AccessControlProvider.class.isAssignableFrom(acProviderClass)) { - AccessControlProvider acProvider = (AccessControlProvider) acProviderClass.newInstance(); + AccessControlProvider acProvider = (AccessControlProvider) acProviderClass.getDeclaredConstructor().newInstance(); acProvider.init(config); return acProvider; } else { diff --git a/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/BinaryTest.java b/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/BinaryTest.java index a01d8209baa..11651c78470 100644 --- a/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/BinaryTest.java +++ b/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/BinaryTest.java @@ -16,19 +16,18 @@ */ package org.apache.jackrabbit.jcr2spi; -import java.util.Random; - import static org.junit.Assert.assertArrayEquals; import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.Random; +import javax.jcr.Binary; import javax.jcr.Node; -import javax.jcr.Session; import javax.jcr.Property; -import javax.jcr.Binary; +import javax.jcr.Session; import javax.jcr.ValueFormatException; -import org.apache.commons.io.IOUtils; import org.apache.jackrabbit.jcr2spi.state.PropertyState; import org.apache.jackrabbit.spi.QValue; import org.apache.jackrabbit.test.AbstractJCRTest; @@ -186,7 +185,9 @@ public void testStreamIntegrity() throws Exception { // check the binaries are indeed the same (JCR-4154) byte[] result = new byte[bytes.length]; - IOUtils.readFully(p.getBinary().getStream(), result); + try (InputStream in = p.getBinary().getStream()) { + result = in.readAllBytes(); + } assertArrayEquals(bytes, result); } finally { s.logout(); diff --git a/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/CopyMoveToJsonTest.java b/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/CopyMoveToJsonTest.java index 9b7e6c26b4d..2ac41fee50c 100755 --- a/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/CopyMoveToJsonTest.java +++ b/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/CopyMoveToJsonTest.java @@ -17,14 +17,15 @@ package org.apache.jackrabbit.jcr2spi; import java.io.ByteArrayInputStream; +import java.io.InputStream; import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import javax.jcr.Node; import javax.jcr.Property; import javax.jcr.RepositoryException; import javax.jcr.Session; -import org.apache.commons.io.IOUtils; import org.apache.jackrabbit.JcrConstants; import org.apache.jackrabbit.test.AbstractJCRTest; @@ -39,7 +40,9 @@ public void testCreateJson() throws Exception { try { Property p = s.getNode(testRoot).getNode("test.json").getNode(JcrConstants.JCR_CONTENT) .getProperty(JcrConstants.JCR_DATA); - assertEquals(jsondata, IOUtils.toString(p.getBinary().getStream(), "UTF-8")); + try (InputStream in = p.getBinary().getStream()) { + assertEquals(jsondata, new String(in.readAllBytes(), StandardCharsets.UTF_8)); + } } finally { s.logout(); } @@ -53,7 +56,9 @@ public void testCopyJson() throws Exception { try { Property p = s.getNode(testRoot).getNode("target.json").getNode(JcrConstants.JCR_CONTENT) .getProperty(JcrConstants.JCR_DATA); - assertEquals(jsondata, IOUtils.toString(p.getBinary().getStream(), "UTF-8")); + try (InputStream in = p.getBinary().getStream()) { + assertEquals(jsondata, new String(in.readAllBytes(), StandardCharsets.UTF_8)); + } } finally { s.logout(); } @@ -67,7 +72,9 @@ public void testMoveJson() throws Exception { try { Property p = s.getNode(testRoot).getNode("target.json").getNode(JcrConstants.JCR_CONTENT) .getProperty(JcrConstants.JCR_DATA); - assertEquals(jsondata, IOUtils.toString(p.getBinary().getStream(), "UTF-8")); + try (InputStream in = p.getBinary().getStream()) { + assertEquals(jsondata, new String(in.readAllBytes(), StandardCharsets.UTF_8)); + } } finally { s.logout(); } diff --git a/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/security/authorization/jackrabbit/acl/AccessControlListImplTest.java b/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/security/authorization/jackrabbit/acl/AccessControlListImplTest.java index 9c6a9789d71..f0fe19ed5ee 100644 --- a/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/security/authorization/jackrabbit/acl/AccessControlListImplTest.java +++ b/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/security/authorization/jackrabbit/acl/AccessControlListImplTest.java @@ -28,7 +28,6 @@ import javax.jcr.security.AccessControlList; import javax.jcr.security.Privilege; -import junit.framework.Assert; import org.apache.jackrabbit.api.security.JackrabbitAccessControlList; import org.apache.jackrabbit.spi.Name; import org.apache.jackrabbit.spi.QValueFactory; @@ -36,6 +35,7 @@ import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver; import org.apache.jackrabbit.spi.commons.value.QValueFactoryImpl; import org.apache.jackrabbit.test.api.security.AbstractAccessControlTest; +import org.junit.Assert; /** * Tests the functionality of the JCR AccessControlList API implementation. The @@ -97,15 +97,14 @@ public void testAddingDifferentEntries() throws Exception { // four different entries Assert.assertEquals(4, acl.size()); - + // UnknownPrincipal entries AccessControlEntry[] pentries = getEntries(acl, unknownPrincipal); Assert.assertEquals(2, pentries.length); - + // secondPrincipal entries AccessControlEntry[] sentries = getEntries(acl, knownPrincipal); Assert.assertEquals(2, sentries.length); - } public void testMultipleEntryEffect() throws Exception { diff --git a/jackrabbit-parent/pom.xml b/jackrabbit-parent/pom.xml index cc7617c4777..9c888e264e3 100644 --- a/jackrabbit-parent/pom.xml +++ b/jackrabbit-parent/pom.xml @@ -27,14 +27,14 @@ org.apache apache - 32 + 39 org.apache.jackrabbit jackrabbit-parent Jackrabbit Parent POM - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT pom @@ -47,23 +47,23 @@ scm:git:https://gitbox.apache.org/repos/asf/jackrabbit.git scm:git:https://gitbox.apache.org/repos/asf/jackrabbit.git https://github.com/apache/jackrabbit/tree/${project.scm.tag} - jackrabbit-2.21.26-beta + jackrabbit-2.23.4-beta - -Xmx256m + -Xmx4g ${test.opts.modules} ${test.opts.coverage} ${test.opts.memory} -enableassertions - - 1.64.0 + + 2.4.0 - 1.22.20 - 9.4.53.v20231009 + 1.22.24 + 9.4.58.v20250814 2.4.1 ${project.build.sourceEncoding} 1.7.36 1.7.36 - 1.2.11 + 1.2.13 11 @@ -76,10 +76,19 @@ 0.0 - 1717331862 + 1782909208 3.6.1 + + + + ${maven.multiModuleProjectDirectory}/target/site/jacoco-aggregate/jacoco.xml + + **/org/apache/jackrabbit/test/** + + ** + http://jackrabbit.apache.org/ 2004 @@ -94,10 +103,6 @@ - - 3.2.1 - - javadoc @@ -114,12 +119,6 @@ - - maven-surefire-plugin - - true - - @@ -139,12 +138,6 @@ - - maven-surefire-plugin - - true - - @@ -201,6 +194,39 @@ false + + + + + + io.github.olamy.maven.plugins + jacoco-aggregator-maven-plugin + 1.0.3 + + + + org/apache/jackrabbit/** + + + + org/apache/jackrabbit/test/** + + + + + aggregate + verify + + report-aggregate-all + + + + + + + @@ -264,29 +290,28 @@ org.jacoco jacoco-maven-plugin - 0.8.12 + 0.8.13 - pre-unit-test + prepare-jacoco-agent prepare-agent + ${skip.coverage} - ${project.build.directory}/coverage-reports/jacoco-ut.exec test.opts.coverage + + true - post-unit-test - test + generate-jacoco-report report ${skip.coverage} - ${project.build.directory}/coverage-reports/jacoco-ut.exec - ${project.reporting.outputDirectory}/jacoco-ut @@ -295,7 +320,6 @@ check - ${project.build.directory}/coverage-reports/jacoco-ut.exec BUNDLE @@ -341,18 +365,10 @@ ${test.opts} - - maven-jar-plugin - 3.4.1 - maven-rar-plugin 3.0.0 - - maven-war-plugin - 3.4.0 - maven-idea-plugin 2.2.1 @@ -383,7 +399,7 @@ - 2.20.16 + 2.22.3 @@ -398,29 +414,16 @@ cobertura-maven-plugin 2.7 - - maven-antrun-plugin - 3.1.0 - - - org.apache.maven.plugins - maven-javadoc-plugin - - - org.apache.maven.plugins - maven-checkstyle-plugin - 3.3.1 - org.apache.maven.plugins maven-pmd-plugin - 3.22.0 + 3.25.0 ${java.version} @@ -428,7 +431,7 @@ com.github.spotbugs spotbugs-maven-plugin - 4.8.5.0 + 4.8.6.4 @@ -454,12 +457,12 @@ org.apache.commons commons-collections4 - 4.4 + 4.5.0 commons-io commons-io - 2.16.1 + 2.21.0 javax.transaction @@ -581,7 +584,7 @@ commons-fileupload commons-fileupload - 1.5 + 1.6.0 org.eclipse.jetty @@ -616,7 +619,7 @@ org.easymock easymock - 5.2.0 + 5.6.0 junit @@ -626,7 +629,7 @@ org.mockito mockito-core - 5.12.0 + 5.23.0 diff --git a/jackrabbit-spi-commons/pom.xml b/jackrabbit-spi-commons/pom.xml index b8a9511b2a6..361ac21cde7 100644 --- a/jackrabbit-spi-commons/pom.xml +++ b/jackrabbit-spi-commons/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-spi-commons diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/EventImpl.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/EventImpl.java index 2baa3c8baa7..8edd58bf38a 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/EventImpl.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/EventImpl.java @@ -81,6 +81,7 @@ public class EventImpl implements Event, Serializable { * Creates a new serializable event. * @deprecated */ + @Deprecated public EventImpl(int type, Path path, ItemId itemId, NodeId parentId, Name primaryNodeTypeName, Name[] mixinTypeNames, String userId) { diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/ItemInfoImpl.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/ItemInfoImpl.java index 0c8b0edef58..4ba735b1305 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/ItemInfoImpl.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/ItemInfoImpl.java @@ -50,6 +50,7 @@ public abstract class ItemInfoImpl implements ItemInfo, Serializable { * parentId is not used any more and the corresponding getter has been * removed. */ + @Deprecated public ItemInfoImpl(NodeId parentId, Name name, Path path, boolean isNode) { this(path, isNode); } diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/LockInfoImpl.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/LockInfoImpl.java index 04906cad5d9..c9f5c161f91 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/LockInfoImpl.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/LockInfoImpl.java @@ -72,6 +72,7 @@ public class LockInfoImpl implements LockInfo, Serializable { * @param nodeId the node id of the locked node. * @deprecated Use {@link #LockInfoImpl(String, String, boolean, boolean, long, boolean, NodeId)} instaed. */ + @Deprecated public LockInfoImpl(String lockToken, String lockOwner, boolean isDeep, boolean isSessionScoped, NodeId nodeId) { this(lockToken, lockOwner, isDeep, isSessionScoped, Long.MAX_VALUE, lockToken != null, nodeId); diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/NodeInfoImpl.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/NodeInfoImpl.java index c4c0f8319c8..1d4ab8c3242 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/NodeInfoImpl.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/NodeInfoImpl.java @@ -149,6 +149,7 @@ public void remove() { * @deprecated Use {@link #NodeInfoImpl(Path, NodeId, int, Name, Name[], Iterator, Iterator, Iterator)} * instead. The parentId is not used any more. */ + @Deprecated public NodeInfoImpl(NodeId parentId, Name name, Path path, NodeId id, int index, Name primaryTypeName, Name[] mixinNames, Iterator references, Iterator propertyIds, diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/PropertyInfoImpl.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/PropertyInfoImpl.java index 8abf38b66ec..fd78d4b3b69 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/PropertyInfoImpl.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/PropertyInfoImpl.java @@ -87,6 +87,7 @@ public static PropertyInfo createSerializablePropertyInfo( * @deprecated Use {@link #PropertyInfoImpl(Path, PropertyId, int, boolean, QValue[])} * instead. The parentId is not used any more. */ + @Deprecated public PropertyInfoImpl(NodeId parentId, Name name, Path path, PropertyId id, int type, boolean isMultiValued, QValue[] values) { diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/iterator/Iterators.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/iterator/Iterators.java index 88301d098ff..4acdf65fad9 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/iterator/Iterators.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/iterator/Iterators.java @@ -121,6 +121,7 @@ public static Iterator arrayIterator(T[] values, int from, int to) { * @return * @deprecated use {@link #filterIterator(Iterator, java.util.function.Predicate)} instead */ + @Deprecated public static Iterator filterIterator(Iterator iterator, final Predicate predicate) { diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/iterator/Predicate.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/iterator/Predicate.java index b94bcbd3bfc..18c788bd236 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/iterator/Predicate.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/iterator/Predicate.java @@ -22,6 +22,7 @@ * @param type of values this predicate is defined on * @deprecated use {@link java.util.function.Predicate} instead */ +@Deprecated public interface Predicate { /** diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/iterator/Predicates.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/iterator/Predicates.java index be81d1110b7..b6880a282dc 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/iterator/Predicates.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/iterator/Predicates.java @@ -21,6 +21,7 @@ * Utility class containing pre defined {@link Predicate}s * @deprecated use instances of {@link java.util.function.Predicate} instead */ +@Deprecated public final class Predicates { /** diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/lock/Locked.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/lock/Locked.java index b9447957c5c..29e0ae1246c 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/lock/Locked.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/lock/Locked.java @@ -78,6 +78,7 @@ * * @deprecated Use org.apache.jackrabbit.util.Locked instead. */ +@Deprecated public abstract class Locked { /** diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/namespace/AbstractNamespaceResolver.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/namespace/AbstractNamespaceResolver.java index bdcb95227c4..6b74d015770 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/namespace/AbstractNamespaceResolver.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/namespace/AbstractNamespaceResolver.java @@ -35,6 +35,7 @@ * * @deprecated https://issues.apache.org/jira/browse/JCR-1700 */ +@Deprecated public abstract class AbstractNamespaceResolver implements NamespaceResolver { private final Set listeners; diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/namespace/NamespaceListener.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/namespace/NamespaceListener.java index a3ee219e596..e3203996bc1 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/namespace/NamespaceListener.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/namespace/NamespaceListener.java @@ -21,6 +21,7 @@ * * @deprecated https://issues.apache.org/jira/browse/JCR-1700 */ +@Deprecated public interface NamespaceListener { /** diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/namespace/SessionNamespaceResolver.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/namespace/SessionNamespaceResolver.java index 4d13fab49e4..528d033743d 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/namespace/SessionNamespaceResolver.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/namespace/SessionNamespaceResolver.java @@ -47,7 +47,7 @@ public String getPrefix(String uri) throws NamespaceException { return session.getNamespacePrefix(uri); } catch (RepositoryException e) { // should never get here... - throw new NamespaceException("internal error: failed to resolve namespace uri", e); + throw new NamespaceException("internal error: failed to resolve namespace uri: '" + uri + "'", e); } } @@ -59,7 +59,7 @@ public String getURI(String prefix) throws NamespaceException { return session.getNamespaceURI(prefix); } catch (RepositoryException e) { // should never get here... - throw new NamespaceException("internal error: failed to resolve namespace prefix", e); + throw new NamespaceException("internal error: failed to resolve namespace prefix: '" + prefix + "'", e); } } } diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/privilege/PrivilegeXmlHandler.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/privilege/PrivilegeXmlHandler.java index ffa24fe2001..6da6ab7e55f 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/privilege/PrivilegeXmlHandler.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/privilege/PrivilegeXmlHandler.java @@ -16,6 +16,7 @@ */ package org.apache.jackrabbit.spi.commons.privilege; +import org.apache.jackrabbit.commons.xml.XMLFactories; import org.apache.jackrabbit.spi.Name; import org.apache.jackrabbit.spi.NameFactory; import org.apache.jackrabbit.spi.PrivilegeDefinition; @@ -105,15 +106,7 @@ private static String createLicenseHeader() { /** * Constant for DocumentBuilderFactory. */ - private static DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = createFactory(); - - private static DocumentBuilderFactory createFactory() { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setIgnoringComments(false); - factory.setIgnoringElementContentWhitespace(true); - return factory; - } + private static DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = XMLFactories.safeDocumentBuilderFactory(); /** * Constant for TransformerFactory @@ -279,6 +272,8 @@ private PrivilegeDefinition parseDefinition(Node n, Map namespac */ private static DocumentBuilder createDocumentBuilder() throws ParserConfigurationException { DocumentBuilder builder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder(); + // defense in depth: entity resolver that will break any document on purpose + builder.setEntityResolver(XMLFactories.nonResolvingEntityResolver()); builder.setErrorHandler(new DefaultHandler()); return builder; } diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/OrderQueryNode.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/OrderQueryNode.java index f5a1d244073..542d1933b49 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/OrderQueryNode.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/OrderQueryNode.java @@ -135,6 +135,7 @@ public boolean isValid() { * ordered ascending; descending if false. * @deprecated use {@link #addOrderSpec(Path , boolean)} instead. */ + @Deprecated public void addOrderSpec(Name property, boolean ascending) { addOrderSpec(createPath(property), ascending); } @@ -232,6 +233,7 @@ public static final class OrderSpec { * ascending, otherwise descending. * @deprecated use {@link OrderSpec#OrderSpec(Path, boolean)} instead. */ + @Deprecated public OrderSpec(Name property, boolean ascending) { this(createPath(property), ascending); } @@ -254,6 +256,7 @@ public OrderSpec(Path property, boolean ascending) { * @return the name of the property. * @deprecated use {@link #getPropertyPath()} instead. */ + @Deprecated public Name getProperty() { return property.getName(); } diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/TextsearchQueryNode.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/TextsearchQueryNode.java index 15d1686e64f..3c2fe14ce82 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/TextsearchQueryNode.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/TextsearchQueryNode.java @@ -98,6 +98,7 @@ public String getQuery() { * @return property name or null. * @deprecated Use {@link #getRelativePath()} instead. */ + @Deprecated public Name getPropertyName() { return relPath == null ? null : relPath.getName(); } @@ -108,6 +109,7 @@ public Name getPropertyName() { * @param property the name of the property. * @deprecated Use {@link #setRelativePath(Path)} instead. */ + @Deprecated public void setPropertyName(Name property) { PathBuilder builder = new PathBuilder(); builder.addLast(property); diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql/SimpleCharStream.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql/SimpleCharStream.java index 2e085993bd7..9df5d742496 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql/SimpleCharStream.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql/SimpleCharStream.java @@ -218,7 +218,7 @@ public char readChar() throws java.io.IOException * @deprecated * @see #getEndColumn */ - + @Deprecated public int getColumn() { return bufcolumn[bufpos]; } @@ -227,7 +227,7 @@ public int getColumn() { * @deprecated * @see #getEndLine */ - + @Deprecated public int getLine() { return bufline[bufpos]; } diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql2/Parser.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql2/Parser.java index d8603db6197..22500e701f8 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql2/Parser.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql2/Parser.java @@ -25,6 +25,7 @@ * @deprecated use {@link org.apache.jackrabbit.commons.query.sql2.Parser} * instead. */ +@Deprecated public class Parser extends org.apache.jackrabbit.commons.query.sql2.Parser { diff --git a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/xpath/SimpleCharStream.java b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/xpath/SimpleCharStream.java index 1547afa8cb8..1d7f294d0e0 100644 --- a/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/xpath/SimpleCharStream.java +++ b/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/xpath/SimpleCharStream.java @@ -202,7 +202,7 @@ public char readChar() throws java.io.IOException * @deprecated * @see #getEndColumn */ - + @Deprecated public int getColumn() { return bufcolumn[bufpos]; } @@ -211,7 +211,7 @@ public int getColumn() { * @deprecated * @see #getEndLine */ - + @Deprecated public int getLine() { return bufline[bufpos]; } diff --git a/jackrabbit-spi/pom.xml b/jackrabbit-spi/pom.xml index ad9f80c260b..1128361ca28 100644 --- a/jackrabbit-spi/pom.xml +++ b/jackrabbit-spi/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-spi diff --git a/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/NodeInfo.java b/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/NodeInfo.java index da56567d520..13c454b3c32 100644 --- a/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/NodeInfo.java +++ b/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/NodeInfo.java @@ -71,6 +71,7 @@ public interface NodeInfo extends ItemInfo { * @see PropertyInfo#getId() * @deprecated Use {@link RepositoryService#getReferences(SessionInfo, NodeId, Name, boolean)} instead. */ + @Deprecated public PropertyId[] getReferences(); /** diff --git a/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java b/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java index a01385bec7b..09e6841766e 100644 --- a/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java +++ b/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java @@ -302,6 +302,7 @@ public SessionInfo obtain(SessionInfo sessionInfo, String workspaceName) * @see javax.jcr.version.Version#getContainingHistory() * @deprecated Use {@link #getItemInfos(SessionInfo, ItemId)} */ + @Deprecated public NodeInfo getNodeInfo(SessionInfo sessionInfo, NodeId nodeId) throws ItemNotFoundException, RepositoryException; /** @@ -382,6 +383,7 @@ public SessionInfo obtain(SessionInfo sessionInfo, String workspaceName) * @see javax.jcr.Node#getProperty(String) * @deprecated Use {@link #getItemInfos(SessionInfo, ItemId)} */ + @Deprecated public PropertyInfo getPropertyInfo(SessionInfo sessionInfo, PropertyId propertyId) throws ItemNotFoundException, RepositoryException; //-----------------------------------------------< general modification >--- diff --git a/jackrabbit-spi2dav/pom.xml b/jackrabbit-spi2dav/pom.xml index 0868d7505f6..ef70fbeda1e 100644 --- a/jackrabbit-spi2dav/pom.xml +++ b/jackrabbit-spi2dav/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-spi2dav diff --git a/jackrabbit-spi2jcr/pom.xml b/jackrabbit-spi2jcr/pom.xml index 379f04a0184..d5e6e13a475 100644 --- a/jackrabbit-spi2jcr/pom.xml +++ b/jackrabbit-spi2jcr/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-spi2jcr diff --git a/jackrabbit-standalone-components/pom.xml b/jackrabbit-standalone-components/pom.xml index ff367477d84..182f448f031 100644 --- a/jackrabbit-standalone-components/pom.xml +++ b/jackrabbit-standalone-components/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-standalone-components @@ -134,7 +134,7 @@ commons-cli commons-cli - 1.8.0 + 1.11.0 commons-chain @@ -150,7 +150,6 @@ org.apache.commons commons-collections4 - 4.4 commons-digester @@ -168,17 +167,6 @@ jline 0.9.94 - - commons-jexl - commons-jexl - 1.1 - - - commons-logging - commons-logging - - - diff --git a/jackrabbit-standalone/pom.xml b/jackrabbit-standalone/pom.xml index 0c1c5edcaef..f72d39b21b9 100644 --- a/jackrabbit-standalone/pom.xml +++ b/jackrabbit-standalone/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-standalone diff --git a/jackrabbit-vfs-ext/pom.xml b/jackrabbit-vfs-ext/pom.xml index b910efeeb4a..d496581dcdf 100644 --- a/jackrabbit-vfs-ext/pom.xml +++ b/jackrabbit-vfs-ext/pom.xml @@ -20,7 +20,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-vfs-ext @@ -44,57 +44,22 @@ org.apache.commons commons-vfs2 - 2.9.0 + 2.10.0 - commons-logging - commons-logging - - - - org.apache.hadoop - hadoop-hdfs-client - - - - - - org.apache.hadoop - hadoop-hdfs-client - 3.4.0 - - - org.jetbrains.kotlin - kotlin-stdlib-common + commons-io + commons-io - - - org.jetbrains.kotlin - kotlin-stdlib - 1.9.0 - org.apache.commons commons-vfs2-jackrabbit2 - 2.9.0 + 2.10.0 - commons-logging - commons-logging - - - org.apache.httpcomponents - httpclient - - - org.apache.jackrabbit - jackrabbit-webdav - - - org.apache.jackrabbit - jackrabbit-standalone-components + commons-io + commons-io diff --git a/jackrabbit-vfs-ext/src/main/java/org/apache/jackrabbit/vfs/ext/ds/VFSDataStore.java b/jackrabbit-vfs-ext/src/main/java/org/apache/jackrabbit/vfs/ext/ds/VFSDataStore.java index 5e03d66ad28..8dd9cfe9606 100644 --- a/jackrabbit-vfs-ext/src/main/java/org/apache/jackrabbit/vfs/ext/ds/VFSDataStore.java +++ b/jackrabbit-vfs-ext/src/main/java/org/apache/jackrabbit/vfs/ext/ds/VFSDataStore.java @@ -300,7 +300,7 @@ protected FileSystemManager createFileSystemManager() throws RepositoryException fileSystemManager = new StandardFileSystemManager(); } else { final Class mgrClass = Class.forName(getFileSystemManagerClassName()); - fileSystemManager = (FileSystemManager) mgrClass.newInstance(); + fileSystemManager = (FileSystemManager) mgrClass.getDeclaredConstructor().newInstance(); } if (fileSystemManager instanceof DefaultFileSystemManager) { diff --git a/jackrabbit-vfs-ext/src/main/java/org/apache/jackrabbit/vfs/ext/fs/VFSFileSystem.java b/jackrabbit-vfs-ext/src/main/java/org/apache/jackrabbit/vfs/ext/fs/VFSFileSystem.java index 8eb1ea1958c..21f08a4b60e 100755 --- a/jackrabbit-vfs-ext/src/main/java/org/apache/jackrabbit/vfs/ext/fs/VFSFileSystem.java +++ b/jackrabbit-vfs-ext/src/main/java/org/apache/jackrabbit/vfs/ext/fs/VFSFileSystem.java @@ -528,7 +528,7 @@ protected FileSystemManager createFileSystemManager() throws FileSystemException fileSystemManager = new StandardFileSystemManager(); } else { final Class mgrClass = Class.forName(getFileSystemManagerClassName()); - fileSystemManager = (FileSystemManager) mgrClass.newInstance(); + fileSystemManager = (FileSystemManager) mgrClass.getDeclaredConstructor().newInstance(); } if (fileSystemManager instanceof DefaultFileSystemManager) { diff --git a/jackrabbit-vfs-ext/src/test/java/org/apache/jackrabbit/vfs/ext/ds/TestVFSDataStore.java b/jackrabbit-vfs-ext/src/test/java/org/apache/jackrabbit/vfs/ext/ds/TestVFSDataStore.java index c8c89d2162a..43736aaba2f 100644 --- a/jackrabbit-vfs-ext/src/test/java/org/apache/jackrabbit/vfs/ext/ds/TestVFSDataStore.java +++ b/jackrabbit-vfs-ext/src/test/java/org/apache/jackrabbit/vfs/ext/ds/TestVFSDataStore.java @@ -32,14 +32,13 @@ import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder; import org.apache.jackrabbit.core.data.CachingDataStore; import org.apache.jackrabbit.core.data.TestCaseBase; +import org.junit.Assert; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.InputSource; -import junit.framework.Assert; - /** * Test {@link CachingDataStore} with VFSBackend with a VFS file system (local file system) by default. *

@@ -191,7 +190,11 @@ protected void doSetFileSystemOptionsPropertiesInString() throws Exception { File [] identities = configBuilder.getIdentities(fso); Assert.assertNotNull(identities); Assert.assertEquals(1, identities.length); - Assert.assertEquals("/home/tester/.ssh/id_rsa", FilenameUtils.separatorsToUnix(identities[0].getPath())); + String expectedPath = identities[0].getPath(); + if (FilenameUtils.getPrefixLength(expectedPath) != 0) { + expectedPath = expectedPath.substring(FilenameUtils.getPrefixLength(expectedPath) - 1); + } + Assert.assertEquals("/home/tester/.ssh/id_rsa", FilenameUtils.separatorsToUnix(expectedPath)); Assert.assertEquals(Integer.valueOf(30000), configBuilder.getTimeout(fso)); dataStore.close(); diff --git a/jackrabbit-webapp/pom.xml b/jackrabbit-webapp/pom.xml index 7c3a23184c0..528ff63baef 100644 --- a/jackrabbit-webapp/pom.xml +++ b/jackrabbit-webapp/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-webapp @@ -35,7 +35,7 @@ Web application that hosts and serves a Jackrabbit content repository - 9.0.89 + 9.0.118 @@ -102,9 +102,9 @@ test - net.sourceforge.htmlunit + org.htmlunit htmlunit - 2.70.0 + 4.21.0 test diff --git a/jackrabbit-webapp/src/test/java/org/apache/jackrabbit/j2ee/TomcatIT.java b/jackrabbit-webapp/src/test/java/org/apache/jackrabbit/j2ee/TomcatIT.java index b7d4b27aed4..bf2e57a157d 100644 --- a/jackrabbit-webapp/src/test/java/org/apache/jackrabbit/j2ee/TomcatIT.java +++ b/jackrabbit-webapp/src/test/java/org/apache/jackrabbit/j2ee/TomcatIT.java @@ -30,11 +30,11 @@ import org.apache.tomcat.util.scan.StandardJarScanner; import org.slf4j.bridge.SLF4JBridgeHandler; -import com.gargoylesoftware.htmlunit.WebClient; -import com.gargoylesoftware.htmlunit.html.HtmlElement; -import com.gargoylesoftware.htmlunit.html.HtmlForm; -import com.gargoylesoftware.htmlunit.html.HtmlInput; -import com.gargoylesoftware.htmlunit.html.HtmlPage; +import org.htmlunit.WebClient; +import org.htmlunit.html.HtmlElement; +import org.htmlunit.html.HtmlForm; +import org.htmlunit.html.HtmlInput; +import org.htmlunit.html.HtmlPage; public class TomcatIT extends TestCase { diff --git a/jackrabbit-webdav/pom.xml b/jackrabbit-webdav/pom.xml index f3daf3399e4..468a93f378e 100644 --- a/jackrabbit-webdav/pom.xml +++ b/jackrabbit-webdav/pom.xml @@ -26,7 +26,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT ../jackrabbit-parent/pom.xml jackrabbit-webdav diff --git a/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/property/PropContainer.java b/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/property/PropContainer.java index a86e55fea36..63d3b81be63 100644 --- a/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/property/PropContainer.java +++ b/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/property/PropContainer.java @@ -42,6 +42,7 @@ public abstract class PropContainer implements XmlSerializable, DavConstants { * @return true if the object could be added; false otherwise * @deprecated Use {@link #addContent(PropEntry)} instead. */ + @Deprecated public boolean addContent(Object contentEntry) { if (contentEntry instanceof PropEntry) { return addContent((PropEntry) contentEntry); diff --git a/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/version/WorkspaceResource.java b/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/version/WorkspaceResource.java index bfbbe5ff6e1..a5e6e309e28 100644 --- a/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/version/WorkspaceResource.java +++ b/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/version/WorkspaceResource.java @@ -56,6 +56,7 @@ public interface WorkspaceResource extends DeltaVResource { /** * @deprecated Use {@link #CURRENT_ACTIVITY_SET} instead. */ + @Deprecated public static final DavPropertyName CUURENT_ACTIVITY_SET = DavPropertyName.create("current-activity-set", DeltaVConstants.NAMESPACE); /** diff --git a/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/version/report/ReportType.java b/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/version/report/ReportType.java index 36bbe30b67e..8366814ba19 100644 --- a/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/version/report/ReportType.java +++ b/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/version/report/ReportType.java @@ -28,6 +28,7 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; +import java.lang.reflect.InvocationTargetException; import java.util.HashMap; /** @@ -68,13 +69,10 @@ private ReportType(String localName, Namespace namespace, String key, ClassExpanded Name. * */ + @Deprecated public static String getQualifiedName(String localName, Namespace namespace) { return getExpandedName(localName, namespace); } diff --git a/pom.xml b/pom.xml index cebd0a85f3b..00b7d8ab163 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ org.apache.jackrabbit jackrabbit-parent - 2.21.28-beta-SNAPSHOT + 2.23.6-beta-SNAPSHOT jackrabbit-parent/pom.xml @@ -87,6 +87,18 @@ + + coverage + + + + io.github.olamy.maven.plugins + jacoco-aggregator-maven-plugin + false + + + + apache-release @@ -171,10 +183,14 @@ A staged Maven repository is available for review at: https://repository.apache.org/ -The command for running automated checks against this release candidate is: +The command for running automated checks requires the use of a *nix +shell such as "bash" ("sh" will not work due to the lack of certain +built-in commands). On Windows, use Cygwin or WSL. + +To check this release candidate, run in a SVN checkout of +<https://dist.apache.org/repos/dist/dev/jackrabbit/>: - # run in SVN checkout of https://dist.apache.org/repos/dist/dev/jackrabbit/ - $ sh check-release.sh jackrabbit ${project.version} ${checksum} + $ ./check-release.sh jackrabbit ${project.version} ${checksum} Please vote on releasing this package as Apache Jackrabbit ${project.version}. The vote is open for the next 72 hours and passes if a majority of at diff --git a/test/compatibility/create10/pom.xml b/test/compatibility/create10/pom.xml deleted file mode 100644 index c93492436f5..00000000000 --- a/test/compatibility/create10/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-bc-parent - SNAPSHOT - ../parent/pom.xml - - - jackrabbit-bc-create10 - Jackrabbit 1.0 Repositories - - - - org.apache.jackrabbit - jackrabbit-bc-base - ${project.version} - test - - - org.apache.jackrabbit - jackrabbit-core - 1.0 - test - - - jsr170 - jcr - - - - - - - diff --git a/test/compatibility/create10/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java b/test/compatibility/create10/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java deleted file mode 100644 index d38aeab367f..00000000000 --- a/test/compatibility/create10/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java +++ /dev/null @@ -1,28 +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. - */ -package org.apache.jackrabbit.harness.compatibility; - -import org.testng.annotations.Test; - -public class CreateRepositoryTest extends AbstractRepositoryTest { - - @Test - public void createRepositories() throws Exception { - doCreateRepositories("jackrabbit-1.0"); - } - -} diff --git a/test/compatibility/create11/pom.xml b/test/compatibility/create11/pom.xml deleted file mode 100644 index 6f34f71863a..00000000000 --- a/test/compatibility/create11/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-bc-parent - SNAPSHOT - ../parent/pom.xml - - - jackrabbit-bc-create11 - Jackrabbit 1.0 Repositories - - - - ${project.groupId} - jackrabbit-bc-base - ${project.version} - test - - - org.apache.jackrabbit - jackrabbit-core - 1.1 - test - - - jsr170 - jcr - - - - - - - diff --git a/test/compatibility/create11/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java b/test/compatibility/create11/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java deleted file mode 100644 index 6f0f7881825..00000000000 --- a/test/compatibility/create11/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java +++ /dev/null @@ -1,28 +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. - */ -package org.apache.jackrabbit.harness.compatibility; - -import org.testng.annotations.Test; - -public class CreateRepositoryTest extends AbstractRepositoryTest { - - @Test - public void createRepositories() throws Exception { - doCreateRepositories("jackrabbit-1.1"); - } - -} diff --git a/test/compatibility/create12/pom.xml b/test/compatibility/create12/pom.xml deleted file mode 100644 index 5b3f977d8b9..00000000000 --- a/test/compatibility/create12/pom.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-bc-parent - SNAPSHOT - ../parent/pom.xml - - - jackrabbit-bc-create12 - Jackrabbit 1.2 Repositories - - - - ${project.groupId} - jackrabbit-bc-base - ${project.version} - test - - - org.apache.jackrabbit - jackrabbit-core - 1.2.1 - test - - - - - diff --git a/test/compatibility/create12/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java b/test/compatibility/create12/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java deleted file mode 100644 index 22fe200a008..00000000000 --- a/test/compatibility/create12/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java +++ /dev/null @@ -1,28 +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. - */ -package org.apache.jackrabbit.harness.compatibility; - -import org.testng.annotations.Test; - -public class CreateRepositoryTest extends AbstractRepositoryTest { - - @Test - public void createRepositories() throws Exception { - doCreateRepositories("jackrabbit-1.2"); - } - -} diff --git a/test/compatibility/create13/pom.xml b/test/compatibility/create13/pom.xml deleted file mode 100644 index 7912e1d89ea..00000000000 --- a/test/compatibility/create13/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-bc-parent - SNAPSHOT - ../parent/pom.xml - - - jackrabbit-bc-create13 - Jackrabbit 1.3 Repositories - - - - ${project.groupId} - jackrabbit-bc-base - ${project.version} - test - - - org.apache.jackrabbit - jackrabbit-core - 1.3 - test - - - org.slf4j - slf4j-log4j12 - 1.3.0 - test - - - - - diff --git a/test/compatibility/create13/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java b/test/compatibility/create13/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java deleted file mode 100644 index f841e6391ad..00000000000 --- a/test/compatibility/create13/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java +++ /dev/null @@ -1,28 +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. - */ -package org.apache.jackrabbit.harness.compatibility; - -import org.testng.annotations.Test; - -public class CreateRepositoryTest extends AbstractRepositoryTest { - - @Test - public void createRepositories() throws Exception { - doCreateRepositories("jackrabbit-1.3"); - } - -} diff --git a/test/compatibility/create13/src/test/resources/bundle.xml b/test/compatibility/create13/src/test/resources/bundle.xml deleted file mode 100644 index f5bd98ba8bd..00000000000 --- a/test/compatibility/create13/src/test/resources/bundle.xml +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/compatibility/create14/pom.xml b/test/compatibility/create14/pom.xml deleted file mode 100644 index 7b4e958902b..00000000000 --- a/test/compatibility/create14/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-bc-parent - SNAPSHOT - ../parent/pom.xml - - - jackrabbit-bc-create14 - Jackrabbit 1.4 Repositories - - - - ${project.groupId} - jackrabbit-bc-base - ${project.version} - test - - - org.apache.jackrabbit - jackrabbit-core - 1.4 - test - - - org.slf4j - slf4j-log4j12 - 1.3.0 - test - - - - - diff --git a/test/compatibility/create14/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java b/test/compatibility/create14/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java deleted file mode 100644 index 9c556b54b46..00000000000 --- a/test/compatibility/create14/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java +++ /dev/null @@ -1,28 +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. - */ -package org.apache.jackrabbit.harness.compatibility; - -import org.testng.annotations.Test; - -public class CreateRepositoryTest extends AbstractRepositoryTest { - - @Test - public void createRepositories() throws Exception { - doCreateRepositories("jackrabbit-1.4"); - } - -} diff --git a/test/compatibility/create14/src/test/resources/JCR-1808.xml b/test/compatibility/create14/src/test/resources/JCR-1808.xml deleted file mode 100644 index f12acae8626..00000000000 --- a/test/compatibility/create14/src/test/resources/JCR-1808.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/compatibility/create14/src/test/resources/datastore-db.xml b/test/compatibility/create14/src/test/resources/datastore-db.xml deleted file mode 100644 index 3430614ffde..00000000000 --- a/test/compatibility/create14/src/test/resources/datastore-db.xml +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/compatibility/create14/src/test/resources/datastore.xml b/test/compatibility/create14/src/test/resources/datastore.xml deleted file mode 100644 index 2f30b1d037d..00000000000 --- a/test/compatibility/create14/src/test/resources/datastore.xml +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/compatibility/create15/pom.xml b/test/compatibility/create15/pom.xml deleted file mode 100644 index ac123bd00a1..00000000000 --- a/test/compatibility/create15/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-bc-parent - SNAPSHOT - ../parent/pom.xml - - - jackrabbit-bc-create15 - Jackrabbit 1.5 Repositories - - - - ${project.groupId} - jackrabbit-bc-base - ${project.version} - test - - - org.apache.jackrabbit - jackrabbit-core - 1.5.0 - test - - - org.slf4j - slf4j-log4j12 - 1.5.3 - test - - - - - diff --git a/test/compatibility/create15/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java b/test/compatibility/create15/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java deleted file mode 100644 index ee54e9a3e42..00000000000 --- a/test/compatibility/create15/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java +++ /dev/null @@ -1,28 +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. - */ -package org.apache.jackrabbit.harness.compatibility; - -import org.testng.annotations.Test; - -public class CreateRepositoryTest extends AbstractRepositoryTest { - - @Test - public void createRepositories() throws Exception { - doCreateRepositories("jackrabbit-1.5"); - } - -} diff --git a/test/compatibility/create16/pom.xml b/test/compatibility/create16/pom.xml deleted file mode 100644 index 732576a1f9b..00000000000 --- a/test/compatibility/create16/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-bc-parent - SNAPSHOT - ../parent/pom.xml - - - jackrabbit-bc-create16 - Jackrabbit 1.6 Repositories - - - - ${project.groupId} - jackrabbit-bc-base - ${project.version} - test - - - org.apache.jackrabbit - jackrabbit-core - 1.6.0 - test - - - org.slf4j - slf4j-log4j12 - 1.5.3 - test - - - - - diff --git a/test/compatibility/create16/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java b/test/compatibility/create16/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java deleted file mode 100644 index 0d97efa21ef..00000000000 --- a/test/compatibility/create16/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java +++ /dev/null @@ -1,28 +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. - */ -package org.apache.jackrabbit.harness.compatibility; - -import org.testng.annotations.Test; - -public class CreateRepositoryTest extends AbstractRepositoryTest { - - @Test - public void createRepositories() throws Exception { - doCreateRepositories("jackrabbit-1.6"); - } - -} diff --git a/test/compatibility/create20/pom.xml b/test/compatibility/create20/pom.xml deleted file mode 100644 index 3a6a35fa7e6..00000000000 --- a/test/compatibility/create20/pom.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-bc-parent - SNAPSHOT - ../parent/pom.xml - - - jackrabbit-bc-create20 - Jackrabbit 2.0 Repositories - - - - ${project.groupId} - jackrabbit-bc-base - ${project.version} - test - - - javax.jcr - jcr - 2.0 - test - - - org.apache.jackrabbit - jackrabbit-core - 2.0.0 - test - - - org.slf4j - slf4j-log4j12 - 1.5.8 - test - - - - - diff --git a/test/compatibility/create20/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java b/test/compatibility/create20/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java deleted file mode 100644 index 5f70d17ebd5..00000000000 --- a/test/compatibility/create20/src/test/java/org/apache/jackrabbit/harness/compatibility/CreateRepositoryTest.java +++ /dev/null @@ -1,28 +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. - */ -package org.apache.jackrabbit.harness.compatibility; - -import org.testng.annotations.Test; - -public class CreateRepositoryTest extends AbstractRepositoryTest { - - @Test - public void createRepositories() throws Exception { - doCreateRepositories("jackrabbit-2.0"); - } - -} diff --git a/test/compatibility/parent/pom.xml b/test/compatibility/parent/pom.xml index f11a717ecbf..6bc05660b11 100644 --- a/test/compatibility/parent/pom.xml +++ b/test/compatibility/parent/pom.xml @@ -44,8 +44,8 @@ maven-compiler-plugin - 1.5 - 1.5 + 1.6 + 1.6 diff --git a/test/compatibility/pom.xml b/test/compatibility/pom.xml index 7bf435214d1..5b2a7ded0a8 100644 --- a/test/compatibility/pom.xml +++ b/test/compatibility/pom.xml @@ -41,14 +41,6 @@ parent base - create10 - create11 - create12 - create13 - create14 - create15 - create16 - create20 create21 create22 create24 diff --git a/test/performance/jackrabbit10/pom.xml b/test/performance/jackrabbit10/pom.xml deleted file mode 100644 index e30a5c818ef..00000000000 --- a/test/performance/jackrabbit10/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-perf-parent - 1-SNAPSHOT - ../parent/pom.xml - - - jackrabbit-perf-jackrabbit10 - Jackrabbit 1.0 Performance Test - - - - org.apache.jackrabbit - jackrabbit-perf-base - ${project.version} - test - - - org.apache.jackrabbit - jackrabbit-core - 1.0 - test - - - jsr170 - jcr - - - org.slf4j - slf4j-log4j12 - - - - - - - diff --git a/test/performance/jackrabbit11/pom.xml b/test/performance/jackrabbit11/pom.xml deleted file mode 100644 index d0c3c5d2d8f..00000000000 --- a/test/performance/jackrabbit11/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-perf-parent - 1-SNAPSHOT - ../parent/pom.xml - - - jackrabbit-perf-jackrabbit11 - Jackrabbit 1.1 Performance Test - - - - org.apache.jackrabbit - jackrabbit-perf-base - ${project.version} - test - - - org.apache.jackrabbit - jackrabbit-core - 1.1 - test - - - jsr170 - jcr - - - org.slf4j - slf4j-log4j12 - - - - - - - diff --git a/test/performance/jackrabbit12/pom.xml b/test/performance/jackrabbit12/pom.xml deleted file mode 100644 index 9ff4fab9700..00000000000 --- a/test/performance/jackrabbit12/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-perf-parent - 1-SNAPSHOT - ../parent/pom.xml - - - jackrabbit-perf-jackrabbit12 - Jackrabbit 1.2 Performance Test - - - - org.apache.jackrabbit - jackrabbit-perf-base - ${project.version} - test - - - org.apache.jackrabbit - jackrabbit-core - 1.2.1 - test - - - org.slf4j - slf4j-log4j12 - - - - - - - diff --git a/test/performance/jackrabbit12/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java b/test/performance/jackrabbit12/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java deleted file mode 100644 index 76266ef8dd2..00000000000 --- a/test/performance/jackrabbit12/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java +++ /dev/null @@ -1,28 +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. - */ -package org.apache.jackrabbit.performance; - -import org.testng.annotations.Test; - -public class PerformanceTest extends AbstractPerformanceTest { - - @Test - public void testPerformance() throws Exception { - testPerformance("1.2"); - } - -} diff --git a/test/performance/jackrabbit13/pom.xml b/test/performance/jackrabbit13/pom.xml deleted file mode 100644 index 90b5dec10ea..00000000000 --- a/test/performance/jackrabbit13/pom.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-perf-parent - 1-SNAPSHOT - ../parent/pom.xml - - - jackrabbit-perf-jackrabbit13 - Jackrabbit 1.3 Performance Test - - - - org.apache.jackrabbit - jackrabbit-perf-base - ${project.version} - test - - - org.apache.jackrabbit - jackrabbit-core - 1.3 - test - - - - - diff --git a/test/performance/jackrabbit13/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java b/test/performance/jackrabbit13/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java deleted file mode 100644 index fc4df262cac..00000000000 --- a/test/performance/jackrabbit13/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java +++ /dev/null @@ -1,28 +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. - */ -package org.apache.jackrabbit.performance; - -import org.testng.annotations.Test; - -public class PerformanceTest extends AbstractPerformanceTest { - - @Test - public void testPerformance() throws Exception { - testPerformance("1.3"); - } - -} diff --git a/test/performance/jackrabbit14/pom.xml b/test/performance/jackrabbit14/pom.xml deleted file mode 100644 index b28716fc3a6..00000000000 --- a/test/performance/jackrabbit14/pom.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-perf-parent - 1-SNAPSHOT - ../parent/pom.xml - - - jackrabbit-perf-jackrabbit14 - Jackrabbit 1.4 Performance Test - - - - org.apache.jackrabbit - jackrabbit-perf-base - ${project.version} - test - - - org.apache.jackrabbit - jackrabbit-core - 1.4 - test - - - - - diff --git a/test/performance/jackrabbit14/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java b/test/performance/jackrabbit14/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java deleted file mode 100644 index ce7d671bc76..00000000000 --- a/test/performance/jackrabbit14/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java +++ /dev/null @@ -1,28 +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. - */ -package org.apache.jackrabbit.performance; - -import org.testng.annotations.Test; - -public class PerformanceTest extends AbstractPerformanceTest { - - @Test - public void testPerformance() throws Exception { - testPerformance("1.4"); - } - -} diff --git a/test/performance/jackrabbit15/pom.xml b/test/performance/jackrabbit15/pom.xml deleted file mode 100644 index 449540d756d..00000000000 --- a/test/performance/jackrabbit15/pom.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-perf-parent - 1-SNAPSHOT - ../parent/pom.xml - - - jackrabbit-perf-jackrabbit15 - Jackrabbit 1.5 Performance Test - - - - org.apache.jackrabbit - jackrabbit-perf-base - ${project.version} - test - - - org.apache.jackrabbit - jackrabbit-core - 1.5.0 - test - - - - - diff --git a/test/performance/jackrabbit15/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java b/test/performance/jackrabbit15/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java deleted file mode 100644 index 6772594f499..00000000000 --- a/test/performance/jackrabbit15/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java +++ /dev/null @@ -1,28 +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. - */ -package org.apache.jackrabbit.performance; - -import org.testng.annotations.Test; - -public class PerformanceTest extends AbstractPerformanceTest { - - @Test - public void testPerformance() throws Exception { - testPerformance("1.5"); - } - -} diff --git a/test/performance/jackrabbit16/pom.xml b/test/performance/jackrabbit16/pom.xml deleted file mode 100644 index a3a3ad4f086..00000000000 --- a/test/performance/jackrabbit16/pom.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-perf-parent - 1-SNAPSHOT - ../parent/pom.xml - - - jackrabbit-perf-jackrabbit16 - Jackrabbit 1.6 Performance Test - - - - org.apache.jackrabbit - jackrabbit-perf-base - ${project.version} - test - - - org.apache.jackrabbit - jackrabbit-core - 1.6.0 - test - - - - - diff --git a/test/performance/jackrabbit16/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java b/test/performance/jackrabbit16/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java deleted file mode 100644 index ecd3a86e52c..00000000000 --- a/test/performance/jackrabbit16/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java +++ /dev/null @@ -1,28 +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. - */ -package org.apache.jackrabbit.performance; - -import org.testng.annotations.Test; - -public class PerformanceTest extends AbstractPerformanceTest { - - @Test - public void testPerformance() throws Exception { - testPerformance("1.6"); - } - -} diff --git a/test/performance/jackrabbit20/pom.xml b/test/performance/jackrabbit20/pom.xml deleted file mode 100644 index e45d0aeb6a0..00000000000 --- a/test/performance/jackrabbit20/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - jackrabbit-perf-parent - 1-SNAPSHOT - ../parent/pom.xml - - - jackrabbit-perf-jackrabbit20 - Jackrabbit 2.0 Performance Test - - - - org.apache.jackrabbit - jackrabbit-perf-base - ${project.version} - test - - - javax.jcr - jcr - 2.0 - test - - - org.apache.jackrabbit - jackrabbit-core - 2.0.0 - test - - - - - diff --git a/test/performance/jackrabbit20/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java b/test/performance/jackrabbit20/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java deleted file mode 100644 index c64c617c07a..00000000000 --- a/test/performance/jackrabbit20/src/test/java/org/apache/jackrabbit/performance/PerformanceTest.java +++ /dev/null @@ -1,28 +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. - */ -package org.apache.jackrabbit.performance; - -import org.testng.annotations.Test; - -public class PerformanceTest extends AbstractPerformanceTest { - - @Test - public void testPerformance() throws Exception { - testPerformance("2.0"); - } - -} diff --git a/test/performance/pom.xml b/test/performance/pom.xml index 4a0330d27e2..f41929ddacd 100644 --- a/test/performance/pom.xml +++ b/test/performance/pom.xml @@ -41,14 +41,6 @@ parent base - - jackrabbit20 jackrabbit21 jackrabbit22 jackrabbit23