diff --git a/.github/workflows/ci-actions.yml b/.github/workflows/ci-actions.yml new file mode 100644 index 0000000000..f838948f15 --- /dev/null +++ b/.github/workflows/ci-actions.yml @@ -0,0 +1,378 @@ +name: Weld CI + +on: + pull_request: + branches: [ 3.1 ] + # Do not run for non-code changes + paths-ignore: + - '.gitignore' + - '*.md' + - '*.adoc' + - '*.txt' + +jobs: + # builds Weld snapshot, downloads WFLY and upgrades it, prepares ENV variable + build-jdk11: + name: "Initial JDK 11 Weld Build + WildFly patch" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up JDK + uses: actions/setup-java@v1.4.3 + with: + java-version: 11 + - name: Download WildFly + # WFLY 26 is the last to support EE 8 and JDK 8, see also https://www.wildfly.org/news/2022/01/21/WildFly-2022/ + run: | + wget https://github.com/wildfly/wildfly/releases/download/26.0.1.Final/wildfly-26.0.1.Final.zip + unzip wildfly-26.0.1.Final.zip -d container + rm wildfly-26.0.1.Final.zip + - name: Get Date + id: get-date + run: | + echo "::set-output name=date::$(/bin/date -u "+%Y-%m")" + shell: bash + - name: Cache Maven Repository + id: cache-maven + uses: actions/cache@v2 + with: + path: ~/.m2/repository + # Caching is an automated pre/post action that installs the cache if the key exists and exports the cache + # after the job is done. In this case we refresh the cache monthly (by changing key) to avoid unlimited growth. + key: q2maven-${{ steps.get-date.outputs.date }} + - name: Build Weld SNAPSHOT + run: mvn clean install -DskipTests -B -V -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 + - name: Patch WildFly + run: | + JBOSS_HOME=`pwd`'/container/*' + export JBOSS_HOME=`echo $JBOSS_HOME` + mvn clean package -Pupdate-jboss-as -Dtck -f jboss-as/pom.xml + - name: Zip Patched WildFly + run: | + cd container/ + mv ./* wildfly/ + zip -r wildfly.zip wildfly + cd .. + - name: Persist WildFly + uses: actions/upload-artifact@v1 + with: + name: wildfly-patched-zip + path: container/wildfly.zip + - name: Tar Maven Repo + shell: bash + run: tar -czf maven-repo.tgz -C ~ .m2/repository + - name: Persist Maven Repo + uses: actions/upload-artifact@v1 + with: + name: maven-repo + path: maven-repo.tgz + - name: Delete Local Artifacts From Cache + shell: bash + run: rm -r ~/.m2/repository/org/jboss/weld* + + # Weld in-container tests, does NOT include TCKs which are run as a separate job + incontainer-tests: + name: "Weld In-container Tests - JDK ${{matrix.java.name}}" + runs-on: ubuntu-latest + needs: build-jdk11 + timeout-minutes: 120 + strategy: + fail-fast: false + matrix: + java: + - { name: "8", + java-version: 8, + } + - { + name: "11", + java-version: 11, + } + steps: + - uses: actions/checkout@v2 + - name: Set up JDK ${{ matrix.java.name }} + uses: actions/setup-java@v1.4.3 + with: + java-version: ${{ matrix.java.java-version }} + + - name: Download Maven Repo + uses: actions/download-artifact@v1 + with: + name: maven-repo + path: . + - name: Extract Maven Repo + shell: bash + run: tar -xzf maven-repo.tgz -C ~ + - name: Download Patched WildFly + uses: actions/download-artifact@v1 + with: + name: wildfly-patched-zip + path: . + - name: Extract WildFly + run: unzip wildfly.zip + - name: Build with Maven + run: | + JBOSS_HOME=`pwd`'/wildfly' + export JBOSS_HOME=`echo $JBOSS_HOME` + mvn clean verify -Dincontainer -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -pl '!jboss-tck-runner,!impl' + - name: Prepare failure archive (if maven failed) + if: failure() + shell: bash + run: | + find . -name '*-reports' -type d | tar -czf test-reports.tgz -T - + find . -name 'server.log' -type f | tar -czf server-log.tgz -T - + - name: Upload failure Archive (if maven failed) + uses: actions/upload-artifact@v1 + if: failure() + with: + name: test-reports-incontainer-jdk${{matrix.java.name}} + path: 'test-reports.tgz' + - name: Upload server log artifact (if maven failed) + uses: actions/upload-artifact@v1 + if: failure() + with: + name: server-log-incontainer-jdk${{matrix.java.name}} + path: 'server-log.tgz' + + # CDI TCKs in WildFly + CDI-TCK: + name: "CDI TCK - JDK ${{matrix.java.name}}" + runs-on: ubuntu-latest + needs: build-jdk11 + timeout-minutes: 120 + strategy: + fail-fast: false + matrix: + java: + - { name: "8", + java-version: 8, + } + - { + name: "11", + java-version: 11, + } + steps: + - uses: actions/checkout@v2 + - name: Set up JDK ${{ matrix.java.name }} + uses: actions/setup-java@v1.4.3 + with: + java-version: ${{ matrix.java.java-version }} + + - name: Download Maven Repo + uses: actions/download-artifact@v1 + with: + name: maven-repo + path: . + - name: Extract Maven Repo + shell: bash + run: tar -xzf maven-repo.tgz -C ~ + - name: Download Patched WildFly + uses: actions/download-artifact@v1 + with: + name: wildfly-patched-zip + path: . + - name: Extract WildFly + run: unzip wildfly.zip + - name: Build with Maven + run: | + JBOSS_HOME=`pwd`'/wildfly' + export JBOSS_HOME=`echo $JBOSS_HOME` + mvn clean verify -Dincontainer -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -f jboss-tck-runner/pom.xml + - name: Prepare failure archive (if maven failed) + if: failure() + shell: bash + run: | + find . -name '*-reports' -type d | tar -czf test-reports.tgz -T - + find . -name 'server.log' -type f | tar -czf server-log.tgz -T - + - name: Upload failure Archive (if maven failed) + uses: actions/upload-artifact@v1 + if: failure() + with: + name: test-reports-cdi-tck-jdk${{matrix.java.name}} + path: 'test-reports.tgz' + - name: Upload server log artifact (if maven failed) + uses: actions/upload-artifact@v1 + if: failure() + with: + name: server-log-cdi-tck-jdk${{matrix.java.name}} + path: 'server-log.tgz' + + # Weld no-container tests, includes junit, Weld SE tests plus CDI TCKs and integration tests that don't require EE container + no-container-tests: + name: "Weld Tests w/o Container - JDK ${{matrix.java.name}}" + runs-on: ubuntu-latest + needs: build-jdk11 + timeout-minutes: 120 + strategy: + fail-fast: false + matrix: + java: + - { name: "8", + java-version: 8, + } + - { + name: "11", + java-version: 11, + } + steps: + - uses: actions/checkout@v2 + - name: Set up JDK ${{ matrix.java.name }} + uses: actions/setup-java@v1.4.3 + with: + java-version: ${{ matrix.java.java-version }} + + - name: Download Maven Repo + uses: actions/download-artifact@v1 + with: + name: maven-repo + path: . + - name: Extract Maven Repo + shell: bash + run: tar -xzf maven-repo.tgz -C ~ + - name: Build with Maven + # avoid building impl as that can only be done with JDK 11 + run: | + mvn clean verify -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -pl '!impl' + - name: Test core-impl separately + run: | + mvn surefire:test -f impl/pom.xml + - name: Prepare failure archive (if maven failed) + if: failure() + shell: bash + run: find . -name '*-reports' -type d | tar -czf test-reports.tgz -T - + - name: Upload failure Archive (if maven failed) + uses: actions/upload-artifact@v1 + if: failure() + with: + name: test-reports-no-container-jdk${{matrix.java.name}} + path: 'test-reports.tgz' + + # Weld Examples build and test, only JDK 11 + examples-tests: + name: "Weld Examples build and test - JDK 11}" + runs-on: ubuntu-latest + needs: build-jdk11 + timeout-minutes: 120 + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v1.4.3 + with: + java-version: 11 + - name: Download Maven Repo + uses: actions/download-artifact@v1 + with: + name: maven-repo + path: . + - name: Extract Maven Repo + shell: bash + run: tar -xzf maven-repo.tgz -C ~ + - name: Download Patched WildFly + uses: actions/download-artifact@v1 + with: + name: wildfly-patched-zip + path: . + - name: Extract WildFly + run: unzip wildfly.zip + - name: Build with Maven + run: | + JBOSS_HOME=`pwd`'/wildfly' + export JBOSS_HOME=`echo $JBOSS_HOME` + mvn clean verify -Darquillian=wildfly-managed -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -f examples/pom.xml + - name: Prepare failure archive (if maven failed) + if: failure() + shell: bash + run: | + find . -name '*-reports' -type d | tar -czf test-reports.tgz -T - + find . -name 'server.log' -type f | tar -czf server-log.tgz -T - + - name: Upload failed tests artifact (if maven failed) + uses: actions/upload-artifact@v1 + if: failure() + with: + name: test-reports-examples + path: 'test-reports.tgz' + - name: Upload server log artifact (if maven failed) + uses: actions/upload-artifact@v1 + if: failure() + with: + name: server-log-examples + path: 'test-reports.tgz' + + # CDI TCK for SE environment + CDI-TCK-SE: + name: "CDI TCK SE - JDK ${{matrix.java.name}}" + runs-on: ubuntu-latest + needs: build-jdk11 + timeout-minutes: 120 + strategy: + fail-fast: false + matrix: + java: + - { name: "8", + java-version: 8, + } + - { + name: "11", + java-version: 11, + } + steps: + - uses: actions/checkout@v2 + - name: Set up JDK ${{ matrix.java.name }} + uses: actions/setup-java@v1.4.3 + with: + java-version: ${{ matrix.java.java-version }} + + - name: Download Maven Repo + uses: actions/download-artifact@v1 + with: + name: maven-repo + path: . + - name: Extract Maven Repo + shell: bash + run: tar -xzf maven-repo.tgz -C ~ + - name: Build with Maven + run: | + mvn clean verify -Dincontainer=se -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -f jboss-tck-runner/pom.xml + - name: Prepare failure archive (if maven failed) + if: failure() + shell: bash + run: find . -name '*-reports' -type d | tar -czf test-reports.tgz -T - + - name: Upload failure Archive (if maven failed) + uses: actions/upload-artifact@v1 + if: failure() + with: + name: test-reports-cdi-tck-se-jdk${{matrix.java.name}} + path: 'test-reports.tgz' + + # Weld SE/Servlet cooperation + weld-se-servlet-coop: + name: "Weld SE-Servlet Cooperation" + runs-on: ubuntu-latest + needs: build-jdk11 + timeout-minutes: 20 + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v1.4.3 + with: + java-version: 11 + - name: Download Maven Repo + uses: actions/download-artifact@v1 + with: + name: maven-repo + path: . + - name: Extract Maven Repo + shell: bash + run: tar -xzf maven-repo.tgz -C ~ + - name: Build with Maven + run: | + mvn clean verify -Dincontainer=weld-se-coop -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -f environments/servlet/tests/jetty/pom.xml + - name: Prepare failure archive (if maven failed) + if: failure() + shell: bash + run: find . -name '*-reports' -type d | tar -czf test-reports.tgz -T - + - name: Upload failure Archive (if maven failed) + uses: actions/upload-artifact@v1 + if: failure() + with: + name: test-reports-se-servlet-coop + path: 'test-reports.tgz' \ No newline at end of file diff --git a/.gitignore b/.gitignore index 82f8660ee0..2ccf56c743 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .project +.checkstyle .classpath .settings .factorypath diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index cf90fc75f8..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: java -jdk: - - openjdk8 - - openjdk11 -script: "mvn verify" -sudo: false -cache: - directories: - - $HOME/.m2/repository diff --git a/README.md b/README.md index 685799e918..38208cdc2e 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ -Weld -==== +# Weld [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/weld/user) -[![Travis CI Build Status](https://img.shields.io/travis/weld/core/master.svg)](https://travis-ci.org/weld/core) +![GH Actions Build Status](https://github.com/weld/core/actions/workflows/ci-actions.yml/badge.svg?branch=3.1) [![Maven Central](http://img.shields.io/maven-central/v/org.jboss.weld.se/weld-se-shaded.svg)](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22weld-core-impl%22) [![License](https://img.shields.io/badge/license-Apache%20License%202.0-yellow.svg)](http://www.apache.org/licenses/LICENSE-2.0.html) @@ -12,15 +11,13 @@ Weld is integrated into many Java EE application servers such as WildFly, JBoss See http://weld.cdi-spec.org for more details. -Building Weld -------------- +## Building Weld To build Weld simply run > $ mvn clean install -Upgrading Weld in WildFly -------------------------- +## Upgrading Weld in WildFly Firstly, set the `JBOSS_HOME` environment property to point to your WildFly installation which already contains Weld 3 in older version: @@ -33,35 +30,7 @@ Then, run the upgrade script: In the above snippet, `${weld.version}` is the version of Weld you want to use. Now you should have patched WildFly in `JBOSS_HOME`. -Creating a patch file for WildFly ---------------------------------- - -Apart from just patching a WildFly, there is an automated way to create reusable patch-file too. -To do that, three things are needed: -* Clean WildFly - * A basis which you want the patch for - * If you use `-Pdownload-wfly` profile, latest patch-able WildFly version will be automatically downloaded into `core/jboss-as/target` folder - * If you already have WildFly, set the path to it throught property `-DwildflyOriginal=/path/to/clean/wfly` -* Patched WildFly with Weld 3 version you want - * `-Pupdate-jboss-as` can be used to create patched WildFly, see the paragraph above - * If you have this in advance, just set the path to it via `-DwildflyPatched=/path/to/patched/wfly` -* Patch XML descriptor - * By default, this is automatically grabbed from our [repository](https://github.com/weld/build/tree/master/wildfly) for given WildFly - * You can set different version via `-Dpatch.file.name="patch-config-wildfly-15-weld-3.1.xml"` - -So, here are some commands: -* `mvn clean package -Pdownload-wfly,update-jboss-as,wfly-patch-gen` - * Fully automated way of downloading pristine WildFly, patching it and creating a patch file, all in `jboss-as/target` folder -* `mvn clean install -Pupdate-jboss-as,download-wfly -f jboss-as/pom.xml` - * This will download pristine WildFly, make a copy of it and patch it right away - * No patch file will be generated -* `export JBOSS_HOME=/path/to/wfly; mvn clean install -Pwfly-patch-gen -DwildflyOriginal=/opt/myCleanWfly -DwildflyPatched=/opt/myPatchedWfly -f jboss-as/pom.xml` - * This is a manual way where all variables are specified; here we generate patch file for Wildfly - * Need to specify both WildFly instances - clean one and already patched one - * You can also provide specific patch XML descriptor if the default one doesn't suit through `-DpatchConfig=patch-config-wildfly-15-weld-3.1.xml` - -Running integration tests and the TCK on WildFly ----------------------------------------------------- +## Running integration tests and the TCK on WildFly Follow the steps above to set the JBOSS_HOME environment property and to upgrade Weld within WildFly. Then, run: @@ -70,7 +39,7 @@ within WildFly. Then, run: > $ mvn clean verify -Dincontainer -f jboss-tck-runner/pom.xml -If you want to run a specific test you can use the `-Dtest=` flag. For example +If you want to run a specific test you can use the `-Dtest=` flag. For example > $ mvn clean verify -Dincontainer -f jboss-tck-runner/pom.xml -Dtest=FireEventTest diff --git a/bom/pom.xml b/bom/pom.xml index ecba3b1192..e5895db99c 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -4,7 +4,7 @@ org.jboss.weld weld-core-bom pom - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT Weld Core BOM @@ -30,8 +30,8 @@ - 3.1.SP2 - 1.6 + 3.1.SP4 + 3.0.1 https://repository.jboss.org/nexus/service/local/staging/deploy/maven2/ https://repository.jboss.org/nexus/content/repositories/snapshots/ https://oss.sonatype.org/service/local/staging/deploy/maven2 diff --git a/bundles/osgi/pom.xml b/bundles/osgi/pom.xml index 9885db1c4c..01ca6e5ae2 100644 --- a/bundles/osgi/pom.xml +++ b/bundles/osgi/pom.xml @@ -3,7 +3,7 @@ weld-core-parent org.jboss.weld - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml 4.0.0 @@ -53,7 +53,7 @@ maven-bundle-plugin - *; scope=compile; inline=true + *; scope=compile; inline=true; optional=false; <_exportcontents> @@ -70,7 +70,10 @@ org.jboss.weld.probe; - org.jboss.weld.module.*; + org.jboss.weld.module.ejb.*; + org.jboss.weld.module.jsf.*; + org.jboss.weld.module.jta.*; + org.jboss.weld.module.web.*; org.jboss.weld; @@ -79,6 +82,7 @@ org.jboss.weld.bean.proxy; org.jboss.weld.bootstrap; org.jboss.weld.config; + org.jboss.weld.contexts.*; org.jboss.weld.event; org.jboss.weld.exceptions; org.jboss.weld.injection; @@ -86,6 +90,7 @@ org.jboss.weld.interceptor.util.proxy; org.jboss.weld.logging; org.jboss.weld.manager; + org.jboss.weld.module.*; org.jboss.weld.security; org.jboss.weld.util; org.jboss.weld.xml; @@ -175,24 +180,26 @@ - + org.apache.maven.plugins maven-shade-plugin + copy-meta-inf-contents shade + verify - + true false - + org.jboss.weld:weld-osgi-bundle @@ -284,8 +291,72 @@ weld-probe-core + + + + org.jboss.spec.javax.servlet + jboss-servlet-api_4.0_spec + true + + + jakarta.persistence + jakarta.persistence-api + true + + + + release + + + release + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + com.github.spotbugs + spotbugs-annotations + ${spotbugs-annotations-version} + + + org.jboss.logging + jboss-logging-annotations + ${jboss.logging.processor.version} + + + org.apache.bcel + bcel + ${apache.bcel.version} + + + org.jboss.spec.javax.faces + jboss-jsf-api_2.3_spec + ${jboss.jsf.api.version} + + + + + + javadoc + package + + jar + + + + + + + + + scm:git:git@github.com:weld/core.git diff --git a/docs/reference/pom.xml b/docs/reference/pom.xml index ace6a32192..b2e49a8be3 100644 --- a/docs/reference/pom.xml +++ b/docs/reference/pom.xml @@ -4,8 +4,8 @@ org.jboss.weld.reference-guide weld-reference-guide - 3.1.5-SNAPSHOT - jdocbook + 3.1.11-SNAPSHOT + pom Weld Reference Guide http://weld.cdi-spec.org @@ -20,19 +20,19 @@ org.jboss.weld weld-core-parent - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml The Weld reference guide - 1.5.7.1 + 2.2.2 + 1.6.2 weld-reference.pdf + index.html ${project.version} - target/docbook - 2.3.10 - 2.0.2 + target/docbook http://docs.jboss.org/weld/reference/latest-master/en-US/html @@ -43,91 +43,72 @@ org.asciidoctor asciidoctor-maven-plugin ${asciidoctor.version} + + + org.asciidoctor + asciidoctorj-pdf + ${asciidoctorj-pdf.version} + + - output-docbook - generate-sources + generate-pdf-doc + generate-resources + + process-asciidoc + + + pdf + Weld_-_JSR-299_Reference_Implementation.asciidoc + ${doc.output.directory}/en-US/pdf + ${pdf.name} + + + + output-html + generate-resources process-asciidoc - docbook45 - book - true + html5 Weld_-_JSR-299_Reference_Implementation.asciidoc - slim - true - false - ${jdocbook.source.directory}/en-US + ${doc.output.directory}/en-US/html_single + ${html.name} + + + + output-html-chunked + generate-resources + + process-asciidoc + + + html5 - true - true - ${weld.version} + shared + + left + 3 + + + ${doc.output.directory}/en-US/html - - - org.jboss.maven.plugins - maven-jdocbook-plugin - ${jdocbook.plugin.version} - true - ${basedir}/${jdocbook.source.directory} - Weld_-_JSR-299_Reference_Implementation.xml - en-US - - ${project.basedir}/src/main/asciidoc - - images/*.png - - - - ${project.basedir}/src/main/style/css - - css/*.css - - - - - pdf - classpath:/xslt/org/jboss/pdf.xsl - ${pdf.name} - - - html - file:${project.basedir}/src/main/style/xslt/org/jboss/weld/xhtml.xsl - index.html - - - html_single - file:${project.basedir}/src/main/style/xslt/org/jboss/weld/xhtml-single.xsl - index.html - - - - true - saxon - 1.77.1 - - - dd/MM/yyyy - + book + ${basedir}/src/main/asciidoc + slim + true + + true + true + ${weld.version} + - - - org.jboss.pressgang - pressgang-xslt-ns - ${pressgang.version} - - - org.jboss.pressgang - pressgang-jdocbook-style - jdocbook-style - ${pressgang.version} - - maven-antrun-plugin @@ -135,9 +116,9 @@ process-classes - - - + + + run @@ -145,68 +126,6 @@ - - maven-resources-plugin - - - copy-resources - validate - - copy-resources - - - ${basedir}/target/docbook/publish/en-US/html/ - - - - src/main/sitemap - true - - sitemap.xml - - - - - - - - - - - jboss-plugin-public-repository - - true - - - - jboss-repo - https://repository.jboss.org/nexus/content/groups/public - - true - - - false - - - - - - jboss-public-repository-group - JBoss Public Maven Repository Group - http://repository.jboss.org/nexus/content/groups/public - - true - never - - - false - never - - - - - - diff --git a/docs/reference/src/main/asciidoc/Weld_-_JSR-299_Reference_Implementation.asciidoc b/docs/reference/src/main/asciidoc/Weld_-_JSR-299_Reference_Implementation.asciidoc index 2660e64aa7..872e0fda80 100644 --- a/docs/reference/src/main/asciidoc/Weld_-_JSR-299_Reference_Implementation.asciidoc +++ b/docs/reference/src/main/asciidoc/Weld_-_JSR-299_Reference_Implementation.asciidoc @@ -1,5 +1,7 @@ :numbered!: :icons: font +:toc: left +:toclevels: 3 = Weld {weldVersion} - CDI Reference Implementation [preface] diff --git a/docs/reference/src/main/asciidoc/Weld_-_JSR-299_Reference_Implementation.ent b/docs/reference/src/main/asciidoc/Weld_-_JSR-299_Reference_Implementation.ent deleted file mode 100644 index eabf013d37..0000000000 --- a/docs/reference/src/main/asciidoc/Weld_-_JSR-299_Reference_Implementation.ent +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/docs/reference/src/main/asciidoc/beans.asciidoc b/docs/reference/src/main/asciidoc/beans.asciidoc index e9b4a2bd3f..6164d941f6 100644 --- a/docs/reference/src/main/asciidoc/beans.asciidoc +++ b/docs/reference/src/main/asciidoc/beans.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[beanscdi]] == More about beans @@ -49,7 +53,10 @@ We can replace one bean with another different bean that implements the same interface and has a different lifecycle (a different scope) without affecting the other bean implementation. In fact, CDI defines a simple facility for overriding bean implementations at deployment time, as we -will see in <>. +will see in +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:injection.html#alternatives[Alternatives]] +. Note that not all clients of a bean are beans themselves. Other objects such as servlets or message-driven beans—which are by nature not @@ -121,7 +128,9 @@ NOTE: The bean types of a session bean include local interfaces and the bean class local view (if any). EJB remote interfaces are not considered bean types of a session bean. You can't inject an EJB using its remote interface unless you define a _resource_, which we'll meet in -<>. +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:resources.html[Java EE component environment resources]] +. Bean types may be restricted to an explicit set by annotating the bean with the `@Typed` annotation and listing the classes that should be bean @@ -202,7 +211,10 @@ it has the default qualifier, `@Default`. That's not quite the end of the story. CDI also defines a simple _resolution rule_ that helps the container decide what to do if there is more than one bean that satisfies a particular contract. We'll get into -the details in <>. +the details in +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:injection.html[Dependency injection and programmatic lookup]] +. ==== Scope @@ -234,7 +246,10 @@ special scope called the _dependent pseudo-scope_. Beans with this scope live to serve the object into which they were injected, which means their lifecycle is bound to the lifecycle of that object. -We'll talk more about scopes in <>. +We'll talk more about scopes in +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:scopescontexts.html[Scopes and contexts]] +. ==== EL name @@ -301,7 +316,10 @@ Different modules can specify that they use different alternatives. The other way to enable an alternative is to annotate the bean with `@Priority` annotation. This will enable it globally. -We cover alternatives in more detail in <>. +We cover alternatives in more detail in +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:injection.html#alternatives[Alternatives]] +. ==== Interceptor binding types @@ -370,7 +388,14 @@ also where we specify the interceptor ordering. Better still, we can use `@Priority` annotation to enable the interceptor and define it's ordering at the same time. -We'll discuss interceptors, and their cousins, decorators, in <> and <>. +We'll discuss interceptors, and their cousins, decorators, in +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:interceptors.html[Interceptors]] +and +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:decorators.html[Decorators]] +. +<> and <>. === What kinds of classes are beans? @@ -590,7 +615,10 @@ injection. } ------------------------------------------ -We'll talk much more about producer methods in <>. +We'll talk much more about producer methods in +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:producermethods.html[Producer methods]] +. ==== Producer fields @@ -616,5 +644,7 @@ A producer field is really just a shortcut that lets us avoid writing a useless getter method. However, in addition to convenience, producer fields serve a specific purpose as an adaptor for Java EE component environment injection, but to learn more about that, you'll have to wait -until <>. Because we can't wait to get -to work on some examples. +until +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:resources.html[Java EE component environment resources]] +. Because we can't wait to get to work on some examples. diff --git a/docs/reference/src/main/asciidoc/configure.asciidoc b/docs/reference/src/main/asciidoc/configure.asciidoc index 40924d1483..fb0523b5ce 100644 --- a/docs/reference/src/main/asciidoc/configure.asciidoc +++ b/docs/reference/src/main/asciidoc/configure.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[configure]] == Configuration @@ -31,7 +35,10 @@ This mode is not enabled by default. It can be enabled using the following confi |`org.jboss.weld.construction.relaxed` |false (true in weld-se)|If set to `true`, then requirements on bean constructors are relaxed. |======================================================================= -Note that relaxed construction is enabled by default in <>. +Note that relaxed construction is enabled by default in +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:environments.html#weld-se[Weld SE]] +. ==== Concurrent deployment configuration @@ -188,7 +195,10 @@ This optimization is used to reduce the HTTP session replication overhead. Howev |`org.jboss.weld.serialization.beanIdentifierIndexOptimization` |true (false in weld-servlet)|If set to `true`, the optimization is enabled. |======================================================================= -NOTE: This optimization is disabled by default in <>. +NOTE: This optimization is disabled by default in +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:environments.html#weld-servlet[Servlet containers]] +. ==== Rolling upgrades ID delimiter @@ -220,19 +230,43 @@ WARNING: Bean archive identifiers are provided by integrators. Therefore, the ab [[config-dev-mode]] ==== Development Mode -Some features of the <> may have negative impact on the performance and/or functionality of the application. The following configuration properties allow to tune or disable these features, e.g. to specify the set of components which will be monitored. +Some features of the +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:developmentmode.html[development mode]] +may have negative impact on the performance and/or functionality of the application. The following configuration properties allow to tune or disable these features, e.g. to specify the set of components which will be monitored. .Supported configuration properties [cols="1,1,1,2",options="header"] |======================================================================= |Configuration key|Tool|Default value |Description -|`org.jboss.weld.probe.invocationMonitor.excludeType`|<>|'' |A regular expression. If a non-empty string and the base type for an AnnotatedType or a declaring type for an AnnotatedMember matches this pattern the type is excluded from monitoring. -|`org.jboss.weld.probe.invocationMonitor.skipJavaBeanProperties`|<>|'true' |If set to `true`, the JavaBean accessor methods are not monitored. -|`org.jboss.weld.probe.eventMonitor.excludeType`|<>|'' |A regular expression. If a non-empty string and the runtime class of the event object matches this pattern the event is excluded from monitoring. -|`org.jboss.weld.probe.eventMonitor.containerLifecycleEvents`|<>|'false'|If set to `true` all the container lifecycle events are monitored during bootstrap. -|`org.jboss.weld.probe.embedInfoSnippet`|<>|'true' | If set to `true` an informative HTML snippet will be added to every HTTP response with Content-Type of value `text/html`. -|`org.jboss.weld.probe.jmxSupport`|<>|'false' | If set to `true` one or more MBean components may be registered so that it's possible to use JMX to access the Probe development tool data. -|`org.jboss.weld.probe.exportDataAfterDeployment`|<>|'' | If a non-empty string the Probe data will be automatically exported after deployment validation. The value represents the path of the directory where to export the data file. +|`org.jboss.weld.probe.invocationMonitor.excludeType`| +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:developmentmode.html#probe[Probe]] +|'' |A regular expression. If a non-empty string and the base type for an AnnotatedType or a declaring type for an AnnotatedMember matches this pattern the type is excluded from monitoring. +|`org.jboss.weld.probe.invocationMonitor.skipJavaBeanProperties`| +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:developmentmode.html#probe[Probe]] +|'true' |If set to `true`, the JavaBean accessor methods are not monitored. +|`org.jboss.weld.probe.eventMonitor.excludeType`| +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:developmentmode.html#probe[Probe]] +|'' |A regular expression. If a non-empty string and the runtime class of the event object matches this pattern the event is excluded from monitoring. +|`org.jboss.weld.probe.eventMonitor.containerLifecycleEvents`| +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:developmentmode.html#probe[Probe]] +|'false'|If set to `true` all the container lifecycle events are monitored during bootstrap. +|`org.jboss.weld.probe.embedInfoSnippet`| +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:developmentmode.html#probe[Probe]] +|'true' | If set to `true` an informative HTML snippet will be added to every HTTP response with Content-Type of value `text/html`. +|`org.jboss.weld.probe.jmxSupport`| +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:developmentmode.html#probe[Probe]] +|'false' | If set to `true` one or more MBean components may be registered so that it's possible to use JMX to access the Probe development tool data. +|`org.jboss.weld.probe.exportDataAfterDeployment`| +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:developmentmode.html#probe[Probe]] +|'' | If a non-empty string the Probe data will be automatically exported after deployment validation. The value represents the path of the directory where to export the data file. |======================================================================= TIP: To disable the monitoring entirely set `org.jboss.weld.probe.invocationMonitor.excludeType` and `org.jboss.weld.probe.eventMonitor.excludeType` properties to `.*`. @@ -279,7 +313,10 @@ The functionality is implemented as a built-in portable extension processing all CDI applications consist of user-defined beans implementing the business logic, but also beans coming from libraries (e.g. DeltaSpike) and integrations (e.g. various Java EE technologies - JSF, Bean Validation, Batch). Most applications actually use only a small part of the beans provided by libraries and integrations. Still, Weld has to retain the metadata for all the beans in memory which can be considerably vast footprint, depending on the application. -If <> is allowed, Weld can remove _unused_ beans after bootstrap. +If +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:ri-spi.html#allow-optimized-cleanup[Optimized cleanup after bootstrap]] +is allowed, Weld can remove _unused_ beans after bootstrap. An _unused_ bean: @@ -291,7 +328,10 @@ An _unused_ bean: * does not declare a producer which is eligible for injection to any injection point, * is not eligible for injection into any `Instance` injection point. -TIP: If you run <> and list all the beans in your application, you will almost certainly notice some of them coming from 3rd party libraries which you never use (marked with a trash icon). Those are candidates for _unused beans_ as you can be sure you are not using them. +TIP: If you run +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:developmentmode.html#probe[Probe]] +and list all the beans in your application, you will almost certainly notice some of them coming from 3rd party libraries which you never use (marked with a trash icon). Those are candidates for _unused beans_ as you can be sure you are not using them. NOTE: As usual, there is a trade-off between memory consumption and bootstrap time. The results may vary depending on the application, but you should always expect (most probably negligible) increase of the bootstrap time. @@ -331,7 +371,10 @@ public class MyExternalConfiguration implements ExternalConfiguration { } -------------------------------------------------------------------------- -Bear in mind that because `ExternalConfiguration` extends a `Service` it is required that any custom external configuration implementation is explicitly registered. See <<_the_weld_spi>> for more information. +Bear in mind that because `ExternalConfiguration` extends a `Service` it is required that any custom external configuration implementation is explicitly registered. See +ifndef::generate-index-link[<<_the_weld_spi>>] +ifdef::generate-index-link[link:ri-spi.html#_the_weld_spi[The Weld SPI]] +for more information. Last but not least external configuration is considered a source with the lowest priority which means that the properties specified there can be overriden by other sources such as system properties. For information on supported configuration keys, see <<_weld_configuration>>. Also note that entries with unsupported properties will be ignored while invalid property values will lead @@ -352,7 +395,10 @@ CDI specification does not support regular expression patterns and `!` character to invert the activation condition. All the configuration is done in the `beans.xml` file. For more -information see <>. +information see +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:ee.html#packaging-and-deployment[Packaging and deployment]] +. [source.XML, xml] ------------------------------------------------------------------------------------------------------ @@ -446,4 +492,3 @@ xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ ----------------------------------------------------------------------------------------------------------- - diff --git a/docs/reference/src/main/asciidoc/contexts.asciidoc b/docs/reference/src/main/asciidoc/contexts.asciidoc index 0a954074ea..76546ce645 100644 --- a/docs/reference/src/main/asciidoc/contexts.asciidoc +++ b/docs/reference/src/main/asciidoc/contexts.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[contexts]] == Context Management diff --git a/docs/reference/src/main/asciidoc/decorators.asciidoc b/docs/reference/src/main/asciidoc/decorators.asciidoc index 336ec8a02a..369304aeda 100644 --- a/docs/reference/src/main/asciidoc/decorators.asciidoc +++ b/docs/reference/src/main/asciidoc/decorators.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[decorators]] == Decorators diff --git a/docs/reference/src/main/asciidoc/developmentmode.asciidoc b/docs/reference/src/main/asciidoc/developmentmode.asciidoc index 02331811be..137732c7d3 100644 --- a/docs/reference/src/main/asciidoc/developmentmode.asciidoc +++ b/docs/reference/src/main/asciidoc/developmentmode.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[devmode]] == Development Mode @@ -72,10 +76,16 @@ You should see the following log message during initialization of your applicati This tool allows you to inspect the application CDI components at runtime. There is a default UI - HTML client (single-page application), which is only available in web applications. Just point your browser to `protocol://host:port/webappContextPath/weld-probe`, e.g. `http://localhost:8080/weld-numberguess/weld-probe`. -However, it's also posible to obtain the JSON data through the REST API, eventually (if <>) through the MXBean of name `org.jboss.weld.probe:type=JsonData,context=ID` where ID should be replaced with an idenfitier of an application. +However, it's also posible to obtain the JSON data through the REST API, eventually (if +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:configure.html#config-dev-mode[JMX support is enabled]] +) through the MXBean of name `org.jboss.weld.probe:type=JsonData,context=ID` where ID should be replaced with an idenfitier of an application. Right now, Probe integration is provided for WildFly, Tomcat and Jetty (Weld Servlet), and Weld SE. -TIP: There are some configuration properties which allow to tune or disable Probe features, e.g. to restrict the set of components which will be monitored. See also <>. +TIP: There are some configuration properties which allow to tune or disable Probe features, e.g. to restrict the set of components which will be monitored. See also +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:configure.html#config-dev-mode[Development Mode]] +. [[validation-report]] @@ -84,7 +94,10 @@ TIP: There are some configuration properties which allow to tune or disable Prob If a deployment validation fails and the development mode is enabled a simple HTML report is generated. The report contains a lot of useful information such as Weld version, list of enabled beans, list of bean archives, Weld configuration, etc. By default, the report is generated to the user's current working directory, ie. `user.dir`. -However, it is also possible to specify a path to the target directory using the `org.jboss.weld.probe.exportDataAfterDeployment` configuration property - see also <>. +However, it is also possible to specify a path to the target directory using the `org.jboss.weld.probe.exportDataAfterDeployment` configuration property - see also +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:configure.html#config-dev-mode[Development Mode]] +. You should see a similar log message which contains the path to the report file: @@ -98,4 +111,4 @@ You should see a similar log message which contains the path to the report file: ===================================== ----------------------------------------------------------------------------------------------------------- -TIP: We encourage you to always attach this report when asking a question on the mailing list or any other communication channel. \ No newline at end of file +TIP: We encourage you to always attach this report when asking a question on the mailing list or any other communication channel. diff --git a/docs/reference/src/main/asciidoc/ee.asciidoc b/docs/reference/src/main/asciidoc/ee.asciidoc index 7f803c4032..678a5ee653 100644 --- a/docs/reference/src/main/asciidoc/ee.asciidoc +++ b/docs/reference/src/main/asciidoc/ee.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[ee]] == Java EE integration diff --git a/docs/reference/src/main/asciidoc/environments.asciidoc b/docs/reference/src/main/asciidoc/environments.asciidoc index 01eb108c6f..728f9adea7 100644 --- a/docs/reference/src/main/asciidoc/environments.asciidoc +++ b/docs/reference/src/main/asciidoc/environments.asciidoc @@ -1,10 +1,17 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[environments]] == Application servers and environments supported by Weld === Using Weld with WildFly WildFly comes with pre-configured Weld. There is no configuration needed to use Weld (or CDI for that matter). -You may still want to fine-tune Weld with <>. +You may still want to fine-tune Weld with +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:configure.html[additional configuration settings]] +. === GlassFish @@ -379,7 +386,10 @@ NOTE: Bean archive isolation is supported (and enabled by default) from version ==== Implicit Bean Archive Support -CDI 1.1 introduced the bean discovery mode of `annotated` used for implicit bean archives (see also <>). +CDI 1.1 introduced the bean discovery mode of `annotated` used for implicit bean archives (see also +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:ee.html#packaging-and-deployment[Packaging and deployment]] +. This mode may bring additional overhead during container bootstrap. Therefore, Weld Servlet supports the use of https://github.com/wildfly/jandex[Jandex] bytecode scanning library to speed up the scanning process. Simply put the http://search.maven.org/#search|gav|1|g%3A%22org.jboss%22%20AND%20a%3A%22jandex%22[jandex.jar] on the classpath. If Jandex is not found on the classpath Weld will use the Java Reflection as a fallback. @@ -736,7 +746,10 @@ TIP: All Weld SE specific configuration properties could be also set through CDI ==== Implicit Bean Archive Support -CDI 1.1 introduced the bean discovery mode of `annotated` used for implicit bean archives (see also <>). This mode may bring additional overhead during container bootstrap. +CDI 1.1 introduced the bean discovery mode of `annotated` used for implicit bean archives (see also +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:ee.html#packaging-and-deployment[Packaging and deployment]] +. This mode may bring additional overhead during container bootstrap. Therefore, Weld Servlet supports the use of https://github.com/wildfly/jandex[Jandex] bytecode scanning library to speed up the scanning process. Simply put the http://search.maven.org/#search|gav|1|g%3A%22org.jboss%22%20AND%20a%3A%22jandex%22[jandex.jar] on the classpath. If Jandex is not found on the classpath Weld will use the Java Reflection as a fallback. diff --git a/docs/reference/src/main/asciidoc/events.asciidoc b/docs/reference/src/main/asciidoc/events.asciidoc index 0a78e97850..fc9f3e476c 100644 --- a/docs/reference/src/main/asciidoc/events.asciidoc +++ b/docs/reference/src/main/asciidoc/events.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[events]] == Events diff --git a/docs/reference/src/main/asciidoc/example.asciidoc b/docs/reference/src/main/asciidoc/example.asciidoc index ff692b0e78..7ee74f1328 100644 --- a/docs/reference/src/main/asciidoc/example.asciidoc +++ b/docs/reference/src/main/asciidoc/example.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[example]] == JSF web application example diff --git a/docs/reference/src/main/asciidoc/extend.asciidoc b/docs/reference/src/main/asciidoc/extend.asciidoc index 7c93007ef1..ba2b5f2664 100644 --- a/docs/reference/src/main/asciidoc/extend.asciidoc +++ b/docs/reference/src/main/asciidoc/extend.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[extend]] == Portable extensions @@ -226,7 +230,10 @@ BeanManager manager = CDI.current().getBeanManager(); ----------------------------------------------------- The `CDI` class can be used directly to programmatically lookup CDI -beans as described in <<_obtaining_a_contextual_instance_by_programmatic_lookup>> +beans as described in +ifndef::generate-index-link[<<_obtaining_a_contextual_instance_by_programmatic_lookup>>] +ifdef::generate-index-link[link:injection.html#_obtaining_a_contextual_instance_by_programmatic_lookup[Obtaining a contextual instance by programmatic lookup]] +. [source.JAVA, java] --------------------------- @@ -287,7 +294,10 @@ application. There are even `Bean` objects representing interceptors, decorators and producer methods. The `BeanAttributes` interface exposes all the interesting things we -discussed in <<_the_anatomy_of_a_bean>>. +discussed in +ifndef::generate-index-link[<<_the_anatomy_of_a_bean>>] +ifdef::generate-index-link[link:beans.html#_the_anatomy_of_a_bean[The anatomy of a bean]] +. [source.JAVA, java] ------------------------------------------------------------ diff --git a/docs/reference/src/main/asciidoc/gettingstarted.asciidoc b/docs/reference/src/main/asciidoc/gettingstarted.asciidoc index 1e5f98e954..223a0c870c 100644 --- a/docs/reference/src/main/asciidoc/gettingstarted.asciidoc +++ b/docs/reference/src/main/asciidoc/gettingstarted.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[gettingstarted]] == Getting started with Weld @@ -199,7 +203,13 @@ container-managed transactions. NOTE: Note that due to limitations of servlet containers (e.g. read-only JNDI) your application might require some additional configuration as well -(see <<_tomcat>> and <<_jetty>> for more info). +(see +ifndef::generate-index-link[<<_tomcat>>] +ifdef::generate-index-link[link:environments.html#_tomcat[Tomcat]] +and +ifndef::generate-index-link[<<_jetty>>] +ifdef::generate-index-link[link:environments.html#_jetty[Jetty]] +for more info). Let's give the Weld servlet extension a spin on Apache Tomcat. First, you'll need to download Tomcat 9.0.11 or later from diff --git a/docs/reference/src/main/asciidoc/index.asciidoc b/docs/reference/src/main/asciidoc/index.asciidoc new file mode 100644 index 0000000000..dd10ffd52b --- /dev/null +++ b/docs/reference/src/main/asciidoc/index.asciidoc @@ -0,0 +1,63 @@ += Weld {weldVersion} - CDI Reference Implementation + +[preface] += A note about naming and nomenclature + +Throughout this document, mentions of JSR-299, JSR-346 and JSR-365 appear. JSR is +a document of a proposed specification used in the Java Community +Process (JCP). JSRs are somewhat analogous to RFCs used by IETF. JSR-299 +and JSR-346 are the JCP specification names for the 1.0 and 1.1 versions +of CDI, respectively. JSR-365 is the JCP specification name for the CDI 2.0 version. + +Shortly before the final draft of JSR-299 was submitted, the +specification changed its name from "Web Beans" to "Java Contexts and +Dependency Injection for the Java EE platform", abbreviated CDI. For a +brief period after the renaming, the reference implementation adopted +the name "Web Beans". However, this ended up causing more confusion than +it solved and Red Hat decided to change the name of the reference +implementation to "Weld". You may still find other documentation, blogs, +forum posts, etc. that use the old nomenclature. Please update any +references you can. The naming game is over. + +You'll also find that some of the functionality that once existed in the +specification is now missing, such as defining beans in XML. These +features will be available as portable extensions. + +Note that this reference guide was started while changes were still +being made to the specification. We've done our best to update it for +accuracy. If you discover a conflict between what is written in this +guide and the specification, the specification is the authority—assume +it is correct. If you believe you have found an error in the +specification, please report it to the CDI EG. + +Below are links to separate documentation chapters. + +. link:part1.html[Beans] +.. link:intro.html[Introduction] +.. link:beans.html[More about beans] +.. link:example.html[JSF web application example] +.. link:injection.html[Dependency injection and programmatic lookup] +.. link:scopescontexts.html[Scopes and contexts] +. link:part2.html[Getting Start with Weld, the CDI Reference Implementation] +.. link:gettingstarted.html[Getting started with Weld] +.. link:weldexamples.html[Diving into the Weld examples] +. link:part3.html[Loose Coupling with Strong Typing] +.. link:producermethods.html[Producer methods] +.. link:interceptors.html[Interceptors] +.. link:decorators.html[Decorators] +.. link:events.html[Events] +.. link:stereotypes.html[Stereotypes] +.. link:specialization.html[Specialization, inheritance and alternatives] +.. link:resources.html[Java EE component environment resources] +. link:part4.html[CDI and the Java EE Ecosystem] +.. link:ee.html[Java EE integration] +.. link:extend.html[Portable extensions] +.. link:next.html[Next steps] +. link:part5.html[Weld Reference Guide] +.. link:environments.html[Application servers and environments supported by Weld] +.. link:configure.html[Weld configuration] +.. link:logging.html[Logging] +.. link:weldmanager.html[`WeldManager` interface] +.. link:developmentmode.html[Development Mode] +.. link:contexts.html[Context Management] +.. link:ri-spi.html[Integrating Weld into other environments] diff --git a/docs/reference/src/main/asciidoc/injection.asciidoc b/docs/reference/src/main/asciidoc/injection.asciidoc index 77b20294e6..dae924f1a7 100644 --- a/docs/reference/src/main/asciidoc/injection.asciidoc +++ b/docs/reference/src/main/asciidoc/injection.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[injection]] == Dependency injection and programmatic lookup @@ -96,7 +100,10 @@ for producer methods: This is a case where the `@Inject` annotation _is not_ required at the injection point. The same is true for observer methods (which we'll meet -in <>) and disposer methods. +in +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:events.html[events]] +) and disposer methods. === What gets injected @@ -468,7 +475,10 @@ change the type of the injection point to `Y`, or [NOTE] ==== Weld also supports a non-standard workaround for this limitation. -See <> for more information. +See +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:configure.html#relaxedConstruction[the Configuration chapter]] +for more information. ==== === Obtaining a contextual instance by programmatic lookup diff --git a/docs/reference/src/main/asciidoc/interceptors.asciidoc b/docs/reference/src/main/asciidoc/interceptors.asciidoc index d5945d79ca..50d0549e76 100644 --- a/docs/reference/src/main/asciidoc/interceptors.asciidoc +++ b/docs/reference/src/main/asciidoc/interceptors.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[interceptors]] == Interceptors diff --git a/docs/reference/src/main/asciidoc/intro.asciidoc b/docs/reference/src/main/asciidoc/intro.asciidoc index 0773f9a1f1..83471992fe 100644 --- a/docs/reference/src/main/asciidoc/intro.asciidoc +++ b/docs/reference/src/main/asciidoc/intro.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[intro]] == Introduction diff --git a/docs/reference/src/main/asciidoc/logging.asciidoc b/docs/reference/src/main/asciidoc/logging.asciidoc index 12e5d0f3e4..6214e785ad 100644 --- a/docs/reference/src/main/asciidoc/logging.asciidoc +++ b/docs/reference/src/main/asciidoc/logging.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[logging]] == Logging Weld is using link:https://developer.jboss.org/wiki/JBossLoggingTooling[JBoss Logging], an abstraction layer which provides support for the internationalization and localization of log messages and exception messages. However, JBoss Logging itself does not write any log messages. Instead, it only constructs a log message and delegates to one of the supported logging frameworks. @@ -31,4 +35,4 @@ If you just want to see the debug log messages as quickly as possible in Weld SE . and change the level for `org.jboss.weld`, e.g.: mvn clean test -Dtest=MyWeldSETest -Dorg.jboss.logging.provider=slf4j -Dorg.slf4j.simpleLogger.log.org.jboss.weld=debug -==== \ No newline at end of file +==== diff --git a/docs/reference/src/main/asciidoc/next.asciidoc b/docs/reference/src/main/asciidoc/next.asciidoc index 5687ead587..312320aa4e 100644 --- a/docs/reference/src/main/asciidoc/next.asciidoc +++ b/docs/reference/src/main/asciidoc/next.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[next]] == Next steps diff --git a/docs/reference/src/main/asciidoc/part1.asciidoc b/docs/reference/src/main/asciidoc/part1.asciidoc index ba5a75d2ba..b88e91e720 100644 --- a/docs/reference/src/main/asciidoc/part1.asciidoc +++ b/docs/reference/src/main/asciidoc/part1.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[part-1]] = Beans @@ -23,7 +27,10 @@ full support for Java EE modularity and the Java EE component architecture. But the specification does not limit the use of CDI to the Java EE environment. Starting with CDI 2.0, the specification covers the use of CDI in the Java SE environment as well. In Java SE, the services might be -provided by a standalone CDI implementation like Weld (see <<_cdi_se_module>>), or even +provided by a standalone CDI implementation like Weld (see +ifndef::generate-index-link[<<_cdi_se_module>>] +ifdef::generate-index-link[link:environments.html#_cdi_se_module[CDI SE Module]] +), or even by a container that also implements the subset of EJB defined for embedded usage by the EJB 3.2 specification. CDI is especially useful in the context of web application development, but the problems it solves diff --git a/docs/reference/src/main/asciidoc/part2.asciidoc b/docs/reference/src/main/asciidoc/part2.asciidoc index 94875aefc3..88b1604472 100644 --- a/docs/reference/src/main/asciidoc/part2.asciidoc +++ b/docs/reference/src/main/asciidoc/part2.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[part-2]] = Getting Start with Weld, the CDI Reference Implementation diff --git a/docs/reference/src/main/asciidoc/part3.asciidoc b/docs/reference/src/main/asciidoc/part3.asciidoc index 73a3d66a87..38b0c487b2 100644 --- a/docs/reference/src/main/asciidoc/part3.asciidoc +++ b/docs/reference/src/main/asciidoc/part3.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[part-3]] = Loose coupling with strong typing diff --git a/docs/reference/src/main/asciidoc/part4.asciidoc b/docs/reference/src/main/asciidoc/part4.asciidoc index 45876a1f7a..de68de9a54 100644 --- a/docs/reference/src/main/asciidoc/part4.asciidoc +++ b/docs/reference/src/main/asciidoc/part4.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[part-4]] = CDI and the Java EE ecosystem diff --git a/docs/reference/src/main/asciidoc/part5.asciidoc b/docs/reference/src/main/asciidoc/part5.asciidoc index d9bfa4687a..0cbb863525 100644 --- a/docs/reference/src/main/asciidoc/part5.asciidoc +++ b/docs/reference/src/main/asciidoc/part5.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[part-5]] = Weld Reference Guide @@ -16,7 +20,10 @@ portable extensions to CDI. If you want to get started quickly using Weld (and, in turn, CDI) with WildFly, GlassFish or Tomcat and experiment with one of the examples, -take a look at <>. Otherwise read on for a +take a look at +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:gettingstarted.html[Getting started with Weld]] +. Otherwise read on for a exhaustive discussion of using Weld in all the environments and application servers it supports and the Weld extensions. -- diff --git a/docs/reference/src/main/asciidoc/producermethods.asciidoc b/docs/reference/src/main/asciidoc/producermethods.asciidoc index 9092204471..d36eea5e5d 100644 --- a/docs/reference/src/main/asciidoc/producermethods.asciidoc +++ b/docs/reference/src/main/asciidoc/producermethods.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[producer_methods]] == Producer methods diff --git a/docs/reference/src/main/asciidoc/resources.asciidoc b/docs/reference/src/main/asciidoc/resources.asciidoc index df561d4f67..5864921305 100644 --- a/docs/reference/src/main/asciidoc/resources.asciidoc +++ b/docs/reference/src/main/asciidoc/resources.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[resources]] == Java EE component environment resources diff --git a/docs/reference/src/main/asciidoc/ri-spi.asciidoc b/docs/reference/src/main/asciidoc/ri-spi.asciidoc index 9b978d970f..48311aaa2a 100644 --- a/docs/reference/src/main/asciidoc/ri-spi.asciidoc +++ b/docs/reference/src/main/asciidoc/ri-spi.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[ri-spi]] [appendix] == Integrating Weld into other environments @@ -221,7 +225,8 @@ the integrator. The integrator may choose to provide all EE resource injection services themselves, using another library or framework. In this case the -integrator should use the `EE` environment, and implement the <<_injection_services>> SPI. +integrator should use the `EE` environment, and implement the +<<_injection_services>> SPI. Alternatively, the integrator may choose to use CDI to provide EE resource injection. In this case, the `EE_INJECT` environment should be @@ -462,7 +467,10 @@ To validate the deployed beans, call `Bootstrap.validateBeans()`. To place the container into a state where it can service requests, call `Bootstrap.endInitialization()` -NOTE: Integrators can set `org.jboss.weld.bootstrap.allowOptimizedCleanup` configuration property using <> to allow to perform efficient cleanup and further optimizations after bootstrap. In this case, `Bootstrap.endInitialization()` must be called after all EE components which support injection are installed (that means all relevant `ProcessInjectionTarget` events were already fired). +NOTE: Integrators can set `org.jboss.weld.bootstrap.allowOptimizedCleanup` configuration property using +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:configure.html#external_config[Defining external configuration]] +to allow to perform efficient cleanup and further optimizations after bootstrap. In this case, `Bootstrap.endInitialization()` must be called after all EE components which support injection are installed (that means all relevant `ProcessInjectionTarget` events were already fired). To shutdown the container you call `Bootstrap.shutdown()`. This allows the container to perform any cleanup operations needed. @@ -841,7 +849,13 @@ for more details. ==== Probe Development Tool (Optional) -Optionally, an integrator may register the following <> components in order to enable its functionality. Note that these components should only be registered if the development mode is enabled - see also <>. +Optionally, an integrator may register the following +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:developmentmode.html#probe[Probe Development Tool]] +components in order to enable its functionality. Note that these components should only be registered if the development mode is enabled - see also +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:developmentmode.html#devmode-enable[How to enable the development mode]] +. .Probe components [cols="1,1,2",options="header"] @@ -859,7 +873,11 @@ NOTE: Probe REST API is implemented using a servlet filter. However, not all ser ==== Optimized cleanup after bootstrap Weld can perfom additional cleanup operations after bootstrap, in order to conserve resources. -See for example <>. +See for example +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:configure.html#remove-unused-beans[Memory consumption optimization - removing unused beans]] +. + However, this feature is disabled by default. An integrator may enable this feature provided the following requirements are met: @@ -872,7 +890,10 @@ An integrator may enable this feature provided the following requirements are me |`org.jboss.weld.bootstrap.allowOptimizedCleanup` |`false`| If set to `true` Weld is allowed to perform efficient cleanup and further optimizations after bootstrap |======================================================================= -NOTE: This property can only be set by integrators through <>. +NOTE: This property can only be set by integrators through +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:configure.html#external_config[Defining external configuration]] +. === Migration notes @@ -978,7 +999,10 @@ Instead, this dependency needs to be deployed separately to the OSGi container. * Java 6 support was dropped. Java 7 or newer is now required for both compile time and runtime. -* An observer for `@Initialized(ConversationScoped.class)` or `@Destroyed(ConversationScoped.class)` event no longer forces eager conversation context initialization. See also <<_lazy_and_eager_conversation_context_initialization>>. +* An observer for `@Initialized(ConversationScoped.class)` or `@Destroyed(ConversationScoped.class)` event no longer forces eager conversation context initialization. See also +ifndef::generate-index-link[<<_lazy_and_eager_conversation_context_initialization>>] +ifdef::generate-index-link[link:scopescontexts.html#_lazy_and_eager_conversation_context_initialization[Lazy and eager conversation context initialization]] +. * `ScheduledExecutorServiceFactory` is deprecated and no default implementation is provided by default. This service has not been used by Weld internals at least since version 1.1.0.Final. diff --git a/docs/reference/src/main/asciidoc/scopescontexts.asciidoc b/docs/reference/src/main/asciidoc/scopescontexts.asciidoc index a60ce05d68..33844ed57a 100644 --- a/docs/reference/src/main/asciidoc/scopescontexts.asciidoc +++ b/docs/reference/src/main/asciidoc/scopescontexts.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[scopescontexts]] == Scopes and contexts @@ -233,7 +237,10 @@ conversation.setTimeout(timeoutInMillis); ----------------------------------------- Another option how to set conversation timeout is to provide configuration -property defining the new time value. See <>. +property defining the new time value. See +ifndef::generate-index-link[<>] +ifdef::generate-index-link[link:configure.html#config-conversation-timeout[Conversation timeout and Conversation concurrent access timeout]] +. However note that any conversation might be destroyed any time sooner when HTTP session invalidation or timeout occurs. diff --git a/docs/reference/src/main/asciidoc/specialization.asciidoc b/docs/reference/src/main/asciidoc/specialization.asciidoc index cf5ce0f483..d9a12f4cbe 100644 --- a/docs/reference/src/main/asciidoc/specialization.asciidoc +++ b/docs/reference/src/main/asciidoc/specialization.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[specialization]] == Specialization, inheritance and alternatives diff --git a/docs/reference/src/main/asciidoc/stereotypes.asciidoc b/docs/reference/src/main/asciidoc/stereotypes.asciidoc index ffac2b279d..73533a2686 100644 --- a/docs/reference/src/main/asciidoc/stereotypes.asciidoc +++ b/docs/reference/src/main/asciidoc/stereotypes.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[stereotypes]] == Stereotypes diff --git a/docs/reference/src/main/asciidoc/weldexamples.asciidoc b/docs/reference/src/main/asciidoc/weldexamples.asciidoc index d7a2bd0978..4af23a6bf4 100644 --- a/docs/reference/src/main/asciidoc/weldexamples.asciidoc +++ b/docs/reference/src/main/asciidoc/weldexamples.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[weldexamples]] == Diving into the Weld examples @@ -365,19 +369,19 @@ Disable m2eclipse's _Workspace Resolution_, to make sure that Eclipse can find `StartMain`. Right click on the project, and choose _Properties \-> Maven_, and uncheck _Resolve dependencies from Workspace projects_: -image:weld-se-numberguess-m2eclipse-1.png[image] +image:images/weld-se-numberguess-m2eclipse-1.png[image] Right click on the project, and choose _Run As \-> Java Application_: -image:weld-se-numberguess-m2eclipse-2.png[image] +image:images/weld-se-numberguess-m2eclipse-2.png[image] Locate the `StartMain` class: -image:weld-se-numberguess-m2eclipse-3.png[image] +image:images/weld-se-numberguess-m2eclipse-3.png[image] The application should now launch! -image:weld-se-numberguess-m2eclipse-4.png[image] +image:images/weld-se-numberguess-m2eclipse-4.png[image] ==== Running the example from the command line @@ -405,7 +409,10 @@ as a CDI application. NOTE: The `beans.xml` file is no longer required for CDI enablement as of CDI 1.1. CDI is automatically enabled for archives which don't contain `beans.xml` but contain one or more bean classes with a _bean defining -annotation_, as described in section <<_implicit_bean_archive>>. +annotation_, as described in section +ifndef::generate-index-link[<<_implicit_bean_archive>>] +ifdef::generate-index-link[link:ee.html#_implicit_bean_archive[Implicit bean archive]] +. The game's main logic is located in `Game.java`. Here is the code for that class, highlighting the ways in which this differs from the web @@ -816,7 +823,10 @@ Finally, let's look at the EJB module, which is located in the example's NOTE: The `beans.xml` file is no longer required for CDI enablement as of CDI 1.1. CDI is automatically enabled for archives which don't contain `beans.xml` but contain one or more bean classes with a _bean defining -annotation_, as described in section <<_implicit_bean_archive>>. +annotation_, as described in section +ifndef::generate-index-link[<<_implicit_bean_archive>>] +ifdef::generate-index-link[link:ee.html#_implicit_bean_archive[Implicit bean archive]] +. We've saved the most interesting bit for last, the code! The project has two simple beans, `SentenceParser` and `TextTranslator` and two session diff --git a/docs/reference/src/main/asciidoc/weldmanager.asciidoc b/docs/reference/src/main/asciidoc/weldmanager.asciidoc index 2bb7e99c7c..594743067d 100644 --- a/docs/reference/src/main/asciidoc/weldmanager.asciidoc +++ b/docs/reference/src/main/asciidoc/weldmanager.asciidoc @@ -1,3 +1,7 @@ +ifdef::generate-index-link[] +link:index.html[Weld {weldVersion} - CDI Reference Implementation] +endif::[] + [[weldmanager]] == `WeldManager` interface diff --git a/docs/reference/src/main/sitemap/sitemap.xml b/docs/reference/src/main/sitemap/sitemap.xml deleted file mode 100644 index 271fef23f8..0000000000 --- a/docs/reference/src/main/sitemap/sitemap.xml +++ /dev/null @@ -1,143 +0,0 @@ - - - - ${documentation.url}/part-1.html - 0.5 - monthly - - - ${documentation.url}/intro.html - 0.5 - monthly - - - ${documentation.url}/beanscdi.html - 0.5 - monthly - - - ${documentation.url}/example.html - 0.5 - monthly - - - ${documentation.url}/injection.html - 0.5 - monthly - - - ${documentation.url}/scopescontexts.html - 0.5 - monthly - - - ${documentation.url}/part-2.html - 0.5 - monthly - - - ${documentation.url}/gettingstarted.html - 0.5 - monthly - - - ${documentation.url}/weldexamples.html - 0.5 - monthly - - - ${documentation.url}/part-3.html - 0.5 - monthly - - - ${documentation.url}/producer_methods.html - 0.5 - monthly - - - ${documentation.url}/interceptors.html - 0.5 - monthly - - - ${documentation.url}/decorators.html - 0.5 - monthly - - - ${documentation.url}/events.html - 0.5 - monthly - - - ${documentation.url}/stereotypes.html - 0.5 - monthly - - - ${documentation.url}/specialization.html - 0.5 - monthly - - - ${documentation.url}/resources.html - 0.5 - monthly - - - ${documentation.url}/part-4.html - 0.5 - monthly - - - ${documentation.url}/ee.html - 0.5 - monthly - - - ${documentation.url}/extend.html - 0.5 - monthly - - - ${documentation.url}/next.html - 0.5 - monthly - - - ${documentation.url}/part-5.html - 0.5 - monthly - - - ${documentation.url}/environments.html - 0.5 - monthly - - - ${documentation.url}/configure.html - 0.5 - monthly - - - ${documentation.url}/logging.html - 0.5 - monthly - - - ${documentation.url}/devmode.html - 0.5 - monthly - - - ${documentation.url}/contexts.html - 0.5 - monthly - - - ${documentation.url}/ri-spi.html - 0.5 - monthly - - \ No newline at end of file diff --git a/docs/reference/src/main/style/css/css/weld.css b/docs/reference/src/main/style/css/css/weld.css deleted file mode 100644 index 8260009983..0000000000 --- a/docs/reference/src/main/style/css/css/weld.css +++ /dev/null @@ -1,38 +0,0 @@ -@CHARSET "UTF-8"; - -@import url("jbossorg.css"); - -body { - font-size: 14px; - max-width: 60em; -} - -div.note, div.tip, div.warning { - border-radius: 4px; -} - -pre.JAVA, pre.XML { - border-radius: 4px; - padding: 10px 15px 10px 25px; -} - -table td, table th { - border-collapse: collapse; - border-color: #e5e5e5; - border-style: solid; -} - -code.literal { - background-color: #efefef; - padding: 2px 3px; - border: 1px solid #e2e2e2; - border-radius: 3px; - white-space: nowrap; - color: #333; -} - -p#title a.site_href { - display: block; - float: left; - background: url(../images/weld_logo.png) top left no-repeat; -} \ No newline at end of file diff --git a/docs/reference/src/main/style/xslt/org/jboss/weld/common-xhtml.xsl b/docs/reference/src/main/style/xslt/org/jboss/weld/common-xhtml.xsl deleted file mode 100644 index 29f6c3e181..0000000000 --- a/docs/reference/src/main/style/xslt/org/jboss/weld/common-xhtml.xsl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - diff --git a/docs/reference/src/main/style/xslt/org/jboss/weld/xhtml-single.xsl b/docs/reference/src/main/style/xslt/org/jboss/weld/xhtml-single.xsl deleted file mode 100644 index 3fc3e85463..0000000000 --- a/docs/reference/src/main/style/xslt/org/jboss/weld/xhtml-single.xsl +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/docs/reference/src/main/style/xslt/org/jboss/weld/xhtml.xsl b/docs/reference/src/main/style/xslt/org/jboss/weld/xhtml.xsl deleted file mode 100644 index 75ad4e4899..0000000000 --- a/docs/reference/src/main/style/xslt/org/jboss/weld/xhtml.xsl +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/environments/common/pom.xml b/environments/common/pom.xml index b111463254..e566cc09f0 100644 --- a/environments/common/pom.xml +++ b/environments/common/pom.xml @@ -3,7 +3,7 @@ weld-core-parent org.jboss.weld - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/environments/common/src/main/java/org/jboss/weld/environment/deployment/discovery/ClassPathBeanArchiveScanner.java b/environments/common/src/main/java/org/jboss/weld/environment/deployment/discovery/ClassPathBeanArchiveScanner.java index 2cc2507aea..e101776908 100644 --- a/environments/common/src/main/java/org/jboss/weld/environment/deployment/discovery/ClassPathBeanArchiveScanner.java +++ b/environments/common/src/main/java/org/jboss/weld/environment/deployment/discovery/ClassPathBeanArchiveScanner.java @@ -34,9 +34,7 @@ import java.util.jar.JarFile; import java.util.jar.Manifest; import java.util.regex.Pattern; - import javax.enterprise.inject.spi.Extension; - import org.jboss.logging.Logger; import org.jboss.weld.bootstrap.api.Bootstrap; import org.jboss.weld.bootstrap.spi.BeansXml; @@ -48,148 +46,177 @@ import org.jboss.weld.util.collections.ImmutableSet; /** - * Scans all the class path entries. Implicit bean archives which don't contain a beans.xml file are also supported. + * Scans all the class path entries. Implicit bean archives which don't contain + * a beans.xml file are also supported. * * @author Martin Kouba * @see ConfigurationKey#IMPLICIT_SCAN */ public class ClassPathBeanArchiveScanner extends AbstractBeanArchiveScanner { - static final String JAVA_CLASS_PATH_SYSTEM_PROPERTY = "java.class.path"; + static final String JAVA_CLASS_PATH_SYSTEM_PROPERTY = "java.class.path"; - static final String EXTENSION_FILE = "META-INF/" + Extension.class.getName(); + static final String EXTENSION_FILE = "META-INF/" + Extension.class.getName(); - private static final Logger logger = Logger.getLogger(ClassPathBeanArchiveScanner.class); + private static final Logger logger = + Logger.getLogger(ClassPathBeanArchiveScanner.class); - private static final String BEANS_XML_FOUND_MESSAGE = "beans.xml found in {0}"; + private static final String BEANS_XML_FOUND_MESSAGE = + "beans.xml found in {0}"; - private static final String BEANS_XML_NOT_FOUND_MESSAGE = "beans.xml not found in {0}"; + private static final String BEANS_XML_NOT_FOUND_MESSAGE = + "beans.xml not found in {0}"; - private static final String MANIFEST_FILE = "META-INF/MANIFEST.MF"; + private static final String MANIFEST_FILE = "META-INF/MANIFEST.MF"; - private static final Pattern MANIFEST_CLASSPATH_SEPARATOR_PATTERN = Pattern.compile(" +"); + private static final Pattern MANIFEST_CLASSPATH_SEPARATOR_PATTERN = + Pattern.compile(" +"); - private final Set visitedManifestClassPathEntries = new HashSet<>(); + private final Set visitedClassPathEntries = new HashSet<>(); - /** - * - * @param bootstrap - */ - public ClassPathBeanArchiveScanner(Bootstrap bootstrap) { - super(bootstrap); - } + /** + * + * @param bootstrap + */ + public ClassPathBeanArchiveScanner(Bootstrap bootstrap) { super(bootstrap); } - @Override - public List scan() { - String javaClassPath = AccessController.doPrivileged(new GetSystemPropertyAction(JAVA_CLASS_PATH_SYSTEM_PROPERTY)); - if (javaClassPath == null) { - throw CommonLogger.LOG.cannotReadJavaClassPathSystemProperty(); + @Override + public List scan() { + String javaClassPath = AccessController.doPrivileged( + new GetSystemPropertyAction(JAVA_CLASS_PATH_SYSTEM_PROPERTY)); + if (javaClassPath == null) { + throw CommonLogger.LOG.cannotReadJavaClassPathSystemProperty(); + } + ImmutableList.Builder results = ImmutableList.builder(); + Set entries = + ImmutableSet.of(javaClassPath.split(Pattern.quote(File.pathSeparator))); + logger.debugv("Scanning class path entries: {0}", entries); + for (String entry : entries) { + if (entry == null || entry.isEmpty()) { + continue; + } + File entryFile = new File(entry); + try { + if (!visitedClassPathEntries.add(entryFile.toURI().toURL())) { + continue; } - ImmutableList.Builder results = ImmutableList.builder(); - Set entries = ImmutableSet.of(javaClassPath.split(Pattern.quote(File.pathSeparator))); - logger.debugv("Scanning class path entries: {0}", entries); - for (String entry : entries) { - if (entry == null || entry.isEmpty()) { - continue; - } - File entryFile = new File(entry); - if (!entryFile.canRead()) { - throw CommonLogger.LOG.cannotReadClassPathEntry(entryFile); - } - try { - if (entryFile.isDirectory()) { - scanDirectory(entryFile, results); - } else { - scanJarFile(entryFile, results); - } - } catch (IOException e) { - throw CommonLogger.LOG.cannotScanClassPathEntry(entryFile, e); - } + if (!entryFile.exists()) { + CommonLogger.LOG.classPathEntryDoesNotExist(entryFile); + continue; } - return results.build(); - } - - private void scanDirectory(File entryDirectory, ImmutableList.Builder results) throws IOException { - // First try to find beans.xml - File beansXmlFile = new File(entryDirectory, AbstractWeldDeployment.BEANS_XML); - if (beansXmlFile.canRead()) { - logger.debugv(BEANS_XML_FOUND_MESSAGE, entryDirectory); - final BeansXml beansXml = parseBeansXml(beansXmlFile.toURI().toURL()); - if (accept(beansXml)) { - results.add(new ScanResult(beansXml, entryDirectory.getPath())); - } + if (!entryFile.canRead()) { + throw CommonLogger.LOG.cannotReadClassPathEntry(entryFile); + } + if (entryFile.isDirectory()) { + scanDirectory(entryFile, results); } else { - // No beans.xml found - check whether the bean archive contains an extension - logger.debugv(BEANS_XML_NOT_FOUND_MESSAGE, entryDirectory); - File extensionFile = new File(entryDirectory, EXTENSION_FILE); - if (!extensionFile.canRead()) { - results.add(new ScanResult(null, entryDirectory.getPath())); - } + scanJarFile(entryFile, results); } + } catch (IOException e) { + throw CommonLogger.LOG.cannotScanClassPathEntry(entryFile, e); + } + } + return results.build(); + } + + private void scanDirectory(File entryDirectory, + ImmutableList.Builder results) + throws IOException { + // First try to find beans.xml + File beansXmlFile = + new File(entryDirectory, AbstractWeldDeployment.BEANS_XML); + if (beansXmlFile.canRead()) { + logger.debugv(BEANS_XML_FOUND_MESSAGE, entryDirectory); + final BeansXml beansXml = parseBeansXml(beansXmlFile.toURI().toURL()); + if (accept(beansXml)) { + results.add(new ScanResult(beansXml, entryDirectory.getPath())); + } + } else { + // No beans.xml found - check whether the bean archive contains an + // extension + logger.debugv(BEANS_XML_NOT_FOUND_MESSAGE, entryDirectory); + File extensionFile = new File(entryDirectory, EXTENSION_FILE); + if (!extensionFile.canRead()) { + results.add(new ScanResult(null, entryDirectory.getPath())); + } + } - File manifestFile = new File(entryDirectory, MANIFEST_FILE); - if (manifestFile.canRead()) { - try (FileInputStream fis = new FileInputStream(manifestFile)) { - final Manifest manifest = new Manifest(fis); - final Attributes manifestMainAttributes = manifest.getMainAttributes(); - if (manifestMainAttributes.containsKey(CLASS_PATH)) { - scanManifestClassPath(entryDirectory.toURI().toURL(), manifestMainAttributes.getValue(CLASS_PATH), results); - } - } + File manifestFile = new File(entryDirectory, MANIFEST_FILE); + if (manifestFile.canRead()) { + try (FileInputStream fis = new FileInputStream(manifestFile)) { + final Manifest manifest = new Manifest(fis); + final Attributes manifestMainAttributes = manifest.getMainAttributes(); + if (manifestMainAttributes.containsKey(CLASS_PATH)) { + scanManifestClassPath(entryDirectory.toURI().toURL(), + manifestMainAttributes.getValue(CLASS_PATH), + results); } + } } - - private void scanJarFile(File entryFile, ImmutableList.Builder results) throws IOException { - try (JarFile jar = new JarFile(entryFile)) { - JarEntry beansXmlEntry = jar.getJarEntry(AbstractWeldDeployment.BEANS_XML); - if (beansXmlEntry != null) { - logger.debugv(BEANS_XML_FOUND_MESSAGE, entryFile); - BeansXml beansXml = parseBeansXml( - new URL(PROCOTOL_JAR + ":" + entryFile.toURI().toURL().toExternalForm() + JAR_URL_SEPARATOR + beansXmlEntry.getName())); - if (accept(beansXml)) { - results.add(new ScanResult(beansXml, entryFile.getPath())); - } - } else { - // No beans.xml found - check whether the bean archive contains an extension - if (jar.getEntry(EXTENSION_FILE) == null) { - logger.debugv(BEANS_XML_NOT_FOUND_MESSAGE, entryFile); - results.add(new ScanResult(null, entryFile.getPath())); - } - } - - Manifest manifest = jar.getManifest(); - if (manifest != null) { - final Attributes manifestMainAttributes = manifest.getMainAttributes(); - if (manifestMainAttributes.containsKey(CLASS_PATH)) { - scanManifestClassPath(entryFile.toURI().toURL(), manifestMainAttributes.getValue(CLASS_PATH), results); - } - } + } + + private void scanJarFile(File entryFile, + ImmutableList.Builder results) + throws IOException { + try (JarFile jar = new JarFile(entryFile)) { + JarEntry beansXmlEntry = + jar.getJarEntry(AbstractWeldDeployment.BEANS_XML); + if (beansXmlEntry != null) { + logger.debugv(BEANS_XML_FOUND_MESSAGE, entryFile); + BeansXml beansXml = parseBeansXml(new URL( + PROCOTOL_JAR + ":" + entryFile.toURI().toURL().toExternalForm() + + JAR_URL_SEPARATOR + beansXmlEntry.getName())); + if (accept(beansXml)) { + results.add(new ScanResult(beansXml, entryFile.getPath())); } + } else { + // No beans.xml found - check whether the bean archive contains an + // extension + if (jar.getEntry(EXTENSION_FILE) == null) { + logger.debugv(BEANS_XML_NOT_FOUND_MESSAGE, entryFile); + results.add(new ScanResult(null, entryFile.getPath())); + } + } + + Manifest manifest = jar.getManifest(); + if (manifest != null) { + final Attributes manifestMainAttributes = manifest.getMainAttributes(); + if (manifestMainAttributes.containsKey(CLASS_PATH)) { + scanManifestClassPath(entryFile.toURI().toURL(), + manifestMainAttributes.getValue(CLASS_PATH), + results); + } + } } - - private void scanManifestClassPath(URL context, String classPath, ImmutableList.Builder results) { - Set entries = ImmutableSet.of(MANIFEST_CLASSPATH_SEPARATOR_PATTERN.split(classPath)); - for (String entry : entries) { - if (entry == null || entry.isEmpty()) { - continue; - } - try { - URL entryUrl = new URL(context, entry); - if (visitedManifestClassPathEntries.add(entryUrl) && entryUrl.getProtocol().equals("file")) { - File entryFile = new File(URI.create(entryUrl.toString())); - // do not throw an error here, as some libraries use the class path attribute wrongly - if (entryFile.canRead()) { - if (entry.endsWith("/")) { - scanDirectory(entryFile, results); - } else { - scanJarFile(entryFile, results); - } - } - } - } catch (IOException e) { - throw CommonLogger.LOG.cannotScanClassPathEntry(entry, e); + } + + private void + scanManifestClassPath(URL context, String classPath, + ImmutableList.Builder results) { + Set entries = + ImmutableSet.of(MANIFEST_CLASSPATH_SEPARATOR_PATTERN.split(classPath)); + for (String entry : entries) { + if (entry == null || entry.isEmpty()) { + continue; + } + try { + URL entryUrl = new URL(context, entry); + if (visitedClassPathEntries.add(entryUrl) && + entryUrl.getProtocol().equals("file")) { + File entryFile = new File(URI.create(entryUrl.toString())); + // do not throw an error here, as some libraries use the class path + // attribute wrongly + if (entryFile.canRead()) { + if (entry.endsWith("/")) { + scanDirectory(entryFile, results); + } else { + scanJarFile(entryFile, results); } + } } + } catch (IOException e) { + throw CommonLogger.LOG.cannotScanClassPathEntry(entry, e); + } } - + } } diff --git a/environments/common/src/main/java/org/jboss/weld/environment/logging/CommonLogger.java b/environments/common/src/main/java/org/jboss/weld/environment/logging/CommonLogger.java index a19d547d63..57c3281f74 100644 --- a/environments/common/src/main/java/org/jboss/weld/environment/logging/CommonLogger.java +++ b/environments/common/src/main/java/org/jboss/weld/environment/logging/CommonLogger.java @@ -16,9 +16,7 @@ */ package org.jboss.weld.environment.logging; - import javax.enterprise.inject.UnsatisfiedResolutionException; - import org.jboss.logging.Logger; import org.jboss.logging.Logger.Level; import org.jboss.logging.annotations.Cause; @@ -39,128 +37,227 @@ @MessageLogger(projectCode = WeldEnvironmentLogger.WELD_ENV_PROJECT_CODE) public interface CommonLogger extends WeldEnvironmentLogger { - CommonLogger LOG = Logger.getMessageLogger(CommonLogger.class, Category.BOOTSTRAP.getName()); - - @LogMessage(level = Level.WARN) - @Message(id = 2, value = "Could not read resource with name: {0}", format = Format.MESSAGE_FORMAT) - void couldNotReadResource(Object param1, @Cause Throwable cause); - - @LogMessage(level = Level.WARN) - @Message(id = 4, value = "Could not invoke JNLPClassLoader#getJarFile(URL) on context class loader, expecting Web Start class loader", format = Format.MESSAGE_FORMAT) - void unexpectedClassLoader(@Cause Throwable cause); - - @LogMessage(level = Level.WARN) - @Message(id = 5, value = "JNLPClassLoader#getJarFile(URL) threw exception", format = Format.MESSAGE_FORMAT) - void jnlpClassLoaderInternalException(@Cause Throwable cause); - - @LogMessage(level = Level.WARN) - @Message(id = 6, value = "Could not invoke JNLPClassLoader#getJarFile(URL) on context class loader", format = Format.MESSAGE_FORMAT) - void jnlpClassLoaderInvocationException(@Cause Throwable cause); - - @LogMessage(level = Level.WARN) - @Message(id = 7, value = "Error handling file path\n File: {0}\n Path: {1}", format = Format.MESSAGE_FORMAT) - void cannotHandleFilePath(Object file, Object path, @Cause Throwable cause); - - // log message with id 8 was removed - - @LogMessage(level = Level.WARN) - @Message(id = 10, value = "Could not open the stream on the url {0} when adding to the jandex index.", format = Format.MESSAGE_FORMAT) - void couldNotOpenStreamForURL(Object param1, @Cause Throwable cause); - - @LogMessage(level = Level.WARN) - @Message(id = 11, value = "Could not close the stream on the url {0} when adding to the jandex index.", format = Format.MESSAGE_FORMAT) - void couldNotCloseStreamForURL(Object param1, @Cause Throwable cause); - - @Message(id = 12, value = "Unable to load class {0}", format = Format.MESSAGE_FORMAT) - ClassFileInfoException unableToLoadClass(Object param1); - - @Message(id = 13, value = "beans.xml defines unrecognized bean-discovery-mode value: {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException undefinedBeanDiscoveryValue(Object param1); - - @LogMessage(level = Level.INFO) - @Message(id = 14, value = "Falling back to Java Reflection for bean-discovery-mode=\"annotated\" discovery. Add org.jboss:jandex to the classpath to speed-up startup.", format = Format.MESSAGE_FORMAT) - void reflectionFallback(); - - @Message(id = 15, value = "Unable to load annotation: {0}", format = Format.MESSAGE_FORMAT) - ClassFileInfoException unableToLoadAnnotation(Object param1); - - @Message(id = 16, value = "Missing beans.xml file in META-INF", format = Format.MESSAGE_FORMAT) - IllegalStateException missingBeansXml(); - - @Message(id = 18, value = "Unable to resolve a bean for {0} with bindings {1}", format = Format.MESSAGE_FORMAT) - UnsatisfiedResolutionException unableToResolveBean(Object param1, Object param2); - - @Message(id = 19, value = "Jandex index is null in the constructor of class: {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException jandexIndexNotCreated(Object param1); - - @LogMessage(level = Level.INFO) - @Message(id = 20, value = "Using jandex for bean discovery", format = Format.MESSAGE_FORMAT) - void usingJandex(); - - // log message with id 21 was removed - // log message with id 22 was removed - - @LogMessage(level = Level.DEBUG) - @Message(id = 23, value = "Archive isolation disabled - only one bean archive will be created", format = Format.MESSAGE_FORMAT) - void archiveIsolationDisabled(); - - @LogMessage(level = Level.DEBUG) - @Message(id = 24, value = "Archive isolation enabled - creating multiple isolated bean archives if needed", format = Format.MESSAGE_FORMAT) - void archiveIsolationEnabled(); - - @Message(id = 25, value = "Index for name: {0} not found.", format = Format.MESSAGE_FORMAT) - ClassFileInfoException indexForNameNotFound(Object param1); - - @Message(id = 26, value = "Unable to instantiate {0} using parameters: {1}.", format = Format.MESSAGE_FORMAT) - IllegalStateException unableToInstantiate(Object param1, Object param2, @Cause Throwable cause); - - @LogMessage(level = Level.WARN) - @Message(id = 28, value = "Weld initialization skipped - no bean archive found") - void initSkippedNoBeanArchiveFound(); - - @Message(id = 29, value = "Cannot load class for {0}.", format = Format.MESSAGE_FORMAT) - IllegalStateException cannotLoadClass(Object param1, @Cause Throwable cause); - - @LogMessage(level = Level.DEBUG) - @Message(id = 30, value = "Cannot load class using the ResourceLoader: {0}", format = Format.MESSAGE_FORMAT) - void cannotLoadClassUsingResourceLoader(String className); - - @LogMessage(level = Level.WARN) - @Message(id = 31, value = "The bean archive reference {0} cannot be handled by any BeanArchiveHandler: {1}", format = Format.MESSAGE_FORMAT) - void beanArchiveReferenceCannotBeHandled(Object beanArchiveRef, Object handlers); - - @LogMessage(level = Level.DEBUG) - @Message(id = 32, value = "Processing bean archive reference: {0}", format = Format.MESSAGE_FORMAT) - void processingBeanArchiveReference(Object beanArchiveRef); - - @Message(id = 33, value = "Invalid bean archive scanning result - found multiple results with the same reference: {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException invalidScanningResult(Object beanArchiveRef); - - @Message(id = 34, value = "Cannot scan class path entry: {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException cannotScanClassPathEntry(Object entry, @Cause Throwable cause); - - @Message(id = 35, value = "Class path entry does not exist or cannot be read: {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException cannotReadClassPathEntry(Object entry); - - @Message(id = 36, value = "Weld cannot read the java class path system property!", format = Format.MESSAGE_FORMAT) - IllegalStateException cannotReadJavaClassPathSystemProperty(); - - @Message(id = 37, value = "Unable to initialize the Probe component: {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException unableToInitializeProbeComponent(Object component, @Cause Throwable cause); - - @Message(id = 38, value = "Development mode is enabled but the following Probe component is not found on the classpath: {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException probeComponentNotFoundOnClasspath(Object component); - - @LogMessage(level = Level.DEBUG) - @Message(id = 39, value = "Bean archive reference {0} handled by {1}", format = Format.MESSAGE_FORMAT) - void beanArchiveReferenceHandled(Object beanArchiveRef, Object handler); - - @LogMessage(level = Level.INFO) - @Message(id = 40, value = "Jandex discovery strategy was disabled.", format = Format.MESSAGE_FORMAT) - void jandexDiscoveryStrategyDisabled(); - - @LogMessage(level = Level.INFO) - @Message(id = 41, value = "Using {0} for bean discovery", format = Format.MESSAGE_FORMAT) - void usingServiceLoaderSourcedDiscoveryStrategy(Object discoveryStrategy); - + CommonLogger LOG = + Logger.getMessageLogger(CommonLogger.class, Category.BOOTSTRAP.getName()); + + @LogMessage(level = Level.WARN) + @Message(id = 2, value = "Could not read resource with name: {0}", + format = Format.MESSAGE_FORMAT) + void + couldNotReadResource(Object param1, @Cause Throwable cause); + + @LogMessage(level = Level.WARN) + @Message(id = 4, + value = "Could not invoke JNLPClassLoader#getJarFile(URL) on " + + "context class loader, expecting Web Start class loader", + format = Format.MESSAGE_FORMAT) + void + unexpectedClassLoader(@Cause Throwable cause); + + @LogMessage(level = Level.WARN) + @Message(id = 5, value = "JNLPClassLoader#getJarFile(URL) threw exception", + format = Format.MESSAGE_FORMAT) + void + jnlpClassLoaderInternalException(@Cause Throwable cause); + + @LogMessage(level = Level.WARN) + @Message(id = 6, + value = "Could not invoke JNLPClassLoader#getJarFile(URL) on " + + "context class loader", + format = Format.MESSAGE_FORMAT) + void + jnlpClassLoaderInvocationException(@Cause Throwable cause); + + @LogMessage(level = Level.WARN) + @Message(id = 7, value = "Error handling file path\n File: {0}\n Path: {1}", + format = Format.MESSAGE_FORMAT) + void + cannotHandleFilePath(Object file, Object path, @Cause Throwable cause); + + // log message with id 8 was removed + + @LogMessage(level = Level.WARN) + @Message(id = 10, + value = "Could not open the stream on the url {0} when adding to " + + "the jandex index.", + format = Format.MESSAGE_FORMAT) + void + couldNotOpenStreamForURL(Object param1, @Cause Throwable cause); + + @LogMessage(level = Level.WARN) + @Message(id = 11, + value = "Could not close the stream on the url {0} when adding to " + + "the jandex index.", + format = Format.MESSAGE_FORMAT) + void + couldNotCloseStreamForURL(Object param1, @Cause Throwable cause); + + @Message(id = 12, value = "Unable to load class {0}", + format = Format.MESSAGE_FORMAT) + ClassFileInfoException + unableToLoadClass(Object param1); + + @Message( + id = 13, + value = "beans.xml defines unrecognized bean-discovery-mode value: {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + undefinedBeanDiscoveryValue(Object param1); + + @LogMessage(level = Level.INFO) + @Message(id = 14, + value = "Falling back to Java Reflection for " + + "bean-discovery-mode=\"annotated\" discovery. Add " + + "org.jboss:jandex to the classpath to speed-up startup.", + format = Format.MESSAGE_FORMAT) + void + reflectionFallback(); + + @Message(id = 15, value = "Unable to load annotation: {0}", + format = Format.MESSAGE_FORMAT) + ClassFileInfoException + unableToLoadAnnotation(Object param1); + + @Message(id = 16, value = "Missing beans.xml file in META-INF", + format = Format.MESSAGE_FORMAT) + IllegalStateException + missingBeansXml(); + + @Message(id = 18, + value = "Unable to resolve a bean for {0} with bindings {1}", + format = Format.MESSAGE_FORMAT) + UnsatisfiedResolutionException + unableToResolveBean(Object param1, Object param2); + + @Message(id = 19, + value = "Jandex index is null in the constructor of class: {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + jandexIndexNotCreated(Object param1); + + @LogMessage(level = Level.INFO) + @Message(id = 20, value = "Using jandex for bean discovery", + format = Format.MESSAGE_FORMAT) + void + usingJandex(); + + // log message with id 21 was removed + // log message with id 22 was removed + + @LogMessage(level = Level.DEBUG) + @Message( + id = 23, + value = + "Archive isolation disabled - only one bean archive will be created", + format = Format.MESSAGE_FORMAT) + void + archiveIsolationDisabled(); + + @LogMessage(level = Level.DEBUG) + @Message(id = 24, + value = "Archive isolation enabled - creating multiple isolated " + + "bean archives if needed", + format = Format.MESSAGE_FORMAT) + void + archiveIsolationEnabled(); + + @Message(id = 25, value = "Index for name: {0} not found.", + format = Format.MESSAGE_FORMAT) + ClassFileInfoException + indexForNameNotFound(Object param1); + + @Message(id = 26, value = "Unable to instantiate {0} using parameters: {1}.", + format = Format.MESSAGE_FORMAT) + IllegalStateException + unableToInstantiate(Object param1, Object param2, @Cause Throwable cause); + + @LogMessage(level = Level.WARN) + @Message(id = 28, + value = "Weld initialization skipped - no bean archive found") + void + initSkippedNoBeanArchiveFound(); + + @Message(id = 29, value = "Cannot load class for {0}.", + format = Format.MESSAGE_FORMAT) + IllegalStateException + cannotLoadClass(Object param1, @Cause Throwable cause); + + @LogMessage(level = Level.DEBUG) + @Message(id = 30, value = "Cannot load class using the ResourceLoader: {0}", + format = Format.MESSAGE_FORMAT) + void + cannotLoadClassUsingResourceLoader(String className); + + @LogMessage(level = Level.WARN) + @Message(id = 31, + value = "The bean archive reference {0} cannot be handled by any " + + "BeanArchiveHandler: {1}", + format = Format.MESSAGE_FORMAT) + void + beanArchiveReferenceCannotBeHandled(Object beanArchiveRef, Object handlers); + + @LogMessage(level = Level.DEBUG) + @Message(id = 32, value = "Processing bean archive reference: {0}", + format = Format.MESSAGE_FORMAT) + void + processingBeanArchiveReference(Object beanArchiveRef); + + @Message(id = 33, + value = "Invalid bean archive scanning result - found multiple " + + "results with the same reference: {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + invalidScanningResult(Object beanArchiveRef); + + @Message(id = 34, value = "Cannot scan class path entry: {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + cannotScanClassPathEntry(Object entry, @Cause Throwable cause); + + @Message(id = 35, value = "Class path entry cannot be read: {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + cannotReadClassPathEntry(Object entry); + + @Message(id = 36, + value = "Weld cannot read the java class path system property!", + format = Format.MESSAGE_FORMAT) + IllegalStateException + cannotReadJavaClassPathSystemProperty(); + + @Message(id = 37, value = "Unable to initialize the Probe component: {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + unableToInitializeProbeComponent(Object component, @Cause Throwable cause); + + @Message(id = 38, + value = "Development mode is enabled but the following Probe " + + "component is not found on the classpath: {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + probeComponentNotFoundOnClasspath(Object component); + + @LogMessage(level = Level.DEBUG) + @Message(id = 39, value = "Bean archive reference {0} handled by {1}", + format = Format.MESSAGE_FORMAT) + void + beanArchiveReferenceHandled(Object beanArchiveRef, Object handler); + + @LogMessage(level = Level.INFO) + @Message(id = 40, value = "Jandex discovery strategy was disabled.", + format = Format.MESSAGE_FORMAT) + void + jandexDiscoveryStrategyDisabled(); + + @LogMessage(level = Level.INFO) + @Message(id = 41, value = "Using {0} for bean discovery", + format = Format.MESSAGE_FORMAT) + void + usingServiceLoaderSourcedDiscoveryStrategy(Object discoveryStrategy); + + @LogMessage(level = Level.WARN) + @Message(id = 42, value = "Class path entry does not exist: {0}", + format = Format.MESSAGE_FORMAT) + void + classPathEntryDoesNotExist(Object entry); } diff --git a/environments/se/build/pom.xml b/environments/se/build/pom.xml index f8b59b327f..6b837386ca 100644 --- a/environments/se/build/pom.xml +++ b/environments/se/build/pom.xml @@ -3,7 +3,7 @@ weld-se-parent org.jboss.weld.se - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../pom.xml 4.0.0 @@ -35,6 +35,31 @@ true + + org.jboss.weld + weld-api + ${weld.api.version} + true + + + + org.jboss.spec.javax.servlet + jboss-servlet-api_4.0_spec + true + + + + jakarta.inject + jakarta.inject-api + true + + + + jakarta.enterprise + jakarta.enterprise.cdi-api + true + + @@ -81,9 +106,10 @@ maven-jar-plugin - - org.jboss.weld.environment.se.StartMain - + + true + org.jboss.weld.environment.se.StartMain + @@ -106,11 +132,28 @@ true - org.jboss.weld:* - org.jboss.weld.se:* - javax.enterprise:* - javax.inject:* + org.jboss.weld:* + org.jboss.weld.se:* + jakarta.enterprise:* + jakarta.inject:* + + + com.github.spotbugs + spotbugs-annotations + ${spotbugs-annotations-version} + + + org.jboss.logging + jboss-logging-annotations + ${jboss.logging.processor.version} + + + org.apache.bcel + bcel + ${apache.bcel.version} + + diff --git a/environments/se/core/pom.xml b/environments/se/core/pom.xml index d9092ec940..8d8f160eda 100644 --- a/environments/se/core/pom.xml +++ b/environments/se/core/pom.xml @@ -3,7 +3,7 @@ weld-se-parent org.jboss.weld.se - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../pom.xml 4.0.0 @@ -126,7 +126,7 @@ org.codehaus.gmavenplus gmavenplus-plugin - 1.6 + 1.13.1 diff --git a/environments/se/core/src/main/java/org/jboss/weld/environment/se/Weld.java b/environments/se/core/src/main/java/org/jboss/weld/environment/se/Weld.java index 54e1339901..c3a20ec11a 100644 --- a/environments/se/core/src/main/java/org/jboss/weld/environment/se/Weld.java +++ b/environments/se/core/src/main/java/org/jboss/weld/environment/se/Weld.java @@ -46,7 +46,6 @@ import java.util.UUID; import java.util.jar.JarEntry; import java.util.jar.JarFile; - import javax.annotation.Priority; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.UnsatisfiedResolutionException; @@ -55,7 +54,6 @@ import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.Extension; - import org.jboss.weld.bootstrap.WeldBootstrap; import org.jboss.weld.bootstrap.api.CDI11Bootstrap; import org.jboss.weld.bootstrap.api.Environments; @@ -131,26 +129,31 @@ * * *

- * By default, the discovery is enabled so that all beans from all discovered bean archives are considered. However, it's possible to define a "synthetic" bean - * archive, or the set of bean classes and enablement respectively: + * By default, the discovery is enabled so that all beans from all discovered + * bean archives are considered. However, it's possible to define a "synthetic" + * bean archive, or the set of bean classes and enablement respectively: *

* *
- * WeldContainer container = new Weld().beanClasses(Foo.class, Bar.class).alternatives(Bar.class).initialize()) {
+ * WeldContainer container = new Weld().beanClasses(Foo.class,
+ * Bar.class).alternatives(Bar.class).initialize()) {
  * 
* *

- * Moreover, it's also possible to disable the discovery completely so that only the "synthetic" bean archive is considered: + * Moreover, it's also possible to disable the discovery completely so that only + * the "synthetic" bean archive is considered: *

* *
- * WeldContainer container = new Weld().disableDiscovery().beanClasses(Foo.class, Bar.class).initialize()) {
+ * WeldContainer container = new
+ * Weld().disableDiscovery().beanClasses(Foo.class, Bar.class).initialize()) {
  * 
* * *

- * In the same manner, it is possible to explicitly declare interceptors, decorators, extensions and Weld-specific options (such as relaxed construction) using - * the builder. + * In the same manner, it is possible to explicitly declare interceptors, + * decorators, extensions and Weld-specific options (such as relaxed + * construction) using the builder. *

* *
@@ -163,8 +166,10 @@
  * 
* *

- * The builder is reusable which means that it's possible to initialize multiple Weld containers with one builder. However, note that containers must have a - * unique identifier assigned when running multiple Weld instances at the same time. + * The builder is reusable which means that it's possible to initialize multiple + * Weld containers with one builder. However, note that containers must have a + * unique identifier assigned when running multiple Weld instances at the same + * time. *

* * @author Peter Royle @@ -174,1120 +179,1300 @@ * @see WeldContainer */ @Vetoed -public class Weld extends SeContainerInitializer implements ContainerInstanceFactory { - - /** - * By default, bean archive isolation is enabled. If set to false, Weld will use a "flat" deployment structure - all bean classes share the same bean - * archive and all beans.xml descriptors are automatically merged into one. - *

- * This key can be also used through {@link #property(String, Object)}. - */ - public static final String ARCHIVE_ISOLATION_SYSTEM_PROPERTY = "org.jboss.weld.se.archive.isolation"; - - /** - * By default, the development mode is disabled. If set to true, the development mode is activated - *

- * This key can be also used through {@link #property(String, Object)}. - */ - public static final String DEV_MODE_SYSTEM_PROPERTY = "org.jboss.weld.development"; - - /** - * By default, Weld automatically registers shutdown hook during initialization. If set to false, the registration of a shutdown hook is skipped. - *

- * This key can be also used through {@link #property(String, Object)}. - */ - public static final String SHUTDOWN_HOOK_SYSTEM_PROPERTY = "org.jboss.weld.se.shutdownHook"; - - /** - * By default, Weld SE does not support implicit bean archives without beans.xml. If set to true, Weld scans the class path entries and implicit bean - * archives which don't contain a beans.xml file are also supported. - *

- * This key can be also used through {@link #property(String, Object)}. - */ - public static final String SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY = "org.jboss.weld.se.scan.classpath.entries"; - - /** - * See also the CDI specification, section 15.1 Bean archive in Java SE. - */ - public static final String JAVAX_ENTERPRISE_INJECT_SCAN_IMPLICIT = "javax.enterprise.inject.scan.implicit"; - - /** - * By default, Weld is allowed to perform efficient cleanup and further optimizations after bootstrap. This feature is normally controlled by integrator - * through {@link ConfigurationKey#ALLOW_OPTIMIZED_CLEANUP} but in Weld SE a client of the bootstrap API is de facto in the role of integrator. - *

- * This key can be also used through {@link #property(String, Object)}. - */ - public static final String ALLOW_OPTIMIZED_CLEANUP = "org.jboss.weld.bootstrap.allowOptimizedCleanup"; - - private static final String SYNTHETIC_LOCATION_PREFIX = "synthetic:"; - - static { - if (!(SingletonProvider.instance() instanceof RegistrySingletonProvider)) { - // make sure RegistrySingletonProvider is used (required for supporting multiple parallel Weld instances) - SingletonProvider.reset(); - SingletonProvider.initialize(new RegistrySingletonProvider()); - } - } - - private final Map initializedContainers; - - private String containerId; - - private boolean discoveryEnabled = true; - - protected final Set> beanClasses; - - protected final Set> extendedBeanDefiningAnnotations; - - protected BeanDiscoveryMode beanDiscoveryMode = BeanDiscoveryMode.ALL; - - private final List> selectedAlternatives; - - private final List> selectedAlternativeStereotypes; - - private final List> enabledInterceptors; - - private final List> enabledDecorators; - - private final Set> extensions; - - private final Map properties; - - private final Set packages; - - private final List> containerLifecycleObservers; - - private ResourceLoader resourceLoader; - - protected final Map, Service> additionalServices; - - public Weld() { - this(null); - } - - /** - * - * @param containerId The container identifier - * @see Weld#containerId(String) - */ - public Weld(String containerId) { - this.containerId = containerId; - this.initializedContainers = new HashMap(); - this.beanClasses = new HashSet>(); - this.selectedAlternatives = new ArrayList>(); - this.selectedAlternativeStereotypes = new ArrayList>(); - this.enabledInterceptors = new ArrayList>(); - this.enabledDecorators = new ArrayList>(); - this.extensions = new HashSet>(); - this.properties = new HashMap(); - this.packages = new HashSet(); - this.containerLifecycleObservers = new LinkedList<>(); - this.resourceLoader = new WeldResourceLoader(); - this.additionalServices = new HashMap<>(); - this.extendedBeanDefiningAnnotations = new HashSet<>(); - } - - /** - * Containers must have a unique identifier assigned when running multiple Weld instances at the same time. - * - * @param containerId - * @return self - */ - public Weld containerId(String containerId) { - this.containerId = containerId; - return this; - } - - /** - * - * @return a container identifier - * @see #containerId(String) - */ - public String getContainerId() { - return containerId; - } - - /** - * Define the set of bean classes for the synthetic bean archive. - * - * @param classes - * @return self - */ - public Weld beanClasses(Class... classes) { - beanClasses.clear(); - addBeanClasses(classes); - return this; - } +public class Weld + extends SeContainerInitializer implements ContainerInstanceFactory { + + /** + * By default, the set of bean-defining annotations is fixed. If set to a + * {@link Set} of annotation classes, the set of bean-defining annotations is + * augmented with the contents of the {@link Set}. + *

+ * This key can be used through {@link #property(String, Object}. + */ + public static final String ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY = + "org.jboss.weld.se.additionalBeanDefiningAnnotations"; - /** - * Add a bean class to the set of bean classes for the synthetic bean archive. - * - * @param beanClass - * @return self - */ - public Weld addBeanClass(Class beanClass) { - beanClasses.add(beanClass); - return this; - } - - @Override - public Weld addBeanClasses(Class... classes) { - for (Class aClass : classes) { - addBeanClass(aClass); - } - return this; - } - - /** - * All classes from the packages of the specified classes will be added to the set of bean classes for the synthetic bean archive. - * - *

- * Note that the scanning possibilities are limited. Therefore, only directories and jar files from the filesystem are supported. - *

- * - *

- * Scanning may also have negative impact on bootstrap performance. - *

- * - * @param classes - * @return self - */ - public Weld packages(Class... packageClasses) { - packages.clear(); - addPackages(false, packageClasses); - return this; - } - - /** - * Packages of the specified classes will be scanned and found classes will be added to the set of bean classes for the synthetic bean archive. - * - * @param scanRecursively - * @param packageClasses - * @return self - */ - public Weld addPackages(boolean scanRecursively, Class... packageClasses) { - for (Class packageClass : packageClasses) { - addPackage(scanRecursively, packageClass); - } - return this; - } - - @Override - public Weld addPackages(Class... packageClasses) { - addPackages(false, packageClasses); - return this; - } - - @Override - public Weld addPackages(Package... packages) { - addPackages(false, packages); - return this; - } - - @Override - public Weld addPackages(boolean scanRecursively, Package... packages) { - for (Package pack : packages) { - this.packages.add(new PackInfo(pack, scanRecursively)); - } - return this; - } - - /** - * A package of the specified class will be scanned and found classes will be added to the set of bean classes for the synthetic bean archive. - * - * @param scanRecursively - * @param packageClass - * @return self - */ - public Weld addPackage(boolean scanRecursively, Class packageClass) { - packages.add(new PackInfo(packageClass, scanRecursively)); - return this; - } - - /** - * Define the set of extensions. - * - * @param extensions - * @return self - */ - public Weld extensions(Extension... extensions) { - this.extensions.clear(); - for (Extension extension : extensions) { - addExtension(extension); - } - return this; - } - - /** - * Add an extension to the set of extensions. - * - * @param extension an extension - */ - public Weld addExtension(Extension extension) { - extensions.add(new MetadataImpl(extension, SYNTHETIC_LOCATION_PREFIX + extension.getClass().getName())); - return this; - } - - @Override - public Weld addExtensions(Extension... extensions) { - for (Extension extension : extensions) { - addExtension(extension); - } - return this; - } - - @SuppressWarnings("unchecked") - @Override - public Weld addExtensions(Class... extensionClasses) { - for (Class extensionClass : extensionClasses) { - try { - Extension extension = SecurityActions.newInstance(extensionClass); - addExtension(extension); - } catch (Exception ex) { - CommonLogger.LOG.unableToInstantiate(extensionClass, new Object[] {}, ex); - } - } - return this; - } - - /** - * Add a synthetic container lifecycle event observer. - * - * @param observer - * @return self - * @see ContainerLifecycleObserver - */ - public Weld addContainerLifecycleObserver(ContainerLifecycleObserver observer) { - containerLifecycleObservers.add(observer); - return this; - } - - /** - * Enable interceptors for the synthetic bean archive, all previous values are removed. - *

- * This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the - * beans.xml descriptor. - * - * @param interceptorClasses - * @return self - */ - public Weld interceptors(Class... interceptorClasses) { - enabledInterceptors.clear(); - enableInterceptors(interceptorClasses); - return this; - } - - /** - * Add an interceptor class to the list of enabled interceptors for the synthetic bean archive. - *

- * This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the - * beans.xml descriptor. - * - * @param interceptorClass - * @return self - */ - public Weld addInterceptor(Class interceptorClass) { - enabledInterceptors.add(syntheticMetadata(interceptorClass)); - return this; - } - - @Override - public Weld enableInterceptors(Class... interceptorClasses) { - for (Class interceptorClass : interceptorClasses) { - addInterceptor(interceptorClass); - } - return this; - } - - /** - * Enable decorators for the synthetic bean archive, all previous values are removed. - *

- * This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the - * beans.xml descriptor. - * - * @param decoratorClasses - * @return self - */ - public Weld decorators(Class... decoratorClasses) { - enabledDecorators.clear(); - enableDecorators(decoratorClasses); - return this; - } - - /** - * Add a decorator class to the list of enabled decorators for the synthetic bean archive. - *

- * This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the - * beans.xml descriptor. - * - * @param decoratorClass - * @return self - */ - public Weld addDecorator(Class decoratorClass) { - enabledDecorators.add(syntheticMetadata(decoratorClass)); - return this; - } - - @Override - public Weld enableDecorators(Class... decoratorClasses) { - for (Class decoratorClass : decoratorClasses) { - addDecorator(decoratorClass); - } - return this; - } - - /** - * Select alternatives for the synthetic bean archive, all previous values are removed. - *

- * This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the - * beans.xml descriptor. - * - * @param alternativeClasses - * @return self - */ - public Weld alternatives(Class... alternativeClasses) { - selectedAlternatives.clear(); - selectAlternatives(alternativeClasses); - return this; - } - - /** - * Add an alternative class to the list of selected alternatives for a synthetic bean archive. - *

- * This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the - * beans.xml descriptor. - * - * @param alternativeClass - * @return self - */ - public Weld addAlternative(Class alternativeClass) { - selectedAlternatives.add(syntheticMetadata(alternativeClass)); - return this; - } - - @Override - public Weld selectAlternatives(Class... alternativeClasses) { - for (Class alternativeClass : alternativeClasses) { - addAlternative(alternativeClass); - } - return this; - } - - /** - * Select alternative stereotypes for the synthetic bean archive, all previous values are removed. - *

- * This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the - * beans.xml descriptor. - * - * @param alternativeStereotypeClasses - * @return self - */ - @SafeVarargs - public final Weld alternativeStereotypes(Class... alternativeStereotypeClasses) { - selectedAlternativeStereotypes.clear(); - selectAlternativeStereotypes(alternativeStereotypeClasses); - return this; - } - - @SuppressWarnings("unchecked") - @Override - public Weld selectAlternativeStereotypes(Class... alternativeStereotypeClasses) { - for (Class alternativeStereotypeClass : alternativeStereotypeClasses) { - addAlternativeStereotype(alternativeStereotypeClass); - } - return this; - } - - /** - * Add an alternative stereotype class to the list of selected alternative stereotypes for a synthetic bean archive. - *

- * This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the - * beans.xml descriptor. - * - * @param alternativeStereotypeClass - * @return self - */ - public Weld addAlternativeStereotype(Class alternativeStereotypeClass) { - selectedAlternativeStereotypes.add(syntheticMetadata(alternativeStereotypeClass)); - return this; - } - - /** - * Set the configuration property. - * - * @param key - * @param value - * @return self - * @see #ARCHIVE_ISOLATION_SYSTEM_PROPERTY - * @see #SHUTDOWN_HOOK_SYSTEM_PROPERTY - * @see #DEV_MODE_SYSTEM_PROPERTY - * @see ConfigurationKey - */ - public Weld property(String key, Object value) { - properties.put(key, value); - return this; - } - - /** - * Set all the configuration properties. - * - * @param properties - * @return self - */ - public Weld properties(Map properties) { - this.properties.putAll(properties); - return this; - } - - @Override - public Weld addProperty(String key, Object value) { - property(key, value); - return this; - } - - @Override - public Weld setProperties(Map propertiesMap) { - properties.clear(); - properties.putAll(propertiesMap); - return this; - } - - /** - * Register per-deployment services which are shared across the entire application. - *

- * Weld uses services to communicate with its environment, e.g. {@link org.jboss.weld.manager.api.ExecutorServices} or - * {@link org.jboss.weld.transaction.spi.TransactionServices}. - *

- *

- * Service implementation may specify their priority using {@link Priority}. Services with higher priority have precedence. Services that do not specify - * priority have the default priority of 4500. - *

- * - * @param services - * @return self - * @see Service - */ - public Weld addServices(Service... services) { - for (Service service : services) { - for (Class serviceInterface : Services.identifyServiceInterfaces(service.getClass(), new HashSet<>())) { - additionalServices.put(serviceInterface, service); - } - } - return this; - } - - /** - * Sets the bean discovery mode for synthetic bean archive. Default mode is ALL. - * @param mode bean discovery mode in a form of an enum from {@link org.jboss.weld.bootstrap.spi.BeanDiscoveryMode}. Accepted values are ALL, ANNOTATED - * - * @return self - * @throws IllegalArgumentException if BeanDiscoveryMode.NONE is passed as an argument - */ - public Weld setBeanDiscoveryMode(BeanDiscoveryMode mode) { - // NONE makes no sense as an option - if (mode.equals(BeanDiscoveryMode.NONE)) { - throw WeldSELogger.LOG.beanArchiveWithModeNone(containerId); - } - beanDiscoveryMode = mode; - return this; - } - - /** - * Reset the synthetic bean archive (bean classes and enablement), explicitly added extensions and services. - * - * @return self - */ - public Weld reset() { - beanClasses.clear(); - packages.clear(); - selectedAlternatives.clear(); - selectedAlternativeStereotypes.clear(); - enabledInterceptors.clear(); - enabledDecorators.clear(); - extensions.clear(); - containerLifecycleObservers.clear(); - additionalServices.clear(); - return this; - } - - /** - * Reset all the state, except for initialized containers. - * - * @return self - * @see Weld#reset() - */ - public Weld resetAll() { - reset(); - properties.clear(); - enableDiscovery(); - containerId(null); - return this; - } - - /** - * - * @return self - * @see #disableDiscovery() - */ - public Weld enableDiscovery() { - this.discoveryEnabled = true; - return this; - } - - /** - * By default, the discovery is enabled. However, it's possible to disable the discovery completely so that only the "synthetic" bean archive is considered. - * - * @return self - */ - public Weld disableDiscovery() { - this.discoveryEnabled = false; - return this; - } - - /** - * - * @return true if the discovery is enabled, false otherwise - * @see #disableDiscovery() - */ - public boolean isDiscoveryEnabled() { - return discoveryEnabled; - } - - /** - * Bootstraps a new Weld SE container with the current container id (generated value if not set through {@link #containerId(String)}). - *

- * The container must be shut down properly when an application is stopped. Applications are encouraged to use the try-with-resources statement or invoke - * {@link WeldContainer#shutdown()} explicitly. - *

- * However, a shutdown hook is also registered during initialization so that all running containers are shut down automatically when a program exits or VM - * is terminated. This means that it's not necessary to implement the shutdown logic in a class where a main method is used to start the container. - * - * @return the Weld container - * @see #enableDiscovery() - * @see WeldContainer#shutdown() - */ - public WeldContainer initialize() { - - // If also building a synthetic bean archive or the implicit scan is enabled, the check for beans.xml is not necessary - if (!isSyntheticBeanArchiveRequired() && !isImplicitScanEnabled() && resourceLoader.getResource(WeldDeployment.BEANS_XML) == null) { - throw CommonLogger.LOG.missingBeansXml(); - } - - final WeldBootstrap bootstrap = new WeldBootstrap(); - final Deployment deployment = createDeployment(resourceLoader, bootstrap); - - final ExternalConfigurationBuilder configurationBuilder = new ExternalConfigurationBuilder() - // weld-se uses CommonForkJoinPoolExecutorServices by default - .add(EXECUTOR_THREAD_POOL_TYPE.get(), COMMON.toString()) - // weld-se uses relaxed construction by default - .add(ConfigurationKey.RELAXED_CONSTRUCTION.get(), true) - // allow optimized cleanup by default - .add(ConfigurationKey.ALLOW_OPTIMIZED_CLEANUP.get(), isEnabled(ALLOW_OPTIMIZED_CLEANUP, true)); - for (Entry property : properties.entrySet()) { - String key = property.getKey(); - if (SHUTDOWN_HOOK_SYSTEM_PROPERTY.equals(key) || ARCHIVE_ISOLATION_SYSTEM_PROPERTY.equals(key) || DEV_MODE_SYSTEM_PROPERTY.equals(key) - || SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY.equals(key) || JAVAX_ENTERPRISE_INJECT_SCAN_IMPLICIT.equals(key)) { - continue; - } - configurationBuilder.add(key, property.getValue()); - } - deployment.getServices().add(ExternalConfiguration.class, configurationBuilder.build()); - - final String containerId = this.containerId != null ? this.containerId : UUID.randomUUID().toString(); - bootstrap.startContainer(containerId, Environments.SE, deployment); - - final WeldContainer weldContainer = WeldContainer.startInitialization(containerId, deployment, bootstrap); - - try { - bootstrap.startInitialization(); - bootstrap.deployBeans(); - bootstrap.validateBeans(); - bootstrap.endInitialization(); - WeldContainer.endInitialization(weldContainer, isEnabled(SHUTDOWN_HOOK_SYSTEM_PROPERTY, true)); - initializedContainers.put(containerId, weldContainer); - } catch (Throwable e) { - // Discard the container if a bootstrap problem occurs, e.g. validation error - WeldContainer.discard(weldContainer.getId()); - throw e; - } - return weldContainer; - } - - /** - * Shuts down all the containers initialized by this builder. - */ - public void shutdown() { - if (!initializedContainers.isEmpty()) { - for (WeldContainer container : initializedContainers.values()) { - container.shutdown(); - } - } - } - - /** - * Set a {@link ClassLoader}. The given {@link ClassLoader} will be scanned automatically for bean archives if scanning is enabled. - * - * @param classLoader - * @return self - */ - public Weld setClassLoader(ClassLoader classLoader) { - Preconditions.checkNotNull(classLoader); - resourceLoader = new ClassLoaderResourceLoader(classLoader); - return this; - } - - /** - * Set a {@link ResourceLoader} used to scan the application for bean archives. If you only want to use a specific {@link ClassLoader} for scanning, use - * {@link #setClassLoader(ClassLoader)} instead. - * - * @param resourceLoader - * @return self - * @see #isDiscoveryEnabled() - */ - public Weld setResourceLoader(ResourceLoader resourceLoader) { - Preconditions.checkNotNull(resourceLoader); - this.resourceLoader = resourceLoader; - return this; - } - - /** - * Disable bean archive isolation, i.e. use a "flat" deployment structure. - * - * @return self - * @see #ARCHIVE_ISOLATION_SYSTEM_PROPERTY - */ - public Weld disableIsolation() { - return property(ARCHIVE_ISOLATION_SYSTEM_PROPERTY, false); - } - - /** - * Skip shutdown hook registration. - * - * @return self - * @see #SHUTDOWN_HOOK_SYSTEM_PROPERTY - */ - public Weld skipShutdownHook() { - return property(SHUTDOWN_HOOK_SYSTEM_PROPERTY, false); - } - - /** - * Scans the class path entries - implicit bean archives which don't contain a beans.xml file are supported. - * - * @return self - * @see #SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY - */ - public Weld scanClasspathEntries() { - return property(SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY, true); - } - - /** - * Enable the development mode. - * - * @return self - * @see #DEV_MODE_SYSTEM_PROPERTY - */ - public Weld enableDevMode() { - return property(DEV_MODE_SYSTEM_PROPERTY, true); - } - - /** - * Registers annotations which will be considered as bean defining annotations. - * - * NOTE - If used along with {@code } bean archives and/or with Weld configuration key - * {@code org.jboss.weld.bootstrap.vetoTypesWithoutBeanDefiningAnnotation}, these annotations will be ignored. - * - * @param annotations annotations which will be considered as Bean Defining Annotations. - * @return self - */ - public Weld addBeanDefiningAnnotations(Class... annotations) { - for (Class annotation : annotations) { - this.extendedBeanDefiningAnnotations.add(annotation); - } - return this; - } - - /** - *

- * Extensions to Weld SE can subclass and override this method to customize the deployment before weld boots up. For example, to add a custom - * ResourceLoader, you would subclass Weld like so: - *

- * - *
-     * public class MyWeld extends Weld {
-     *     protected Deployment createDeployment(ResourceLoader resourceLoader, CDI11Bootstrap bootstrap) {
-     *         return super.createDeployment(new MyResourceLoader(), bootstrap);
-     *     }
-     * }
-     * 
- * - *

- * This could then be used as normal: - *

- * - *
-     * WeldContainer container = new MyWeld().initialize();
-     * 
- * - * @param resourceLoader - * @param bootstrap - */ - protected Deployment createDeployment(ResourceLoader resourceLoader, CDI11Bootstrap bootstrap) { - - final Iterable> extensions = getExtensions(); - final TypeDiscoveryConfiguration typeDiscoveryConfiguration = bootstrap.startExtensions(extensions); - final Deployment deployment; - final Set beanDeploymentArchives = new HashSet(); - final Map, Service> additionalServices = new HashMap<>(this.additionalServices); - final Set> beanDefiningAnnotations = ImmutableSet.> builder() - .addAll(typeDiscoveryConfiguration.getKnownBeanDefiningAnnotations()) - // Add ThreadScoped manually as Weld SE doesn't support implicit bean archives without beans.xml + /** + * By default, bean archive isolation is enabled. If set to false, Weld will + * use a "flat" deployment structure - all bean classes share the same bean + * archive and all beans.xml descriptors are automatically merged into one. + *

+ * This key can be also used through {@link #property(String, Object)}. + */ + public static final String ARCHIVE_ISOLATION_SYSTEM_PROPERTY = + "org.jboss.weld.se.archive.isolation"; + + /** + * By default, the development mode is disabled. If set to true, the + * development mode is activated

This key can be also used through {@link + * #property(String, Object)}. + */ + public static final String DEV_MODE_SYSTEM_PROPERTY = + "org.jboss.weld.development"; + + /** + * By default, Weld automatically registers shutdown hook during + * initialization. If set to false, the registration of a shutdown hook is + * skipped.

This key can be also used through {@link #property(String, + * Object)}. + */ + public static final String SHUTDOWN_HOOK_SYSTEM_PROPERTY = + "org.jboss.weld.se.shutdownHook"; + + /** + * By default, Weld SE does not support implicit bean archives without + * beans.xml. If set to true, Weld scans the class path entries and implicit + * bean archives which don't contain a beans.xml file are also supported.

+ * This key can be also used through {@link #property(String, Object)}. + */ + public static final String SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY = + "org.jboss.weld.se.scan.classpath.entries"; + + /** + * See also the CDI specification, section 15.1 Bean archive in Java + * SE. + */ + public static final String JAVAX_ENTERPRISE_INJECT_SCAN_IMPLICIT = + "javax.enterprise.inject.scan.implicit"; + + /** + * By default, Weld is allowed to perform efficient cleanup and further + * optimizations after bootstrap. This feature is normally controlled by + * integrator through {@link ConfigurationKey#ALLOW_OPTIMIZED_CLEANUP} but in + * Weld SE a client of the bootstrap API is de facto in the role of + * integrator.

This key can be also used through {@link #property(String, + * Object)}. + */ + public static final String ALLOW_OPTIMIZED_CLEANUP = + "org.jboss.weld.bootstrap.allowOptimizedCleanup"; + + private static final String SYNTHETIC_LOCATION_PREFIX = "synthetic:"; + + static { + if (!(SingletonProvider.instance() instanceof RegistrySingletonProvider)) { + // make sure RegistrySingletonProvider is used (required for supporting + // multiple parallel Weld instances) + SingletonProvider.reset(); + SingletonProvider.initialize(new RegistrySingletonProvider()); + } + } + + private final Map initializedContainers; + + private String containerId; + + private boolean discoveryEnabled = true; + + protected final Set> beanClasses; + + protected final Set> + extendedBeanDefiningAnnotations; + + protected BeanDiscoveryMode beanDiscoveryMode = BeanDiscoveryMode.ALL; + + private final List> selectedAlternatives; + + private final List> selectedAlternativeStereotypes; + + private final List> enabledInterceptors; + + private final List> enabledDecorators; + + private final Set> extensions; + + private final Map properties; + + private final Set packages; + + private final List> containerLifecycleObservers; + + private ResourceLoader resourceLoader; + + protected final Map, Service> additionalServices; + + public Weld() { this(null); } + + /** + * + * @param containerId The container identifier + * @see Weld#containerId(String) + */ + public Weld(String containerId) { + this.containerId = containerId; + this.initializedContainers = new HashMap(); + this.beanClasses = new HashSet>(); + this.selectedAlternatives = new ArrayList>(); + this.selectedAlternativeStereotypes = new ArrayList>(); + this.enabledInterceptors = new ArrayList>(); + this.enabledDecorators = new ArrayList>(); + this.extensions = new HashSet>(); + this.properties = new HashMap(); + this.packages = new HashSet(); + this.containerLifecycleObservers = new LinkedList<>(); + this.resourceLoader = new WeldResourceLoader(); + this.additionalServices = new HashMap<>(); + this.extendedBeanDefiningAnnotations = new HashSet<>(); + } + + /** + * Containers must have a unique identifier assigned when running multiple + * Weld instances at the same time. + * + * @param containerId + * @return self + */ + public Weld containerId(String containerId) { + this.containerId = containerId; + return this; + } + + /** + * + * @return a container identifier + * @see #containerId(String) + */ + public String getContainerId() { return containerId; } + + /** + * Define the set of bean classes for the synthetic bean archive. + * + * @param classes + * @return self + */ + public Weld beanClasses(Class... classes) { + beanClasses.clear(); + addBeanClasses(classes); + return this; + } + + /** + * Add a bean class to the set of bean classes for the synthetic bean archive. + * + * @param beanClass + * @return self + */ + public Weld addBeanClass(Class beanClass) { + beanClasses.add(beanClass); + return this; + } + + @Override + public Weld addBeanClasses(Class... classes) { + for (Class aClass : classes) { + addBeanClass(aClass); + } + return this; + } + + /** + * All classes from the packages of the specified classes will be added to the + * set of bean classes for the synthetic bean archive. + * + *

+ * Note that the scanning possibilities are limited. Therefore, only + * directories and jar files from the filesystem are supported. + *

+ * + *

+ * Scanning may also have negative impact on bootstrap performance. + *

+ * + * @param classes + * @return self + */ + public Weld packages(Class... packageClasses) { + packages.clear(); + addPackages(false, packageClasses); + return this; + } + + /** + * Packages of the specified classes will be scanned and found classes will be + * added to the set of bean classes for the synthetic bean archive. + * + * @param scanRecursively + * @param packageClasses + * @return self + */ + public Weld addPackages(boolean scanRecursively, Class... packageClasses) { + for (Class packageClass : packageClasses) { + addPackage(scanRecursively, packageClass); + } + return this; + } + + @Override + public Weld addPackages(Class... packageClasses) { + addPackages(false, packageClasses); + return this; + } + + @Override + public Weld addPackages(Package... packages) { + addPackages(false, packages); + return this; + } + + @Override + public Weld addPackages(boolean scanRecursively, Package... packages) { + for (Package pack : packages) { + this.packages.add(new PackInfo(pack, scanRecursively)); + } + return this; + } + + /** + * A package of the specified class will be scanned and found classes will be + * added to the set of bean classes for the synthetic bean archive. + * + * @param scanRecursively + * @param packageClass + * @return self + */ + public Weld addPackage(boolean scanRecursively, Class packageClass) { + packages.add(new PackInfo(packageClass, scanRecursively)); + return this; + } + + /** + * Define the set of extensions. + * + * @param extensions + * @return self + */ + public Weld extensions(Extension... extensions) { + this.extensions.clear(); + for (Extension extension : extensions) { + addExtension(extension); + } + return this; + } + + /** + * Add an extension to the set of extensions. + * + * @param extension an extension + */ + public Weld addExtension(Extension extension) { + extensions.add(new MetadataImpl( + extension, SYNTHETIC_LOCATION_PREFIX + extension.getClass().getName())); + return this; + } + + @Override + public Weld addExtensions(Extension... extensions) { + for (Extension extension : extensions) { + addExtension(extension); + } + return this; + } + + @SuppressWarnings("unchecked") + @Override + public Weld addExtensions(Class... extensionClasses) { + for (Class extensionClass : extensionClasses) { + try { + Extension extension = SecurityActions.newInstance(extensionClass); + addExtension(extension); + } catch (Exception ex) { + CommonLogger.LOG.unableToInstantiate(extensionClass, new Object[] {}, + ex); + } + } + return this; + } + + /** + * Add a synthetic container lifecycle event observer. + * + * @param observer + * @return self + * @see ContainerLifecycleObserver + */ + public Weld + addContainerLifecycleObserver(ContainerLifecycleObserver observer) { + containerLifecycleObservers.add(observer); + return this; + } + + /** + * Enable interceptors for the synthetic bean archive, all previous values are + * removed.

This method does not add any class to the set of bean classes + * for the synthetic bean archive. It's purpose is solely to compensate the + * absence of the beans.xml descriptor. + * + * @param interceptorClasses + * @return self + */ + public Weld interceptors(Class... interceptorClasses) { + enabledInterceptors.clear(); + enableInterceptors(interceptorClasses); + return this; + } + + /** + * Add an interceptor class to the list of enabled interceptors for the + * synthetic bean archive.

This method does not add any class to the set + * of bean classes for the synthetic bean archive. It's purpose is solely to + * compensate the absence of the beans.xml descriptor. + * + * @param interceptorClass + * @return self + */ + public Weld addInterceptor(Class interceptorClass) { + enabledInterceptors.add(syntheticMetadata(interceptorClass)); + return this; + } + + @Override + public Weld enableInterceptors(Class... interceptorClasses) { + for (Class interceptorClass : interceptorClasses) { + addInterceptor(interceptorClass); + } + return this; + } + + /** + * Enable decorators for the synthetic bean archive, all previous values are + * removed.

This method does not add any class to the set of bean classes + * for the synthetic bean archive. It's purpose is solely to compensate the + * absence of the beans.xml descriptor. + * + * @param decoratorClasses + * @return self + */ + public Weld decorators(Class... decoratorClasses) { + enabledDecorators.clear(); + enableDecorators(decoratorClasses); + return this; + } + + /** + * Add a decorator class to the list of enabled decorators for the synthetic + * bean archive.

This method does not add any class to the set of bean + * classes for the synthetic bean archive. It's purpose is solely to + * compensate the absence of the beans.xml descriptor. + * + * @param decoratorClass + * @return self + */ + public Weld addDecorator(Class decoratorClass) { + enabledDecorators.add(syntheticMetadata(decoratorClass)); + return this; + } + + @Override + public Weld enableDecorators(Class... decoratorClasses) { + for (Class decoratorClass : decoratorClasses) { + addDecorator(decoratorClass); + } + return this; + } + + /** + * Select alternatives for the synthetic bean archive, all previous values are + * removed.

This method does not add any class to the set of bean classes + * for the synthetic bean archive. It's purpose is solely to compensate the + * absence of the beans.xml descriptor. + * + * @param alternativeClasses + * @return self + */ + public Weld alternatives(Class... alternativeClasses) { + selectedAlternatives.clear(); + selectAlternatives(alternativeClasses); + return this; + } + + /** + * Add an alternative class to the list of selected alternatives for a + * synthetic bean archive.

This method does not add any class to the set + * of bean classes for the synthetic bean archive. It's purpose is solely to + * compensate the absence of the beans.xml descriptor. + * + * @param alternativeClass + * @return self + */ + public Weld addAlternative(Class alternativeClass) { + selectedAlternatives.add(syntheticMetadata(alternativeClass)); + return this; + } + + @Override + public Weld selectAlternatives(Class... alternativeClasses) { + for (Class alternativeClass : alternativeClasses) { + addAlternative(alternativeClass); + } + return this; + } + + /** + * Select alternative stereotypes for the synthetic bean archive, all previous + * values are removed.

This method does not add any class to the set of + * bean classes for the synthetic bean archive. It's purpose is solely to + * compensate the absence of the beans.xml descriptor. + * + * @param alternativeStereotypeClasses + * @return self + */ + @SafeVarargs + public final Weld alternativeStereotypes( + Class... alternativeStereotypeClasses) { + selectedAlternativeStereotypes.clear(); + selectAlternativeStereotypes(alternativeStereotypeClasses); + return this; + } + + @SuppressWarnings("unchecked") + @Override + public Weld selectAlternativeStereotypes( + Class... alternativeStereotypeClasses) { + for (Class alternativeStereotypeClass : + alternativeStereotypeClasses) { + addAlternativeStereotype(alternativeStereotypeClass); + } + return this; + } + + /** + * Add an alternative stereotype class to the list of selected alternative + * stereotypes for a synthetic bean archive.

This method does not add any + * class to the set of bean classes for the synthetic bean archive. It's + * purpose is solely to compensate the absence of the beans.xml + * descriptor. + * + * @param alternativeStereotypeClass + * @return self + */ + public Weld addAlternativeStereotype( + Class alternativeStereotypeClass) { + selectedAlternativeStereotypes.add( + syntheticMetadata(alternativeStereotypeClass)); + return this; + } + + /** + * Set the configuration property. + * + * @param key + * @param value + * @return self + * @see #ARCHIVE_ISOLATION_SYSTEM_PROPERTY + * @see #SHUTDOWN_HOOK_SYSTEM_PROPERTY + * @see #DEV_MODE_SYSTEM_PROPERTY + * @see ConfigurationKey + */ + public Weld property(String key, Object value) { + properties.put(key, value); + return this; + } + + /** + * Set all the configuration properties. + * + * @param properties + * @return self + */ + public Weld properties(Map properties) { + this.properties.putAll(properties); + return this; + } + + @Override + public Weld addProperty(String key, Object value) { + property(key, value); + return this; + } + + @Override + public Weld setProperties(Map propertiesMap) { + properties.clear(); + properties.putAll(propertiesMap); + return this; + } + + /** + * Register per-deployment services which are shared across the entire + * application.

Weld uses services to communicate with its environment, + * e.g. {@link org.jboss.weld.manager.api.ExecutorServices} or + * {@link org.jboss.weld.transaction.spi.TransactionServices}. + *

+ *

+ * Service implementation may specify their priority using {@link Priority}. + * Services with higher priority have precedence. Services that do not specify + * priority have the default priority of 4500. + *

+ * + * @param services + * @return self + * @see Service + */ + public Weld addServices(Service... services) { + for (Service service : services) { + for (Class serviceInterface : + Services.identifyServiceInterfaces(service.getClass(), + new HashSet<>())) { + additionalServices.put(serviceInterface, service); + } + } + return this; + } + + /** + * Sets the bean discovery mode for synthetic bean archive. Default mode is + * ALL. + * @param mode bean discovery mode in a form of an enum from {@link + * org.jboss.weld.bootstrap.spi.BeanDiscoveryMode}. Accepted values are + * ALL, ANNOTATED + * + * @return self + * @throws IllegalArgumentException if BeanDiscoveryMode.NONE is passed as an + * argument + */ + public Weld setBeanDiscoveryMode(BeanDiscoveryMode mode) { + // NONE makes no sense as an option + if (mode.equals(BeanDiscoveryMode.NONE)) { + throw WeldSELogger.LOG.beanArchiveWithModeNone(containerId); + } + beanDiscoveryMode = mode; + return this; + } + + /** + * Reset the synthetic bean archive (bean classes and enablement), explicitly + * added extensions and services. + * + * @return self + */ + public Weld reset() { + beanClasses.clear(); + packages.clear(); + selectedAlternatives.clear(); + selectedAlternativeStereotypes.clear(); + enabledInterceptors.clear(); + enabledDecorators.clear(); + extensions.clear(); + containerLifecycleObservers.clear(); + additionalServices.clear(); + return this; + } + + /** + * Reset all the state, except for initialized containers. + * + * @return self + * @see Weld#reset() + */ + public Weld resetAll() { + reset(); + properties.clear(); + enableDiscovery(); + containerId(null); + return this; + } + + /** + * + * @return self + * @see #disableDiscovery() + */ + public Weld enableDiscovery() { + this.discoveryEnabled = true; + return this; + } + + /** + * By default, the discovery is enabled. However, it's possible to disable the + * discovery completely so that only the "synthetic" bean archive is + * considered. + * + * @return self + */ + public Weld disableDiscovery() { + this.discoveryEnabled = false; + return this; + } + + /** + * + * @return true if the discovery is enabled, false + * otherwise + * @see #disableDiscovery() + */ + public boolean isDiscoveryEnabled() { return discoveryEnabled; } + + /** + * Bootstraps a new Weld SE container with the current container id (generated + * value if not set through {@link #containerId(String)}).

The container + * must be shut down properly when an application is stopped. Applications are + * encouraged to use the try-with-resources statement or invoke + * {@link WeldContainer#shutdown()} explicitly. + *

+ * However, a shutdown hook is also registered during initialization so that + * all running containers are shut down automatically when a program exits or + * VM is terminated. This means that it's not necessary to implement the + * shutdown logic in a class where a main method is used to start the + * container. + * + * @return the Weld container + * @see #enableDiscovery() + * @see WeldContainer#shutdown() + */ + public WeldContainer initialize() { + + // If also building a synthetic bean archive or the implicit scan is + // enabled, the check for beans.xml is not necessary + if (!isSyntheticBeanArchiveRequired() && !isImplicitScanEnabled() && + resourceLoader.getResource(WeldDeployment.BEANS_XML) == null) { + throw CommonLogger.LOG.missingBeansXml(); + } + + final WeldBootstrap bootstrap = new WeldBootstrap(); + // load possible additional BDA + parseAdditionalBeanDefiningAnnotations(); + final Deployment deployment = createDeployment(resourceLoader, bootstrap); + + final ExternalConfigurationBuilder configurationBuilder = + new ExternalConfigurationBuilder() + // weld-se uses CommonForkJoinPoolExecutorServices by default + .add(EXECUTOR_THREAD_POOL_TYPE.get(), COMMON.toString()) + // weld-se uses relaxed construction by default + .add(ConfigurationKey.RELAXED_CONSTRUCTION.get(), true) + // allow optimized cleanup by default + .add(ConfigurationKey.ALLOW_OPTIMIZED_CLEANUP.get(), + isEnabled(ALLOW_OPTIMIZED_CLEANUP, true)); + for (Entry property : properties.entrySet()) { + String key = property.getKey(); + if (SHUTDOWN_HOOK_SYSTEM_PROPERTY.equals(key) || + ARCHIVE_ISOLATION_SYSTEM_PROPERTY.equals(key) || + DEV_MODE_SYSTEM_PROPERTY.equals(key) || + SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY.equals(key) || + JAVAX_ENTERPRISE_INJECT_SCAN_IMPLICIT.equals(key) || + ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY.equals(key)) { + continue; + } + configurationBuilder.add(key, property.getValue()); + } + deployment.getServices().add(ExternalConfiguration.class, + configurationBuilder.build()); + + final String containerId = this.containerId != null + ? this.containerId + : UUID.randomUUID().toString(); + bootstrap.startContainer(containerId, Environments.SE, deployment); + + final WeldContainer weldContainer = + WeldContainer.startInitialization(containerId, deployment, bootstrap); + + try { + bootstrap.startInitialization(); + bootstrap.deployBeans(); + bootstrap.validateBeans(); + bootstrap.endInitialization(); + WeldContainer.endInitialization( + weldContainer, isEnabled(SHUTDOWN_HOOK_SYSTEM_PROPERTY, true)); + initializedContainers.put(containerId, weldContainer); + } catch (Throwable e) { + // Discard the container if a bootstrap problem occurs, e.g. validation + // error + WeldContainer.discard(weldContainer.getId()); + throw e; + } + return weldContainer; + } + + /** + * Shuts down all the containers initialized by this builder. + */ + public void shutdown() { + if (!initializedContainers.isEmpty()) { + for (WeldContainer container : initializedContainers.values()) { + container.shutdown(); + } + } + } + + /** + * Set a {@link ClassLoader}. The given {@link ClassLoader} will be scanned + * automatically for bean archives if scanning is enabled. + * + * @param classLoader + * @return self + */ + public Weld setClassLoader(ClassLoader classLoader) { + Preconditions.checkNotNull(classLoader); + resourceLoader = new ClassLoaderResourceLoader(classLoader); + return this; + } + + /** + * Set a {@link ResourceLoader} used to scan the application for bean + * archives. If you only want to use a specific {@link ClassLoader} for + * scanning, use + * {@link #setClassLoader(ClassLoader)} instead. + * + * @param resourceLoader + * @return self + * @see #isDiscoveryEnabled() + */ + public Weld setResourceLoader(ResourceLoader resourceLoader) { + Preconditions.checkNotNull(resourceLoader); + this.resourceLoader = resourceLoader; + return this; + } + + /** + * Disable bean archive isolation, i.e. use a "flat" deployment structure. + * + * @return self + * @see #ARCHIVE_ISOLATION_SYSTEM_PROPERTY + */ + public Weld disableIsolation() { + return property(ARCHIVE_ISOLATION_SYSTEM_PROPERTY, false); + } + + /** + * Skip shutdown hook registration. + * + * @return self + * @see #SHUTDOWN_HOOK_SYSTEM_PROPERTY + */ + public Weld skipShutdownHook() { + return property(SHUTDOWN_HOOK_SYSTEM_PROPERTY, false); + } + + /** + * Scans the class path entries - implicit bean archives which don't contain a + * beans.xml file are supported. + * + * @return self + * @see #SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY + */ + public Weld scanClasspathEntries() { + return property(SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY, true); + } + + /** + * Enable the development mode. + * + * @return self + * @see #DEV_MODE_SYSTEM_PROPERTY + */ + public Weld enableDevMode() { + return property(DEV_MODE_SYSTEM_PROPERTY, true); + } + + /** + * Registers annotations which will be considered as bean defining + * annotations. + * + * NOTE - If used along with {@code } bean archives and/or with Weld + * configuration key + * {@code org.jboss.weld.bootstrap.vetoTypesWithoutBeanDefiningAnnotation}, + * these annotations will be ignored. + * + * @param annotations annotations which will be considered as Bean Defining + * Annotations. + * @return self + */ + public Weld + addBeanDefiningAnnotations(Class... annotations) { + for (Class annotation : annotations) { + this.extendedBeanDefiningAnnotations.add(annotation); + } + return this; + } + + /** + *

+ * Extensions to Weld SE can subclass and override this method to customize + * the deployment before weld boots up. For example, to add a custom + * ResourceLoader, you would subclass Weld like so: + *

+ * + *
+   * public class MyWeld extends Weld {
+   *     protected Deployment createDeployment(ResourceLoader resourceLoader,
+   * CDI11Bootstrap bootstrap) { return super.createDeployment(new
+   * MyResourceLoader(), bootstrap);
+   *     }
+   * }
+   * 
+ * + *

+ * This could then be used as normal: + *

+ * + *
+   * WeldContainer container = new MyWeld().initialize();
+   * 
+ * + * @param resourceLoader + * @param bootstrap + */ + protected Deployment createDeployment(ResourceLoader resourceLoader, + CDI11Bootstrap bootstrap) { + + final Iterable> extensions = getExtensions(); + final TypeDiscoveryConfiguration typeDiscoveryConfiguration = + bootstrap.startExtensions(extensions); + final Deployment deployment; + final Set beanDeploymentArchives = + new HashSet(); + final Map, Service> additionalServices = + new HashMap<>(this.additionalServices); + final Set> beanDefiningAnnotations = + ImmutableSet.>builder() + .addAll( + typeDiscoveryConfiguration.getKnownBeanDefiningAnnotations()) + // Add ThreadScoped manually as Weld SE doesn't support implicit + // bean archives without beans.xml .add(ThreadScoped.class) - // Add all custom bean defining annotations user registered via Weld.addBeanDefiningAnnotations() + // Add all custom bean defining annotations user registered via + // Weld.addBeanDefiningAnnotations() .addAll(extendedBeanDefiningAnnotations) .build(); - if (discoveryEnabled) { - DiscoveryStrategy strategy = DiscoveryStrategyFactory.create(resourceLoader, bootstrap, - beanDefiningAnnotations, isEnabled(Jandex.DISABLE_JANDEX_DISCOVERY_STRATEGY, false)); - if (isImplicitScanEnabled()) { - strategy.setScanner(new ClassPathBeanArchiveScanner(bootstrap)); - } - beanDeploymentArchives.addAll(strategy.performDiscovery()); - ClassFileServices classFileServices = strategy.getClassFileServices(); - if (classFileServices != null) { - additionalServices.put(ClassFileServices.class, classFileServices); - } + if (discoveryEnabled) { + DiscoveryStrategy strategy = DiscoveryStrategyFactory.create( + resourceLoader, bootstrap, beanDefiningAnnotations, + isEnabled(Jandex.DISABLE_JANDEX_DISCOVERY_STRATEGY, false)); + if (isImplicitScanEnabled()) { + strategy.setScanner(new ClassPathBeanArchiveScanner(bootstrap)); + } + beanDeploymentArchives.addAll(strategy.performDiscovery()); + ClassFileServices classFileServices = strategy.getClassFileServices(); + if (classFileServices != null) { + additionalServices.put(ClassFileServices.class, classFileServices); + } + } + + if (isSyntheticBeanArchiveRequired()) { + ImmutableSet.Builder beanClassesBuilder = ImmutableSet.builder(); + beanClassesBuilder.addAll(scanPackages()); + Set setOfAllBeanClasses = beanClassesBuilder.build(); + // the creation process differs based on bean discovery mode + if (BeanDiscoveryMode.ANNOTATED.equals(beanDiscoveryMode)) { + // Annotated bean discovery mode, filter classes + ImmutableSet.Builder filteredSetbuilder = + ImmutableSet.builder(); + for (String className : setOfAllBeanClasses) { + Class clazz = Reflections.loadClass(resourceLoader, className); + if (clazz != null && Reflections.hasBeanDefiningAnnotation( + clazz, beanDefiningAnnotations)) { + filteredSetbuilder.add(className); + } } + setOfAllBeanClasses = filteredSetbuilder.build(); + } + WeldBeanDeploymentArchive syntheticBeanArchive = + new WeldBeanDeploymentArchive( + WeldDeployment.SYNTHETIC_BDA_ID, setOfAllBeanClasses, null, + buildSyntheticBeansXml(), Collections.emptySet(), + ImmutableSet.copyOf(beanClasses)); + beanDeploymentArchives.add(syntheticBeanArchive); + } + + if (beanDeploymentArchives.isEmpty() && + this.containerLifecycleObservers.isEmpty() && + this.extensions.isEmpty()) { + throw WeldSELogger.LOG + .weldContainerCannotBeInitializedNoBeanArchivesFound(); + } + + Multimap problems = + BeanArchives.findBeanClassesDeployedInMultipleBeanArchives( + beanDeploymentArchives); + if (!problems.isEmpty()) { + // Right now, we only log a warning for each bean class deployed in + // multiple bean archives + for (Entry> entry : + problems.entrySet()) { + WeldSELogger.LOG.beanClassDeployedInMultipleBeanArchives( + entry.getKey(), WeldCollections.toMultiRowString(entry.getValue())); + } + } + + if (isEnabled(ARCHIVE_ISOLATION_SYSTEM_PROPERTY, true)) { + deployment = new WeldDeployment(resourceLoader, bootstrap, + beanDeploymentArchives, extensions); + CommonLogger.LOG.archiveIsolationEnabled(); + } else { + Set flatDeployment = + new HashSet(); + flatDeployment.add( + WeldBeanDeploymentArchive.merge(bootstrap, beanDeploymentArchives)); + deployment = new WeldDeployment(resourceLoader, bootstrap, flatDeployment, + extensions); + CommonLogger.LOG.archiveIsolationDisabled(); + } + + // Register additional services if a service with higher priority not + // present + for (Entry, Service> entry : + additionalServices.entrySet()) { + Services.put(deployment.getServices(), entry.getKey(), entry.getValue()); + } + return deployment; + } + + /** + * Utility method allowing managed instances of beans to provide entry points + * for non-managed beans (such as {@link WeldContainer}). Should only called + * once Weld has finished booting. + * + * @param manager the BeanManager to use to access the managed instance + * @param type the type of the Bean + * @param bindings the bean's qualifiers + * @return a managed instance of the bean + * @throws IllegalArgumentException if the given type represents a type + * variable + * @throws IllegalArgumentException if two instances of the same qualifier + * type are given + * @throws IllegalArgumentException if an instance of an annotation that is + * not a qualifier type is given + * @throws UnsatisfiedResolutionException if no beans can be resolved * + * @throws AmbiguousResolutionException if the ambiguous dependency + * resolution rules + * fail + * @throws IllegalArgumentException if the given type is not a bean type of + * the given bean + */ + protected T getInstanceByType(BeanManager manager, Class type, + Annotation... bindings) { + final Bean bean = manager.resolve(manager.getBeans(type, bindings)); + if (bean == null) { + throw CommonLogger.LOG.unableToResolveBean(type, Arrays.asList(bindings)); + } + CreationalContext cc = manager.createCreationalContext(bean); + return type.cast(manager.getReference(bean, type, cc)); + } + + protected boolean isImplicitScanEnabled() { + return isEnabled(SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY, false) || + isEnabled(JAVAX_ENTERPRISE_INJECT_SCAN_IMPLICIT, false); + } + + protected boolean isSyntheticBeanArchiveRequired() { + return !beanClasses.isEmpty() || !packages.isEmpty(); + } + + protected Iterable> getExtensions() { + Set> result = new HashSet>(); + if (discoveryEnabled) { + Iterables.addAll(result, loadExtensions(resourceLoader)); + } + if (!extensions.isEmpty()) { + result.addAll(extensions); + } + // Ensure that WeldSEBeanRegistrant is present + WeldSEBeanRegistrant weldSEBeanRegistrant = null; + for (Metadata metadata : result) { + if (metadata.getValue().getClass().getName().equals( + WeldSEBeanRegistrant.class.getName())) { + weldSEBeanRegistrant = (WeldSEBeanRegistrant)metadata.getValue(); + break; + } + } + if (weldSEBeanRegistrant == null) { + try { + weldSEBeanRegistrant = + SecurityActions.newInstance(WeldSEBeanRegistrant.class); + result.add(new MetadataImpl( + weldSEBeanRegistrant, + SYNTHETIC_LOCATION_PREFIX + WeldSEBeanRegistrant.class.getName())); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + if (isEnabled(DEV_MODE_SYSTEM_PROPERTY, false)) { + // The development mode is enabled - register the Probe extension + result.add(new MetadataImpl( + DevelopmentMode.getProbeExtension(resourceLoader), "N/A")); + } + if (!containerLifecycleObservers.isEmpty()) { + result.add(new MetadataImpl( + new ContainerLifecycleObserverExtension(containerLifecycleObservers), + SYNTHETIC_LOCATION_PREFIX + + ContainerLifecycleObserver.class.getName())); + } + return result; + } + + private Iterable> + loadExtensions(ResourceLoader resourceLoader) { + return ServiceLoader.load(Extension.class, resourceLoader); + } + + protected BeansXml buildSyntheticBeansXml() { + return new BeansXmlImpl( + ImmutableList.copyOf(selectedAlternatives), + ImmutableList.copyOf(selectedAlternativeStereotypes), + ImmutableList.copyOf(enabledDecorators), + ImmutableList.copyOf(enabledInterceptors), Scanning.EMPTY_SCANNING, + null, beanDiscoveryMode, null, false); + } + + private MetadataImpl syntheticMetadata(Class clazz) { + return new MetadataImpl(clazz.getName(), SYNTHETIC_LOCATION_PREFIX + + clazz.getName()); + } + + protected Set scanPackages() { + + if (packages.isEmpty()) { + return Collections.emptySet(); + } + + Set foundClasses = new HashSet(); + + for (PackInfo packInfo : packages) { + + String packName = packInfo.getPackName(); + URL resourceUrl = packInfo.getResourceUrl(resourceLoader); + + if (resourceUrl != null) { + + WeldSELogger.LOG.scanningPackage(packName, resourceUrl); - if (isSyntheticBeanArchiveRequired()) { - ImmutableSet.Builder beanClassesBuilder = ImmutableSet.builder(); - beanClassesBuilder.addAll(scanPackages()); - Set setOfAllBeanClasses = beanClassesBuilder.build(); - // the creation process differs based on bean discovery mode - if (BeanDiscoveryMode.ANNOTATED.equals(beanDiscoveryMode)) { - // Annotated bean discovery mode, filter classes - ImmutableSet.Builder filteredSetbuilder = ImmutableSet.builder(); - for (String className : setOfAllBeanClasses) { - Class clazz = Reflections.loadClass(resourceLoader, className); - if (clazz != null && Reflections.hasBeanDefiningAnnotation(clazz, beanDefiningAnnotations)) { - filteredSetbuilder.add(className); - } - } - setOfAllBeanClasses = filteredSetbuilder.build(); - } - WeldBeanDeploymentArchive syntheticBeanArchive = new WeldBeanDeploymentArchive(WeldDeployment.SYNTHETIC_BDA_ID, setOfAllBeanClasses, null, - buildSyntheticBeansXml(), Collections.emptySet(), ImmutableSet.copyOf(beanClasses)); - beanDeploymentArchives.add(syntheticBeanArchive); - } - - if (beanDeploymentArchives.isEmpty() && this.containerLifecycleObservers.isEmpty() && this.extensions.isEmpty()) { - throw WeldSELogger.LOG.weldContainerCannotBeInitializedNoBeanArchivesFound(); - } - - Multimap problems = BeanArchives.findBeanClassesDeployedInMultipleBeanArchives(beanDeploymentArchives); - if (!problems.isEmpty()) { - // Right now, we only log a warning for each bean class deployed in multiple bean archives - for (Entry> entry : problems.entrySet()) { - WeldSELogger.LOG.beanClassDeployedInMultipleBeanArchives(entry.getKey(), WeldCollections.toMultiRowString(entry.getValue())); - } - } - - if (isEnabled(ARCHIVE_ISOLATION_SYSTEM_PROPERTY, true)) { - deployment = new WeldDeployment(resourceLoader, bootstrap, beanDeploymentArchives, extensions); - CommonLogger.LOG.archiveIsolationEnabled(); - } else { - Set flatDeployment = new HashSet(); - flatDeployment.add(WeldBeanDeploymentArchive.merge(bootstrap, beanDeploymentArchives)); - deployment = new WeldDeployment(resourceLoader, bootstrap, flatDeployment, extensions); - CommonLogger.LOG.archiveIsolationDisabled(); - } - - // Register additional services if a service with higher priority not present - for (Entry, Service> entry : additionalServices.entrySet()) { - Services.put(deployment.getServices(), entry.getKey(), entry.getValue()); - } - return deployment; - } - - /** - * Utility method allowing managed instances of beans to provide entry points for non-managed beans (such as {@link WeldContainer}). Should only called once - * Weld has finished booting. - * - * @param manager the BeanManager to use to access the managed instance - * @param type the type of the Bean - * @param bindings the bean's qualifiers - * @return a managed instance of the bean - * @throws IllegalArgumentException if the given type represents a type variable - * @throws IllegalArgumentException if two instances of the same qualifier type are given - * @throws IllegalArgumentException if an instance of an annotation that is not a qualifier type is given - * @throws UnsatisfiedResolutionException if no beans can be resolved * @throws AmbiguousResolutionException if the ambiguous dependency resolution rules - * fail - * @throws IllegalArgumentException if the given type is not a bean type of the given bean - */ - protected T getInstanceByType(BeanManager manager, Class type, Annotation... bindings) { - final Bean bean = manager.resolve(manager.getBeans(type, bindings)); - if (bean == null) { - throw CommonLogger.LOG.unableToResolveBean(type, Arrays.asList(bindings)); - } - CreationalContext cc = manager.createCreationalContext(bean); - return type.cast(manager.getReference(bean, type, cc)); - } - - protected boolean isImplicitScanEnabled() { - return isEnabled(SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY, false) || isEnabled(JAVAX_ENTERPRISE_INJECT_SCAN_IMPLICIT, false); - } - - protected boolean isSyntheticBeanArchiveRequired() { - return !beanClasses.isEmpty() || !packages.isEmpty(); - } - - protected Iterable> getExtensions() { - Set> result = new HashSet>(); - if (discoveryEnabled) { - Iterables.addAll(result, loadExtensions(resourceLoader)); + try { + URI resourceUri = resourceUrl.toURI(); + + if (PROCOTOL_FILE.equals(resourceUrl.getProtocol())) { + File file = new File(resourceUri); + handleDir(file.isDirectory() ? file : file.getParentFile(), + packInfo.isScanRecursively(), packName, foundClasses); + } else if (PROCOTOL_JAR.equals(resourceUrl.getProtocol())) { + handleJar(resourceUri, packInfo.isScanRecursively(), packName, + foundClasses); + } else { + WeldSELogger.LOG.resourceUrlProtocolNotSupported(resourceUrl); + } + + } catch (URISyntaxException e) { + CommonLogger.LOG.couldNotReadResource(resourceUrl, e); } - if (!extensions.isEmpty()) { - result.addAll(extensions); + } else { + WeldSELogger.LOG.packageNotFound(packName); + } + } + return foundClasses; + } + + private void handleDir(File packDir, boolean scanRecursively, String packName, + Set foundClasses) { + if (packDir != null && packDir.exists() && packDir.canRead()) { + for (File file : packDir.listFiles()) { + if (file.isFile()) { + if (file.canRead() && Files.isClass(file.getName())) { + foundClasses.add( + Files.filenameToClassname(packName + "." + file.getName())); + } } - // Ensure that WeldSEBeanRegistrant is present - WeldSEBeanRegistrant weldSEBeanRegistrant = null; - for (Metadata metadata : result) { - if (metadata.getValue().getClass().getName().equals(WeldSEBeanRegistrant.class.getName())) { - weldSEBeanRegistrant = (WeldSEBeanRegistrant) metadata.getValue(); - break; - } + if (file.isDirectory() && scanRecursively) { + handleDir(file, scanRecursively, packName + "." + file.getName(), + foundClasses); } - if (weldSEBeanRegistrant == null) { - try { - weldSEBeanRegistrant = SecurityActions.newInstance(WeldSEBeanRegistrant.class); - result.add(new MetadataImpl(weldSEBeanRegistrant, SYNTHETIC_LOCATION_PREFIX + WeldSEBeanRegistrant.class.getName())); - } catch (Exception e) { - throw new RuntimeException(e); + } + } + } + + private void handleJar(URI resourceUri, boolean scanRecursively, + String packName, Set foundClasses) { + + // Currently we only support jar:file + if (resourceUri.getSchemeSpecificPart().startsWith(PROCOTOL_FILE)) { + + // Get the JAR file path, e.g. "jar:file:/home/duke/duke.jar!/com/foo/Bar" + // becomes "/home/duke/duke.jar" + String path = resourceUri.getSchemeSpecificPart().substring( + PROTOCOL_FILE_PART.length()); + if (path.lastIndexOf(JAR_URL_SEPARATOR) > 0) { + path = path.substring(0, path.lastIndexOf(JAR_URL_SEPARATOR)); + } + + JarFile jar = null; + String packNamePath = packName.replace('.', '/'); + int expectedPartsLength = splitBySlash(packNamePath).length + 1; + + try { + jar = new JarFile(new File(path)); + Enumeration entries = jar.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + if (!entry.getName().endsWith(Files.CLASS_FILE_EXTENSION)) { + continue; + } + if (entry.getName().startsWith(packNamePath + '/')) { + if (scanRecursively) { + foundClasses.add(Files.filenameToClassname(entry.getName())); + } else { + String[] parts = splitBySlash(entry.getName()); + if (parts.length == expectedPartsLength) { + foundClasses.add(Files.filenameToClassname(entry.getName())); + } } + } } - if (isEnabled(DEV_MODE_SYSTEM_PROPERTY, false)) { - // The development mode is enabled - register the Probe extension - result.add(new MetadataImpl(DevelopmentMode.getProbeExtension(resourceLoader), "N/A")); - } - if (!containerLifecycleObservers.isEmpty()) { - result.add(new MetadataImpl(new ContainerLifecycleObserverExtension(containerLifecycleObservers), - SYNTHETIC_LOCATION_PREFIX + ContainerLifecycleObserver.class.getName())); + } catch (IOException e) { + CommonLogger.LOG.couldNotReadResource(resourceUri, e); + } finally { + if (jar != null) { + try { + jar.close(); + } catch (IOException ignored) { + } } - return result; - } - - private Iterable> loadExtensions(ResourceLoader resourceLoader) { - return ServiceLoader.load(Extension.class, resourceLoader); - } - - protected BeansXml buildSyntheticBeansXml() { - return new BeansXmlImpl(ImmutableList.copyOf(selectedAlternatives), ImmutableList.copyOf(selectedAlternativeStereotypes), - ImmutableList.copyOf(enabledDecorators), ImmutableList.copyOf(enabledInterceptors), Scanning.EMPTY_SCANNING, null, beanDiscoveryMode, null, false); - } - - private MetadataImpl syntheticMetadata(Class clazz) { - return new MetadataImpl(clazz.getName(), SYNTHETIC_LOCATION_PREFIX + clazz.getName()); - } - - protected Set scanPackages() { - - if (packages.isEmpty()) { - return Collections.emptySet(); + } + } + } + + private String[] splitBySlash(String value) { return value.split("/"); } + + protected boolean isEnabled(String key, boolean defaultValue) { + Object value = properties.get(key); + if (value != null) { + return Boolean.TRUE.equals(value); + } + String system = + AccessController.doPrivileged(new GetSystemPropertyAction(key)); + if (system != null) { + return Boolean.valueOf(system); + } + return defaultValue; + } + + protected Object getPropertyValue(String key, Object defaultValue) { + Object value = properties.get(key); + if (value != null) { + return value; + } + return defaultValue; + } + + /** + * Parses additional bean defining annotations from either system properties, + * or SE container properties. + */ + private void parseAdditionalBeanDefiningAnnotations() { + // parse additional bean defining annotations from SE container properties + if (properties.containsKey(ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY)) { + Object valueObj = + properties.get(ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY); + if (valueObj instanceof Collection) { + for (Object element : ((Collection)valueObj)) { + if (element instanceof Class && + Annotation.class.isAssignableFrom((Class)element)) { + extendedBeanDefiningAnnotations.add( + (Class)element); + } else { + // one of the values is not an annotation, log warning + WeldSELogger.LOG.unexpectedItemsInValueCollection( + element.getClass()); + } } - - Set foundClasses = new HashSet(); - - for (PackInfo packInfo : packages) { - - String packName = packInfo.getPackName(); - URL resourceUrl = packInfo.getResourceUrl(resourceLoader); - - if (resourceUrl != null) { - - WeldSELogger.LOG.scanningPackage(packName, resourceUrl); - - try { - URI resourceUri = resourceUrl.toURI(); - - if (PROCOTOL_FILE.equals(resourceUrl.getProtocol())) { - File file = new File(resourceUri); - handleDir(file.isDirectory() ? file : file.getParentFile(), packInfo.isScanRecursively(), packName, foundClasses); - } else if (PROCOTOL_JAR.equals(resourceUrl.getProtocol())) { - handleJar(resourceUri, packInfo.isScanRecursively(), packName, foundClasses); - } else { - WeldSELogger.LOG.resourceUrlProtocolNotSupported(resourceUrl); - } - - } catch (URISyntaxException e) { - CommonLogger.LOG.couldNotReadResource(resourceUrl, e); - } + } else { + // value is not a collection, throw IAE + throw WeldSELogger.LOG + .unexpectedValueForAdditionalBeanDefiningAnnotations( + valueObj.getClass()); + } + } + + // parse from system properties + String stringValue = + AccessController.doPrivileged(new GetSystemPropertyAction( + ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY)); + if (stringValue != null) { + for (String className : stringValue.split(",")) { + if (!className.isEmpty()) { + try { + Class loadedClass = Class.forName(className); + if (loadedClass.isAnnotation()) { + extendedBeanDefiningAnnotations.add( + (Class)loadedClass); } else { - WeldSELogger.LOG.packageNotFound(packName); + // one of the values is not an annotation, log warning + WeldSELogger.LOG.unexpectedItemsInValueCollection(loadedClass); } + } catch (LinkageError | ClassNotFoundException e) { + throw WeldSELogger.LOG.failedToLoadClass(className, e.toString()); + } } - return foundClasses; + } } + } - private void handleDir(File packDir, boolean scanRecursively, String packName, Set foundClasses) { - if (packDir != null && packDir.exists() && packDir.canRead()) { - for (File file : packDir.listFiles()) { - if (file.isFile()) { - if (file.canRead() && Files.isClass(file.getName())) { - foundClasses.add(Files.filenameToClassname(packName + "." + file.getName())); - } - } - if (file.isDirectory() && scanRecursively) { - handleDir(file, scanRecursively, packName + "." + file.getName(), foundClasses); - } - } - } - } + private static class PackInfo { - private void handleJar(URI resourceUri, boolean scanRecursively, String packName, Set foundClasses) { + private final String packName; - // Currently we only support jar:file - if (resourceUri.getSchemeSpecificPart().startsWith(PROCOTOL_FILE)) { + private final String packClassName; - // Get the JAR file path, e.g. "jar:file:/home/duke/duke.jar!/com/foo/Bar" becomes "/home/duke/duke.jar" - String path = resourceUri.getSchemeSpecificPart().substring(PROTOCOL_FILE_PART.length()); - if (path.lastIndexOf(JAR_URL_SEPARATOR) > 0) { - path = path.substring(0, path.lastIndexOf(JAR_URL_SEPARATOR)); - } + private final boolean scanRecursively; - JarFile jar = null; - String packNamePath = packName.replace('.', '/'); - int expectedPartsLength = splitBySlash(packNamePath).length + 1; - - try { - jar = new JarFile(new File(path)); - Enumeration entries = jar.entries(); - while (entries.hasMoreElements()) { - JarEntry entry = entries.nextElement(); - if (!entry.getName().endsWith(Files.CLASS_FILE_EXTENSION)) { - continue; - } - if (entry.getName().startsWith(packNamePath + '/')) { - if (scanRecursively) { - foundClasses.add(Files.filenameToClassname(entry.getName())); - } else { - String[] parts = splitBySlash(entry.getName()); - if (parts.length == expectedPartsLength) { - foundClasses.add(Files.filenameToClassname(entry.getName())); - } - } - } - } - } catch (IOException e) { - CommonLogger.LOG.couldNotReadResource(resourceUri, e); - } finally { - if (jar != null) { - try { - jar.close(); - } catch (IOException ignored) { - } - } - } - } - } + private final WeakReference classLoaderRef; - private String[] splitBySlash(String value) { - return value.split("/"); + PackInfo(Class packClass, boolean recursiveScan) { + this.packName = packClass.getPackage().getName(); + this.packClassName = packClass.getName(); + this.scanRecursively = recursiveScan; + this.classLoaderRef = new WeakReference( + AccessController.doPrivileged(new GetClassLoaderAction(packClass))); } - protected boolean isEnabled(String key, boolean defaultValue) { - Object value = properties.get(key); - if (value != null) { - return Boolean.TRUE.equals(value); - } - String system = AccessController.doPrivileged(new GetSystemPropertyAction(key)); - if (system != null) { - return Boolean.valueOf(system); - } - return defaultValue; + PackInfo(Package pack, boolean recursiveScan) { + this.packName = pack.getName(); + this.scanRecursively = recursiveScan; + this.packClassName = null; + this.classLoaderRef = null; } - protected Object getPropertyValue(String key, Object defaultValue) { - Object value = properties.get(key); - if (value != null) { - return value; - } - return defaultValue; + public URL getResourceUrl(ResourceLoader resourceLoader) { + if (classLoaderRef != null) { + return classLoaderRef.get().getResource( + this.getPackClassName().replace('.', '/') + + Files.CLASS_FILE_EXTENSION); + } else { + return resourceLoader.getResource(getPackName().replace('.', '/')); + } } - private static class PackInfo { - - private final String packName; + public String getPackName() { return packName; } - private final String packClassName; - - private final boolean scanRecursively; - - private final WeakReference classLoaderRef; - - PackInfo(Class packClass, boolean recursiveScan) { - this.packName = packClass.getPackage().getName(); - this.packClassName = packClass.getName(); - this.scanRecursively = recursiveScan; - this.classLoaderRef = new WeakReference(AccessController.doPrivileged(new GetClassLoaderAction(packClass))); - } + public String getPackClassName() { return packClassName; } - PackInfo(Package pack, boolean recursiveScan) { - this.packName = pack.getName(); - this.scanRecursively = recursiveScan; - this.packClassName = null; - this.classLoaderRef = null; - } - - public URL getResourceUrl(ResourceLoader resourceLoader) { - if (classLoaderRef != null) { - return classLoaderRef.get().getResource(this.getPackClassName().replace('.', '/') + Files.CLASS_FILE_EXTENSION); - } else { - return resourceLoader.getResource(getPackName().replace('.', '/')); - } - } - - public String getPackName() { - return packName; - } + public boolean isScanRecursively() { return scanRecursively; } - public String getPackClassName() { - return packClassName; - } - - public boolean isScanRecursively() { - return scanRecursively; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((packClassName == null) ? 0 : packClassName.hashCode()); - return result; - } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((packClassName == null) ? 0 : packClassName.hashCode()); + return result; + } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - PackInfo other = (PackInfo) obj; - if (packName == null) { - if (other.packName != null) { - return false; - } - } else if (!packName.equals(other.packName)) { - return false; - } - return true; + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + PackInfo other = (PackInfo)obj; + if (packName == null) { + if (other.packName != null) { + return false; } - + } else if (!packName.equals(other.packName)) { + return false; + } + return true; } - + } } diff --git a/environments/se/core/src/main/java/org/jboss/weld/environment/se/logging/WeldSELogger.java b/environments/se/core/src/main/java/org/jboss/weld/environment/se/logging/WeldSELogger.java index abc526e247..802aedd22c 100644 --- a/environments/se/core/src/main/java/org/jboss/weld/environment/se/logging/WeldSELogger.java +++ b/environments/se/core/src/main/java/org/jboss/weld/environment/se/logging/WeldSELogger.java @@ -11,8 +11,9 @@ import org.jboss.weld.exceptions.IllegalArgumentException; /** - * A source of localized log/bundle messages and exceptions. Note that this interface extends {@link WeldEnvironmentLogger} so that regular logger methods are - * available. + * A source of localized log/bundle messages and exceptions. Note that this + * interface extends {@link WeldEnvironmentLogger} so that regular logger + * methods are available. * * Message IDs: 002000 - 002099 * @@ -23,62 +24,145 @@ @MessageLogger(projectCode = WeldEnvironmentLogger.WELD_ENV_PROJECT_CODE) public interface WeldSELogger extends WeldEnvironmentLogger { - WeldSELogger LOG = Logger.getMessageLogger(WeldSELogger.class, Category.BOOTSTRAP.getName()); - - @Message(id = 2000, value = "Weld SE container {0} is already running!", format = Format.MESSAGE_FORMAT) - IllegalStateException weldContainerAlreadyRunning(Object id); - - @LogMessage(level = Level.INFO) - @Message(id = 2001, value = "Weld SE container {0} shut down", format = Format.MESSAGE_FORMAT) - void weldContainerShutdown(Object id); - - @Message(id = 2002, value = "Weld SE container {0} was already shut down", format = Format.MESSAGE_FORMAT) - IllegalStateException weldContainerAlreadyShutDown(Object id); - - @LogMessage(level = Level.INFO) - @Message(id = 2003, value = "Weld SE container {0} initialized", format = Format.MESSAGE_FORMAT) - void weldContainerInitialized(Object id); - - @LogMessage(level = Level.DEBUG) - @Message(id = 2004, value = "Scanning package {0}, class resource: {1}", format = Format.MESSAGE_FORMAT) - void scanningPackage(Object packageName, Object resource); - - @LogMessage(level = Level.WARN) - @Message(id = 2005, value = "Package intended for scanning was not found: {0}", format = Format.MESSAGE_FORMAT) - void packageNotFound(Object packageName); - - @LogMessage(level = Level.INFO) - @Message(id = 2006, value = "Multiple containers running - CDI.current() may not work properly: {0}", format = Format.MESSAGE_FORMAT) - void multipleContainersRunning(Object ids); - - @LogMessage(level = Level.DEBUG) - @Message(id = 2007, value = "Resource URL procotol not supported: {0}", format = Format.MESSAGE_FORMAT) - void resourceUrlProtocolNotSupported(Object resource); - - @LogMessage(level = Level.WARN) - @Message(id = 2008, value = "Bean class {0} found in multiple bean archives - this may result in incorrect behavior: {1}", format = Format.MESSAGE_FORMAT) - void beanClassDeployedInMultipleBeanArchives(Object beanClass, Object bdas); - - @Message(id = 2009, value = "Weld SE container cannot be initialized - no bean archives found") - IllegalStateException weldContainerCannotBeInitializedNoBeanArchivesFound(); - - @Message(id = 2010, value = "The observed type {0} is not a container lifecycle event type", format = Format.MESSAGE_FORMAT) - IllegalArgumentException observedTypeNotContonainerLifecycleEventType(Object type); - - @Message(id = 2011, value = "The observed type {0} does not match the container lifecycle event type {1}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException observedTypeDoesNotMatchContonainerLifecycleEventType(Object type, Object eventType); - - @Message(id = 2012, value = "The container lifecycle observer is not properly initialized: {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException containerLifecycleObserverNotInitialized(Object info); - - // 2013 used in Weld 2.3 - - @Message(id = 2014, value = "Weld SE container with id {0} has not yet validated the deployment - methods for programmatic lookup cannot be used", format = Format.MESSAGE_FORMAT) - IllegalStateException weldContainerDeploymentNotValidated(Object id); - - @Message(id = 2015, value = "Bean discovery mode NONE is not a valid option for Weld SE deployment archive - Weld SE container with id {0}.", format = Format.MESSAGE_FORMAT) - IllegalArgumentException beanArchiveWithModeNone(Object id); - - @Message(id = 2016, value = "Zero or more than one container is running - WeldContainer.current() cannot determine the current container.", format = Format.MESSAGE_FORMAT) - IllegalStateException zeroOrMoreThanOneContainerRunning(); + WeldSELogger LOG = + Logger.getMessageLogger(WeldSELogger.class, Category.BOOTSTRAP.getName()); + + @Message(id = 2000, value = "Weld SE container {0} is already running!", + format = Format.MESSAGE_FORMAT) + IllegalStateException + weldContainerAlreadyRunning(Object id); + + @LogMessage(level = Level.INFO) + @Message(id = 2001, value = "Weld SE container {0} shut down", + format = Format.MESSAGE_FORMAT) + void + weldContainerShutdown(Object id); + + @Message(id = 2002, value = "Weld SE container {0} was already shut down", + format = Format.MESSAGE_FORMAT) + IllegalStateException + weldContainerAlreadyShutDown(Object id); + + @LogMessage(level = Level.INFO) + @Message(id = 2003, value = "Weld SE container {0} initialized", + format = Format.MESSAGE_FORMAT) + void + weldContainerInitialized(Object id); + + @LogMessage(level = Level.DEBUG) + @Message(id = 2004, value = "Scanning package {0}, class resource: {1}", + format = Format.MESSAGE_FORMAT) + void + scanningPackage(Object packageName, Object resource); + + @LogMessage(level = Level.WARN) + @Message(id = 2005, + value = "Package intended for scanning was not found: {0}", + format = Format.MESSAGE_FORMAT) + void + packageNotFound(Object packageName); + + @LogMessage(level = Level.INFO) + @Message(id = 2006, + value = "Multiple containers running - CDI.current() may not work " + + "properly: {0}", + format = Format.MESSAGE_FORMAT) + void + multipleContainersRunning(Object ids); + + @LogMessage(level = Level.DEBUG) + @Message(id = 2007, value = "Resource URL procotol not supported: {0}", + format = Format.MESSAGE_FORMAT) + void + resourceUrlProtocolNotSupported(Object resource); + + @LogMessage(level = Level.WARN) + @Message(id = 2008, + value = "Bean class {0} found in multiple bean archives - this " + + "may result in incorrect behavior: {1}", + format = Format.MESSAGE_FORMAT) + void + beanClassDeployedInMultipleBeanArchives(Object beanClass, Object bdas); + + @Message( + id = 2009, + value = + "Weld SE container cannot be initialized - no bean archives found") + IllegalStateException + weldContainerCannotBeInitializedNoBeanArchivesFound(); + + @Message( + id = 2010, + value = "The observed type {0} is not a container lifecycle event type", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + observedTypeNotContonainerLifecycleEventType(Object type); + + @Message(id = 2011, + value = "The observed type {0} does not match the container " + + "lifecycle event type {1}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + observedTypeDoesNotMatchContonainerLifecycleEventType(Object type, + Object eventType); + + @Message( + id = 2012, + value = + "The container lifecycle observer is not properly initialized: {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + containerLifecycleObserverNotInitialized(Object info); + + // 2013 used in Weld 2.3 + + @Message( + id = 2014, + value = "Weld SE container with id {0} has not yet validated the " + + "deployment - methods for programmatic lookup cannot be used", + format = Format.MESSAGE_FORMAT) + IllegalStateException + weldContainerDeploymentNotValidated(Object id); + + @Message(id = 2015, + value = "Bean discovery mode NONE is not a valid option for Weld " + + "SE deployment archive - Weld SE container with id {0}.", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + beanArchiveWithModeNone(Object id); + + @Message( + id = 2016, + value = "Zero or more than one container is running - " + + + "WeldContainer.current() cannot determine the current container.", + format = Format.MESSAGE_FORMAT) + IllegalStateException + zeroOrMoreThanOneContainerRunning(); + + @Message(id = 2017, + value = "Unexpected value for parameter " + + "'org.jboss.weld.se.additionalBeanDefiningAnnotations'. " + + "Expected java.util.Collection but found {0}. ", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + unexpectedValueForAdditionalBeanDefiningAnnotations(Class clazz); + + @LogMessage(level = Level.WARN) + @Message( + id = 2018, + value = "Skipping registration of additional bean defining annotation " + + "via `org.jboss.weld.se.additionalBeanDefiningAnnotations`. " + + "Only values of type Class are valid. " + + "Found: {0}", + format = Format.MESSAGE_FORMAT) + void + unexpectedItemsInValueCollection(Class clazz); + + @Message(id = 2019, + value = "Failed to parse the following string as additional bean " + + "defining annotation: {0}. The exception was: {1}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + failedToLoadClass(String className, String exception); } diff --git a/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/bootstrap/BootstrapFailsWithWrongProxyServicesTest.java b/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/bootstrap/BootstrapFailsWithWrongProxyServicesTest.java new file mode 100644 index 0000000000..4e71b5b4b9 --- /dev/null +++ b/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/bootstrap/BootstrapFailsWithWrongProxyServicesTest.java @@ -0,0 +1,47 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.environment.se.test.bootstrap; + +import org.jboss.weld.environment.se.Weld; +import org.jboss.weld.environment.se.WeldContainer; +import org.jboss.weld.exceptions.IllegalStateException; +import org.junit.Assert; +import org.junit.Test; + +/** + * Tests that Weld container fails to bootstrap if provided with insufficient + * implementation of ProxyServices + * + * @author Matej Novotny + */ +public class BootstrapFailsWithWrongProxyServicesTest { + + @Test + public void testBootstrapFails() { + Weld weld = new Weld() + .disableDiscovery() + .addBeanClass(DummyBean.class) + .addServices(new InvalidProxyServices()); + try (WeldContainer container = weld.initialize()) { + // ISE should have been thrown earlier + Assert.fail(); + } catch (IllegalStateException ise) { + // expected + } + } +} diff --git a/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/bootstrap/DummyBean.java b/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/bootstrap/DummyBean.java new file mode 100644 index 0000000000..b21eaaafb3 --- /dev/null +++ b/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/bootstrap/DummyBean.java @@ -0,0 +1,23 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.environment.se.test.bootstrap; + +import javax.enterprise.context.Dependent; + +@Dependent +public class DummyBean {} diff --git a/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/bootstrap/InvalidProxyServices.java b/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/bootstrap/InvalidProxyServices.java new file mode 100644 index 0000000000..94f22a0f1c --- /dev/null +++ b/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/bootstrap/InvalidProxyServices.java @@ -0,0 +1,66 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.environment.se.test.bootstrap; + +import java.security.ProtectionDomain; +import org.jboss.weld.serialization.spi.ProxyServices; + +/** + * Contents of this class don't really matter - imports part is that + * supportsClassDefining returns false + */ +public class InvalidProxyServices implements ProxyServices { + @Override + public ClassLoader getClassLoader(Class proxiedBeanType) { + return null; + } + + @Override + public Class loadBeanClass(String className) { + return null; + } + + @Override + public Class defineClass(Class originalClass, String className, + byte[] classBytes, int off, int len) + throws ClassFormatError { + return null; + } + + @Override + public Class defineClass(Class originalClass, String className, + byte[] classBytes, int off, int len, + ProtectionDomain protectionDomain) + throws ClassFormatError { + return null; + } + + @Override + public Class loadClass(Class originalClass, String classBinaryName) + throws ClassNotFoundException { + return null; + } + + @Override + public boolean supportsClassDefining() { + return false; + } + + @Override + public void cleanup() {} +} diff --git a/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/merging/BeansXmlMergingTest.java b/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/merging/BeansXmlMergingTest.java deleted file mode 100644 index 9bb7f78ac6..0000000000 --- a/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/merging/BeansXmlMergingTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * JBoss, Home of Professional Open Source - * Copyright 2019, Red Hat, Inc., and individual contributors - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * Licensed 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.jboss.weld.environment.se.test.merging; - -import org.jboss.arquillian.container.test.api.Deployer; -import org.jboss.arquillian.container.test.api.Deployment; -import org.jboss.arquillian.junit.Arquillian; -import org.jboss.arquillian.test.api.ArquillianResource; -import org.jboss.shrinkwrap.api.Archive; -import org.jboss.shrinkwrap.api.BeanArchive; -import org.jboss.shrinkwrap.api.BeanDiscoveryMode; -import org.jboss.shrinkwrap.api.ShrinkWrap; -import org.jboss.shrinkwrap.api.spec.JavaArchive; -import org.jboss.shrinkwrap.impl.BeansXml; -import org.jboss.weld.environment.se.Weld; -import org.jboss.weld.environment.se.test.arquillian.WeldSEClassPath; -import org.jboss.weld.tests.util.Assert; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Simulates a situation where there is implicit discovery (javax.enterprise.inject.scan.implicit) - * and no org.jboss.weld.se.archive.isolation and there are multiple archives on the classpath. - * This triggers beans.xml merging. - * - * The test controls deployment flow so as to be able to set system variables. - */ -@RunWith(Arquillian.class) -public class BeansXmlMergingTest { - - private static final String isolationOriginalValue = System.getProperty(Weld.ARCHIVE_ISOLATION_SYSTEM_PROPERTY); - private static final String implicitScanOriginalValue = System.getProperty(Weld.JAVAX_ENTERPRISE_INJECT_SCAN_IMPLICIT); - - @Deployment(managed = false) - public static Archive getDeployment() { - WeldSEClassPath archives = ShrinkWrap.create(WeldSEClassPath.class); - JavaArchive archive01 = ShrinkWrap - .create(BeanArchive.class) - // no beans.xml here but still should be discovered - .addClasses(Foo.class); - JavaArchive archive02 = ShrinkWrap - .create(BeanArchive.class) - .addAsManifestResource(new BeansXml(BeanDiscoveryMode.ALL), - "beans.xml") - .addClasses(Bar.class); - archives.add(archive01); - archives.add(archive02); - return archives; - } - - @ArquillianResource - private Deployer deployer; - - @Before - public void before() { - System.setProperty(Weld.ARCHIVE_ISOLATION_SYSTEM_PROPERTY, Boolean.toString(false)); - System.setProperty(Weld.JAVAX_ENTERPRISE_INJECT_SCAN_IMPLICIT, Boolean.toString(true)); - deployer.deploy("_DEFAULT_"); - } - - @After - public void after() { - deployer.undeploy("_DEFAULT_"); - } - - @AfterClass - public static void setIsolationBackToOriginal() { - if (isolationOriginalValue == null) { - System.clearProperty(Weld.ARCHIVE_ISOLATION_SYSTEM_PROPERTY); - } else { - System.setProperty(Weld.ARCHIVE_ISOLATION_SYSTEM_PROPERTY, isolationOriginalValue); - } - if (implicitScanOriginalValue == null) { - System.clearProperty(Weld.JAVAX_ENTERPRISE_INJECT_SCAN_IMPLICIT); - } else { - System.setProperty(Weld.JAVAX_ENTERPRISE_INJECT_SCAN_IMPLICIT, implicitScanOriginalValue); - } - } - - @Test - public void testArchivesCanBeDeployedAndDiscoveryWorks(Foo foo, Bar bar) { - Assert.assertNotNull(foo); - Assert.assertNotNull(bar); - } -} \ No newline at end of file diff --git a/environments/se/pom.xml b/environments/se/pom.xml index 0c8c3c9049..5deae2f82d 100644 --- a/environments/se/pom.xml +++ b/environments/se/pom.xml @@ -10,7 +10,7 @@ org.jboss.weld weld-core-parent ../../pom.xml - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT @@ -24,7 +24,7 @@ - 2.0.23.Final + 2.2.16.Final diff --git a/environments/se/tests/pom.xml b/environments/se/tests/pom.xml index aab7fbe5df..d3ecf1be67 100644 --- a/environments/se/tests/pom.xml +++ b/environments/se/tests/pom.xml @@ -3,7 +3,7 @@ weld-se-parent org.jboss.weld.se - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../pom.xml 4.0.0 @@ -22,7 +22,7 @@ - 1.0.4 + 1.1.4 @@ -131,7 +131,7 @@
- + jacoco diff --git a/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/discovery/beanDefiningAnnotations/AdditionalBeanDefiningAnnotationsTest.java b/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/discovery/beanDefiningAnnotations/AdditionalBeanDefiningAnnotationsTest.java index 4314c77e96..6128f1a858 100644 --- a/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/discovery/beanDefiningAnnotations/AdditionalBeanDefiningAnnotationsTest.java +++ b/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/discovery/beanDefiningAnnotations/AdditionalBeanDefiningAnnotationsTest.java @@ -16,6 +16,11 @@ */ package org.jboss.weld.environment.se.test.discovery.beanDefiningAnnotations; +import java.lang.annotation.Annotation; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; import org.jboss.arquillian.container.se.api.ClassPath; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; @@ -30,34 +35,179 @@ import org.junit.runner.RunWith; /** - * Adds new bean defining annotations in Weld SE, then leaves discovery on and asserts that beans were found. + * Adds new bean defining annotations in Weld SE, then leaves discovery on and + * asserts that beans were found. + * + * Also tests that you can add new BDA via purely CDI SE container properties + * and via system properties. * * @see WELD-2523 + * @see WELD-2639 * * @author Matej Novotny */ @RunWith(Arquillian.class) public class AdditionalBeanDefiningAnnotationsTest { - @Deployment - public static Archive createTestArchive() { - return ClassPath.builder().add(ShrinkWrap.create(BeanArchive.class).addPackage(AdditionalBeanDefiningAnnotationsTest.class.getPackage())) - .build(); - } + @Deployment + public static Archive createTestArchive() { + return ClassPath.builder() + .add(ShrinkWrap.create(BeanArchive.class) + .addPackage( + AdditionalBeanDefiningAnnotationsTest.class.getPackage())) + .build(); + } - @Test - public void testNewBeanDefiningAnnotationWorks() { - Weld weld = new Weld() + @Test + public void testNewBeanDefiningAnnotationWorks() { + Weld weld = + new Weld() .disableDiscovery() .setBeanDiscoveryMode(BeanDiscoveryMode.ANNOTATED) .addPackages(Bar.class.getPackage()) .addBeanDefiningAnnotations(NewBeanDefiningAnnotation.class); - try (WeldContainer container = weld.initialize()) { - Assert.assertTrue(container.isRunning()); - Assert.assertTrue(container.select(Foo.class).isResolvable()); - Assert.assertTrue(container.select(Bar.class).isResolvable()); - } + try (WeldContainer container = weld.initialize()) { + Assert.assertTrue(container.isRunning()); + Assert.assertTrue(container.select(Foo.class).isResolvable()); + Assert.assertTrue(container.select(Bar.class).isResolvable()); + } + } + + @Test + public void testDeclarationViaPropertiesWithWrongValue() { + Weld weld = + new Weld() + .disableDiscovery() + .setBeanDiscoveryMode(BeanDiscoveryMode.ANNOTATED) + .addPackages(Bar.class.getPackage()) + .addProperty(Weld.ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY, + "foo"); + + try (WeldContainer container = weld.initialize()) { + // should throw up while booting + Assert.fail(); + } catch (IllegalArgumentException expected) { + // OK + } + } + + @Test + public void testDeclarationViaPropertiesWithCorruptedSet() { + // we log warning on each wrong item in the list, so this should pass and + // just skip wrong value + Set corruptedSet = new HashSet<>(); + corruptedSet.add(NewBeanDefiningAnnotation.class); + corruptedSet.add(1l); + + Weld weld = + new Weld() + .disableDiscovery() + .setBeanDiscoveryMode(BeanDiscoveryMode.ANNOTATED) + .addPackages(Bar.class.getPackage()) + .addProperty(Weld.ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY, + corruptedSet); + + try (WeldContainer container = weld.initialize()) { + Assert.assertTrue(container.isRunning()); + Assert.assertTrue(container.select(Foo.class).isResolvable()); + Assert.assertTrue(container.select(Bar.class).isResolvable()); + } + } + + @Test + public void testCorrectDeclarationViaProperties() { + // we log warning on each wrong item in the list, so this should pass and + // just skip wrong value + Set> correctSet = new HashSet<>(); + correctSet.add(NewBeanDefiningAnnotation.class); + + Weld weld = + new Weld() + .disableDiscovery() + .setBeanDiscoveryMode(BeanDiscoveryMode.ANNOTATED) + .addPackages(Bar.class.getPackage()) + .addProperty(Weld.ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY, + correctSet); + + try (WeldContainer container = weld.initialize()) { + Assert.assertTrue(container.isRunning()); + Assert.assertTrue(container.select(Foo.class).isResolvable()); + Assert.assertTrue(container.select(Bar.class).isResolvable()); + } + } + + @Test + public void testCorrectDeclarationViaSystemProperties() { + setupSystemProperty(true, false, false); + Weld weld = new Weld() + .disableDiscovery() + .setBeanDiscoveryMode(BeanDiscoveryMode.ANNOTATED) + .addPackages(Bar.class.getPackage()); + + try (WeldContainer container = weld.initialize()) { + Assert.assertTrue(container.isRunning()); + Assert.assertTrue(container.select(Foo.class).isResolvable()); + Assert.assertTrue(container.select(Bar.class).isResolvable()); + } finally { + clearSystemProperty(); + } + } + + @Test + public void testDeclarationViaSystemPropertiesWithCorruptedList() { + setupSystemProperty(true, true, false); + Weld weld = new Weld() + .disableDiscovery() + .setBeanDiscoveryMode(BeanDiscoveryMode.ANNOTATED) + .addPackages(Bar.class.getPackage()); + + try (WeldContainer container = weld.initialize()) { + Assert.assertTrue(container.isRunning()); + Assert.assertTrue(container.select(Foo.class).isResolvable()); + Assert.assertTrue(container.select(Bar.class).isResolvable()); + } finally { + clearSystemProperty(); + } + } + + @Test + public void testDeclarationViaSystemPropertiesWithWrongValue() { + setupSystemProperty(true, false, true); + Weld weld = new Weld() + .disableDiscovery() + .setBeanDiscoveryMode(BeanDiscoveryMode.ANNOTATED) + .addPackages(Bar.class.getPackage()); + + try (WeldContainer container = weld.initialize()) { + Assert.fail(); + } catch (IllegalArgumentException expected) { + // OK, this should blow up + System.err.println(expected); + } finally { + clearSystemProperty(); + } + } + + private void setupSystemProperty(boolean correctClass, boolean wrongType, + boolean nonExistentClass) { + Properties props = System.getProperties(); + StringBuilder builder = new StringBuilder(); + if (correctClass) { + builder.append(NewBeanDefiningAnnotation.class.getName()).append(","); + } + if (wrongType) { + builder.append(Integer.class.getName()).append(","); + } + if (nonExistentClass) { + builder.append("foo.bar.Nope"); } + props.setProperty(Weld.ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY, + builder.toString()); + } + private void clearSystemProperty() { + Properties props = System.getProperties(); + props.remove(Weld.ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY); + } } diff --git a/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/event/options/timeout/IncompleteCustomExecutorServices.java b/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/event/options/timeout/IncompleteCustomExecutorServices.java index 294e868ccd..2e3f01ad7b 100644 --- a/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/event/options/timeout/IncompleteCustomExecutorServices.java +++ b/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/event/options/timeout/IncompleteCustomExecutorServices.java @@ -19,7 +19,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; - import org.jboss.weld.executor.AbstractExecutorServices; import org.jboss.weld.executor.DaemonThreadFactory; @@ -29,24 +28,21 @@ */ public class IncompleteCustomExecutorServices extends AbstractExecutorServices { - static final String PREFIX = "weld-worker-test"; - - private final transient ExecutorService taskExecutor = Executors - .newSingleThreadExecutor(new DaemonThreadFactory(new ThreadGroup(DaemonThreadFactory.WELD_WORKERS), PREFIX)); + static final String PREFIX = "weld-worker-test"; - public ExecutorService getTaskExecutor() { - return taskExecutor; - } + private final transient ExecutorService taskExecutor = + Executors.newSingleThreadExecutor(new DaemonThreadFactory(PREFIX)); - @Override - protected int getThreadPoolSize() { - return 1; - } + public ExecutorService getTaskExecutor() { return taskExecutor; } - @Override - public ScheduledExecutorService getTimerExecutor() { - // deliberately return null - return null; - } + @Override + protected int getThreadPoolSize() { + return 1; + } + @Override + public ScheduledExecutorService getTimerExecutor() { + // deliberately return null + return null; + } } diff --git a/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/merging/Bar.java b/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/implicit/merging/Bar.java similarity index 90% rename from environments/se/core/src/test/java/org/jboss/weld/environment/se/test/merging/Bar.java rename to environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/implicit/merging/Bar.java index a8692861b5..e44588e6fd 100644 --- a/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/merging/Bar.java +++ b/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/implicit/merging/Bar.java @@ -15,7 +15,6 @@ * limitations under the License. */ -package org.jboss.weld.environment.se.test.merging; +package org.jboss.weld.environment.se.test.implicit.merging; -public class Bar { -} +public class Bar {} diff --git a/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/implicit/merging/BeansXmlMergingTest.java b/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/implicit/merging/BeansXmlMergingTest.java new file mode 100644 index 0000000000..64f165f6ca --- /dev/null +++ b/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/implicit/merging/BeansXmlMergingTest.java @@ -0,0 +1,72 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.environment.se.test.implicit.merging; + +import static org.junit.Assert.assertTrue; + +import org.jboss.arquillian.container.se.api.ClassPath; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.BeanDiscoveryMode; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.jboss.shrinkwrap.impl.BeansXml; +import org.jboss.weld.environment.se.Weld; +import org.jboss.weld.environment.se.WeldContainer; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Simulates a situation where there is implicit discovery + * (javax.enterprise.inject.scan.implicit) and no + * org.jboss.weld.se.archive.isolation and there are multiple archives on the + * classpath. This triggers beans.xml merging.

The test controls deployment + * flow so as to be able to set system variables. + */ +@RunWith(Arquillian.class) +public class BeansXmlMergingTest { + + @Deployment + public static Archive createTestArchive() { + JavaArchive archive01 = + ShrinkWrap + .create(JavaArchive.class) + // no beans.xml here but still should be discovered + .addClasses(Foo.class); + JavaArchive archive02 = + ShrinkWrap.create(JavaArchive.class) + .addAsManifestResource(new BeansXml(BeanDiscoveryMode.ALL), + "beans.xml") + .addClasses(Bar.class, BeansXmlMergingTest.class); + return ClassPath.builder().add(archive01).add(archive02).build(); + } + + @Test + public void testArchivesCanBeDeployedAndDiscoveryWorks() { + try (WeldContainer container = + new Weld() + .property(Weld.JAVAX_ENTERPRISE_INJECT_SCAN_IMPLICIT, + Boolean.TRUE) + .property(Weld.ARCHIVE_ISOLATION_SYSTEM_PROPERTY, false) + .initialize()) { + assertTrue(container.select(Foo.class).isResolvable()); + assertTrue(container.select(Bar.class).isResolvable()); + } + } +} diff --git a/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/merging/Foo.java b/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/implicit/merging/Foo.java similarity index 91% rename from environments/se/core/src/test/java/org/jboss/weld/environment/se/test/merging/Foo.java rename to environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/implicit/merging/Foo.java index 1969f52361..5c543aa16b 100644 --- a/environments/se/core/src/test/java/org/jboss/weld/environment/se/test/merging/Foo.java +++ b/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/implicit/merging/Foo.java @@ -15,10 +15,9 @@ * limitations under the License. */ -package org.jboss.weld.environment.se.test.merging; +package org.jboss.weld.environment.se.test.implicit.merging; import javax.enterprise.context.ApplicationScoped; @ApplicationScoped -public class Foo { -} +public class Foo {} diff --git a/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/instance/enhanced/WeldInstanceTest.java b/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/instance/enhanced/WeldInstanceTest.java index 0abb084759..ae6aba1804 100644 --- a/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/instance/enhanced/WeldInstanceTest.java +++ b/environments/se/tests/src/test/java/org/jboss/weld/environment/se/test/instance/enhanced/WeldInstanceTest.java @@ -21,14 +21,13 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.math.BigDecimal; import java.util.Iterator; import java.util.List; - import javax.enterprise.context.Dependent; import javax.enterprise.inject.spi.Bean; - import org.jboss.arquillian.container.se.api.ClassPath; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; @@ -52,124 +51,169 @@ @RunWith(Arquillian.class) public class WeldInstanceTest { - @Deployment - public static Archive createTestArchive() { - return ClassPath.builder().add(ShrinkWrap.create(BeanArchive.class, Utils.getDeploymentNameAsHash(WeldInstanceTest.class)) - .addPackage(WeldInstanceTest.class.getPackage()).addClass(ActionSequence.class)).build(); - } - - @Test - public void testIsResolvable(Client client) { - try (WeldContainer container = new Weld().initialize()) { - assertTrue(container.select(Alpha.class).isResolvable()); - assertFalse(container.select(BigDecimal.class, Juicy.Literal.INSTANCE).isResolvable()); - } + @Deployment + public static Archive createTestArchive() { + return ClassPath.builder() + .add(ShrinkWrap + .create(BeanArchive.class, + Utils.getDeploymentNameAsHash(WeldInstanceTest.class)) + .addPackage(WeldInstanceTest.class.getPackage()) + .addClass(ActionSequence.class)) + .build(); + } + + @Test + public void testIsResolvable(Client client) { + try (WeldContainer container = new Weld().initialize()) { + assertTrue(container.select(Alpha.class).isResolvable()); + assertFalse(container.select(BigDecimal.class, Juicy.Literal.INSTANCE) + .isResolvable()); } - - @Test - public void testGetHandler() { + } + + @Test + public void testGetHandler() { + ActionSequence.reset(); + try (WeldContainer container = new Weld().initialize()) { + + Bean alphaBean = container.getBeanManager().resolve( + container.getBeanManager().getBeans(Alpha.class)); + WeldInstance instance = container.select(Alpha.class); + + Handler alpha1 = instance.getHandler(); + assertEquals(alphaBean, alpha1.getBean()); + assertEquals(Dependent.class, alpha1.getBean().getScope()); + // Contextual reference is obtained lazily + assertNull(ActionSequence.getSequenceData()); + + String alpha2Id; + + // Test try-with-resource + try (Handler alpha2 = instance.getHandler()) { + assertNull(ActionSequence.getSequenceData()); + alpha2Id = alpha2.get().getId(); + assertFalse(alpha1.get().getId().equals(alpha2Id)); + } + + List sequence = ActionSequence.getSequenceData(); + assertEquals(3, sequence.size()); + assertEquals("c" + alpha2Id, sequence.get(0)); + assertEquals("c" + alpha1.get().getId(), sequence.get(1)); + assertEquals("d" + alpha2Id, sequence.get(2)); + + alpha1.destroy(); + // Alpha1 destroyed + sequence = ActionSequence.getSequenceData(); + assertEquals(4, sequence.size()); + // Subsequent invocations are no-op + alpha1.destroy(); + + // Test normal scoped bean is also destroyed + WeldInstance bravoInstance = container.select(Bravo.class); + String bravoId = bravoInstance.get().getId(); + try (Handler bravo = bravoInstance.getHandler()) { + assertEquals(bravoId, bravo.get().getId()); ActionSequence.reset(); - try (WeldContainer container = new Weld().initialize()) { - - Bean alphaBean = container.getBeanManager().resolve(container.getBeanManager().getBeans(Alpha.class)); - WeldInstance instance = container.select(Alpha.class); - - Handler alpha1 = instance.getHandler(); - assertEquals(alphaBean, alpha1.getBean()); - assertEquals(Dependent.class, alpha1.getBean().getScope()); - // Contextual reference is obtained lazily - assertNull(ActionSequence.getSequenceData()); - - String alpha2Id; - - // Test try-with-resource - try (Handler alpha2 = instance.getHandler()) { - assertNull(ActionSequence.getSequenceData()); - alpha2Id = alpha2.get().getId(); - assertFalse(alpha1.get().getId().equals(alpha2Id)); - } - - List sequence = ActionSequence.getSequenceData(); - assertEquals(3, sequence.size()); - assertEquals("c" + alpha2Id, sequence.get(0)); - assertEquals("c" + alpha1.get().getId(), sequence.get(1)); - assertEquals("d" + alpha2Id, sequence.get(2)); - - alpha1.destroy(); - // Alpha1 destroyed - sequence = ActionSequence.getSequenceData(); - assertEquals(4, sequence.size()); - assertEquals("d" + alpha1.get().getId(), sequence.get(3)); - // Subsequent invocations are no-op - alpha1.destroy(); - - // Test normal scoped bean is also destroyed - WeldInstance bravoInstance = container.select(Bravo.class); - String bravoId = bravoInstance.get().getId(); - try (Handler bravo = bravoInstance.getHandler()) { - assertEquals(bravoId, bravo.get().getId()); - ActionSequence.reset(); - } - sequence = ActionSequence.getSequenceData(); - assertEquals(1, sequence.size()); - assertEquals("d" + bravoId, sequence.get(0)); - } + } + sequence = ActionSequence.getSequenceData(); + assertEquals(1, sequence.size()); + assertEquals("d" + bravoId, sequence.get(0)); } - - @Test - public void testHandlers() { - ActionSequence.reset(); - try (WeldContainer container = new Weld().initialize()) { - WeldInstance instance = container.select(Processor.class); - assertTrue(instance.isAmbiguous()); - for (Handler handler : instance.handlers()) { - handler.get().ping(); - if (handler.getBean().getScope().equals(Dependent.class)) { - handler.destroy(); - } - } - assertEquals(3, ActionSequence.getSequenceSize()); - ActionSequence.assertSequenceDataContainsAll("firstPing", "secondPing", "firstDestroy"); - - ActionSequence.reset(); - assertTrue(instance.isAmbiguous()); - for (Iterator> iterator = instance.handlers().iterator(); iterator.hasNext();) { - try (Handler handler = iterator.next()) { - handler.get().ping(); - } - } - assertEquals(4, ActionSequence.getSequenceSize()); - ActionSequence.assertSequenceDataContainsAll("firstPing", "secondPing", "firstDestroy", "secondDestroy"); - } - + } + + @Test + public void testGetAfterDestroyingContextualInstance() { + ActionSequence.reset(); + try (WeldContainer container = new Weld().initialize()) { + Client client = container.select(Client.class).get(); + assertNotNull(client); + + Handler alphaHandle = client.getAlphaInstance().getHandler(); + // trigger bean creation and assert + alphaHandle.get(); + List sequence = ActionSequence.getSequenceData(); + assertEquals(1, sequence.size()); + // trigger bean destruction + alphaHandle.destroy(); + // verify that the destruction happened + sequence = ActionSequence.getSequenceData(); + assertEquals(2, sequence.size()); + + // try to invoke Handle.get() again; this should throw an exception + try { + alphaHandle.get(); + fail("Invoking Handle.get() after destroying contextual instance " + + "should throw an exception."); + } catch (IllegalStateException e) { + // expected + } } - - @Test - public void testHandlersStream() { - ActionSequence.reset(); - try (WeldContainer container = new Weld().initialize()) { - - Handler processor = container.select(Processor.class).handlersStream().filter(h -> Dependent.class.equals(h.getBean().getScope())) - .findFirst().orElse(null); - assertNull(ActionSequence.getSequenceData()); - assertNotNull(processor); - assertEquals(FirstProcessor.class, processor.getBean().getBeanClass()); - assertEquals(FirstProcessor.class.getName(), processor.get().getId()); - processor.destroy(); - List sequence = ActionSequence.getSequenceData(); - assertEquals(1, sequence.size()); - assertEquals("firstDestroy", sequence.get(0)); - - Handler withPriority = container.select(WithPriority.class).handlersStream().sorted(container.getPriorityComparator()).findFirst() - .orElse(null); - assertNotNull(withPriority); - assertEquals(Priority3.class, withPriority.getBean().getBeanClass()); - withPriority.get(); - sequence = ActionSequence.getSequenceData(); - assertEquals(2, sequence.size()); - assertEquals("firstDestroy", sequence.get(0)); - assertEquals("c" + Priority3.class.getName(), sequence.get(1)); + } + + @Test + public void testHandlers() { + ActionSequence.reset(); + try (WeldContainer container = new Weld().initialize()) { + WeldInstance instance = container.select(Processor.class); + assertTrue(instance.isAmbiguous()); + for (Handler handler : instance.handlers()) { + handler.get().ping(); + if (handler.getBean().getScope().equals(Dependent.class)) { + handler.destroy(); + } + } + assertEquals(3, ActionSequence.getSequenceSize()); + ActionSequence.assertSequenceDataContainsAll("firstPing", "secondPing", + "firstDestroy"); + + ActionSequence.reset(); + assertTrue(instance.isAmbiguous()); + for (Iterator> iterator = + instance.handlers().iterator(); + iterator.hasNext();) { + try (Handler handler = iterator.next()) { + handler.get().ping(); } + } + assertEquals(4, ActionSequence.getSequenceSize()); + ActionSequence.assertSequenceDataContainsAll( + "firstPing", "secondPing", "firstDestroy", "secondDestroy"); } - + } + + @Test + public void testHandlersStream() { + ActionSequence.reset(); + try (WeldContainer container = new Weld().initialize()) { + + Handler processor = + container.select(Processor.class) + .handlersStream() + .filter(h -> Dependent.class.equals(h.getBean().getScope())) + .findFirst() + .orElse(null); + assertNull(ActionSequence.getSequenceData()); + assertNotNull(processor); + assertEquals(FirstProcessor.class, processor.getBean().getBeanClass()); + assertEquals(FirstProcessor.class.getName(), processor.get().getId()); + processor.destroy(); + List sequence = ActionSequence.getSequenceData(); + assertEquals(1, sequence.size()); + assertEquals("firstDestroy", sequence.get(0)); + + Handler withPriority = + container.select(WithPriority.class) + .handlersStream() + .sorted(container.getPriorityComparator()) + .findFirst() + .orElse(null); + assertNotNull(withPriority); + assertEquals(Priority3.class, withPriority.getBean().getBeanClass()); + withPriority.get(); + sequence = ActionSequence.getSequenceData(); + assertEquals(2, sequence.size()); + assertEquals("firstDestroy", sequence.get(0)); + assertEquals("c" + Priority3.class.getName(), sequence.get(1)); + } + } } diff --git a/environments/servlet/build/pom.xml b/environments/servlet/build/pom.xml index 1825bdaf57..cba486b691 100644 --- a/environments/servlet/build/pom.xml +++ b/environments/servlet/build/pom.xml @@ -3,7 +3,7 @@ weld-servlet-parent org.jboss.weld.servlet - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT 4.0.0 org.jboss.weld.servlet @@ -40,6 +40,31 @@ true + + org.jboss.weld + weld-api + ${weld.api.version} + true + + + + org.jboss.spec.javax.servlet + jboss-servlet-api_4.0_spec + true + + + + jakarta.inject + jakarta.inject-api + true + + + + jakarta.enterprise + jakarta.enterprise.cdi-api + true + + @@ -73,7 +98,6 @@ org.apache.tomcat:juli org.apache.tomcat:annotations-api javax.faces:jsf-api - org.mortbay.jetty:jetty javax.el:el-api org.jboss.spec.javax.el:jboss-el-api_3.0_spec @@ -82,6 +106,17 @@ + + org.apache.maven.plugins + maven-jar-plugin + + + + true + + + + @@ -101,12 +136,69 @@ true - org.jboss.weld:* - org.jboss.weld.module:* - org.jboss.weld.servlet:* - javax.enterprise:* - javax.inject:* + org.jboss.weld:* + org.jboss.weld.module:* + org.jboss.weld.servlet:* + jakarta.enterprise:* + jakarta.inject:* + + + com.github.spotbugs + spotbugs-annotations + ${spotbugs-annotations-version} + + + org.jboss.logging + jboss-logging-annotations + ${jboss.logging.processor.version} + + + org.apache.bcel + bcel + ${apache.bcel.version} + + + io.undertow + undertow-servlet + ${undertow.version} + + + jakarta.servlet.jsp + jakarta.servlet.jsp-api + ${jsp.api.version} + + + org.jboss + jandex + ${jandex.version} + + + jakarta.faces + jakarta.faces-api + ${jsf.version} + + + org.eclipse.jetty + jetty-server + ${jetty.version} + + + org.eclipse.jetty + jetty-util + ${jetty.version} + + + org.eclipse.jetty + jetty-servlet + ${jetty.version} + + + org.apache.tomcat.embed + tomcat-embed-core + ${tomcat.version} + + diff --git a/environments/servlet/core/pom.xml b/environments/servlet/core/pom.xml index 990a8f417f..1a89f1dcf8 100644 --- a/environments/servlet/core/pom.xml +++ b/environments/servlet/core/pom.xml @@ -3,7 +3,7 @@ weld-servlet-parent org.jboss.weld.servlet - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../pom.xml 4.0.0 @@ -72,7 +72,7 @@ javax.portlet portlet-api - 2.0 + 3.0.1 provided @@ -83,24 +83,6 @@ true - - org.mortbay.jetty - jetty - provided - - - - org.mortbay.jetty - jetty-plus - provided - - - - org.mortbay.jetty - jetty-util - provided - - org.eclipse.jetty jetty-server @@ -167,7 +149,7 @@ ${undertow.version} provided - + org.jboss.classfilewriter jboss-classfilewriter diff --git a/environments/servlet/core/src/main/java/org/jboss/weld/environment/gwtdev/GwtDevHostedModeContainer.java b/environments/servlet/core/src/main/java/org/jboss/weld/environment/gwtdev/GwtDevHostedModeContainer.java index 761002f79e..fc2a372b95 100644 --- a/environments/servlet/core/src/main/java/org/jboss/weld/environment/gwtdev/GwtDevHostedModeContainer.java +++ b/environments/servlet/core/src/main/java/org/jboss/weld/environment/gwtdev/GwtDevHostedModeContainer.java @@ -18,13 +18,12 @@ package org.jboss.weld.environment.gwtdev; import java.lang.reflect.Method; - import javax.servlet.ServletContext; - -import org.jboss.weld.environment.servlet.Container; -import org.jboss.weld.environment.servlet.ContainerContext; import org.jboss.weld.environment.jetty.AbstractJettyContainer; +import org.jboss.weld.environment.jetty.JettyContainer; import org.jboss.weld.environment.jetty.JettyWeldInjector; +import org.jboss.weld.environment.servlet.Container; +import org.jboss.weld.environment.servlet.ContainerContext; import org.jboss.weld.environment.servlet.logging.JettyLogger; /** @@ -32,31 +31,35 @@ * */ public class GwtDevHostedModeContainer extends AbstractJettyContainer { - public static final Container INSTANCE = new GwtDevHostedModeContainer(); + public static final Container INSTANCE = new GwtDevHostedModeContainer(); - // The gwt-dev jar is never in the project classpath (only in the maven/eclipse/intellij plugin classpath) - // except when GWT is being run in hosted mode. - private static final String GWT_DEV_HOSTED_MODE_REQUIRED_CLASS_NAME = "com.google.gwt.dev.HostedMode"; + // The gwt-dev jar is never in the project classpath (only in the + // maven/eclipse/intellij plugin classpath) except when GWT is being run in + // hosted mode. + private static final String GWT_DEV_HOSTED_MODE_REQUIRED_CLASS_NAME = + "com.google.gwt.dev.HostedMode"; - protected String classToCheck() { - return GWT_DEV_HOSTED_MODE_REQUIRED_CLASS_NAME; - } + protected String classToCheck() { + return GWT_DEV_HOSTED_MODE_REQUIRED_CLASS_NAME; + } - protected Class getWeldServletHandlerClass() { - return MortbayWeldServletHandler.class; - } + protected Class getWeldServletHandlerClass() { + return JettyContainer.class; + } + + public void initialize(ContainerContext context) { + // Try pushing a Jetty Injector into the servlet context + try { + context.getServletContext().setAttribute( + INJECTOR_ATTRIBUTE_NAME, new JettyWeldInjector(context.getManager())); + JettyLogger.LOG.gwtHostedModeDetected(); - public void initialize(ContainerContext context) { - // Try pushing a Jetty Injector into the servlet context - try { - context.getServletContext().setAttribute(INJECTOR_ATTRIBUTE_NAME, new JettyWeldInjector(context.getManager())); - JettyLogger.LOG.gwtHostedModeDetected(); - - Class decoratorClass = getWeldServletHandlerClass(); - Method processMethod = decoratorClass.getMethod("process", ServletContext.class); - processMethod.invoke(null, context.getServletContext()); - } catch (Exception e) { - JettyLogger.LOG.unableToCreateJettyWeldInjector(e); - } + Class decoratorClass = getWeldServletHandlerClass(); + Method processMethod = + decoratorClass.getMethod("process", ServletContext.class); + processMethod.invoke(null, context.getServletContext()); + } catch (Exception e) { + JettyLogger.LOG.unableToCreateJettyWeldInjector(e); } + } } diff --git a/environments/servlet/core/src/main/java/org/jboss/weld/environment/gwtdev/MortbayWeldServletHandler.java b/environments/servlet/core/src/main/java/org/jboss/weld/environment/gwtdev/MortbayWeldServletHandler.java deleted file mode 100644 index ca7002e77e..0000000000 --- a/environments/servlet/core/src/main/java/org/jboss/weld/environment/gwtdev/MortbayWeldServletHandler.java +++ /dev/null @@ -1,118 +0,0 @@ -package org.jboss.weld.environment.gwtdev; - -import javax.servlet.Filter; -import javax.servlet.Servlet; -import javax.servlet.ServletContext; - -import org.jboss.weld.environment.jetty.AbstractJettyContainer; -import org.jboss.weld.environment.jetty.JettyWeldInjector; -import org.jboss.weld.environment.servlet.logging.JettyLogger; -import org.mortbay.jetty.Handler; -import org.mortbay.jetty.Server; -import org.mortbay.jetty.handler.ContextHandler; -import org.mortbay.jetty.handler.HandlerCollection; -import org.mortbay.jetty.servlet.ServletHandler; -import org.mortbay.jetty.webapp.WebAppContext; -import org.mortbay.resource.Resource; - -/** - * @author Matija Mazi - * @author Ales Justin - */ -public class MortbayWeldServletHandler extends ServletHandler { - - private ServletContext sco; - private JettyWeldInjector injector; - - public MortbayWeldServletHandler(ServletHandler existingHandler, ServletContext servletContext) { - sco = servletContext; - setFilters(existingHandler.getFilters()); - setFilterMappings(existingHandler.getFilterMappings()); - setServlets(existingHandler.getServlets()); - setServletMappings(existingHandler.getServletMappings()); - } - - @Override - public Servlet customizeServlet(Servlet servlet) throws Exception { - inject(servlet); - return servlet; - } - - @Override - public Filter customizeFilter(Filter filter) throws Exception { - inject(filter); - return filter; - } - - protected void inject(Object injectable) { - if (injector == null) { - injector = (JettyWeldInjector) sco.getAttribute(AbstractJettyContainer.INJECTOR_ATTRIBUTE_NAME); - } - if (injector == null) { - JettyLogger.LOG.cantFindInjector(injectable); - } else { - injector.inject(injectable); - } - } - - protected static void process(WebAppContext wac, boolean startNewHandler) throws Exception { - MortbayWeldServletHandler wHanlder = new MortbayWeldServletHandler(wac.getServletHandler(), wac.getServletContext()); - wac.setServletHandler(wHanlder); - wac.getSecurityHandler().setHandler(wHanlder); - - if (startNewHandler) { - wHanlder.start(); - } - - Resource jettyEnv = null; - Resource webInf = wac.getWebInf(); - if (webInf != null && webInf.exists()) { - jettyEnv = webInf.addPath("jetty-env.xml"); - } - if (jettyEnv == null || !(jettyEnv.exists())) { - JettyLogger.LOG.missingJettyEnv(); - } - } - - public static void process(WebAppContext wac) throws Exception { - process(wac, false); - } - - public static void process(ServletContext context) throws Exception { - WebAppContext wac = (WebAppContext) WebAppContext.getCurrentWebAppContext(); - if (wac == null) { - wac = findWAC(context); - } - - if (wac != null) { - process(wac, true); - } else { - JettyLogger.LOG.cantFindWebApplicationContext(); - } - } - - protected static WebAppContext findWAC(ServletContext context) { - if (context instanceof ContextHandler.SContext) { - ContextHandler.SContext sContext = (ContextHandler.SContext) context; - ContextHandler contextHandler = sContext.getContextHandler(); - Handler handler = contextHandler.getHandler(); - if (handler instanceof ServletHandler) { - ServletHandler servletHandler = (ServletHandler) handler; - Server server = servletHandler.getServer(); - Handler serverHandler = server.getHandler(); - if (serverHandler instanceof HandlerCollection) { - HandlerCollection hc = (HandlerCollection) serverHandler; - for (Handler h : hc.getHandlers()) { - if (h instanceof WebAppContext) { - WebAppContext wac = (WebAppContext) h; - if (wac.getServletHandler() == servletHandler) { - return wac; - } - } - } - } - } - } - return null; - } -} diff --git a/environments/servlet/core/src/main/java/org/jboss/weld/environment/servlet/deployment/WebAppBeanArchiveScanner.java b/environments/servlet/core/src/main/java/org/jboss/weld/environment/servlet/deployment/WebAppBeanArchiveScanner.java index e488a518af..03efeb3646 100644 --- a/environments/servlet/core/src/main/java/org/jboss/weld/environment/servlet/deployment/WebAppBeanArchiveScanner.java +++ b/environments/servlet/core/src/main/java/org/jboss/weld/environment/servlet/deployment/WebAppBeanArchiveScanner.java @@ -22,9 +22,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; - import javax.servlet.ServletContext; - import org.jboss.weld.bootstrap.api.Bootstrap; import org.jboss.weld.bootstrap.spi.BeansXml; import org.jboss.weld.environment.deployment.discovery.DefaultBeanArchiveScanner; @@ -40,78 +38,96 @@ */ public class WebAppBeanArchiveScanner extends DefaultBeanArchiveScanner { - static final String WEB_INF = "/WEB-INF"; - - static final String WEB_INF_CLASSES = WEB_INF + "/classes"; - - static final String WEB_INF_BEANS_XML = WEB_INF + "/beans.xml"; - - static final String WEB_INF_CLASSES_BEANS_XML = WEB_INF_CLASSES + "/META-INF/beans.xml"; - - static final String WEB_INF_CLASSES_FILE_PATH = File.separatorChar + "WEB-INF" + File.separatorChar + "classes"; - - static final String[] RESOURCES = { WEB_INF_BEANS_XML, WEB_INF_CLASSES_BEANS_XML }; - - private final ServletContext servletContext; - - /** - * - * @param resourceLoader - * @param bootstrap - * @param servletContext - */ - public WebAppBeanArchiveScanner(ResourceLoader resourceLoader, Bootstrap bootstrap, ServletContext servletContext) { - super(resourceLoader, bootstrap); - this.servletContext = servletContext; + static final String WEB_INF = "/WEB-INF"; + + static final String WEB_INF_CLASSES = WEB_INF + "/classes"; + + static final String WEB_INF_BEANS_XML = WEB_INF + "/beans.xml"; + + static final String WEB_INF_CLASSES_BEANS_XML = + WEB_INF_CLASSES + "/META-INF/beans.xml"; + + static final String WEB_INF_CLASSES_FILE_PATH = + File.separatorChar + "WEB-INF" + File.separatorChar + "classes"; + + static final String[] RESOURCES = {WEB_INF_BEANS_XML, + WEB_INF_CLASSES_BEANS_XML}; + + private final ServletContext servletContext; + + /** + * + * @param resourceLoader + * @param bootstrap + * @param servletContext + */ + public WebAppBeanArchiveScanner(ResourceLoader resourceLoader, + Bootstrap bootstrap, + ServletContext servletContext) { + super(resourceLoader, bootstrap); + this.servletContext = servletContext; + } + + @Override + public List scan() { + + // We use context path as a base for bean archive ids + String contextPath = servletContext.getContextPath(); + List results = new ArrayList<>(super.scan()); + + File webInfClasses = null; + ScanResult webInfBeansXML = null; + + try { + // WEB-INF/classes + URL beansXmlUrl = null; + for (String resource : RESOURCES) { + URL resourceUrl; + resourceUrl = servletContext.getResource(resource); + if (resourceUrl != null) { + if (beansXmlUrl != null) { + WeldServletLogger.LOG.foundBothConfiguration(beansXmlUrl); + } else { + beansXmlUrl = resourceUrl; + } + } + } + if (beansXmlUrl != null) { + BeansXml beansXml = parseBeansXml(beansXmlUrl); + if (accept(beansXml)) { + webInfClasses = Servlets.getRealFile(servletContext, WEB_INF_CLASSES); + if (webInfClasses != null) { + webInfBeansXML = new ScanResult(beansXml, webInfClasses.getPath()) + .extractBeanArchiveId(contextPath, WEB_INF); + } else { + // The WAR is not extracted to the file system - make use of + // ServletContext.getResourcePaths() + webInfBeansXML = new ScanResult(beansXml, WEB_INF_CLASSES); + } + } + } + } catch (MalformedURLException e) { + throw WeldServletLogger.LOG.errorLoadingResources(e); } - @Override - public List scan() { - - // We use context path as a base for bean archive ids - String contextPath = servletContext.getContextPath(); - List results = new ArrayList<>(super.scan()); - - // All previous results for WEB-INF/classes must be ignored - for (Iterator iterator = results.iterator(); iterator.hasNext();) { - ScanResult result = iterator.next(); - String path = result.getBeanArchiveRef().toString(); - if (path.contains(WEB_INF_CLASSES_FILE_PATH) || path.contains(WEB_INF_CLASSES)) { - iterator.remove(); - } else { - result.extractBeanArchiveId(contextPath, WEB_INF); - } - } + // All previous results for WEB-INF/classes must be ignored + for (Iterator iterator = results.iterator(); + iterator.hasNext();) { + ScanResult result = iterator.next(); + String path = result.getBeanArchiveRef().toString(); + if (path.contains(WEB_INF_CLASSES_FILE_PATH) || + path.contains(WEB_INF_CLASSES) || + new File(path).equals(webInfClasses)) { + iterator.remove(); + } else { + result.extractBeanArchiveId(contextPath, WEB_INF); + } + } - try { - // WEB-INF/classes - URL beansXmlUrl = null; - for (String resource : RESOURCES) { - URL resourceUrl; - resourceUrl = servletContext.getResource(resource); - if (resourceUrl != null) { - if (beansXmlUrl != null) { - WeldServletLogger.LOG.foundBothConfiguration(beansXmlUrl); - } else { - beansXmlUrl = resourceUrl; - } - } - } - if (beansXmlUrl != null) { - BeansXml beansXml = parseBeansXml(beansXmlUrl); - if (accept(beansXml)) { - File webInfClasses = Servlets.getRealFile(servletContext, WEB_INF_CLASSES); - if (webInfClasses != null) { - results.add(new ScanResult(beansXml, webInfClasses.getPath()).extractBeanArchiveId(contextPath, WEB_INF)); - } else { - // The WAR is not extracted to the file system - make use of ServletContext.getResourcePaths() - results.add(new ScanResult(beansXml, WEB_INF_CLASSES)); - } - } - } - } catch (MalformedURLException e) { - throw WeldServletLogger.LOG.errorLoadingResources(e); - } - return ImmutableList.copyOf(results); + if (webInfBeansXML != null) { + results.add(webInfBeansXML); } + + return ImmutableList.copyOf(results); + } } diff --git a/environments/servlet/core/src/main/java/org/jboss/weld/environment/undertow/WeldServletExtension.java b/environments/servlet/core/src/main/java/org/jboss/weld/environment/undertow/WeldServletExtension.java index 3b072d34f7..b3331f9960 100644 --- a/environments/servlet/core/src/main/java/org/jboss/weld/environment/undertow/WeldServletExtension.java +++ b/environments/servlet/core/src/main/java/org/jboss/weld/environment/undertow/WeldServletExtension.java @@ -19,48 +19,62 @@ import io.undertow.servlet.ServletExtension; import io.undertow.servlet.api.DeploymentInfo; import io.undertow.servlet.api.FilterInfo; +import io.undertow.servlet.api.InstanceFactory; import io.undertow.servlet.api.ListenerInfo; import io.undertow.servlet.api.ServletInfo; - +import io.undertow.servlet.util.ImmediateInstanceFactory; +import java.util.EventListener; import javax.servlet.ServletContext; - import org.jboss.weld.environment.servlet.logging.UndertowLogger; /** - * Undertow extension that hooks into undertow's instance creation and delegates to Weld. + * Undertow extension that hooks into undertow's instance creation and delegates + * to Weld. * * @author Jozef Hartinger * */ public class WeldServletExtension implements ServletExtension { - public static final String INSTALLED = WeldServletExtension.class.getName() + ".installed"; - public static final String INSTALLED_SERVLET = "servlet-only"; - public static final String INSTALLED_FULL = "full"; + public static final String INSTALLED = + WeldServletExtension.class.getName() + ".installed"; + public static final String INSTALLED_SERVLET = "servlet-only"; + public static final String INSTALLED_FULL = "full"; - @Override - public void handleDeployment(DeploymentInfo deploymentInfo, ServletContext servletContext) { - // Servlet injection - for (ServletInfo servlet : deploymentInfo.getServlets().values()) { - UndertowLogger.LOG.installingCdiSupport(servlet.getServletClass()); - servlet.setInstanceFactory(WeldInstanceFactory.of(servlet.getInstanceFactory(), servletContext, servlet.getServletClass())); - } - try { - // Filter injection - for (FilterInfo filter : deploymentInfo.getFilters().values()) { - UndertowLogger.LOG.installingCdiSupport(filter.getFilterClass()); - filter.setInstanceFactory(WeldInstanceFactory.of(filter.getInstanceFactory(), servletContext, filter.getFilterClass())); - } - // Listener injection - for (ListenerInfo listener : deploymentInfo.getListeners()) { - UndertowLogger.LOG.installingCdiSupport(listener.getListenerClass()); - listener.setInstanceFactory(WeldInstanceFactory.of(listener.getInstanceFactory(), servletContext, listener.getListenerClass())); - } - servletContext.setAttribute(INSTALLED, INSTALLED_FULL); - } catch (NoSuchMethodError e) { - // Undertow 1.2 and older does not have setInstanceFactory() on listeners/filters - servletContext.setAttribute(INSTALLED, INSTALLED_SERVLET); - return; + @Override + public void handleDeployment(DeploymentInfo deploymentInfo, + ServletContext servletContext) { + // Servlet injection + for (ServletInfo servlet : deploymentInfo.getServlets().values()) { + UndertowLogger.LOG.installingCdiSupport(servlet.getServletClass()); + servlet.setInstanceFactory( + WeldInstanceFactory.of(servlet.getInstanceFactory(), servletContext, + servlet.getServletClass())); + } + try { + // Filter injection + for (FilterInfo filter : deploymentInfo.getFilters().values()) { + UndertowLogger.LOG.installingCdiSupport(filter.getFilterClass()); + filter.setInstanceFactory( + WeldInstanceFactory.of(filter.getInstanceFactory(), servletContext, + filter.getFilterClass())); + } + // Listener injection + for (ListenerInfo listener : deploymentInfo.getListeners()) { + UndertowLogger.LOG.installingCdiSupport(listener.getListenerClass()); + InstanceFactory instanceFactory = + listener.getInstanceFactory(); + if (!(instanceFactory instanceof ImmediateInstanceFactory)) { + listener.setInstanceFactory(WeldInstanceFactory.of( + instanceFactory, servletContext, listener.getListenerClass())); } + } + servletContext.setAttribute(INSTALLED, INSTALLED_FULL); + } catch (NoSuchMethodError e) { + // Undertow 1.2 and older does not have setInstanceFactory() on + // listeners/filters + servletContext.setAttribute(INSTALLED, INSTALLED_SERVLET); + return; } + } } diff --git a/environments/servlet/core/src/test/java/org/jboss/weld/environment/servlet/undertow/UndertowSmokeTest.java b/environments/servlet/core/src/test/java/org/jboss/weld/environment/servlet/undertow/UndertowSmokeTest.java index b8125c1b91..0100a2dbe0 100644 --- a/environments/servlet/core/src/test/java/org/jboss/weld/environment/servlet/undertow/UndertowSmokeTest.java +++ b/environments/servlet/core/src/test/java/org/jboss/weld/environment/servlet/undertow/UndertowSmokeTest.java @@ -18,16 +18,6 @@ import static org.junit.Assert.assertTrue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.servlet.ServletException; - -import org.jboss.weld.environment.servlet.Container; -import org.jboss.weld.environment.servlet.Listener; -import org.jboss.weld.environment.undertow.UndertowContainer; -import org.junit.Test; - import io.undertow.Handlers; import io.undertow.Undertow; import io.undertow.server.HttpHandler; @@ -36,43 +26,67 @@ import io.undertow.servlet.Servlets; import io.undertow.servlet.api.DeploymentInfo; import io.undertow.servlet.api.DeploymentManager; +import io.undertow.servlet.api.ServletContainerInitializerInfo; +import java.util.Collections; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.servlet.ServletException; +import org.jboss.weld.environment.servlet.Container; +import org.jboss.weld.environment.servlet.EnhancedListener; +import org.jboss.weld.environment.undertow.UndertowContainer; +import org.junit.Test; /** - * Smoke test for Undertow integration. More sophisticated tests should be added to a separate undertow test project. + * Smoke test for Undertow integration. More sophisticated tests should be added + * to a separate undertow test project. * * @author Jozef Hartinger * */ public class UndertowSmokeTest { - static final CountDownLatch SYNC = new CountDownLatch(3); - - @Test - public void testUndertow() throws ServletException, InterruptedException { - DeploymentInfo servletBuilder = Servlets.deployment().setClassLoader(UndertowSmokeTest.class.getClassLoader()) - .setResourceManager(new ClassPathResourceManager(UndertowSmokeTest.class.getClassLoader())).setContextPath("/").setDeploymentName("test.war") - // Weld listner - .addListener(Servlets.listener(Listener.class)) - // application components - .addServlet(Servlets.servlet(InjectedServlet.class).addMapping("/*").setLoadOnStartup(1)) - .addListener(Servlets.listener(InjectedListener.class)) - .addFilter(Servlets.filter(InjectedFilter.class)) - .setEagerFilterInit(true) - .addInitParameter(Container.CONTEXT_PARAM_CONTAINER_CLASS, UndertowContainer.class.getName()); + static final CountDownLatch SYNC = new CountDownLatch(3); + @Test + public void testUndertow() throws ServletException, InterruptedException { + DeploymentInfo servletBuilder = + Servlets.deployment() + .setClassLoader(UndertowSmokeTest.class.getClassLoader()) + .setResourceManager(new ClassPathResourceManager( + UndertowSmokeTest.class.getClassLoader())) + .setContextPath("/") + .setDeploymentName("test.war") + // register Weld EnhancedListener + .addServletContainerInitializers( + new ServletContainerInitializerInfo( + EnhancedListener.class, Collections.>emptySet())) + // application components + .addServlet(Servlets.servlet(InjectedServlet.class) + .addMapping("/*") + .setLoadOnStartup(1)) + .addListener(Servlets.listener(InjectedListener.class)) + .addFilter(Servlets.filter(InjectedFilter.class)) + .setEagerFilterInit(true) + .addInitParameter(Container.CONTEXT_PARAM_CONTAINER_CLASS, + UndertowContainer.class.getName()); - DeploymentManager manager = Servlets.defaultContainer().addDeployment(servletBuilder); - manager.deploy(); + DeploymentManager manager = + Servlets.defaultContainer().addDeployment(servletBuilder); + manager.deploy(); - HttpHandler servletHandler = manager.start(); - PathHandler path = Handlers.path(Handlers.redirect("/")).addPrefixPath("/", servletHandler); - Undertow server = Undertow.builder().addHttpListener(8080, "localhost").setHandler(path).build(); - server.start(); + HttpHandler servletHandler = manager.start(); + PathHandler path = Handlers.path(Handlers.redirect("/")) + .addPrefixPath("/", servletHandler); + Undertow server = Undertow.builder() + .addHttpListener(8080, "localhost") + .setHandler(path) + .build(); + server.start(); - try { - assertTrue(SYNC.await(5, TimeUnit.SECONDS)); - } finally { - server.stop(); - } + try { + assertTrue(SYNC.await(5, TimeUnit.SECONDS)); + } finally { + server.stop(); } + } } diff --git a/environments/servlet/pom.xml b/environments/servlet/pom.xml index 71b03bdeb9..05d2cbca81 100644 --- a/environments/servlet/pom.xml +++ b/environments/servlet/pom.xml @@ -10,7 +10,7 @@ org.jboss.weld weld-core-parent ../../pom.xml - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT @@ -27,17 +27,12 @@ 2.3.2 - 9.0.31 - 9.4.14.v20181114 - 7.0 - - 6.1.26 - 2.2 + 9.0.58 + 9.4.45.v20220203 1.1.2 - 1.3.0.Beta1 + 2.2.16.Final 3.1 - 2.4 @@ -68,37 +63,6 @@ ${tomcat.version} - - org.mortbay.jetty - jetty - ${jetty6.version} - - - - org.mortbay.jetty - jetty-util - ${jetty6.version} - - - - - org.mortbay.jetty - jetty-plus - ${jetty6.version} - - - - org.mortbay.jetty - jetty-naming - ${jetty6.version} - - - - org.mortbay.jetty - jsp-2.1-jetty - ${jetty6.version} - - org.eclipse.jetty jetty-server @@ -144,7 +108,7 @@ org.glassfish.web el-impl - ${uel.glassfish.version} + ${glassfish.el.version} diff --git a/environments/servlet/tests/base/pom.xml b/environments/servlet/tests/base/pom.xml index 02d1da4974..7ce4d58faa 100644 --- a/environments/servlet/tests/base/pom.xml +++ b/environments/servlet/tests/base/pom.xml @@ -3,7 +3,7 @@ weld-servlet-parent org.jboss.weld.servlet - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml 4.0.0 @@ -35,11 +35,6 @@ jakarta.enterprise.cdi-api - - commons-httpclient - commons-httpclient - - junit junit @@ -53,6 +48,13 @@ net.sourceforge.htmlunit htmlunit + + + + org.eclipse.jetty.websocket + websocket-client + + diff --git a/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/bootstrap/enhanced/shutdown/EnhancedListenerShutdownTest.java b/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/bootstrap/enhanced/shutdown/EnhancedListenerShutdownTest.java index 82d58bb1d5..2e6bf5d1ad 100644 --- a/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/bootstrap/enhanced/shutdown/EnhancedListenerShutdownTest.java +++ b/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/bootstrap/enhanced/shutdown/EnhancedListenerShutdownTest.java @@ -24,11 +24,12 @@ import static org.jboss.weld.environment.servlet.test.util.Deployments.toListener; import static org.junit.Assert.assertEquals; +import com.gargoylesoftware.htmlunit.TextPage; +import com.gargoylesoftware.htmlunit.WebClient; import java.io.IOException; import java.net.URL; import java.net.URLEncoder; import java.util.List; - import org.jboss.arquillian.container.test.api.Deployer; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.OperateOnDeployment; @@ -45,9 +46,6 @@ import org.junit.Test; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.TextPage; -import com.gargoylesoftware.htmlunit.WebClient; - /** * * @author Martin Kouba @@ -57,66 +55,79 @@ @RunWith(Arquillian.class) public class EnhancedListenerShutdownTest { - protected static final String TEST = "test"; - protected static final String ASSERT = "assert"; - - protected static final Asset TEST_WEB_XML = new StringAsset(DEFAULT_WEB_XML_START + DEFAULT_WEB_XML_BODY + toListener(TestListener.class.getName()) - + toContextParam("WELD_CONTEXT_ID_KEY", TEST) + DEFAULT_WEB_XML_SUFFIX); - - protected static final Asset ASSERT_WEB_XML = new StringAsset(DEFAULT_WEB_XML_START + DEFAULT_WEB_XML_BODY + toContextParam("WELD_CONTEXT_ID_KEY", ASSERT) - + DEFAULT_WEB_XML_SUFFIX); - - @Deployment(name = TEST, managed = false) - public static WebArchive createTestArchive() { - WebArchive war = ShrinkWrap.create(WebArchive.class, "app-test.war").addAsWebInfResource(new BeansXml(), "beans.xml").setWebXML(TEST_WEB_XML); - war.addClasses(InitServlet.class, InfoClient.class, Foo.class, TestListener.class); - return war; - } - - @Deployment(name = ASSERT, managed = false) - public static WebArchive createAssertArchive() { - WebArchive war = ShrinkWrap.create(WebArchive.class, "app-assert.war").addAsWebInfResource(new BeansXml(), "beans.xml").setWebXML(DEFAULT_WEB_XML); - war.addClasses(InfoServlet.class, ActionSequence.class); - return war; - } - - @ArquillianResource - Deployer deployer; - - /** - * This is not a real test method. - * - * @see #testEnhancedListenerDoesNotDestroyWeldIfListenerRegistered(URL) - */ - @Test - @InSequence(1) - public void deployArchives() { - // In order to use @ArquillianResource URLs we need to deploy both test archives first - deployer.deploy(TEST); - deployer.deploy(ASSERT); - } - - @Test - @InSequence(2) - public void testEnhancedListenerNotDestroyingWeldIfListenerRegistered(@ArquillianResource @OperateOnDeployment(TEST) URL testContext, - @ArquillianResource @OperateOnDeployment(ASSERT) URL assertContext) throws IOException { - - // Init foo - set info archive deployment url - WebClient webClient = new WebClient(); - webClient.setThrowExceptionOnFailingStatusCode(true); - webClient.getPage(testContext + "init?url=" + URLEncoder.encode(assertContext.toExternalForm(), "UTF-8")); - - // Undeploy TEST - deployer.undeploy(TEST); - - // Test that Foo is destroyed after TestListener is notified - TextPage info = webClient.getPage(assertContext + "info?action=get"); - List data = ActionSequence.buildFromCsvData(info.getContent()).getData(); - assertEquals(2, data.size()); - assertEquals(TestListener.class.getSimpleName(), data.get(0)); - assertEquals(Foo.class.getSimpleName(), data.get(1)); - - // Undeploy ASSERT - deployer.undeploy(ASSERT); - } -} \ No newline at end of file + protected static final String TEST = "test"; + protected static final String ASSERT = "assert"; + + protected static final Asset TEST_WEB_XML = new StringAsset( + DEFAULT_WEB_XML_START + DEFAULT_WEB_XML_BODY + + toListener(TestListener.class.getName()) + + toContextParam("WELD_CONTEXT_ID_KEY", TEST) + DEFAULT_WEB_XML_SUFFIX); + + protected static final Asset ASSERT_WEB_XML = new StringAsset( + DEFAULT_WEB_XML_START + DEFAULT_WEB_XML_BODY + + toContextParam("WELD_CONTEXT_ID_KEY", ASSERT) + DEFAULT_WEB_XML_SUFFIX); + + @Deployment(name = TEST, managed = false) + public static WebArchive createTestArchive() { + WebArchive war = ShrinkWrap.create(WebArchive.class, "app-test.war") + .addAsWebInfResource(new BeansXml(), "beans.xml") + .setWebXML(TEST_WEB_XML); + war.addClasses(InitServlet.class, InfoClient.class, Foo.class, + TestListener.class); + return war; + } + + @Deployment(name = ASSERT, managed = false) + public static WebArchive createAssertArchive() { + WebArchive war = ShrinkWrap.create(WebArchive.class, "app-assert.war") + .addAsWebInfResource(new BeansXml(), "beans.xml") + .setWebXML(DEFAULT_WEB_XML); + war.addClasses(InfoServlet.class, ActionSequence.class); + return war; + } + + @ArquillianResource Deployer deployer; + + /** + * This is not a real test method. + * + * @see #testEnhancedListenerDoesNotDestroyWeldIfListenerRegistered(URL) + */ + @Test + @InSequence(1) + public void deployArchives() { + // In order to use @ArquillianResource URLs we need to deploy both test + // archives first + deployer.deploy(TEST); + deployer.deploy(ASSERT); + } + + @Test + @InSequence(2) + public void testEnhancedListenerNotDestroyingWeldIfListenerRegistered( + @ArquillianResource @OperateOnDeployment(TEST) URL testContext, + @ArquillianResource @OperateOnDeployment(ASSERT) URL assertContext) + throws IOException { + + // Init foo - set info archive deployment url + WebClient webClient = new WebClient(); + webClient.getOptions().setThrowExceptionOnFailingStatusCode(false); + webClient.getPage( + testContext + "init?url=" + + URLEncoder.encode(assertContext.toExternalForm(), "UTF-8")); + + // Undeploy TEST + deployer.undeploy(TEST); + + // Test that Foo is destroyed after TestListener is notified + TextPage info = webClient.getPage(assertContext + "info?action=get"); + List data = + ActionSequence.buildFromCsvData(info.getContent()).getData(); + assertEquals(2, data.size()); + assertEquals(TestListener.class.getSimpleName(), data.get(0)); + assertEquals(Foo.class.getSimpleName(), data.get(1)); + + // Undeploy ASSERT + deployer.undeploy(ASSERT); + } +} diff --git a/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/context/async/SimpleAsyncListenerTest.java b/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/context/async/SimpleAsyncListenerTest.java index b338660ea6..bafab8b330 100644 --- a/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/context/async/SimpleAsyncListenerTest.java +++ b/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/context/async/SimpleAsyncListenerTest.java @@ -3,8 +3,9 @@ import static org.jboss.weld.environment.servlet.test.util.Deployments.baseDeployment; import static org.junit.Assert.assertTrue; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.WebClient; import java.net.URL; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.RunAsClient; import org.jboss.arquillian.junit.Arquillian; @@ -14,9 +15,6 @@ import org.junit.Test; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebClient; - /** * @author Martin Kouba * @author Tomas Remes @@ -25,53 +23,59 @@ @RunWith(Arquillian.class) public class SimpleAsyncListenerTest { - @ArquillianResource - private URL contextPath; - - @Deployment - public static WebArchive createTestArchive() { - return baseDeployment().addClasses(SimpleAsyncListenerTest.class, FailingServlet.class, StatusServlet.class, - AsyncServlet.class, AsyncRequestProcessor.class, SimpleAsyncListener.class); - } + @ArquillianResource private URL contextPath; - @Test - public void testOnCompleteCalledSuccesfully() throws Exception { - WebClient webClient = new WebClient(); - webClient.getPage(getPath(AsyncServlet.TEST_COMPLETE)); - Page results = webClient.getPage(contextPath + "Status"); - assertTrue(results.getWebResponse().getContentAsString().contains("onComplete: true")); - } + @Deployment + public static WebArchive createTestArchive() { + return baseDeployment().addClasses( + SimpleAsyncListenerTest.class, FailingServlet.class, + StatusServlet.class, AsyncServlet.class, AsyncRequestProcessor.class, + SimpleAsyncListener.class); + } - @Test - public void testOnTimeoutCalledSuccesfully() throws Exception { - WebClient webClient = new WebClient(); - webClient.setThrowExceptionOnFailingStatusCode(false); - webClient.getPage(getPath(AsyncServlet.TEST_TIMEOUT)); - Page results = webClient.getPage(contextPath + "Status"); - assertTrue(results.getWebResponse().getContentAsString().contains("onTimeout: true")); - } + @Test + public void testOnCompleteCalledSuccesfully() throws Exception { + WebClient webClient = new WebClient(); + webClient.getPage(getPath(AsyncServlet.TEST_COMPLETE)); + Page results = webClient.getPage(contextPath + "Status"); + assertTrue(results.getWebResponse().getContentAsString().contains( + "onComplete: true")); + } - @Test - @Ignore //enable when WELD-1774 is fixed - public void testOnErrorCalledSuccesfully() throws Exception { - WebClient webClient = new WebClient(); - webClient.setThrowExceptionOnFailingStatusCode(false); - webClient.getPage(getPath(AsyncServlet.TEST_ERROR)); - Page results = webClient.getPage(contextPath + "Status"); - assertTrue(results.getWebResponse().getContentAsString(), results.getWebResponse().getContentAsString().contains("onError: true")); - } + @Test + public void testOnTimeoutCalledSuccesfully() throws Exception { + WebClient webClient = new WebClient(); + webClient.getOptions().setThrowExceptionOnFailingStatusCode(false); + webClient.getPage(getPath(AsyncServlet.TEST_TIMEOUT)); + Page results = webClient.getPage(contextPath + "Status"); + assertTrue(results.getWebResponse().getContentAsString().contains( + "onTimeout: true")); + } - @Test - public void testOnStartAsyncCalledSuccesfully() throws Exception { - WebClient webClient = new WebClient(); - webClient.getPage(getPath(AsyncServlet.TEST_LOOP)); - Page results = webClient.getPage(contextPath + "Status"); - assertTrue(results.getWebResponse().getContentAsString().contains("onComplete: true")); - assertTrue(results.getWebResponse().getContentAsString().contains("onStartAsync: true")); - } + @Test + @Ignore // enable when WELD-1774 is fixed + public void testOnErrorCalledSuccesfully() throws Exception { + WebClient webClient = new WebClient(); + webClient.getOptions().setThrowExceptionOnFailingStatusCode(false); + webClient.getPage(getPath(AsyncServlet.TEST_ERROR)); + Page results = webClient.getPage(contextPath + "Status"); + assertTrue(results.getWebResponse().getContentAsString(), + results.getWebResponse().getContentAsString().contains( + "onError: true")); + } - private String getPath(String test) { - return contextPath + "AsyncServlet?test=" + test; - } + @Test + public void testOnStartAsyncCalledSuccesfully() throws Exception { + WebClient webClient = new WebClient(); + webClient.getPage(getPath(AsyncServlet.TEST_LOOP)); + Page results = webClient.getPage(contextPath + "Status"); + assertTrue(results.getWebResponse().getContentAsString().contains( + "onComplete: true")); + assertTrue(results.getWebResponse().getContentAsString().contains( + "onStartAsync: true")); + } + private String getPath(String test) { + return contextPath + "AsyncServlet?test=" + test; + } } diff --git a/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/el/JsfTest.java b/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/el/JsfTest.java index f7f53c6c97..07d9ea6168 100644 --- a/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/el/JsfTest.java +++ b/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/el/JsfTest.java @@ -16,16 +16,19 @@ */ package org.jboss.weld.environment.servlet.test.el; -import static org.junit.Assert.assertEquals; import static org.jboss.weld.environment.servlet.test.util.Deployments.EMPTY_FACES_CONFIG_XML; import static org.jboss.weld.environment.servlet.test.util.Deployments.FACES_WEB_XML; import static org.jboss.weld.environment.servlet.test.util.Deployments.baseDeployment; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.html.HtmlElement; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.html.HtmlSpan; import java.net.URL; import java.util.HashSet; import java.util.Set; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.RunAsClient; import org.jboss.arquillian.junit.Arquillian; @@ -36,84 +39,83 @@ import org.junit.Test; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.WebClient; -import com.gargoylesoftware.htmlunit.html.HtmlElement; -import com.gargoylesoftware.htmlunit.html.HtmlPage; -import com.gargoylesoftware.htmlunit.html.HtmlSpan; - @RunAsClient @RunWith(Arquillian.class) public class JsfTest { - public static final Asset CHARLIE_XHTML = new ByteArrayAsset((" " + - " " + - " " + - " " + - " " + - " " + - " " + - "" + - "" + - " " + - " " + - " " + - "").getBytes()); - - @Deployment - public static WebArchive createTestArchive() { - return baseDeployment(FACES_WEB_XML) - .add(CHARLIE_XHTML, "charlie.xhtml") - .addAsWebInfResource(EMPTY_FACES_CONFIG_XML, "faces-config.xml") - .addClass(Chicken.class); + public static final Asset CHARLIE_XHTML = new ByteArrayAsset( + (" " + + " " + + " " + + " " + + " " + + " " + + " " + + "" + + "" + + " " + + " " + + " " + + "") + .getBytes()); + + @Deployment + public static WebArchive createTestArchive() { + return baseDeployment(FACES_WEB_XML) + .add(CHARLIE_XHTML, "charlie.xhtml") + .addAsWebInfResource(EMPTY_FACES_CONFIG_XML, "faces-config.xml") + .addClass(Chicken.class); + } + + @Test + public void testELWithParameters(@ArquillianResource URL baseURL) + throws Exception { + WebClient client = new WebClient(); + HtmlPage page = client.getPage(new URL(baseURL, "charlie.jsf")); + + page.asXml(); + + HtmlSpan oldel = getFirstMatchingElement(page, HtmlSpan.class, "oldel"); + assertNotNull(oldel); + final String charlie = "Charlie"; + assertEquals(charlie, oldel.asNormalizedText()); + + HtmlSpan newel = getFirstMatchingElement(page, HtmlSpan.class, "newel"); + assertNotNull(newel); + assertEquals(charlie, newel.asNormalizedText()); + } + + protected Set getElements(HtmlElement rootElement, + Class elementClass) { + Set result = new HashSet(); + + for (HtmlElement element : rootElement.getHtmlElementDescendants()) { + result.addAll(getElements(element, elementClass)); } - @Test - public void testELWithParameters(@ArquillianResource URL baseURL) throws Exception { - WebClient client = new WebClient(); - HtmlPage page = client.getPage(new URL(baseURL, "charlie.jsf")); - - page.asXml(); - - HtmlSpan oldel = getFirstMatchingElement(page, HtmlSpan.class, "oldel"); - assertNotNull(oldel); - final String charlie = "Charlie"; - assertEquals(charlie, oldel.asText()); - - HtmlSpan newel = getFirstMatchingElement(page, HtmlSpan.class, "newel"); - assertNotNull(newel); - assertEquals(charlie, newel.asText()); + if (elementClass.isInstance(rootElement)) { + result.add(elementClass.cast(rootElement)); } + return result; + } - protected Set getElements(HtmlElement rootElement, Class elementClass) { - Set result = new HashSet(); - - for (HtmlElement element : rootElement.getAllHtmlChildElements()) { - result.addAll(getElements(element, elementClass)); - } - - if (elementClass.isInstance(rootElement)) { - result.add(elementClass.cast(rootElement)); - } - return result; + protected T + getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { + Set inputs = getElements(page.getBody(), elementClass); + for (T input : inputs) { + if (input.getId().contains(id)) { + return input; + } } - - protected T getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { - - Set inputs = getElements(page.getBody(), elementClass); - for (T input : inputs) { - if (input.getId().contains(id)) { - return input; - } - } - return null; - } - + return null; + } } diff --git a/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/injection/FilterInjectionTest.java b/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/injection/FilterInjectionTest.java index d7bd4fc96d..a673038cf2 100644 --- a/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/injection/FilterInjectionTest.java +++ b/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/injection/FilterInjectionTest.java @@ -21,12 +21,10 @@ import static org.junit.Assert.assertEquals; import java.net.URL; - import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpMethod; -import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.RunAsClient; import org.jboss.arquillian.junit.Arquillian; @@ -41,18 +39,33 @@ @RunWith(Arquillian.class) public class FilterInjectionTest { - public static final Asset WEB_XML = new ByteArrayAsset(extendDefaultWebXml("Cat Filter" + CatFilter.class.getName() + "Cat Filter/cat Wolverine Servlet" + WolverineServlet.class.getName() + " Wolverine Servlet/").getBytes()); + public static final Asset WEB_XML = new ByteArrayAsset( + extendDefaultWebXml( + "Cat Filter" + + CatFilter.class.getName() + + ("Cat " + + "Filter/cat Wolverine " + + "Servlet") + + WolverineServlet.class.getName() + + (" " + + "Wolverine " + + "Servlet/")) + .getBytes()); - @Deployment - public static WebArchive createTestArchive() { - return baseDeployment(WEB_XML).addClasses(CatFilter.class, Sewer.class, RatServlet.class); - } + @Deployment + public static WebArchive createTestArchive() { + return baseDeployment(WEB_XML).addClasses(CatFilter.class, Sewer.class, + RatServlet.class); + } - @Test - public void testFilterInjection(@ArquillianResource URL baseURL) throws Exception { - HttpClient client = new HttpClient(); - HttpMethod method = new GetMethod(new URL(baseURL, "cat").toExternalForm()); - int sc = client.executeMethod(method); - assertEquals(HttpServletResponse.SC_OK, sc); - } + @Test + public void testFilterInjection(@ArquillianResource URL baseURL) + throws Exception { + CloseableHttpClient client = HttpClients.createDefault(); + HttpGet request = new HttpGet(new URL(baseURL, "cat").toExternalForm()); + assertEquals(HttpServletResponse.SC_OK, + client.execute(request).getStatusLine().getStatusCode()); + } } diff --git a/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/injection/ListenerInjectionTest.java b/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/injection/ListenerInjectionTest.java index 5d1400f3c9..f2f145fc50 100644 --- a/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/injection/ListenerInjectionTest.java +++ b/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/injection/ListenerInjectionTest.java @@ -22,12 +22,10 @@ import static org.junit.Assert.assertEquals; import java.net.URL; - import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpMethod; -import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.RunAsClient; import org.jboss.arquillian.junit.Arquillian; @@ -42,43 +40,55 @@ @RunWith(Arquillian.class) public class ListenerInjectionTest { - @Deployment - public static WebArchive createTestArchive() { - StringBuilder listeners = new StringBuilder(); - listeners.append(toListener(BatRequestListener.class.getName())); - listeners.append(toListener(BatSessionListener.class.getName())); - listeners.append(toListener(BatServletContextListener.class.getName())); - Asset webXml = new ByteArrayAsset( - extendDefaultWebXml( - listeners.toString() - + "Bat Servlet" - + BatServlet.class.getName() - + " Bat Servlet/bat") - .getBytes()); - return baseDeployment(webXml).addClasses(BatRequestListener.class, BatSessionListener.class, BatServletContextListener.class, BatListener.class, BatServlet.class, Sewer.class); - } + @Deployment + public static WebArchive createTestArchive() { + StringBuilder listeners = new StringBuilder(); + listeners.append(toListener(BatRequestListener.class.getName())); + listeners.append(toListener(BatSessionListener.class.getName())); + listeners.append(toListener(BatServletContextListener.class.getName())); + Asset webXml = new ByteArrayAsset( + extendDefaultWebXml( + listeners.toString() + + ("Bat " + + "Servlet") + + BatServlet.class.getName() + + (" Bat " + + "Servlet/bat")) + .getBytes()); + return baseDeployment(webXml).addClasses( + BatRequestListener.class, BatSessionListener.class, + BatServletContextListener.class, BatListener.class, BatServlet.class, + Sewer.class); + } - @Test - public void testRequestListenerInjection(@ArquillianResource URL baseURL) throws Exception { - HttpClient client = new HttpClient(); - HttpMethod method = new GetMethod(new URL(baseURL, "bat?mode=request").toExternalForm()); - int sc = client.executeMethod(method); - assertEquals(HttpServletResponse.SC_OK, sc); - } + @Test + public void testRequestListenerInjection(@ArquillianResource URL baseURL) + throws Exception { + CloseableHttpClient client = HttpClients.createDefault(); + HttpGet request = + new HttpGet(new URL(baseURL, "bat?mode=request").toExternalForm()); + assertEquals(HttpServletResponse.SC_OK, + client.execute(request).getStatusLine().getStatusCode()); + } - @Test - public void testSceListenerInjection(@ArquillianResource URL baseURL) throws Exception { - HttpClient client = new HttpClient(); - HttpMethod method = new GetMethod(new URL(baseURL, "bat?mode=sce").toExternalForm()); - int sc = client.executeMethod(method); - assertEquals(HttpServletResponse.SC_OK, sc); - } + @Test + public void testSceListenerInjection(@ArquillianResource URL baseURL) + throws Exception { + CloseableHttpClient client = HttpClients.createDefault(); + HttpGet request = + new HttpGet(new URL(baseURL, "bat?mode=sce").toExternalForm()); + assertEquals(HttpServletResponse.SC_OK, + client.execute(request).getStatusLine().getStatusCode()); + } - @Test - public void testSessionListenerInjection(@ArquillianResource URL baseURL) throws Exception { - HttpClient client = new HttpClient(); - HttpMethod method = new GetMethod(new URL(baseURL, "bat?mode=session").toExternalForm()); - int sc = client.executeMethod(method); - assertEquals(HttpServletResponse.SC_OK, sc); - } + @Test + public void testSessionListenerInjection(@ArquillianResource URL baseURL) + throws Exception { + CloseableHttpClient client = HttpClients.createDefault(); + HttpGet request = + new HttpGet(new URL(baseURL, "bat?mode=session").toExternalForm()); + assertEquals(HttpServletResponse.SC_OK, + client.execute(request).getStatusLine().getStatusCode()); + } } diff --git a/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/injection/ServletInjectionTest.java b/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/injection/ServletInjectionTest.java index cf5c7e9c29..d567f6a82d 100644 --- a/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/injection/ServletInjectionTest.java +++ b/environments/servlet/tests/base/src/main/java/org/jboss/weld/environment/servlet/test/injection/ServletInjectionTest.java @@ -21,12 +21,10 @@ import static org.junit.Assert.assertEquals; import java.net.URL; - import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpMethod; -import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.RunAsClient; import org.jboss.arquillian.junit.Arquillian; @@ -41,18 +39,26 @@ @RunWith(Arquillian.class) public class ServletInjectionTest { - public static final Asset WEB_XML = new ByteArrayAsset(extendDefaultWebXml("Rat Servlet" + RatServlet.class.getName() + " Rat Servlet/rat").getBytes()); - - @Deployment - public static WebArchive createTestArchive() { - return baseDeployment(WEB_XML).addClasses(RatServlet.class, Sewer.class); - } + public static final Asset WEB_XML = new ByteArrayAsset( + extendDefaultWebXml( + "Rat Servlet" + + RatServlet.class.getName() + + (" Rat " + + "Servlet/rat")) + .getBytes()); - @Test - public void testServletInjection(@ArquillianResource URL baseURL) throws Exception { - HttpClient client = new HttpClient(); - HttpMethod method = new GetMethod(new URL(baseURL, "rat").toExternalForm()); - assertEquals(HttpServletResponse.SC_OK, client.executeMethod(method)); - } + @Deployment + public static WebArchive createTestArchive() { + return baseDeployment(WEB_XML).addClasses(RatServlet.class, Sewer.class); + } + @Test + public void testServletInjection(@ArquillianResource URL baseURL) + throws Exception { + CloseableHttpClient client = HttpClients.createDefault(); + HttpGet request = new HttpGet(new URL(baseURL, "rat").toExternalForm()); + assertEquals(HttpServletResponse.SC_OK, + client.execute(request).getStatusLine().getStatusCode()); + } } diff --git a/environments/servlet/tests/jetty/pom.xml b/environments/servlet/tests/jetty/pom.xml index d5668c8656..b735233170 100644 --- a/environments/servlet/tests/jetty/pom.xml +++ b/environments/servlet/tests/jetty/pom.xml @@ -3,7 +3,7 @@ weld-servlet-parent org.jboss.weld.servlet - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml 4.0.0 @@ -19,11 +19,6 @@ test - - commons-httpclient - commons-httpclient - - junit junit @@ -104,6 +99,8 @@ **/CrossContextForwardTest.java + + **/HSCycleTest.java @@ -216,23 +213,6 @@ org.eclipse.jetty jetty-annotations test - - - - org.ow2.asm - asm-commons - - - org.ow2.asm - asm - - - - - - org.ow2.asm - asm - ${jetty9.asm.version} diff --git a/environments/servlet/tests/jetty/src/test/weld-se-coop/org/jboss/weld/environment/servlet/test/se/coop/BootstrapNotNeededTest.java b/environments/servlet/tests/jetty/src/test/weld-se-coop/org/jboss/weld/environment/servlet/test/se/coop/BootstrapNotNeededTest.java index 30634a0bb0..43d4315751 100644 --- a/environments/servlet/tests/jetty/src/test/weld-se-coop/org/jboss/weld/environment/servlet/test/se/coop/BootstrapNotNeededTest.java +++ b/environments/servlet/tests/jetty/src/test/weld-se-coop/org/jboss/weld/environment/servlet/test/se/coop/BootstrapNotNeededTest.java @@ -20,12 +20,12 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.WebClient; import java.net.InetSocketAddress; import java.util.List; import java.util.UUID; - import javax.enterprise.inject.spi.CDI; - import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.jboss.weld.environment.se.Weld; @@ -35,55 +35,55 @@ import org.jboss.weld.environment.servlet.WeldServletLifecycle; import org.junit.Test; -import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebClient; - public class BootstrapNotNeededTest { - @Test - public void testBootstrapNotNeeded() throws Exception { - - String id = UUID.randomUUID().toString(); - - // First boostrap Weld SE - try (WeldContainer container = new Weld(id).initialize()) { - - TestBean testBean = container.instance().select(TestBean.class).get(); - assertNotNull(testBean); - - // @Initialized(ApplicationScoped.class) ContainerInitialized - List initEvents = testBean.getInitEvents(); - assertEquals(1, initEvents.size()); - Object event = initEvents.get(0); - assertTrue(event instanceof ContainerInitialized); - assertEquals(id, ((ContainerInitialized)event).getContainerId()); - - // Test CDIProvider - CDI cdi = CDI.current(); - assertTrue(cdi instanceof WeldContainer); - - // Then start Jetty - Server server = new Server(InetSocketAddress.createUnresolved("localhost", 8080)); - try { - ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); - context.setContextPath("/"); - server.setHandler(context); - context.addServlet(TestServlet.class, "/test"); - context.setAttribute(WeldServletLifecycle.BEAN_MANAGER_ATTRIBUTE_NAME, container.getBeanManager()); - context.addEventListener(new Listener()); - server.start(); - - // @Initialized(ApplicationScoped.class) ServletContext not fired - assertEquals(1, initEvents.size()); - - WebClient webClient = new WebClient(); - webClient.setThrowExceptionOnFailingStatusCode(true); - Page page = webClient.getPage("http://localhost:8080/test"); - assertEquals(testBean.getId(), page.getWebResponse().getContentAsString().trim()); - } finally { - server.stop(); - } - } + @Test + public void testBootstrapNotNeeded() throws Exception { + + String id = UUID.randomUUID().toString(); + + // First boostrap Weld SE + try (WeldContainer container = new Weld(id).initialize()) { + + TestBean testBean = container.instance().select(TestBean.class).get(); + assertNotNull(testBean); + + // @Initialized(ApplicationScoped.class) ContainerInitialized + List initEvents = testBean.getInitEvents(); + assertEquals(1, initEvents.size()); + Object event = initEvents.get(0); + assertTrue(event instanceof ContainerInitialized); + assertEquals(id, ((ContainerInitialized)event).getContainerId()); + + // Test CDIProvider + CDI cdi = CDI.current(); + assertTrue(cdi instanceof WeldContainer); + + // Then start Jetty + Server server = + new Server(InetSocketAddress.createUnresolved("localhost", 8080)); + try { + ServletContextHandler context = + new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/"); + server.setHandler(context); + context.addServlet(TestServlet.class, "/test"); + context.setAttribute(WeldServletLifecycle.BEAN_MANAGER_ATTRIBUTE_NAME, + container.getBeanManager()); + context.addEventListener(new Listener()); + server.start(); + + // @Initialized(ApplicationScoped.class) ServletContext not fired + assertEquals(1, initEvents.size()); + + WebClient webClient = new WebClient(); + webClient.getOptions().setThrowExceptionOnFailingStatusCode(true); + Page page = webClient.getPage("http://localhost:8080/test"); + assertEquals(testBean.getId(), + page.getWebResponse().getContentAsString().trim()); + } finally { + server.stop(); + } } - + } } diff --git a/environments/servlet/tests/jetty/src/test/weld-se-coop/org/jboss/weld/environment/servlet/test/se/coop/builder/WeldSeBuilderTest.java b/environments/servlet/tests/jetty/src/test/weld-se-coop/org/jboss/weld/environment/servlet/test/se/coop/builder/WeldSeBuilderTest.java index d16d3c4314..7bf8469260 100644 --- a/environments/servlet/tests/jetty/src/test/weld-se-coop/org/jboss/weld/environment/servlet/test/se/coop/builder/WeldSeBuilderTest.java +++ b/environments/servlet/tests/jetty/src/test/weld-se-coop/org/jboss/weld/environment/servlet/test/se/coop/builder/WeldSeBuilderTest.java @@ -18,6 +18,8 @@ import static org.junit.Assert.assertEquals; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.WebClient; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.jboss.weld.environment.se.Weld; @@ -25,9 +27,6 @@ import org.jboss.weld.environment.servlet.Listener; import org.junit.Test; -import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebClient; - /** * Testcase for WELD-1927 * @@ -36,57 +35,66 @@ */ public class WeldSeBuilderTest { - @Test - public void testPassingWeldSeBuilderToWeldServlet() throws Exception { - Weld builder = new Weld().disableDiscovery().beanClasses(Cat.class); - ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); - context.addEventListener(Listener.using(builder)); - test(context); - } + @Test + public void testPassingWeldSeBuilderToWeldServlet() throws Exception { + Weld builder = new Weld().disableDiscovery().beanClasses(Cat.class); + ServletContextHandler context = + new ServletContextHandler(ServletContextHandler.SESSIONS); + context.addEventListener(Listener.using(builder)); + test(context); + } - @Test - public void testPassingWeldSeBuilderToWeldServletViaParam() throws Exception { - Weld builder = new Weld().disableDiscovery().beanClasses(Cat.class); - ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); - context.addEventListener(new Listener()); - context.setAttribute(Listener.CONTAINER_ATTRIBUTE_NAME, builder); - test(context); - } + @Test + public void testPassingWeldSeBuilderToWeldServletViaParam() throws Exception { + Weld builder = new Weld().disableDiscovery().beanClasses(Cat.class); + ServletContextHandler context = + new ServletContextHandler(ServletContextHandler.SESSIONS); + context.addEventListener(new Listener()); + context.setAttribute(Listener.CONTAINER_ATTRIBUTE_NAME, builder); + test(context); + } - @Test - public void testPassingWeldSeContainerToWeldServlet() throws Exception { - try (WeldContainer weld = new Weld().disableDiscovery().beanClasses(Cat.class).initialize()) { - ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); - context.addEventListener(Listener.using(weld)); - test(context); - } + @Test + public void testPassingWeldSeContainerToWeldServlet() throws Exception { + try ( + WeldContainer weld = + new Weld().disableDiscovery().beanClasses(Cat.class).initialize()) { + ServletContextHandler context = + new ServletContextHandler(ServletContextHandler.SESSIONS); + context.addEventListener(Listener.using(weld)); + test(context); } + } - @Test - public void testPassingWeldSeContainerToWeldServletViaParam() throws Exception { - try (WeldContainer weld = new Weld().disableDiscovery().beanClasses(Cat.class).initialize()) { - ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); - context.addEventListener(new Listener()); - context.setAttribute(Listener.CONTAINER_ATTRIBUTE_NAME, weld); - test(context); - } + @Test + public void testPassingWeldSeContainerToWeldServletViaParam() + throws Exception { + try ( + WeldContainer weld = + new Weld().disableDiscovery().beanClasses(Cat.class).initialize()) { + ServletContextHandler context = + new ServletContextHandler(ServletContextHandler.SESSIONS); + context.addEventListener(new Listener()); + context.setAttribute(Listener.CONTAINER_ATTRIBUTE_NAME, weld); + test(context); } + } - private void test(ServletContextHandler context) throws Exception { - Server server = new Server(8080); - context.setContextPath("/"); - server.setHandler(context); - context.addServlet(TestServlet.class, "/test"); - server.start(); + private void test(ServletContextHandler context) throws Exception { + Server server = new Server(8080); + context.setContextPath("/"); + server.setHandler(context); + context.addServlet(TestServlet.class, "/test"); + server.start(); - try { - WebClient webClient = new WebClient(); - webClient.setThrowExceptionOnFailingStatusCode(true); - Page page = webClient.getPage("http://localhost:8080/test"); - assertEquals("Kitty", page.getWebResponse().getContentAsString().trim()); - } finally { - // no need to stop Weld here, it is stopped by weld-servlet - server.stop(); - } + try { + WebClient webClient = new WebClient(); + webClient.getOptions().setThrowExceptionOnFailingStatusCode(true); + Page page = webClient.getPage("http://localhost:8080/test"); + assertEquals("Kitty", page.getWebResponse().getContentAsString().trim()); + } finally { + // no need to stop Weld here, it is stopped by weld-servlet + server.stop(); } + } } diff --git a/environments/servlet/tests/tomcat/pom.xml b/environments/servlet/tests/tomcat/pom.xml index d58138fcee..7e0aaea11d 100644 --- a/environments/servlet/tests/tomcat/pom.xml +++ b/environments/servlet/tests/tomcat/pom.xml @@ -3,7 +3,7 @@ weld-servlet-parent org.jboss.weld.servlet - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml 4.0.0 @@ -19,11 +19,6 @@ test - - commons-httpclient - commons-httpclient - - junit junit diff --git a/examples/jsf/login/pom.xml b/examples/jsf/login/pom.xml index ad2916709f..792523f850 100644 --- a/examples/jsf/login/pom.xml +++ b/examples/jsf/login/pom.xml @@ -5,7 +5,7 @@ org.jboss.weld.examples weld-examples-parent - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml @@ -123,4 +123,3 @@ - diff --git a/examples/jsf/numberguess/pom.xml b/examples/jsf/numberguess/pom.xml index 0eddd19c0e..525faa38c8 100644 --- a/examples/jsf/numberguess/pom.xml +++ b/examples/jsf/numberguess/pom.xml @@ -5,7 +5,7 @@ org.jboss.weld.examples weld-examples-parent - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml @@ -282,4 +282,3 @@ - diff --git a/examples/jsf/pastecode/pom.xml b/examples/jsf/pastecode/pom.xml index f6388a9550..99d851e19a 100644 --- a/examples/jsf/pastecode/pom.xml +++ b/examples/jsf/pastecode/pom.xml @@ -5,7 +5,7 @@ org.jboss.weld.examples weld-examples-parent - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml @@ -16,7 +16,7 @@ 4.0.4 - 5.3.2.Final + 5.6.5.Final @@ -231,4 +231,3 @@ - diff --git a/examples/jsf/translator/ear/pom.xml b/examples/jsf/translator/ear/pom.xml index 218e7b6d28..c318173143 100644 --- a/examples/jsf/translator/ear/pom.xml +++ b/examples/jsf/translator/ear/pom.xml @@ -5,7 +5,7 @@ org.jboss.weld.examples.jsf.translator weld-jsf-translator-parent - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT org.jboss.weld.examples.jsf.translator @@ -59,4 +59,3 @@ - diff --git a/examples/jsf/translator/ejb/pom.xml b/examples/jsf/translator/ejb/pom.xml index 338789164c..0af322594d 100644 --- a/examples/jsf/translator/ejb/pom.xml +++ b/examples/jsf/translator/ejb/pom.xml @@ -5,7 +5,7 @@ org.jboss.weld.examples.jsf.translator weld-jsf-translator-parent - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT org.jboss.weld.examples.jsf.translator @@ -42,4 +42,3 @@ - diff --git a/examples/jsf/translator/ftest/pom.xml b/examples/jsf/translator/ftest/pom.xml index 397c2dc489..feee10bead 100644 --- a/examples/jsf/translator/ftest/pom.xml +++ b/examples/jsf/translator/ftest/pom.xml @@ -5,7 +5,7 @@ org.jboss.weld.examples.jsf.translator weld-jsf-translator-parent - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT org.jboss.weld.examples.jsf.translator @@ -35,13 +35,13 @@ junit test - + org.jboss.arquillian.junit arquillian-junit-container test - + org.jboss.arquillian.graphene graphene-webdriver @@ -52,9 +52,9 @@ - ftest + ftest - + arquillian-wildfly-managed @@ -78,4 +78,3 @@ - diff --git a/examples/jsf/translator/pom.xml b/examples/jsf/translator/pom.xml index 927332cdd7..a936c812c3 100644 --- a/examples/jsf/translator/pom.xml +++ b/examples/jsf/translator/pom.xml @@ -4,7 +4,7 @@ org.jboss.weld.examples weld-examples-parent - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml org.jboss.weld.examples.jsf.translator @@ -55,4 +55,3 @@ - diff --git a/examples/jsf/translator/war/pom.xml b/examples/jsf/translator/war/pom.xml index 8f6dd6dcac..99347f457e 100644 --- a/examples/jsf/translator/war/pom.xml +++ b/examples/jsf/translator/war/pom.xml @@ -5,7 +5,7 @@ org.jboss.weld.examples.jsf.translator weld-jsf-translator-parent - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT org.jboss.weld.examples.jsf.translator @@ -36,4 +36,3 @@ - diff --git a/examples/pom.xml b/examples/pom.xml index 8eac20f966..abeaf18fe7 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -4,12 +4,12 @@ org.jboss.weld weld-core-parent - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../pom.xml org.jboss.weld.examples weld-examples-parent - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT pom Weld Examples @@ -105,7 +105,7 @@ 2.0.0.Final 2.3.2 1.1.15 - 2.0.0.Final + 2.1.0.Final 3.0.2 src/ftest/java src/ftest/resources @@ -192,7 +192,7 @@ org.apache.maven.plugins maven-ejb-plugin - 3.0.0 + 3.1.0 3.2 @@ -200,14 +200,14 @@ org.apache.maven.plugins maven-ear-plugin - 3.0.0 + 3.2.0 org.apache.maven.plugins maven-war-plugin - 3.2.0 + 3.3.2 false @@ -446,7 +446,7 @@ jboss-public-repository-group JBoss Public Maven Repository Group - http://repository.jboss.org/nexus/content/groups/public + https://repository.jboss.org/nexus/content/groups/public default true @@ -462,7 +462,7 @@ jboss-public-repository-group JBoss Public Maven Repository Group - http://repository.jboss.org/nexus/content/groups/public + https://repository.jboss.org/nexus/content/groups/public default true diff --git a/examples/se/groovy-numberguess/pom.xml b/examples/se/groovy-numberguess/pom.xml index f8ffa29a6e..751fa8ac12 100644 --- a/examples/se/groovy-numberguess/pom.xml +++ b/examples/se/groovy-numberguess/pom.xml @@ -3,7 +3,7 @@ weld-examples-parent org.jboss.weld.examples - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml 4.0.0 @@ -29,7 +29,7 @@ org.jboss.weld.se weld-se-shaded - + org.codehaus.groovy groovy-all @@ -56,7 +56,7 @@ org.codehaus.gmavenplus gmavenplus-plugin - 1.6 + 1.13.1 diff --git a/examples/se/numberguess/pom.xml b/examples/se/numberguess/pom.xml index dea29b5f17..1aa853f104 100644 --- a/examples/se/numberguess/pom.xml +++ b/examples/se/numberguess/pom.xml @@ -3,7 +3,7 @@ weld-examples-parent org.jboss.weld.examples - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml 4.0.0 @@ -113,7 +113,7 @@ org.jboss.jandex jandex-maven-plugin - 1.0.5 + 1.2.2 make-index diff --git a/impl/build-include-jdk-misc b/impl/build-include-jdk-misc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/impl/build-release-8 b/impl/build-release-8 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/impl/build-test-java8 b/impl/build-test-java8 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/impl/pom.xml b/impl/pom.xml index d085e507c0..f57f03b5e8 100644 --- a/impl/pom.xml +++ b/impl/pom.xml @@ -3,7 +3,7 @@ weld-core-parent org.jboss.weld - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../pom.xml 4.0.0 @@ -79,7 +79,7 @@ spotbugs-annotations true - + org.apache.bcel bcel @@ -104,6 +104,26 @@ + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-java-version + + enforce + + + + + To build this project JDK ${jdk.min.version} (or greater) is required. Please install it. + ${jdk.min.version} + + + + + + org.apache.maven.plugins maven-surefire-plugin @@ -121,12 +141,12 @@ prepare-package - + - + run diff --git a/impl/src/main/java/org/jboss/weld/bean/builtin/DecoratedBeanMetadataBean.java b/impl/src/main/java/org/jboss/weld/bean/builtin/DecoratedBeanMetadataBean.java index c722896c20..7571810676 100644 --- a/impl/src/main/java/org/jboss/weld/bean/builtin/DecoratedBeanMetadataBean.java +++ b/impl/src/main/java/org/jboss/weld/bean/builtin/DecoratedBeanMetadataBean.java @@ -16,19 +16,23 @@ */ package org.jboss.weld.bean.builtin; +import java.io.Serializable; import java.lang.annotation.Annotation; import java.util.Collections; import java.util.Set; - +import javax.enterprise.context.spi.Contextual; +import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.Decorated; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.Decorator; import javax.enterprise.inject.spi.InjectionPoint; - import org.jboss.weld.bean.BeanIdentifiers; import org.jboss.weld.bean.StringBeanIdentifier; +import org.jboss.weld.contexts.WeldCreationalContext; import org.jboss.weld.literal.DecoratedLiteral; +import org.jboss.weld.logging.InterceptorLogger; import org.jboss.weld.manager.BeanManagerImpl; +import org.jboss.weld.util.bean.SerializableForwardingBean; /** * Allows a decorator to obtain information about the bean it decorates. @@ -39,24 +43,58 @@ */ public class DecoratedBeanMetadataBean extends InterceptedBeanMetadataBean { - public DecoratedBeanMetadataBean(BeanManagerImpl beanManager) { - super(new StringBeanIdentifier(BeanIdentifiers.forBuiltInBean(beanManager, Bean.class, Decorated.class.getSimpleName())), beanManager); - } + public DecoratedBeanMetadataBean(BeanManagerImpl beanManager) { + super(new StringBeanIdentifier(BeanIdentifiers.forBuiltInBean( + beanManager, Bean.class, Decorated.class.getSimpleName())), + beanManager); + } - @Override - protected void checkInjectionPoint(InjectionPoint ip) { - if (!(ip.getBean() instanceof Decorator)) { - throw new IllegalArgumentException("@Decorated Bean can only be injected into a decorator."); - } + @Override + protected void checkInjectionPoint(InjectionPoint ip) { + if (!(ip.getBean() instanceof Decorator)) { + throw new IllegalArgumentException( + "@Decorated Bean can only be injected into a decorator."); } + } - @Override - public Set getQualifiers() { - return Collections. singleton(DecoratedLiteral.INSTANCE); + @Override + protected Bean newInstance(InjectionPoint ip, + CreationalContext> ctx) { + checkInjectionPoint(ip); + + WeldCreationalContext decoratorContext = getParentCreationalContext(ctx); + WeldCreationalContext beanContext = + getParentCreationalContext(decoratorContext); + // when there are more decorators present, a CreationalContext hierarchy is + // created between them we want to iterate over this hierarchy to make sure + // we return the original decorated bean + while (beanContext.getContextual() instanceof Decorator) { + beanContext = getParentCreationalContext(beanContext); } + Contextual decoratedContextual = beanContext.getContextual(); - @Override - public String toString() { - return "Implicit Bean [javax.enterprise.inject.spi.Bean] with qualifiers [@Decorated]"; + if (decoratedContextual instanceof Bean) { + Bean bean = (Bean)decoratedContextual; + if (bean instanceof Serializable) { + return bean; + } else { + return SerializableForwardingBean.of(getBeanManager().getContextId(), + bean); + } + } else { + InterceptorLogger.LOG.unableToDetermineInterceptedBean(ip); + return null; } + } + + @Override + public Set getQualifiers() { + return Collections.singleton(DecoratedLiteral.INSTANCE); + } + + @Override + public String toString() { + return "Implicit Bean [javax.enterprise.inject.spi.Bean] with qualifiers " + + "[@Decorated]"; + } } diff --git a/impl/src/main/java/org/jboss/weld/bean/builtin/InstanceImpl.java b/impl/src/main/java/org/jboss/weld/bean/builtin/InstanceImpl.java index 90d32d41b2..08fcdfae56 100644 --- a/impl/src/main/java/org/jboss/weld/bean/builtin/InstanceImpl.java +++ b/impl/src/main/java/org/jboss/weld/bean/builtin/InstanceImpl.java @@ -19,6 +19,7 @@ import static org.jboss.weld.util.Preconditions.checkNotNull; import static org.jboss.weld.util.reflection.Reflections.cast; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.ObjectInputStream; import java.io.ObjectStreamException; import java.io.Serializable; @@ -30,7 +31,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; - import javax.enterprise.context.Dependent; import javax.enterprise.context.spi.AlterableContext; import javax.enterprise.context.spi.Context; @@ -39,7 +39,6 @@ import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.InjectionPoint; import javax.enterprise.util.TypeLiteral; - import org.jboss.weld.bean.proxy.ProxyMethodHandler; import org.jboss.weld.bean.proxy.ProxyObject; import org.jboss.weld.contexts.WeldCreationalContext; @@ -61,336 +60,363 @@ import org.jboss.weld.util.reflection.Formats; import org.jboss.weld.util.reflection.Reflections; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - /** * Helper implementation for Instance for getting instances * * @param * @author Gavin King */ -@SuppressFBWarnings(value = { "SE_NO_SUITABLE_CONSTRUCTOR", "SE_BAD_FIELD" }, justification = "Uses SerializationProxy") -public class InstanceImpl extends AbstractFacade> implements WeldInstance, Serializable { - - private static final long serialVersionUID = -376721889693284887L; - - private final transient Set> allBeans; - private final transient Bean bean; - - private final transient CurrentInjectionPoint currentInjectionPoint; - private final transient InjectionPoint ip; - private final transient EjbSupport ejbSupport; - - public static Instance of(InjectionPoint injectionPoint, CreationalContext creationalContext, BeanManagerImpl beanManager) { - return new InstanceImpl(injectionPoint, creationalContext, beanManager); +@SuppressFBWarnings(value = {"SE_NO_SUITABLE_CONSTRUCTOR", "SE_BAD_FIELD"}, + justification = "Uses SerializationProxy") +public class InstanceImpl extends AbstractFacade> + implements WeldInstance, Serializable { + + private static final long serialVersionUID = -376721889693284887L; + + private final transient Set> allBeans; + private final transient Bean bean; + + private final transient CurrentInjectionPoint currentInjectionPoint; + private final transient InjectionPoint ip; + private final transient EjbSupport ejbSupport; + + public static Instance of(InjectionPoint injectionPoint, + CreationalContext creationalContext, + BeanManagerImpl beanManager) { + return new InstanceImpl(injectionPoint, creationalContext, beanManager); + } + + private InstanceImpl(InjectionPoint injectionPoint, + CreationalContext creationalContext, + BeanManagerImpl beanManager) { + super(injectionPoint, creationalContext, beanManager); + + if (injectionPoint.getQualifiers().isEmpty() && + Object.class.equals(getType())) { + // Do not prefetch the beans for Instance with no qualifiers + allBeans = null; + bean = null; + } else { + this.allBeans = resolveBeans(); + // Optimization for the most common path - non-null bean means we are not + // unsatisfied not ambiguous + if (allBeans.size() == 1) { + this.bean = allBeans.iterator().next(); + } else { + this.bean = null; + } } - private InstanceImpl(InjectionPoint injectionPoint, CreationalContext creationalContext, BeanManagerImpl beanManager) { - super(injectionPoint, creationalContext, beanManager); - - if (injectionPoint.getQualifiers().isEmpty() && Object.class.equals(getType())) { - // Do not prefetch the beans for Instance with no qualifiers - allBeans = null; - bean = null; + this.currentInjectionPoint = + beanManager.getServices().getRequired(CurrentInjectionPoint.class); + // Generate a correct injection point for the bean, we do this by taking the + // original injection point and adjusting the qualifiers and type + this.ip = new DynamicLookupInjectionPoint(getInjectionPoint(), getType(), + getQualifiers()); + this.ejbSupport = beanManager.getServices().get(EjbSupport.class); + } + + public T get() { + checkBeanResolved(); + return getBeanInstance(bean); + } + + /** + * Gets a string representation + * + * @return A string representation + */ + @Override + public String toString() { + return Formats.formatAnnotations(getQualifiers()) + " Instance<" + + Formats.formatType(getType()) + ">"; + } + + public Iterator iterator() { return new InstanceImplIterator(allBeans()); } + + public boolean isAmbiguous() { return allBeans().size() > 1; } + + public boolean isUnsatisfied() { return allBeans().isEmpty(); } + + public WeldInstance select(Annotation... qualifiers) { + return selectInstance(this.getType(), qualifiers); + } + + public WeldInstance select(Class subtype, + Annotation... qualifiers) { + return selectInstance(subtype, qualifiers); + } + + public WeldInstance select(TypeLiteral subtype, + Annotation... qualifiers) { + return selectInstance(subtype.getType(), qualifiers); + } + + @Override + @SuppressWarnings("unchecked") + public WeldInstance select(Type subtype, Annotation... qualifiers) { + // verify if this was invoked on WeldInstance + if (!this.getType().equals(Object.class)) { + throw BeanLogger.LOG.selectByTypeOnlyWorksOnObject(); + } + // This cast should be safe, we make sure that this method is only invoked + // on WeldInstance and any type X will always extend Object + return (WeldInstance)selectInstance(subtype, qualifiers); + } + + private WeldInstance + selectInstance(Type subtype, Annotation[] newQualifiers) { + InjectionPoint modifiedInjectionPoint = new FacadeInjectionPoint( + getBeanManager(), getInjectionPoint(), Instance.class, subtype, + getQualifiers(), newQualifiers); + return new InstanceImpl(modifiedInjectionPoint, getCreationalContext(), + getBeanManager()); + } + + @Override + public void destroy(T instance) { + checkNotNull(instance); + // Attempt to destroy instance which is either a client proxy or a dependent + // session bean proxy + if (instance instanceof ProxyObject) { + ProxyObject proxy = (ProxyObject)instance; + if (proxy.weld_getHandler() instanceof ProxyMethodHandler) { + ProxyMethodHandler handler = + (ProxyMethodHandler)proxy.weld_getHandler(); + Bean bean = handler.getBean(); + if (isSessionBeanProxy(instance) && + Dependent.class.equals(bean.getScope())) { + // Destroy internal reference to a dependent session bean + destroyDependentInstance(instance); + return; } else { - this.allBeans = resolveBeans(); - // Optimization for the most common path - non-null bean means we are not unsatisfied not ambiguous - if (allBeans.size() == 1) { - this.bean = allBeans.iterator().next(); - } else { - this.bean = null; - } + // Destroy contextual instance of a normal-scoped bean + Context context = getBeanManager().getContext(bean.getScope()); + if (context instanceof AlterableContext) { + AlterableContext alterableContext = (AlterableContext)context; + alterableContext.destroy(bean); + return; + } else { + throw BeanLogger.LOG.destroyUnsupported(context); + } } - - this.currentInjectionPoint = beanManager.getServices().getRequired(CurrentInjectionPoint.class); - // Generate a correct injection point for the bean, we do this by taking the original injection point and adjusting the - // qualifiers and type - this.ip = new DynamicLookupInjectionPoint(getInjectionPoint(), getType(), getQualifiers()); - this.ejbSupport = beanManager.getServices().get(EjbSupport.class); - } - - public T get() { - checkBeanResolved(); - return getBeanInstance(bean); - } - - /** - * Gets a string representation - * - * @return A string representation - */ - @Override - public String toString() { - return Formats.formatAnnotations(getQualifiers()) + " Instance<" + Formats.formatType(getType()) + ">"; - } - - public Iterator iterator() { - return new InstanceImplIterator(allBeans()); + } } - - public boolean isAmbiguous() { - return allBeans().size() > 1; + // Attempt to destroy dependent instance which is neither a client proxy nor + // a dependent session bean proxy + destroyDependentInstance(instance); + } + + @Override + public Handler getHandler() { + checkBeanResolved(); + return new HandlerImpl(() -> getBeanInstance(bean), this, bean); + } + + @Override + public boolean isResolvable() { + return allBeans().size() == 1; + } + + @Override + public Iterable> handlers() { + return new Iterable>() { + @Override + public Iterator> + iterator() { + return new HandlerIterator(allBeans()); + } + }; + } + + @Override + public Comparator> getPriorityComparator() { + return new PriorityComparator( + getBeanManager().getServices().get(AnnotationApiAbstraction.class)); + } + + private boolean isSessionBeanProxy(T instance) { + return ejbSupport != null ? ejbSupport.isSessionBeanProxy(instance) : false; + } + + private void destroyDependentInstance(T instance) { + CreationalContext ctx = getCreationalContext(); + if (ctx instanceof WeldCreationalContext) { + WeldCreationalContext weldCtx = cast(ctx); + weldCtx.destroyDependentInstance(instance); } - - public boolean isUnsatisfied() { - return allBeans().isEmpty(); + } + + private void checkBeanResolved() { + if (bean != null) { + return; + } else if (isUnsatisfied()) { + throw BeanManagerLogger.LOG.injectionPointHasUnsatisfiedDependencies( + Formats.formatAnnotations(ip.getQualifiers()), + Formats.formatInjectionPointType(ip.getType()), + InjectionPoints.getUnsatisfiedDependenciesAdditionalInfo( + ip, getBeanManager())); + } else { + throw BeanManagerLogger.LOG.injectionPointHasAmbiguousDependencies( + Formats.formatAnnotations(ip.getQualifiers()), + Formats.formatInjectionPointType(ip.getType()), + WeldCollections.toMultiRowString(allBeans())); } - - public WeldInstance select(Annotation... qualifiers) { - return selectInstance(this.getType(), qualifiers); + } + + private T getBeanInstance(Bean bean) { + final ThreadLocalStackReference stack = + currentInjectionPoint.pushConditionally(ip, + isRegisterableInjectionPoint()); + try { + return Reflections.cast(getBeanManager().getReference( + bean, getType(), getCreationalContext(), false)); + } finally { + stack.pop(); } - - public WeldInstance select(Class subtype, Annotation... qualifiers) { - return selectInstance(subtype, qualifiers); + } + + private boolean isRegisterableInjectionPoint() { + return !getType().equals(InjectionPoint.class); + } + + private Set> allBeans() { + return allBeans == null ? resolveBeans() : allBeans; + } + + private Set> resolveBeans() { + // Perform typesafe resolution, and possibly attempt to resolve the + // ambiguity + Resolvable resolvable = new ResolvableBuilder(getType(), getBeanManager()) + .addQualifiers(getQualifiers()) + .setDeclaringBean(getInjectionPoint().getBean()) + .create(); + TypeSafeBeanResolver beanResolver = getBeanManager().getBeanResolver(); + return beanResolver.resolve(beanResolver.resolve( + resolvable, Reflections.isCacheable(getQualifiers()))); + } + + // Serialization + private Object writeReplace() throws ObjectStreamException { + return new SerializationProxy(this); + } + + private void readObject(ObjectInputStream stream) + throws InvalidObjectException { + throw BeanLogger.LOG.serializationProxyRequired(); + } + + private static class SerializationProxy + extends AbstractFacadeSerializationProxy> { + + private static final long serialVersionUID = 9181171328831559650L; + + public SerializationProxy(InstanceImpl instance) { super(instance); } + + private Object readResolve() throws ObjectStreamException { + return InstanceImpl.of(getInjectionPoint(), getCreationalContext(), + getBeanManager()); } + } - public WeldInstance select(TypeLiteral subtype, Annotation... qualifiers) { - return selectInstance(subtype.getType(), qualifiers); - } + abstract class BeanIterator implements Iterator { - @Override - @SuppressWarnings("unchecked") - public WeldInstance select(Type subtype, Annotation... qualifiers) { - // verify if this was invoked on WeldInstance - if (!this.getType().equals(Object.class)) { - throw BeanLogger.LOG.selectByTypeOnlyWorksOnObject(); - } - // This cast should be safe, we make sure that this method is only invoked on WeldInstance - // and any type X will always extend Object - return (WeldInstance)selectInstance(subtype, qualifiers); - } + protected final Iterator> delegate; - private WeldInstance selectInstance(Type subtype, Annotation[] newQualifiers) { - InjectionPoint modifiedInjectionPoint = new FacadeInjectionPoint(getBeanManager(), getInjectionPoint(), Instance.class, subtype, getQualifiers(), - newQualifiers); - return new InstanceImpl(modifiedInjectionPoint, getCreationalContext(), getBeanManager()); + private BeanIterator(Set> beans) { + this.delegate = beans.iterator(); } @Override - public void destroy(T instance) { - checkNotNull(instance); - // Attempt to destroy instance which is either a client proxy or a dependent session bean proxy - if (instance instanceof ProxyObject) { - ProxyObject proxy = (ProxyObject) instance; - if (proxy.weld_getHandler() instanceof ProxyMethodHandler) { - ProxyMethodHandler handler = (ProxyMethodHandler) proxy.weld_getHandler(); - Bean bean = handler.getBean(); - if (isSessionBeanProxy(instance) && Dependent.class.equals(bean.getScope())) { - // Destroy internal reference to a dependent session bean - destroyDependentInstance(instance); - return; - } else { - // Destroy contextual instance of a normal-scoped bean - Context context = getBeanManager().getContext(bean.getScope()); - if (context instanceof AlterableContext) { - AlterableContext alterableContext = (AlterableContext) context; - alterableContext.destroy(bean); - return; - } else { - throw BeanLogger.LOG.destroyUnsupported(context); - } - } - } - } - // Attempt to destroy dependent instance which is neither a client proxy nor a dependent session bean proxy - destroyDependentInstance(instance); + public boolean hasNext() { + return delegate.hasNext(); } @Override - public Handler getHandler() { - checkBeanResolved(); - return new HandlerImpl(() -> getBeanInstance(bean), this, bean); + public void remove() { + throw BeanLogger.LOG.instanceIteratorRemoveUnsupported(); } + } - @Override - public boolean isResolvable() { - return allBeans().size() == 1; - } + class InstanceImplIterator extends BeanIterator { - @Override - public Iterable> handlers() { - return new Iterable>() { - @Override - public Iterator> iterator() { - return new HandlerIterator(allBeans()); - } - }; - } + private InstanceImplIterator(Set> beans) { super(beans); } @Override - public Comparator> getPriorityComparator() { - return new PriorityComparator(getBeanManager().getServices().get(AnnotationApiAbstraction.class)); + public T next() { + return getBeanInstance(delegate.next()); } + } - private boolean isSessionBeanProxy(T instance) { - return ejbSupport != null ? ejbSupport.isSessionBeanProxy(instance) : false; - } + class HandlerIterator extends BeanIterator> { - private void destroyDependentInstance(T instance) { - CreationalContext ctx = getCreationalContext(); - if (ctx instanceof WeldCreationalContext) { - WeldCreationalContext weldCtx = cast(ctx); - weldCtx.destroyDependentInstance(instance); - } - } + private HandlerIterator(Set> beans) { super(beans); } - private void checkBeanResolved() { - if (bean != null) { - return; - } else if (isUnsatisfied()) { - throw BeanManagerLogger.LOG.injectionPointHasUnsatisfiedDependencies(Formats.formatAnnotations(ip.getQualifiers()), - Formats.formatInjectionPointType(ip.getType()), InjectionPoints.getUnsatisfiedDependenciesAdditionalInfo(ip, getBeanManager())); - } else { - throw BeanManagerLogger.LOG.injectionPointHasAmbiguousDependencies(Formats.formatAnnotations(ip.getQualifiers()), - Formats.formatInjectionPointType(ip.getType()), WeldCollections.toMultiRowString(allBeans())); - } + @Override + public Handler next() { + Bean bean = delegate.next(); + return new HandlerImpl<>( + () -> getBeanInstance(bean), InstanceImpl.this, bean); } + } - private T getBeanInstance(Bean bean) { - final ThreadLocalStackReference stack = currentInjectionPoint.pushConditionally(ip, isRegisterableInjectionPoint()); - try { - return Reflections. cast(getBeanManager().getReference(bean, getType(), getCreationalContext(), false)); - } finally { - stack.pop(); - } - } + private static class HandlerImpl implements Handler { - private boolean isRegisterableInjectionPoint() { - return !getType().equals(InjectionPoint.class); - } + private final LazyValueHolder value; - private Set> allBeans() { - return allBeans == null ? resolveBeans() : allBeans; - } + private final Bean bean; - private Set> resolveBeans() { - // Perform typesafe resolution, and possibly attempt to resolve the ambiguity - Resolvable resolvable = new ResolvableBuilder(getType(), getBeanManager()).addQualifiers(getQualifiers()) - .setDeclaringBean(getInjectionPoint().getBean()).create(); - TypeSafeBeanResolver beanResolver = getBeanManager().getBeanResolver(); - return beanResolver.resolve(beanResolver.resolve(resolvable, Reflections.isCacheable(getQualifiers()))); - } + private final WeakReference> instance; - // Serialization - private Object writeReplace() throws ObjectStreamException { - return new SerializationProxy(this); - } + private final AtomicBoolean isDestroyed; - private void readObject(ObjectInputStream stream) throws InvalidObjectException { - throw BeanLogger.LOG.serializationProxyRequired(); + HandlerImpl(Supplier supplier, WeldInstance instance, Bean bean) { + this.value = LazyValueHolder.forSupplier(supplier); + this.bean = bean; + this.instance = new WeakReference<>(instance); + this.isDestroyed = new AtomicBoolean(false); } - private static class SerializationProxy extends AbstractFacadeSerializationProxy> { - - private static final long serialVersionUID = 9181171328831559650L; - - public SerializationProxy(InstanceImpl instance) { - super(instance); - } - - private Object readResolve() throws ObjectStreamException { - return InstanceImpl.of(getInjectionPoint(), getCreationalContext(), getBeanManager()); - } - + @Override + public T get() { + // attempting to resolve the contextual reference after it has been + // destroyed should throw an ISE + if (isDestroyed.get()) { + throw BeanLogger.LOG + .tryingToResolveContextualReferenceAfterDestroyWasInvoked(this); + } + if (!value.isAvailable() && instance.get() == null) { + // Contextual reference cannot be obtained if the producing Instance + // does not exist + throw BeanLogger.LOG.cannotObtainHandlerContextualReference(this); + } + return value.get(); } - abstract class BeanIterator implements Iterator { - - protected final Iterator> delegate; - - private BeanIterator(Set> beans) { - this.delegate = beans.iterator(); - } - - @Override - public boolean hasNext() { - return delegate.hasNext(); - } - - @Override - public void remove() { - throw BeanLogger.LOG.instanceIteratorRemoveUnsupported(); - } - + @Override + public Bean getBean() { + return bean; } - class InstanceImplIterator extends BeanIterator { - - private InstanceImplIterator(Set> beans) { - super(beans); - } - - @Override - public T next() { - return getBeanInstance(delegate.next()); - } + @Override + public void destroy() { + WeldInstance ref = instance.get(); + if (ref == null) { + BeanLogger.LOG.cannotDestroyHandlerContextualReference(this); + } + if (value.isAvailable() && isDestroyed.compareAndSet(false, true)) { + ref.destroy(value.get()); + } } - class HandlerIterator extends BeanIterator> { - - private HandlerIterator(Set> beans) { - super(beans); - } - - @Override - public Handler next() { - Bean bean = delegate.next(); - return new HandlerImpl<>(() -> getBeanInstance(bean), InstanceImpl.this, bean); - } - + @Override + public void close() { + destroy(); } - private static class HandlerImpl implements Handler { - - private final LazyValueHolder value; - - private final Bean bean; - - private final WeakReference> instance; - - private final AtomicBoolean isDestroyed; - - HandlerImpl(Supplier supplier, WeldInstance instance, Bean bean) { - this.value = LazyValueHolder.forSupplier(supplier); - this.bean = bean; - this.instance = new WeakReference<>(instance); - this.isDestroyed = new AtomicBoolean(false); - } - - @Override - public T get() { - if (!value.isAvailable() && instance.get() == null) { - // Contextual reference cannot be obtained if the producing Instance does not exist - throw BeanLogger.LOG.cannotObtainHandlerContextualReference(this); - } - return value.get(); - } - - @Override - public Bean getBean() { - return bean; - } - - @Override - public void destroy() { - WeldInstance ref = instance.get(); - if (ref == null) { - BeanLogger.LOG.cannotDestroyHandlerContextualReference(this); - } - if (value.isAvailable() && isDestroyed.compareAndSet(false, true)) { - ref.destroy(value.get()); - } - } - - @Override - public void close() { - destroy(); - } - - @Override - public String toString() { - return "HandlerImpl [bean=" + bean + "]"; - } - + @Override + public String toString() { + return "HandlerImpl [bean=" + bean + "]"; } + } } diff --git a/impl/src/main/java/org/jboss/weld/bean/proxy/InterceptedSubclassFactory.java b/impl/src/main/java/org/jboss/weld/bean/proxy/InterceptedSubclassFactory.java index f291d08883..3e70c2eda8 100644 --- a/impl/src/main/java/org/jboss/weld/bean/proxy/InterceptedSubclassFactory.java +++ b/impl/src/main/java/org/jboss/weld/bean/proxy/InterceptedSubclassFactory.java @@ -28,11 +28,10 @@ import java.lang.reflect.TypeVariable; import java.security.AccessController; import java.util.Arrays; +import java.util.Collection; import java.util.HashSet; import java.util.Set; - import javax.enterprise.inject.spi.Bean; - import org.jboss.classfilewriter.AccessFlag; import org.jboss.classfilewriter.ClassFile; import org.jboss.classfilewriter.ClassMethod; @@ -55,604 +54,787 @@ import org.jboss.weld.util.reflection.Reflections; /** - * Factory for producing subclasses that are used by the combined interceptors and decorators stack. + * Factory for producing subclasses that are used by the combined interceptors + * and decorators stack. * * @author Marius Bogoevici */ public class InterceptedSubclassFactory extends ProxyFactory { - // Default proxy class name suffix - public static final String PROXY_SUFFIX = "Subclass"; - - private static final String SUPER_DELEGATE_SUFFIX = "$$super"; - - static final String COMBINED_INTERCEPTOR_AND_DECORATOR_STACK_METHOD_HANDLER_CLASS_NAME = CombinedInterceptorAndDecoratorStackMethodHandler.class.getName(); - static final String[] INVOKE_METHOD_PARAMETERS = new String[] { makeDescriptor(Stack.class), LJAVA_LANG_OBJECT, LJAVA_LANG_REFLECT_METHOD, LJAVA_LANG_REFLECT_METHOD, "[" + LJAVA_LANG_OBJECT }; - - protected static final String PRIVATE_METHOD_HANDLER_FIELD_NAME = "privateMethodHandler"; - - private final Set enhancedMethodSignatures; - private final Set interceptedMethodSignatures; - private Set> interfacesToInspect; - - private final Class proxiedBeanType; - - public InterceptedSubclassFactory(String contextId, Class proxiedBeanType, Set typeClosure, Bean bean, Set enhancedMethodSignatures, Set interceptedMethodSignatures) { - this(contextId, proxiedBeanType, typeClosure, getProxyName(contextId, proxiedBeanType, typeClosure, bean), bean, enhancedMethodSignatures, interceptedMethodSignatures); + // Default proxy class name suffix + public static final String PROXY_SUFFIX = "Subclass"; + + private static final String SUPER_DELEGATE_SUFFIX = "$$super"; + + static final String + COMBINED_INTERCEPTOR_AND_DECORATOR_STACK_METHOD_HANDLER_CLASS_NAME = + CombinedInterceptorAndDecoratorStackMethodHandler.class.getName(); + static final String[] INVOKE_METHOD_PARAMETERS = new String[] { + makeDescriptor(Stack.class), LJAVA_LANG_OBJECT, LJAVA_LANG_REFLECT_METHOD, + LJAVA_LANG_REFLECT_METHOD, "[" + LJAVA_LANG_OBJECT}; + + protected static final String PRIVATE_METHOD_HANDLER_FIELD_NAME = + "privateMethodHandler"; + + private final Set enhancedMethodSignatures; + private final Set interceptedMethodSignatures; + private Set> interfacesToInspect; + + private final Class proxiedBeanType; + + public InterceptedSubclassFactory( + String contextId, Class proxiedBeanType, + Set typeClosure, Bean bean, + Set enhancedMethodSignatures, + Set interceptedMethodSignatures) { + this(contextId, proxiedBeanType, typeClosure, + getProxyName(contextId, proxiedBeanType, typeClosure, bean), bean, + enhancedMethodSignatures, interceptedMethodSignatures); + } + + /** + * Creates a new proxy factory when the name of the proxy class is already + * known, such as during de-serialization + * + * @param proxiedBeanType the super-class for this proxy class + * @param typeClosure the bean types of the bean + * @param enhancedMethodSignatures a restricted set of methods that need to be + * intercepted + */ + public InterceptedSubclassFactory( + String contextId, Class proxiedBeanType, + Set typeClosure, String proxyName, Bean bean, + Set enhancedMethodSignatures, + Set interceptedMethodSignatures) { + super(contextId, proxiedBeanType, typeClosure, proxyName, bean, true); + this.enhancedMethodSignatures = enhancedMethodSignatures; + this.interceptedMethodSignatures = interceptedMethodSignatures; + this.proxiedBeanType = proxiedBeanType; + } + + @Override + public void addInterfacesFromTypeClosure(Set typeClosure, + Class proxiedBeanType) { + // these interfaces we want to scan for method and our proxies will + // implement them + for (Class c : proxiedBeanType.getInterfaces()) { + addInterface(c); } - - /** - * Creates a new proxy factory when the name of the proxy class is already - * known, such as during de-serialization - * - * @param proxiedBeanType the super-class for this proxy class - * @param typeClosure the bean types of the bean - * @param enhancedMethodSignatures a restricted set of methods that need to be intercepted - */ - public InterceptedSubclassFactory(String contextId, Class proxiedBeanType, Set typeClosure, String proxyName, Bean bean, - Set enhancedMethodSignatures, Set interceptedMethodSignatures) { - super(contextId, proxiedBeanType, typeClosure, proxyName, bean, true); - this.enhancedMethodSignatures = enhancedMethodSignatures; - this.interceptedMethodSignatures = interceptedMethodSignatures; - this.proxiedBeanType = proxiedBeanType; + // now we need to go deeper in hierarchy and scan those interfaces for + // additional interfaces with default impls + for (Type type : typeClosure) { + Class c = Reflections.getRawType(type); + if (c.isInterface()) { + addInterfaceToInspect(c); + } } + } - @Override - public void addInterfacesFromTypeClosure(Set typeClosure, Class proxiedBeanType) { - // these interfaces we want to scan for method and our proxies will implement them - for (Class c : proxiedBeanType.getInterfaces()) { - addInterface(c); + private void addInterfaceToInspect(Class iface) { + if (interfacesToInspect == null) { + interfacesToInspect = new HashSet<>(); + } + this.interfacesToInspect.add(iface); + } + + /** + * Returns a suffix to append to the name of the proxy class. The name + * already consists of _$$_Weld, to which the suffix is added. + * This allows the creation of different types of proxies for the same class. + * + * @return a name suffix + */ + protected String getProxyNameSuffix() { return PROXY_SUFFIX; } + + @Override + protected void addMethods(ClassFile proxyClassType, + ClassMethod staticConstructor) { + // Add all class methods for interception + addMethodsFromClass(proxyClassType, staticConstructor); + + // Add special proxy methods + addSpecialMethods(proxyClassType, staticConstructor); + } + + private boolean skipIfBridgeMethod(Method method, + Collection classDeclaredMethods) { + if (method.isBridge()) { + // if it's a bridge method, we need to see if the class also contains an + // actual "impl" of that method if it does, we can skip this method, if it + // doesn't we will need to intercept it + for (Method declaredMethod : classDeclaredMethods) { + // only check non-bridge declared methods + if (declaredMethod.isBridge()) { + continue; } - // now we need to go deeper in hierarchy and scan those interfaces for additional interfaces with default impls - for (Type type : typeClosure) { - Class c = Reflections.getRawType(type); - if (c.isInterface()) { - addInterfaceToInspect(c); + if (method.getName().equals(declaredMethod.getName())) { + Class[] methodParams = method.getParameterTypes(); + Class[] declaredMethodParams = declaredMethod.getParameterTypes(); + if (methodParams.length != declaredMethodParams.length) { + continue; + } + boolean paramsNotMatching = false; + for (int i = 0; i < methodParams.length; i++) { + String methodParamName = methodParams[i].getName(); + String declaredMethodParamName = declaredMethodParams[i].getName(); + if (methodParamName.equals(declaredMethodParamName) || + methodParamName.equals(Object.class.getName())) { + continue; + } else { + paramsNotMatching = true; + break; } + } + if (paramsNotMatching) { + continue; + } + if (!Modifier.isInterface( + declaredMethod.getDeclaringClass().getModifiers())) { + if (method.getReturnType().getName().equals( + Object.class.getName()) || + Modifier.isAbstract(declaredMethod.getModifiers())) { + // bridge method with matching signature has Object as return type + // or the method we compare against is abstract meaning the bridge + // overrides it both cases are a match + return true; + } else { + // as a last resort, we simply check equality of return Type + if (method.getReturnType().getName().equals( + declaredMethod.getReturnType().getName())) { + return true; + } + } + } } + } + return false; + } else { + return false; } - - private void addInterfaceToInspect(Class iface) { - if (interfacesToInspect == null) { - interfacesToInspect = new HashSet<>(); - } - this.interfacesToInspect.add(iface); - } - - /** - * Returns a suffix to append to the name of the proxy class. The name - * already consists of _$$_Weld, to which the suffix is added. - * This allows the creation of different types of proxies for the same class. - * - * @return a name suffix - */ - protected String getProxyNameSuffix() { - return PROXY_SUFFIX; - } - - @Override - protected void addMethods(ClassFile proxyClassType, ClassMethod staticConstructor) { - // Add all class methods for interception - addMethodsFromClass(proxyClassType, staticConstructor); - - // Add special proxy methods - addSpecialMethods(proxyClassType, staticConstructor); - - } - - @Override - protected void addMethodsFromClass(ClassFile proxyClassType, ClassMethod staticConstructor) { - try { - - final Set finalMethods = new HashSet(); - final Set processedBridgeMethods = new HashSet(); - - // Add all methods from the class hierarchy - Class cls = getBeanType(); - while (cls != null) { - Set declaredBridgeMethods = new HashSet(); - for (Method method : AccessController.doPrivileged(new GetDeclaredMethodsAction(cls))) { - - final MethodSignatureImpl methodSignature = new MethodSignatureImpl(method); - - if (!Modifier.isFinal(method.getModifiers()) && !method.isBridge() && enhancedMethodSignatures.contains(methodSignature) - && !finalMethods.contains(methodSignature) && CommonProxiedMethodFilters.NON_PRIVATE_WITHOUT_PACK_PRIVATE_PARAMS.accept(method, getProxySuperclass()) - && !bridgeMethodsContainsMethod(processedBridgeMethods, methodSignature, method.getGenericReturnType(), Modifier.isAbstract(method.getModifiers()))) { - try { - final MethodInformation methodInfo = new RuntimeMethodInformation(method); - - if (interceptedMethodSignatures.contains(methodSignature)) { - // create delegate-to-super method - createDelegateMethod(proxyClassType, method, methodInfo); - - // this method is intercepted - // override a subclass method to delegate to method handler - ClassMethod classMethod = proxyClassType.addMethod(method); - addConstructedGuardToMethodBody(classMethod); - createForwardingMethodBody(classMethod, methodInfo, staticConstructor); - BeanLogger.LOG.addingMethodToProxy(method); - } else { - // this method is not intercepted - // we still need to override and push InterceptionDecorationContext stack to prevent full interception - ClassMethod classMethod = proxyClassType.addMethod(method); - new RunWithinInterceptionDecorationContextGenerator(classMethod, this) { - - @Override - void doWork(CodeAttribute b, ClassMethod classMethod) { - if (Modifier.isPrivate(classMethod.getAccessFlags())) { - // Weld cannot use invokespecial to invoke a private method from the superclass - invokePrivateMethodHandler(b, classMethod, methodInfo, staticConstructor); - } else { - // build the bytecode that invokes the super class method directly - b.aload(0); - // create the method invocation - b.loadMethodParameters(); - b.invokespecial(methodInfo.getDeclaringClass(), methodInfo.getName(), methodInfo.getDescriptor()); - } - // leave the result on top of the stack - } - - @Override - void doReturn(CodeAttribute b, ClassMethod method) { - // assumes doWork() result is on top of the stack - b.returnInstruction(); - } - }.runStartIfNotOnTop(); - } - - - } catch (DuplicateMemberException e) { - // do nothing. This will happen if superclass methods have - // been overridden - } + } + + @Override + protected void addMethodsFromClass(ClassFile proxyClassType, + ClassMethod staticConstructor) { + try { + + final Set finalMethods = new HashSet(); + final Set processedBridgeMethods = + new HashSet(); + + // Add all methods from the class hierarchy + Class cls = getBeanType(); + while (cls != null) { + Set declaredBridgeMethods = new HashSet(); + Collection classDeclaredMethods = Arrays.asList( + AccessController.doPrivileged(new GetDeclaredMethodsAction(cls)) + .clone()); + for (Method method : classDeclaredMethods) { + + final MethodSignatureImpl methodSignature = + new MethodSignatureImpl(method); + + if (!Modifier.isFinal(method.getModifiers()) && + !skipIfBridgeMethod(method, classDeclaredMethods) && + enhancedMethodSignatures.contains(methodSignature) && + !finalMethods.contains(methodSignature) && + CommonProxiedMethodFilters.NON_PRIVATE_WITHOUT_PACK_PRIVATE_PARAMS + .accept(method, getProxySuperclass()) && + !bridgeMethodsContainsMethod( + processedBridgeMethods, methodSignature, + method.getGenericReturnType(), + Modifier.isAbstract(method.getModifiers()))) { + try { + final MethodInformation methodInfo = + new RuntimeMethodInformation(method); + + if (interceptedMethodSignatures.contains(methodSignature)) { + // create delegate-to-super method + createDelegateMethod(proxyClassType, method, methodInfo); + + // this method is intercepted + // override a subclass method to delegate to method handler + ClassMethod classMethod = proxyClassType.addMethod(method); + addConstructedGuardToMethodBody(classMethod); + createForwardingMethodBody(classMethod, methodInfo, + staticConstructor); + BeanLogger.LOG.addingMethodToProxy(method); + } else { + // this method is not intercepted + // we still need to override and push + // InterceptionDecorationContext stack to prevent full + // interception + ClassMethod classMethod = proxyClassType.addMethod(method); + new RunWithinInterceptionDecorationContextGenerator(classMethod, + this) { + @Override + void doWork(CodeAttribute b, ClassMethod classMethod) { + if (Modifier.isPrivate(classMethod.getAccessFlags())) { + // Weld cannot use invokespecial to invoke a private + // method from the superclass + invokePrivateMethodHandler(b, classMethod, methodInfo, + staticConstructor); } else { - if (Modifier.isFinal(method.getModifiers())) { - finalMethods.add(methodSignature); - } - if (method.isBridge()) { - BridgeMethod bridgeMethod = new BridgeMethod(methodSignature, method.getGenericReturnType()); - if (!hasAbstractPackagePrivateSuperClassWithImplementation(cls, bridgeMethod)) { - declaredBridgeMethods.add(bridgeMethod); - } - } + // build the bytecode that invokes the super class method + // directly + b.aload(0); + // create the method invocation + b.loadMethodParameters(); + b.invokespecial(methodInfo.getDeclaringClass(), + methodInfo.getName(), + methodInfo.getDescriptor()); } - } - processedBridgeMethods.addAll(declaredBridgeMethods); - cls = cls.getSuperclass(); + // leave the result on top of the stack + } + + @Override + void doReturn(CodeAttribute b, ClassMethod method) { + // assumes doWork() result is on top of the stack + b.returnInstruction(); + } + }.runStartIfNotOnTop(); + } + + } catch (DuplicateMemberException e) { + // do nothing. This will happen if superclass methods have + // been overridden } - // We want to iterate over pre-defined interfaces (getAdditionalInterfaces()) and also over those we discovered earlier (interfacesToInspect) - Set> allInterfaces = new HashSet<>(getAdditionalInterfaces()); - if (interfacesToInspect != null) { - allInterfaces.addAll(interfacesToInspect); + } else { + if (Modifier.isFinal(method.getModifiers())) { + finalMethods.add(methodSignature); } - for (Class c : allInterfaces) { - for (Method method : c.getMethods()) { - MethodSignature signature = new MethodSignatureImpl(method); - // For interfaces we do not consider return types when going through processed bridge methods - if (enhancedMethodSignatures.contains(signature) && !bridgeMethodsContainsMethod(processedBridgeMethods, signature, null, Modifier.isAbstract(method.getModifiers()))) { - try { - MethodInformation methodInfo = new RuntimeMethodInformation(method); - if (interceptedMethodSignatures.contains(signature) && Reflections.isDefault(method)) { - createDelegateMethod(proxyClassType, method, methodInfo); - - // this method is intercepted - // override a subclass method to delegate to method handler - ClassMethod classMethod = proxyClassType.addMethod(method); - addConstructedGuardToMethodBody(classMethod); - createForwardingMethodBody(classMethod, methodInfo, staticConstructor); - BeanLogger.LOG.addingMethodToProxy(method); - } else { - if (Reflections.isDefault(method)) { - createDelegateMethod(proxyClassType, method, methodInfo); - } else { - final ClassMethod classMethod = proxyClassType.addMethod(method); - createSpecialMethodBody(classMethod, methodInfo, staticConstructor); - BeanLogger.LOG.addingMethodToProxy(method); - } - } - } catch (DuplicateMemberException e) { - } - } - if (method.isBridge()) { - processedBridgeMethods.add(new BridgeMethod(signature, method.getGenericReturnType())); - } - } + if (method.isBridge()) { + BridgeMethod bridgeMethod = new BridgeMethod( + methodSignature, method.getGenericReturnType()); + if (!hasAbstractPackagePrivateSuperClassWithImplementation( + cls, bridgeMethod)) { + declaredBridgeMethods.add(bridgeMethod); + } } - } catch (Exception e) { - throw new WeldException(e); + } } - } - - /** - * Returns true if super class of the parameter exists and is abstract and package private. In such case we want to omit such method. - * - * See WELD-2507 and Oracle issue - https://bugs.java.com/view_bug.do?bug_id=6342411 - * - * @return true if the super class exists and is abstract and package private - */ - private boolean hasAbstractPackagePrivateSuperClassWithImplementation(Class clazz, BridgeMethod bridgeMethod) { - Class superClass = clazz.getSuperclass(); - while (superClass != null) { - if (Modifier.isAbstract(superClass.getModifiers()) && Reflections.isPackagePrivate(superClass.getModifiers())) { - // if superclass is abstract, we need to dig deeper - for (Method method : superClass.getDeclaredMethods()) { - if (bridgeMethod.signature.matches(method) && method.getGenericReturnType().equals(bridgeMethod.returnType) - && !Reflections.isAbstract(method)) { - // this is the case we are after -> methods have same signature and the one in super class has actual implementation - return true; - } + processedBridgeMethods.addAll(declaredBridgeMethods); + cls = cls.getSuperclass(); + } + // We want to iterate over pre-defined interfaces + // (getAdditionalInterfaces()) and also over those we discovered earlier + // (interfacesToInspect) + Set> allInterfaces = new HashSet<>(getAdditionalInterfaces()); + if (interfacesToInspect != null) { + allInterfaces.addAll(interfacesToInspect); + } + for (Class c : allInterfaces) { + for (Method method : c.getMethods()) { + MethodSignature signature = new MethodSignatureImpl(method); + // For interfaces we do not consider return types when going through + // processed bridge methods + if (enhancedMethodSignatures.contains(signature) && + !bridgeMethodsContainsMethod( + processedBridgeMethods, signature, null, + Modifier.isAbstract(method.getModifiers()))) { + try { + MethodInformation methodInfo = + new RuntimeMethodInformation(method); + if (interceptedMethodSignatures.contains(signature) && + Reflections.isDefault(method)) { + createDelegateMethod(proxyClassType, method, methodInfo); + + // this method is intercepted + // override a subclass method to delegate to method handler + ClassMethod classMethod = proxyClassType.addMethod(method); + addConstructedGuardToMethodBody(classMethod); + createForwardingMethodBody(classMethod, methodInfo, + staticConstructor); + BeanLogger.LOG.addingMethodToProxy(method); + } else { + // we only want to add default methods, rest is abstract and + // cannot be invoked + if (Reflections.isDefault(method)) { + createDelegateMethod(proxyClassType, method, methodInfo); } + } + } catch (DuplicateMemberException e) { } - superClass = superClass.getSuperclass(); + } + if (method.isBridge()) { + processedBridgeMethods.add( + new BridgeMethod(signature, method.getGenericReturnType())); + } } - return false; + } + } catch (Exception e) { + throw new WeldException(e); } - - private boolean bridgeMethodsContainsMethod(Set processedBridgeMethods, MethodSignature signature, Type returnType, boolean isMethodAbstract) { - for (BridgeMethod bridgeMethod : processedBridgeMethods) { - if (bridgeMethod.signature.equals(signature)) { - // method signature is equal (name and params) but return type can still differ - if (returnType != null) { - if (bridgeMethod.returnType.equals(Object.class) || isMethodAbstract) { - // bridge method with matching signature has Object as return type - // or the method we compare against is abstract meaning the bridge overrides it - // both cases are a match - return true; - } else { - if (bridgeMethod.returnType instanceof Class && returnType instanceof TypeVariable) { - // in this case we have encountered a bridge method with specific return type in subclass - // and we are observing a TypeVariable return type in superclass, this is a match - return true; - } else { - // as a last resort, we simply check equality of return Type - return bridgeMethod.returnType.equals(returnType); - } - } - } - return true; - } + } + + /** + * Returns true if super class of the parameter exists and is abstract and + * package private. In such case we want to omit such method. + * + * See WELD-2507 and Oracle issue - + * https://bugs.java.com/view_bug.do?bug_id=6342411 + * + * @return true if the super class exists and is abstract and package private + */ + private boolean hasAbstractPackagePrivateSuperClassWithImplementation( + Class clazz, BridgeMethod bridgeMethod) { + Class superClass = clazz.getSuperclass(); + while (superClass != null) { + if (Modifier.isAbstract(superClass.getModifiers()) && + Reflections.isPackagePrivate(superClass.getModifiers())) { + // if superclass is abstract, we need to dig deeper + for (Method method : superClass.getDeclaredMethods()) { + if (bridgeMethod.signature.matches(method) && + method.getGenericReturnType().equals(bridgeMethod.returnType) && + !Reflections.isAbstract(method)) { + // this is the case we are after -> methods have same signature and + // the one in super class has actual implementation + return true; + } } - return false; + } + superClass = superClass.getSuperclass(); } - - protected void createForwardingMethodBody(ClassMethod classMethod, MethodInformation method, ClassMethod staticConstructor) { - createInterceptorBody(classMethod, method, true, staticConstructor); - } - - /** - * Creates the given method on the proxy class where the implementation - * forwards the call directly to the method handler. - *

- * the generated bytecode is equivalent to: - *

- * return (RetType) methodHandler.invoke(this,param1,param2); - * - * @param methodInfo any JLR method - * @param delegateToSuper - * @return the method byte code - */ - - protected void createInterceptorBody(ClassMethod method, MethodInformation methodInfo, boolean delegateToSuper, ClassMethod staticConstructor) { - - invokeMethodHandler(method, methodInfo, true, DEFAULT_METHOD_RESOLVER, delegateToSuper, staticConstructor); - } - - private void createDelegateToSuper(ClassMethod classMethod, MethodInformation method) { - createDelegateToSuper(classMethod, method, classMethod.getClassFile().getSuperclass()); + return false; + } + + private boolean + bridgeMethodsContainsMethod(Set processedBridgeMethods, + MethodSignature signature, Type returnType, + boolean isMethodAbstract) { + for (BridgeMethod bridgeMethod : processedBridgeMethods) { + if (bridgeMethod.signature.equals(signature)) { + // method signature is equal (name and params) but return type can still + // differ + if (returnType != null) { + if (bridgeMethod.returnType.equals(Object.class) || + isMethodAbstract) { + // bridge method with matching signature has Object as return type + // or the method we compare against is abstract meaning the bridge + // overrides it both cases are a match + return true; + } else { + if (bridgeMethod.returnType instanceof Class && + returnType instanceof TypeVariable) { + // in this case we have encountered a bridge method with specific + // return type in subclass and we are observing a TypeVariable + // return type in superclass, this is a match + return true; + } else { + // as a last resort, we simply check equality of return Type + return bridgeMethod.returnType.equals(returnType); + } + } + } + return true; + } } - - private void createDelegateToSuper(ClassMethod classMethod, MethodInformation method, String className) { - CodeAttribute b = classMethod.getCodeAttribute(); - // first generate the invokespecial call to the super class method + return false; + } + + protected void createForwardingMethodBody(ClassMethod classMethod, + MethodInformation method, + ClassMethod staticConstructor) { + createInterceptorBody(classMethod, method, true, staticConstructor); + } + + /** + * Creates the given method on the proxy class where the implementation + * forwards the call directly to the method handler. + *

+ * the generated bytecode is equivalent to: + *

+ * return (RetType) methodHandler.invoke(this,param1,param2); + * + * @param methodInfo any JLR method + * @param delegateToSuper + * @return the method byte code + */ + + protected void createInterceptorBody(ClassMethod method, + MethodInformation methodInfo, + boolean delegateToSuper, + ClassMethod staticConstructor) { + + invokeMethodHandler(method, methodInfo, true, DEFAULT_METHOD_RESOLVER, + delegateToSuper, staticConstructor); + } + + private void createDelegateToSuper(ClassMethod classMethod, + MethodInformation method) { + createDelegateToSuper(classMethod, method, + classMethod.getClassFile().getSuperclass()); + } + + private void createDelegateToSuper(ClassMethod classMethod, + MethodInformation method, + String className) { + CodeAttribute b = classMethod.getCodeAttribute(); + // first generate the invokespecial call to the super class method + b.aload(0); + b.loadMethodParameters(); + b.invokespecial(className, method.getName(), method.getDescriptor()); + b.returnInstruction(); + } + + /** + * calls methodHandler.invoke for a given method + * + * @param methodInfo declaring class of the method + * @param addReturnInstruction set to true you want to return the result of + * @param bytecodeMethodResolver The method resolver + * @param addProceed + */ + protected void + invokeMethodHandler(ClassMethod method, MethodInformation methodInfo, + boolean addReturnInstruction, + BytecodeMethodResolver bytecodeMethodResolver, + boolean addProceed, ClassMethod staticConstructor) { + // now we need to build the bytecode. The order we do this in is as + // follows: + // load methodHandler + // dup the methodhandler + // invoke isDisabledHandler on the method handler to figure out of this is + // a self invocation. + + // load this + // load the method object + // load the proceed method that invokes the superclass version of the + // current method + // create a new array the same size as the number of parameters + // push our parameter values into the array + // invokeinterface the invoke method + // add checkcast to cast the result to the return type, or unbox if + // primitive + // add an appropriate return instruction + final CodeAttribute b = method.getCodeAttribute(); + b.aload(0); + getMethodHandlerField(method.getClassFile(), b); + + if (addProceed) { + b.dup(); + + // get the Stack + b.invokestatic(InterceptionDecorationContext.class.getName(), "getStack", + "()" + DescriptorUtils.makeDescriptor(Stack.class)); + + // this is a self invocation optimisation + // test to see if this is a self invocation, and if so invokespecial the + // superclass method directly + // Do not optimize in case of private and default methods + if (!Reflections.isDefault(methodInfo.getMethod()) && + !Modifier.isPrivate(method.getAccessFlags())) { + b.dupX1(); // Handler, Stack -> Stack, Handler, Stack + b.invokevirtual( + COMBINED_INTERCEPTOR_AND_DECORATOR_STACK_METHOD_HANDLER_CLASS_NAME, + "isDisabledHandler", + "(" + DescriptorUtils.makeDescriptor(Stack.class) + ")" + + BytecodeUtils.BOOLEAN_CLASS_DESCRIPTOR); + b.iconst(0); + BranchEnd invokeSuperDirectly = b.ifIcmpeq(); + // now build the bytecode that invokes the super class method + b.pop2(); // pop Stack and Handler b.aload(0); + // create the method invocation b.loadMethodParameters(); - b.invokespecial(className, method.getName(), method.getDescriptor()); + b.invokespecial(methodInfo.getDeclaringClass(), methodInfo.getName(), + methodInfo.getDescriptor()); b.returnInstruction(); + b.branchEnd(invokeSuperDirectly); + } + } else { + b.aconstNull(); } - /** - * calls methodHandler.invoke for a given method - * - * @param methodInfo declaring class of the method - * @param addReturnInstruction set to true you want to return the result of - * @param bytecodeMethodResolver The method resolver - * @param addProceed - */ - protected void invokeMethodHandler(ClassMethod method, MethodInformation methodInfo, boolean addReturnInstruction, BytecodeMethodResolver bytecodeMethodResolver, boolean addProceed, ClassMethod staticConstructor) { - // now we need to build the bytecode. The order we do this in is as - // follows: - // load methodHandler - // dup the methodhandler - // invoke isDisabledHandler on the method handler to figure out of this is - // a self invocation. - - // load this - // load the method object - // load the proceed method that invokes the superclass version of the - // current method - // create a new array the same size as the number of parameters - // push our parameter values into the array - // invokeinterface the invoke method - // add checkcast to cast the result to the return type, or unbox if - // primitive - // add an appropriate return instruction - final CodeAttribute b = method.getCodeAttribute(); - b.aload(0); - getMethodHandlerField(method.getClassFile(), b); - - if (addProceed) { - b.dup(); - - // get the Stack - b.invokestatic(InterceptionDecorationContext.class.getName(), "getStack", "()" + DescriptorUtils.makeDescriptor(Stack.class)); - - // this is a self invocation optimisation - // test to see if this is a self invocation, and if so invokespecial the - // superclass method directly - // Do not optimize in case of private and default methods - if (!Reflections.isDefault(methodInfo.getMethod()) && !Modifier.isPrivate(method.getAccessFlags())) { - b.dupX1(); // Handler, Stack -> Stack, Handler, Stack - b.invokevirtual(COMBINED_INTERCEPTOR_AND_DECORATOR_STACK_METHOD_HANDLER_CLASS_NAME, "isDisabledHandler", - "(" + DescriptorUtils.makeDescriptor(Stack.class) + ")" + BytecodeUtils.BOOLEAN_CLASS_DESCRIPTOR); - b.iconst(0); - BranchEnd invokeSuperDirectly = b.ifIcmpeq(); - // now build the bytecode that invokes the super class method - b.pop2(); // pop Stack and Handler - b.aload(0); - // create the method invocation - b.loadMethodParameters(); - b.invokespecial(methodInfo.getDeclaringClass(), methodInfo.getName(), methodInfo.getDescriptor()); - b.returnInstruction(); - b.branchEnd(invokeSuperDirectly); - } - } else { - b.aconstNull(); - } - - b.aload(0); - bytecodeMethodResolver.getDeclaredMethod(method, methodInfo.getDeclaringClass(), methodInfo.getName(), methodInfo.getParameterTypes(), staticConstructor); - - if (addProceed) { - if (Modifier.isPrivate(method.getAccessFlags())) { - // If the original method is private we can't use WeldSubclass.method$$super() as proceed - bytecodeMethodResolver.getDeclaredMethod(method, methodInfo.getDeclaringClass(), methodInfo.getName(), methodInfo.getParameterTypes(), - staticConstructor); - } else { - bytecodeMethodResolver.getDeclaredMethod(method, method.getClassFile().getName(), methodInfo.getName() + SUPER_DELEGATE_SUFFIX, - methodInfo.getParameterTypes(), staticConstructor); - } - } else { - b.aconstNull(); - } - - b.iconst(methodInfo.getParameterTypes().length); - b.anewarray(Object.class.getName()); - - int localVariableCount = 1; - - for (int i = 0; i < methodInfo.getParameterTypes().length; ++i) { - String typeString = methodInfo.getParameterTypes()[i]; - b.dup(); // duplicate the array reference - b.iconst(i); - // load the parameter value - BytecodeUtils.addLoadInstruction(b, typeString, localVariableCount); - // box the parameter if necessary - Boxing.boxIfNessesary(b, typeString); - // and store it in the array - b.aastore(); - if (isWide(typeString)) { - localVariableCount = localVariableCount + 2; - } else { - localVariableCount++; - } - } - // now we have all our arguments on the stack - // lets invoke the method - b.invokeinterface(StackAwareMethodHandler.class.getName(), INVOKE_METHOD_NAME, LJAVA_LANG_OBJECT, INVOKE_METHOD_PARAMETERS); - if (addReturnInstruction) { - // now we need to return the appropriate type - if (methodInfo.getReturnType().equals(BytecodeUtils.VOID_CLASS_DESCRIPTOR)) { - b.returnInstruction(); - } else if (isPrimitive(methodInfo.getReturnType())) { - Boxing.unbox(b,method.getReturnType()); - b.returnInstruction(); - } else { - b.checkcast(BytecodeUtils.getName(methodInfo.getReturnType())); - b.returnInstruction(); - } - } + b.aload(0); + bytecodeMethodResolver.getDeclaredMethod( + method, methodInfo.getDeclaringClass(), methodInfo.getName(), + methodInfo.getParameterTypes(), staticConstructor); + + if (addProceed) { + if (Modifier.isPrivate(method.getAccessFlags())) { + // If the original method is private we can't use + // WeldSubclass.method$$super() as proceed + bytecodeMethodResolver.getDeclaredMethod( + method, methodInfo.getDeclaringClass(), methodInfo.getName(), + methodInfo.getParameterTypes(), staticConstructor); + } else { + bytecodeMethodResolver.getDeclaredMethod( + method, method.getClassFile().getName(), + methodInfo.getName() + SUPER_DELEGATE_SUFFIX, + methodInfo.getParameterTypes(), staticConstructor); + } + } else { + b.aconstNull(); } - /** - * Adds methods requiring special implementations rather than just - * delegation. - * - * @param proxyClassType the Javassist class description for the proxy type - */ - protected void addSpecialMethods(ClassFile proxyClassType, ClassMethod staticConstructor) { - try { - // Add special methods for interceptors - for (Method method : LifecycleMixin.class.getMethods()) { - BeanLogger.LOG.addingMethodToProxy(method); - MethodInformation methodInfo = new RuntimeMethodInformation(method); - createInterceptorBody(proxyClassType.addMethod(method), methodInfo, false, staticConstructor); - } - Method getInstanceMethod = TargetInstanceProxy.class.getMethod("weld_getTargetInstance"); - Method getInstanceClassMethod = TargetInstanceProxy.class.getMethod("weld_getTargetClass"); - generateGetTargetInstanceBody(proxyClassType.addMethod(getInstanceMethod)); - generateGetTargetClassBody(proxyClassType.addMethod(getInstanceClassMethod)); - - Method setMethodHandlerMethod = ProxyObject.class.getMethod("weld_setHandler", MethodHandler.class); - generateSetMethodHandlerBody(proxyClassType.addMethod(setMethodHandlerMethod)); - - Method getMethodHandlerMethod = ProxyObject.class.getMethod("weld_getHandler"); - generateGetMethodHandlerBody(proxyClassType.addMethod(getMethodHandlerMethod)); - } catch (Exception e) { - throw new WeldException(e); - } + b.iconst(methodInfo.getParameterTypes().length); + b.anewarray(Object.class.getName()); + + int localVariableCount = 1; + + for (int i = 0; i < methodInfo.getParameterTypes().length; ++i) { + String typeString = methodInfo.getParameterTypes()[i]; + b.dup(); // duplicate the array reference + b.iconst(i); + // load the parameter value + BytecodeUtils.addLoadInstruction(b, typeString, localVariableCount); + // box the parameter if necessary + Boxing.boxIfNessesary(b, typeString); + // and store it in the array + b.aastore(); + if (isWide(typeString)) { + localVariableCount = localVariableCount + 2; + } else { + localVariableCount++; + } } - - private static void generateGetTargetInstanceBody(ClassMethod method) { - final CodeAttribute b = method.getCodeAttribute(); - b.aload(0); + // now we have all our arguments on the stack + // lets invoke the method + b.invokeinterface(StackAwareMethodHandler.class.getName(), + INVOKE_METHOD_NAME, LJAVA_LANG_OBJECT, + INVOKE_METHOD_PARAMETERS); + if (addReturnInstruction) { + // now we need to return the appropriate type + if (methodInfo.getReturnType().equals( + BytecodeUtils.VOID_CLASS_DESCRIPTOR)) { b.returnInstruction(); - } - - private static void generateGetTargetClassBody(ClassMethod method) { - final CodeAttribute b = method.getCodeAttribute(); - BytecodeUtils.pushClassType(b, method.getClassFile().getSuperclass()); + } else if (isPrimitive(methodInfo.getReturnType())) { + Boxing.unbox(b, method.getReturnType()); + b.returnInstruction(); + } else { + b.checkcast(BytecodeUtils.getName(methodInfo.getReturnType())); b.returnInstruction(); + } } - - @Override - public Class getBeanType() { - return proxiedBeanType; + } + + /** + * Adds methods requiring special implementations rather than just + * delegation. + * + * @param proxyClassType the Javassist class description for the proxy type + */ + protected void addSpecialMethods(ClassFile proxyClassType, + ClassMethod staticConstructor) { + try { + // Add special methods for interceptors + for (Method method : LifecycleMixin.class.getMethods()) { + BeanLogger.LOG.addingMethodToProxy(method); + MethodInformation methodInfo = new RuntimeMethodInformation(method); + createInterceptorBody(proxyClassType.addMethod(method), methodInfo, + false, staticConstructor); + } + Method getInstanceMethod = + TargetInstanceProxy.class.getMethod("weld_getTargetInstance"); + Method getInstanceClassMethod = + TargetInstanceProxy.class.getMethod("weld_getTargetClass"); + generateGetTargetInstanceBody( + proxyClassType.addMethod(getInstanceMethod)); + generateGetTargetClassBody( + proxyClassType.addMethod(getInstanceClassMethod)); + + Method setMethodHandlerMethod = + ProxyObject.class.getMethod("weld_setHandler", MethodHandler.class); + generateSetMethodHandlerBody( + proxyClassType.addMethod(setMethodHandlerMethod)); + + Method getMethodHandlerMethod = + ProxyObject.class.getMethod("weld_getHandler"); + generateGetMethodHandlerBody( + proxyClassType.addMethod(getMethodHandlerMethod)); + } catch (Exception e) { + throw new WeldException(e); } - - @Override - protected Class getMethodHandlerType() { - return CombinedInterceptorAndDecoratorStackMethodHandler.class; + } + + private static void generateGetTargetInstanceBody(ClassMethod method) { + final CodeAttribute b = method.getCodeAttribute(); + b.aload(0); + b.returnInstruction(); + } + + private static void generateGetTargetClassBody(ClassMethod method) { + final CodeAttribute b = method.getCodeAttribute(); + BytecodeUtils.pushClassType(b, method.getClassFile().getSuperclass()); + b.returnInstruction(); + } + + @Override + public Class getBeanType() { + return proxiedBeanType; + } + + @Override + protected Class getMethodHandlerType() { + return CombinedInterceptorAndDecoratorStackMethodHandler.class; + } + + @Override + protected boolean isUsingProxyInstantiator() { + return false; + } + + @SuppressWarnings("unchecked") + private void createDelegateMethod(ClassFile proxyClassType, Method method, + MethodInformation methodInformation) { + int modifiers = + (method.getModifiers() | AccessFlag.SYNTHETIC | AccessFlag.PRIVATE) & + ~AccessFlag.PUBLIC & ~AccessFlag.PROTECTED; + ClassMethod delegatingMethod = proxyClassType.addMethod( + modifiers, method.getName() + SUPER_DELEGATE_SUFFIX, + DescriptorUtils.makeDescriptor(method.getReturnType()), + DescriptorUtils.parameterDescriptors(method.getParameterTypes())); + delegatingMethod.addCheckedExceptions( + (Class[])method.getExceptionTypes()); + createDelegateToSuper(delegatingMethod, methodInformation); + } + + private void invokePrivateMethodHandler(CodeAttribute b, + ClassMethod classMethod, + MethodInformation methodInfo, + ClassMethod staticConstructor) { + try { + classMethod.getClassFile().addField(AccessFlag.PRIVATE, + PRIVATE_METHOD_HANDLER_FIELD_NAME, + MethodHandler.class); + } catch (DuplicateMemberException ignored) { } - - @Override - protected boolean isUsingProxyInstantiator() { - return false; - } - - @SuppressWarnings("unchecked") - private void createDelegateMethod(ClassFile proxyClassType, Method method, MethodInformation methodInformation) { - int modifiers = (method.getModifiers() | AccessFlag.SYNTHETIC | AccessFlag.PRIVATE) & ~AccessFlag.PUBLIC - & ~AccessFlag.PROTECTED; - ClassMethod delegatingMethod = proxyClassType.addMethod(modifiers, method.getName() + SUPER_DELEGATE_SUFFIX, - DescriptorUtils.makeDescriptor(method.getReturnType()), - DescriptorUtils.parameterDescriptors(method.getParameterTypes())); - delegatingMethod.addCheckedExceptions((Class[]) method.getExceptionTypes()); - createDelegateToSuper(delegatingMethod, methodInformation); + // 1. Load private method handler + b.aload(0); + b.getfield(classMethod.getClassFile().getName(), + PRIVATE_METHOD_HANDLER_FIELD_NAME, + DescriptorUtils.makeDescriptor(MethodHandler.class)); + // 2. Load this + b.aload(0); + // 3. Load method + DEFAULT_METHOD_RESOLVER.getDeclaredMethod( + classMethod, methodInfo.getDeclaringClass(), methodInfo.getName(), + methodInfo.getParameterTypes(), staticConstructor); + // 4. No proceed method + b.aconstNull(); + // 5. Load method params + b.iconst(methodInfo.getParameterTypes().length); + b.anewarray(Object.class.getName()); + int localVariableCount = 1; + for (int i = 0; i < methodInfo.getParameterTypes().length; ++i) { + String typeString = methodInfo.getParameterTypes()[i]; + b.dup(); // duplicate the array reference + b.iconst(i); + // load the parameter value + BytecodeUtils.addLoadInstruction(b, typeString, localVariableCount); + // box the parameter if necessary + Boxing.boxIfNessesary(b, typeString); + // and store it in the array + b.aastore(); + if (isWide(typeString)) { + localVariableCount = localVariableCount + 2; + } else { + localVariableCount++; + } } - - private void invokePrivateMethodHandler(CodeAttribute b, ClassMethod classMethod, MethodInformation methodInfo, ClassMethod staticConstructor) { - try { - classMethod.getClassFile().addField(AccessFlag.PRIVATE, PRIVATE_METHOD_HANDLER_FIELD_NAME, MethodHandler.class); - } catch (DuplicateMemberException ignored) { - } - // 1. Load private method handler - b.aload(0); - b.getfield(classMethod.getClassFile().getName(), PRIVATE_METHOD_HANDLER_FIELD_NAME, - DescriptorUtils.makeDescriptor(MethodHandler.class)); - // 2. Load this - b.aload(0); - // 3. Load method - DEFAULT_METHOD_RESOLVER.getDeclaredMethod(classMethod, methodInfo.getDeclaringClass(), methodInfo.getName(), methodInfo.getParameterTypes(), - staticConstructor); - // 4. No proceed method - b.aconstNull(); - // 5. Load method params - b.iconst(methodInfo.getParameterTypes().length); - b.anewarray(Object.class.getName()); - int localVariableCount = 1; - for (int i = 0; i < methodInfo.getParameterTypes().length; ++i) { - String typeString = methodInfo.getParameterTypes()[i]; - b.dup(); // duplicate the array reference - b.iconst(i); - // load the parameter value - BytecodeUtils.addLoadInstruction(b, typeString, localVariableCount); - // box the parameter if necessary - Boxing.boxIfNessesary(b, typeString); - // and store it in the array - b.aastore(); - if (isWide(typeString)) { - localVariableCount = localVariableCount + 2; - } else { - localVariableCount++; - } - } - // Invoke PrivateMethodHandler - b.invokeinterface(MethodHandler.class.getName(), INVOKE_METHOD_NAME, LJAVA_LANG_OBJECT, - new String[] { LJAVA_LANG_OBJECT, LJAVA_LANG_REFLECT_METHOD, LJAVA_LANG_REFLECT_METHOD, "[" + LJAVA_LANG_OBJECT }); - if (methodInfo.getReturnType().equals(BytecodeUtils.VOID_CLASS_DESCRIPTOR)) { - // No-op - } else if (isPrimitive(methodInfo.getReturnType())) { - Boxing.unbox(b, methodInfo.getReturnType()); - } else { - b.checkcast(BytecodeUtils.getName(methodInfo.getReturnType())); - } + // Invoke PrivateMethodHandler + b.invokeinterface( + MethodHandler.class.getName(), INVOKE_METHOD_NAME, LJAVA_LANG_OBJECT, + new String[] {LJAVA_LANG_OBJECT, LJAVA_LANG_REFLECT_METHOD, + LJAVA_LANG_REFLECT_METHOD, "[" + LJAVA_LANG_OBJECT}); + if (methodInfo.getReturnType().equals( + BytecodeUtils.VOID_CLASS_DESCRIPTOR)) { + // No-op + } else if (isPrimitive(methodInfo.getReturnType())) { + Boxing.unbox(b, methodInfo.getReturnType()); + } else { + b.checkcast(BytecodeUtils.getName(methodInfo.getReturnType())); } - - /** - * If the given instance represents a proxy and its class is synthetic and its class name ends with {@value #PROXY_SUFFIX}, attempt to find the - * {@value #PRIVATE_METHOD_HANDLER_FIELD_NAME} field and set its value to {@link PrivateMethodHandler#INSTANCE}. - * - * @param instance - */ - public static void setPrivateMethodHandler(T instance) { - if (instance instanceof ProxyObject && instance.getClass().isSynthetic() && instance.getClass().getName().endsWith(PROXY_SUFFIX) - && SecurityActions.hasDeclaredField(instance.getClass(), PRIVATE_METHOD_HANDLER_FIELD_NAME)) { - try { - Field privateMethodHandlerField = SecurityActions.getDeclaredField(instance.getClass(), PRIVATE_METHOD_HANDLER_FIELD_NAME); - SecurityActions.ensureAccessible(privateMethodHandlerField); - privateMethodHandlerField.set(instance, PrivateMethodHandler.INSTANCE); - } catch (NoSuchFieldException ignored) { - } catch (IllegalArgumentException | IllegalAccessException e) { - throw new RuntimeException(e); - } - } + } + + /** + * If the given instance represents a proxy and its class is synthetic and its + * class name ends with {@value #PROXY_SUFFIX}, attempt to find the + * {@value #PRIVATE_METHOD_HANDLER_FIELD_NAME} field and set its value to + * {@link PrivateMethodHandler#INSTANCE}. + * + * @param instance + */ + public static void setPrivateMethodHandler(T instance) { + if (instance instanceof ProxyObject && instance.getClass().isSynthetic() && + instance.getClass().getName().endsWith(PROXY_SUFFIX) && + SecurityActions.hasDeclaredField(instance.getClass(), + PRIVATE_METHOD_HANDLER_FIELD_NAME)) { + try { + Field privateMethodHandlerField = SecurityActions.getDeclaredField( + instance.getClass(), PRIVATE_METHOD_HANDLER_FIELD_NAME); + SecurityActions.ensureAccessible(privateMethodHandlerField); + privateMethodHandlerField.set(instance, PrivateMethodHandler.INSTANCE); + } catch (NoSuchFieldException ignored) { + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } } + } - private static class BridgeMethod { + private static class BridgeMethod { - private final Type returnType; + private final Type returnType; - private final MethodSignature signature; + private final MethodSignature signature; - public BridgeMethod(MethodSignature signature, Type returnType) { - this.signature = signature; - this.returnType = returnType; - } + public BridgeMethod(MethodSignature signature, Type returnType) { + this.signature = signature; + this.returnType = returnType; + } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((returnType == null) ? 0 : returnType.hashCode()); - result = prime * result + ((signature == null) ? 0 : signature.hashCode()); - return result; - } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = + prime * result + ((returnType == null) ? 0 : returnType.hashCode()); + result = + prime * result + ((signature == null) ? 0 : signature.hashCode()); + return result; + } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof BridgeMethod)) { - return false; - } - BridgeMethod other = (BridgeMethod) obj; - if (returnType == null) { - if (other.returnType != null) { - return false; - } - } else if (!returnType.equals(other.returnType)) { - return false; - } - if (signature == null) { - if (other.signature != null) { - return false; - } - } else if (!signature.equals(other.signature)) { - return false; - } - return true; + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof BridgeMethod)) { + return false; + } + BridgeMethod other = (BridgeMethod)obj; + if (returnType == null) { + if (other.returnType != null) { + return false; } - - @Override - public String toString() { - return new StringBuilder().append("method ").append(returnType).append(" ").append(signature.getMethodName()) - .append(Arrays.toString(signature.getParameterTypes()).replace('[', '(').replace(']', ')')).toString(); + } else if (!returnType.equals(other.returnType)) { + return false; + } + if (signature == null) { + if (other.signature != null) { + return false; } - + } else if (!signature.equals(other.signature)) { + return false; + } + return true; } -} \ No newline at end of file + @Override + public String toString() { + return new StringBuilder() + .append("method ") + .append(returnType) + .append(" ") + .append(signature.getMethodName()) + .append(Arrays.toString(signature.getParameterTypes()) + .replace('[', '(') + .replace(']', ')')) + .toString(); + } + } +} diff --git a/impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java b/impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java index d24df6b94d..300098a2ac 100644 --- a/impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java +++ b/impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java @@ -1,8 +1,8 @@ /* * JBoss, Home of Professional Open Source - * Copyright 2008, Red Hat, Inc. and/or its affiliates, and individual contributors - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. + * Copyright 2008, Red Hat, Inc. and/or its affiliates, and individual + * contributors by the @authors tag. See the copyright.txt in the distribution + * for a full listing of individual contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,14 +35,12 @@ import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; - import javax.enterprise.inject.spi.Bean; - import org.jboss.classfilewriter.AccessFlag; import org.jboss.classfilewriter.ClassFile; import org.jboss.classfilewriter.ClassMethod; @@ -52,6 +50,7 @@ import org.jboss.classfilewriter.util.Boxing; import org.jboss.classfilewriter.util.DescriptorUtils; import org.jboss.weld.Container; +import org.jboss.weld.bean.AbstractProducerBean; import org.jboss.weld.bean.builtin.AbstractBuiltInBean; import org.jboss.weld.config.WeldConfiguration; import org.jboss.weld.exceptions.DefinitionException; @@ -69,7 +68,6 @@ import org.jboss.weld.util.Proxies; import org.jboss.weld.util.Proxies.TypeInfo; import org.jboss.weld.util.bytecode.BytecodeUtils; -import org.jboss.weld.util.bytecode.ClassFileUtils; import org.jboss.weld.util.bytecode.ConstructorUtils; import org.jboss.weld.util.bytecode.DeferredBytecode; import org.jboss.weld.util.bytecode.MethodInformation; @@ -90,856 +88,1017 @@ */ public class ProxyFactory implements PrivilegedAction { - // Default proxy class name suffix - public static final String PROXY_SUFFIX = "$Proxy$"; - public static final String DEFAULT_PROXY_PACKAGE = "org.jboss.weld.proxies"; - - private final Class beanType; - private final Set> additionalInterfaces = new LinkedHashSet>(); - private final ClassLoader classLoader; - private final String baseProxyName; - private final Bean bean; - private final Class proxiedBeanType; - private final String contextId; - private final ProxyServices proxyServices; - - private final WeldConfiguration configuration; - - public static final String CONSTRUCTED_FLAG_NAME = "constructed"; - - private final ProxyInstantiator proxyInstantiator; - - protected static final BytecodeMethodResolver DEFAULT_METHOD_RESOLVER = new DefaultBytecodeMethodResolver(); - - protected static final String LJAVA_LANG_REFLECT_METHOD = "Ljava/lang/reflect/Method;"; - protected static final String LJAVA_LANG_BYTE = "Ljava/lang/Byte;"; - protected static final String LJAVA_LANG_CLASS = "Ljava/lang/Class;"; - protected static final String LJAVA_LANG_OBJECT = "Ljava/lang/Object;"; - protected static final String LBEAN_IDENTIFIER = "Lorg/jboss/weld/serialization/spi/BeanIdentifier;"; - protected static final String LJAVA_LANG_STRING = "Ljava/lang/String;"; - protected static final String LJAVA_LANG_THREAD_LOCAL = "Ljava/lang/ThreadLocal;"; - - protected static final String INIT_METHOD_NAME = ""; - protected static final String INVOKE_METHOD_NAME = "invoke"; - protected static final String METHOD_HANDLER_FIELD_NAME = "methodHandler"; - static final String JAVA = "java"; - static final String NULL = "the class package is null"; - static final String SIGNED = "the class is signed"; - - private static final Set METHOD_FILTERS; - - static { - Set filters = new HashSet<>(); - filters.add(CommonProxiedMethodFilters.NON_STATIC); - filters.add(CommonProxiedMethodFilters.NON_FINAL); - filters.add(CommonProxiedMethodFilters.OBJECT_TO_STRING); - filters.add(CommonProxiedMethodFilters.NON_JDK_PACKAGE_PRIVATE); - GroovyMethodFilter groovy = new GroovyMethodFilter(); - if (groovy.isEnabled()) { - filters.add(groovy); - } - METHOD_FILTERS = ImmutableSet.copyOf(filters); + // Default proxy class name suffix + public static final String PROXY_SUFFIX = "$Proxy$"; + // choose different package from what we have in tests to distinguish it + // clearly + public static final String WELD_PROXY_PREFIX = + "org.jboss.weld.generated.proxies"; + public static final String DEFAULT_PROXY_PACKAGE = + WELD_PROXY_PREFIX + ".default"; + public static final String CONSTRUCTED_FLAG_NAME = "constructed"; + protected static final BytecodeMethodResolver DEFAULT_METHOD_RESOLVER = + new DefaultBytecodeMethodResolver(); + protected static final String LJAVA_LANG_REFLECT_METHOD = + "Ljava/lang/reflect/Method;"; + protected static final String LJAVA_LANG_BYTE = "Ljava/lang/Byte;"; + protected static final String LJAVA_LANG_CLASS = "Ljava/lang/Class;"; + protected static final String LJAVA_LANG_OBJECT = "Ljava/lang/Object;"; + protected static final String LBEAN_IDENTIFIER = + "Lorg/jboss/weld/serialization/spi/BeanIdentifier;"; + protected static final String LJAVA_LANG_STRING = "Ljava/lang/String;"; + protected static final String LJAVA_LANG_THREAD_LOCAL = + "Ljava/lang/ThreadLocal;"; + protected static final String INIT_METHOD_NAME = ""; + protected static final String INVOKE_METHOD_NAME = "invoke"; + protected static final String METHOD_HANDLER_FIELD_NAME = "methodHandler"; + static final String JAVA = "java"; + static final String JAKARTA = "jakarta"; + static final String NO_PACKAGE = "the class package is null or empty"; + static final String SIGNED = "the class is signed"; + private static final Set METHOD_FILTERS; + + static { + Set filters = new HashSet<>(); + filters.add(CommonProxiedMethodFilters.NON_STATIC); + filters.add(CommonProxiedMethodFilters.NON_FINAL); + filters.add(CommonProxiedMethodFilters.OBJECT_TO_STRING); + filters.add(CommonProxiedMethodFilters.NON_JDK_PACKAGE_PRIVATE); + GroovyMethodFilter groovy = new GroovyMethodFilter(); + if (groovy.isEnabled()) { + filters.add(groovy); } - - /** - * created a new proxy factory from a bean instance. The proxy name is - * generated from the bean id - */ - public ProxyFactory(String contextId, Class proxiedBeanType, Set typeClosure, Bean bean) { - this(contextId, proxiedBeanType, typeClosure, bean, false); + METHOD_FILTERS = ImmutableSet.copyOf(filters); + } + + private final Class beanType; + private final Set> additionalInterfaces = + new LinkedHashSet>(); + private final String baseProxyName; + private final Bean bean; + private final Class proxiedBeanType; + private final String contextId; + private final ProxyServices proxyServices; + private final WeldConfiguration configuration; + private final ProxyInstantiator proxyInstantiator; + + /** + * created a new proxy factory from a bean instance. The proxy name is + * generated from the bean id + */ + public ProxyFactory(String contextId, Class proxiedBeanType, + Set typeClosure, Bean bean) { + this(contextId, proxiedBeanType, typeClosure, bean, false); + } + + public ProxyFactory(String contextId, Class proxiedBeanType, + Set typeClosure, Bean bean, + boolean forceSuperClass) { + this(contextId, proxiedBeanType, typeClosure, + getProxyName(contextId, proxiedBeanType, typeClosure, bean), bean, + forceSuperClass); + } + + /** + * Creates a new proxy factory when the name of the proxy class is already + * known, such as during de-serialization + * + * @param proxiedBeanType the super-class for this proxy class + * @param typeClosure the bean types of the bean + * @param proxyName the name of the proxy class + */ + public ProxyFactory(String contextId, Class proxiedBeanType, + Set typeClosure, String proxyName, + Bean bean) { + this(contextId, proxiedBeanType, typeClosure, proxyName, bean, false); + } + + public ProxyFactory(String contextId, Class proxiedBeanType, + Set typeClosure, String proxyName, + Bean bean, boolean forceSuperClass) { + this.bean = bean; + this.contextId = contextId; + this.proxiedBeanType = proxiedBeanType; + this.configuration = + Container.instance(contextId).deploymentManager().getServices().get( + WeldConfiguration.class); + addInterfacesFromTypeClosure(typeClosure, proxiedBeanType); + TypeInfo typeInfo = TypeInfo.of(typeClosure); + Class superClass = typeInfo.getSuperClass(); + superClass = superClass == null ? Object.class : superClass; + if (forceSuperClass || + (superClass.equals(Object.class) && additionalInterfaces.isEmpty())) { + // No interface beans, must use the bean impl as superclass + superClass = proxiedBeanType; } - - public ProxyFactory(String contextId, Class proxiedBeanType, Set typeClosure, Bean bean, boolean forceSuperClass) { - this(contextId, proxiedBeanType, typeClosure, getProxyName(contextId, proxiedBeanType, typeClosure, bean), bean, forceSuperClass); + this.beanType = superClass; + + addDefaultAdditionalInterfaces(); + baseProxyName = proxyName; + proxyServices = + Container.instance(contextId).services().get(ProxyServices.class); + // hierarchy order + if (additionalInterfaces.size() > 1) { + LinkedHashSet> sorted = + Proxies.sortInterfacesHierarchy(additionalInterfaces); + additionalInterfaces.clear(); + additionalInterfaces.addAll(sorted); } - /** - * Creates a new proxy factory when the name of the proxy class is already - * known, such as during de-serialization - * - * @param proxiedBeanType the super-class for this proxy class - * @param typeClosure the bean types of the bean - * @param proxyName the name of the proxy class - */ - public ProxyFactory(String contextId, Class proxiedBeanType, Set typeClosure, String proxyName, Bean bean) { - this(contextId, proxiedBeanType, typeClosure, proxyName, bean, false); - } - - public ProxyFactory(String contextId, Class proxiedBeanType, Set typeClosure, String proxyName, Bean bean, boolean forceSuperClass) { - this.bean = bean; - this.contextId = contextId; - this.proxiedBeanType = proxiedBeanType; - this.configuration = Container.instance(contextId).deploymentManager().getServices().get(WeldConfiguration.class); - addInterfacesFromTypeClosure(typeClosure, proxiedBeanType); - TypeInfo typeInfo = TypeInfo.of(typeClosure); - Class superClass = typeInfo.getSuperClass(); - superClass = superClass == null ? Object.class : superClass; - if (forceSuperClass || (superClass.equals(Object.class) && additionalInterfaces.isEmpty())) { - // No interface beans must use the bean impl as superclass - superClass = proxiedBeanType; - } - this.beanType = superClass; - - addDefaultAdditionalInterfaces(); - baseProxyName = proxyName; - proxyServices = Container.instance(contextId).services().get(ProxyServices.class); - if (!proxyServices.supportsClassDefining()) { - if (bean != null) { - /* - * this may happen when creating an InjectionTarget for a decorator using BeanManager#createInjectionTarget() - * which does not allow the bean to be specified - */ - this.classLoader = resolveClassLoaderForBeanProxy(contextId, bean.getBeanClass(), typeInfo, proxyServices); - } else { - this.classLoader = resolveClassLoaderForBeanProxy(contextId, proxiedBeanType, typeInfo, proxyServices); - } - } else { - // integrator defines new proxies and looks them up, we don't need CL information - this.classLoader = null; - } - // hierarchy order - if (additionalInterfaces.size() > 1) { - LinkedHashSet> sorted = Proxies.sortInterfacesHierarchy(additionalInterfaces); - additionalInterfaces.clear(); - additionalInterfaces.addAll(sorted); - } - - this.proxyInstantiator = Container.instance(contextId).services().get(ProxyInstantiator.class); - } - - static String getProxyName(String contextId, Class proxiedBeanType, Set typeClosure, Bean bean) { - TypeInfo typeInfo = TypeInfo.of(typeClosure); - String proxyPackage; - if (proxiedBeanType.equals(Object.class)) { - Class superInterface = typeInfo.getSuperInterface(); - if (superInterface == null) { - throw new IllegalArgumentException("Proxied bean type cannot be java.lang.Object without an interface"); - } else { - String reason = getDefaultPackageReason(superInterface); - if (reason != null) { - proxyPackage = DEFAULT_PROXY_PACKAGE; - BeanLogger.LOG.generatingProxyToDefaultPackage(superInterface, DEFAULT_PROXY_PACKAGE, reason); - } else { - proxyPackage = superInterface.getPackage().getName(); - } - } - } else { - String reason = getDefaultPackageReason(proxiedBeanType); - if (reason != null && reason.equals(NULL)) { - proxyPackage = DEFAULT_PROXY_PACKAGE; - BeanLogger.LOG.generatingProxyToDefaultPackage(proxiedBeanType, DEFAULT_PROXY_PACKAGE, reason); - } else { - proxyPackage = proxiedBeanType.getPackage().getName(); - } + this.proxyInstantiator = + Container.instance(contextId).services().get(ProxyInstantiator.class); + } + + static String getProxyName(String contextId, Class proxiedBeanType, + Set typeClosure, Bean bean) { + TypeInfo typeInfo = TypeInfo.of(typeClosure); + final String className; + ProxyNameHolder holder; + if (typeInfo.getSuperClass() == Object.class) { + final StringBuilder name = new StringBuilder(); + // interface only bean. + holder = createCompoundProxyName(contextId, bean, typeInfo, name); + } else { + boolean typeModified = false; + for (Class iface : typeInfo.getInterfaces()) { + if (!iface.isAssignableFrom(typeInfo.getSuperClass())) { + typeModified = true; + break; } - final String className; - - if (typeInfo.getSuperClass() == Object.class) { - final StringBuilder name = new StringBuilder(); - //interface only bean. - className = createCompoundProxyName(contextId, bean, typeInfo, name) + PROXY_SUFFIX; - } else { - boolean typeModified = false; - for (Class iface : typeInfo.getInterfaces()) { - if (!iface.isAssignableFrom(typeInfo.getSuperClass())) { - typeModified = true; - break; - } - } - if (typeModified) { - //this bean has interfaces that the base type is not assignable to - //which can happen with some creative use of the SPI - //interface only bean. - StringBuilder name = new StringBuilder(typeInfo.getSuperClass().getSimpleName() + "$"); - className = createCompoundProxyName(contextId, bean, typeInfo, name) + PROXY_SUFFIX; - } else { - className = typeInfo.getSuperClass().getSimpleName() + PROXY_SUFFIX; - } - } - - return proxyPackage + '.' + getEnclosingPrefix(proxiedBeanType) + className; + } + if (typeModified) { + // this bean has interfaces that the base type is not assignable to + // which can happen with some creative use of the SPI + // interface only bean. + StringBuilder name = + new StringBuilder(typeInfo.getSuperClass().getSimpleName() + "$"); + holder = createCompoundProxyName(contextId, bean, typeInfo, name); + } else { + holder = new ProxyNameHolder( + null, typeInfo.getSuperClass().getSimpleName(), bean); + } } - - public void addInterfacesFromTypeClosure(Set typeClosure, Class proxiedBeanType) { - for (Type type : typeClosure) { - Class c = Reflections.getRawType(type); - // Ignore no-interface views, they are dealt with proxiedBeanType - // (pending redesign) - if (c.isInterface()) { - addInterface(c); - } + className = holder.getClassName() + PROXY_SUFFIX; + String proxyPackage = holder.getPackageName(); + if (proxiedBeanType.equals(Object.class)) { + Class superInterface = typeInfo.getSuperInterface(); + if (superInterface == null) { + throw new IllegalArgumentException( + "Proxied bean type cannot be java.lang.Object without an " + + "interface"); + } else { + String reason = getDefaultPackageReason(superInterface); + if (reason != null) { + proxyPackage = DEFAULT_PROXY_PACKAGE; + BeanLogger.LOG.generatingProxyToDefaultPackage( + superInterface, DEFAULT_PROXY_PACKAGE, reason); } - } - - private static String createCompoundProxyName(String contextId, Bean bean, TypeInfo typeInfo, StringBuilder name) { - String className; - final List interfaces = new ArrayList(); - for (Class type : typeInfo.getInterfaces()) { - interfaces.add(type.getSimpleName()); - } - Collections.sort(interfaces); - for (final String iface : interfaces) { - name.append(iface); - name.append('$'); + } + } else { + String reason = getDefaultPackageReason(proxiedBeanType); + if (reason != null && reason.equals(NO_PACKAGE)) { + proxyPackage = DEFAULT_PROXY_PACKAGE; + BeanLogger.LOG.generatingProxyToDefaultPackage( + proxiedBeanType, DEFAULT_PROXY_PACKAGE, reason); + } else { + if (proxyPackage == null) { + proxyPackage = proxiedBeanType.getPackage().getName(); } - //there is a remote chance that this could generate the same - //proxy name for two interfaces with the same simple name. - //append the hash code of the bean id to be sure - // However, it is safe to share a proxy class for built-in beans of the same type (e.g. Event) - if (bean != null && !(bean instanceof AbstractBuiltInBean)) { - final BeanIdentifier id = Container.instance(contextId).services().get(ContextualStore.class).putIfAbsent(bean); - int idHash = id.hashCode(); - name.append(Math.abs(idHash == Integer.MIN_VALUE ? 0 : idHash)); - } - className = name.toString(); - return className; + } } - - private static String getEnclosingPrefix(Class clazz) { - Class encl = clazz.getEnclosingClass(); - return encl == null ? "" : getEnclosingPrefix(encl) + encl.getSimpleName() + '$'; + return proxyPackage + '.' + getEnclosingPrefix(proxiedBeanType) + className; + } + + private static ProxyNameHolder createCompoundProxyName(String contextId, + Bean bean, + TypeInfo typeInfo, + StringBuilder name) { + String className; + String proxyPackage = null; + // we need a sorted collection without repetition, hence LinkedHashSet + final Set interfaces = new LinkedHashSet<>(); + // for producers, try to determine the most specific class and make sure the + // proxy starts with the same package and class + if (bean != null && bean instanceof AbstractProducerBean) { + Class mostSpecificClass = ((AbstractProducerBean)bean).getType(); + proxyPackage = mostSpecificClass.getPackage().getName(); + if (mostSpecificClass.getDeclaringClass() != null) { + interfaces.add(mostSpecificClass.getDeclaringClass().getSimpleName()); + } + interfaces.add(mostSpecificClass.getSimpleName()); } - - /** - * Adds an additional interface that the proxy should implement. The default - * implementation will be to forward invocations to the bean instance. - * - * @param newInterface an interface - */ - public void addInterface(Class newInterface) { - if (!newInterface.isInterface()) { - throw new IllegalArgumentException(newInterface + " is not an interface"); - } - additionalInterfaces.add(newInterface); + final Set declaringClasses = new HashSet<>(); + for (Class type : typeInfo.getInterfaces()) { + Class declaringClass = type.getDeclaringClass(); + if (declaringClass != null && + declaringClasses.add(declaringClass.getSimpleName())) { + interfaces.add(declaringClass.getSimpleName()); + } + interfaces.add(type.getSimpleName()); + if (proxyPackage == null) { + proxyPackage = typeInfo.getPackageNameForClass(type); + } } - - /** - * Method to create a new proxy that wraps the bean instance. - * - * @param beanInstance the bean instance - * @return a new proxy object - */ - public T create(BeanInstance beanInstance) { - final T proxy = (System.getSecurityManager() == null) ? run() : AccessController.doPrivileged(this); - ((ProxyObject) proxy).weld_setHandler(new ProxyMethodHandler(contextId, beanInstance, bean)); - return proxy; + // no need to sort the set, because we copied and already sorted one + Iterator iterator = interfaces.iterator(); + while (iterator.hasNext()) { + name.append(iterator.next()); + if (iterator.hasNext()) { + name.append("$"); + } } - - @Override - public T run() { - try { - Class proxyClass = getProxyClass(); - boolean hasConstrutedField = SecurityActions.hasDeclaredField(proxyClass, CONSTRUCTED_FLAG_NAME); - if (hasConstrutedField != useConstructedFlag()) { - // The proxy class was created with a different type of ProxyInstantiator - ProxyInstantiator newInstantiator = ProxyInstantiator.Factory.create(!hasConstrutedField); - BeanLogger.LOG.creatingProxyInstanceUsingDifferentInstantiator(proxyClass, newInstantiator, proxyInstantiator); - return newInstantiator.newInstance(proxyClass); - } - return proxyInstantiator.newInstance(proxyClass); - } catch (InstantiationException e) { - throw new DefinitionException(BeanLogger.LOG.proxyInstantiationFailed(this), e.getCause()); - } catch (IllegalAccessException e) { - throw new DefinitionException(BeanLogger.LOG.proxyInstantiationBeanAccessFailed(this), e.getCause()); - } + // there is a remote chance that this could generate the same + // proxy name for two interfaces with the same simple name. + // append the hash code of the bean id to be sure + // However, it is safe to share a proxy class for built-in beans of the + // same type (e.g. Event) + if (bean != null && !(bean instanceof AbstractBuiltInBean)) { + final BeanIdentifier id = Container.instance(contextId) + .services() + .get(ContextualStore.class) + .putIfAbsent(bean); + int idHash = id.hashCode(); + // add a separator so that WeldDefaultProxyServices can determine the + // correct full class name by first occurrence of "$" + name.append("$"); + name.append(Math.abs(idHash == Integer.MIN_VALUE ? 0 : idHash)); } - - /** - * Produces or returns the existing proxy class. The operation is thread-safe. - * - * @return always the class of the proxy - */ - public Class getProxyClass() { - String suffix = "_$$_Weld" + getProxyNameSuffix(); - String proxyClassName = getBaseProxyName(); - if (!proxyClassName.endsWith(suffix)) { - proxyClassName = proxyClassName + suffix; - } - if (proxyClassName.startsWith(JAVA)) { - proxyClassName = proxyClassName.replaceFirst(JAVA, "org.jboss.weld"); - } - Class proxyClass = null; - Class originalClass = bean != null ? bean.getBeanClass() : proxiedBeanType; - BeanLogger.LOG.generatingProxyClass(proxyClassName); - try { - // First check to see if we already have this proxy class - proxyClass = cast(classLoader == null? proxyServices.loadClass(originalClass, proxyClassName) : classLoader.loadClass(proxyClassName)); - } catch (ClassNotFoundException e) { - // Create the proxy class for this instance - try { - proxyClass = createProxyClass(originalClass, proxyClassName); - } catch (Throwable e1) { - //attempt to load the class again, just in case another thread - //defined it between the check and the create method - try { - proxyClass = cast(classLoader == null? proxyServices.loadClass(originalClass, proxyClassName) : classLoader.loadClass(proxyClassName)); - } catch (ClassNotFoundException e2) { - BeanLogger.LOG.catchingDebug(e1); - throw BeanLogger.LOG.unableToLoadProxyClass(bean, proxiedBeanType, e1); - } - } - } - return proxyClass; + className = name.toString(); + return new ProxyNameHolder(proxyPackage, className, bean); + } + + private static String getEnclosingPrefix(Class clazz) { + Class encl = clazz.getEnclosingClass(); + return encl == null ? "" + : getEnclosingPrefix(encl) + encl.getSimpleName() + '$'; + } + + /** + * Convenience method to set the underlying bean instance for a proxy. + * + * @param proxy the proxy instance + * @param beanInstance the instance of the bean + */ + public static void setBeanInstance(String contextId, T proxy, + BeanInstance beanInstance, + Bean bean) { + if (proxy instanceof ProxyObject) { + ProxyObject proxyView = (ProxyObject)proxy; + proxyView.weld_setHandler( + new ProxyMethodHandler(contextId, beanInstance, bean)); } + } - /** - * Returns the package and base name for the proxy class. - * - * @return base name without suffixes - */ - protected String getBaseProxyName() { - return baseProxyName; + private static String getDefaultPackageReason(Class clazz) { + if (clazz.getPackage() == null || clazz.getPackage().getName().isEmpty()) { + return NO_PACKAGE; } - - /** - * Convenience method to set the underlying bean instance for a proxy. - * - * @param proxy the proxy instance - * @param beanInstance the instance of the bean - */ - public static void setBeanInstance(String contextId, T proxy, BeanInstance beanInstance, Bean bean) { - if (proxy instanceof ProxyObject) { - ProxyObject proxyView = (ProxyObject) proxy; - proxyView.weld_setHandler(new ProxyMethodHandler(contextId, beanInstance, bean)); - } + if (clazz.getSigners() != null) { + return SIGNED; } - - /** - * Returns a suffix to append to the name of the proxy class. The name - * already consists of _$$_Weld, to which the suffix is added. - * This allows the creation of different types of proxies for the same class. - * - * @return a name suffix - */ - protected String getProxyNameSuffix() { - return PROXY_SUFFIX; + return null; + } + + public void addInterfacesFromTypeClosure(Set typeClosure, + Class proxiedBeanType) { + for (Type type : typeClosure) { + Class c = Reflections.getRawType(type); + // Ignore no-interface views, they are dealt with proxiedBeanType + // (pending redesign) + if (c.isInterface()) { + addInterface(c); + } } - - private void addDefaultAdditionalInterfaces() { - additionalInterfaces.add(Serializable.class); - // add a marker interface denoting that the resulting class uses weld internal contructs - additionalInterfaces.add(WeldConstruct.class); + } + + /** + * Adds an additional interface that the proxy should implement. The default + * implementation will be to forward invocations to the bean instance. + * + * @param newInterface an interface + */ + public void addInterface(Class newInterface) { + if (!newInterface.isInterface()) { + throw new IllegalArgumentException(newInterface + (" is not an " + + "interface")); } - - /** - * Sub classes may override to specify additional interfaces the proxy should - * implement - */ - protected void addAdditionalInterfaces(Set> interfaces) { - + additionalInterfaces.add(newInterface); + } + + /** + * Method to create a new proxy that wraps the bean instance. + * + * @param beanInstance the bean instance + * @return a new proxy object + */ + public T create(BeanInstance beanInstance) { + final T proxy = (System.getSecurityManager() == null) + ? run() + : AccessController.doPrivileged(this); + ((ProxyObject)proxy) + .weld_setHandler(new ProxyMethodHandler(contextId, beanInstance, bean)); + return proxy; + } + + @Override + public T run() { + try { + Class proxyClass = getProxyClass(); + boolean hasConstrutedField = + SecurityActions.hasDeclaredField(proxyClass, CONSTRUCTED_FLAG_NAME); + if (hasConstrutedField != useConstructedFlag()) { + // The proxy class was created with a different type of + // ProxyInstantiator + ProxyInstantiator newInstantiator = + ProxyInstantiator.Factory.create(!hasConstrutedField); + BeanLogger.LOG.creatingProxyInstanceUsingDifferentInstantiator( + proxyClass, newInstantiator, proxyInstantiator); + return newInstantiator.newInstance(proxyClass); + } + return proxyInstantiator.newInstance(proxyClass); + } catch (InstantiationException e) { + throw new DefinitionException( + BeanLogger.LOG.proxyInstantiationFailed(this), e.getCause()); + } catch (IllegalAccessException e) { + throw new DefinitionException( + BeanLogger.LOG.proxyInstantiationBeanAccessFailed(this), + e.getCause()); } - - private Class createProxyClass(Class originalClass, String proxyClassName) throws Exception { - Set> specialInterfaces = Sets.newHashSet(LifecycleMixin.class, TargetInstanceProxy.class, ProxyObject.class); - addAdditionalInterfaces(specialInterfaces); - // Remove special interfaces from main set (deserialization scenario) - additionalInterfaces.removeAll(specialInterfaces); - - ClassFile proxyClassType = null; - final int accessFlags = AccessFlag.of(AccessFlag.PUBLIC, AccessFlag.SUPER, AccessFlag.SYNTHETIC); - if (getBeanType().isInterface()) { - proxyClassType = newClassFile(proxyClassName, accessFlags, Object.class.getName()); - proxyClassType.addInterface(getBeanType().getName()); - } else { - proxyClassType = newClassFile(proxyClassName, accessFlags, getBeanType().getName()); - } - // Add interfaces which require method generation - for (Class clazz : additionalInterfaces) { - proxyClassType.addInterface(clazz.getName()); - } - List initialValueBytecode = new ArrayList(); - - // Workaround for IBM JVM - the ACC_STATIC flag should only be required for class file with version number 51.0 or above - ClassMethod staticConstructor = proxyClassType.addMethod(AccessFlag.of(AccessFlag.PUBLIC, AccessFlag.STATIC), "", "V"); - - addFields(proxyClassType, initialValueBytecode); - addConstructors(proxyClassType, initialValueBytecode); - addMethods(proxyClassType, staticConstructor); - - staticConstructor.getCodeAttribute().returnInstruction(); - - // Additional interfaces whose methods require special handling - for (Class specialInterface : specialInterfaces) { - proxyClassType.addInterface(specialInterface.getName()); - } - - // Dump proxy type bytecode if necessary - dumpToFile(proxyClassName, proxyClassType.toBytecode()); - - ProtectionDomain domain = AccessController.doPrivileged(new GetProtectionDomainAction(proxiedBeanType)); - - if (proxiedBeanType.getPackage() == null || proxiedBeanType.equals(Object.class)) { - domain = ProxyFactory.class.getProtectionDomain(); - } else if (System.getSecurityManager() != null) { - ProtectionDomainCache cache = Container.instance(contextId).services().get(ProtectionDomainCache.class); - domain = cache.getProtectionDomainForProxy(domain); - } - Class proxyClass; - if (classLoader == null) { - proxyClass = cast(ClassFileUtils.toClass(proxyClassType, originalClass, proxyServices, domain)); - } else { - proxyClass = cast(ClassFileUtils.toClass(proxyClassType, classLoader, domain)); - } - BeanLogger.LOG.createdProxyClass(proxyClass, Arrays.toString(proxyClass.getInterfaces())); - return proxyClass; + } + + /** + * Produces or returns the existing proxy class. The operation is thread-safe. + * + * @return always the class of the proxy + */ + public Class getProxyClass() { + String suffix = "_$$_Weld" + getProxyNameSuffix(); + String proxyClassName = getBaseProxyName(); + if (!proxyClassName.endsWith(suffix)) { + proxyClassName = proxyClassName + suffix; } - - private ClassFile newClassFile(String name, int accessFlags, String superclass, String... interfaces) { - try { - if (classLoader == null) { - // initiate without the CL information as CL is null - return new ClassFile(name, accessFlags, superclass, interfaces); - } else { - // initiate with the CL information - return new ClassFile(name, accessFlags, superclass, classLoader, interfaces); - } - } catch (Exception e) { - throw BeanLogger.LOG.unableToCreateClassFile(name, e.getCause()); - } + if (proxyClassName.startsWith(JAVA)) { + proxyClassName = proxyClassName.replaceFirst(JAVA, WELD_PROXY_PREFIX); + } else if (proxyClassName.startsWith(JAKARTA)) { + proxyClassName = proxyClassName.replaceFirst(JAKARTA, WELD_PROXY_PREFIX); } - - private void dumpToFile(String fileName, byte[] data) { - File proxyDumpFilePath = configuration.getProxyDumpFilePath(); - if (proxyDumpFilePath == null) { - return; - } - File dumpFile = new File(proxyDumpFilePath, fileName + ".class"); + Class proxyClass = null; + Class originalClass = + bean != null ? bean.getBeanClass() : proxiedBeanType; + BeanLogger.LOG.generatingProxyClass(proxyClassName); + try { + // First check to see if we already have this proxy class + proxyClass = cast(proxyServices.loadClass(originalClass, proxyClassName)); + } catch (ClassNotFoundException e) { + // Create the proxy class for this instance + try { + proxyClass = createProxyClass(originalClass, proxyClassName); + } catch (Throwable e1) { + // attempt to load the class again, just in case another thread + // defined it between the check and the create method try { - Files.write(dumpFile.toPath(), data, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); - } catch (IOException e) { - BeanLogger.LOG.beanCannotBeDumped(fileName, e); + proxyClass = + cast(proxyServices.loadClass(originalClass, proxyClassName)); + } catch (ClassNotFoundException e2) { + BeanLogger.LOG.catchingDebug(e1); + throw BeanLogger.LOG.unableToLoadProxyClass(bean, proxiedBeanType, + e1); } + } } - - /** - * Adds a constructor for the proxy for each constructor declared by the base - * bean type. - * - * @param proxyClassType the Javassist class for the proxy - * @param initialValueBytecode - */ - protected void addConstructors(ClassFile proxyClassType, List initialValueBytecode) { - try { - if (getBeanType().isInterface()) { - ConstructorUtils.addDefaultConstructor(proxyClassType, initialValueBytecode, !useConstructedFlag()); - } else { - boolean constructorFound = false; - for (Constructor constructor : AccessController.doPrivileged(new GetDeclaredConstructorsAction(getBeanType()))) { - if ((constructor.getModifiers() & Modifier.PRIVATE) == 0) { - constructorFound = true; - String[] exceptions = new String[constructor.getExceptionTypes().length]; - for (int i = 0; i < exceptions.length; ++i) { - exceptions[i] = constructor.getExceptionTypes()[i].getName(); - } - ConstructorUtils.addConstructor(BytecodeUtils.VOID_CLASS_DESCRIPTOR, DescriptorUtils.parameterDescriptors(constructor.getParameterTypes()), exceptions, proxyClassType, initialValueBytecode, !useConstructedFlag()); - } - } - if (!constructorFound) { - // the bean only has private constructors, we need to generate - // two fake constructors that call each other - addConstructorsForBeanWithPrivateConstructors(proxyClassType); - } - } - } catch (Exception e) { - throw new WeldException(e); - } + return proxyClass; + } + + /** + * Returns the package and base name for the proxy class. + * + * @return base name without suffixes + */ + protected String getBaseProxyName() { return baseProxyName; } + + /** + * Returns a suffix to append to the name of the proxy class. The name + * already consists of _$$_Weld, to which the suffix is added. + * This allows the creation of different types of proxies for the same class. + * + * @return a name suffix + */ + protected String getProxyNameSuffix() { return PROXY_SUFFIX; } + + private void addDefaultAdditionalInterfaces() { + additionalInterfaces.add(Serializable.class); + // add a marker interface denoting that the resulting class uses weld + // internal contructs + additionalInterfaces.add(WeldConstruct.class); + } + + /** + * Sub classes may override to specify additional interfaces the proxy should + * implement + */ + protected void addAdditionalInterfaces(Set> interfaces) {} + + private Class createProxyClass(Class originalClass, + String proxyClassName) throws Exception { + Set> specialInterfaces = Sets.newHashSet( + LifecycleMixin.class, TargetInstanceProxy.class, ProxyObject.class); + addAdditionalInterfaces(specialInterfaces); + // Remove special interfaces from main set (deserialization scenario) + additionalInterfaces.removeAll(specialInterfaces); + + ClassFile proxyClassType = null; + final int accessFlags = AccessFlag.of(AccessFlag.PUBLIC, AccessFlag.SUPER, + AccessFlag.SYNTHETIC); + if (getBeanType().isInterface()) { + proxyClassType = + newClassFile(proxyClassName, accessFlags, Object.class.getName()); + proxyClassType.addInterface(getBeanType().getName()); + } else { + proxyClassType = + newClassFile(proxyClassName, accessFlags, getBeanType().getName()); } - - protected void addFields(ClassFile proxyClassType, List initialValueBytecode) { - // The field representing the underlying instance or special method - // handling - proxyClassType.addField(AccessFlag.PRIVATE, METHOD_HANDLER_FIELD_NAME, getMethodHandlerType()); - if (useConstructedFlag()) { - // field used to indicate that super() has been called - proxyClassType.addField(AccessFlag.PRIVATE, CONSTRUCTED_FLAG_NAME, BytecodeUtils.BOOLEAN_CLASS_DESCRIPTOR); - } + // Add interfaces which require method generation + for (Class clazz : additionalInterfaces) { + proxyClassType.addInterface(clazz.getName()); } + List initialValueBytecode = + new ArrayList(); - protected Class getMethodHandlerType() { - return MethodHandler.class; - } + // Workaround for IBM JVM - the ACC_STATIC flag should only be required for + // class file with version number 51.0 or above + ClassMethod staticConstructor = proxyClassType.addMethod( + AccessFlag.of(AccessFlag.PUBLIC, AccessFlag.STATIC), "", "V"); - protected void addMethods(ClassFile proxyClassType, ClassMethod staticConstructor) { - // Add all class methods for interception - addMethodsFromClass(proxyClassType, staticConstructor); + addFields(proxyClassType, initialValueBytecode); + addConstructors(proxyClassType, initialValueBytecode); + addMethods(proxyClassType, staticConstructor); - // Add special proxy methods - addSpecialMethods(proxyClassType, staticConstructor); + staticConstructor.getCodeAttribute().returnInstruction(); - // Add serialization support methods - addSerializationSupport(proxyClassType); + // Additional interfaces whose methods require special handling + for (Class specialInterface : specialInterfaces) { + proxyClassType.addInterface(specialInterface.getName()); } - /** - * Adds special serialization code. By default this is a nop - * - * @param proxyClassType the Javassist class for the proxy class - */ - protected void addSerializationSupport(ClassFile proxyClassType) { - //noop + // Dump proxy type bytecode if necessary + dumpToFile(proxyClassName, proxyClassType.toBytecode()); + + ProtectionDomain domain = AccessController.doPrivileged( + new GetProtectionDomainAction(proxiedBeanType)); + + if (proxiedBeanType.getPackage() == null || + proxiedBeanType.getPackage().getName().isEmpty() || + proxiedBeanType.equals(Object.class)) { + domain = ProxyFactory.class.getProtectionDomain(); + } else if (System.getSecurityManager() != null) { + ProtectionDomainCache cache = + Container.instance(contextId).services().get( + ProtectionDomainCache.class); + domain = cache.getProtectionDomainForProxy(domain); } - - protected void addMethodsFromClass(ClassFile proxyClassType, ClassMethod staticConstructor) { - try { - // Add all methods from the class hierarchy - Class cls = getBeanType(); - - // First add equals/hashCode methods if required - generateEqualsMethod(proxyClassType); - generateHashCodeMethod(proxyClassType); - - // In rare cases, the bean class may be abstract - in this case we have to add methods from all interfaces implemented by any abstract class - // from the hierarchy - boolean isBeanClassAbstract = Modifier.isAbstract(cls.getModifiers()); - - while (cls != null) { - addMethods(cls, proxyClassType, staticConstructor); - if (isBeanClassAbstract && Modifier.isAbstract(cls.getModifiers())) { - for (Class implementedInterface : Reflections.getInterfaceClosure(cls)) { - if (!additionalInterfaces.contains(implementedInterface)) { - addMethods(implementedInterface, proxyClassType, staticConstructor); - } - } - } - cls = cls.getSuperclass(); - } - for (Class c : additionalInterfaces) { - for (Method method : c.getMethods()) { - if (isMethodAccepted(method, getProxySuperclass())) { - try { - MethodInformation methodInfo = new RuntimeMethodInformation(method); - ClassMethod classMethod = proxyClassType.addMethod(method); - if (Reflections.isDefault(method)) { - addConstructedGuardToMethodBody(classMethod); - createForwardingMethodBody(classMethod, methodInfo, staticConstructor); - } else { - createSpecialMethodBody(classMethod, methodInfo, staticConstructor); - } - BeanLogger.LOG.addingMethodToProxy(method); - } catch (DuplicateMemberException e) { - } - } - } - } - } catch (Exception e) { - throw new WeldException(e); - } + Class proxyClass = + cast(toClass(proxyClassType, originalClass, proxyServices, domain)); + BeanLogger.LOG.createdProxyClass( + proxyClass, Arrays.toString(proxyClass.getInterfaces())); + return proxyClass; + } + + private ClassFile newClassFile(String name, int accessFlags, + String superclass, String... interfaces) { + try { + return new ClassFile(name, accessFlags, superclass, interfaces); + } catch (Exception e) { + throw BeanLogger.LOG.unableToCreateClassFile(name, e.getCause()); } + } - private void addMethods(Class cls, ClassFile proxyClassType, ClassMethod staticConstructor) { - for (Method method : AccessController.doPrivileged(new GetDeclaredMethodsAction(cls))) { - if (isMethodAccepted(method, getProxySuperclass())) { - try { - MethodInformation methodInfo = new RuntimeMethodInformation(method); - ClassMethod classMethod = proxyClassType.addMethod(method); - addConstructedGuardToMethodBody(classMethod); - createForwardingMethodBody(classMethod, methodInfo, staticConstructor); - BeanLogger.LOG.addingMethodToProxy(method); - } catch (DuplicateMemberException e) { - // do nothing. This will happen if superclass methods - // have been overridden - } - } - } + private void dumpToFile(String fileName, byte[] data) { + File proxyDumpFilePath = configuration.getProxyDumpFilePath(); + if (proxyDumpFilePath == null) { + return; } - - protected boolean isMethodAccepted(Method method, Class proxySuperclass) { - for (ProxiedMethodFilter filter : METHOD_FILTERS) { - if (!filter.accept(method, proxySuperclass)) { - return false; + File dumpFile = new File(proxyDumpFilePath, fileName + ".class"); + try { + Files.write(dumpFile.toPath(), data, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING); + } catch (IOException e) { + BeanLogger.LOG.beanCannotBeDumped(fileName, e); + } + } + + /** + * Adds a constructor for the proxy for each constructor declared by the base + * bean type. + * + * @param proxyClassType the Javassist class for the proxy + * @param initialValueBytecode + */ + protected void addConstructors(ClassFile proxyClassType, + List initialValueBytecode) { + try { + if (getBeanType().isInterface()) { + ConstructorUtils.addDefaultConstructor( + proxyClassType, initialValueBytecode, !useConstructedFlag()); + } else { + boolean constructorFound = false; + for (Constructor constructor : AccessController.doPrivileged( + new GetDeclaredConstructorsAction(getBeanType()))) { + if ((constructor.getModifiers() & Modifier.PRIVATE) == 0) { + constructorFound = true; + String[] exceptions = + new String[constructor.getExceptionTypes().length]; + for (int i = 0; i < exceptions.length; ++i) { + exceptions[i] = constructor.getExceptionTypes()[i].getName(); } + ConstructorUtils.addConstructor( + BytecodeUtils.VOID_CLASS_DESCRIPTOR, + DescriptorUtils.parameterDescriptors( + constructor.getParameterTypes()), + exceptions, proxyClassType, initialValueBytecode, + !useConstructedFlag()); + } } - return true; - } - - /** - * Generate the body of the proxies hashCode method. - *

- * If this method returns null, the method will not be added, and the - * hashCode on the superclass will be used as per normal virtual method - * resolution rules - */ - protected void generateHashCodeMethod(ClassFile proxyClassType) { - } - - /** - * Generate the body of the proxies equals method. - *

- * If this method returns null, the method will not be added, and the - * hashCode on the superclass will be used as per normal virtual method - * resolution rules - * - * @param proxyClassType The class file - */ - protected void generateEqualsMethod(ClassFile proxyClassType) { - - } - - protected void createSpecialMethodBody(ClassMethod proxyClassType, MethodInformation method, ClassMethod staticConstructor) { - createInterceptorBody(proxyClassType, method, staticConstructor); - } - - protected void addConstructedGuardToMethodBody(final ClassMethod classMethod) { - addConstructedGuardToMethodBody(classMethod, classMethod.getClassFile().getSuperclass()); - } - - /** - * Adds the following code to a delegating method: - *

- * - * if(!this.constructed) return super.thisMethod() - * - *

- * This means that the proxy will not start to delegate to the underlying - * bean instance until after the constructor has finished. - */ - protected void addConstructedGuardToMethodBody(final ClassMethod classMethod, String className) { - if (!useConstructedFlag()) { - return; + if (!constructorFound) { + // the bean only has private constructors, we need to generate + // two fake constructors that call each other + addConstructorsForBeanWithPrivateConstructors(proxyClassType); } - // now create the conditional - final CodeAttribute cond = classMethod.getCodeAttribute(); - cond.aload(0); - cond.getfield(classMethod.getClassFile().getName(), CONSTRUCTED_FLAG_NAME, BytecodeUtils.BOOLEAN_CLASS_DESCRIPTOR); - - // jump if the proxy constructor has finished - BranchEnd jumpMarker = cond.ifne(); - // generate the invokespecial call to the super class method - // this is run when the proxy is being constructed - cond.aload(0); - cond.loadMethodParameters(); - cond.invokespecial(className, classMethod.getName(), classMethod.getDescriptor()); - cond.returnInstruction(); - cond.branchEnd(jumpMarker); + } + } catch (Exception e) { + throw new WeldException(e); } - - protected void createForwardingMethodBody(ClassMethod classMethod, MethodInformation method, ClassMethod staticConstructor) { - createInterceptorBody(classMethod, method, staticConstructor); - } - - /** - * Creates the given method on the proxy class where the implementation - * forwards the call directly to the method handler. - *

- * the generated bytecode is equivalent to: - *

- * return (RetType) methodHandler.invoke(this,param1,param2); - * - * @param classMethod the class method - * @param method any JLR method - * @return the method byte code - */ - protected void createInterceptorBody(ClassMethod classMethod, MethodInformation method, ClassMethod staticConstructor) { - invokeMethodHandler(classMethod, method, true, DEFAULT_METHOD_RESOLVER, staticConstructor); + } + + protected void addFields(ClassFile proxyClassType, + List initialValueBytecode) { + // The field representing the underlying instance or special method + // handling + proxyClassType.addField(AccessFlag.PRIVATE, METHOD_HANDLER_FIELD_NAME, + getMethodHandlerType()); + if (useConstructedFlag()) { + // field used to indicate that super() has been called + proxyClassType.addField(AccessFlag.PRIVATE, CONSTRUCTED_FLAG_NAME, + BytecodeUtils.BOOLEAN_CLASS_DESCRIPTOR); } - - /** - * calls methodHandler.invoke for a given method - * - * @param method The method information - * @param addReturnInstruction set to true you want to return the result of - * the method invocation - * @param bytecodeMethodResolver The resolver that returns the method to invoke - */ - protected void invokeMethodHandler(ClassMethod classMethod, MethodInformation method, boolean addReturnInstruction, BytecodeMethodResolver bytecodeMethodResolver, ClassMethod staticConstructor) { - // now we need to build the bytecode. The order we do this in is as - // follows: - // load methodHandler - // load this - // load the method object - // load null - // create a new array the same size as the number of parameters - // push our parameter values into the array - // invokeinterface the invoke method - // add checkcast to cast the result to the return type, or unbox if - // primitive - // add an appropriate return instruction - final CodeAttribute b = classMethod.getCodeAttribute(); - b.aload(0); - getMethodHandlerField(classMethod.getClassFile(), b); - b.aload(0); - bytecodeMethodResolver.getDeclaredMethod(classMethod, method.getDeclaringClass(), method.getName(), method.getParameterTypes(), staticConstructor); - b.aconstNull(); - - b.iconst(method.getParameterTypes().length); - b.anewarray("java.lang.Object"); - - int localVariableCount = 1; - - for (int i = 0; i < method.getParameterTypes().length; ++i) { - String typeString = method.getParameterTypes()[i]; - b.dup(); // duplicate the array reference - b.iconst(i); - // load the parameter value - BytecodeUtils.addLoadInstruction(b, typeString, localVariableCount); - // box the parameter if necessary - Boxing.boxIfNessesary(b, typeString); - // and store it in the array - b.aastore(); - if (isWide(typeString)) { - localVariableCount = localVariableCount + 2; - } else { - localVariableCount++; + } + + protected Class getMethodHandlerType() { + return MethodHandler.class; + } + + protected void addMethods(ClassFile proxyClassType, + ClassMethod staticConstructor) { + // Add all class methods for interception + addMethodsFromClass(proxyClassType, staticConstructor); + + // Add special proxy methods + addSpecialMethods(proxyClassType, staticConstructor); + + // Add serialization support methods + addSerializationSupport(proxyClassType); + } + + /** + * Adds special serialization code. By default this is a nop + * + * @param proxyClassType the Javassist class for the proxy class + */ + protected void addSerializationSupport(ClassFile proxyClassType) { + // noop + } + + protected void addMethodsFromClass(ClassFile proxyClassType, + ClassMethod staticConstructor) { + try { + // Add all methods from the class hierarchy + Class cls = getBeanType(); + + // First add equals/hashCode methods if required + generateEqualsMethod(proxyClassType); + generateHashCodeMethod(proxyClassType); + + // In rare cases, the bean class may be abstract - in this case we have to + // add methods from all interfaces implemented by any abstract class from + // the hierarchy + boolean isBeanClassAbstract = Modifier.isAbstract(cls.getModifiers()); + + while (cls != null) { + addMethods(cls, proxyClassType, staticConstructor); + if (isBeanClassAbstract && Modifier.isAbstract(cls.getModifiers())) { + for (Class implementedInterface : + Reflections.getInterfaceClosure(cls)) { + if (!additionalInterfaces.contains(implementedInterface)) { + addMethods(implementedInterface, proxyClassType, + staticConstructor); } + } } - // now we have all our arguments on the stack - // lets invoke the method - b.invokeinterface(MethodHandler.class.getName(), INVOKE_METHOD_NAME, LJAVA_LANG_OBJECT, new String[] { LJAVA_LANG_OBJECT, - LJAVA_LANG_REFLECT_METHOD, LJAVA_LANG_REFLECT_METHOD, "[" + LJAVA_LANG_OBJECT }); - if (addReturnInstruction) { - // now we need to return the appropriate type - if (method.getReturnType().equals(BytecodeUtils.VOID_CLASS_DESCRIPTOR)) { - b.returnInstruction(); - } else if(isPrimitive(method.getReturnType())) { - Boxing.unbox(b, method.getReturnType()); - b.returnInstruction(); - } else { - b.checkcast(BytecodeUtils.getName(method.getReturnType())); - b.returnInstruction(); + cls = cls.getSuperclass(); + } + for (Class c : additionalInterfaces) { + for (Method method : c.getMethods()) { + if (isMethodAccepted(method, getProxySuperclass())) { + try { + MethodInformation methodInfo = + new RuntimeMethodInformation(method); + ClassMethod classMethod = proxyClassType.addMethod(method); + if (Reflections.isDefault(method)) { + addConstructedGuardToMethodBody(classMethod); + createForwardingMethodBody(classMethod, methodInfo, + staticConstructor); + } else { + createSpecialMethodBody(classMethod, methodInfo, + staticConstructor); + } + BeanLogger.LOG.addingMethodToProxy(method); + } catch (DuplicateMemberException e) { } + } } + } + } catch (Exception e) { + throw new WeldException(e); } + } - /** - * Adds methods requiring special implementations rather than just - * delegation. - * - * @param proxyClassType the Javassist class description for the proxy type - */ - protected void addSpecialMethods(ClassFile proxyClassType, ClassMethod staticConstructor) { + private void addMethods(Class cls, ClassFile proxyClassType, + ClassMethod staticConstructor) { + for (Method method : + AccessController.doPrivileged(new GetDeclaredMethodsAction(cls))) { + if (isMethodAccepted(method, getProxySuperclass())) { try { - // Add special methods for interceptors - for (Method method : LifecycleMixin.class.getMethods()) { - BeanLogger.LOG.addingMethodToProxy(method); - MethodInformation methodInfo = new RuntimeMethodInformation(method); - final ClassMethod classMethod = proxyClassType.addMethod(method); - createInterceptorBody(classMethod, methodInfo, staticConstructor); - } - Method getInstanceMethod = TargetInstanceProxy.class.getMethod("weld_getTargetInstance"); - Method getInstanceClassMethod = TargetInstanceProxy.class.getMethod("weld_getTargetClass"); - - MethodInformation getInstanceMethodInfo = new RuntimeMethodInformation(getInstanceMethod); - createInterceptorBody(proxyClassType.addMethod(getInstanceMethod), getInstanceMethodInfo, staticConstructor); - - - MethodInformation getInstanceClassMethodInfo = new RuntimeMethodInformation(getInstanceClassMethod); - createInterceptorBody(proxyClassType.addMethod(getInstanceClassMethod), getInstanceClassMethodInfo, staticConstructor); - - Method setMethodHandlerMethod = ProxyObject.class.getMethod("weld_setHandler", MethodHandler.class); - generateSetMethodHandlerBody(proxyClassType.addMethod(setMethodHandlerMethod)); - - Method getMethodHandlerMethod = ProxyObject.class.getMethod("weld_getHandler"); - generateGetMethodHandlerBody(proxyClassType.addMethod(getMethodHandlerMethod)); - } catch (Exception e) { - throw new WeldException(e); + MethodInformation methodInfo = new RuntimeMethodInformation(method); + ClassMethod classMethod = proxyClassType.addMethod(method); + addConstructedGuardToMethodBody(classMethod); + createForwardingMethodBody(classMethod, methodInfo, + staticConstructor); + BeanLogger.LOG.addingMethodToProxy(method); + } catch (DuplicateMemberException e) { + // do nothing. This will happen if superclass methods + // have been overridden } + } } + } - protected void generateSetMethodHandlerBody(ClassMethod method) { - final CodeAttribute b = method.getCodeAttribute(); - b.aload(0); - b.aload(1); - b.checkcast(getMethodHandlerType()); - b.putfield(method.getClassFile().getName(), METHOD_HANDLER_FIELD_NAME, DescriptorUtils.makeDescriptor(getMethodHandlerType())); - b.returnInstruction(); + protected boolean isMethodAccepted(Method method, Class proxySuperclass) { + for (ProxiedMethodFilter filter : METHOD_FILTERS) { + if (!filter.accept(method, proxySuperclass)) { + return false; + } } - - protected void generateGetMethodHandlerBody(ClassMethod method) { - final CodeAttribute b = method.getCodeAttribute(); - b.aload(0); - getMethodHandlerField(method.getClassFile(), b); - b.returnInstruction(); + return true; + } + + /** + * Generate the body of the proxies hashCode method. + *

+ * If this method returns null, the method will not be added, and the + * hashCode on the superclass will be used as per normal virtual method + * resolution rules + */ + protected void generateHashCodeMethod(ClassFile proxyClassType) {} + + /** + * Generate the body of the proxies equals method. + *

+ * If this method returns null, the method will not be added, and the + * hashCode on the superclass will be used as per normal virtual method + * resolution rules + * + * @param proxyClassType The class file + */ + protected void generateEqualsMethod(ClassFile proxyClassType) {} + + protected void createSpecialMethodBody(ClassMethod proxyClassType, + MethodInformation method, + ClassMethod staticConstructor) { + createInterceptorBody(proxyClassType, method, staticConstructor); + } + + protected void + addConstructedGuardToMethodBody(final ClassMethod classMethod) { + addConstructedGuardToMethodBody(classMethod, + classMethod.getClassFile().getSuperclass()); + } + + /** + * Adds the following code to a delegating method: + *

+ * + * if(!this.constructed) return super.thisMethod() + * + *

+ * This means that the proxy will not start to delegate to the underlying + * bean instance until after the constructor has finished. + */ + protected void addConstructedGuardToMethodBody(final ClassMethod classMethod, + String className) { + if (!useConstructedFlag()) { + return; } - - - /** - * Adds two constructors to the class that call each other in order to bypass - * the JVM class file verifier. - *

- * This would result in a stack overflow if they were actually called, - * however the proxy is directly created without calling the constructor - */ - private void addConstructorsForBeanWithPrivateConstructors(ClassFile proxyClassType) { - ClassMethod ctor = proxyClassType.addMethod(AccessFlag.PUBLIC, INIT_METHOD_NAME, BytecodeUtils.VOID_CLASS_DESCRIPTOR, LJAVA_LANG_BYTE); - CodeAttribute b = ctor.getCodeAttribute(); - b.aload(0); - b.aconstNull(); - b.aconstNull(); - b.invokespecial(proxyClassType.getName(), INIT_METHOD_NAME, "(" + LJAVA_LANG_BYTE + LJAVA_LANG_BYTE + ")" + BytecodeUtils.VOID_CLASS_DESCRIPTOR); + // now create the conditional + final CodeAttribute cond = classMethod.getCodeAttribute(); + cond.aload(0); + cond.getfield(classMethod.getClassFile().getName(), CONSTRUCTED_FLAG_NAME, + BytecodeUtils.BOOLEAN_CLASS_DESCRIPTOR); + + // jump if the proxy constructor has finished + BranchEnd jumpMarker = cond.ifne(); + // generate the invokespecial call to the super class method + // this is run when the proxy is being constructed + cond.aload(0); + cond.loadMethodParameters(); + cond.invokespecial(className, classMethod.getName(), + classMethod.getDescriptor()); + cond.returnInstruction(); + cond.branchEnd(jumpMarker); + } + + protected void createForwardingMethodBody(ClassMethod classMethod, + MethodInformation method, + ClassMethod staticConstructor) { + createInterceptorBody(classMethod, method, staticConstructor); + } + + /** + * Creates the given method on the proxy class where the implementation + * forwards the call directly to the method handler. + *

+ * the generated bytecode is equivalent to: + *

+ * return (RetType) methodHandler.invoke(this,param1,param2); + * + * @param classMethod the class method + * @param method any JLR method + * @return the method byte code + */ + protected void createInterceptorBody(ClassMethod classMethod, + MethodInformation method, + ClassMethod staticConstructor) { + invokeMethodHandler(classMethod, method, true, DEFAULT_METHOD_RESOLVER, + staticConstructor); + } + + /** + * calls methodHandler.invoke for a given method + * + * @param method The method information + * @param addReturnInstruction set to true you want to return the result of + * the method invocation + * @param bytecodeMethodResolver The resolver that returns the method to + * invoke + */ + protected void + invokeMethodHandler(ClassMethod classMethod, MethodInformation method, + boolean addReturnInstruction, + BytecodeMethodResolver bytecodeMethodResolver, + ClassMethod staticConstructor) { + // now we need to build the bytecode. The order we do this in is as + // follows: + // load methodHandler + // load this + // load the method object + // load null + // create a new array the same size as the number of parameters + // push our parameter values into the array + // invokeinterface the invoke method + // add checkcast to cast the result to the return type, or unbox if + // primitive + // add an appropriate return instruction + final CodeAttribute b = classMethod.getCodeAttribute(); + b.aload(0); + getMethodHandlerField(classMethod.getClassFile(), b); + b.aload(0); + bytecodeMethodResolver.getDeclaredMethod( + classMethod, method.getDeclaringClass(), method.getName(), + method.getParameterTypes(), staticConstructor); + b.aconstNull(); + + b.iconst(method.getParameterTypes().length); + b.anewarray("java.lang.Object"); + + int localVariableCount = 1; + + for (int i = 0; i < method.getParameterTypes().length; ++i) { + String typeString = method.getParameterTypes()[i]; + b.dup(); // duplicate the array reference + b.iconst(i); + // load the parameter value + BytecodeUtils.addLoadInstruction(b, typeString, localVariableCount); + // box the parameter if necessary + Boxing.boxIfNessesary(b, typeString); + // and store it in the array + b.aastore(); + if (isWide(typeString)) { + localVariableCount = localVariableCount + 2; + } else { + localVariableCount++; + } + } + // now we have all our arguments on the stack + // lets invoke the method + b.invokeinterface( + MethodHandler.class.getName(), INVOKE_METHOD_NAME, LJAVA_LANG_OBJECT, + new String[] {LJAVA_LANG_OBJECT, LJAVA_LANG_REFLECT_METHOD, + LJAVA_LANG_REFLECT_METHOD, "[" + LJAVA_LANG_OBJECT}); + if (addReturnInstruction) { + // now we need to return the appropriate type + if (method.getReturnType().equals(BytecodeUtils.VOID_CLASS_DESCRIPTOR)) { b.returnInstruction(); - - ctor = proxyClassType.addMethod(AccessFlag.PUBLIC, INIT_METHOD_NAME, BytecodeUtils.VOID_CLASS_DESCRIPTOR, LJAVA_LANG_BYTE, LJAVA_LANG_BYTE); - b = ctor.getCodeAttribute(); - b.aload(0); - b.aconstNull(); - b.invokespecial(proxyClassType.getName(), INIT_METHOD_NAME, "(" + LJAVA_LANG_BYTE + ")" + BytecodeUtils.VOID_CLASS_DESCRIPTOR); + } else if (isPrimitive(method.getReturnType())) { + Boxing.unbox(b, method.getReturnType()); b.returnInstruction(); + } else { + b.checkcast(BytecodeUtils.getName(method.getReturnType())); + b.returnInstruction(); + } } - - public Class getBeanType() { - return beanType; - } - - public Set> getAdditionalInterfaces() { - return additionalInterfaces; - } - - public Bean getBean() { - return bean; + } + + /** + * Adds methods requiring special implementations rather than just + * delegation. + * + * @param proxyClassType the Javassist class description for the proxy type + */ + protected void addSpecialMethods(ClassFile proxyClassType, + ClassMethod staticConstructor) { + try { + // Add special methods for interceptors + for (Method method : LifecycleMixin.class.getMethods()) { + BeanLogger.LOG.addingMethodToProxy(method); + MethodInformation methodInfo = new RuntimeMethodInformation(method); + final ClassMethod classMethod = proxyClassType.addMethod(method); + createInterceptorBody(classMethod, methodInfo, staticConstructor); + } + Method getInstanceMethod = + TargetInstanceProxy.class.getMethod("weld_getTargetInstance"); + Method getInstanceClassMethod = + TargetInstanceProxy.class.getMethod("weld_getTargetClass"); + + MethodInformation getInstanceMethodInfo = + new RuntimeMethodInformation(getInstanceMethod); + createInterceptorBody(proxyClassType.addMethod(getInstanceMethod), + getInstanceMethodInfo, staticConstructor); + + MethodInformation getInstanceClassMethodInfo = + new RuntimeMethodInformation(getInstanceClassMethod); + createInterceptorBody(proxyClassType.addMethod(getInstanceClassMethod), + getInstanceClassMethodInfo, staticConstructor); + + Method setMethodHandlerMethod = + ProxyObject.class.getMethod("weld_setHandler", MethodHandler.class); + generateSetMethodHandlerBody( + proxyClassType.addMethod(setMethodHandlerMethod)); + + Method getMethodHandlerMethod = + ProxyObject.class.getMethod("weld_getHandler"); + generateGetMethodHandlerBody( + proxyClassType.addMethod(getMethodHandlerMethod)); + } catch (Exception e) { + throw new WeldException(e); } - - public String getContextId() { - return contextId; + } + + protected void generateSetMethodHandlerBody(ClassMethod method) { + final CodeAttribute b = method.getCodeAttribute(); + b.aload(0); + b.aload(1); + b.checkcast(getMethodHandlerType()); + b.putfield(method.getClassFile().getName(), METHOD_HANDLER_FIELD_NAME, + DescriptorUtils.makeDescriptor(getMethodHandlerType())); + b.returnInstruction(); + } + + protected void generateGetMethodHandlerBody(ClassMethod method) { + final CodeAttribute b = method.getCodeAttribute(); + b.aload(0); + getMethodHandlerField(method.getClassFile(), b); + b.returnInstruction(); + } + + /** + * Adds two constructors to the class that call each other in order to bypass + * the JVM class file verifier. + *

+ * This would result in a stack overflow if they were actually called, + * however the proxy is directly created without calling the constructor + */ + private void + addConstructorsForBeanWithPrivateConstructors(ClassFile proxyClassType) { + ClassMethod ctor = proxyClassType.addMethod( + AccessFlag.PUBLIC, INIT_METHOD_NAME, + BytecodeUtils.VOID_CLASS_DESCRIPTOR, LJAVA_LANG_BYTE); + CodeAttribute b = ctor.getCodeAttribute(); + b.aload(0); + b.aconstNull(); + b.aconstNull(); + b.invokespecial(proxyClassType.getName(), INIT_METHOD_NAME, + "(" + LJAVA_LANG_BYTE + LJAVA_LANG_BYTE + ")" + + BytecodeUtils.VOID_CLASS_DESCRIPTOR); + b.returnInstruction(); + + ctor = proxyClassType.addMethod(AccessFlag.PUBLIC, INIT_METHOD_NAME, + BytecodeUtils.VOID_CLASS_DESCRIPTOR, + LJAVA_LANG_BYTE, LJAVA_LANG_BYTE); + b = ctor.getCodeAttribute(); + b.aload(0); + b.aconstNull(); + b.invokespecial(proxyClassType.getName(), INIT_METHOD_NAME, + "(" + LJAVA_LANG_BYTE + ")" + + BytecodeUtils.VOID_CLASS_DESCRIPTOR); + b.returnInstruction(); + } + + public Class getBeanType() { return beanType; } + + public Set> getAdditionalInterfaces() { + return additionalInterfaces; + } + + public Bean getBean() { return bean; } + + public String getContextId() { return contextId; } + + protected Class getProxiedBeanType() { return proxiedBeanType; } + + protected void getMethodHandlerField(ClassFile file, CodeAttribute b) { + b.getfield(file.getName(), METHOD_HANDLER_FIELD_NAME, + DescriptorUtils.makeDescriptor(getMethodHandlerType())); + } + + protected Class getProxySuperclass() { + return getBeanType().isInterface() ? Object.class : getBeanType(); + } + + /** + * @return {@code true} if {@link ProxyInstantiator} is used to instantiate + * proxy instances + */ + protected boolean isUsingProxyInstantiator() { return true; } + + /** + * @return {@code true} if {@link #CONSTRUCTED_FLAG_NAME} should be used + */ + private boolean useConstructedFlag() { + return !isUsingProxyInstantiator() || + proxyInstantiator.isUsingConstructor(); + } + + /** + * Delegates proxy creation via {@link ProxyServices} to the integrator or to + * our own implementation. + */ + protected Class toClass(ClassFile ct, Class originalClass, + ProxyServices proxyServices, + ProtectionDomain domain) { + try { + byte[] bytecode = ct.toBytecode(); + Class result; + if (domain == null) { + result = proxyServices.defineClass(originalClass, ct.getName(), + bytecode, 0, bytecode.length); + } else { + result = proxyServices.defineClass( + originalClass, ct.getName(), bytecode, 0, bytecode.length, domain); + } + return result; + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); } - - protected Class getProxiedBeanType() { - return proxiedBeanType; + } + + /** + * When creating a proxy class name we can sometimes determine it's package as + * well. + */ + private static class ProxyNameHolder { + private String packageName; + private String className; + + private ProxyNameHolder(String packageName, String className, + Bean bean) { + this.packageName = packageName; + if (className == null) { + throw BeanLogger.LOG.tryingToCreateProxyNameHolderWithoutClassName( + bean.getBeanClass()); + } + this.className = className; } /** - * Figures out the correct class loader to use for a proxy for a given bean + * Class name, never null + * @return class name, never null */ - public static ClassLoader resolveClassLoaderForBeanProxy(String contextId, Class proxiedType, TypeInfo typeInfo, ProxyServices proxyServices) { - Class superClass = typeInfo.getSuperClass(); - if (superClass.getName().startsWith(JAVA)) { - ClassLoader cl = proxyServices.getClassLoader(proxiedType); - if (cl == null) { - cl = Thread.currentThread().getContextClassLoader(); - } - return cl; - } - return Container.instance(contextId).services().get(ProxyServices.class).getClassLoader(superClass); - } - - protected void getMethodHandlerField(ClassFile file, CodeAttribute b) { - b.getfield(file.getName(), METHOD_HANDLER_FIELD_NAME, DescriptorUtils.makeDescriptor(getMethodHandlerType())); - } - - protected Class getProxySuperclass() { - return getBeanType().isInterface() ? Object.class : getBeanType(); - } - - /** - * @return {@code true} if {@link ProxyInstantiator} is used to instantiate proxy instances - */ - protected boolean isUsingProxyInstantiator() { - return true; - } + public String getClassName() { return className; } /** - * @return {@code true} if {@link #CONSTRUCTED_FLAG_NAME} should be used + * Package name, can be null + * @return package name or null */ - private boolean useConstructedFlag() { - return !isUsingProxyInstantiator() || proxyInstantiator.isUsingConstructor(); - } - - private static String getDefaultPackageReason(Class clazz) { - if (clazz.getPackage() == null) { - return NULL; - } - if (clazz.getSigners() != null) { - return SIGNED; - } - return null; - } + public String getPackageName() { return packageName; } + } } diff --git a/impl/src/main/java/org/jboss/weld/bean/proxy/util/SimpleProxyServices.java b/impl/src/main/java/org/jboss/weld/bean/proxy/util/SimpleProxyServices.java deleted file mode 100644 index 3512edfe69..0000000000 --- a/impl/src/main/java/org/jboss/weld/bean/proxy/util/SimpleProxyServices.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * JBoss, Home of Professional Open Source - * Copyright 2008, Red Hat, Inc. and/or its affiliates, and individual contributors - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * Licensed 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.jboss.weld.bean.proxy.util; - -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; - -import org.jboss.weld.logging.BeanLogger; -import org.jboss.weld.serialization.spi.ProxyServices; - -/** - * A default implementation of the {@link ProxyServices} which simply use the - * corresponding information from the proxy type. An exception is made for - * {@code java.*} and {@code javax.*} packages which are often associated with - * the system classloader and a more privileged ProtectionDomain. - * - * @author David Allen - */ -public class SimpleProxyServices implements ProxyServices { - - public ClassLoader getClassLoader(final Class proxiedBeanType) { - return proxiedBeanType.getClassLoader(); - } - - public void cleanup() { - // This implementation requires no cleanup - - } - - @Deprecated - public Class loadBeanClass(final String className) { - try { - return (Class) AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws Exception { - return Class.forName(className, true, getClassLoader(this.getClass())); - } - }); - } catch (PrivilegedActionException pae) { - throw BeanLogger.LOG.cannotLoadClass(className, pae.getException()); - } - } - -} diff --git a/impl/src/main/java/org/jboss/weld/bean/proxy/util/WeldDefaultProxyServices.java b/impl/src/main/java/org/jboss/weld/bean/proxy/util/WeldDefaultProxyServices.java new file mode 100644 index 0000000000..f6ab8c1a2c --- /dev/null +++ b/impl/src/main/java/org/jboss/weld/bean/proxy/util/WeldDefaultProxyServices.java @@ -0,0 +1,153 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.bean.proxy.util; + +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.ProtectionDomain; +import java.util.concurrent.atomic.AtomicBoolean; +import org.jboss.weld.exceptions.UnsupportedOperationException; +import org.jboss.weld.logging.BeanLogger; +import org.jboss.weld.serialization.spi.ProxyServices; + +/** + * This class is a default implementation of ProxyServices that will only be + * loaded if no other implementation is detected. It is only used up until JDK + * 11 at which point it is replaced by its alternative implementation.

This + * class cracks open the class loader's {@code defineclass} method and then uses + * it to define new classes. + */ +public class WeldDefaultProxyServices implements ProxyServices { + + private static java.lang.reflect.Method defineClass1, defineClass2; + private static final AtomicBoolean classLoaderMethodsMadeAccessible = + new AtomicBoolean(false); + + /** + * This method cracks open {@code ClassLoader#defineClass()} methods by + *calling {@code setAccessible()}.

It is invoked during {@code + *WeldStartup#startContainer()} and only in case the integrator does not fully + *implement {@link ProxyServices}. + **/ + public static void makeClassLoaderMethodsAccessible() { + // the AtomicBoolean make sure this gets invoked only once as WeldStartup is + // triggered per deployment + if (classLoaderMethodsMadeAccessible.compareAndSet(false, true)) { + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws Exception { + Class cl = Class.forName("java.lang.ClassLoader"); + final String name = "defineClass"; + + defineClass1 = cl.getDeclaredMethod( + name, String.class, byte[].class, int.class, int.class); + defineClass2 = cl.getDeclaredMethod( + name, String.class, byte[].class, int.class, int.class, + ProtectionDomain.class); + defineClass1.setAccessible(true); + defineClass2.setAccessible(true); + return null; + } + }); + } catch (PrivilegedActionException pae) { + throw new RuntimeException("cannot initialize ClassPool", + pae.getException()); + } + } + } + + public ClassLoader getClassLoader(final Class proxiedBeanType) { + throw new UnsupportedOperationException( + "WeldDefaultProxyServices.getClassLoader(Class) is not " + + "implemented."); + } + + public Class loadBeanClass(final String className) { + throw new UnsupportedOperationException( + "WeldDefaultProxyServices.loadBeanClass(String) is not implemented."); + } + + @Override + public Class defineClass(Class originalClass, String className, + byte[] classBytes, int off, int len) + throws ClassFormatError { + return defineClass(originalClass, className, classBytes, off, len, null); + } + + @Override + public Class defineClass(Class originalClass, String className, + byte[] classBytes, int off, int len, + ProtectionDomain protectionDomain) + throws ClassFormatError { + try { + java.lang.reflect.Method method; + Object[] args; + if (protectionDomain == null) { + method = defineClass1; + args = new Object[] {className, classBytes, 0, len}; + } else { + method = defineClass2; + args = new Object[] {className, classBytes, 0, len, protectionDomain}; + } + ClassLoader loader = originalClass.getClassLoader(); + if (loader == null) { + loader = Thread.currentThread().getContextClassLoader(); + // cannot determine CL, we need to throw an exception + if (loader == null) { + throw BeanLogger.LOG.cannotDetermineClassLoader(className, + originalClass); + } + } + Class clazz = (Class)method.invoke(loader, args); + return clazz; + } catch (RuntimeException e) { + throw e; + } catch (java.lang.reflect.InvocationTargetException e) { + throw new RuntimeException(e.getTargetException()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public Class loadClass(Class originalClass, String classBinaryName) + throws ClassNotFoundException { + ClassLoader loader = originalClass.getClassLoader(); + if (loader == null) { + loader = Thread.currentThread().getContextClassLoader(); + // the following should not happen, but if it does, we need to throw an + // exception + if (loader == null) { + throw BeanLogger.LOG.cannotDetermineClassLoader(classBinaryName, + originalClass); + } + } + return loader.loadClass(classBinaryName); + } + + @Override + public boolean supportsClassDefining() { + return true; + } + + @Override + public void cleanup() { + // noop + } +} diff --git a/impl/src/main/java/org/jboss/weld/bootstrap/AnnotatedTypeLoader.java b/impl/src/main/java/org/jboss/weld/bootstrap/AnnotatedTypeLoader.java index 411d60e166..d2e46f90c8 100644 --- a/impl/src/main/java/org/jboss/weld/bootstrap/AnnotatedTypeLoader.java +++ b/impl/src/main/java/org/jboss/weld/bootstrap/AnnotatedTypeLoader.java @@ -29,90 +29,119 @@ import org.jboss.weld.util.Beans; /** - * Takes care of loading a class, creating {@link BackedAnnotatedType} and creating {@link SlimAnnotatedTypeContext}. + * Takes care of loading a class, creating {@link BackedAnnotatedType} and + * creating {@link SlimAnnotatedTypeContext}. * * @author Jozef Hartinger * */ class AnnotatedTypeLoader { - final ResourceLoader resourceLoader; - final ClassTransformer classTransformer; - final MissingDependenciesRegistry missingDependenciesRegistry; - final ContainerLifecycleEvents containerLifecycleEvents; + final ResourceLoader resourceLoader; + final ClassTransformer classTransformer; + final MissingDependenciesRegistry missingDependenciesRegistry; + final ContainerLifecycleEvents containerLifecycleEvents; - static final String MODULEINFO_CLASS_NAME = "module-info"; + static final String MODULEINFO_CLASS_NAME = "module-info"; + static final String MULTI_RELEASE_JAR_PATH = "META-INF.versions"; - AnnotatedTypeLoader(BeanManagerImpl manager, ClassTransformer transformer, ContainerLifecycleEvents containerLifecycleEvents) { - this.resourceLoader = manager.getServices().get(ResourceLoader.class); - this.classTransformer = transformer; - this.missingDependenciesRegistry = manager.getServices().get(MissingDependenciesRegistry.class); - this.containerLifecycleEvents = containerLifecycleEvents; - } + AnnotatedTypeLoader(BeanManagerImpl manager, ClassTransformer transformer, + ContainerLifecycleEvents containerLifecycleEvents) { + this.resourceLoader = manager.getServices().get(ResourceLoader.class); + this.classTransformer = transformer; + this.missingDependenciesRegistry = + manager.getServices().get(MissingDependenciesRegistry.class); + this.containerLifecycleEvents = containerLifecycleEvents; + } - /** - * Creates a new {@link SlimAnnotatedTypeContext} instance for a class with the specified class name. This method may return null if there is a problem - * loading the class or this class is not needed for further processing (e.g. an annotation or a vetoed class). - * - * @param className the specified class name - * @param bdaId the identifier of the bean archive this class resides in - * @return a new {@code SlimAnnotatedTypeContext} for a specified class or null - */ - public SlimAnnotatedTypeContext loadAnnotatedType(String className, String bdaId) { - return loadAnnotatedType(this. loadClass(className), bdaId); - } + /** + * Creates a new {@link SlimAnnotatedTypeContext} instance for a class with + * the specified class name. This method may return null if there is a problem + * loading the class or this class is not needed for further processing (e.g. + * an annotation or a vetoed class). + * + * @param className the specified class name + * @param bdaId the identifier of the bean archive this class resides in + * @return a new {@code SlimAnnotatedTypeContext} for a specified class or + * null + */ + public SlimAnnotatedTypeContext loadAnnotatedType(String className, + String bdaId) { + return loadAnnotatedType(this.loadClass(className), bdaId); + } - /** - * Creates a new {@link SlimAnnotatedTypeContext} instance for the given class. This method may return null if there is a problem - * loading the class or this class is not needed for further processing (e.g. an annotation or a vetoed class). - * - * @param clazz the given class - * @param bdaId the identifier of the bean archive this class resides in - * @return a new {@code SlimAnnotatedTypeContext} for a specified class or null - */ - public SlimAnnotatedTypeContext loadAnnotatedType(Class clazz, String bdaId) { - return createContext(internalLoadAnnotatedType(clazz, bdaId)); - } + /** + * Creates a new {@link SlimAnnotatedTypeContext} instance for the given + * class. This method may return null if there is a problem loading the class + * or this class is not needed for further processing (e.g. an annotation or a + * vetoed class). + * + * @param clazz the given class + * @param bdaId the identifier of the bean archive this class resides in + * @return a new {@code SlimAnnotatedTypeContext} for a specified class or + * null + */ + public SlimAnnotatedTypeContext loadAnnotatedType(Class clazz, + String bdaId) { + return createContext(internalLoadAnnotatedType(clazz, bdaId)); + } - protected Class loadClass(String className) { - if (isModuleInfo(className)) { - return null; - } - try { - return cast(resourceLoader.classForName(className)); - } catch (ResourceLoadingException e) { - missingDependenciesRegistry.handleResourceLoadingException(className, e); - return null; - } + protected Class loadClass(String className) { + if (isModuleInfo(className) || isMultiReleaseJarClass(className)) { + return null; } - - protected SlimAnnotatedType internalLoadAnnotatedType(Class clazz, String bdaId) { - // do not load if clazz is null, an annotation or anonymous/local class - if (clazz != null && !clazz.isAnnotation() && !clazz.isAnonymousClass() && !clazz.isLocalClass()) { - try { - if (!Beans.isVetoed(clazz)) { // may throw ArrayStoreException - see bug http://bugs.sun.com/view_bug.do?bug_id=7183985 - containerLifecycleEvents.preloadProcessAnnotatedType(clazz); - try { - return classTransformer.getBackedAnnotatedType(clazz, bdaId); - } catch (ResourceLoadingException e) { - missingDependenciesRegistry.handleResourceLoadingException(clazz.getName(), e); - } - } - } catch (ArrayStoreException e) { - missingDependenciesRegistry.handleResourceLoadingException(clazz.getName(), e); - } - } - return null; + try { + return cast(resourceLoader.classForName(className)); + } catch (ResourceLoadingException e) { + missingDependenciesRegistry.handleResourceLoadingException(className, e); + return null; } + } - protected SlimAnnotatedTypeContext createContext(SlimAnnotatedType type) { - if (type != null) { - return SlimAnnotatedTypeContext.of(type); + protected SlimAnnotatedType internalLoadAnnotatedType(Class clazz, + String bdaId) { + // do not load if clazz is null, an annotation or anonymous/local class + if (clazz != null && !clazz.isAnnotation() && !clazz.isAnonymousClass() && + !clazz.isLocalClass()) { + try { + if (!Beans.isVetoed( + clazz)) { // may throw ArrayStoreException - see bug + // http://bugs.sun.com/view_bug.do?bug_id=7183985 + containerLifecycleEvents.preloadProcessAnnotatedType(clazz); + try { + return classTransformer.getBackedAnnotatedType(clazz, bdaId); + } catch (ResourceLoadingException e) { + missingDependenciesRegistry.handleResourceLoadingException( + clazz.getName(), e); + } } - return null; + } catch (ArrayStoreException e) { + missingDependenciesRegistry.handleResourceLoadingException( + clazz.getName(), e); + } } + return null; + } - protected boolean isModuleInfo(String className) { - return MODULEINFO_CLASS_NAME.equals(className); + protected SlimAnnotatedTypeContext + createContext(SlimAnnotatedType type) { + if (type != null) { + return SlimAnnotatedTypeContext.of(type); } + return null; + } + + protected boolean isModuleInfo(String className) { + return MODULEINFO_CLASS_NAME.equals(className); + } + + /** + * Determines if the class is a MR JAR class, e.g. checks if its path starts + * with "META-INF.versions" + * + * @param className name of the class + */ + protected boolean isMultiReleaseJarClass(String className) { + return className.startsWith(MULTI_RELEASE_JAR_PATH); + } } diff --git a/impl/src/main/java/org/jboss/weld/bootstrap/WeldStartup.java b/impl/src/main/java/org/jboss/weld/bootstrap/WeldStartup.java index 67ee87d024..97da03a680 100644 --- a/impl/src/main/java/org/jboss/weld/bootstrap/WeldStartup.java +++ b/impl/src/main/java/org/jboss/weld/bootstrap/WeldStartup.java @@ -1,4 +1,4 @@ - /* +/* * JBoss, Home of Professional Open Source * Copyright 2013, Red Hat, Inc., and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a @@ -26,7 +26,6 @@ import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; - import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.ConversationScoped; import javax.enterprise.context.Dependent; @@ -41,7 +40,6 @@ import javax.enterprise.inject.spi.Decorator; import javax.enterprise.inject.spi.Extension; import javax.enterprise.inject.spi.Interceptor; - import org.jboss.weld.Container; import org.jboss.weld.ContainerState; import org.jboss.weld.annotated.slim.SlimAnnotatedTypeStore; @@ -55,7 +53,7 @@ import org.jboss.weld.bean.builtin.ContextBean; import org.jboss.weld.bean.proxy.ProtectionDomainCache; import org.jboss.weld.bean.proxy.ProxyInstantiator; -import org.jboss.weld.bean.proxy.util.SimpleProxyServices; +import org.jboss.weld.bean.proxy.util.WeldDefaultProxyServices; import org.jboss.weld.bootstrap.api.Environment; import org.jboss.weld.bootstrap.api.Service; import org.jboss.weld.bootstrap.api.ServiceRegistry; @@ -129,7 +127,6 @@ import org.jboss.weld.transaction.spi.TransactionServices; import org.jboss.weld.util.Bindings; import org.jboss.weld.util.Permissions; -import org.jboss.weld.util.bytecode.ClassFileUtils; import org.jboss.weld.util.collections.ImmutableSet; import org.jboss.weld.util.collections.Iterables; import org.jboss.weld.util.reflection.Formats; @@ -145,573 +142,678 @@ */ public class WeldStartup { - static { - VersionLogger.LOG.version(Formats.version(null)); + static { VersionLogger.LOG.version(Formats.version(null)); } + + private BeanManagerImpl deploymentManager; + private BeanDeploymentArchiveMapping bdaMapping; + private Collection> contexts; + private List> extensions; + private Environment environment; + private Deployment deployment; + private DeploymentVisitor deploymentVisitor; + private final ServiceRegistry initialServices = new SimpleServiceRegistry(); + private String contextId; + private final Tracker tracker = Trackers.create(); + + public WeldStartup() {} + + public WeldRuntime startContainer(String contextId, Environment environment, + Deployment deployment) { + if (deployment == null) { + throw BootstrapLogger.LOG.deploymentRequired(); } + tracker.start(Tracker.OP_BOOTSTRAP); + tracker.start(Tracker.OP_START_CONTAINER); + checkApiVersion(); - private BeanManagerImpl deploymentManager; - private BeanDeploymentArchiveMapping bdaMapping; - private Collection> contexts; - private List> extensions; - private Environment environment; - private Deployment deployment; - private DeploymentVisitor deploymentVisitor; - private final ServiceRegistry initialServices = new SimpleServiceRegistry(); - private String contextId; - private final Tracker tracker = Trackers.create(); + final ServiceRegistry registry = deployment.getServices(); + // initiate part of registry in order to allow access to WeldConfiguration + new AdditionalServiceLoader(deployment).loadAdditionalServices(registry); - public WeldStartup() { + // Resource Loader has to be loaded prior to WeldConfiguration + if (!registry.contains(ResourceLoader.class)) { + registry.add(ResourceLoader.class, DefaultResourceLoader.INSTANCE); } - public WeldRuntime startContainer(String contextId, Environment environment, Deployment deployment) { - if (deployment == null) { - throw BootstrapLogger.LOG.deploymentRequired(); - } - tracker.start(Tracker.OP_BOOTSTRAP); - tracker.start(Tracker.OP_START_CONTAINER); - checkApiVersion(); - - final ServiceRegistry registry = deployment.getServices(); - - // initiate part of registry in order to allow access to WeldConfiguration - new AdditionalServiceLoader(deployment).loadAdditionalServices(registry); - - // Resource Loader has to be loaded prior to WeldConfiguration - if (!registry.contains(ResourceLoader.class)) { - registry.add(ResourceLoader.class, DefaultResourceLoader.INSTANCE); - } - - WeldConfiguration configuration = new WeldConfiguration(registry, deployment); - registry.add(WeldConfiguration.class, configuration); - - String finalContextId = BeanDeployments.getFinalId(contextId, - registry.get(WeldConfiguration.class).getStringProperty(ROLLING_UPGRADES_ID_DELIMITER)); - this.contextId = finalContextId; - this.deployment = deployment; - this.environment = environment; - - if (this.extensions == null) { - setExtensions(deployment.getExtensions()); - } - // Add extension to register built-in components - this.extensions.add(MetadataImpl.from(new WeldExtension())); - - // Additional Weld extensions - String vetoTypeRegex = configuration.getStringProperty(ConfigurationKey.VETO_TYPES_WITHOUT_BEAN_DEFINING_ANNOTATION); - if (!vetoTypeRegex.isEmpty()) { - this.extensions.add(MetadataImpl.from(new WeldVetoExtension(vetoTypeRegex))); - } - if (UnusedBeans.isEnabled(configuration)) { - this.extensions.add(MetadataImpl.from(new WeldUnusedMetadataExtension())); - } - - // Finish the rest of registry init, setupInitialServices() requires already changed finalContextId - tracker.start(Tracker.OP_INIT_SERVICES); - setupInitialServices(); - registry.addAll(initialServices.entrySet()); - - if (!registry.contains(ProxyServices.class)) { - registry.add(ProxyServices.class, new SimpleProxyServices()); - } - // check if ProxyServices implementation supports class defining on integrator side - if (!registry.get(ProxyServices.class).supportsClassDefining()) { - // we will need to invoke CL.defineClass() ourselves, crack open those methods eagerly - ClassFileUtils.makeClassLoaderMethodsAccessible(); - } - if (!registry.contains(SecurityServices.class)) { - registry.add(SecurityServices.class, NoopSecurityServices.INSTANCE); - } - - addImplementationServices(registry); - tracker.end(); + WeldConfiguration configuration = + new WeldConfiguration(registry, deployment); + registry.add(WeldConfiguration.class, configuration); - verifyServices(registry, environment.getRequiredDeploymentServices(), contextId); - if (!registry.contains(TransactionServices.class)) { - BootstrapLogger.LOG.jtaUnavailable(); - } - - this.deploymentManager = BeanManagerImpl.newRootManager(finalContextId, "deployment", registry); + String finalContextId = BeanDeployments.getFinalId( + contextId, registry.get(WeldConfiguration.class) + .getStringProperty(ROLLING_UPGRADES_ID_DELIMITER)); + this.contextId = finalContextId; + this.deployment = deployment; + this.environment = environment; - Container.initialize(finalContextId, deploymentManager, ServiceRegistries.unmodifiableServiceRegistry(deployment.getServices()), environment); - getContainer().setState(ContainerState.STARTING); + if (this.extensions == null) { + setExtensions(deployment.getExtensions()); + } + // Add extension to register built-in components + this.extensions.add(MetadataImpl.from(new WeldExtension())); + + // Additional Weld extensions + String vetoTypeRegex = configuration.getStringProperty( + ConfigurationKey.VETO_TYPES_WITHOUT_BEAN_DEFINING_ANNOTATION); + if (!vetoTypeRegex.isEmpty()) { + this.extensions.add( + MetadataImpl.from(new WeldVetoExtension(vetoTypeRegex))); + } + if (UnusedBeans.isEnabled(configuration)) { + this.extensions.add(MetadataImpl.from(new WeldUnusedMetadataExtension())); + } - tracker.start(Tracker.OP_CONTEXTS); - this.contexts = createContexts(registry); - tracker.end(); + // Finish the rest of registry init, setupInitialServices() requires already + // changed finalContextId + tracker.start(Tracker.OP_INIT_SERVICES); + setupInitialServices(); + registry.addAll(initialServices.entrySet()); - this.bdaMapping = new BeanDeploymentArchiveMapping(); - this.deploymentVisitor = new DeploymentVisitor(deploymentManager, environment, deployment, contexts, bdaMapping); + if (!registry.contains(ProxyServices.class)) { + // add our own default impl that supports class defining + registry.add(ProxyServices.class, new WeldDefaultProxyServices()); + } + // all implementations of ProxyServices need to support class defining + ProxyServices proxyServices = registry.get(ProxyServices.class); + if (!proxyServices.supportsClassDefining()) { + throw BootstrapLogger.LOG.proxyServicesWithoutClassDefining( + proxyServices.getClass().getName()); + } + // if we use our own ProxyServices impl, we need to crack open CL for JDK 8 + // impl note that this is no-op call for JDK 11+ + if (proxyServices instanceof WeldDefaultProxyServices) { + WeldDefaultProxyServices.makeClassLoaderMethodsAccessible(); + } + if (!registry.contains(SecurityServices.class)) { + registry.add(SecurityServices.class, NoopSecurityServices.INSTANCE); + } - if (deployment instanceof CDI11Deployment) { - registry.add(BeanManagerLookupService.class, new BeanManagerLookupService((CDI11Deployment) deployment, bdaMapping.getBdaToBeanManagerMap())); - } else { - BootstrapLogger.LOG.legacyDeploymentMetadataProvided(); - } + addImplementationServices(registry); + tracker.end(); - // Read the deployment structure, bdaMapping will be the physical structure - // as caused by the presence of beans.xml - tracker.start(Tracker.OP_READ_DEPLOYMENT); - deploymentVisitor.visit(); - tracker.end(); + verifyServices(registry, environment.getRequiredDeploymentServices(), + contextId); + if (!registry.contains(TransactionServices.class)) { + BootstrapLogger.LOG.jtaUnavailable(); + } - WeldRuntime weldRuntime = new WeldRuntime(finalContextId, deploymentManager, bdaMapping.getBdaToBeanManagerMap()); - tracker.end(); - return weldRuntime; + this.deploymentManager = + BeanManagerImpl.newRootManager(finalContextId, "deployment", registry); + + Container.initialize( + finalContextId, deploymentManager, + ServiceRegistries.unmodifiableServiceRegistry(deployment.getServices()), + environment); + getContainer().setState(ContainerState.STARTING); + + tracker.start(Tracker.OP_CONTEXTS); + this.contexts = createContexts(registry); + tracker.end(); + + this.bdaMapping = new BeanDeploymentArchiveMapping(); + this.deploymentVisitor = new DeploymentVisitor( + deploymentManager, environment, deployment, contexts, bdaMapping); + + if (deployment instanceof CDI11Deployment) { + registry.add( + BeanManagerLookupService.class, + new BeanManagerLookupService((CDI11Deployment)deployment, + bdaMapping.getBdaToBeanManagerMap())); + } else { + BootstrapLogger.LOG.legacyDeploymentMetadataProvided(); } - private void checkApiVersion() { - if (Bean.class.getInterfaces().length == 1) { - // this means Bean only extends Contextual - since CDI 1.1 Bean also extends BeanAttributes - // CDI 1.0 API is detected on classpath - since that would result in obscure exception later, we - // throw an appropriate exception right now - throw BootstrapLogger.LOG.cdiApiVersionMismatch(); - } + // Read the deployment structure, bdaMapping will be the physical structure + // as caused by the presence of beans.xml + tracker.start(Tracker.OP_READ_DEPLOYMENT); + deploymentVisitor.visit(); + tracker.end(); + + WeldRuntime weldRuntime = new WeldRuntime( + finalContextId, deploymentManager, bdaMapping.getBdaToBeanManagerMap()); + tracker.end(); + return weldRuntime; + } + + private void checkApiVersion() { + if (Bean.class.getInterfaces().length == 1) { + // this means Bean only extends Contextual - since CDI 1.1 Bean also + // extends BeanAttributes CDI 1.0 API is detected on classpath - since + // that would result in obscure exception later, we throw an appropriate + // exception right now + throw BootstrapLogger.LOG.cdiApiVersionMismatch(); } + } - private void setupInitialServices() { - if (initialServices.contains(TypeStore.class)) { - return; - } - // instantiate initial services which we need for this phase - TypeStore store = new TypeStore(); - SharedObjectCache cache = new SharedObjectCache(); - ReflectionCache reflectionCache = ReflectionCacheFactory.newInstance(store); - ClassTransformer classTransformer = new ClassTransformer(store, cache, reflectionCache, contextId); - initialServices.add(TypeStore.class, store); - initialServices.add(SharedObjectCache.class, cache); - initialServices.add(ReflectionCache.class, reflectionCache); - initialServices.add(ClassTransformer.class, classTransformer); - } - - private void addImplementationServices(ServiceRegistry services) { - final WeldModules modules = new WeldModules(); - services.add(WeldModules.class, modules); - - final WeldConfiguration configuration = services.get(WeldConfiguration.class); - services.add(SlimAnnotatedTypeStore.class, new SlimAnnotatedTypeStoreImpl()); - if (services.get(ClassTransformer.class) == null) { - throw new IllegalStateException(ClassTransformer.class.getSimpleName() + " not installed."); - } - services.add(MemberTransformer.class, new MemberTransformer(services.get(ClassTransformer.class))); - services.add(MetaAnnotationStore.class, new MetaAnnotationStore(services.get(ClassTransformer.class))); + private void setupInitialServices() { + if (initialServices.contains(TypeStore.class)) { + return; + } + // instantiate initial services which we need for this phase + TypeStore store = new TypeStore(); + SharedObjectCache cache = new SharedObjectCache(); + ReflectionCache reflectionCache = ReflectionCacheFactory.newInstance(store); + ClassTransformer classTransformer = + new ClassTransformer(store, cache, reflectionCache, contextId); + initialServices.add(TypeStore.class, store); + initialServices.add(SharedObjectCache.class, cache); + initialServices.add(ReflectionCache.class, reflectionCache); + initialServices.add(ClassTransformer.class, classTransformer); + } + + private void addImplementationServices(ServiceRegistry services) { + final WeldModules modules = new WeldModules(); + services.add(WeldModules.class, modules); + + final WeldConfiguration configuration = + services.get(WeldConfiguration.class); + services.add(SlimAnnotatedTypeStore.class, + new SlimAnnotatedTypeStoreImpl()); + if (services.get(ClassTransformer.class) == null) { + throw new IllegalStateException(ClassTransformer.class.getSimpleName() + + " not installed."); + } + services.add(MemberTransformer.class, + new MemberTransformer(services.get(ClassTransformer.class))); + services.add(MetaAnnotationStore.class, + new MetaAnnotationStore(services.get(ClassTransformer.class))); + + BeanIdentifierIndex beanIdentifierIndex = null; + if (configuration.getBooleanProperty( + ConfigurationKey.BEAN_IDENTIFIER_INDEX_OPTIMIZATION)) { + beanIdentifierIndex = new BeanIdentifierIndex(); + services.add(BeanIdentifierIndex.class, beanIdentifierIndex); + } - BeanIdentifierIndex beanIdentifierIndex = null; - if (configuration.getBooleanProperty(ConfigurationKey.BEAN_IDENTIFIER_INDEX_OPTIMIZATION)) { - beanIdentifierIndex = new BeanIdentifierIndex(); - services.add(BeanIdentifierIndex.class, beanIdentifierIndex); - } + services.add(ContextualStore.class, + new ContextualStoreImpl(contextId, beanIdentifierIndex)); + services.add(CurrentInjectionPoint.class, new CurrentInjectionPoint()); + services.add(CurrentEventMetadata.class, new CurrentEventMetadata()); + services.add(SpecializationAndEnablementRegistry.class, + new SpecializationAndEnablementRegistry()); + services.add(MissingDependenciesRegistry.class, + new MissingDependenciesRegistry()); - services.add(ContextualStore.class, new ContextualStoreImpl(contextId, beanIdentifierIndex)); - services.add(CurrentInjectionPoint.class, new CurrentInjectionPoint()); - services.add(CurrentEventMetadata.class, new CurrentEventMetadata()); - services.add(SpecializationAndEnablementRegistry.class, new SpecializationAndEnablementRegistry()); - services.add(MissingDependenciesRegistry.class, new MissingDependenciesRegistry()); - - /* - * Setup ExecutorServices - */ - ExecutorServices executor = services.get(ExecutorServices.class); - if (executor == null) { - executor = ExecutorServicesFactory.create(DefaultResourceLoader.INSTANCE, configuration); - if (executor != null) { - services.add(ExecutorServices.class, executor); - } - } + /* + * Setup ExecutorServices + */ + ExecutorServices executor = services.get(ExecutorServices.class); + if (executor == null) { + executor = ExecutorServicesFactory.create(DefaultResourceLoader.INSTANCE, + configuration); + if (executor != null) { + services.add(ExecutorServices.class, executor); + } + } - services.add(RequiredAnnotationDiscovery.class, new RequiredAnnotationDiscovery(services.get(ReflectionCache.class))); + services.add( + RequiredAnnotationDiscovery.class, + new RequiredAnnotationDiscovery(services.get(ReflectionCache.class))); - services.add(GlobalEnablementBuilder.class, new GlobalEnablementBuilder()); - if (!services.contains(HttpContextActivationFilter.class)) { - services.add(HttpContextActivationFilter.class, AcceptingHttpContextActivationFilter.INSTANCE); - } - services.add(ProtectionDomainCache.class, new ProtectionDomainCache()); + services.add(GlobalEnablementBuilder.class, new GlobalEnablementBuilder()); + if (!services.contains(HttpContextActivationFilter.class)) { + services.add(HttpContextActivationFilter.class, + AcceptingHttpContextActivationFilter.INSTANCE); + } + services.add(ProtectionDomainCache.class, new ProtectionDomainCache()); - services.add(ProxyInstantiator.class, ProxyInstantiator.Factory.create(configuration)); + services.add(ProxyInstantiator.class, + ProxyInstantiator.Factory.create(configuration)); - services.add(ObserverNotifierFactory.class, DefaultObserverNotifierFactory.INSTANCE); + services.add(ObserverNotifierFactory.class, + DefaultObserverNotifierFactory.INSTANCE); - services.add(ResourceInjectionFactory.class, new ResourceInjectionFactory()); + services.add(ResourceInjectionFactory.class, + new ResourceInjectionFactory()); - modules.postServiceRegistration(contextId, services); + modules.postServiceRegistration(contextId, services); - /* - * Setup Validator - */ - Validator validator; - if (configuration.getBooleanProperty(ConfigurationKey.CONCURRENT_DEPLOYMENT) && services.contains(ExecutorServices.class)) { - validator = new ConcurrentValidator(modules.getPluggableValidators(), executor, - UnusedBeans.isEnabled(configuration) ? new ConcurrentHashMap<>() : null); - } else { - validator = new Validator(modules.getPluggableValidators(), - UnusedBeans.isEnabled(configuration) ? new HashMap<>() : null); - } - services.add(Validator.class, validator); - - GlobalObserverNotifierService observerNotificationService = new GlobalObserverNotifierService(services, contextId); - services.add(GlobalObserverNotifierService.class, observerNotificationService); - - /* - * Preloader for container lifecycle events - */ - ContainerLifecycleEventPreloader preloader = null; - int preloaderThreadPoolSize = configuration.getIntegerProperty(ConfigurationKey.PRELOADER_THREAD_POOL_SIZE); - if (preloaderThreadPoolSize > 0 && Permissions.hasPermission(Permissions.MODIFY_THREAD_GROUP)) { - preloader = new ContainerLifecycleEventPreloader(preloaderThreadPoolSize, observerNotificationService.getGlobalLenientObserverNotifier()); - } - services.add(ContainerLifecycleEvents.class, new ContainerLifecycleEvents(preloader, services.get(RequiredAnnotationDiscovery.class))); - if (environment.isEEModulesAware()) { - services.add(BeanDeploymentModules.class, new BeanDeploymentModules(contextId, services)); - } + /* + * Setup Validator + */ + Validator validator; + if (configuration.getBooleanProperty( + ConfigurationKey.CONCURRENT_DEPLOYMENT) && + services.contains(ExecutorServices.class)) { + validator = new ConcurrentValidator( + modules.getPluggableValidators(), executor, + UnusedBeans.isEnabled(configuration) ? new ConcurrentHashMap<>() + : null); + } else { + validator = new Validator( + modules.getPluggableValidators(), + UnusedBeans.isEnabled(configuration) ? new HashMap<>() : null); } + services.add(Validator.class, validator); - // needs to be resolved once extension beans are deployed - private void installFastProcessAnnotatedTypeResolver(ServiceRegistry services) { - ClassFileServices classFileServices = services.get(ClassFileServices.class); - if (classFileServices != null) { - final GlobalObserverNotifierService observers = services.get(GlobalObserverNotifierService.class); - try { - final FastProcessAnnotatedTypeResolver resolver = new FastProcessAnnotatedTypeResolver(observers.getAllObserverMethods()); - services.add(FastProcessAnnotatedTypeResolver.class, resolver); - } catch (UnsupportedObserverMethodException e) { - BootstrapLogger.LOG.notUsingFastResolver(e.getObserver()); - return; - } - } + GlobalObserverNotifierService observerNotificationService = + new GlobalObserverNotifierService(services, contextId); + services.add(GlobalObserverNotifierService.class, + observerNotificationService); + + /* + * Preloader for container lifecycle events + */ + ContainerLifecycleEventPreloader preloader = null; + int preloaderThreadPoolSize = configuration.getIntegerProperty( + ConfigurationKey.PRELOADER_THREAD_POOL_SIZE); + if (preloaderThreadPoolSize > 0 && + Permissions.hasPermission(Permissions.MODIFY_THREAD_GROUP)) { + preloader = new ContainerLifecycleEventPreloader( + preloaderThreadPoolSize, + observerNotificationService.getGlobalLenientObserverNotifier()); + } + services.add( + ContainerLifecycleEvents.class, + new ContainerLifecycleEvents( + preloader, services.get(RequiredAnnotationDiscovery.class))); + if (environment.isEEModulesAware()) { + services.add(BeanDeploymentModules.class, + new BeanDeploymentModules(contextId, services)); } + } + + // needs to be resolved once extension beans are deployed + private void + installFastProcessAnnotatedTypeResolver(ServiceRegistry services) { + ClassFileServices classFileServices = services.get(ClassFileServices.class); + if (classFileServices != null) { + final GlobalObserverNotifierService observers = + services.get(GlobalObserverNotifierService.class); + try { + final FastProcessAnnotatedTypeResolver resolver = + new FastProcessAnnotatedTypeResolver( + observers.getAllObserverMethods()); + services.add(FastProcessAnnotatedTypeResolver.class, resolver); + } catch (UnsupportedObserverMethodException e) { + BootstrapLogger.LOG.notUsingFastResolver(e.getObserver()); + return; + } + } + } - public void startInitialization() { - if (deploymentManager == null) { - throw BootstrapLogger.LOG.managerNotInitialized(); - } - tracker.start(Tracker.OP_START_INIT); + public void startInitialization() { + if (deploymentManager == null) { + throw BootstrapLogger.LOG.managerNotInitialized(); + } + tracker.start(Tracker.OP_START_INIT); - Set physicalBeanDeploymentArchives = new HashSet(getBeanDeployments()); + Set physicalBeanDeploymentArchives = + new HashSet(getBeanDeployments()); - ExtensionBeanDeployer extensionBeanDeployer = new ExtensionBeanDeployer(deploymentManager, deployment, bdaMapping, contexts); - extensionBeanDeployer.addExtensions(extensions); - extensionBeanDeployer.deployBeans(); + ExtensionBeanDeployer extensionBeanDeployer = new ExtensionBeanDeployer( + deploymentManager, deployment, bdaMapping, contexts); + extensionBeanDeployer.addExtensions(extensions); + extensionBeanDeployer.deployBeans(); - installFastProcessAnnotatedTypeResolver(deploymentManager.getServices()); + installFastProcessAnnotatedTypeResolver(deploymentManager.getServices()); - // Add the Deployment BeanManager Bean to the Deployment BeanManager - deploymentManager.addBean(new BeanManagerBean(deploymentManager)); - deploymentManager.addBean(new BeanManagerImplBean(deploymentManager)); + // Add the Deployment BeanManager Bean to the Deployment BeanManager + deploymentManager.addBean(new BeanManagerBean(deploymentManager)); + deploymentManager.addBean(new BeanManagerImplBean(deploymentManager)); - // Re-Read the deployment structure, bdaMapping will be the physical - // structure, and will add in BDAs for any extensions outside a - // physical BDA - deploymentVisitor.visit(); + // Re-Read the deployment structure, bdaMapping will be the physical + // structure, and will add in BDAs for any extensions outside a + // physical BDA + deploymentVisitor.visit(); - tracker.start(Tracker.OP_BBD); - BeforeBeanDiscoveryImpl.fire(deploymentManager, deployment, bdaMapping, contexts); - tracker.end(); + tracker.start(Tracker.OP_BBD); + BeforeBeanDiscoveryImpl.fire(deploymentManager, deployment, bdaMapping, + contexts); + tracker.end(); - // for each physical BDA transform its classes into AnnotatedType instances - for (BeanDeployment beanDeployment : physicalBeanDeploymentArchives) { - beanDeployment.createClasses(); - } + // for each physical BDA transform its classes into AnnotatedType instances + for (BeanDeployment beanDeployment : physicalBeanDeploymentArchives) { + beanDeployment.createClasses(); + } - // Re-Read the deployment structure, bdaMapping will be the physical - // structure, extensions and any classes added using addAnnotatedType - // outside the physical BDA - deploymentVisitor.visit(); + // Re-Read the deployment structure, bdaMapping will be the physical + // structure, extensions and any classes added using addAnnotatedType + // outside the physical BDA + deploymentVisitor.visit(); - for (BeanDeployment beanDeployment : getBeanDeployments()) { - beanDeployment.createTypes(); - } + for (BeanDeployment beanDeployment : getBeanDeployments()) { + beanDeployment.createTypes(); + } - tracker.start(Tracker.OP_ATD); - AfterTypeDiscoveryImpl.fire(deploymentManager, deployment, bdaMapping, contexts); - tracker.end(); + tracker.start(Tracker.OP_ATD); + AfterTypeDiscoveryImpl.fire(deploymentManager, deployment, bdaMapping, + contexts); + tracker.end(); - for (BeanDeployment beanDeployment : getBeanDeployments()) { - beanDeployment.createEnablement(); - } - tracker.end(); + for (BeanDeployment beanDeployment : getBeanDeployments()) { + beanDeployment.createEnablement(); } + tracker.end(); + } + public void deployBeans() { + tracker.start(Tracker.OP_DEPLOY_BEANS); + for (BeanDeployment deployment : getBeanDeployments()) { + deployment.createBeans(environment); + } + // we must use separate loops, otherwise cyclic specialization would not + // work + for (BeanDeployment deployment : getBeanDeployments()) { + deployment.getBeanDeployer().processClassBeanAttributes(); + deployment.getBeanDeployer().createProducersAndObservers(); + } + for (BeanDeployment deployment : getBeanDeployments()) { + deployment.getBeanDeployer().processProducerAttributes(); + deployment.getBeanDeployer().createNewBeans(); + } + for (BeanDeployment beanDeployment : getBeanDeployments()) { + beanDeployment.deploySpecialized(environment); + } + for (BeanDeployment beanDeployment : getBeanDeployments()) { + beanDeployment.deployBeans(environment); + } - public void deployBeans() { - tracker.start(Tracker.OP_DEPLOY_BEANS); - for (BeanDeployment deployment : getBeanDeployments()) { - deployment.createBeans(environment); - } - // we must use separate loops, otherwise cyclic specialization would not work - for (BeanDeployment deployment : getBeanDeployments()) { - deployment.getBeanDeployer().processClassBeanAttributes(); - deployment.getBeanDeployer().createProducersAndObservers(); - } - for (BeanDeployment deployment : getBeanDeployments()) { - deployment.getBeanDeployer().processProducerAttributes(); - deployment.getBeanDeployer().createNewBeans(); - } - for (BeanDeployment beanDeployment : getBeanDeployments()) { - beanDeployment.deploySpecialized(environment); - } - for (BeanDeployment beanDeployment : getBeanDeployments()) { - beanDeployment.deployBeans(environment); - } - - getContainer().setState(ContainerState.DISCOVERED); + getContainer().setState(ContainerState.DISCOVERED); - // Flush caches for BeanManager.getBeans() to be usable in ABD (WELD-1729) - flushCaches(); + // Flush caches for BeanManager.getBeans() to be usable in ABD (WELD-1729) + flushCaches(); - tracker.start(Tracker.OP_ABD); - AfterBeanDiscoveryImpl.fire(deploymentManager, deployment, bdaMapping, contexts); - tracker.end(); + tracker.start(Tracker.OP_ABD); + AfterBeanDiscoveryImpl.fire(deploymentManager, deployment, bdaMapping, + contexts); + tracker.end(); - // Extensions may have registered beans / observers. We need to flush caches. - flushCaches(); + // Extensions may have registered beans / observers. We need to flush + // caches. + flushCaches(); - // If needed, recreate enablement once again - extensions may have registered interceptors, decorators and alternatives - if(deployment.getServices().getRequired(GlobalEnablementBuilder.class).isDirty()) { - for (BeanDeployment beanDeployment : getBeanDeployments()) { - beanDeployment.createEnablement(); - } - } + // If needed, recreate enablement once again - extensions may have + // registered interceptors, decorators and alternatives + if (deployment.getServices() + .getRequired(GlobalEnablementBuilder.class) + .isDirty()) { + for (BeanDeployment beanDeployment : getBeanDeployments()) { + beanDeployment.createEnablement(); + } + } - // Re-read the deployment structure, bdaMapping will be the physical - // structure, extensions, classes, and any beans added using addBean - // outside the physical structure - deploymentVisitor.visit(); + // Re-read the deployment structure, bdaMapping will be the physical + // structure, extensions, classes, and any beans added using addBean + // outside the physical structure + deploymentVisitor.visit(); + + for (BeanDeployment beanDeployment : getBeanDeployments()) { + beanDeployment.getBeanManager() + .getServices() + .get(InjectionTargetService.class) + .initialize(); + beanDeployment.afterBeanDiscovery(environment); + } + getContainer().putBeanDeployments(bdaMapping); + getContainer().setState(ContainerState.DEPLOYED); + tracker.end(); + } + + public void validateBeans() { + BootstrapLogger.LOG.validatingBeans(); + tracker.start(Tracker.OP_VALIDATE_BEANS); + try { + for (BeanDeployment beanDeployment : getBeanDeployments()) { + BeanManagerImpl beanManager = beanDeployment.getBeanManager(); + beanManager.getBeanResolver().clear(); + deployment.getServices() + .get(Validator.class) + .validateDeployment(beanManager, beanDeployment); + beanManager.getServices().get(InjectionTargetService.class).validate(); + } + } catch (Exception e) { + validationFailed(e); + throw e; + } + getContainer().setState(ContainerState.VALIDATED); + tracker.start(Tracker.OP_ADV); + AfterDeploymentValidationImpl.fire(deploymentManager); + + final BeanIdentifierIndex index = + deploymentManager.getServices().get(BeanIdentifierIndex.class); + if (index != null) { + // Build a special index of bean identifiers + index.build(getBeansForBeanIdentifierIndex()); + } - for (BeanDeployment beanDeployment : getBeanDeployments()) { - beanDeployment.getBeanManager().getServices().get(InjectionTargetService.class).initialize(); - beanDeployment.afterBeanDiscovery(environment); - } - getContainer().putBeanDeployments(bdaMapping); - getContainer().setState(ContainerState.DEPLOYED); - tracker.end(); - } - - public void validateBeans() { - BootstrapLogger.LOG.validatingBeans(); - tracker.start(Tracker.OP_VALIDATE_BEANS); - try { - for (BeanDeployment beanDeployment : getBeanDeployments()) { - BeanManagerImpl beanManager = beanDeployment.getBeanManager(); - beanManager.getBeanResolver().clear(); - deployment.getServices().get(Validator.class).validateDeployment(beanManager, beanDeployment); - beanManager.getServices().get(InjectionTargetService.class).validate(); - } - } catch (Exception e) { - validationFailed(e); - throw e; - } - getContainer().setState(ContainerState.VALIDATED); - tracker.start(Tracker.OP_ADV); - AfterDeploymentValidationImpl.fire(deploymentManager); - - final BeanIdentifierIndex index = deploymentManager.getServices().get(BeanIdentifierIndex.class); - if (index != null) { - // Build a special index of bean identifiers - index.build(getBeansForBeanIdentifierIndex()); - } + // feed BeanDeploymentModule registry + final BeanDeploymentModules modules = + deploymentManager.getServices().get(BeanDeploymentModules.class); + if (modules != null) { + modules.processBeanDeployments(getBeanDeployments()); + BootstrapLogger.LOG.debugv("EE modules: {0}", modules); + } - // feed BeanDeploymentModule registry - final BeanDeploymentModules modules = deploymentManager.getServices().get(BeanDeploymentModules.class); - if (modules != null) { - modules.processBeanDeployments(getBeanDeployments()); - BootstrapLogger.LOG.debugv("EE modules: {0}", modules); - } + tracker.end(); + tracker.end(); + } + + public void endInitialization() { + tracker.start(Tracker.OP_END_INIT); + + // Register the managers so external requests can handle them + // clear the TypeSafeResolvers, so data that is only used at startup + // is not kept around using up memory + flushCaches(); + deploymentManager.getServices().cleanupAfterBoot(); + deploymentManager.cleanupAfterBoot(); + for (BeanDeployment beanDeployment : getBeanDeployments()) { + BeanManagerImpl beanManager = beanDeployment.getBeanManager(); + beanManager.getInterceptorMetadataReader().cleanAfterBoot(); + beanManager.getServices().cleanupAfterBoot(); + beanManager.cleanupAfterBoot(); + // for safety sake perform after boot cleanup on all services in BDA + beanDeployment.getBeanDeploymentArchive() + .getServices() + .cleanupAfterBoot(); + // clean up beans + for (Bean bean : beanManager.getBeans()) { + if (bean instanceof RIBean) { + RIBean riBean = (RIBean)bean; + riBean.cleanupAfterBoot(); + } + } + // clean up decorators + for (Decorator decorator : beanManager.getDecorators()) { + if (decorator instanceof DecoratorImpl) { + Reflections.>cast(decorator).cleanupAfterBoot(); + } + } + // clean up interceptors + for (Interceptor interceptor : beanManager.getInterceptors()) { + if (interceptor instanceof InterceptorImpl) { + Reflections.>cast(interceptor).cleanupAfterBoot(); + } + } + } + for (BeanDeployment beanDeployment : getBeanDeployments()) { + beanDeployment.getBeanDeployer().cleanup(); + } - tracker.end(); - tracker.end(); - } - - public void endInitialization() { - tracker.start(Tracker.OP_END_INIT); - - // Register the managers so external requests can handle them - // clear the TypeSafeResolvers, so data that is only used at startup - // is not kept around using up memory - flushCaches(); - deploymentManager.getServices().cleanupAfterBoot(); - deploymentManager.cleanupAfterBoot(); - for (BeanDeployment beanDeployment : getBeanDeployments()) { - BeanManagerImpl beanManager = beanDeployment.getBeanManager(); - beanManager.getInterceptorMetadataReader().cleanAfterBoot(); - beanManager.getServices().cleanupAfterBoot(); - beanManager.cleanupAfterBoot(); - // for safety sake perform after boot cleanup on all services in BDA - beanDeployment.getBeanDeploymentArchive().getServices().cleanupAfterBoot(); - // clean up beans - for (Bean bean : beanManager.getBeans()) { - if (bean instanceof RIBean) { - RIBean riBean = (RIBean) bean; - riBean.cleanupAfterBoot(); - } - } - // clean up decorators - for (Decorator decorator : beanManager.getDecorators()) { - if (decorator instanceof DecoratorImpl) { - Reflections.>cast(decorator).cleanupAfterBoot(); - } - } - // clean up interceptors - for (Interceptor interceptor : beanManager.getInterceptors()) { - if (interceptor instanceof InterceptorImpl) { - Reflections.>cast(interceptor).cleanupAfterBoot(); - } - } - } - for (BeanDeployment beanDeployment : getBeanDeployments()) { - beanDeployment.getBeanDeployer().cleanup(); - } + // Perform additional cleanup if removing unused beans + if (UnusedBeans.isEnabled( + deploymentManager.getServices().get(WeldConfiguration.class))) { + deploymentManager.getBeanResolver().clear(); + for (BeanDeployment beanDeployment : getBeanDeployments()) { + beanDeployment.getBeanManager().getBeanResolver().clear(); + } + deploymentManager.getServices().get(Validator.class).clearResolved(); + deploymentManager.getServices() + .get(ClassTransformer.class) + .cleanupAfterBoot(); + } - // Perform additional cleanup if removing unused beans - if (UnusedBeans.isEnabled(deploymentManager.getServices().get(WeldConfiguration.class))) { - deploymentManager.getBeanResolver().clear(); - for (BeanDeployment beanDeployment : getBeanDeployments()) { - beanDeployment.getBeanManager().getBeanResolver().clear(); - } - deploymentManager.getServices().get(Validator.class).clearResolved(); - deploymentManager.getServices().get(ClassTransformer.class).cleanupAfterBoot(); - } + getContainer().setState(ContainerState.INITIALIZED); - getContainer().setState(ContainerState.INITIALIZED); - - final BeanDeploymentModules modules = deploymentManager.getServices().get(BeanDeploymentModules.class); - if (modules != null) { - // fire @Initialized(ApplicationScoped.class) for non-web modules - // web modules are handled by HttpContextLifecycle - for (BeanDeploymentModule module : modules) { - if (!module.isWebModule()) { - module.fireEvent(Object.class, ContextEvent.APPLICATION_INITIALIZED, Initialized.Literal.APPLICATION); - } - } + final BeanDeploymentModules modules = + deploymentManager.getServices().get(BeanDeploymentModules.class); + if (modules != null) { + // fire @Initialized(ApplicationScoped.class) for non-web modules + // web modules are handled by HttpContextLifecycle + for (BeanDeploymentModule module : modules) { + if (!module.isWebModule()) { + module.fireEvent(Object.class, ContextEvent.APPLICATION_INITIALIZED, + Initialized.Literal.APPLICATION); } - tracker.close(); - } - - private void flushCaches() { - deploymentManager.getBeanResolver().clear(); - deploymentManager.getAccessibleLenientObserverNotifier().clear(); - deploymentManager.getGlobalStrictObserverNotifier().clear(); - deploymentManager.getGlobalLenientObserverNotifier().clear(); - deploymentManager.getDecoratorResolver().clear(); - deploymentManager.getInterceptorResolver().clear(); - deploymentManager.getNameBasedResolver().clear(); - for (BeanDeployment beanDeployment : getBeanDeployments()) { - BeanManagerImpl beanManager = beanDeployment.getBeanManager(); - beanManager.getBeanResolver().clear(); - beanManager.getAccessibleLenientObserverNotifier().clear(); - beanManager.getDecoratorResolver().clear(); - beanManager.getInterceptorResolver().clear(); - beanManager.getNameBasedResolver().clear(); - } - } - - private Collection getBeanDeployments() { - return bdaMapping.getBeanDeployments(); + } } - - private Container getContainer() { - return Container.instance(contextId); + tracker.close(); + } + + private void flushCaches() { + deploymentManager.getBeanResolver().clear(); + deploymentManager.getAccessibleLenientObserverNotifier().clear(); + deploymentManager.getGlobalStrictObserverNotifier().clear(); + deploymentManager.getGlobalLenientObserverNotifier().clear(); + deploymentManager.getDecoratorResolver().clear(); + deploymentManager.getInterceptorResolver().clear(); + deploymentManager.getNameBasedResolver().clear(); + for (BeanDeployment beanDeployment : getBeanDeployments()) { + BeanManagerImpl beanManager = beanDeployment.getBeanManager(); + beanManager.getBeanResolver().clear(); + beanManager.getAccessibleLenientObserverNotifier().clear(); + beanManager.getDecoratorResolver().clear(); + beanManager.getInterceptorResolver().clear(); + beanManager.getNameBasedResolver().clear(); } + } - protected Collection> createContexts(ServiceRegistry services) { - List> contexts = new ArrayList>(); + private Collection getBeanDeployments() { + return bdaMapping.getBeanDeployments(); + } - BeanIdentifierIndex beanIdentifierIndex = services.get(BeanIdentifierIndex.class); + private Container getContainer() { return Container.instance(contextId); } - /* - * Register a full set of bound and unbound contexts. Although we may not use all of - * these (e.g. if we are running in a servlet environment) they may be - * useful for an application. - */ - Set boundQualifires = ImmutableSet.builder().addAll(Bindings.DEFAULT_QUALIFIERS).add(BoundLiteral.INSTANCE).build(); - Set unboundQualifiers = ImmutableSet.builder().addAll(Bindings.DEFAULT_QUALIFIERS).add(UnboundLiteral.INSTANCE).build(); - contexts.add(new ContextHolder(new ApplicationContextImpl(contextId), ApplicationContext.class, unboundQualifiers)); - contexts.add(new ContextHolder(new SingletonContextImpl(contextId), SingletonContext.class, unboundQualifiers)); - contexts.add(new ContextHolder(new BoundSessionContextImpl(contextId, beanIdentifierIndex), BoundSessionContext.class, boundQualifires)); - contexts.add(new ContextHolder(new BoundConversationContextImpl(contextId, services), BoundConversationContext.class, boundQualifires)); - contexts.add(new ContextHolder(new BoundRequestContextImpl(contextId), BoundRequestContext.class, boundQualifires)); - contexts.add(new ContextHolder(new RequestContextImpl(contextId), RequestContext.class, unboundQualifiers)); - contexts.add(new ContextHolder(new DependentContextImpl(services.get(ContextualStore.class)), DependentContext.class, unboundQualifiers)); + protected Collection> + createContexts(ServiceRegistry services) { + List> contexts = + new ArrayList>(); - services.get(WeldModules.class).postContextRegistration(contextId, services, contexts); + BeanIdentifierIndex beanIdentifierIndex = + services.get(BeanIdentifierIndex.class); - /* - * Register the contexts with the bean manager and add the beans to the - * deployment manager so that they are easily accessible (contexts are app - * scoped) - */ - for (ContextHolder context : contexts) { - deploymentManager.addContext(context.getContext()); - deploymentManager.addBean(ContextBean.of(context, deploymentManager)); - } + /* + * Register a full set of bound and unbound contexts. Although we may not + * use all of these (e.g. if we are running in a servlet environment) they + * may be useful for an application. + */ + Set boundQualifires = ImmutableSet.builder() + .addAll(Bindings.DEFAULT_QUALIFIERS) + .add(BoundLiteral.INSTANCE) + .build(); + Set unboundQualifiers = ImmutableSet.builder() + .addAll(Bindings.DEFAULT_QUALIFIERS) + .add(UnboundLiteral.INSTANCE) + .build(); + contexts.add(new ContextHolder( + new ApplicationContextImpl(contextId), ApplicationContext.class, + unboundQualifiers)); + contexts.add(new ContextHolder( + new SingletonContextImpl(contextId), SingletonContext.class, + unboundQualifiers)); + contexts.add(new ContextHolder( + new BoundSessionContextImpl(contextId, beanIdentifierIndex), + BoundSessionContext.class, boundQualifires)); + contexts.add(new ContextHolder( + new BoundConversationContextImpl(contextId, services), + BoundConversationContext.class, boundQualifires)); + contexts.add(new ContextHolder( + new BoundRequestContextImpl(contextId), BoundRequestContext.class, + boundQualifires)); + contexts.add(new ContextHolder( + new RequestContextImpl(contextId), RequestContext.class, + unboundQualifiers)); + contexts.add(new ContextHolder( + new DependentContextImpl(services.get(ContextualStore.class)), + DependentContext.class, unboundQualifiers)); + + services.get(WeldModules.class) + .postContextRegistration(contextId, services, contexts); - return contexts; + /* + * Register the contexts with the bean manager and add the beans to the + * deployment manager so that they are easily accessible (contexts are app + * scoped) + */ + for (ContextHolder context : contexts) { + deploymentManager.addContext(context.getContext()); + deploymentManager.addBean(ContextBean.of(context, deploymentManager)); } - protected static void verifyServices(ServiceRegistry services, Set> requiredServices, Object target) { - for (Class serviceType : requiredServices) { - if (!services.contains(serviceType)) { - throw BootstrapLogger.LOG.unspecifiedRequiredService(serviceType.getName(), target); - } - } + return contexts; + } + + protected static void + verifyServices(ServiceRegistry services, + Set> requiredServices, + Object target) { + for (Class serviceType : requiredServices) { + if (!services.contains(serviceType)) { + throw BootstrapLogger.LOG.unspecifiedRequiredService( + serviceType.getName(), target); + } } - - public TypeDiscoveryConfiguration startExtensions(Iterable> extensions) { - setExtensions(extensions); - // TODO WELD-1624 Weld should fire BeforeBeanDiscovery to allow extensions to register additional scopes - final Set> beanDefiningAnnotations = ImmutableSet.of( - // built-in scopes - Dependent.class, RequestScoped.class, ConversationScoped.class, SessionScoped.class, ApplicationScoped.class, - javax.interceptor.Interceptor.class, javax.decorator.Decorator.class, - // built-in stereotype - Model.class, - // meta-annotations - NormalScope.class, Stereotype.class); - return new TypeDiscoveryConfigurationImpl(beanDefiningAnnotations); - } - - /** - * Right now, only session and conversation scoped beans (except for built-in beans) are taken into account. - * - * @return the set of beans the index should be built from - */ - private Set> getBeansForBeanIdentifierIndex() { - Set> beans = new HashSet>(); - for (BeanDeployment beanDeployment : getBeanDeployments()) { - for (Bean bean : beanDeployment.getBeanManager().getBeans()) { - if (!(bean instanceof AbstractBuiltInBean) - && (bean.getScope().equals(SessionScoped.class) || bean.getScope().equals(ConversationScoped.class))) { - beans.add(bean); - } - } - } - return beans; + } + + public TypeDiscoveryConfiguration + startExtensions(Iterable> extensions) { + setExtensions(extensions); + // TODO WELD-1624 Weld should fire BeforeBeanDiscovery to allow extensions + // to register additional scopes + final Set> beanDefiningAnnotations = + ImmutableSet.of( + // built-in scopes + Dependent.class, RequestScoped.class, ConversationScoped.class, + SessionScoped.class, ApplicationScoped.class, + javax.interceptor.Interceptor.class, + javax.decorator.Decorator.class, + // built-in stereotype + Model.class, + // meta-annotations + NormalScope.class, Stereotype.class); + return new TypeDiscoveryConfigurationImpl(beanDefiningAnnotations); + } + + /** + * Right now, only session and conversation scoped beans (except for built-in + * beans) are taken into account. + * + * @return the set of beans the index should be built from + */ + private Set> getBeansForBeanIdentifierIndex() { + Set> beans = new HashSet>(); + for (BeanDeployment beanDeployment : getBeanDeployments()) { + for (Bean bean : beanDeployment.getBeanManager().getBeans()) { + if (!(bean instanceof AbstractBuiltInBean) && + (bean.getScope().equals(SessionScoped.class) || + bean.getScope().equals(ConversationScoped.class))) { + beans.add(bean); + } + } } + return beans; + } - private void setExtensions(Iterable> extensions) { - this.extensions = new ArrayList>(); - Iterables.addAll(this.extensions, extensions); - } + private void setExtensions(Iterable> extensions) { + this.extensions = new ArrayList>(); + Iterables.addAll(this.extensions, extensions); + } - BeanManagerImpl getDeploymentManager() { - return deploymentManager; - } + BeanManagerImpl getDeploymentManager() { return deploymentManager; } - BeanDeploymentArchiveMapping getBdaMapping() { - return bdaMapping; - } + BeanDeploymentArchiveMapping getBdaMapping() { return bdaMapping; } - Collection> getContexts() { - return contexts; - } + Collection> getContexts() { + return contexts; + } - Deployment getDeployment() { - return deployment; - } + Deployment getDeployment() { return deployment; } - private void validationFailed(Exception failure) { - for (BeanDeployment beanDeployment : getBeanDeployments()) { - beanDeployment.getBeanManager().validationFailed(failure, environment); - } + private void validationFailed(Exception failure) { + for (BeanDeployment beanDeployment : getBeanDeployments()) { + beanDeployment.getBeanManager().validationFailed(failure, environment); } - + } } diff --git a/impl/src/main/java/org/jboss/weld/bootstrap/enablement/Item.java b/impl/src/main/java/org/jboss/weld/bootstrap/enablement/Item.java index a840536ea4..1558a2a8df 100644 --- a/impl/src/main/java/org/jboss/weld/bootstrap/enablement/Item.java +++ b/impl/src/main/java/org/jboss/weld/bootstrap/enablement/Item.java @@ -18,7 +18,6 @@ import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; - import org.jboss.weld.util.Preconditions; /** @@ -28,89 +27,87 @@ */ class Item implements Comparable { - static final int ITEM_PRIORITY_SCALE_POWER = 10; + static final int ITEM_PRIORITY_SCALE_POWER = 10; - private final Class javaClass; + private final Class javaClass; - private final int originalPriority; + private final int originalPriority; - private final AtomicInteger priority; + private final AtomicInteger priority; - Item(Class javaClass, int priority) { - this(javaClass, priority, priority); - } + Item(Class javaClass, int priority) { + this(javaClass, priority, priority); + } - Item(Class javaClass, int originalPriority, int priority) { - Preconditions.checkArgumentNotNull(javaClass, "javaClass"); - Preconditions.checkArgumentNotNull(priority, "priority"); - Preconditions.checkArgumentNotNull(originalPriority, "originalPriority"); - this.javaClass = javaClass; - this.priority = new AtomicInteger(priority); - this.originalPriority = originalPriority; - } + Item(Class javaClass, int originalPriority, int priority) { + Preconditions.checkArgumentNotNull(javaClass, "javaClass"); + Preconditions.checkArgumentNotNull(priority, "priority"); + Preconditions.checkArgumentNotNull(originalPriority, "originalPriority"); + this.javaClass = javaClass; + this.priority = new AtomicInteger(priority); + this.originalPriority = originalPriority; + } - void scalePriority() { - priority.getAndUpdate((p) -> p * ITEM_PRIORITY_SCALE_POWER); - } + void scalePriority() { + priority.getAndUpdate((p) -> p * ITEM_PRIORITY_SCALE_POWER); + } - Class getJavaClass() { - return javaClass; - } + Class getJavaClass() { return javaClass; } - int getPriority() { - return priority.get(); - } + int getPriority() { return priority.get(); } - int getOriginalPriority() { - return originalPriority; - } + int getOriginalPriority() { return originalPriority; } - int getNumberOfScaling() { - int current = priority.get(); - if (current == originalPriority) { - return 0; - } - int scaling = 0; - do { - current = current / ITEM_PRIORITY_SCALE_POWER; - scaling++; - } while (current != originalPriority); - return scaling; + int getNumberOfScaling() { + int current = priority.get(); + if (current == originalPriority) { + return 0; } - - @Override - public int compareTo(Item o) { - int p1 = priority.get(); - int p2 = o.priority.get(); - if (p1 == p2) { - /* - * The spec does not specify what happens if two records have the same priority. Instead of giving random results, we compare the records based on - * their class name lexicographically. - */ - return javaClass.getName().compareTo(o.javaClass.getName()); - } - return p1 - p2; + int scaling = 0; + do { + current = current / ITEM_PRIORITY_SCALE_POWER; + scaling++; + } while (current != originalPriority); + return scaling; + } + + @Override + public int compareTo(Item o) { + int p1 = priority.get(); + int p2 = o.priority.get(); + if (p1 == p2) { + /* + * The spec does not specify what happens if two records have the same + * priority. Instead of giving random results, we compare the records + * based on their class name lexicographically. + */ + return javaClass.getName().compareTo(o.javaClass.getName()); + } else if (p1 < p2) { + return -1; + } else { + return 1; } + } - @Override - public int hashCode() { - return javaClass.hashCode(); - } + @Override + public int hashCode() { + return javaClass.hashCode(); + } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof Item) { - Item that = (Item) obj; - return Objects.equals(javaClass, that.javaClass); - } - return false; + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; } - - @Override - public String toString() { - return "[Class=" + javaClass + ", priority=" + priority + "]"; + if (obj instanceof Item) { + Item that = (Item)obj; + return Objects.equals(javaClass, that.javaClass); } -} \ No newline at end of file + return false; + } + + @Override + public String toString() { + return "[Class=" + javaClass + ", priority=" + priority + "]"; + } +} diff --git a/impl/src/main/java/org/jboss/weld/bootstrap/events/ContainerLifecycleEventPreloader.java b/impl/src/main/java/org/jboss/weld/bootstrap/events/ContainerLifecycleEventPreloader.java index f57fee1216..e1d6891e41 100644 --- a/impl/src/main/java/org/jboss/weld/bootstrap/events/ContainerLifecycleEventPreloader.java +++ b/impl/src/main/java/org/jboss/weld/bootstrap/events/ContainerLifecycleEventPreloader.java @@ -16,65 +16,71 @@ */ package org.jboss.weld.bootstrap.events; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.lang.reflect.Type; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; - import org.jboss.weld.event.ObserverNotifier; import org.jboss.weld.executor.DaemonThreadFactory; import org.jboss.weld.util.reflection.ParameterizedTypeImpl; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - /** - * Allows observer methods for container lifecycle events to be resolved upfront while the deployment is waiting for classloader - * or reflection API. + * Allows observer methods for container lifecycle events to be resolved upfront + * while the deployment is waiting for classloader or reflection API. * * @author Jozef Hartinger * */ public class ContainerLifecycleEventPreloader { - private class PreloadingTask implements Callable { + private class PreloadingTask implements Callable { - private final Type type; + private final Type type; - public PreloadingTask(Type type) { - this.type = type; - } + public PreloadingTask(Type type) { this.type = type; } - @Override - public Void call() throws Exception { - notifier.resolveObserverMethods(type); - return null; - } + @Override + public Void call() throws Exception { + notifier.resolveObserverMethods(type); + return null; } + } - private final ExecutorService executor; - private final ObserverNotifier notifier; + private final ExecutorService executor; + private final ObserverNotifier notifier; - public ContainerLifecycleEventPreloader(int threadPoolSize, ObserverNotifier notifier) { - this.executor = Executors.newFixedThreadPool(threadPoolSize, new DaemonThreadFactory(new ThreadGroup("weld-preloaders"), "weld-preloader-")); - this.notifier = notifier; - } + public ContainerLifecycleEventPreloader(int threadPoolSize, + ObserverNotifier notifier) { + this.executor = Executors.newFixedThreadPool( + threadPoolSize, new DaemonThreadFactory("weld-preloader-")); + this.notifier = notifier; + } - /** - * In multi-threaded environment we often cannot leverage multiple core fully in bootstrap because the deployer - * threads are often blocked by the reflection API or waiting to get a classloader lock. While waiting for classes to be loaded or - * reflection metadata to be obtained, we can make use of the idle CPU cores and start resolving container lifecycle event observers - * (extensions) upfront for those types of events we know we will be firing. Since these resolutions are cached, firing of the - * lifecycle events will then be very fast. - * - */ - @SuppressFBWarnings(value = "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE", justification = "We never need to synchronize with the preloader.") - void preloadContainerLifecycleEvent(Class eventRawType, Type... typeParameters) { - executor.submit(new PreloadingTask(new ParameterizedTypeImpl(eventRawType, typeParameters, null))); - } + /** + * In multi-threaded environment we often cannot leverage multiple core fully + * in bootstrap because the deployer threads are often blocked by the + * reflection API or waiting to get a classloader lock. While waiting for + * classes to be loaded or reflection metadata to be obtained, we can make use + * of the idle CPU cores and start resolving container lifecycle event + * observers (extensions) upfront for those types of events we know we will be + * firing. Since these resolutions are cached, firing of the lifecycle events + * will then be very fast. + * + */ + @SuppressFBWarnings( + value = "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE", + justification = "We never need to synchronize with the preloader.") + void + preloadContainerLifecycleEvent(Class eventRawType, + Type... typeParameters) { + executor.submit(new PreloadingTask( + new ParameterizedTypeImpl(eventRawType, typeParameters, null))); + } - void shutdown() { - if (!executor.isShutdown()) { - executor.shutdownNow(); - } + void shutdown() { + if (!executor.isShutdown()) { + executor.shutdownNow(); } + } } diff --git a/impl/src/main/java/org/jboss/weld/bootstrap/events/configurator/BeanAttributesConfiguratorImpl.java b/impl/src/main/java/org/jboss/weld/bootstrap/events/configurator/BeanAttributesConfiguratorImpl.java index dafb1d07c3..2457c7eaa6 100644 --- a/impl/src/main/java/org/jboss/weld/bootstrap/events/configurator/BeanAttributesConfiguratorImpl.java +++ b/impl/src/main/java/org/jboss/weld/bootstrap/events/configurator/BeanAttributesConfiguratorImpl.java @@ -23,7 +23,6 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; - import javax.enterprise.context.Dependent; import javax.enterprise.inject.Any; import javax.enterprise.inject.Default; @@ -31,7 +30,6 @@ import javax.enterprise.inject.spi.configurator.BeanAttributesConfigurator; import javax.enterprise.util.TypeLiteral; import javax.inject.Named; - import org.jboss.weld.bean.attributes.ImmutableBeanAttributes; import org.jboss.weld.logging.BeanLogger; import org.jboss.weld.logging.BeanManagerLogger; @@ -50,234 +48,245 @@ * * @param */ -public class BeanAttributesConfiguratorImpl implements BeanAttributesConfigurator, Configurator> { - - private final BeanManagerImpl beanManager; - - private String name; - - final Set qualifiers; - - private Class scope; - - private final Set> stereotypes; - - final Set types; - - private boolean isAlternative; - - public BeanAttributesConfiguratorImpl(BeanManagerImpl beanManager) { - this.beanManager = beanManager; - this.qualifiers = new HashSet(); - this.types = new HashSet(); - this.types.add(Object.class); - this.stereotypes = new HashSet>(); - } - - /** - * - * @param beanAttributes - */ - public BeanAttributesConfiguratorImpl(BeanAttributes beanAttributes, BeanManagerImpl beanManager) { - this(beanManager); - read(beanAttributes); - } - - public BeanAttributesConfigurator read(BeanAttributes beanAttributes) { - checkArgumentNotNull(beanAttributes); - name(beanAttributes.getName()); - qualifiers(beanAttributes.getQualifiers()); - scope(beanAttributes.getScope()); - stereotypes(beanAttributes.getStereotypes()); - types(beanAttributes.getTypes()); - alternative(beanAttributes.isAlternative()); - return this; - } - - @Override - public BeanAttributesConfigurator addType(Type type) { - checkArgumentNotNull(type); - this.types.add(type); - return this; - } - - @Override - public BeanAttributesConfigurator addType(TypeLiteral typeLiteral) { - checkArgumentNotNull(typeLiteral); - this.types.add(typeLiteral.getType()); - return null; - } - - @Override - public BeanAttributesConfigurator addTypes(Type... types) { - checkArgumentNotNull(types); - Collections.addAll(this.types, types); - return this; - } - - @Override - public BeanAttributesConfigurator addTypes(Set types) { - checkArgumentNotNull(types); - this.types.addAll(types); - return this; - } - - @Override - public BeanAttributesConfigurator addTransitiveTypeClosure(Type type) { - checkArgumentNotNull(type); - this.types.addAll(Beans.getLegalBeanTypes(new HierarchyDiscovery(type).getTypeClosure(), type)); - return this; - } - - @Override - public BeanAttributesConfigurator types(Type... types) { - this.types.clear(); - return addTypes(types); - } - - @Override - public BeanAttributesConfigurator types(Set types) { - this.types.clear(); - return addTypes(types); - } - - @Override - public BeanAttributesConfigurator scope(Class scope) { - checkArgumentNotNull(scope); - this.scope = scope; - return this; - } - - @Override - public BeanAttributesConfigurator addQualifier(Annotation qualifier) { - checkArgumentNotNull(qualifier); - removeDefaultQualifierIfNeeded(qualifier); - qualifiers.add(qualifier); - return this; - } - - @Override - public BeanAttributesConfigurator addQualifiers(Annotation... qualifiers) { - checkArgumentNotNull(qualifiers); - for (Annotation annotation : qualifiers) { - removeDefaultQualifierIfNeeded(annotation); - } - Collections.addAll(this.qualifiers, qualifiers); - return this; +public class BeanAttributesConfiguratorImpl + implements BeanAttributesConfigurator, Configurator> { + + private final BeanManagerImpl beanManager; + + private String name; + + final Set qualifiers; + + private Class scope; + + private final Set> stereotypes; + + final Set types; + + private boolean isAlternative; + + public BeanAttributesConfiguratorImpl(BeanManagerImpl beanManager) { + this.beanManager = beanManager; + this.qualifiers = new HashSet(); + this.types = new HashSet(); + this.types.add(Object.class); + this.stereotypes = new HashSet>(); + } + + /** + * + * @param beanAttributes + */ + public BeanAttributesConfiguratorImpl(BeanAttributes beanAttributes, + BeanManagerImpl beanManager) { + this(beanManager); + read(beanAttributes); + } + + public BeanAttributesConfigurator read(BeanAttributes beanAttributes) { + checkArgumentNotNull(beanAttributes); + name(beanAttributes.getName()); + qualifiers(beanAttributes.getQualifiers()); + scope(beanAttributes.getScope()); + stereotypes(beanAttributes.getStereotypes()); + types(beanAttributes.getTypes()); + alternative(beanAttributes.isAlternative()); + return this; + } + + @Override + public BeanAttributesConfigurator addType(Type type) { + checkArgumentNotNull(type); + this.types.add(type); + return this; + } + + @Override + public BeanAttributesConfigurator addType(TypeLiteral typeLiteral) { + checkArgumentNotNull(typeLiteral); + this.types.add(typeLiteral.getType()); + return null; + } + + @Override + public BeanAttributesConfigurator addTypes(Type... types) { + checkArgumentNotNull(types); + Collections.addAll(this.types, types); + return this; + } + + @Override + public BeanAttributesConfigurator addTypes(Set types) { + checkArgumentNotNull(types); + this.types.addAll(types); + return this; + } + + @Override + public BeanAttributesConfigurator addTransitiveTypeClosure(Type type) { + checkArgumentNotNull(type); + this.types.addAll(Beans.getLegalBeanTypes( + new HierarchyDiscovery(type).getTypeClosure(), type)); + return this; + } + + @Override + public BeanAttributesConfigurator types(Type... types) { + this.types.clear(); + return addTypes(types); + } + + @Override + public BeanAttributesConfigurator types(Set types) { + this.types.clear(); + return addTypes(types); + } + + @Override + public BeanAttributesConfigurator + scope(Class scope) { + checkArgumentNotNull(scope); + this.scope = scope; + return this; + } + + @Override + public BeanAttributesConfigurator addQualifier(Annotation qualifier) { + checkArgumentNotNull(qualifier); + removeDefaultQualifierIfNeeded(qualifier); + qualifiers.add(qualifier); + return this; + } + + @Override + public BeanAttributesConfigurator addQualifiers(Annotation... qualifiers) { + checkArgumentNotNull(qualifiers); + for (Annotation annotation : qualifiers) { + removeDefaultQualifierIfNeeded(annotation); } - - @Override - public BeanAttributesConfigurator addQualifiers(Set qualifiers) { - checkArgumentNotNull(qualifiers); - for (Annotation annotation : qualifiers) { - removeDefaultQualifierIfNeeded(annotation); - } - this.qualifiers.addAll(qualifiers); - return this; + Collections.addAll(this.qualifiers, qualifiers); + return this; + } + + @Override + public BeanAttributesConfigurator + addQualifiers(Set qualifiers) { + checkArgumentNotNull(qualifiers); + for (Annotation annotation : qualifiers) { + removeDefaultQualifierIfNeeded(annotation); } - - @Override - public BeanAttributesConfigurator qualifiers(Annotation... qualifiers) { - this.qualifiers.clear(); - return addQualifiers(qualifiers); - } - - @Override - public BeanAttributesConfigurator qualifiers(Set qualifiers) { - this.qualifiers.clear(); - return addQualifiers(qualifiers); - } - - @Override - public BeanAttributesConfigurator addStereotype(Class stereotype) { - checkArgumentNotNull(stereotype); - this.stereotypes.add(stereotype); - return this; - } - - @Override - public BeanAttributesConfigurator addStereotypes(Set> stereotypes) { - checkArgumentNotNull(stereotypes); - this.stereotypes.addAll(stereotypes); - return this; + this.qualifiers.addAll(qualifiers); + return this; + } + + @Override + public BeanAttributesConfigurator qualifiers(Annotation... qualifiers) { + this.qualifiers.clear(); + return addQualifiers(qualifiers); + } + + @Override + public BeanAttributesConfigurator qualifiers(Set qualifiers) { + this.qualifiers.clear(); + return addQualifiers(qualifiers); + } + + @Override + public BeanAttributesConfigurator + addStereotype(Class stereotype) { + checkArgumentNotNull(stereotype); + this.stereotypes.add(stereotype); + return this; + } + + @Override + public BeanAttributesConfigurator + addStereotypes(Set> stereotypes) { + checkArgumentNotNull(stereotypes); + this.stereotypes.addAll(stereotypes); + return this; + } + + @Override + public BeanAttributesConfigurator + stereotypes(Set> stereotypes) { + this.stereotypes.clear(); + return addStereotypes(stereotypes); + } + + @Override + public BeanAttributesConfigurator name(String name) { + this.name = name; + return this; + } + + @Override + public BeanAttributesConfigurator alternative(boolean alternative) { + this.isAlternative = alternative; + return this; + } + + @Override + public BeanAttributes complete() { + return new ImmutableBeanAttributes( + ImmutableSet.copyOf(stereotypes), isAlternative, name, + initQualifiers(qualifiers), ImmutableSet.copyOf(types), initScope()); + } + + private void removeDefaultQualifierIfNeeded(Annotation qualifier) { + if (!qualifier.annotationType().equals(Named.class)) { + qualifiers.remove(Default.Literal.INSTANCE); } + } - @Override - public BeanAttributesConfigurator stereotypes(Set> stereotypes) { - this.stereotypes.clear(); - return addStereotypes(stereotypes); + private Class initScope() { + if (scope != null) { + return scope; } - - @Override - public BeanAttributesConfigurator name(String name) { - this.name = name; - return this; - } - - @Override - public BeanAttributesConfigurator alternative(boolean alternative) { - this.isAlternative = alternative; - return this; - } - - @Override - public BeanAttributes complete() { - return new ImmutableBeanAttributes(ImmutableSet.copyOf(stereotypes), isAlternative, name, initQualifiers(qualifiers), ImmutableSet.copyOf(types), - initScope()); - } - - private void removeDefaultQualifierIfNeeded(Annotation qualifier) { - if (!qualifier.annotationType().equals(Named.class)) { - qualifiers.remove(Default.Literal.INSTANCE); + if (!stereotypes.isEmpty()) { + MetaAnnotationStore metaAnnotationStore = + beanManager.getServices().get(MetaAnnotationStore.class); + Set possibleScopeTypes = new HashSet<>(); + for (Class stereotype : stereotypes) { + StereotypeModel model = + metaAnnotationStore.getStereotype(stereotype); + if (model.isValid()) { + possibleScopeTypes.add(model.getDefaultScopeType()); + } else { + throw BeanManagerLogger.LOG.notStereotype(stereotype); } + } + if (possibleScopeTypes.size() == 1) { + return possibleScopeTypes.iterator().next().annotationType(); + } else { + throw BeanLogger.LOG.multipleScopesFoundFromStereotypes( + BeanAttributesConfigurator.class.getSimpleName(), + Formats.formatTypes(stereotypes, false), possibleScopeTypes, ""); + } } + return Dependent.class; + } - private Class initScope() { - if (scope != null) { - return scope; - } - if (!stereotypes.isEmpty()) { - MetaAnnotationStore metaAnnotationStore = beanManager.getServices().get(MetaAnnotationStore.class); - Set possibleScopeTypes = new HashSet<>(); - for (Class stereotype : stereotypes) { - StereotypeModel model = metaAnnotationStore.getStereotype(stereotype); - if (model.isValid()) { - possibleScopeTypes.add(model.getDefaultScopeType()); - } else { - throw BeanManagerLogger.LOG.notStereotype(stereotype); - } - } - if (possibleScopeTypes.size() == 1) { - return possibleScopeTypes.iterator().next().annotationType(); - } else { - throw BeanLogger.LOG.multipleScopesFoundFromStereotypes(BeanAttributesConfigurator.class.getSimpleName(), - Formats.formatTypes(stereotypes, false), possibleScopeTypes, ""); - } - } - return Dependent.class; + private Set initQualifiers(Set qualifiers) { + if (qualifiers.isEmpty()) { + return Bindings.DEFAULT_QUALIFIERS; } - - private Set initQualifiers(Set qualifiers) { - if (qualifiers.isEmpty()) { - return Bindings.DEFAULT_QUALIFIERS; + Set normalized = new HashSet(qualifiers); + normalized.remove(Any.Literal.INSTANCE); + normalized.remove(Default.Literal.INSTANCE); + if (normalized.isEmpty()) { + normalized = Bindings.DEFAULT_QUALIFIERS; + } else { + ImmutableSet.Builder builder = ImmutableSet.builder(); + if (normalized.size() == 1) { + if (normalized.iterator().next().annotationType().equals(Named.class)) { + builder.add(Default.Literal.INSTANCE); } - Set normalized = new HashSet(qualifiers); - normalized.remove(Any.Literal.INSTANCE); - normalized.remove(Default.Literal.INSTANCE); - if (normalized.isEmpty()) { - normalized = Bindings.DEFAULT_QUALIFIERS; - } else { - ImmutableSet.Builder builder = ImmutableSet.builder(); - if (normalized.size() == 1) { - if (qualifiers.iterator().next().annotationType().equals(Named.class)) { - builder.add(Default.Literal.INSTANCE); - } - } - builder.add(Any.Literal.INSTANCE); - builder.addAll(qualifiers); - normalized = builder.build(); - } - return normalized; + } + builder.add(Any.Literal.INSTANCE); + builder.addAll(qualifiers); + normalized = builder.build(); } - + return normalized; + } } diff --git a/impl/src/main/java/org/jboss/weld/bootstrap/events/configurator/BeanConfiguratorImpl.java b/impl/src/main/java/org/jboss/weld/bootstrap/events/configurator/BeanConfiguratorImpl.java index 67888cb48a..5f5436de32 100644 --- a/impl/src/main/java/org/jboss/weld/bootstrap/events/configurator/BeanConfiguratorImpl.java +++ b/impl/src/main/java/org/jboss/weld/bootstrap/events/configurator/BeanConfiguratorImpl.java @@ -27,7 +27,6 @@ import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.Supplier; - import javax.enterprise.context.Dependent; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.Instance; @@ -38,12 +37,12 @@ import javax.enterprise.inject.spi.InjectionTarget; import javax.enterprise.inject.spi.PassivationCapable; import javax.enterprise.util.TypeLiteral; - import org.jboss.weld.bean.BeanIdentifiers; import org.jboss.weld.bean.StringBeanIdentifier; import org.jboss.weld.bean.WeldBean; import org.jboss.weld.bootstrap.BeanDeploymentFinder; import org.jboss.weld.bootstrap.event.WeldBeanConfigurator; +import org.jboss.weld.contexts.CreationalContextImpl; import org.jboss.weld.inject.WeldInstance; import org.jboss.weld.logging.BeanLogger; import org.jboss.weld.manager.BeanManagerImpl; @@ -59,499 +58,548 @@ * * @param */ -public class BeanConfiguratorImpl implements WeldBeanConfigurator, Configurator> { +public class BeanConfiguratorImpl + implements WeldBeanConfigurator, Configurator> { + + private final BeanManagerImpl beanManager; + + private Class beanClass; + + private final Set injectionPoints; + + private final BeanAttributesConfiguratorImpl attributes; + + private String id; + + private CreateCallback createCallback; + + private DestroyCallback destroyCallback; + + private Integer priority = null; + + /** + * + * @param defaultBeanClass + * @param beanDeploymentFinder + */ + public BeanConfiguratorImpl(Class defaultBeanClass, + BeanDeploymentFinder beanDeploymentFinder) { + this.beanClass = defaultBeanClass; + this.injectionPoints = new HashSet<>(); + this.beanManager = beanDeploymentFinder.getOrCreateBeanDeployment(beanClass) + .getBeanManager(); + this.attributes = new BeanAttributesConfiguratorImpl<>(beanManager); + } + + @Override + public WeldBeanConfigurator priority(int priority) { + this.priority = priority; + return this; + } + + @Override + public WeldBeanConfigurator beanClass(Class beanClass) { + checkArgumentNotNull(beanClass); + this.beanClass = beanClass; + return this; + } + + @Override + public WeldBeanConfigurator + addInjectionPoint(InjectionPoint injectionPoint) { + checkArgumentNotNull(injectionPoint); + this.injectionPoints.add(injectionPoint); + return this; + } + + @Override + public WeldBeanConfigurator + addInjectionPoints(InjectionPoint... injectionPoints) { + checkArgumentNotNull(injectionPoints); + Collections.addAll(this.injectionPoints, injectionPoints); + return this; + } + + @Override + public WeldBeanConfigurator + addInjectionPoints(Set injectionPoints) { + checkArgumentNotNull(injectionPoints); + this.injectionPoints.addAll(injectionPoints); + return this; + } + + @Override + public WeldBeanConfigurator + injectionPoints(InjectionPoint... injectionPoints) { + this.injectionPoints.clear(); + return addInjectionPoints(injectionPoints); + } + + @Override + public WeldBeanConfigurator + injectionPoints(Set injectionPoints) { + this.injectionPoints.clear(); + return addInjectionPoints(injectionPoints); + } + + @Override + public WeldBeanConfigurator id(String id) { + checkArgumentNotNull(id); + this.id = id; + return this; + } + + @Override + public WeldBeanConfigurator + createWith(Function, U> callback) { + checkArgumentNotNull(callback); + this.createCallback = cast(CreateCallback.fromCreateWith(callback)); + return cast(this); + } + + @Override + public WeldBeanConfigurator + produceWith(Function, U> callback) { + checkArgumentNotNull(callback); + this.createCallback = cast(CreateCallback.fromProduceWith(callback)); + return cast(this); + } + + @Override + public WeldBeanConfigurator + destroyWith(BiConsumer> callback) { + checkArgumentNotNull(callback); + this.destroyCallback = DestroyCallback.fromDestroy(callback); + return this; + } + + @Override + public WeldBeanConfigurator + disposeWith(BiConsumer> callback) { + checkArgumentNotNull(callback); + this.destroyCallback = DestroyCallback.fromDispose(callback); + return this; + } + + @Override + public WeldBeanConfigurator read(AnnotatedType type) { + checkArgumentNotNull(type); + final InjectionTarget injectionTarget = + cast(beanManager.getInjectionTargetFactory(type).createInjectionTarget( + null)); + addInjectionPoints(injectionTarget.getInjectionPoints()); + createWith(c -> { + T instance = injectionTarget.produce(c); + injectionTarget.inject(instance, c); + injectionTarget.postConstruct(instance); + return instance; + }); + destroyWith((i, c) -> { + injectionTarget.preDestroy(i); + c.release(); + }); + BeanAttributes beanAttributes = beanManager.createBeanAttributes(type); + read(beanAttributes); + return cast(this); + } + + @Override + public WeldBeanConfigurator read(BeanAttributes beanAttributes) { + checkArgumentNotNull(beanAttributes); + this.attributes.read(beanAttributes); + return this; + } + + @Override + public WeldBeanConfigurator addType(Type type) { + checkArgumentNotNull(type); + this.attributes.addType(type); + return this; + } + + @Override + public WeldBeanConfigurator addType(TypeLiteral typeLiteral) { + checkArgumentNotNull(typeLiteral); + this.attributes.addType(typeLiteral.getType()); + return this; + } + + @Override + public WeldBeanConfigurator addTypes(Type... types) { + checkArgumentNotNull(types); + this.attributes.addTypes(types); + return this; + } + + @Override + public WeldBeanConfigurator addTypes(Set types) { + checkArgumentNotNull(types); + this.attributes.addTypes(types); + return this; + } + + @Override + public WeldBeanConfigurator addTransitiveTypeClosure(Type type) { + checkArgumentNotNull(type); + this.attributes.addTransitiveTypeClosure(type); + return this; + } + + @Override + public WeldBeanConfigurator types(Type... types) { + checkArgumentNotNull(types); + this.attributes.types(types); + return this; + } + + @Override + public WeldBeanConfigurator types(Set types) { + checkArgumentNotNull(types); + this.attributes.types(types); + return this; + } + + @Override + public WeldBeanConfigurator scope(Class scope) { + checkArgumentNotNull(scope); + this.attributes.scope(scope); + return this; + } + + @Override + public WeldBeanConfigurator addQualifier(Annotation qualifier) { + checkArgumentNotNull(qualifier); + this.attributes.addQualifier(qualifier); + return this; + } + + @Override + public WeldBeanConfigurator addQualifiers(Annotation... qualifiers) { + checkArgumentNotNull(qualifiers); + this.attributes.addQualifiers(qualifiers); + return this; + } + + @Override + public WeldBeanConfigurator addQualifiers(Set qualifiers) { + checkArgumentNotNull(qualifiers); + this.attributes.addQualifiers(qualifiers); + return this; + } + + @Override + public WeldBeanConfigurator qualifiers(Annotation... qualifiers) { + checkArgumentNotNull(qualifiers); + this.attributes.qualifiers(qualifiers); + return this; + } + + @Override + public WeldBeanConfigurator qualifiers(Set qualifiers) { + checkArgumentNotNull(qualifiers); + this.attributes.qualifiers(qualifiers); + return this; + } + + @Override + public WeldBeanConfigurator + addStereotype(Class stereotype) { + checkArgumentNotNull(stereotype); + this.attributes.addStereotype(stereotype); + return this; + } + + @Override + public WeldBeanConfigurator + addStereotypes(Set> stereotypes) { + checkArgumentNotNull(stereotypes); + this.attributes.addStereotypes(stereotypes); + return this; + } + + @Override + public WeldBeanConfigurator + stereotypes(Set> stereotypes) { + checkArgumentNotNull(stereotypes); + this.attributes.stereotypes(stereotypes); + return this; + } + + @Override + public WeldBeanConfigurator name(String name) { + this.attributes.name(name); + return this; + } + + @Override + public WeldBeanConfigurator alternative(boolean alternative) { + this.attributes.alternative(alternative); + return this; + } - private final BeanManagerImpl beanManager; + public Bean complete() { + if (createCallback == null) { + // not callback specified, Weld does not know how to instantiate this new + // custom bean + throw BeanLogger.LOG.noCallbackSpecifiedForCustomBean( + "bean [" + beanClass.toString() + ", with types: " + + Formats.formatTypes(attributes.types) + ", and qualifiers: " + + Formats.formatAnnotations(attributes.qualifiers) + "]"); + } + return new ImmutableBean<>(this); + } - private Class beanClass; + public BeanManagerImpl getBeanManager() { return beanManager; } - private final Set injectionPoints; + static final class CreateCallback { - private final BeanAttributesConfiguratorImpl attributes; + private final Supplier simple; - private String id; + private final Function, T> create; - private CreateCallback createCallback; + private final Function, T> instance; - private DestroyCallback destroyCallback; + private CreationalContext creationalContext; - private Integer priority = null; - - /** - * - * @param defaultBeanClass - * @param beanDeploymentFinder - */ - public BeanConfiguratorImpl(Class defaultBeanClass, BeanDeploymentFinder beanDeploymentFinder) { - this.beanClass = defaultBeanClass; - this.injectionPoints = new HashSet<>(); - this.beanManager = beanDeploymentFinder.getOrCreateBeanDeployment(beanClass).getBeanManager(); - this.attributes = new BeanAttributesConfiguratorImpl<>(beanManager); + static CreateCallback + fromProduceWith(Function, T> callback) { + return new CreateCallback(null, null, callback); } - @Override - public WeldBeanConfigurator priority(int priority){ - this.priority = priority; - return this; + static CreateCallback fromProduceWith(Supplier callback) { + return new CreateCallback(callback, null, null); } - @Override - public WeldBeanConfigurator beanClass(Class beanClass) { - checkArgumentNotNull(beanClass); - this.beanClass = beanClass; - return this; + static CreateCallback + fromCreateWith(Function, T> callback) { + return new CreateCallback(null, callback, null); } - @Override - public WeldBeanConfigurator addInjectionPoint(InjectionPoint injectionPoint) { - checkArgumentNotNull(injectionPoint); - this.injectionPoints.add(injectionPoint); - return this; + CreateCallback(Supplier simple, Function, T> create, + Function, T> instance) { + this.simple = simple; + this.create = create; + this.instance = instance; } - @Override - public WeldBeanConfigurator addInjectionPoints(InjectionPoint... injectionPoints) { - checkArgumentNotNull(injectionPoints); - Collections.addAll(this.injectionPoints, injectionPoints); - return this; + private T create(Bean bean, CreationalContext ctx, + BeanManagerImpl beanManager) { + this.creationalContext = ctx; + if (simple != null) { + return simple.get(); + } else if (instance != null) { + return instance.apply(createInstance(bean, ctx, beanManager)); + } else { + return create.apply(ctx); + } } - @Override - public WeldBeanConfigurator addInjectionPoints(Set injectionPoints) { - checkArgumentNotNull(injectionPoints); - this.injectionPoints.addAll(injectionPoints); - return this; + private Instance createInstance(Bean bean, + CreationalContext ctx, + BeanManagerImpl beanManager) { + WeldInstance instance = beanManager.getInstance(ctx); + if (Dependent.class.equals(bean.getScope())) { + return instance; + } + return new GuardedInstance<>(bean, instance); } - @Override - public WeldBeanConfigurator injectionPoints(InjectionPoint... injectionPoints) { - this.injectionPoints.clear(); - return addInjectionPoints(injectionPoints); - } + CreationalContext getCreationalContext() { return creationalContext; } + } - @Override - public WeldBeanConfigurator injectionPoints(Set injectionPoints) { - this.injectionPoints.clear(); - return addInjectionPoints(injectionPoints); - } + static class GuardedInstance extends ForwardingWeldInstance { - @Override - public WeldBeanConfigurator id(String id) { - checkArgumentNotNull(id); - this.id = id; - return this; - } + private final Bean bean; - @Override - public WeldBeanConfigurator createWith(Function, U> callback) { - checkArgumentNotNull(callback); - this.createCallback = cast(CreateCallback.fromCreateWith(callback)); - return cast(this); - } + private final WeldInstance delegate; - @Override - public WeldBeanConfigurator produceWith(Function, U> callback) { - checkArgumentNotNull(callback); - this.createCallback = cast(CreateCallback.fromProduceWith(callback)); - return cast(this); + public GuardedInstance(Bean bean, WeldInstance delegate) { + this.bean = bean; + this.delegate = delegate; } @Override - public WeldBeanConfigurator destroyWith(BiConsumer> callback) { - checkArgumentNotNull(callback); - this.destroyCallback = DestroyCallback.fromDestroy(callback); - return this; + public WeldInstance delegate() { + return delegate; } @Override - public WeldBeanConfigurator disposeWith(BiConsumer> callback) { - checkArgumentNotNull(callback); - this.destroyCallback = DestroyCallback.fromDispose(callback); - return this; + public WeldInstance select(Class subtype, + Annotation... qualifiers) { + return wrap(subtype, delegate.select(subtype, qualifiers)); } @Override - public WeldBeanConfigurator read(AnnotatedType type) { - checkArgumentNotNull(type); - final InjectionTarget injectionTarget = cast(beanManager.getInjectionTargetFactory(type).createInjectionTarget(null)); - addInjectionPoints(injectionTarget.getInjectionPoints()); - createWith(c -> { - T instance = injectionTarget.produce(c); - injectionTarget.inject(instance, c); - injectionTarget.postConstruct(instance); - return instance; - }); - destroyWith((i, c) -> { - injectionTarget.preDestroy(i); - c.release(); - }); - BeanAttributes beanAttributes = beanManager.createBeanAttributes(type); - read(beanAttributes); - return cast(this); + public WeldInstance select(TypeLiteral subtype, + Annotation... qualifiers) { + return wrap(subtype.getType(), delegate.select(subtype, qualifiers)); } @Override - public WeldBeanConfigurator read(BeanAttributes beanAttributes) { - checkArgumentNotNull(beanAttributes); - this.attributes.read(beanAttributes); - return this; + public WeldInstance select(Annotation... qualifiers) { + return wrap(null, delegate.select(qualifiers)); } @Override - public WeldBeanConfigurator addType(Type type) { - checkArgumentNotNull(type); - this.attributes.addType(type); - return this; + public WeldInstance select(Type subtype, Annotation... qualifiers) { + return wrap(subtype, delegate.select(subtype, qualifiers)); } - @Override - public WeldBeanConfigurator addType(TypeLiteral typeLiteral) { - checkArgumentNotNull(typeLiteral); - this.attributes.addType(typeLiteral.getType()); - return this; + private WeldInstance wrap(Type subtype, + WeldInstance delegate) { + if (subtype != null && InjectionPoint.class.equals(subtype)) { + throw BeanLogger.LOG.cannotInjectInjectionPointMetadataIntoNonDependent( + bean); + } + return new GuardedInstance<>(bean, delegate); } + } - @Override - public WeldBeanConfigurator addTypes(Type... types) { - checkArgumentNotNull(types); - this.attributes.addTypes(types); - return this; - } + static final class DestroyCallback { - @Override - public WeldBeanConfigurator addTypes(Set types) { - checkArgumentNotNull(types); - this.attributes.addTypes(types); - return this; - } + private final BiConsumer> destroy; - @Override - public WeldBeanConfigurator addTransitiveTypeClosure(Type type) { - checkArgumentNotNull(type); - this.attributes.addTransitiveTypeClosure(type); - return this; - } + private final BiConsumer> dispose; - @Override - public WeldBeanConfigurator types(Type... types) { - checkArgumentNotNull(types); - this.attributes.types(types); - return this; + static DestroyCallback + fromDispose(BiConsumer> callback) { + return new DestroyCallback<>(callback, null); } - @Override - public WeldBeanConfigurator types(Set types) { - checkArgumentNotNull(types); - this.attributes.types(types); - return this; + static DestroyCallback + fromDestroy(BiConsumer> callback) { + return new DestroyCallback<>(null, callback); } - @Override - public WeldBeanConfigurator scope(Class scope) { - checkArgumentNotNull(scope); - this.attributes.scope(scope); - return this; + public DestroyCallback(BiConsumer> dispose, + BiConsumer> destroy) { + this.destroy = destroy; + this.dispose = dispose; } - @Override - public WeldBeanConfigurator addQualifier(Annotation qualifier) { - checkArgumentNotNull(qualifier); - this.attributes.addQualifier(qualifier); - return this; + void destroy(T instance, CreationalContext ctx, + BeanManagerImpl beanManager) { + if (dispose != null) { + dispose.accept(instance, beanManager.getInstance(ctx)); + } else { + destroy.accept(instance, ctx); + } } + } - @Override - public WeldBeanConfigurator addQualifiers(Annotation... qualifiers) { - checkArgumentNotNull(qualifiers); - this.attributes.addQualifiers(qualifiers); - return this; - } + /** + * + * @author Martin Kouba + * + * @param the class of the bean instance + */ + static class ImmutableBean extends ForwardingBeanAttributes + implements WeldBean, PassivationCapable { - @Override - public WeldBeanConfigurator addQualifiers(Set qualifiers) { - checkArgumentNotNull(qualifiers); - this.attributes.addQualifiers(qualifiers); - return this; - } + private final String id; - @Override - public WeldBeanConfigurator qualifiers(Annotation... qualifiers) { - checkArgumentNotNull(qualifiers); - this.attributes.qualifiers(qualifiers); - return this; - } + private final Integer priority; - @Override - public WeldBeanConfigurator qualifiers(Set qualifiers) { - checkArgumentNotNull(qualifiers); - this.attributes.qualifiers(qualifiers); - return this; - } + private final BeanManagerImpl beanManager; - @Override - public WeldBeanConfigurator addStereotype(Class stereotype) { - checkArgumentNotNull(stereotype); - this.attributes.addStereotype(stereotype); - return this; - } + private final Class beanClass; - @Override - public WeldBeanConfigurator addStereotypes(Set> stereotypes) { - checkArgumentNotNull(stereotypes); - this.attributes.addStereotypes(stereotypes); - return this; - } + private final BeanAttributes attributes; - @Override - public WeldBeanConfigurator stereotypes(Set> stereotypes) { - checkArgumentNotNull(stereotypes); - this.attributes.stereotypes(stereotypes); - return this; + private final Set injectionPoints; + + private final CreateCallback createCallback; + + private final DestroyCallback destroyCallback; + + /** + * + * @param configurator + */ + ImmutableBean(BeanConfiguratorImpl configurator) { + this.beanManager = configurator.getBeanManager(); + this.beanClass = configurator.beanClass; + this.attributes = configurator.attributes.complete(); + this.injectionPoints = ImmutableSet.copyOf(configurator.injectionPoints); + this.createCallback = configurator.createCallback; + this.destroyCallback = configurator.destroyCallback; + this.priority = configurator.priority; + if (configurator.id != null) { + this.id = configurator.id; + } else { + this.id = BeanIdentifiers.forBuilderBean(attributes, beanClass); + } + } + + @Override + public T create(CreationalContext creationalContext) { + return createCallback.create(this, creationalContext, beanManager); + } + + @Override + public void destroy(T instance, CreationalContext creationalContext) { + if (destroyCallback != null) { + destroyCallback.destroy(instance, creationalContext, beanManager); + } + // release dependent beans from create/destroy callbacks + if (creationalContext instanceof CreationalContextImpl) { + // release dependent instances linked with this bean but avoid double + // invocation + ((CreationalContextImpl)creationalContext).release(this, instance); + // in some cases, the CC for create and destroy callbacks might differ; + // hence this special handling + CreationalContext createCallbackCreationalContext = + createCallback.getCreationalContext(); + if (createCallbackCreationalContext != null && + createCallbackCreationalContext != creationalContext) { + createCallbackCreationalContext.release(); + } + } else { + creationalContext.release(); + } } @Override - public WeldBeanConfigurator name(String name) { - this.attributes.name(name); - return this; + public Class getBeanClass() { + return beanClass; } @Override - public WeldBeanConfigurator alternative(boolean alternative) { - this.attributes.alternative(alternative); - return this; + public BeanIdentifier getIdentifier() { + // this will likely never get called, so it's ok to create new object here + return new StringBeanIdentifier(id); } - public Bean complete() { - if (createCallback == null) { - // not callback specified, Weld does not know how to instantiate this new custom bean - throw BeanLogger.LOG.noCallbackSpecifiedForCustomBean("bean [" + beanClass.toString() - + ", with types: " + Formats.formatTypes(attributes.types) - + ", and qualifiers: " + Formats.formatAnnotations(attributes.qualifiers) + "]"); - } - return new ImmutableBean<>(this); + @Override + public Set getInjectionPoints() { + return injectionPoints; } - public BeanManagerImpl getBeanManager() { - return beanManager; + @Override + public boolean isNullable() { + return false; } - static final class CreateCallback { - - private final Supplier simple; - - private final Function, T> create; - - private final Function, T> instance; - - static CreateCallback fromProduceWith(Function, T> callback) { - return new CreateCallback(null, null, callback); - } - - static CreateCallback fromProduceWith(Supplier callback) { - return new CreateCallback(callback, null, null); - } - - static CreateCallback fromCreateWith(Function, T> callback) { - return new CreateCallback(null, callback, null); - } - - CreateCallback(Supplier simple, Function, T> create, Function, T> instance) { - this.simple = simple; - this.create = create; - this.instance = instance; - } - - private T create(Bean bean, CreationalContext ctx, BeanManagerImpl beanManager) { - if (simple != null) { - return simple.get(); - } else if (instance != null) { - return instance.apply(createInstance(bean, ctx, beanManager)); - } else { - return create.apply(ctx); - } - } - - private Instance createInstance(Bean bean, CreationalContext ctx, BeanManagerImpl beanManager) { - WeldInstance instance = beanManager.getInstance(ctx); - if (Dependent.class.equals(bean.getScope())) { - return instance; - } - return new GuardedInstance<>(bean, instance); - } - + @Override + protected BeanAttributes attributes() { + return attributes; } - static class GuardedInstance extends ForwardingWeldInstance { - - private final Bean bean; - - private final WeldInstance delegate; - - public GuardedInstance(Bean bean, WeldInstance delegate) { - this.bean = bean; - this.delegate = delegate; - } - - @Override - public WeldInstance delegate() { - return delegate; - } - - @Override - public WeldInstance select(Class subtype, Annotation... qualifiers) { - return wrap(subtype, delegate.select(subtype, qualifiers)); - } - - @Override - public WeldInstance select(TypeLiteral subtype, Annotation... qualifiers) { - return wrap(subtype.getType(), delegate.select(subtype, qualifiers)); - } - - @Override - public WeldInstance select(Annotation... qualifiers) { - return wrap(null, delegate.select(qualifiers)); - } - - @Override - public WeldInstance select(Type subtype, Annotation... qualifiers) { - return wrap(subtype, delegate.select(subtype, qualifiers)); - } - - private WeldInstance wrap(Type subtype, WeldInstance delegate) { - if (subtype != null && InjectionPoint.class.equals(subtype)) { - throw BeanLogger.LOG.cannotInjectInjectionPointMetadataIntoNonDependent(bean); - } - return new GuardedInstance<>(bean, delegate); - } - + @Override + public String getId() { + return id; } - static final class DestroyCallback { - - private final BiConsumer> destroy; - - private final BiConsumer> dispose; - - static DestroyCallback fromDispose(BiConsumer> callback) { - return new DestroyCallback<>(callback, null); - } - - static DestroyCallback fromDestroy(BiConsumer> callback) { - return new DestroyCallback<>(null, callback); - } - - public DestroyCallback(BiConsumer> dispose, BiConsumer> destroy) { - this.destroy = destroy; - this.dispose = dispose; - } - - void destroy(T instance, CreationalContext ctx, BeanManagerImpl beanManager) { - if (dispose != null) { - dispose.accept(instance, beanManager.getInstance(ctx)); - } else { - destroy.accept(instance, ctx); - } - } - + @Override + public Integer getPriority() { + return priority; } - /** - * - * @author Martin Kouba - * - * @param the class of the bean instance - */ - static class ImmutableBean extends ForwardingBeanAttributes implements WeldBean, PassivationCapable { - - private final String id; - - private final Integer priority; - - private final BeanManagerImpl beanManager; - - private final Class beanClass; - - private final BeanAttributes attributes; - - private final Set injectionPoints; - - private final CreateCallback createCallback; - - private final DestroyCallback destroyCallback; - - /** - * - * @param configurator - */ - ImmutableBean(BeanConfiguratorImpl configurator) { - this.beanManager = configurator.getBeanManager(); - this.beanClass = configurator.beanClass; - this.attributes = configurator.attributes.complete(); - this.injectionPoints = ImmutableSet.copyOf(configurator.injectionPoints); - this.createCallback = configurator.createCallback; - this.destroyCallback = configurator.destroyCallback; - this.priority = configurator.priority; - if (configurator.id != null) { - this.id = configurator.id; - } else { - this.id = BeanIdentifiers.forBuilderBean(attributes, beanClass); - } - } - - @Override - public T create(CreationalContext creationalContext) { - return createCallback.create(this, creationalContext, beanManager); - } - - @Override - public void destroy(T instance, CreationalContext creationalContext) { - if (destroyCallback != null) { - destroyCallback.destroy(instance, creationalContext, beanManager); - } - } - - @Override - public Class getBeanClass() { - return beanClass; - } - - @Override - public BeanIdentifier getIdentifier() { - // this will likely never get called, so it's ok to create new object here - return new StringBeanIdentifier(id); - } - - @Override - public Set getInjectionPoints() { - return injectionPoints; - } - - @Override - public boolean isNullable() { - return false; - } - - @Override - protected BeanAttributes attributes() { - return attributes; - } - - @Override - public String getId() { - return id; - } - - @Override - public Integer getPriority() { - return priority; - } - - @Override - public String toString() { - return "Configurator Bean [" + getBeanClass().toString() + ", types: " + Formats.formatTypes(getTypes()) + ", qualifiers: " - + Formats.formatAnnotations(getQualifiers()) + "]"; - } - + @Override + public String toString() { + return "Configurator Bean [" + getBeanClass().toString() + + ", types: " + Formats.formatTypes(getTypes()) + + ", qualifiers: " + Formats.formatAnnotations(getQualifiers()) + "]"; } - + } } diff --git a/impl/src/main/java/org/jboss/weld/contexts/AbstractConversationContext.java b/impl/src/main/java/org/jboss/weld/contexts/AbstractConversationContext.java index 09536d4692..4d244cd946 100644 --- a/impl/src/main/java/org/jboss/weld/contexts/AbstractConversationContext.java +++ b/impl/src/main/java/org/jboss/weld/contexts/AbstractConversationContext.java @@ -31,11 +31,9 @@ import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; - import javax.enterprise.context.BeforeDestroyed; import javax.enterprise.context.ConversationScoped; import javax.enterprise.context.Destroyed; - import org.jboss.weld.Container; import org.jboss.weld.bootstrap.api.ServiceRegistry; import org.jboss.weld.config.ConfigurationKey; @@ -63,545 +61,641 @@ * @author George Sapountzis * @author Marko Luksa */ -public abstract class AbstractConversationContext extends AbstractBoundContext implements ConversationContext { - - public static final String CONVERSATIONS_ATTRIBUTE_NAME = ConversationContext.class.getName() + ".conversations"; - public static final String DESTRUCTION_QUEUE_ATTRIBUTE_NAME = ConversationContext.class.getName() + ".destructionQueue"; - private static final String CURRENT_CONVERSATION_ATTRIBUTE_NAME = ConversationContext.class.getName() + ".currentConversation"; - - private static final String PARAMETER_NAME = "cid"; - - private final AtomicReference parameterName; - private final AtomicLong defaultTimeout; - private final AtomicLong concurrentAccessTimeout; - - private final ThreadLocal associated; - - private final BeanManagerImpl manager; - - private final BeanIdentifierIndex beanIdentifierIndex; - private final LazyValueHolder> conversationBeforeDestroyedEvent = new LazyValueHolder>() { - @Override - protected FastEvent computeValue() { - return FastEvent.of(String.class, manager, BeforeDestroyed.Literal.CONVERSATION); - } - }; - private final LazyValueHolder> conversationDestroyedEvent = new LazyValueHolder>() { - @Override - protected FastEvent computeValue() { - return FastEvent.of(String.class, manager, Destroyed.Literal.CONVERSATION); - } - }; - - public AbstractConversationContext(String contextId, ServiceRegistry services) { - super(contextId, true); - this.parameterName = new AtomicReference(PARAMETER_NAME); - WeldConfiguration configuration = services.get(WeldConfiguration.class); - this.defaultTimeout = new AtomicLong(configuration.getLongProperty(ConfigurationKey.CONVERSATION_TIMEOUT)); - this.concurrentAccessTimeout = new AtomicLong(configuration.getLongProperty(ConfigurationKey.CONVERSATION_CONCURRENT_ACCESS_TIMEOUT)); - this.associated = new ThreadLocal(); - this.manager = Container.instance(contextId).deploymentManager(); - this.beanIdentifierIndex = services.get(BeanIdentifierIndex.class); - } - - @Override - public String getParameterName() { - return parameterName.get(); - } +public abstract class AbstractConversationContext + extends AbstractBoundContext implements ConversationContext { - @Override - public void setParameterName(String cid) { - this.parameterName.set(cid); - } + public static final String CONVERSATIONS_ATTRIBUTE_NAME = + ConversationContext.class.getName() + ".conversations"; + public static final String DESTRUCTION_QUEUE_ATTRIBUTE_NAME = + ConversationContext.class.getName() + ".destructionQueue"; + private static final String CURRENT_CONVERSATION_ATTRIBUTE_NAME = + ConversationContext.class.getName() + ".currentConversation"; - @Override - public void setConcurrentAccessTimeout(long timeout) { - this.concurrentAccessTimeout.set(timeout); - } + private static final String PARAMETER_NAME = "cid"; - @Override - public long getConcurrentAccessTimeout() { - return concurrentAccessTimeout.get(); - } + private final AtomicReference parameterName; + private final AtomicLong defaultTimeout; + private final AtomicLong concurrentAccessTimeout; - @Override - public void setDefaultTimeout(long timeout) { - this.defaultTimeout.set(timeout); - } + private final boolean resetHttpSessionAttributeOnBeanAccess; - @Override - public long getDefaultTimeout() { - return defaultTimeout.get(); - } + private final ThreadLocal associated; - @Override - public boolean associate(R request) { - this.associated.set(request); - /* - * We need to delay attaching the bean store until activate() is called so that we can attach the correct conversation id. We may need access to the - * conversation id generator and conversation map are initialized lazily. - */ - return true; - } + private final BeanManagerImpl manager; - @Override - public boolean dissociate(R request) { - if (isAssociated()) { - try { - copyConversationIdGeneratorAndConversationsToSession(); - return true; - } finally { - this.associated.set(null); - cleanup(); + private final BeanIdentifierIndex beanIdentifierIndex; + private final LazyValueHolder> + conversationBeforeDestroyedEvent = + new LazyValueHolder>() { + @Override + protected FastEvent computeValue() { + return FastEvent.of(String.class, manager, + BeforeDestroyed.Literal.CONVERSATION); } - } else { - return false; - } - } - - protected void copyConversationIdGeneratorAndConversationsToSession() { - final R request = getRequest(); - if (request == null) { - return; - } - // If necessary, store the conversation id generator and conversation map in the session - Object conversationIdGenerator = getRequestAttribute(request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME); - if (conversationIdGenerator != null && getSessionAttribute(request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME, false) == null) { - setSessionAttribute(request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME, conversationIdGenerator, false); - } - Object conversationMap = getRequestAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME); - if (conversationMap != null && getSessionAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME, false) == null) { - setSessionAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME, conversationMap, false); + }; + private final LazyValueHolder> conversationDestroyedEvent = + new LazyValueHolder>() { + @Override + protected FastEvent computeValue() { + return FastEvent.of(String.class, manager, + Destroyed.Literal.CONVERSATION); } - } + }; + + public AbstractConversationContext(String contextId, + ServiceRegistry services) { + super(contextId, true); + this.parameterName = new AtomicReference(PARAMETER_NAME); + WeldConfiguration configuration = services.get(WeldConfiguration.class); + this.defaultTimeout = new AtomicLong( + configuration.getLongProperty(ConfigurationKey.CONVERSATION_TIMEOUT)); + this.concurrentAccessTimeout = new AtomicLong(configuration.getLongProperty( + ConfigurationKey.CONVERSATION_CONCURRENT_ACCESS_TIMEOUT)); + this.associated = new ThreadLocal(); + this.manager = Container.instance(contextId).deploymentManager(); + this.beanIdentifierIndex = services.get(BeanIdentifierIndex.class); + this.resetHttpSessionAttributeOnBeanAccess = + configuration.getBooleanProperty( + ConfigurationKey.RESET_HTTP_SESSION_ATTR_ON_BEAN_ACCESS); + } + + @Override + public String getParameterName() { + return parameterName.get(); + } + + @Override + public void setParameterName(String cid) { + this.parameterName.set(cid); + } + + @Override + public void setConcurrentAccessTimeout(long timeout) { + this.concurrentAccessTimeout.set(timeout); + } + + @Override + public long getConcurrentAccessTimeout() { + return concurrentAccessTimeout.get(); + } + + @Override + public void setDefaultTimeout(long timeout) { + this.defaultTimeout.set(timeout); + } + + @Override + public long getDefaultTimeout() { + return defaultTimeout.get(); + } + + @Override + public boolean associate(R request) { + this.associated.set(request); + /* + * We need to delay attaching the bean store until activate() is called so + * that we can attach the correct conversation id. We may need access to the + * conversation id generator and conversation map are initialized lazily. + */ + return true; + } - public void sessionCreated() { + @Override + public boolean dissociate(R request) { + if (isAssociated()) { + try { copyConversationIdGeneratorAndConversationsToSession(); - } - - protected void associateRequestWithNewConversation() { - ManagedConversation conversation = new ConversationImpl(manager); - lock(conversation); - setRequestAttribute(getRequest(), CURRENT_CONVERSATION_ATTRIBUTE_NAME, conversation); - - // Set a temporary bean store, this will be attached at the end of the request if needed - NamingScheme namingScheme = new ConversationNamingScheme(getNamingSchemePrefix(), "transient", beanIdentifierIndex); - setBeanStore(createRequestBeanStore(namingScheme, getRequest())); - setRequestAttribute(getRequest(), ConversationNamingScheme.PARAMETER_NAME, namingScheme); - } - - protected void associateRequest(ManagedConversation conversation) { - setRequestAttribute(getRequest(), CURRENT_CONVERSATION_ATTRIBUTE_NAME, conversation); - - NamingScheme namingScheme = new ConversationNamingScheme(getNamingSchemePrefix(), conversation.getId(), beanIdentifierIndex); - setBeanStore(createRequestBeanStore(namingScheme, getRequest())); - getBeanStore().attach(); - } - - @Override - public void activate() { - this.activate(null); - } - - @Override - public void activate(String cid) { - if (!isAssociated()) { - throw ConversationLogger.LOG.mustCallAssociateBeforeActivate(); - } - if (!isActive()) { - super.setActive(true); - } else { - ConversationLogger.LOG.contextAlreadyActive(getRequest()); - } - initialize(cid); - } - - protected void initialize(String cid) { - // Attach the conversation - // WELD-1315 Don't try to restore the long-running conversation if cid param is empty - if (cid != null && !cid.isEmpty()) { - ManagedConversation conversation = getConversation(cid); - if (conversation != null && !isExpired(conversation)) { - boolean lock = lock(conversation); - if (lock) { - // WELD-1690 Don't associate a conversation which was ended (race condition) - if (conversation.isTransient()) { - associateRequestWithNewConversation(); - throw ConversationLogger.LOG.noConversationFoundToRestore(cid); - } - associateRequest(conversation); - } else { - // CDI 6.7.4 we must activate a new transient conversation before we throw the exception - associateRequestWithNewConversation(); - throw ConversationLogger.LOG.conversationLockTimedout(cid); - } - } else { - // CDI 6.7.4 we must activate a new transient conversation before we throw the exception - associateRequestWithNewConversation(); - throw ConversationLogger.LOG.noConversationFoundToRestore(cid); - } - } else { + return true; + } finally { + this.associated.set(null); + cleanup(); + } + } else { + return false; + } + } + + protected void copyConversationIdGeneratorAndConversationsToSession() { + final R request = getRequest(); + if (request == null) { + return; + } + // If necessary, store the conversation id generator and conversation map in + // the session + Object conversationIdGenerator = + getRequestAttribute(request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME); + if (conversationIdGenerator != null && + getSessionAttribute(request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME, + false) == null) { + setSessionAttribute(request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME, + conversationIdGenerator, false); + } + Object conversationMap = + getRequestAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME); + if (conversationMap != null && + (resetHttpSessionAttributeOnBeanAccess || + getSessionAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME, false) == + null)) { + setSessionAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME, + conversationMap, false); + } + } + + public void sessionCreated() { + copyConversationIdGeneratorAndConversationsToSession(); + } + + protected void associateRequestWithNewConversation() { + ManagedConversation conversation = new ConversationImpl(manager); + lock(conversation); + setRequestAttribute(getRequest(), CURRENT_CONVERSATION_ATTRIBUTE_NAME, + conversation); + + // Set a temporary bean store, this will be attached at the end of the + // request if needed + NamingScheme namingScheme = new ConversationNamingScheme( + getNamingSchemePrefix(), "transient", beanIdentifierIndex); + setBeanStore(createRequestBeanStore(namingScheme, getRequest())); + setRequestAttribute(getRequest(), ConversationNamingScheme.PARAMETER_NAME, + namingScheme); + } + + protected void associateRequest(ManagedConversation conversation) { + setRequestAttribute(getRequest(), CURRENT_CONVERSATION_ATTRIBUTE_NAME, + conversation); + + NamingScheme namingScheme = new ConversationNamingScheme( + getNamingSchemePrefix(), conversation.getId(), beanIdentifierIndex); + setBeanStore(createRequestBeanStore(namingScheme, getRequest())); + getBeanStore().attach(); + } + + @Override + public void activate() { + this.activate(null); + } + + @Override + public void activate(String cid) { + if (!isAssociated()) { + throw ConversationLogger.LOG.mustCallAssociateBeforeActivate(); + } + if (!isActive()) { + super.setActive(true); + } else { + ConversationLogger.LOG.contextAlreadyActive(getRequest()); + } + initialize(cid); + } + + protected void initialize(String cid) { + // Attach the conversation + // WELD-1315 Don't try to restore the long-running conversation if cid param + // is empty + if (cid != null && !cid.isEmpty()) { + ManagedConversation conversation = getConversation(cid); + if (conversation != null && !isExpired(conversation)) { + boolean lock = lock(conversation); + if (lock) { + // WELD-1690 Don't associate a conversation which was ended (race + // condition) + if (conversation.isTransient()) { associateRequestWithNewConversation(); - } - } - - private boolean lock(ManagedConversation conversation) { - return conversation.lock(getConcurrentAccessTimeout()); - } - - @Override - public void deactivate() { - // Disassociate from the current conversation - if (isActive()) { - if (!isAssociated()) { - throw ConversationLogger.LOG.mustCallAssociateBeforeDeactivate(); - } - - try { - if (getCurrentConversation().isTransient() && getRequestAttribute(getRequest(), ConversationNamingScheme.PARAMETER_NAME) != null) { - // WELD-1746 Don't destroy ended conversations - these must be destroyed in a synchronized block - see also cleanUpConversationMap() - destroy(); - } else { - // Update the conversation timestamp - getCurrentConversation().touch(); - if (!getBeanStore().isAttached()) { - /* - * This was a transient conversation at the beginning of the request, so we need to update the CID it uses, and attach it. We also add - * it to the conversations the session knows about. - */ - if (!(getRequestAttribute(getRequest(), ConversationNamingScheme.PARAMETER_NAME) instanceof ConversationNamingScheme)) { - throw ConversationLogger.LOG.conversationNamingSchemeNotFound(); - } - ((ConversationNamingScheme) getRequestAttribute(getRequest(), ConversationNamingScheme.PARAMETER_NAME)).setCid(getCurrentConversation() - .getId()); - - getBeanStore().attach(); - getConversationMap().put(getCurrentConversation().getId(), getCurrentConversation()); - } - } - } finally { - // WELD-1690 always try to unlock the current conversation - getCurrentConversation().unlock(); - // WELD-1802 - setBeanStore(null); - // Clean up any expired/ended conversations - cleanUpConversationMap(); - // Deactivate the context, i.e. remove state threadlocal - removeState(); - } + throw ConversationLogger.LOG.noConversationFoundToRestore(cid); + } + associateRequest(conversation); } else { - throw ConversationLogger.LOG.contextNotActive(); - } - } - - private void cleanUpConversationMap() { - ManagedConversation currentConversation = getCurrentConversation(); - Map conversations = getConversationMap(); - Map toClear = new HashMap<>(); - S session = getSessionFromRequest(getRequest(), false); - // while synced, extract a map of conversations that we'll need to clean up, already removing them from map - synchronized (conversations) { - Iterator> entryIterator = conversations.entrySet().iterator(); - while (entryIterator.hasNext()) { - Entry entry = entryIterator.next(); - if (entry.getValue().isTransient()) { - toClear.put(entry.getKey(), entry.getValue()); - entryIterator.remove(); - } - } - } - // let the lock go, now destroy the conversation contexts, this will trigger locking on session - Iterator> toClearIterator = toClear.entrySet().iterator(); - while (toClearIterator.hasNext()) { - Entry entry = toClearIterator.next(); - if (entry.getValue().isTransient()) { - destroyConversation(session, entry.getKey(), !currentConversation.equals(entry.getValue())); - toClearIterator.remove(); - } + // CDI 6.7.4 we must activate a new transient conversation before we + // throw the exception + associateRequestWithNewConversation(); + throw ConversationLogger.LOG.conversationLockTimedout(cid); } - } - - public void conversationPromotedToLongRunning(ConversationImpl conversation) { - getConversationMap().put(conversation.getId(), conversation); - } - - @Override - public void invalidate() { - ManagedConversation currentConversation = getCurrentConversation(); - Map conversations = getConversationMap(); - synchronized (conversations) { - for (Entry stringManagedConversationEntry : conversations.entrySet()) { - ManagedConversation conversation = stringManagedConversationEntry.getValue(); - if (!currentConversation.equals(conversation) && !conversation.isTransient() && isExpired(conversation)) { - // Try to lock the conversation and log warning if not successful - unlocking should not be necessary - if (!conversation.lock(0)) { - ConversationLogger.LOG.endLockedConversation(conversation.getId()); - } - conversation.end(); - } - } - } - } - - public boolean destroy(S session) { - // the context may be active - // if it is, we need to re-attach the bean store once the other conversations are destroyed - final BoundBeanStore beanStore = getBeanStore(); - final boolean active = isActive(); - if (beanStore != null) { - beanStore.detach(); - } - try { - Object conversationMap = getSessionAttributeFromSession(session, CONVERSATIONS_ATTRIBUTE_NAME); - if (conversationMap instanceof Map) { - Map conversations = cast(conversationMap); - synchronized (conversations) { - if (!conversations.isEmpty()) { - // There are some conversations to destroy - setActive(true); - if (beanStore == null) { - // There is no request associated - destroy conversation contexts immediately - for (Entry entry : conversations.entrySet()) { - destroyConversation(session, entry.getKey(), true); - } - } else { - // All conversation contexts created during the current session should be destroyed after the servlet service() completes - // However, at that time the session will not be available - store all remaining contextual instances in the request - setDestructionQueue(conversations, session); - } - } - } - } - return true; - } finally { - setBeanStore(beanStore); - setActive(active); - if (beanStore != null) { - beanStore.attach(); - } else if (!active) { - removeState(); - cleanup(); - } - } - } - - private void setDestructionQueue(Map conversations, S session) { - Map>> contexts = new HashMap<>(); - for (Entry entry : conversations.entrySet()) { - ManagedConversation conversation = entry.getValue(); - // First make all conversations transient - if (!conversation.isTransient()) { - conversation.end(); - } - // Extract contextual instances - List> contextualInstances = new ArrayList<>(); - for (String id : new ConversationNamingScheme(getNamingSchemePrefix(), entry.getKey(), beanIdentifierIndex) - .filterIds(getSessionAttributeNames(session))) { - contextualInstances.add((ContextualInstance) getSessionAttributeFromSession(session, id)); + } else { + // CDI 6.7.4 we must activate a new transient conversation before we + // throw the exception + associateRequestWithNewConversation(); + throw ConversationLogger.LOG.noConversationFoundToRestore(cid); + } + } else { + associateRequestWithNewConversation(); + } + } + + private boolean lock(ManagedConversation conversation) { + return conversation.lock(getConcurrentAccessTimeout()); + } + + @Override + public void deactivate() { + // Disassociate from the current conversation + if (isActive()) { + if (!isAssociated()) { + throw ConversationLogger.LOG.mustCallAssociateBeforeDeactivate(); + } + + try { + if (getCurrentConversation().isTransient() && + getRequestAttribute(getRequest(), + ConversationNamingScheme.PARAMETER_NAME) != + null) { + // WELD-1746 Don't destroy ended conversations - these must be + // destroyed in a synchronized block - see also + // cleanUpConversationMap() + destroy(); + } else { + // Update the conversation timestamp + getCurrentConversation().touch(); + if (!getBeanStore().isAttached()) { + /* + * This was a transient conversation at the beginning of the + * request, so we need to update the CID it uses, and attach it. We + * also add it to the conversations the session knows about. + */ + if (!(getRequestAttribute(getRequest(), + ConversationNamingScheme.PARAMETER_NAME) + instanceof ConversationNamingScheme)) { + throw ConversationLogger.LOG.conversationNamingSchemeNotFound(); } - contexts.put(entry.getKey(), contextualInstances); - } - // Store remaining conversation contexts for later destruction - setRequestAttribute(getRequest(), DESTRUCTION_QUEUE_ATTRIBUTE_NAME, Collections.synchronizedMap(contexts)); - } + ((ConversationNamingScheme)getRequestAttribute( + getRequest(), ConversationNamingScheme.PARAMETER_NAME)) + .setCid(getCurrentConversation().getId()); - protected void destroyConversation(S session, String id, boolean fireEvents) { - if (session != null) { - if (fireEvents) { - conversationBeforeDestroyedEvent.get().fire(id); - } - setBeanStore(createSessionBeanStore(new ConversationNamingScheme(getNamingSchemePrefix(), id, beanIdentifierIndex), session)); getBeanStore().attach(); - destroy(); - getBeanStore().detach(); - setBeanStore(null); - if (fireEvents) { - conversationDestroyedEvent.get().fire(id); - } + getConversationMap().put(getCurrentConversation().getId(), + getCurrentConversation()); + } } - } - - @Override - public String generateConversationId() { - ConversationIdGenerator generator = getConversationIdGenerator(); - checkContextInitialized(); - return generator.call(); - } - - // method is synchronized so that creation of conversation generator isn't a subject to race condition - protected synchronized ConversationIdGenerator getConversationIdGenerator() { - final R request = associated.get(); - if (request == null) { - throw ConversationLogger.LOG.mustCallAssociateBeforeGeneratingId(); + } finally { + // WELD-1690 always try to unlock the current conversation + getCurrentConversation().unlock(); + // WELD-1802 + setBeanStore(null); + // Clean up any expired/ended conversations + cleanUpConversationMap(); + // Deactivate the context, i.e. remove state threadlocal + removeState(); + } + } else { + throw ConversationLogger.LOG.contextNotActive(); + } + } + + private void cleanUpConversationMap() { + ManagedConversation currentConversation = getCurrentConversation(); + Map conversations = getConversationMap(); + Map toClear = new HashMap<>(); + S session = getSessionFromRequest(getRequest(), false); + // while synced, extract a map of conversations that we'll need to clean up, + // already removing them from map + synchronized (conversations) { + Iterator> entryIterator = + conversations.entrySet().iterator(); + while (entryIterator.hasNext()) { + Entry entry = entryIterator.next(); + if (entry.getValue().isTransient()) { + toClear.put(entry.getKey(), entry.getValue()); + entryIterator.remove(); } - Object conversationIdGenerator = getRequestAttribute(request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME); - if (conversationIdGenerator == null) { - conversationIdGenerator = getSessionAttribute(request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME, false); - if (conversationIdGenerator == null) { - conversationIdGenerator = new ConversationIdGenerator(); - setRequestAttribute(request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME, conversationIdGenerator); - setSessionAttribute(request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME, conversationIdGenerator, false); - } else { - setRequestAttribute(request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME, conversationIdGenerator); - } - } - if (!(conversationIdGenerator instanceof ConversationIdGenerator)) { - throw ConversationLogger.LOG.conversationIdGeneratorNotFound(); + } + } + // let the lock go, now destroy the conversation contexts, this will trigger + // locking on session + Iterator> toClearIterator = + toClear.entrySet().iterator(); + while (toClearIterator.hasNext()) { + Entry entry = toClearIterator.next(); + if (entry.getValue().isTransient()) { + destroyConversation(session, entry.getKey(), + !currentConversation.equals(entry.getValue())); + toClearIterator.remove(); + } + } + } + + public void conversationPromotedToLongRunning(ConversationImpl conversation) { + getConversationMap().put(conversation.getId(), conversation); + } + + @Override + public void invalidate() { + ManagedConversation currentConversation = getCurrentConversation(); + Map conversations = getConversationMap(); + synchronized (conversations) { + for (Entry stringManagedConversationEntry : + conversations.entrySet()) { + ManagedConversation conversation = + stringManagedConversationEntry.getValue(); + if (!currentConversation.equals(conversation) && + !conversation.isTransient() && isExpired(conversation)) { + // Try to lock the conversation and log warning if not successful - + // unlocking should not be necessary + if (!conversation.lock(0)) { + ConversationLogger.LOG.endLockedConversation(conversation.getId()); + } + conversation.end(); } - return (ConversationIdGenerator) conversationIdGenerator; - } - - private static boolean isExpired(ManagedConversation conversation) { - return System.currentTimeMillis() > (conversation.getLastUsed() + conversation.getTimeout()); - } - - @Override - public ManagedConversation getConversation(String id) { - return getConversationMap().get(id); - } - - @Override - public Collection getConversations() { - // Don't return the map view to avoid concurrency issues - Map conversations = getConversationMap(); + } + } + } + + public boolean destroy(S session) { + // the context may be active + // if it is, we need to re-attach the bean store once the other + // conversations are destroyed + final BoundBeanStore beanStore = getBeanStore(); + final boolean active = isActive(); + if (beanStore != null) { + beanStore.detach(); + } + try { + Object conversationMap = + getSessionAttributeFromSession(session, CONVERSATIONS_ATTRIBUTE_NAME); + if (conversationMap instanceof Map) { + Map conversations = cast(conversationMap); synchronized (conversations) { - return new HashSet(conversations.values()); - } - } - - private void checkIsAssociated() { - if (!isAssociated()) { - throw ConversationLogger.LOG.mustCallAssociateBeforeLoadingKnownConversations(); - } - } - - private synchronized Map getConversationMap() { - checkIsAssociated(); - checkContextInitialized(); - final R request = getRequest(); - Object conversationMap = getRequestAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME); - if (conversationMap == null) { - conversationMap = getSessionAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME, false); - if (conversationMap == null) { - conversationMap = Collections.synchronizedMap(new HashMap()); - setRequestAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME, conversationMap); - setSessionAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME, conversationMap, false); + if (!conversations.isEmpty()) { + // There are some conversations to destroy + setActive(true); + if (beanStore == null) { + // There is no request associated - destroy conversation contexts + // immediately + for (Entry entry : + conversations.entrySet()) { + destroyConversation(session, entry.getKey(), true); + } } else { - setRequestAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME, conversationMap); + // All conversation contexts created during the current session + // should be destroyed after the servlet service() completes + // However, at that time the session will not be available - store + // all remaining contextual instances in the request + setDestructionQueue(conversations, session); } + } } - if (conversationMap == null || !(conversationMap instanceof Map)) { - throw ConversationLogger.LOG.unableToLoadConversations(CONVERSATIONS_ATTRIBUTE_NAME, conversationMap, request); - } - return cast(conversationMap); - } - - @Override - public ManagedConversation getCurrentConversation() { - checkIsAssociated(); - checkContextInitialized(); - R request = getRequest(); - Object attribute = getRequestAttribute(request, CURRENT_CONVERSATION_ATTRIBUTE_NAME); - if (attribute == null || !(attribute instanceof ManagedConversation)) { - throw ConversationLogger.LOG.unableToLoadCurrentConversation(CURRENT_CONVERSATION_ATTRIBUTE_NAME, attribute, request); - } - return (ManagedConversation) attribute; - } - - @Override - public Class getScope() { - return ConversationScoped.class; - } - - /** - * Set an attribute in the session. - * - * @param request the request to set the session attribute in - * @param name the name of the attribute - * @param value the value of the attribute - * @param create if false, the attribute will only be set if the session - * already exists, otherwise it will always be set - * @throws IllegalStateException if create is true, and the session can't be - * created - */ - protected abstract void setSessionAttribute(R request, String name, Object value, boolean create); - - /** - * Get an attribute value from the session. - * - * @param request the request to get the session attribute from - * @param name the name of the attribute - * @param create if false, the attribute will only be retrieved if the - * session already exists, other wise it will always be retrieved - * @return attribute - * @throws IllegalStateException if create is true, and the session can't be - * created - */ - protected abstract Object getSessionAttribute(R request, String name, boolean create); - - /** - * Get an attribute value from the session. - * - * @param session the session to get the session attribute from - * @param name the name of the attribute - * @return attribute - * @throws IllegalStateException if create is true, and the session can't be - * created - */ - protected abstract Object getSessionAttributeFromSession(S session, String name); - - /** - * Remove an attribute from the request. - * - * @param request the request to remove the attribute from - * @param name the name of the attribute - */ - protected abstract void removeRequestAttribute(R request, String name); - - /** - * Set an attribute in the request. - * - * @param request the request to set the attribute from - * @param name the name of the attribute - * @param value the value of the attribute - */ - protected abstract void setRequestAttribute(R request, String name, Object value); - - /** - * Retrieve an attribute value from the request - * - * @param request the request to get the attribute from - * @param name the name of the attribute to get - * @return the value of the attribute - */ - protected abstract Object getRequestAttribute(R request, String name); - - protected abstract BoundBeanStore createRequestBeanStore(NamingScheme namingScheme, R request); - - protected abstract BoundBeanStore createSessionBeanStore(NamingScheme namingScheme, S session); - - protected abstract S getSessionFromRequest(R request, boolean create); - - protected abstract String getNamingSchemePrefix(); - - /** - * Check if the context is currently associated - * - * @return true if the context is associated - */ - protected boolean isAssociated() { - return associated.get() != null; - } - - /** - * Get the associated store - * - * @return the request - */ - protected R getRequest() { - return associated.get(); - } - - protected abstract Iterator getSessionAttributeNames(S session); - + } + return true; + } finally { + setBeanStore(beanStore); + setActive(active); + if (beanStore != null) { + beanStore.attach(); + } else if (!active) { + removeState(); + cleanup(); + } + } + } + + private void + setDestructionQueue(Map conversations, + S session) { + Map>> contexts = new HashMap<>(); + for (Entry entry : conversations.entrySet()) { + ManagedConversation conversation = entry.getValue(); + // First make all conversations transient + if (!conversation.isTransient()) { + conversation.end(); + } + // Extract contextual instances + List> contextualInstances = new ArrayList<>(); + for (String id : + new ConversationNamingScheme(getNamingSchemePrefix(), entry.getKey(), + beanIdentifierIndex) + .filterIds(getSessionAttributeNames(session))) { + contextualInstances.add( + (ContextualInstance)getSessionAttributeFromSession(session, id)); + } + contexts.put(entry.getKey(), contextualInstances); + } + // Store remaining conversation contexts for later destruction + setRequestAttribute(getRequest(), DESTRUCTION_QUEUE_ATTRIBUTE_NAME, + Collections.synchronizedMap(contexts)); + } + + protected void destroyConversation(S session, String id, boolean fireEvents) { + if (session != null) { + if (fireEvents) { + conversationBeforeDestroyedEvent.get().fire(id); + } + setBeanStore(createSessionBeanStore( + new ConversationNamingScheme(getNamingSchemePrefix(), id, + beanIdentifierIndex), + session)); + getBeanStore().attach(); + destroy(); + getBeanStore().detach(); + setBeanStore(null); + if (fireEvents) { + conversationDestroyedEvent.get().fire(id); + } + } + } + + @Override + public String generateConversationId() { + ConversationIdGenerator generator = getConversationIdGenerator(); + checkContextInitialized(); + return generator.call(); + } + + // method is synchronized so that creation of conversation generator isn't a + // subject to race condition + protected synchronized ConversationIdGenerator getConversationIdGenerator() { + final R request = associated.get(); + if (request == null) { + throw ConversationLogger.LOG.mustCallAssociateBeforeGeneratingId(); + } + Object conversationIdGenerator = + getRequestAttribute(request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME); + if (conversationIdGenerator == null) { + conversationIdGenerator = getSessionAttribute( + request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME, false); + if (conversationIdGenerator == null) { + conversationIdGenerator = new ConversationIdGenerator(); + setRequestAttribute(request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME, + conversationIdGenerator); + setSessionAttribute(request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME, + conversationIdGenerator, false); + } else { + setRequestAttribute(request, CONVERSATION_ID_GENERATOR_ATTRIBUTE_NAME, + conversationIdGenerator); + } + } + if (!(conversationIdGenerator instanceof ConversationIdGenerator)) { + throw ConversationLogger.LOG.conversationIdGeneratorNotFound(); + } + return (ConversationIdGenerator)conversationIdGenerator; + } + + private static boolean isExpired(ManagedConversation conversation) { + return System.currentTimeMillis() > + (conversation.getLastUsed() + conversation.getTimeout()); + } + + @Override + public ManagedConversation getConversation(String id) { + return getConversationMap().get(id); + } + + @Override + public Collection getConversations() { + // Don't return the map view to avoid concurrency issues + Map conversations = getConversationMap(); + synchronized (conversations) { + return new HashSet(conversations.values()); + } + } + + private void checkIsAssociated() { + if (!isAssociated()) { + throw ConversationLogger.LOG + .mustCallAssociateBeforeLoadingKnownConversations(); + } + } + + private synchronized Map getConversationMap() { + checkIsAssociated(); + checkContextInitialized(); + final R request = getRequest(); + Object conversationMap = + getRequestAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME); + if (conversationMap == null) { + conversationMap = + getSessionAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME, false); + if (conversationMap == null) { + conversationMap = Collections.synchronizedMap( + new HashMap()); + setRequestAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME, + conversationMap); + setSessionAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME, + conversationMap, false); + } else if (resetHttpSessionAttributeOnBeanAccess) { + setRequestAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME, + conversationMap); + setSessionAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME, + conversationMap, false); + } else { + setRequestAttribute(request, CONVERSATIONS_ATTRIBUTE_NAME, + conversationMap); + } + } + if (conversationMap == null || !(conversationMap instanceof Map)) { + throw ConversationLogger.LOG.unableToLoadConversations( + CONVERSATIONS_ATTRIBUTE_NAME, conversationMap, request); + } + return cast(conversationMap); + } + + @Override + public ManagedConversation getCurrentConversation() { + checkIsAssociated(); + checkContextInitialized(); + R request = getRequest(); + Object attribute = + getRequestAttribute(request, CURRENT_CONVERSATION_ATTRIBUTE_NAME); + if (attribute == null || !(attribute instanceof ManagedConversation)) { + throw ConversationLogger.LOG.unableToLoadCurrentConversation( + CURRENT_CONVERSATION_ATTRIBUTE_NAME, attribute, request); + } + return (ManagedConversation)attribute; + } + + @Override + public Class getScope() { + return ConversationScoped.class; + } + + /** + * Set an attribute in the session. + * + * @param request the request to set the session attribute in + * @param name the name of the attribute + * @param value the value of the attribute + * @param create if false, the attribute will only be set if the session + * already exists, otherwise it will always be set + * @throws IllegalStateException if create is true, and the session can't be + * created + */ + protected abstract void setSessionAttribute(R request, String name, + Object value, boolean create); + + /** + * Get an attribute value from the session. + * + * @param request the request to get the session attribute from + * @param name the name of the attribute + * @param create if false, the attribute will only be retrieved if the + * session already exists, other wise it will always be + * retrieved + * @return attribute + * @throws IllegalStateException if create is true, and the session can't be + * created + */ + protected abstract Object getSessionAttribute(R request, String name, + boolean create); + + /** + * Get an attribute value from the session. + * + * @param session the session to get the session attribute from + * @param name the name of the attribute + * @return attribute + * @throws IllegalStateException if create is true, and the session can't be + * created + */ + protected abstract Object getSessionAttributeFromSession(S session, + String name); + + /** + * Remove an attribute from the request. + * + * @param request the request to remove the attribute from + * @param name the name of the attribute + */ + protected abstract void removeRequestAttribute(R request, String name); + + /** + * Set an attribute in the request. + * + * @param request the request to set the attribute from + * @param name the name of the attribute + * @param value the value of the attribute + */ + protected abstract void setRequestAttribute(R request, String name, + Object value); + + /** + * Retrieve an attribute value from the request + * + * @param request the request to get the attribute from + * @param name the name of the attribute to get + * @return the value of the attribute + */ + protected abstract Object getRequestAttribute(R request, String name); + + protected abstract BoundBeanStore + createRequestBeanStore(NamingScheme namingScheme, R request); + + protected abstract BoundBeanStore + createSessionBeanStore(NamingScheme namingScheme, S session); + + protected abstract S getSessionFromRequest(R request, boolean create); + + protected abstract String getNamingSchemePrefix(); + + /** + * Check if the context is currently associated + * + * @return true if the context is associated + */ + protected boolean isAssociated() { return associated.get() != null; } + + /** + * Get the associated store + * + * @return the request + */ + protected R getRequest() { return associated.get(); } + + protected abstract Iterator getSessionAttributeNames(S session); } diff --git a/impl/src/main/java/org/jboss/weld/executor/AbstractExecutorServices.java b/impl/src/main/java/org/jboss/weld/executor/AbstractExecutorServices.java index ec59194fc6..d388b4d7cd 100644 --- a/impl/src/main/java/org/jboss/weld/executor/AbstractExecutorServices.java +++ b/impl/src/main/java/org/jboss/weld/executor/AbstractExecutorServices.java @@ -24,7 +24,6 @@ import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; - import org.jboss.weld.exceptions.DeploymentException; import org.jboss.weld.exceptions.WeldException; import org.jboss.weld.logging.BootstrapLogger; @@ -38,110 +37,127 @@ */ public abstract class AbstractExecutorServices implements ExecutorServices { - private static final long SHUTDOWN_TIMEOUT = 60L; + private static final long SHUTDOWN_TIMEOUT = 60L; - private final ScheduledExecutorService timerExecutor = - Executors.newScheduledThreadPool(1, new DaemonThreadFactory(new ThreadGroup(DaemonThreadFactory.WELD_WORKERS), "weld-timer-")); + private final ScheduledExecutorService timerExecutor = + Executors.newScheduledThreadPool(1, + new DaemonThreadFactory("weld-timer-")); - /** - * Returns a singleton instance of ScheduledExecutorService. - * @return A managed instance of ScheduledExecutorService - */ - @Override - public ScheduledExecutorService getTimerExecutor() { - return timerExecutor; - } + /** + * Returns a singleton instance of ScheduledExecutorService. + * @return A managed instance of ScheduledExecutorService + */ + @Override + public ScheduledExecutorService getTimerExecutor() { + return timerExecutor; + } - @Override - public List> invokeAllAndCheckForExceptions(Collection> tasks) { - try { - // the cast is needed to compile this expression in JDK 8, works without it on JDK 10+ - return checkForExceptions(getTaskExecutor().invokeAll((Collection>)wrap(tasks))); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new DeploymentException(e); - } + @Override + public List> + invokeAllAndCheckForExceptions(Collection> tasks) { + try { + // the cast is needed to compile this expression in JDK 8, works without + // it on JDK 10+ + return checkForExceptions(getTaskExecutor().invokeAll( + (Collection>)wrap(tasks))); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new DeploymentException(e); } + } - public List> invokeAllAndCheckForExceptions(TaskFactory factory) { - return invokeAllAndCheckForExceptions(factory.createTasks(getThreadPoolSize())); - } + public List> + invokeAllAndCheckForExceptions(TaskFactory factory) { + return invokeAllAndCheckForExceptions( + factory.createTasks(getThreadPoolSize())); + } - protected List> checkForExceptions(List> futures) { - for (Future result : futures) { - try { - result.get(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new WeldException(e); - } catch (ExecutionException e) { - Throwable cause = e.getCause(); - if (cause instanceof RuntimeException) { - throw RuntimeException.class.cast(cause); - } else { - throw new WeldException(cause); - } - } + protected List> checkForExceptions(List> futures) { + for (Future result : futures) { + try { + result.get(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new WeldException(e); + } catch (ExecutionException e) { + Throwable cause = e.getCause(); + if (cause instanceof RuntimeException) { + throw RuntimeException.class.cast(cause); + } else { + throw new WeldException(cause); } - return futures; + } } + return futures; + } - /** - * Indicates the maximum number of threads in this thread pool. If the value is unknown or if the max number of threads is not bounded this method should - * return -1 - */ - protected abstract int getThreadPoolSize(); + /** + * Indicates the maximum number of threads in this thread pool. If the value + * is unknown or if the max number of threads is not bounded this method + * should return -1 + */ + protected abstract int getThreadPoolSize(); - @Override - public void cleanup() { - shutdown(); - } + @Override + public void cleanup() { + shutdown(); + } - protected void shutdown() { - SecurityActions.shutdown(getTaskExecutor()); - SecurityActions.shutdown(getTimerExecutor()); - try { - // Wait a while for existing tasks to terminate - if (!getTaskExecutor().awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.SECONDS)) { - SecurityActions.shutdownNow(getTaskExecutor()); // Cancel currently executing tasks - // Wait a while for tasks to respond to being cancelled - if (!getTaskExecutor().awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.SECONDS)) { - // Log the error here - BootstrapLogger.LOG.timeoutShuttingDownThreadPool(getTaskExecutor(), this); - } - } - } catch (InterruptedException ie) { - // (Re-)Cancel if current thread also interrupted - SecurityActions.shutdownNow(getTaskExecutor()); - // Preserve interrupt status - Thread.currentThread().interrupt(); + protected void shutdown() { + SecurityActions.shutdown(getTaskExecutor()); + SecurityActions.shutdown(getTimerExecutor()); + try { + // Wait a while for existing tasks to terminate + if (!getTaskExecutor().awaitTermination(SHUTDOWN_TIMEOUT, + TimeUnit.SECONDS)) { + SecurityActions.shutdownNow( + getTaskExecutor()); // Cancel currently executing tasks + // Wait a while for tasks to respond to being cancelled + if (!getTaskExecutor().awaitTermination(SHUTDOWN_TIMEOUT, + TimeUnit.SECONDS)) { + // Log the error here + BootstrapLogger.LOG.timeoutShuttingDownThreadPool(getTaskExecutor(), + this); } + } + } catch (InterruptedException ie) { + // (Re-)Cancel if current thread also interrupted + SecurityActions.shutdownNow(getTaskExecutor()); + // Preserve interrupt status + Thread.currentThread().interrupt(); + } - // Do the same for timer executor - try { - if (!getTimerExecutor().isShutdown()) { // no need to do the full wait, one already elapsed - SecurityActions.shutdownNow(getTimerExecutor()); - if (!getTimerExecutor().awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.SECONDS)) { - // Log the error here - BootstrapLogger.LOG.timeoutShuttingDownThreadPool(getTimerExecutor(), this); - } - } - } catch (InterruptedException ie) { - // (Re-)Cancel if current thread also interrupted - SecurityActions.shutdownNow(getTimerExecutor()); - // Preserve interrupt status - Thread.currentThread().interrupt(); + // Do the same for timer executor + try { + if (!getTimerExecutor().isShutdown()) { // no need to do the full wait, + // one already elapsed + SecurityActions.shutdownNow(getTimerExecutor()); + if (!getTimerExecutor().awaitTermination(SHUTDOWN_TIMEOUT, + TimeUnit.SECONDS)) { + // Log the error here + BootstrapLogger.LOG.timeoutShuttingDownThreadPool(getTimerExecutor(), + this); } + } + } catch (InterruptedException ie) { + // (Re-)Cancel if current thread also interrupted + SecurityActions.shutdownNow(getTimerExecutor()); + // Preserve interrupt status + Thread.currentThread().interrupt(); } + } - /** - * This method is invoked with the body of {@link AbstractExecutorServices#invokeAllAndCheckForExceptions(java.util.Collection)} - * - * It allows to wrap the tasks with some additional logic. For instance, Weld's {@link CommonForkJoinPoolExecutorServices} - * overrides this in order to set TCCL to null prior to execution. - */ - public Collection> wrap(Collection> tasks) { - //no-op by default - return tasks; - } + /** + * This method is invoked with the body of {@link + * AbstractExecutorServices#invokeAllAndCheckForExceptions(java.util.Collection)} + * + * It allows to wrap the tasks with some additional logic. For instance, + * Weld's {@link CommonForkJoinPoolExecutorServices} overrides this in order + * to set TCCL to null prior to execution. + */ + public Collection> + wrap(Collection> tasks) { + // no-op by default + return tasks; + } } diff --git a/impl/src/main/java/org/jboss/weld/executor/DaemonThreadFactory.java b/impl/src/main/java/org/jboss/weld/executor/DaemonThreadFactory.java index 8a8d4017b4..99a3ab8de5 100644 --- a/impl/src/main/java/org/jboss/weld/executor/DaemonThreadFactory.java +++ b/impl/src/main/java/org/jboss/weld/executor/DaemonThreadFactory.java @@ -20,27 +20,25 @@ import java.util.concurrent.atomic.AtomicInteger; /** - * {@link ThreadFactory} that creates daemon threads so that Weld does not hang e.g. in a SE environment. + * {@link ThreadFactory} that creates daemon threads so that Weld does not hang + * e.g. in a SE environment. * @author Jozef Hartinger * */ public class DaemonThreadFactory implements ThreadFactory { - public static final String WELD_WORKERS = "weld-workers"; + private final AtomicInteger threadNumber = new AtomicInteger(1); + private final String threadNamePrefix; - private final AtomicInteger threadNumber = new AtomicInteger(1); - private final String threadNamePrefix; - private final ThreadGroup threadGroup ; + public DaemonThreadFactory(String threadNamePrefix) { + this.threadNamePrefix = threadNamePrefix; + } - public DaemonThreadFactory(ThreadGroup threadGroup, String threadNamePrefix) { - this.threadGroup = threadGroup; - this.threadNamePrefix = threadNamePrefix; - } - - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(threadGroup, r, threadNamePrefix + threadNumber.getAndIncrement()); - thread.setDaemon(true); - return thread; - } -} \ No newline at end of file + @Override + public Thread newThread(Runnable r) { + Thread thread = + new Thread(r, threadNamePrefix + threadNumber.getAndIncrement()); + thread.setDaemon(true); + return thread; + } +} diff --git a/impl/src/main/java/org/jboss/weld/executor/FixedThreadPoolExecutorServices.java b/impl/src/main/java/org/jboss/weld/executor/FixedThreadPoolExecutorServices.java index f3802a31e9..275675aab8 100644 --- a/impl/src/main/java/org/jboss/weld/executor/FixedThreadPoolExecutorServices.java +++ b/impl/src/main/java/org/jboss/weld/executor/FixedThreadPoolExecutorServices.java @@ -18,40 +18,42 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; - import org.jboss.weld.logging.BootstrapLogger; /** - * Implementation of {@link ExtendedExecutorServices} that uses a fixed thread pool. The size of the underlying thread pool is - * determined by executing Runtime.getRuntime().availableProcessors() + 1. + * Implementation of {@link ExtendedExecutorServices} that uses a fixed thread + * pool. The size of the underlying thread pool is determined by executing + * Runtime.getRuntime().availableProcessors() + 1. * * @author Jozef Hartinger * */ public class FixedThreadPoolExecutorServices extends AbstractExecutorServices { - private final int threadPoolSize; + private final int threadPoolSize; - private final ExecutorService executor; + private final ExecutorService executor; - public FixedThreadPoolExecutorServices(int threadPoolSize) { - this.threadPoolSize = threadPoolSize; - this.executor = Executors.newFixedThreadPool(threadPoolSize, new DaemonThreadFactory(new ThreadGroup(DaemonThreadFactory.WELD_WORKERS), "weld-worker-")); - BootstrapLogger.LOG.threadsInUse(threadPoolSize); - } + public FixedThreadPoolExecutorServices(int threadPoolSize) { + this.threadPoolSize = threadPoolSize; + this.executor = Executors.newFixedThreadPool( + threadPoolSize, new DaemonThreadFactory("weld-worker-")); + BootstrapLogger.LOG.threadsInUse(threadPoolSize); + } - @Override - public ExecutorService getTaskExecutor() { - return executor; - } + @Override + public ExecutorService getTaskExecutor() { + return executor; + } - @Override - public int getThreadPoolSize() { - return threadPoolSize; - } + @Override + public int getThreadPoolSize() { + return threadPoolSize; + } - @Override - public String toString() { - return "FixedThreadPoolExecutorServices [threadPoolSize=" + threadPoolSize + "]"; - } + @Override + public String toString() { + return "FixedThreadPoolExecutorServices [threadPoolSize=" + threadPoolSize + + "]"; + } } diff --git a/impl/src/main/java/org/jboss/weld/executor/TimingOutFixedThreadPoolExecutorServices.java b/impl/src/main/java/org/jboss/weld/executor/TimingOutFixedThreadPoolExecutorServices.java index d59f8732c1..85a2c6e897 100644 --- a/impl/src/main/java/org/jboss/weld/executor/TimingOutFixedThreadPoolExecutorServices.java +++ b/impl/src/main/java/org/jboss/weld/executor/TimingOutFixedThreadPoolExecutorServices.java @@ -20,57 +20,58 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; - import org.jboss.weld.logging.BootstrapLogger; /** - * Implementation of {@link ExtendedExecutorServices} that uses a fixed thread pool. However threads are terminated if no new tasks arrive within the keep-alive time. + * Implementation of {@link ExtendedExecutorServices} that uses a fixed thread + * pool. However threads are terminated if no new tasks arrive within the + * keep-alive time. * * @author Martin Kouba */ -public class TimingOutFixedThreadPoolExecutorServices extends AbstractExecutorServices { - - private final int threadPoolSize; - /** - * Keep-alive time in seconds - */ - private long keepAliveTime; +public class TimingOutFixedThreadPoolExecutorServices + extends AbstractExecutorServices { - private final ThreadPoolExecutor executor; + private final int threadPoolSize; + /** + * Keep-alive time in seconds + */ + private long keepAliveTime; - public TimingOutFixedThreadPoolExecutorServices(int threadPoolSize, long keepAliveTime) { + private final ThreadPoolExecutor executor; - this.threadPoolSize = threadPoolSize; - this.keepAliveTime = keepAliveTime; + public TimingOutFixedThreadPoolExecutorServices(int threadPoolSize, + long keepAliveTime) { - this.executor = new ThreadPoolExecutor(threadPoolSize, threadPoolSize, - keepAliveTime, TimeUnit.SECONDS, - new LinkedBlockingQueue(), - new DaemonThreadFactory(new ThreadGroup(DaemonThreadFactory.WELD_WORKERS), "weld-worker-")); - // Terminate threads if no new tasks arrive within the keep-alive time - this.executor.allowCoreThreadTimeOut(true); + this.threadPoolSize = threadPoolSize; + this.keepAliveTime = keepAliveTime; - BootstrapLogger.LOG.threadsInUse(threadPoolSize); - } + this.executor = new ThreadPoolExecutor( + threadPoolSize, threadPoolSize, keepAliveTime, TimeUnit.SECONDS, + new LinkedBlockingQueue(), + new DaemonThreadFactory("weld-worker-")); + // Terminate threads if no new tasks arrive within the keep-alive time + this.executor.allowCoreThreadTimeOut(true); - public int getPoolSize() { - return executor.getPoolSize(); - } + BootstrapLogger.LOG.threadsInUse(threadPoolSize); + } - @Override - public ExecutorService getTaskExecutor() { - return executor; - } + public int getPoolSize() { return executor.getPoolSize(); } - @Override - protected int getThreadPoolSize() { - return threadPoolSize; - } + @Override + public ExecutorService getTaskExecutor() { + return executor; + } - @Override - public String toString() { - return String.format("TimingOutFixedThreadPoolExecutorServices [threadPoolSize=%s, keepAliveTime=%s]", threadPoolSize, - keepAliveTime); - } + @Override + protected int getThreadPoolSize() { + return threadPoolSize; + } + @Override + public String toString() { + return String.format("TimingOutFixedThreadPoolExecutorServices " + + "[threadPoolSize=%s, keepAliveTime=%s]", + threadPoolSize, keepAliveTime); + } } diff --git a/impl/src/main/java/org/jboss/weld/interceptor/proxy/WeldInvocationContextImpl.java b/impl/src/main/java/org/jboss/weld/interceptor/proxy/WeldInvocationContextImpl.java index 9ec6318b4b..f482efa577 100644 --- a/impl/src/main/java/org/jboss/weld/interceptor/proxy/WeldInvocationContextImpl.java +++ b/impl/src/main/java/org/jboss/weld/interceptor/proxy/WeldInvocationContextImpl.java @@ -25,9 +25,7 @@ import java.util.List; import java.util.Map; import java.util.Set; - import javax.interceptor.InvocationContext; - import org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler; import org.jboss.weld.bean.proxy.InterceptionDecorationContext; import org.jboss.weld.bean.proxy.InterceptionDecorationContext.Stack; @@ -37,125 +35,149 @@ import org.jboss.weld.util.Preconditions; /** - * Weld's {@link InvocationContext} implementation. This is a forwarding implementation that delegates most method calls to an underlying - * {@link InvocationContext}. This allows multiple interceptor chains to be combined. + * Weld's {@link InvocationContext} implementation. This is a forwarding + * implementation that delegates most method calls to an underlying + * {@link InvocationContext}. This allows multiple interceptor chains to be + * combined. * - * A call to {@link #proceed()} invokes the chain of intercepors in the given order. Once the chain finishes, the {@link #proceed()} method of the delegate is - * invoked which results in the target method being invoked in case of {@link SimpleInvocationContext}. Otherwise, the delegate chain is run. + * A call to {@link #proceed()} invokes the chain of intercepors in the given + * order. Once the chain finishes, the {@link #proceed()} method of the delegate + * is invoked which results in the target method being invoked in case of {@link + * SimpleInvocationContext}. Otherwise, the delegate chain is run. * * @author Jozef Hartinger * */ -public class WeldInvocationContextImpl extends ForwardingInvocationContext implements org.jboss.weld.interceptor.WeldInvocationContext { - - private int position; - private final List chain; - private final CombinedInterceptorAndDecoratorStackMethodHandler currentHandler; - private final InvocationContext delegate; - private final Set interceptorBindings; - - public WeldInvocationContextImpl(Constructor constructor, Object[] parameters, Map contextData, List chain, Set interceptorBindings) { - this(new SimpleInvocationContext(constructor, parameters, contextData, interceptorBindings), chain, interceptorBindings, null); - } - - public WeldInvocationContextImpl(Object target, Method targetMethod, Method proceed, Object[] parameters, List chain, Set interceptorBindings, Stack stack) { - this(new SimpleInvocationContext(target, targetMethod, proceed, parameters, interceptorBindings), chain, interceptorBindings, (stack == null) ? null : stack.peek()); - } - - public WeldInvocationContextImpl(InvocationContext delegate, List chain, Set interceptorBindings, CombinedInterceptorAndDecoratorStackMethodHandler currentHandler) { - this.delegate = delegate; - this.chain = chain; - this.currentHandler = currentHandler; - if (interceptorBindings == null) { - this.interceptorBindings = Collections.emptySet(); - } else { - this.interceptorBindings = interceptorBindings; - } - getContextData().put(WeldInvocationContext.INTERCEPTOR_BINDINGS_KEY, interceptorBindings); - } - - @Override - protected InvocationContext delegate() { - return delegate; +public class WeldInvocationContextImpl extends ForwardingInvocationContext + implements org.jboss.weld.interceptor.WeldInvocationContext { + + private int position; + private final List chain; + private final CombinedInterceptorAndDecoratorStackMethodHandler + currentHandler; + private final InvocationContext delegate; + private final Set interceptorBindings; + + public WeldInvocationContextImpl(Constructor constructor, + Object[] parameters, + Map contextData, + List chain, + Set interceptorBindings) { + this(new SimpleInvocationContext(constructor, parameters, contextData, + interceptorBindings), + chain, interceptorBindings, null); + } + + public WeldInvocationContextImpl(Object target, Method targetMethod, + Method proceed, Object[] parameters, + List chain, + Set interceptorBindings, + Stack stack) { + this(new SimpleInvocationContext(target, targetMethod, proceed, parameters, + interceptorBindings), + chain, interceptorBindings, (stack == null) ? null : stack.peek()); + } + + public WeldInvocationContextImpl( + InvocationContext delegate, List chain, + Set interceptorBindings, + CombinedInterceptorAndDecoratorStackMethodHandler currentHandler) { + this.delegate = delegate; + this.chain = chain; + this.currentHandler = currentHandler; + if (interceptorBindings == null) { + this.interceptorBindings = Collections.emptySet(); + } else { + this.interceptorBindings = interceptorBindings; } - - public boolean hasNextInterceptor() { - return position < chain.size(); - } - - protected Object invokeNext() throws Exception { - int oldCurrentPosition = position; - try { - InterceptorMethodInvocation nextInterceptorMethodInvocation = chain.get(position++); - InterceptorLogger.LOG.invokingNextInterceptorInChain(nextInterceptorMethodInvocation); - if (nextInterceptorMethodInvocation.expectsInvocationContext()) { - return nextInterceptorMethodInvocation.invoke(WeldInvocationContextImpl.this); - } else { - nextInterceptorMethodInvocation.invoke(null); - while (hasNextInterceptor()) { - nextInterceptorMethodInvocation = chain.get(position++); - nextInterceptorMethodInvocation.invoke(null); - } - return null; - } - } finally { - position = oldCurrentPosition; + getContextData().put(WeldInvocationContext.INTERCEPTOR_BINDINGS_KEY, + this.interceptorBindings); + } + + @Override + protected InvocationContext delegate() { + return delegate; + } + + public boolean hasNextInterceptor() { return position < chain.size(); } + + protected Object invokeNext() throws Exception { + int oldCurrentPosition = position; + try { + InterceptorMethodInvocation nextInterceptorMethodInvocation = + chain.get(position++); + InterceptorLogger.LOG.invokingNextInterceptorInChain( + nextInterceptorMethodInvocation); + if (nextInterceptorMethodInvocation.expectsInvocationContext()) { + return nextInterceptorMethodInvocation.invoke( + WeldInvocationContextImpl.this); + } else { + nextInterceptorMethodInvocation.invoke(null); + while (hasNextInterceptor()) { + nextInterceptorMethodInvocation = chain.get(position++); + nextInterceptorMethodInvocation.invoke(null); } + return null; + } + } finally { + position = oldCurrentPosition; } - - protected Object interceptorChainCompleted() throws Exception { - return delegate().proceed(); + } + + protected Object interceptorChainCompleted() throws Exception { + return delegate().proceed(); + } + + @Override + public Object proceed() throws Exception { + Stack stack = null; + /* + * No need to push the context for the first interceptor as the current + * context was set by CombinedInterceptorAndDecoratorStackMethodHandler + */ + + if (currentHandler != null && position != 0) { + stack = InterceptionDecorationContext.startIfNotOnTop(currentHandler); } - @Override - public Object proceed() throws Exception { - Stack stack = null; - /* - * No need to push the context for the first interceptor as the current context - * was set by CombinedInterceptorAndDecoratorStackMethodHandler - */ - - if (currentHandler != null && position != 0) { - stack = InterceptionDecorationContext.startIfNotOnTop(currentHandler); - } - - try { - if (hasNextInterceptor()) { - return invokeNext(); - } else { - return interceptorChainCompleted(); - } - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - if (cause instanceof Error) { - throw (Error) cause; - } - if (cause instanceof Exception) { - throw (Exception) cause; - } - throw new RuntimeException(cause); - } finally { - if (stack != null) { - stack.end(); - } - } + try { + if (hasNextInterceptor()) { + return invokeNext(); + } else { + return interceptorChainCompleted(); + } + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof Error) { + throw (Error)cause; + } + if (cause instanceof Exception) { + throw (Exception)cause; + } + throw new RuntimeException(cause); + } finally { + if (stack != null) { + stack.end(); + } } - - @Override - @SuppressWarnings("unchecked") - public Set getInterceptorBindingsByType(Class annotationType) { - Preconditions.checkArgumentNotNull(annotationType, "annotationType"); - Set result = new HashSet<>(); - for (Annotation interceptorBinding : interceptorBindings) { - if (interceptorBinding.annotationType().equals(annotationType)) { - result.add((T) interceptorBinding); - } - } - return result; + } + + @Override + @SuppressWarnings("unchecked") + public Set + getInterceptorBindingsByType(Class annotationType) { + Preconditions.checkArgumentNotNull(annotationType, "annotationType"); + Set result = new HashSet<>(); + for (Annotation interceptorBinding : interceptorBindings) { + if (interceptorBinding.annotationType().equals(annotationType)) { + result.add((T)interceptorBinding); + } } + return result; + } - @Override - public Set getInterceptorBindings() { - return interceptorBindings; - } + @Override + public Set getInterceptorBindings() { + return interceptorBindings; + } } diff --git a/impl/src/main/java/org/jboss/weld/logging/BeanLogger.java b/impl/src/main/java/org/jboss/weld/logging/BeanLogger.java index eea994cc44..eb7a4518f6 100644 --- a/impl/src/main/java/org/jboss/weld/logging/BeanLogger.java +++ b/impl/src/main/java/org/jboss/weld/logging/BeanLogger.java @@ -44,506 +44,1065 @@ @MessageLogger(projectCode = WELD_PROJECT_CODE) public interface BeanLogger extends WeldLogger { - BeanLogger LOG = Logger.getMessageLogger(BeanLogger.class, Category.BEAN.getName()); - - @LogMessage(level = Level.TRACE) - @Message(id = 1, value = "Exactly one constructor ({0}) annotated with @Inject defined, using it as the bean constructor for {1}", format = Format.MESSAGE_FORMAT) - void foundOneInjectableConstructor(Object param1, Object param2); - - @LogMessage(level = Level.TRACE) - @Message(id = 2, value = "Exactly one constructor ({0}) defined, using it as the bean constructor for {1}", format = Format.MESSAGE_FORMAT) - void foundDefaultConstructor(Object param1, Object param2); - - @LogMessage(level = Level.TRACE) - @Message(id = 4, value = "Exactly one post construct method ({0}) for {1}", format = Format.MESSAGE_FORMAT) - void foundOnePostConstructMethod(Object param1, Object param2); - - @LogMessage(level = Level.TRACE) - @Message(id = 6, value = "Exactly one pre destroy method ({0}) for {1}", format = Format.MESSAGE_FORMAT) - void foundOnePreDestroyMethod(Object param1, Object param2); - - @LogMessage(level = Level.TRACE) - @Message(id = 7, value = "Created session bean proxy for {0}", format = Format.MESSAGE_FORMAT) - void createdSessionBeanProxy(Object param1); - - @LogMessage(level = Level.TRACE) - @Message(id = 8, value = "Called {0} on {1} with parameters {2} which returned {3}", format = Format.MESSAGE_FORMAT) - void callProxiedMethod(Object param1, Object param2, Object param3, Object param4); - - @Message(id = 9, value = "Dynamic lookup of {0} is not supported", format = Format.MESSAGE_FORMAT) - IllegalArgumentException dynamicLookupOfBuiltInNotAllowed(Object param1); - - @LogMessage(level = Level.TRACE) - @Message(id = 10, value = "Using qualifiers {0} for {1}", format = Format.MESSAGE_FORMAT) - void qualifiersUsed(Object param1, Object param2); - - @LogMessage(level = Level.TRACE) - @Message(id = 12, value = "Building bean metadata for {0}", format = Format.MESSAGE_FORMAT) - void creatingBean(Object param1); - - @LogMessage(level = Level.TRACE) - @Message(id = 14, value = "Using name {0} for {1}", format = Format.MESSAGE_FORMAT) - void usingName(Object param1, Object param2); - - @LogMessage(level = Level.TRACE) - @Message(id = 16, value = "Using scope {0} for {1}", format = Format.MESSAGE_FORMAT) - void usingScope(Object param1, Object param2); - - @LogMessage(level = Level.WARN) - @Message(id = 18, value = "Executing producer field or method {0} on incomplete declaring bean {1} due to circular injection", format = Format.MESSAGE_FORMAT) - void circularCall(Object param1, Object param2); - - @LogMessage(level = Level.ERROR) - @Message(id = 19, value = "Error destroying an instance {0} of {1}", format = Format.MESSAGE_FORMAT) - void errorDestroying(Object param1, Object param2); - - @Message(id = 23, value = "Type parameter must be a concrete type: {0}", format = Format.MESSAGE_FORMAT) - String typeParameterMustBeConcrete(Object param1); - - @Message(id = 25, value = "Tried to create an EEResourceProducerField, but no @Resource, @PersistenceContext, @PersistenceUnit, @WebServiceRef or @EJB is present: {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException invalidResourceProducerField(Object param1); - - @Message(id = 26, value = "Security Services not available - unable to obtain the Principal") - IllegalStateException securityServicesNotAvailable(); - - @Message(id = 27, value = "Transaction Services not available - unable to obtain the UserTransaction") - IllegalStateException transactionServicesNotAvailable(); - - @Message(id = 28, value = "Interception model must not be null") - IllegalArgumentException interceptionModelNull(); - - @Message(id = 29, value = "InterceptionType must not be null") - IllegalArgumentException interceptionTypeNull(); - - @Message(id = 30, value = "Method must not be null") - IllegalArgumentException methodNull(); - - @Message(id = 31, value = "InterceptionType must not be lifecycle, but it is {0}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException interceptionTypeLifecycle(Object param1); - - @Message(id = 32, value = "InterceptionType must be lifecycle, but it is {0}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException interceptionTypeNotLifecycle(Object param1); - - @Message(id = 33, value = "Could not instantiate client proxy for {0}", format = Format.MESSAGE_FORMAT) - String proxyInstantiationFailed(Object param1); - - @Message(id = 34, value = "Could not access bean correctly when creating client proxy for {0}", format = Format.MESSAGE_FORMAT) - String proxyInstantiationBeanAccessFailed(Object param1); - - @Message(id = 35, value = "There was an error creating an id for {0}", format = Format.MESSAGE_FORMAT) - DefinitionException beanIdCreationFailed(Object param1); - - @Message(id = 36, value = "Unexpected unwrapped custom decorator instance: {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException unexpectedUnwrappedCustomDecorator(Object param1); - - @Message(id = 37, value = "Cannot call EJB remove method directly on non-dependent scoped bean {0}", format = Format.MESSAGE_FORMAT) - UnsupportedOperationException invalidRemoveMethodInvocation(Object param1); - - @Message(id = 38, value = "A bean class that is not a decorator has an injection point annotated @Delegate\n at injection point {0}\n\tat {1}\n StackTrace:", format = Format.MESSAGE_FORMAT) - DefinitionException delegateNotOnDecorator(Object ip, Object stackElement); - - @Message(id = 39, value = "@Typed class {0} not present in the set of bean types of {1} [{2}]", format = Format.MESSAGE_FORMAT) - DefinitionException typedClassNotInHierarchy(Object param1, Object param2, Object types); - - @SuppressWarnings({ "weldlog:method-sig", "weldlog:msg-value" }) - @Message(id = 40, value = "All stereotypes must specify the same scope or the bean must declare a scope - declared on {0}, declared stereotypes [{1}], possible scopes {2}{3}", format = Format.MESSAGE_FORMAT) - DefinitionException multipleScopesFoundFromStereotypes(Object declaredOn, Object stereotypes, Object possibleScopes, String stack); - - @Message(id = 41, value = "Specializing bean may not declare a bean name if it is declared by specialized bean\n specializing: {0}\n specialized: {1}", format = Format.MESSAGE_FORMAT) - DefinitionException nameNotAllowedOnSpecialization(Object specializing, Object specialized); - - @Message(id = 42, value = "Cannot operate on non container provided decorator {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException nonContainerDecorator(Object param1); - - @Message(id = 43, value = "The following bean is not an EE resource producer: {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException beanNotEeResourceProducer(Object param1); - - @Message(id = 44, value = "Unable to obtain instance from {0}", format = Format.MESSAGE_FORMAT) - NullInstanceException nullInstance(Object param1); - - @Message(id = 45, value = "Unable to deserialize object - serialization proxy is required") - InvalidObjectException serializationProxyRequired(); - - @Message(id = 46, value = "At most one scope may be specified on {0}", format = Format.MESSAGE_FORMAT) - DefinitionException onlyOneScopeAllowed(Object param1); - - @Message(id = 47, value = "Specializing bean must extend another bean: {0}", format = Format.MESSAGE_FORMAT) - DefinitionException specializingBeanMustExtendABean(Object param1); - - @Message(id = 48, value = "Conflicting interceptor bindings found on {0}", format = Format.MESSAGE_FORMAT) - String conflictingInterceptorBindings(Object param1); - - @Message(id = 49, value = "Unable to invoke {0} on {1}", format = Format.MESSAGE_FORMAT) - WeldException invocationError(Object param1, Object param2, @Cause Throwable cause); - - @Message(id = 50, value = "Cannot cast producer type {0} to bean type {1}", format = Format.MESSAGE_FORMAT) - WeldException producerCastError(Object param1, Object param2, @Cause Throwable cause); - - @Message(id = 52, value = "Cannot return null from a non-dependent producer method: {0}\n\tat {1}\n StackTrace:", format = Format.MESSAGE_FORMAT) - IllegalProductException nullNotAllowedFromProducer(Object param1, Object stackElement); - - @Message(id = 53, value = "Producers cannot declare passivating scope and return a non-serializable class: {0}\n\tat {1}\n StackTrace:", format = Format.MESSAGE_FORMAT) - IllegalProductException nonSerializableProductError(Object param1, Object stackElement); - - @Message(id = 54, value = "Producers cannot produce unserializable instances for injection into an injection point that requires a passivation capable dependency\n Producer: {0}\n\tat {1}\n Injection Point: {2}\n\tat {3}\n StackTrace:", format = Format.MESSAGE_FORMAT) - IllegalProductException unserializableProductInjectionError(Object producer, Object producerStackElement, Object ip, Object ipStackElement); - - @Message(id = 59, value = "No delegate injection point defined for {0}", format = Format.MESSAGE_FORMAT) - DefinitionException noDelegateInjectionPoint(Object param1); - - @Message(id = 60, value = "Too many delegate injection points defined for {0}", format = Format.MESSAGE_FORMAT) - DefinitionException tooManyDelegateInjectionPoints(Object param1); - - @Message(id = 61, value = "The delegate type does not extend or implement the decorated type. \n Decorated type: {0}\n Decorator: {1}", format = Format.MESSAGE_FORMAT) - DefinitionException delegateMustSupportEveryDecoratedType(Object decoratedType, Object decorator); - - @Message(id = 64, value = "Unable to process decorated type: {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException unableToProcessDecoratedType(Object decoratedType); - - @Message(id = 66, value = "{0} has more than one @Dispose parameter \n\tat {1}\n StackTrace:", format = Format.MESSAGE_FORMAT) - DefinitionException multipleDisposeParams(Object param1, Object stackElement); - - @Message(id = 67, value = "{0} is not allowed on same method as {1}, see {2}\n\tat {3}\n StackTrace:", format = Format.MESSAGE_FORMAT) - DefinitionException inconsistentAnnotationsOnMethod(Object param1, Object param2, Object param3, Object stackElement); - - @Message(id = 68, value = "{0} method {1} is not a business method of {2}\n\tat {3}\n StackTrace:", format = Format.MESSAGE_FORMAT) - DefinitionException methodNotBusinessMethod(Object methodType, Object param1, Object param2, Object stackElement); - - @Message(id = 70, value = "Simple bean {0} cannot be a non-static inner class", format = Format.MESSAGE_FORMAT) - DefinitionException simpleBeanAsNonStaticInnerClassNotAllowed(Object param1); - - @Message(id = 71, value = "Managed bean with a parameterized bean class must be @Dependent: {0}", format = Format.MESSAGE_FORMAT) - DefinitionException managedBeanWithParameterizedBeanClassMustBeDependent(Object param1); - - @Message(id = 72, value = "Bean declaring a passivating scope must be passivation capable. Bean: {0}", format = Format.MESSAGE_FORMAT) - DeploymentException passivatingBeanNeedsSerializableImpl(Object param1); - - @Message(id = 73, value = "Bean class which has decorators cannot be declared final: {0}", format = Format.MESSAGE_FORMAT) - DeploymentException finalBeanClassWithDecoratorsNotAllowed(Object param1); - - @Message(id = 75, value = "Normal scoped managed bean implementation class has a public field: {0}", format = Format.MESSAGE_FORMAT) - DefinitionException publicFieldOnNormalScopedBeanNotAllowed(Object param1); - - @Message(id = 76, value = "Bean constructor must not have a parameter annotated with {0}: {1}\n\tat {2}\n StackTrace:", format = Format.MESSAGE_FORMAT) - DefinitionException parameterAnnotationNotAllowedOnConstructor(Object param1, Object param2, Object stackElement); - - @Message(id = 77, value = "Cannot declare multiple disposal methods for this producer method.\n\nProducer method: {0}\nDisposal methods: {1}", format = Format.MESSAGE_FORMAT) - DefinitionException multipleDisposalMethods(Object param1, Object param2); - - @Message(id = 78, value = "Specialized producer method does not override another producer method: {0}\n\tat {1}\n StackTrace:", format = Format.MESSAGE_FORMAT) - DefinitionException producerMethodNotSpecializing(Object param1, Object stackElement); - - @Message(id = 79, value = "Could not instantiate a proxy for a session bean: {0}\n Proxy: {1}", format = Format.MESSAGE_FORMAT) - CreationException sessionBeanProxyInstantiationFailed(Object sessionBean, Object proxyClass, @Cause Throwable cause); - - @Message(id = 80, value = "Enterprise beans cannot be interceptors: {0}", format = Format.MESSAGE_FORMAT) - DefinitionException ejbCannotBeInterceptor(Object param1); - - @Message(id = 81, value = "Enterprise beans cannot be decorators: {0}", format = Format.MESSAGE_FORMAT) - DefinitionException ejbCannotBeDecorator(Object param1); - - @Message(id = 82, value = "Scope {0} is not allowed on stateless session beans for {1}. Only @Dependent is allowed.", format = Format.MESSAGE_FORMAT) - DefinitionException scopeNotAllowedOnStatelessSessionBean(Object param1, Object param2); - - @Message(id = 83, value = "Scope {0} is not allowed on singleton session beans for {1}. Only @Dependent and @ApplicationScoped is allowed.", format = Format.MESSAGE_FORMAT) - DefinitionException scopeNotAllowedOnSingletonBean(Object param1, Object param2); - - @Message(id = 84, value = "Specializing enterprise bean must extend another enterprise bean: {0}", format = Format.MESSAGE_FORMAT) - DefinitionException specializingEnterpriseBeanMustExtendAnEnterpriseBean(Object param1); - - @Message(id = 85, value = "Cannot destroy null instance of {0}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException cannotDestroyNullBean(Object param1); - - @Message(id = 86, value = "Cannot destroy session bean instance not created by the container: {0}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException cannotDestroyEnterpriseBeanNotCreated(Object param1); - - @Message(id = 87, value = "Message driven beans cannot be Managed Beans: {0}", format = Format.MESSAGE_FORMAT) - DefinitionException messageDrivenBeansCannotBeManaged(Object param1); - - @Message(id = 88, value = "Observer method must be static or local business method: {0}\n\tat {1}\n StackTrace:", format = Format.MESSAGE_FORMAT) - DefinitionException observerMethodMustBeStaticOrBusiness(Object param1, Object stackElement); - - @Message(id = 89, value = "Unable to determine EJB for {0}, multiple EJBs with that class: {1}", format = Format.MESSAGE_FORMAT) - IllegalStateException tooManyEjbsForClass(Object param1, Object param2); - - @Message(id = 90, value = "A decorator has an abstract method that is not declared by any decorated type\n Method: {0}\n\tat {1}\n StackTrace:", format = Format.MESSAGE_FORMAT) - DefinitionException abstractMethodMustMatchDecoratedType(Object param1, Object param2); - - @Message(id = 94, value = "Injected field {0} cannot be annotated @Produces on {1}", format = Format.MESSAGE_FORMAT) - DefinitionException injectedFieldCannotBeProducer(Object param1, Object param2); - - @Message(id = 95, value = "Session bean with generic class {0} must be @Dependent scope", format = Format.MESSAGE_FORMAT) - DefinitionException genericSessionBeanMustBeDependent(Object param1); - - @Message(id = 96, value = "Producer fields on session beans must be static. Field {0} declared on {1}", format = Format.MESSAGE_FORMAT) - DefinitionException producerFieldOnSessionBeanMustBeStatic(Object param1, Object param2); - - @Message(id = 97, value = "A producer method with a parameterized return type with a type variable must be declared @Dependent scoped: \n {0}\n\tat {1}\n StackTrace:", format = Format.MESSAGE_FORMAT) - DefinitionException producerMethodWithTypeVariableReturnTypeMustBeDependent(Object param1, String stackElement); - - @Message(id = 98, value = "A producer method return type may not contain a wildcard: \n {0}\n\tat {1}\n StackTrace:", format = Format.MESSAGE_FORMAT) - DefinitionException producerMethodCannotHaveAWildcardReturnType(Object param1, String stackElement); - - @Message(id = 99, value = "Cannot load class {0} during deserialization of proxy", format = Format.MESSAGE_FORMAT) - WeldException cannotLoadClass(Object param1, @Cause Throwable cause); - - @Message(id = 1500, value = "Failed to deserialize proxy object with beanId {0}", format = Format.MESSAGE_FORMAT) - WeldException proxyDeserializationFailure(Object param1); - - @Message(id = 1501, value = "Method call requires a BeanInstance which has not been set for this proxy {0}", format = Format.MESSAGE_FORMAT) - WeldException beanInstanceNotSetOnProxy(Object param1); - - @Message(id = 1502, value = "Resource producer field [{0}] must be @Dependent scoped", format = Format.MESSAGE_FORMAT) - DefinitionException nonDependentResourceProducerField(Object param1); - - @Message(id = 1503, value = "Bean class which has interceptors cannot be declared final: {0}", format = Format.MESSAGE_FORMAT) - DeploymentException finalBeanClassWithInterceptorsNotAllowed(Object param1); - - @Message(id = 1504, value = "Intercepted bean method {0} (intercepted by {1}) cannot be declared final", format = Format.MESSAGE_FORMAT) - DeploymentException finalInterceptedBeanMethodNotAllowed(Object param1, Object param2); - - @LogMessage(level = Level.WARN) - @Message(id = 1505, value = "Method {0} cannot be intercepted by {1} - will be ignored by interceptors and should never be invoked upon the proxy instance!", format = Format.MESSAGE_FORMAT) - void finalMethodNotIntercepted(Object method, Object interceptor); - - @LogMessage(level = Level.TRACE) - @Message(id = 1506, value = "Created new client proxy of type {0} for bean {1} with ID {2}", format = Format.MESSAGE_FORMAT) - void createdNewClientProxyType(Object param1, Object param2, Object param3); - - @LogMessage(level = Level.TRACE) - @Message(id = 1507, value = "Located client proxy of type {0} for bean {1}", format = Format.MESSAGE_FORMAT) - void lookedUpClientProxy(Object param1, Object param2); - - @Message(id = 1508, value = "Cannot create an InjectionTarget from {0} as it is an interface", format = Format.MESSAGE_FORMAT) - DefinitionException injectionTargetCannotBeCreatedForInterface(Object param1); - - @Message(id = 1510, value = "Non passivation capable bean serialized with ProxyMethodHandler") - WeldException proxyHandlerSerializedForNonSerializableBean(); - - @Message(id = 1511, value = "Specializing bean {0} does not have bean type {1} of specialized bean {2}", format = Format.MESSAGE_FORMAT) - DefinitionException specializingBeanMissingSpecializedType(Object param1, Object param2, Object param3); - - @Message(id = 1512, value = "{0} cannot be constructed for {1}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException invalidInjectionPointType(Object param1, Object param2); - - @Message(id = 1513, value = "An implementation of AnnotatedCallable must implement either AnnotatedConstructor or AnnotatedMethod, {0}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException invalidAnnotatedCallable(Object param1); - - @Message(id = 1514, value = "An implementation of AnnotatedMember must implement either AnnotatedConstructor, AnnotatedMethod or AnnotatedField, {0}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException invalidAnnotatedMember(Object param1); - - @Message(id = 1515, value = "Unable to load annotated member {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException unableToLoadMember(Object param1); - - @Message(id = 1516, value = "Resource producer field [{0}] must not have an EL name", format = Format.MESSAGE_FORMAT) - DefinitionException namedResourceProducerField(Object param1); - - @Message(id = 1517, value = "The type of the resource producer field [{0}] does not match the resource type {1}", format = Format.MESSAGE_FORMAT) - DefinitionException invalidResourceProducerType(Object param1, Object param2); - - @Message(id = 1518, value = "Cannot create Producer implementation. Declaring bean missing for a non-static member {0}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException declaringBeanMissing(Object param1); - - @LogMessage(level = Level.DEBUG) - @Message(id = 1519, value = "An InjectionTarget is created for an abstract {0}. It will not be possible to produce instances of this type!", format = Format.MESSAGE_FORMAT) - void injectionTargetCreatedForAbstractClass(Object param1); - - @Message(id = 1520, value = "Beans with different bean names {0}, {1} cannot be specialized by a single bean {2}", format = Format.MESSAGE_FORMAT) - DefinitionException beansWithDifferentBeanNamesCannotBeSpecialized(Object param1, Object param2, Object param3); - - @Message(id = 1521, value = "InjectionPoint.getAnnotated() must return either AnnotatedParameter or AnnotatedField but {0} was returned for {1}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException invalidAnnotatedOfInjectionPoint(Object param1, Object param2); - - @Message(id = 1522, value = "Unable to restore InjectionPoint. No matching InjectionPoint found on {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException unableToRestoreInjectionPoint(Object param1); - - @Message(id = 1523, value = "Unable to restore InjectionPoint. Multiple matching InjectionPoints found on {0}:\n - {1},\n - {2}", format = Format.MESSAGE_FORMAT) - IllegalStateException unableToRestoreInjectionPointMultiple(Object param1, Object param2, Object param3); - - @Message(id = 1524, value = "Unable to load proxy class for bean {0} with class {1}", format = Format.MESSAGE_FORMAT) - WeldException unableToLoadProxyClass(Object param1, Object param2, @Cause Throwable cause); - - @Message(id = 1525, value = "Instance.destroy() is not supported. The underlying context {0} does not support destroying of contextual instances", format = Format.MESSAGE_FORMAT) - UnsupportedOperationException destroyUnsupported(Object param1); - - @Message(id = 1526, value = "Managed bean declaring a passivating scope has a non-passivation capable decorator. Bean: {0} Decorator: {1}", format = Format.MESSAGE_FORMAT) - DeploymentException passivatingBeanHasNonPassivationCapableDecorator(Object param1, Object param2); - - @Message(id = 1527, value = "Managed bean declaring a passivating scope has a non-serializable interceptor. Bean: {0} Interceptor: {1}", format = Format.MESSAGE_FORMAT) - DeploymentException passivatingBeanHasNonPassivationCapableInterceptor(Object param1, Object param2); - - @LogMessage(level = Level.DEBUG) - @Message(id = 1529, value = "An InjectionTarget is created for a {0} which does not have any appropriate constructor. It will not be possible to produce instances of this type!", format = Format.MESSAGE_FORMAT) - void injectionTargetCreatedForClassWithoutAppropriateConstructor(Object param1); - - @Message(id = 1530, value = "Cannot produce an instance of {0}.", format = Format.MESSAGE_FORMAT) - CreationException injectionTargetCannotProduceInstance(Object param1); - - @Message(id = 1531, value = "Instance.iterator().remove() is not supported.") - UnsupportedOperationException instanceIteratorRemoveUnsupported(); - - @Message(id = 1532, value = "A passivation capable bean cannot have a null id: {0}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException passivationCapableBeanHasNullId(Object param1); - - @LogMessage(level = Level.DEBUG) - @Message(id = 1533, value = "An InjectionTarget is created for a non-static inner {0}. It will not be possible to produce instances of this type!", format = Format.MESSAGE_FORMAT) - void injectionTargetCreatedForNonStaticInnerClass(Object param1); - - @Message(id = 1534, value = "Bean class which has decorators must have a public constructor without parameters: {0}", format = Format.MESSAGE_FORMAT) - DeploymentException decoratedHasNoNoargsConstructor(Object param1); - - @Message(id = 1535, value = "Constructor without parameters cannot be private in bean class which has decorators: {0}\n\tat {1}\n StackTrace:", format = Format.MESSAGE_FORMAT) - DeploymentException decoratedNoargsConstructorIsPrivate(Object param1, Object stackElement); - - /** - * ID of this message was originally 0 but in jboss-logging zero is a special value meaning no ID - * - * @param params - */ - @LogMessage(level = Level.TRACE) - @Message(id = 1536, value = "Found {0} constructors annotated with @Inject for {1}", format = Format.MESSAGE_FORMAT) - void foundInjectableConstructors(Object param1, Object param2); - - // Message version of 1529 - @Message(id = 1537, value = "An InjectionTarget is created for a {0} which does not have any appropriate constructor.", format = Format.MESSAGE_FORMAT) - DefinitionException injectionTargetCreatedForClassWithoutAppropriateConstructorException(Object param1); - - @LogMessage(level = Level.TRACE) - @Message(id = 1538, value = "Created context instance for bean {0} identified as {1}", format = Format.MESSAGE_FORMAT) - void createdContextInstance(Object param1, Object param2); - - @LogMessage(level = Level.TRACE) - @Message(id = 1539, value = "Created MH initializer body for decorator proxy: {0}", format = Format.MESSAGE_FORMAT) - void createdMethodHandlerInitializerForDecoratorProxy(Object param1); - - @LogMessage(level = Level.TRACE) - @Message(id = 1540, value = "Adding method to enterprise proxy: {0}", format = Format.MESSAGE_FORMAT) - void addingMethodToEnterpriseProxy(Object param1); - - @LogMessage(level = Level.TRACE) - @Message(id = 1541, value = "Adding method to proxy: {0}", format = Format.MESSAGE_FORMAT) - void addingMethodToProxy(Object param1); - - @LogMessage(level = Level.TRACE) - @Message(id = 1542, value = "Retrieving/generating proxy class {0}", format = Format.MESSAGE_FORMAT) - void generatingProxyClass(Object param1); - - @LogMessage(level = Level.TRACE) - @Message(id = 1543, value = "Created Proxy class of type {0} supporting interfaces {1}", format = Format.MESSAGE_FORMAT) - void createdProxyClass(Object param1, Object param2); - - @LogMessage(level = Level.TRACE) - @Message(id = 1544, value = "MethodHandler processing returning bean instance for {0}", format = Format.MESSAGE_FORMAT) - void methodHandlerProcessingReturningBeanInstance(Object param1); - - @LogMessage(level = Level.TRACE) - @Message(id = 1545, value = "MethodHandler processing call to {0} for {1}", format = Format.MESSAGE_FORMAT) - void methodHandlerProcessingCall(Object param1, Object param2); - - @LogMessage(level = Level.TRACE) - @Message(id = 1546, value = "Setting new MethodHandler with bean instance for {0} on {1}", format = Format.MESSAGE_FORMAT) - void settingNewMethodHandler(Object param1, Object param2); - - @LogMessage(level = Level.TRACE) - @Message(id = 1547, value = "Invoking interceptor chain for method {0} on {1}", format = Format.MESSAGE_FORMAT) - void invokingInterceptorChain(Object param1, Object param2); - - @LogMessage(level = Level.TRACE) - @Message(id = 1548, value = "Invoking method {0} directly on {1}", format = Format.MESSAGE_FORMAT) - void invokingMethodDirectly(Object param1, Object param2); - - @Message(id = 1549, value = "Unable to determine parent creational context of {0}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException unableToDetermineParentCreationalContext(Object param1); - - @Message(id = 1550, value = "A producer field with a parameterized type with a type variable must be declared @Dependent scoped: \n {0}\n\tat {1}\n StackTrace:", format = Format.MESSAGE_FORMAT) - DefinitionException producerFieldWithTypeVariableBeanTypeMustBeDependent(Object param1, String stackElement); - - @Message(id = 1551, value = "A producer field type may not contain a wildcard: \n {0}\n\tat {1}\n StackTrace:", format = Format.MESSAGE_FORMAT) - DefinitionException producerFieldCannotHaveAWildcardBeanType(Object param1, String stackElement); - - @LogMessage(level = Level.WARN) - @Message(id = 1552, value = "An extension ({0}) has a non-static public field ({1}).", format = Format.MESSAGE_FORMAT) - void extensionWithNonStaticPublicField(Object param1, Object param2); - - @LogMessage(level = Level.TRACE) - @Message(id = 1553, value = "Proxy activated after passivation for {0}", format = Format.MESSAGE_FORMAT) - void activatedSessionBeanProxy(Object param1); - - @Message(id = 1554, value = "Bean.{0}() returned null for {1}", format = Format.MESSAGE_FORMAT) - DefinitionException beanMethodReturnsNull(Object param1, Object param2); - - @Message(id = 1555, value = "Decorator.{0}() returned null for {1}", format = Format.MESSAGE_FORMAT) - DefinitionException decoratorMethodReturnsNull(Object param1, Object param2); - - @Message(id = 1556, value = "Specializing {0} cannot specialize a non-managed bean {1}", format = Format.MESSAGE_FORMAT) - DefinitionException specializingManagedBeanCanExtendOnlyManagedBeans(Object param1, Object param2); - - @LogMessage(level = Level.WARN) - @Message(id = 1557, value = "Unable to dump the proxy class file for {0}", format = Format.MESSAGE_FORMAT) - void beanCannotBeDumped(Object param1, @Cause Throwable cause); - - @LogMessage(level = Level.WARN) - @Message(id = 1558, value = "Unable to create directory {0} to dump the proxy classes.", format = Format.MESSAGE_FORMAT) - void directoryCannotBeCreated(Object param1); - - @Message(id = 1559, value = "Bean builder {0} does not define a create lifecycle callback.", format = Format.MESSAGE_FORMAT) - DefinitionException beanBuilderInvalidCreateCallback(Object param1); - - @Message(id = 1560, value = "Bean builder {0} does not define a destroy lifecycle callback.", format = Format.MESSAGE_FORMAT) - DefinitionException beanBuilderInvalidDestroyCallback(Object param1); - - @Message(id = 1561, value = "Bean builder {0} does not define a BeanManager.", format = Format.MESSAGE_FORMAT) - DefinitionException beanBuilderInvalidBeanManager(Object param1); - - @Message(id = 1562, value = "A producer method return type may not be a type variable or an array type whose component type is a type variable: \n {0}\n\tat {1}\n StackTrace:", format = Format.MESSAGE_FORMAT) - DefinitionException producerMethodReturnTypeInvalidTypeVariable(Object param1, String stackElement); - - @Message(id = 1563, value = "A producer field type may not be a type variable or an array type whose component type is a type variable: \n {0}\n\tat {1}\n StackTrace:", format = Format.MESSAGE_FORMAT) - DefinitionException producerFieldTypeInvalidTypeVariable(Object param1, String stackElement); - - @Message(id = 1564, value = "Injection point metadata injected into a stateless session bean may only be accessed within its business method invocation", format = Format.MESSAGE_FORMAT) - IllegalStateException statelessSessionBeanInjectionPointMetadataNotAvailable(); - - @Message(id = 1565, value = "Interceptor builder {0} does not define an interception function.", format = Format.MESSAGE_FORMAT) - DefinitionException noInterceptionFunction(Object param1); - - @Message(id = 1566, value = "Interceptor builder {0} does not define any InterceptionType.", format = Format.MESSAGE_FORMAT) - DefinitionException noInterceptionType(Object param1); - - @Message(id = 1567, value = "Cannot create contextual instance of {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException cannotCreateContextualInstanceOfBuilderInterceptor(Object param1); - - @Message(id = 1568, value = "Unable to create ClassFile for: {1}.", format = Format.MESSAGE_FORMAT) - IllegalStateException unableToCreateClassFile(Object name, @Cause Throwable cause); - - @Message(id = 1569, value = "Cannot inject injection point metadata in a non @Dependent bean: {0}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException cannotInjectInjectionPointMetadataIntoNonDependent(Object bean); - - @Message(id = 1570, value = "Invalid BeanConfigurator setup - no callback was specified for {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException noCallbackSpecifiedForCustomBean(Object bean); - - @LogMessage(level = Level.INFO) - @Message(id = 1571, value = "Proxy for {0} created in {1} because {2}.", format = Format.MESSAGE_FORMAT) - void generatingProxyToDefaultPackage(Object param1, Object param2, Object param3); - - @Message(id = 1572, value = "Cannot create instance of session bean from Annotated Type {0} before AfterDeploymentValidation phase.", format = Format.MESSAGE_FORMAT) - CreationException initABDnotInvoked(Object bean); - - @Message(id = 1573, value = "Cannot obtain contextual reference for {0} - producing WeldInstance does not exist anymore", format = Format.MESSAGE_FORMAT) - IllegalStateException cannotObtainHandlerContextualReference(Object handler); - - @LogMessage(level = Level.WARN) - @Message(id = 1574, value = "Cannot destroy contextual instance for {0} - producing WeldInstance does not exist anymore", format = Format.MESSAGE_FORMAT) - void cannotDestroyHandlerContextualReference(Object handler); - - @Message(id = 1575, value = "WeldInstance.select(Type subtype, Annotation... qualifiers) can be invoked only on an instance of WeldInstance.", format = Format.MESSAGE_FORMAT) - IllegalStateException selectByTypeOnlyWorksOnObject(); - - @LogMessage(level = Level.DEBUG) - @Message(id = 1576, value = "Using {1} to instantiate a shared proxy class {0}; the deployment implementation [{2}] does not match the instantiator the proxy was created with", format = Format.MESSAGE_FORMAT) - void creatingProxyInstanceUsingDifferentInstantiator(Object proxyClass, Object newInstantiator, Object oldInstantiator); - - @LogMessage(level = Level.INFO) - @Message(id = 1577, value = "Detected private final method: {1}\non an intercepted bean: {0}\nWeld will ignore this method during interception.", format = Format.MESSAGE_FORMAT) - void privateFinalMethodOnInterceptedBean(Object beanClass, Object method); + BeanLogger LOG = + Logger.getMessageLogger(BeanLogger.class, Category.BEAN.getName()); + + @LogMessage(level = Level.TRACE) + @Message(id = 1, + value = "Exactly one constructor ({0}) annotated with @Inject " + + "defined, using it as the bean constructor for {1}", + format = Format.MESSAGE_FORMAT) + void + foundOneInjectableConstructor(Object param1, Object param2); + + @LogMessage(level = Level.TRACE) + @Message(id = 2, + value = "Exactly one constructor ({0}) defined, using it as the " + + "bean constructor for {1}", + format = Format.MESSAGE_FORMAT) + void + foundDefaultConstructor(Object param1, Object param2); + + @LogMessage(level = Level.TRACE) + @Message(id = 4, value = "Exactly one post construct method ({0}) for {1}", + format = Format.MESSAGE_FORMAT) + void + foundOnePostConstructMethod(Object param1, Object param2); + + @LogMessage(level = Level.TRACE) + @Message(id = 6, value = "Exactly one pre destroy method ({0}) for {1}", + format = Format.MESSAGE_FORMAT) + void + foundOnePreDestroyMethod(Object param1, Object param2); + + @LogMessage(level = Level.TRACE) + @Message(id = 7, value = "Created session bean proxy for {0}", + format = Format.MESSAGE_FORMAT) + void + createdSessionBeanProxy(Object param1); + + @LogMessage(level = Level.TRACE) + @Message(id = 8, + value = "Called {0} on {1} with parameters {2} which returned {3}", + format = Format.MESSAGE_FORMAT) + void + callProxiedMethod(Object param1, Object param2, Object param3, Object param4); + + @Message(id = 9, value = "Dynamic lookup of {0} is not supported", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + dynamicLookupOfBuiltInNotAllowed(Object param1); + + @LogMessage(level = Level.TRACE) + @Message(id = 10, value = "Using qualifiers {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + qualifiersUsed(Object param1, Object param2); + + @LogMessage(level = Level.TRACE) + @Message(id = 12, value = "Building bean metadata for {0}", + format = Format.MESSAGE_FORMAT) + void + creatingBean(Object param1); + + @LogMessage(level = Level.TRACE) + @Message(id = 14, value = "Using name {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + usingName(Object param1, Object param2); + + @LogMessage(level = Level.TRACE) + @Message(id = 16, value = "Using scope {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + usingScope(Object param1, Object param2); + + @LogMessage(level = Level.WARN) + @Message(id = 18, + value = "Executing producer field or method {0} on incomplete " + + "declaring bean {1} due to circular injection", + format = Format.MESSAGE_FORMAT) + void + circularCall(Object param1, Object param2); + + @LogMessage(level = Level.ERROR) + @Message(id = 19, value = "Error destroying an instance {0} of {1}", + format = Format.MESSAGE_FORMAT) + void + errorDestroying(Object param1, Object param2); + + @Message(id = 23, value = "Type parameter must be a concrete type: {0}", + format = Format.MESSAGE_FORMAT) + String + typeParameterMustBeConcrete(Object param1); + + @Message(id = 25, + value = "Tried to create an EEResourceProducerField, but no " + + "@Resource, @PersistenceContext, @PersistenceUnit, " + + "@WebServiceRef or @EJB is present: {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + invalidResourceProducerField(Object param1); + + @Message( + id = 26, + value = + "Security Services not available - unable to obtain the Principal") + IllegalStateException + securityServicesNotAvailable(); + + @Message(id = 27, value = "Transaction Services not available - unable to " + + "obtain the UserTransaction") + IllegalStateException + transactionServicesNotAvailable(); + + @Message(id = 28, value = "Interception model must not be null") + IllegalArgumentException interceptionModelNull(); + + @Message(id = 29, value = "InterceptionType must not be null") + IllegalArgumentException interceptionTypeNull(); + + @Message(id = 30, value = "Method must not be null") + IllegalArgumentException methodNull(); + + @Message(id = 31, + value = "InterceptionType must not be lifecycle, but it is {0}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + interceptionTypeLifecycle(Object param1); + + @Message(id = 32, value = "InterceptionType must be lifecycle, but it is {0}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + interceptionTypeNotLifecycle(Object param1); + + @Message(id = 33, value = "Could not instantiate client proxy for {0}", + format = Format.MESSAGE_FORMAT) + String + proxyInstantiationFailed(Object param1); + + @Message( + id = 34, + value = + "Could not access bean correctly when creating client proxy for {0}", + format = Format.MESSAGE_FORMAT) + String + proxyInstantiationBeanAccessFailed(Object param1); + + @Message(id = 35, value = "There was an error creating an id for {0}", + format = Format.MESSAGE_FORMAT) + DefinitionException + beanIdCreationFailed(Object param1); + + @Message(id = 36, + value = "Unexpected unwrapped custom decorator instance: {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + unexpectedUnwrappedCustomDecorator(Object param1); + + @Message(id = 37, + value = "Cannot call EJB remove method directly on non-dependent " + + "scoped bean {0}", + format = Format.MESSAGE_FORMAT) + UnsupportedOperationException + invalidRemoveMethodInvocation(Object param1); + + @Message(id = 38, + value = "A bean class that is not a decorator has an injection " + + "point annotated @Delegate\n at injection point " + + "{0}\n\tat {1}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + DefinitionException + delegateNotOnDecorator(Object ip, Object stackElement); + + @Message( + id = 39, + value = + "@Typed class {0} not present in the set of bean types of {1} [{2}]", + format = Format.MESSAGE_FORMAT) + DefinitionException + typedClassNotInHierarchy(Object param1, Object param2, Object types); + + @SuppressWarnings({"weldlog:method-sig", "weldlog:msg-value"}) + @Message(id = 40, + value = "All stereotypes must specify the same scope or the bean " + + "must declare a scope - declared on {0}, declared " + + "stereotypes [{1}], possible scopes {2}{3}", + format = Format.MESSAGE_FORMAT) + DefinitionException + multipleScopesFoundFromStereotypes(Object declaredOn, Object stereotypes, + Object possibleScopes, String stack); + + @Message( + id = 41, + value = "Specializing bean may not declare a bean name if it is declared " + + "by specialized bean\n specializing: {0}\n specialized: {1}", + format = Format.MESSAGE_FORMAT) + DefinitionException + nameNotAllowedOnSpecialization(Object specializing, Object specialized); + + @Message(id = 42, + value = "Cannot operate on non container provided decorator {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + nonContainerDecorator(Object param1); + + @Message(id = 43, + value = "The following bean is not an EE resource producer: {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + beanNotEeResourceProducer(Object param1); + + @Message(id = 44, value = "Unable to obtain instance from {0}", + format = Format.MESSAGE_FORMAT) + NullInstanceException + nullInstance(Object param1); + + @Message( + id = 45, + value = "Unable to deserialize object - serialization proxy is required") + InvalidObjectException + serializationProxyRequired(); + + @Message(id = 46, value = "At most one scope may be specified on {0}", + format = Format.MESSAGE_FORMAT) + DefinitionException + onlyOneScopeAllowed(Object param1); + + @Message(id = 47, value = "Specializing bean must extend another bean: {0}", + format = Format.MESSAGE_FORMAT) + DefinitionException + specializingBeanMustExtendABean(Object param1); + + @Message(id = 48, value = "Conflicting interceptor bindings found on {0}", + format = Format.MESSAGE_FORMAT) + String + conflictingInterceptorBindings(Object param1); + + @Message(id = 49, value = "Unable to invoke {0} on {1}", + format = Format.MESSAGE_FORMAT) + WeldException + invocationError(Object param1, Object param2, @Cause Throwable cause); + + @Message(id = 50, value = "Cannot cast producer type {0} to bean type {1}", + format = Format.MESSAGE_FORMAT) + WeldException + producerCastError(Object param1, Object param2, @Cause Throwable cause); + + @Message(id = 52, + value = "Cannot return null from a non-dependent producer method: " + + "{0}\n\tat {1}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + IllegalProductException + nullNotAllowedFromProducer(Object param1, Object stackElement); + + @Message(id = 53, + value = "Producers cannot declare passivating scope and return a " + + "non-serializable class: {0}\n\tat {1}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + IllegalProductException + nonSerializableProductError(Object param1, Object stackElement); + + @Message(id = 54, + value = "Producers cannot produce unserializable instances for " + + "injection into an injection point that requires a " + + "passivation capable dependency\n Producer: {0}\n\tat " + + "{1}\n Injection Point: {2}\n\tat {3}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + IllegalProductException + unserializableProductInjectionError(Object producer, + Object producerStackElement, Object ip, + Object ipStackElement); + + @Message(id = 59, value = "No delegate injection point defined for {0}", + format = Format.MESSAGE_FORMAT) + DefinitionException + noDelegateInjectionPoint(Object param1); + + @Message(id = 60, + value = "Too many delegate injection points defined for {0}", + format = Format.MESSAGE_FORMAT) + DefinitionException + tooManyDelegateInjectionPoints(Object param1); + + @Message(id = 61, + value = "The delegate type does not extend or implement the " + + + "decorated type. \n Decorated type: {0}\n Decorator: {1}", + format = Format.MESSAGE_FORMAT) + DefinitionException + delegateMustSupportEveryDecoratedType(Object decoratedType, Object decorator); + + @Message(id = 64, value = "Unable to process decorated type: {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + unableToProcessDecoratedType(Object decoratedType); + + @Message( + id = 66, + value = + "{0} has more than one @Dispose parameter \n\tat {1}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + DefinitionException + multipleDisposeParams(Object param1, Object stackElement); + + @Message(id = 67, + value = "{0} is not allowed on same method as {1}, see {2}\n\tat " + + "{3}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + DefinitionException + inconsistentAnnotationsOnMethod(Object param1, Object param2, Object param3, + Object stackElement); + + @Message(id = 68, + value = "{0} method {1} is not a business method of {2}\n\tat " + + "{3}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + DefinitionException + methodNotBusinessMethod(Object methodType, Object param1, Object param2, + Object stackElement); + + @Message(id = 70, + value = "Simple bean {0} cannot be a non-static inner class", + format = Format.MESSAGE_FORMAT) + DefinitionException + simpleBeanAsNonStaticInnerClassNotAllowed(Object param1); + + @Message(id = 71, + value = "Managed bean with a parameterized bean class must be " + + "@Dependent: {0}", + format = Format.MESSAGE_FORMAT) + DefinitionException + managedBeanWithParameterizedBeanClassMustBeDependent(Object param1); + + @Message(id = 72, + value = "Bean declaring a passivating scope must be passivation " + + "capable. Bean: {0}", + format = Format.MESSAGE_FORMAT) + DeploymentException + passivatingBeanNeedsSerializableImpl(Object param1); + + @Message( + id = 73, + value = "Bean class which has decorators cannot be declared final: {0}", + format = Format.MESSAGE_FORMAT) + DeploymentException + finalBeanClassWithDecoratorsNotAllowed(Object param1); + + @Message(id = 75, + value = "Normal scoped managed bean implementation class has a " + + "public field: {0}", + format = Format.MESSAGE_FORMAT) + DefinitionException + publicFieldOnNormalScopedBeanNotAllowed(Object param1); + + @Message(id = 76, + value = "Bean constructor must not have a parameter annotated " + + "with {0}: {1}\n\tat {2}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + DefinitionException + parameterAnnotationNotAllowedOnConstructor(Object param1, Object param2, + Object stackElement); + + @Message(id = 77, + value = "Cannot declare multiple disposal methods for this producer " + + "method.\n\nProducer method: {0}\nDisposal methods: {1}", + format = Format.MESSAGE_FORMAT) + DefinitionException + multipleDisposalMethods(Object param1, Object param2); + + @Message(id = 78, + value = "Specialized producer method does not override another " + + "producer method: {0}\n\tat {1}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + DefinitionException + producerMethodNotSpecializing(Object param1, Object stackElement); + + @Message(id = 79, + value = "Could not instantiate a proxy for a session bean: {0}\n " + + " Proxy: {1}", + format = Format.MESSAGE_FORMAT) + CreationException + sessionBeanProxyInstantiationFailed(Object sessionBean, Object proxyClass, + @Cause Throwable cause); + + @Message(id = 80, value = "Enterprise beans cannot be interceptors: {0}", + format = Format.MESSAGE_FORMAT) + DefinitionException + ejbCannotBeInterceptor(Object param1); + + @Message(id = 81, value = "Enterprise beans cannot be decorators: {0}", + format = Format.MESSAGE_FORMAT) + DefinitionException + ejbCannotBeDecorator(Object param1); + + @Message(id = 82, + value = "Scope {0} is not allowed on stateless session beans for " + + "{1}. Only @Dependent is allowed.", + format = Format.MESSAGE_FORMAT) + DefinitionException + scopeNotAllowedOnStatelessSessionBean(Object param1, Object param2); + + @Message(id = 83, + value = "Scope {0} is not allowed on singleton session beans for " + + "{1}. Only @Dependent and @ApplicationScoped is allowed.", + format = Format.MESSAGE_FORMAT) + DefinitionException + scopeNotAllowedOnSingletonBean(Object param1, Object param2); + + @Message(id = 84, + value = "Specializing enterprise bean must extend another " + + "enterprise bean: {0}", + format = Format.MESSAGE_FORMAT) + DefinitionException + specializingEnterpriseBeanMustExtendAnEnterpriseBean(Object param1); + + @Message(id = 85, value = "Cannot destroy null instance of {0}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + cannotDestroyNullBean(Object param1); + + @Message(id = 86, + value = "Cannot destroy session bean instance not created by the " + + "container: {0}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + cannotDestroyEnterpriseBeanNotCreated(Object param1); + + @Message(id = 87, + value = "Message driven beans cannot be Managed Beans: {0}", + format = Format.MESSAGE_FORMAT) + DefinitionException + messageDrivenBeansCannotBeManaged(Object param1); + + @Message(id = 88, + value = "Observer method must be static or local business method: " + + " {0}\n\tat {1}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + DefinitionException + observerMethodMustBeStaticOrBusiness(Object param1, Object stackElement); + + @Message(id = 89, + value = "Unable to determine EJB for {0}, multiple EJBs with that " + + "class: {1}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + tooManyEjbsForClass(Object param1, Object param2); + + @Message(id = 90, + value = "A decorator has an abstract method that is not declared by " + + + "any decorated type\n Method: {0}\n\tat {1}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + DefinitionException + abstractMethodMustMatchDecoratedType(Object param1, Object param2); + + @Message(id = 94, + value = "Injected field {0} cannot be annotated @Produces on {1}", + format = Format.MESSAGE_FORMAT) + DefinitionException + injectedFieldCannotBeProducer(Object param1, Object param2); + + @Message( + id = 95, + value = "Session bean with generic class {0} must be @Dependent scope", + format = Format.MESSAGE_FORMAT) + DefinitionException + genericSessionBeanMustBeDependent(Object param1); + + @Message(id = 96, + value = "Producer fields on session beans must be static. Field " + + "{0} declared on {1}", + format = Format.MESSAGE_FORMAT) + DefinitionException + producerFieldOnSessionBeanMustBeStatic(Object param1, Object param2); + + @Message(id = 97, + value = "A producer method with a parameterized return type with " + + "a type variable must be declared @Dependent scoped: \n " + + "{0}\n\tat {1}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + DefinitionException + producerMethodWithTypeVariableReturnTypeMustBeDependent(Object param1, + String stackElement); + + @Message(id = 98, + value = "A producer method return type may not contain a " + + "wildcard: \n {0}\n\tat {1}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + DefinitionException + producerMethodCannotHaveAWildcardReturnType(Object param1, + String stackElement); + + @Message(id = 99, + value = "Cannot load class {0} during deserialization of proxy", + format = Format.MESSAGE_FORMAT) + WeldException + cannotLoadClass(Object param1, @Cause Throwable cause); + + @Message(id = 1500, + value = "Failed to deserialize proxy object with beanId {0}", + format = Format.MESSAGE_FORMAT) + WeldException + proxyDeserializationFailure(Object param1); + + @Message(id = 1501, + value = "Method call requires a BeanInstance which has not been " + + "set for this proxy {0}", + format = Format.MESSAGE_FORMAT) + WeldException + beanInstanceNotSetOnProxy(Object param1); + + @Message(id = 1502, + value = "Resource producer field [{0}] must be @Dependent scoped", + format = Format.MESSAGE_FORMAT) + DefinitionException + nonDependentResourceProducerField(Object param1); + + @Message( + id = 1503, + value = + "Bean class which has interceptors cannot be declared final: {0}", + format = Format.MESSAGE_FORMAT) + DeploymentException + finalBeanClassWithInterceptorsNotAllowed(Object param1); + + @Message(id = 1504, + value = "Intercepted bean method {0} (intercepted by {1}) cannot " + + "be declared final", + format = Format.MESSAGE_FORMAT) + DeploymentException + finalInterceptedBeanMethodNotAllowed(Object param1, Object param2); + + @LogMessage(level = Level.WARN) + @Message( + id = 1505, + value = + "Method {0} cannot be intercepted by {1} - will be ignored by " + + "interceptors and should never be invoked upon the proxy instance!", + format = Format.MESSAGE_FORMAT) + void + finalMethodNotIntercepted(Object method, Object interceptor); + + @LogMessage(level = Level.TRACE) + @Message( + id = 1506, + value = "Created new client proxy of type {0} for bean {1} with ID {2}", + format = Format.MESSAGE_FORMAT) + void + createdNewClientProxyType(Object param1, Object param2, Object param3); + + @LogMessage(level = Level.TRACE) + @Message(id = 1507, value = "Located client proxy of type {0} for bean {1}", + format = Format.MESSAGE_FORMAT) + void + lookedUpClientProxy(Object param1, Object param2); + + @Message( + id = 1508, + value = "Cannot create an InjectionTarget from {0} as it is an interface", + format = Format.MESSAGE_FORMAT) + DefinitionException + injectionTargetCannotBeCreatedForInterface(Object param1); + + @Message( + id = 1510, + value = "Non passivation capable bean serialized with ProxyMethodHandler") + WeldException + proxyHandlerSerializedForNonSerializableBean(); + + @Message(id = 1511, + value = "Specializing bean {0} does not have bean type {1} of " + + "specialized bean {2}", + format = Format.MESSAGE_FORMAT) + DefinitionException + specializingBeanMissingSpecializedType(Object param1, Object param2, + Object param3); + + @Message(id = 1512, value = "{0} cannot be constructed for {1}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + invalidInjectionPointType(Object param1, Object param2); + + @Message(id = 1513, + value = "An implementation of AnnotatedCallable must implement " + + "either AnnotatedConstructor or AnnotatedMethod, {0}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + invalidAnnotatedCallable(Object param1); + + @Message( + id = 1514, + value = "An implementation of AnnotatedMember must implement either " + + "AnnotatedConstructor, AnnotatedMethod or AnnotatedField, {0}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + invalidAnnotatedMember(Object param1); + + @Message(id = 1515, value = "Unable to load annotated member {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + unableToLoadMember(Object param1); + + @Message(id = 1516, + value = "Resource producer field [{0}] must not have an EL name", + format = Format.MESSAGE_FORMAT) + DefinitionException + namedResourceProducerField(Object param1); + + @Message(id = 1517, + value = "The type of the resource producer field [{0}] does not " + + "match the resource type {1}", + format = Format.MESSAGE_FORMAT) + DefinitionException + invalidResourceProducerType(Object param1, Object param2); + + @Message(id = 1518, + value = "Cannot create Producer implementation. Declaring bean " + + "missing for a non-static member {0}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + declaringBeanMissing(Object param1); + + @LogMessage(level = Level.DEBUG) + @Message(id = 1519, + value = "An InjectionTarget is created for an abstract {0}. It " + + "will not be possible to produce instances of this type!", + format = Format.MESSAGE_FORMAT) + void + injectionTargetCreatedForAbstractClass(Object param1); + + @Message(id = 1520, + value = "Beans with different bean names {0}, {1} cannot be " + + "specialized by a single bean {2}", + format = Format.MESSAGE_FORMAT) + DefinitionException + beansWithDifferentBeanNamesCannotBeSpecialized(Object param1, Object param2, + Object param3); + + @Message( + id = 1521, + value = + "InjectionPoint.getAnnotated() must return either " + + "AnnotatedParameter or AnnotatedField but {0} was returned for {1}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + invalidAnnotatedOfInjectionPoint(Object param1, Object param2); + + @Message(id = 1522, + value = "Unable to restore InjectionPoint. No matching " + + "InjectionPoint found on {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + unableToRestoreInjectionPoint(Object param1); + + @Message(id = 1523, + value = "Unable to restore InjectionPoint. Multiple matching " + + "InjectionPoints found on {0}:\n - {1},\n - {2}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + unableToRestoreInjectionPointMultiple(Object param1, Object param2, + Object param3); + + @Message(id = 1524, + value = "Unable to load proxy class for bean {0} with class {1}", + format = Format.MESSAGE_FORMAT) + WeldException + unableToLoadProxyClass(Object param1, Object param2, @Cause Throwable cause); + + @Message( + id = 1525, + value = "Instance.destroy() is not supported. The underlying context " + + "{0} does not support destroying of contextual instances", + format = Format.MESSAGE_FORMAT) + UnsupportedOperationException + destroyUnsupported(Object param1); + + @Message( + id = 1526, + value = "Managed bean declaring a passivating scope has a " + + + "non-passivation capable decorator. Bean: {0} Decorator: {1}", + format = Format.MESSAGE_FORMAT) + DeploymentException + passivatingBeanHasNonPassivationCapableDecorator(Object param1, + Object param2); + + @Message( + id = 1527, + value = "Managed bean declaring a passivating scope has a " + + "non-serializable interceptor. Bean: {0} Interceptor: {1}", + format = Format.MESSAGE_FORMAT) + DeploymentException + passivatingBeanHasNonPassivationCapableInterceptor(Object param1, + Object param2); + + @LogMessage(level = Level.DEBUG) + @Message(id = 1529, + value = "An InjectionTarget is created for a {0} which does not " + + "have any appropriate constructor. It will not be " + + "possible to produce instances of this type!", + format = Format.MESSAGE_FORMAT) + void + injectionTargetCreatedForClassWithoutAppropriateConstructor(Object param1); + + @Message(id = 1530, value = "Cannot produce an instance of {0}.", + format = Format.MESSAGE_FORMAT) + CreationException + injectionTargetCannotProduceInstance(Object param1); + + @Message(id = 1531, value = "Instance.iterator().remove() is not supported.") + UnsupportedOperationException instanceIteratorRemoveUnsupported(); + + @Message(id = 1532, + value = "A passivation capable bean cannot have a null id: {0}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + passivationCapableBeanHasNullId(Object param1); + + @LogMessage(level = Level.DEBUG) + @Message( + id = 1533, + value = "An InjectionTarget is created for a non-static inner {0}. It " + + "will not be possible to produce instances of this type!", + format = Format.MESSAGE_FORMAT) + void + injectionTargetCreatedForNonStaticInnerClass(Object param1); + + @Message(id = 1534, + value = "Bean class which has decorators must have a public " + + "constructor without parameters: {0}", + format = Format.MESSAGE_FORMAT) + DeploymentException + decoratedHasNoNoargsConstructor(Object param1); + + @Message(id = 1535, + value = "Constructor without parameters cannot be private in bean " + + "class which has decorators: {0}\n\tat {1}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + DeploymentException + decoratedNoargsConstructorIsPrivate(Object param1, Object stackElement); + + /** + * ID of this message was originally 0 but in jboss-logging zero is a special + * value meaning no ID + */ + @LogMessage(level = Level.TRACE) + @Message(id = 1536, + value = "Found {0} constructors annotated with @Inject for {1}", + format = Format.MESSAGE_FORMAT) + void + foundInjectableConstructors(Object param1, Object param2); + + // Message version of 1529 + @Message(id = 1537, + value = "An InjectionTarget is created for a {0} which does not " + + "have any appropriate constructor.", + format = Format.MESSAGE_FORMAT) + DefinitionException + injectionTargetCreatedForClassWithoutAppropriateConstructorException( + Object param1); + + @LogMessage(level = Level.TRACE) + @Message(id = 1538, + value = "Created context instance for bean {0} identified as {1}", + format = Format.MESSAGE_FORMAT) + void + createdContextInstance(Object param1, Object param2); + + @LogMessage(level = Level.TRACE) + @Message(id = 1539, + value = "Created MH initializer body for decorator proxy: {0}", + format = Format.MESSAGE_FORMAT) + void + createdMethodHandlerInitializerForDecoratorProxy(Object param1); + + @LogMessage(level = Level.TRACE) + @Message(id = 1540, value = "Adding method to enterprise proxy: {0}", + format = Format.MESSAGE_FORMAT) + void + addingMethodToEnterpriseProxy(Object param1); + + @LogMessage(level = Level.TRACE) + @Message(id = 1541, value = "Adding method to proxy: {0}", + format = Format.MESSAGE_FORMAT) + void + addingMethodToProxy(Object param1); + + @LogMessage(level = Level.TRACE) + @Message(id = 1542, value = "Retrieving/generating proxy class {0}", + format = Format.MESSAGE_FORMAT) + void + generatingProxyClass(Object param1); + + @LogMessage(level = Level.TRACE) + @Message(id = 1543, + value = "Created Proxy class of type {0} supporting interfaces {1}", + format = Format.MESSAGE_FORMAT) + void + createdProxyClass(Object param1, Object param2); + + @LogMessage(level = Level.TRACE) + @Message(id = 1544, + value = "MethodHandler processing returning bean instance for {0}", + format = Format.MESSAGE_FORMAT) + void + methodHandlerProcessingReturningBeanInstance(Object param1); + + @LogMessage(level = Level.TRACE) + @Message(id = 1545, value = "MethodHandler processing call to {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + methodHandlerProcessingCall(Object param1, Object param2); + + @LogMessage(level = Level.TRACE) + @Message( + id = 1546, + value = "Setting new MethodHandler with bean instance for {0} on {1}", + format = Format.MESSAGE_FORMAT) + void + settingNewMethodHandler(Object param1, Object param2); + + @LogMessage(level = Level.TRACE) + @Message(id = 1547, + value = "Invoking interceptor chain for method {0} on {1}", + format = Format.MESSAGE_FORMAT) + void + invokingInterceptorChain(Object param1, Object param2); + + @LogMessage(level = Level.TRACE) + @Message(id = 1548, value = "Invoking method {0} directly on {1}", + format = Format.MESSAGE_FORMAT) + void + invokingMethodDirectly(Object param1, Object param2); + + @Message(id = 1549, + value = "Unable to determine parent creational context of {0}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + unableToDetermineParentCreationalContext(Object param1); + + @Message(id = 1550, + value = "A producer field with a parameterized type with a type " + + "variable must be declared @Dependent scoped: \n " + + "{0}\n\tat {1}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + DefinitionException + producerFieldWithTypeVariableBeanTypeMustBeDependent(Object param1, + String stackElement); + + @Message(id = 1551, + value = "A producer field type may not contain a wildcard: \n " + + "{0}\n\tat {1}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + DefinitionException + producerFieldCannotHaveAWildcardBeanType(Object param1, String stackElement); + + @LogMessage(level = Level.WARN) + @Message(id = 1552, + value = "An extension ({0}) has a non-static public field ({1}).", + format = Format.MESSAGE_FORMAT) + void + extensionWithNonStaticPublicField(Object param1, Object param2); + + @LogMessage(level = Level.TRACE) + @Message(id = 1553, value = "Proxy activated after passivation for {0}", + format = Format.MESSAGE_FORMAT) + void + activatedSessionBeanProxy(Object param1); + + @Message(id = 1554, value = "Bean.{0}() returned null for {1}", + format = Format.MESSAGE_FORMAT) + DefinitionException + beanMethodReturnsNull(Object param1, Object param2); + + @Message(id = 1555, value = "Decorator.{0}() returned null for {1}", + format = Format.MESSAGE_FORMAT) + DefinitionException + decoratorMethodReturnsNull(Object param1, Object param2); + + @Message(id = 1556, + value = "Specializing {0} cannot specialize a non-managed bean {1}", + format = Format.MESSAGE_FORMAT) + DefinitionException + specializingManagedBeanCanExtendOnlyManagedBeans(Object param1, + Object param2); + + @LogMessage(level = Level.WARN) + @Message(id = 1557, value = "Unable to dump the proxy class file for {0}", + format = Format.MESSAGE_FORMAT) + void + beanCannotBeDumped(Object param1, @Cause Throwable cause); + + @LogMessage(level = Level.WARN) + @Message(id = 1558, + value = "Unable to create directory {0} to dump the proxy classes.", + format = Format.MESSAGE_FORMAT) + void + directoryCannotBeCreated(Object param1); + + @Message( + id = 1559, + value = "Bean builder {0} does not define a create lifecycle callback.", + format = Format.MESSAGE_FORMAT) + DefinitionException + beanBuilderInvalidCreateCallback(Object param1); + + @Message( + id = 1560, + value = "Bean builder {0} does not define a destroy lifecycle callback.", + format = Format.MESSAGE_FORMAT) + DefinitionException + beanBuilderInvalidDestroyCallback(Object param1); + + @Message(id = 1561, value = "Bean builder {0} does not define a BeanManager.", + format = Format.MESSAGE_FORMAT) + DefinitionException + beanBuilderInvalidBeanManager(Object param1); + + @Message(id = 1562, + value = "A producer method return type may not be a type variable " + + "or an array type whose component type is a type " + + "variable: \n {0}\n\tat {1}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + DefinitionException + producerMethodReturnTypeInvalidTypeVariable(Object param1, + String stackElement); + + @Message(id = 1563, + value = "A producer field type may not be a type variable or an " + + "array type whose component type is a type variable: \n " + + "{0}\n\tat {1}\n StackTrace:", + format = Format.MESSAGE_FORMAT) + DefinitionException + producerFieldTypeInvalidTypeVariable(Object param1, String stackElement); + + @Message( + id = 1564, + value = "Injection point metadata injected into a stateless session " + + + "bean may only be accessed within its business method invocation", + format = Format.MESSAGE_FORMAT) + IllegalStateException + statelessSessionBeanInjectionPointMetadataNotAvailable(); + + @Message( + id = 1565, + value = + "Interceptor builder {0} does not define an interception function.", + format = Format.MESSAGE_FORMAT) + DefinitionException + noInterceptionFunction(Object param1); + + @Message( + id = 1566, + value = "Interceptor builder {0} does not define any InterceptionType.", + format = Format.MESSAGE_FORMAT) + DefinitionException + noInterceptionType(Object param1); + + @Message(id = 1567, value = "Cannot create contextual instance of {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + cannotCreateContextualInstanceOfBuilderInterceptor(Object param1); + + @Message(id = 1568, value = "Unable to create ClassFile for: {1}.", + format = Format.MESSAGE_FORMAT) + IllegalStateException + unableToCreateClassFile(Object name, @Cause Throwable cause); + + @Message(id = 1569, + value = "Cannot inject injection point metadata in a non " + + "@Dependent bean: {0}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + cannotInjectInjectionPointMetadataIntoNonDependent(Object bean); + + @Message( + id = 1570, + value = + "Invalid BeanConfigurator setup - no callback was specified for {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + noCallbackSpecifiedForCustomBean(Object bean); + + @LogMessage(level = Level.INFO) + @Message(id = 1571, value = "Proxy for {0} created in {1} because {2}.", + format = Format.MESSAGE_FORMAT) + void + generatingProxyToDefaultPackage(Object param1, Object param2, Object param3); + + @Message(id = 1572, + value = "Cannot create instance of session bean from Annotated " + + "Type {0} before AfterDeploymentValidation phase.", + format = Format.MESSAGE_FORMAT) + CreationException + initABDnotInvoked(Object bean); + + @Message(id = 1573, + value = "Cannot obtain contextual reference for {0} - producing " + + "WeldInstance does not exist anymore", + format = Format.MESSAGE_FORMAT) + IllegalStateException + cannotObtainHandlerContextualReference(Object handler); + + @LogMessage(level = Level.WARN) + @Message(id = 1574, + value = "Cannot destroy contextual instance for {0} - producing " + + "WeldInstance does not exist anymore", + format = Format.MESSAGE_FORMAT) + void + cannotDestroyHandlerContextualReference(Object handler); + + @Message( + id = 1575, + value = "WeldInstance.select(Type subtype, Annotation... qualifiers) " + + "can be invoked only on an instance of WeldInstance.", + format = Format.MESSAGE_FORMAT) + IllegalStateException + selectByTypeOnlyWorksOnObject(); + + @LogMessage(level = Level.DEBUG) + @Message(id = 1576, + value = "Using {1} to instantiate a shared proxy class {0}; the " + + "deployment implementation [{2}] does not match the " + + "instantiator the proxy was created with", + format = Format.MESSAGE_FORMAT) + void + creatingProxyInstanceUsingDifferentInstantiator(Object proxyClass, + Object newInstantiator, + Object oldInstantiator); + + @LogMessage(level = Level.INFO) + @Message( + id = 1577, + value = "Detected private final method: {1}\non an intercepted bean: " + + "{0}\nWeld will ignore this method during interception.", + format = Format.MESSAGE_FORMAT) + void + privateFinalMethodOnInterceptedBean(Object beanClass, Object method); + + @Message(id = 1578, + value = "WeldDefaultProxyServices failed to load/define a class " + + "with name {0} whose original class was {1} because all " + + "attempts to determine a class loader ended with null.", + format = Format.MESSAGE_FORMAT) + IllegalStateException + cannotDetermineClassLoader(Object beanName, Object originalClass); + + @Message( + id = 1579, + value = "An instance of ProxyFactory.ProxyNameHolder has to contain a " + + "class name. This instance was created for bean class: {1}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + tryingToCreateProxyNameHolderWithoutClassName(Object bean); + + @Message(id = 1580, + value = "Cannot obtain contextual reference for {0} - a " + + + "previously obtained reference has already been destroyed.", + format = Format.MESSAGE_FORMAT) + IllegalStateException + tryingToResolveContextualReferenceAfterDestroyWasInvoked(Object handler); } diff --git a/impl/src/main/java/org/jboss/weld/logging/BootstrapLogger.java b/impl/src/main/java/org/jboss/weld/logging/BootstrapLogger.java index 6fb799eb16..b9a41802c3 100644 --- a/impl/src/main/java/org/jboss/weld/logging/BootstrapLogger.java +++ b/impl/src/main/java/org/jboss/weld/logging/BootstrapLogger.java @@ -19,7 +19,6 @@ import static org.jboss.weld.logging.WeldLogger.WELD_PROJECT_CODE; import javax.enterprise.inject.spi.ObserverMethod; - import org.jboss.logging.Logger; import org.jboss.logging.Logger.Level; import org.jboss.logging.annotations.Cause; @@ -41,301 +40,554 @@ @MessageLogger(projectCode = WELD_PROJECT_CODE) public interface BootstrapLogger extends WeldLogger { - BootstrapLogger LOG = Logger.getMessageLogger(BootstrapLogger.class, Category.BOOTSTRAP.getName()); - - BootstrapLogger TRACKER_LOG = Logger.getMessageLogger(BootstrapLogger.class, Category.BOOTSTRAP_TRACKER.getName()); - - @LogMessage(level = Level.DEBUG) - @Message(id = 100, value = "Weld initialized. Validating beans") - void validatingBeans(); - - @LogMessage(level = Level.INFO) - @Message(id = 101, value = "Transactional services not available. Injection of @Inject UserTransaction not available. Transactional observers will be invoked synchronously.") - void jtaUnavailable(); - - @LogMessage(level = Level.DEBUG) - @Message(id = 103, value = "Enabled alternatives for {0}: {1}", format = Format.MESSAGE_FORMAT) - void enabledAlternatives(Object param1, Object param2); - - @LogMessage(level = Level.DEBUG) - @Message(id = 104, value = "Enabled decorator types for {0}: {1}", format = Format.MESSAGE_FORMAT) - void enabledDecorators(Object param1, Object param2); - - @LogMessage(level = Level.DEBUG) - @Message(id = 105, value = "Enabled interceptor types for {0}: {1}", format = Format.MESSAGE_FORMAT) - void enabledInterceptors(Object param1, Object param2); - - @LogMessage(level = Level.DEBUG) - @Message(id = 106, value = "Bean: {0}", format = Format.MESSAGE_FORMAT) - void foundBean(Object param1); - - @LogMessage(level = Level.DEBUG) - @Message(id = 107, value = "Interceptor: {0}", format = Format.MESSAGE_FORMAT) - void foundInterceptor(Object param1); - - @LogMessage(level = Level.DEBUG) - @Message(id = 108, value = "Decorator: {0}", format = Format.MESSAGE_FORMAT) - void foundDecorator(Object param1); - - @LogMessage(level = Level.DEBUG) - @Message(id = 109, value = "ObserverMethod: {0}", format = Format.MESSAGE_FORMAT) - void foundObserverMethod(Object param1); - - @Message(id = 110, value = "Cannot set the annotation type to null (if you want to stop the type being used, call veto()): {0}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException annotationTypeNull(Object param1); - - @Message(id = 111, value = "Bean type is not STATELESS, STATEFUL or SINGLETON: {0}", format = Format.MESSAGE_FORMAT) - IllegalStateException beanTypeNotEjb(Object param1); - - @Message(id = 112, value = "Class {0} has both @Interceptor and @Decorator annotations", format = Format.MESSAGE_FORMAT) - DefinitionException beanIsBothInterceptorAndDecorator(Object param1); - - @Message(id = 113, value = "BeanDeploymentArchive must not be null: {0}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException deploymentArchiveNull(Object param1); - - @Message(id = 114, value = "Must start the container with a deployment") - IllegalArgumentException deploymentRequired(); - - @Message(id = 116, value = "Manager has not been initialized") - IllegalStateException managerNotInitialized(); - - @Message(id = 117, value = "Required service {0} has not been specified for {1}", format = Format.MESSAGE_FORMAT) - IllegalStateException unspecifiedRequiredService(Object service, Object target); - - @Message(id = 118, value = "Only normal scopes can be passivating. Scope {0}", format = Format.MESSAGE_FORMAT) - DefinitionException passivatingNonNormalScopeIllegal(Object param1); - - @LogMessage(level = Level.INFO) - @Message(id = 119, value = "Not generating any bean definitions from {0} because of underlying class loading error: Type {1} not found. If this is unexpected, enable DEBUG logging to see the full error.", format = Format.MESSAGE_FORMAT) - void ignoringClassDueToLoadingError(Object param1, Object param2); - - @Message(id = 123, value = "Error loading {0} defined in {1}", format = Format.MESSAGE_FORMAT) - DeploymentException errorLoadingBeansXmlEntry(Object param1, Object param2, @Cause Throwable cause); - - @LogMessage(level = Level.DEBUG) - @Message(id = 124, value = "Using {0} threads for bootstrap", format = Format.MESSAGE_FORMAT) - void threadsInUse(Object param1); - - @Message(id = 125, value = "Invalid thread pool size: {0}", format = Format.MESSAGE_FORMAT) - DeploymentException invalidThreadPoolSize(Object param1); - - @LogMessage(level = Level.WARN) - @Message(id = 126, value = "Timeout shutting down thread pool {0} at {1}", format = Format.MESSAGE_FORMAT) - void timeoutShuttingDownThreadPool(Object param1, Object param2); - - @Message(id = 127, value = "Invalid thread pool type: {0}", format = Format.MESSAGE_FORMAT) - DeploymentException invalidThreadPoolType(Object param1); - - @Message(id = 128, value = "Invalid value for property {0}: {1}", format = Format.MESSAGE_FORMAT) - DeploymentException invalidPropertyValue(Object param1, Object param2); - - @Message(id = 130, value = "Cannot replace AnnotatedType for {0} with AnnotatedType for {1}", format = Format.MESSAGE_FORMAT) - IllegalArgumentException annotatedTypeJavaClassMismatch(Object param1, Object param2); - - @LogMessage(level = Level.DEBUG) - @Message(id = 132, value = "Disabled alternative (ignored): {0}", format = Format.MESSAGE_FORMAT) - void foundDisabledAlternative(Object param1); - - @LogMessage(level = Level.DEBUG) - @Message(id = 133, value = "Specialized bean (ignored): {0}", format = Format.MESSAGE_FORMAT) - void foundSpecializedBean(Object param1); - - @LogMessage(level = Level.DEBUG) - @Message(id = 134, value = "Producer (method or field) of specialized bean (ignored): {0}", format = Format.MESSAGE_FORMAT) - void foundProducerOfSpecializedBean(Object param1); - - @LogMessage(level = Level.WARN) - @Message(id = 135, value = "Legacy deployment metadata provided by the integrator. Certain functionality will not be available.") - void legacyDeploymentMetadataProvided(); - - @LogMessage(level = Level.ERROR) - @Message(id = 136, value = "Exception(s) thrown during observer of BeforeShutdown: ") - void exceptionThrownDuringBeforeShutdownObserver(); - - @LogMessage(level = Level.TRACE) - @Message(id = 137, value = "Exception while loading class '{0}' : {1}", format = Format.MESSAGE_FORMAT) - void exceptionWhileLoadingClass(Object param1, Object param2); - - @LogMessage(level = Level.TRACE) - @Message(id = 138, value = "Error while loading class '{0}' : {1}", format = Format.MESSAGE_FORMAT) - void errorWhileLoadingClass(Object param1, Object param2); - - @LogMessage(level = Logger.Level.WARN) - @Message(id = 139, value = "Ignoring portable extension class {0} because of underlying class loading error: Type {1} not found. Enable DEBUG logging level to see the full error.", format = Format.MESSAGE_FORMAT) - void ignoringExtensionClassDueToLoadingError(String className, String missingDependency); - - @Message(id = 140, value = "Calling Bootstrap method after container has already been initialized. For correct order, see CDI11Bootstrap's documentation.") - IllegalStateException callingBootstrapMethodAfterContainerHasBeenInitialized(); - - @LogMessage(level = Logger.Level.INFO) - @Message(id = 141, value = "Falling back to the default observer method resolver due to {0}", format = Format.MESSAGE_FORMAT) - void notUsingFastResolver(ObserverMethod observer); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 142, value = "Exception loading annotated type using ClassFileServices. Falling back to the default implementation. {0}", format = Format.MESSAGE_FORMAT) - void exceptionLoadingAnnotatedType(String message); - - @LogMessage(level = Logger.Level.TRACE) - @Message(id = Message.NONE, value = "No PAT observers resolved for {0}. Skipping.", format = Format.MESSAGE_FORMAT) - void patSkipped(SlimAnnotatedType type); - - @LogMessage(level = Logger.Level.TRACE) - @Message(id = Message.NONE, value = "Sending PAT using the default event resolver: {0}", format = Format.MESSAGE_FORMAT) - void patDefaultResolver(SlimAnnotatedType type); - - @LogMessage(level = Logger.Level.TRACE) - @Message(id = Message.NONE, value = "Sending PAT using the fast event resolver: {0}", format = Format.MESSAGE_FORMAT) - void patFastResolver(SlimAnnotatedType type); - - @Message(id = 143, value = "Container lifecycle event method invoked outside of extension observer method invocation.") - IllegalStateException containerLifecycleEventMethodInvokedOutsideObserver(); - - @Message(id = 144, value = "CDI API version mismatch. CDI 1.0 API detected on classpath. Weld requires version 1.1 or better.") - IllegalStateException cdiApiVersionMismatch(); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 145, value = "Bean identifier index built:\n {0}", format = Format.MESSAGE_FORMAT) - void beanIdentifierIndexBuilt(Object info); - - @LogMessage(level = Level.WARN) - @Message(id = 146, value = "BeforeBeanDiscovery.addAnnotatedType(AnnotatedType) used for {0} is deprecated from CDI 1.1!", format = Format.MESSAGE_FORMAT) - void deprecatedAddAnnotatedTypeMethodUsed(Class clazz); - - @LogMessage(level = Level.WARN) - @Message(id = 147, value = "Decorator {0} declares inappropriate constructor therefore will not available as a managed bean!", format = Format.MESSAGE_FORMAT) - void decoratorWithNonCdiConstructor(String clazzName); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 148, value = "ProcessAnnotatedType.setAnnotatedType() called by {0}: {1} replaced by {2}", format = Format.MESSAGE_FORMAT) - void setAnnotatedTypeCalled(Object extensionName, Object original, Object newer); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 149, value = "ProcessBeanAttributes.setBeanAttributes() called by {0}: {1} replaced by {2}", format = Format.MESSAGE_FORMAT) - void setBeanAttributesCalled(Object extensionName, Object original, Object newer); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 150, value = "ProcessInjectionPoint.setInjectionPoint() called by {0}: {1} replaced by {2}", format = Format.MESSAGE_FORMAT) - void setInjectionPointCalled(Object extensionName, Object original, Object newer); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 151, value = "ProcessInjectionTarget.setInjectionTarget() called by {0}: {1} replaced by {2}", format = Format.MESSAGE_FORMAT) - void setInjectionTargetCalled(Object extensionName, Object original, Object newer); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 152, value = "ProcessProducer.setProducer() called by {0}: {1} replaced by {2}", format = Format.MESSAGE_FORMAT) - void setProducerCalled(Object extensionName, Object original, Object newer); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 153, value = "AfterTypeDiscovery.addAnnotatedType() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void addAnnotatedTypeCalled(Object extensionName, Object type); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 154, value = "AfterBeanDiscovery.addBean() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void addBeanCalled(Object extensionName, Object type); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 155, value = "AfterBeanDiscovery.addObserverMethod() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void addObserverMethodCalled(Object extensionName, Object type); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 156, value = "AfterBeanDiscovery.addContext() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void addContext(Object extensionName, Object type); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 157, value = "AfterBeanDiscovery.addDefinitionError() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void addDefinitionErrorCalled(Object extensionName, Object type); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 158, value = "BeforeBeanDiscovery.addQualifier() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void addQualifierCalled(Object extensionName, Object type); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 159, value = "BeforeBeanDiscovery.addScope() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void addScopeCalled(Object extensionName, Object type); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 160, value = "BeforeBeanDiscovery.addStereoType() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void addStereoTypeCalled(Object extensionName, Object type); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 161, value = "BeforeBeanDiscovery.addInterceptorBindingCalled() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void addInterceptorBindingCalled(Object extensionName, Object type); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 162, value = "BeforeBeanDiscovery.addAnnotatedType() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void addAnnotatedTypeCalledInBBD(Object extensionName, Object type); - - @Message(id = 163, value = "Non-unique bean deployment identifier detected: {0}", format = Format.MESSAGE_FORMAT) - DeploymentException nonuniqueBeanDeploymentIdentifier(Object info); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 164, value = "ProcessAnnotatedType.veto() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void annotatedTypeVetoed(Object extensionName, Object type); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 165, value = "ProcessBeanAttributes.veto() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void beanAttributesVetoed(Object extensionName, Object type); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 166, value = "AfterTypeDiscovery.{3} modified by {0} {2} {1}", format = Format.MESSAGE_FORMAT) - void typeModifiedInAfterTypeDiscovery(Object extensionName, Object type, Object operation, Object types); - - @LogMessage(level = Level.WARN) - @Message(id = 167, value = "Class {0} is annotated with @{1} but it does not declare an appropriate constructor therefore is not registered as a bean!", format = Format.MESSAGE_FORMAT) - void annotatedTypeNotRegisteredAsBeanDueToMissingAppropriateConstructor(String clazzName, String annotationName); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 168, value = "Extension bean deployed: {0}", format = Format.MESSAGE_FORMAT) - void extensionBeanDeployed(Object extension); - - @LogMessage(level = Level.INFO) - @Message(id = 169, value = "Jandex cannot distinguish inner and static nested classes! Update Jandex to 2.0.3.Final version or newer to improve scanning performance.", format = Format.MESSAGE_FORMAT) - void usingOldJandexVersion(); - - @Message(id = 170, value = "{0} observer cannot call both the configurator and set methods. Extension {1} \nStackTrace:", format = Format.MESSAGE_FORMAT) - IllegalStateException configuratorAndSetMethodBothCalled(Object observerName, Object extension); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 171, value = "BeforeBeanDiscovery.configureQualifier() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void configureQualifierCalled(Object extensionName, Object type); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 172, value = "BeforeBeanDiscovery.configureInterceptorBinding() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void configureInterceptorBindingCalled(Object extensionName, Object type); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 173, value = "ProcessProducer.configureProducer() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void configureProducerCalled(Object extensionName, Object bean); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 174, value = "ProcessBeanAttributes.configureBeanAttributes() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void configureBeanAttributesCalled(Object extensionName, Object bean); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 175, value = "ProcessBeanAttributes.isIgnoreFinalMethods() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void ignoreFinalMethodsCalled(Object extensionName, Object bean); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 176, value = "ProcessAnnotatedType.configureAnnotatedType() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void configureAnnotatedTypeCalled(Object extensionName, Object bean); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 177, value = "ProcessObserverMethod.configureObserverMethod() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void configureObserverMethodCalled(Object extensionName, Object bean); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 178, value = "ProcessInjectionPoint.configureInjectionPoint() called by {0} for {1}", format = Format.MESSAGE_FORMAT) - void configureInjectionPointCalled(Object extensionName, Object bean); - - @Message(id = 179, value = "{0} created by {1} cannot be processed", format = Format.MESSAGE_FORMAT) - DeploymentException unableToProcessConfigurator(Object configurator, Object extensionName, @Cause Throwable cause); - - @LogMessage(level = Logger.Level.DEBUG) - @Message(id = 180, value = "Drop unused bean metadata: {0}", format = Format.MESSAGE_FORMAT) - void dropUnusedBeanMetadata(Object bean); - - @LogMessage(level = Logger.Level.WARN) - @Message(id = 181, value = "org.jboss.weld.executor.threadPoolType=COMMON detected but ForkJoinPool.commonPool() does not work with SecurityManager enabled, switching to {0} thread pool", format = Format.MESSAGE_FORMAT) - void commonThreadPoolWithSecurityManagerEnabled(Object threadPoolType); - + BootstrapLogger LOG = Logger.getMessageLogger(BootstrapLogger.class, + Category.BOOTSTRAP.getName()); + + BootstrapLogger TRACKER_LOG = Logger.getMessageLogger( + BootstrapLogger.class, Category.BOOTSTRAP_TRACKER.getName()); + + @LogMessage(level = Level.DEBUG) + @Message(id = 100, value = "Weld initialized. Validating beans") + void validatingBeans(); + + @LogMessage(level = Level.INFO) + @Message(id = 101, + value = "Transactional services not available. Injection of " + + "@Inject UserTransaction not available. Transactional " + + "observers will be invoked synchronously.") + void + jtaUnavailable(); + + @LogMessage(level = Level.DEBUG) + @Message(id = 103, value = "Enabled alternatives for {0}: {1}", + format = Format.MESSAGE_FORMAT) + void + enabledAlternatives(Object param1, Object param2); + + @LogMessage(level = Level.DEBUG) + @Message(id = 104, value = "Enabled decorator types for {0}: {1}", + format = Format.MESSAGE_FORMAT) + void + enabledDecorators(Object param1, Object param2); + + @LogMessage(level = Level.DEBUG) + @Message(id = 105, value = "Enabled interceptor types for {0}: {1}", + format = Format.MESSAGE_FORMAT) + void + enabledInterceptors(Object param1, Object param2); + + @LogMessage(level = Level.DEBUG) + @Message(id = 106, value = "Bean: {0}", format = Format.MESSAGE_FORMAT) + void foundBean(Object param1); + + @LogMessage(level = Level.DEBUG) + @Message(id = 107, value = "Interceptor: {0}", format = Format.MESSAGE_FORMAT) + void foundInterceptor(Object param1); + + @LogMessage(level = Level.DEBUG) + @Message(id = 108, value = "Decorator: {0}", format = Format.MESSAGE_FORMAT) + void foundDecorator(Object param1); + + @LogMessage(level = Level.DEBUG) + @Message(id = 109, value = "ObserverMethod: {0}", + format = Format.MESSAGE_FORMAT) + void + foundObserverMethod(Object param1); + + @Message(id = 110, + value = "Cannot set the annotation type to null (if you want to " + + "stop the type being used, call veto()): {0}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + annotationTypeNull(Object param1); + + @Message(id = 111, + value = "Bean type is not STATELESS, STATEFUL or SINGLETON: {0}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + beanTypeNotEjb(Object param1); + + @Message(id = 112, + value = "Class {0} has both @Interceptor and @Decorator annotations", + format = Format.MESSAGE_FORMAT) + DefinitionException + beanIsBothInterceptorAndDecorator(Object param1); + + @Message(id = 113, value = "BeanDeploymentArchive must not be null: {0}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + deploymentArchiveNull(Object param1); + + @Message(id = 114, value = "Must start the container with a deployment") + IllegalArgumentException deploymentRequired(); + + @Message(id = 116, value = "Manager has not been initialized") + IllegalStateException managerNotInitialized(); + + @Message(id = 117, + value = "Required service {0} has not been specified for {1}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + unspecifiedRequiredService(Object service, Object target); + + @Message(id = 118, value = "Only normal scopes can be passivating. Scope {0}", + format = Format.MESSAGE_FORMAT) + DefinitionException + passivatingNonNormalScopeIllegal(Object param1); + + @LogMessage(level = Level.INFO) + @Message( + id = 119, + value = "Not generating any bean definitions from {0} because of " + + "underlying class loading error: Type {1} not found. If this " + + "is unexpected, enable DEBUG logging to see the full error.", + format = Format.MESSAGE_FORMAT) + void + ignoringClassDueToLoadingError(Object param1, Object param2); + + @Message(id = 123, value = "Error loading {0} defined in {1}", + format = Format.MESSAGE_FORMAT) + DeploymentException + errorLoadingBeansXmlEntry(Object param1, Object param2, + @Cause Throwable cause); + + @LogMessage(level = Level.DEBUG) + @Message(id = 124, value = "Using {0} threads for bootstrap", + format = Format.MESSAGE_FORMAT) + void + threadsInUse(Object param1); + + @Message(id = 125, value = "Invalid thread pool size: {0}", + format = Format.MESSAGE_FORMAT) + DeploymentException + invalidThreadPoolSize(Object param1); + + @LogMessage(level = Level.WARN) + @Message(id = 126, value = "Timeout shutting down thread pool {0} at {1}", + format = Format.MESSAGE_FORMAT) + void + timeoutShuttingDownThreadPool(Object param1, Object param2); + + @Message(id = 127, value = "Invalid thread pool type: {0}", + format = Format.MESSAGE_FORMAT) + DeploymentException + invalidThreadPoolType(Object param1); + + @Message(id = 128, value = "Invalid value for property {0}: {1}", + format = Format.MESSAGE_FORMAT) + DeploymentException + invalidPropertyValue(Object param1, Object param2); + + @Message( + id = 130, + value = "Cannot replace AnnotatedType for {0} with AnnotatedType for {1}", + format = Format.MESSAGE_FORMAT) + IllegalArgumentException + annotatedTypeJavaClassMismatch(Object param1, Object param2); + + @LogMessage(level = Level.DEBUG) + @Message(id = 132, value = "Disabled alternative (ignored): {0}", + format = Format.MESSAGE_FORMAT) + void + foundDisabledAlternative(Object param1); + + @LogMessage(level = Level.DEBUG) + @Message(id = 133, value = "Specialized bean (ignored): {0}", + format = Format.MESSAGE_FORMAT) + void + foundSpecializedBean(Object param1); + + @LogMessage(level = Level.DEBUG) + @Message( + id = 134, + value = "Producer (method or field) of specialized bean (ignored): {0}", + format = Format.MESSAGE_FORMAT) + void + foundProducerOfSpecializedBean(Object param1); + + @LogMessage(level = Level.WARN) + @Message(id = 135, + value = "Legacy deployment metadata provided by the integrator. " + + "Certain functionality will not be available.") + void + legacyDeploymentMetadataProvided(); + + @LogMessage(level = Level.ERROR) + @Message(id = 136, + value = "Exception(s) thrown during observer of BeforeShutdown: ") + void + exceptionThrownDuringBeforeShutdownObserver(); + + @LogMessage(level = Level.TRACE) + @Message(id = 137, value = "Exception while loading class '{0}' : {1}", + format = Format.MESSAGE_FORMAT) + void + exceptionWhileLoadingClass(Object param1, Object param2); + + @LogMessage(level = Level.TRACE) + @Message(id = 138, value = "Error while loading class '{0}' : {1}", + format = Format.MESSAGE_FORMAT) + void + errorWhileLoadingClass(Object param1, Object param2); + + @LogMessage(level = Logger.Level.WARN) + @Message(id = 139, + value = "Ignoring portable extension class {0} because of " + + "underlying class loading error: Type {1} not found. " + + "Enable DEBUG logging level to see the full error.", + format = Format.MESSAGE_FORMAT) + void + ignoringExtensionClassDueToLoadingError(String className, + String missingDependency); + + @Message( + id = 140, + value = + "Calling Bootstrap method after container has already been " + + + "initialized. For correct order, see CDI11Bootstrap's documentation.") + IllegalStateException + callingBootstrapMethodAfterContainerHasBeenInitialized(); + + @LogMessage(level = Logger.Level.INFO) + @Message( + id = 141, + value = "Falling back to the default observer method resolver due to {0}", + format = Format.MESSAGE_FORMAT) + void + notUsingFastResolver(ObserverMethod observer); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 142, + value = "Exception loading annotated type using ClassFileServices. " + + "Falling back to the default implementation. {0}", + format = Format.MESSAGE_FORMAT) + void + exceptionLoadingAnnotatedType(String message); + + @LogMessage(level = Logger.Level.TRACE) + @Message(id = Message.NONE, + value = "No PAT observers resolved for {0}. Skipping.", + format = Format.MESSAGE_FORMAT) + void + patSkipped(SlimAnnotatedType type); + + @LogMessage(level = Logger.Level.TRACE) + @Message(id = Message.NONE, + value = "Sending PAT using the default event resolver: {0}", + format = Format.MESSAGE_FORMAT) + void + patDefaultResolver(SlimAnnotatedType type); + + @LogMessage(level = Logger.Level.TRACE) + @Message(id = Message.NONE, + value = "Sending PAT using the fast event resolver: {0}", + format = Format.MESSAGE_FORMAT) + void + patFastResolver(SlimAnnotatedType type); + + @Message(id = 143, value = "Container lifecycle event method invoked " + + + "outside of extension observer method invocation.") + IllegalStateException + containerLifecycleEventMethodInvokedOutsideObserver(); + + @Message(id = 144, + value = "CDI API version mismatch. CDI 1.0 API detected on " + + "classpath. Weld requires version 1.1 or better.") + IllegalStateException + cdiApiVersionMismatch(); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 145, value = "Bean identifier index built:\n {0}", + format = Format.MESSAGE_FORMAT) + void + beanIdentifierIndexBuilt(Object info); + + @LogMessage(level = Level.WARN) + @Message(id = 146, + value = "BeforeBeanDiscovery.addAnnotatedType(AnnotatedType) " + + "used for {0} is deprecated from CDI 1.1!", + format = Format.MESSAGE_FORMAT) + void + deprecatedAddAnnotatedTypeMethodUsed(Class clazz); + + @LogMessage(level = Level.WARN) + @Message(id = 147, + value = "Decorator {0} declares inappropriate constructor " + + "therefore will not available as a managed bean!", + format = Format.MESSAGE_FORMAT) + void + decoratorWithNonCdiConstructor(String clazzName); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 148, + value = "ProcessAnnotatedType.setAnnotatedType() called by {0}: " + + "{1} replaced by {2}", + format = Format.MESSAGE_FORMAT) + void + setAnnotatedTypeCalled(Object extensionName, Object original, Object newer); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 149, + value = "ProcessBeanAttributes.setBeanAttributes() called by {0}: " + + "{1} replaced by {2}", + format = Format.MESSAGE_FORMAT) + void + setBeanAttributesCalled(Object extensionName, Object original, Object newer); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 150, + value = "ProcessInjectionPoint.setInjectionPoint() called by {0}: " + + "{1} replaced by {2}", + format = Format.MESSAGE_FORMAT) + void + setInjectionPointCalled(Object extensionName, Object original, Object newer); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 151, + value = "ProcessInjectionTarget.setInjectionTarget() called by " + + "{0}: {1} replaced by {2}", + format = Format.MESSAGE_FORMAT) + void + setInjectionTargetCalled(Object extensionName, Object original, Object newer); + + @LogMessage(level = Logger.Level.DEBUG) + @Message( + id = 152, + value = + "ProcessProducer.setProducer() called by {0}: {1} replaced by {2}", + format = Format.MESSAGE_FORMAT) + void + setProducerCalled(Object extensionName, Object original, Object newer); + + @LogMessage(level = Logger.Level.DEBUG) + @Message( + id = 153, + value = "AfterTypeDiscovery.addAnnotatedType() called by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + addAnnotatedTypeCalled(Object extensionName, Object type); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 154, + value = "AfterBeanDiscovery.addBean() called by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + addBeanCalled(Object extensionName, Object type); + + @LogMessage(level = Logger.Level.DEBUG) + @Message( + id = 155, + value = "AfterBeanDiscovery.addObserverMethod() called by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + addObserverMethodCalled(Object extensionName, Object type); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 156, + value = "AfterBeanDiscovery.addContext() called by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + addContext(Object extensionName, Object type); + + @LogMessage(level = Logger.Level.DEBUG) + @Message( + id = 157, + value = "AfterBeanDiscovery.addDefinitionError() called by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + addDefinitionErrorCalled(Object extensionName, Object type); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 158, + value = "BeforeBeanDiscovery.addQualifier() called by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + addQualifierCalled(Object extensionName, Object type); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 159, + value = "BeforeBeanDiscovery.addScope() called by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + addScopeCalled(Object extensionName, Object type); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 160, + value = "BeforeBeanDiscovery.addStereoType() called by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + addStereoTypeCalled(Object extensionName, Object type); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 161, + value = "BeforeBeanDiscovery.addInterceptorBindingCalled() called " + + "by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + addInterceptorBindingCalled(Object extensionName, Object type); + + @LogMessage(level = Logger.Level.DEBUG) + @Message( + id = 162, + value = "BeforeBeanDiscovery.addAnnotatedType() called by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + addAnnotatedTypeCalledInBBD(Object extensionName, Object type); + + @Message(id = 163, + value = "Non-unique bean deployment identifier detected: {0}", + format = Format.MESSAGE_FORMAT) + DeploymentException + nonuniqueBeanDeploymentIdentifier(Object info); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 164, + value = "ProcessAnnotatedType.veto() called by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + annotatedTypeVetoed(Object extensionName, Object type); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 165, + value = "ProcessBeanAttributes.veto() called by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + beanAttributesVetoed(Object extensionName, Object type); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 166, value = "AfterTypeDiscovery.{3} modified by {0} {2} {1}", + format = Format.MESSAGE_FORMAT) + void + typeModifiedInAfterTypeDiscovery(Object extensionName, Object type, + Object operation, Object types); + + @LogMessage(level = Level.WARN) + @Message( + id = 167, + value = "Class {0} is annotated with @{1} but it does not declare an " + + + "appropriate constructor therefore is not registered as a bean!", + format = Format.MESSAGE_FORMAT) + void + annotatedTypeNotRegisteredAsBeanDueToMissingAppropriateConstructor( + String clazzName, String annotationName); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 168, value = "Extension bean deployed: {0}", + format = Format.MESSAGE_FORMAT) + void + extensionBeanDeployed(Object extension); + + @LogMessage(level = Level.INFO) + @Message(id = 169, + value = "Jandex cannot distinguish inner and static nested " + + "classes! Update Jandex to 2.0.3.Final version or newer " + + "to improve scanning performance.", + format = Format.MESSAGE_FORMAT) + void + usingOldJandexVersion(); + + @Message(id = 170, + value = "{0} observer cannot call both the configurator and set " + + "methods. Extension {1} \nStackTrace:", + format = Format.MESSAGE_FORMAT) + IllegalStateException + configuratorAndSetMethodBothCalled(Object observerName, Object extension); + + @LogMessage(level = Logger.Level.DEBUG) + @Message( + id = 171, + value = "BeforeBeanDiscovery.configureQualifier() called by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + configureQualifierCalled(Object extensionName, Object type); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 172, + value = "BeforeBeanDiscovery.configureInterceptorBinding() called " + + "by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + configureInterceptorBindingCalled(Object extensionName, Object type); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 173, + value = "ProcessProducer.configureProducer() called by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + configureProducerCalled(Object extensionName, Object bean); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 174, + value = "ProcessBeanAttributes.configureBeanAttributes() called " + + "by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + configureBeanAttributesCalled(Object extensionName, Object bean); + + @LogMessage(level = Logger.Level.DEBUG) + @Message( + id = 175, + value = + "ProcessBeanAttributes.isIgnoreFinalMethods() called by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + ignoreFinalMethodsCalled(Object extensionName, Object bean); + + @LogMessage(level = Logger.Level.DEBUG) + @Message( + id = 176, + value = + "ProcessAnnotatedType.configureAnnotatedType() called by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + configureAnnotatedTypeCalled(Object extensionName, Object bean); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 177, + value = "ProcessObserverMethod.configureObserverMethod() called " + + "by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + configureObserverMethodCalled(Object extensionName, Object bean); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 178, + value = "ProcessInjectionPoint.configureInjectionPoint() called " + + "by {0} for {1}", + format = Format.MESSAGE_FORMAT) + void + configureInjectionPointCalled(Object extensionName, Object bean); + + @Message(id = 179, value = "{0} created by {1} cannot be processed", + format = Format.MESSAGE_FORMAT) + DeploymentException + unableToProcessConfigurator(Object configurator, Object extensionName, + @Cause Throwable cause); + + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 180, value = "Drop unused bean metadata: {0}", + format = Format.MESSAGE_FORMAT) + void + dropUnusedBeanMetadata(Object bean); + + @LogMessage(level = Logger.Level.WARN) + @Message(id = 181, + value = "org.jboss.weld.executor.threadPoolType=COMMON detected " + + "but ForkJoinPool.commonPool() does not work with " + + "SecurityManager enabled, switching to {0} thread pool", + format = Format.MESSAGE_FORMAT) + void + commonThreadPoolWithSecurityManagerEnabled(Object threadPoolType); + + @Message(id = 182, + value = "Provided implementation of " + + "org.jboss.weld.serialization.spi.ProxyServices ({0}) " + + "does not support class defining. This functionality is " + + "required in order to be able to define proxy classes.", + format = Format.MESSAGE_FORMAT) + IllegalStateException + proxyServicesWithoutClassDefining(Object services); } diff --git a/impl/src/main/java/org/jboss/weld/util/Beans.java b/impl/src/main/java/org/jboss/weld/util/Beans.java index a5d722a320..d827b68d8c 100644 --- a/impl/src/main/java/org/jboss/weld/util/Beans.java +++ b/impl/src/main/java/org/jboss/weld/util/Beans.java @@ -34,7 +34,6 @@ import java.util.List; import java.util.Map; import java.util.Set; - import javax.decorator.Decorator; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.ConversationScoped; @@ -58,8 +57,8 @@ import javax.enterprise.inject.spi.BeanAttributes; import javax.enterprise.inject.spi.Extension; import javax.enterprise.inject.spi.PassivationCapable; +import javax.enterprise.inject.spi.Prioritized; import javax.inject.Inject; - import org.jboss.weld.annotated.enhanced.EnhancedAnnotated; import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedConstructor; import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedMethod; @@ -70,6 +69,7 @@ import org.jboss.weld.bean.ForwardingBean; import org.jboss.weld.bean.InterceptorImpl; import org.jboss.weld.bean.RIBean; +import org.jboss.weld.bean.WeldBean; import org.jboss.weld.bootstrap.api.ServiceRegistry; import org.jboss.weld.bootstrap.enablement.ModuleEnablement; import org.jboss.weld.injection.FieldInjectionPoint; @@ -103,595 +103,712 @@ */ public class Beans { - private Beans() { - } - - /** - * Indicates if a bean's scope type is passivating - * - * @param bean The bean to inspect - * @return True if the scope is passivating, false otherwise - */ - public static boolean isPassivatingScope(Bean bean, BeanManagerImpl manager) { - if (bean == null) { - return false; - } else { - return manager.getServices().get(MetaAnnotationStore.class).getScopeModel(bean.getScope()).isPassivating(); - } - } - - /** - * Tests if a bean is capable of having its state temporarily stored to secondary storage - * - * @param bean The bean to inspect - * @return True if the bean is passivation capable - */ - public static boolean isPassivationCapableBean(Bean bean) { - if (bean instanceof RIBean) { - return ((RIBean) bean).isPassivationCapableBean(); - } else { - return bean instanceof PassivationCapable; - } - } - - /** - * Tests if a bean is capable of having its state temporarily stored to secondary storage - * - * @param bean The bean to inspect - * @return True if the bean is passivation capable - */ - public static boolean isPassivationCapableDependency(Bean bean) { - if (bean instanceof RIBean) { - return ((RIBean) bean).isPassivationCapableDependency(); - } - return bean instanceof PassivationCapable; - } - - /** - * Indicates if a bean is proxyable - * - * @param bean The bean to test - * @return True if proxyable, false otherwise - */ - public static boolean isBeanProxyable(Bean bean, BeanManagerImpl manager) { - if (bean instanceof RIBean) { - return ((RIBean) bean).isProxyable(); - } else { - return Proxies.isTypesProxyable(bean.getTypes(), manager.getServices()); - } - } - - public static List> getInterceptableMethods(EnhancedAnnotatedType type) { - List> annotatedMethods = new ArrayList>(); - for (EnhancedAnnotatedMethod annotatedMethod : type.getEnhancedMethods()) { - boolean businessMethod = !annotatedMethod.isStatic() && !annotatedMethod.isAnnotationPresent(Inject.class) - && !annotatedMethod.getJavaMember().isBridge(); - - if (businessMethod && !isInterceptorMethod(annotatedMethod)) { - annotatedMethods.add(annotatedMethod); - } - } - return annotatedMethods; - } - - private static boolean isInterceptorMethod(AnnotatedMethod annotatedMethod) { - for (InterceptionType interceptionType : InterceptionTypeRegistry.getSupportedInterceptionTypes()) { - if (annotatedMethod.isAnnotationPresent(InterceptionTypeRegistry.getAnnotationClass(interceptionType))) { - return true; - } - } - return false; - } - - /** - * Checks that all the qualifiers in the set requiredQualifiers are in the set of qualifiers. Qualifier equality rules for - * annotation members are followed. - * - * @param requiredQualifiers The required qualifiers - * @param qualifiers The set of qualifiers to check - * @return True if all matches, false otherwise - */ - public static boolean containsAllQualifiers(Set requiredQualifiers, Set qualifiers) { - return qualifiers.containsAll(requiredQualifiers); - } - - public static boolean containsAllInterceptionBindings(Set expectedBindings, - Set existingBindings, BeanManagerImpl manager) { - final Set expected = manager.extractInterceptorBindingsForQualifierInstance(QualifierInstance.of(expectedBindings, manager.getServices().get(MetaAnnotationStore.class))); - return expected.isEmpty() ? false : manager.extractInterceptorBindingsForQualifierInstance(existingBindings).containsAll(expected); - } - - /** - * Retains only beans which are enabled. - * - * @param beans The mutable set of beans to filter - * @param beanManager The bean manager - * @return a mutable set of enabled beans - */ - public static > Set removeDisabledBeans(Set beans, final BeanManagerImpl beanManager) { - if (beans.isEmpty()) { - return beans; - } else { - for (Iterator iterator = beans.iterator(); iterator.hasNext();) { - if (!isBeanEnabled(iterator.next(), beanManager.getEnabled())) { - iterator.remove(); - } - } - return beans; - } - } - - public static boolean isBeanEnabled(Bean bean, ModuleEnablement enabled) { - if (bean.isAlternative()) { - if (enabled.isEnabledAlternativeClass(bean.getBeanClass())) { - return true; - } else { - for (Class stereotype : bean.getStereotypes()) { - if (enabled.isEnabledAlternativeStereotype(stereotype)) { - return true; - } - } - return false; + private Beans() {} + + /** + * Indicates if a bean's scope type is passivating + * + * @param bean The bean to inspect + * @return True if the scope is passivating, false otherwise + */ + public static boolean isPassivatingScope(Bean bean, + BeanManagerImpl manager) { + if (bean == null) { + return false; + } else { + return manager.getServices() + .get(MetaAnnotationStore.class) + .getScopeModel(bean.getScope()) + .isPassivating(); + } + } + + /** + * Tests if a bean is capable of having its state temporarily stored to + * secondary storage + * + * @param bean The bean to inspect + * @return True if the bean is passivation capable + */ + public static boolean isPassivationCapableBean(Bean bean) { + if (bean instanceof RIBean) { + return ((RIBean)bean).isPassivationCapableBean(); + } else { + return bean instanceof PassivationCapable; + } + } + + /** + * Tests if a bean is capable of having its state temporarily stored to + * secondary storage + * + * @param bean The bean to inspect + * @return True if the bean is passivation capable + */ + public static boolean isPassivationCapableDependency(Bean bean) { + if (bean instanceof RIBean) { + return ((RIBean)bean).isPassivationCapableDependency(); + } + return bean instanceof PassivationCapable; + } + + /** + * Indicates if a bean is proxyable + * + * @param bean The bean to test + * @return True if proxyable, false otherwise + */ + public static boolean isBeanProxyable(Bean bean, BeanManagerImpl manager) { + if (bean instanceof RIBean) { + return ((RIBean)bean).isProxyable(); + } else { + return Proxies.isTypesProxyable(bean.getTypes(), manager.getServices()); + } + } + + public static List> + getInterceptableMethods(EnhancedAnnotatedType type) { + List> annotatedMethods = + new ArrayList>(); + for (EnhancedAnnotatedMethod annotatedMethod : + type.getEnhancedMethods()) { + // note that a bridge method can be a candidate for interception in rare + // cases; do not discard those + boolean businessMethod = + !annotatedMethod.isStatic() && + !annotatedMethod.isAnnotationPresent(Inject.class); + + if (businessMethod && !isInterceptorMethod(annotatedMethod)) { + annotatedMethods.add(annotatedMethod); + } + } + return annotatedMethods; + } + + private static boolean + isInterceptorMethod(AnnotatedMethod annotatedMethod) { + for (InterceptionType interceptionType : + InterceptionTypeRegistry.getSupportedInterceptionTypes()) { + if (annotatedMethod.isAnnotationPresent( + InterceptionTypeRegistry.getAnnotationClass(interceptionType))) { + return true; + } + } + return false; + } + + /** + * Checks that all the qualifiers in the set requiredQualifiers are in the set + * of qualifiers. Qualifier equality rules for annotation members are + * followed. + * + * @param requiredQualifiers The required qualifiers + * @param qualifiers The set of qualifiers to check + * @return True if all matches, false otherwise + */ + public static boolean + containsAllQualifiers(Set requiredQualifiers, + Set qualifiers) { + return qualifiers.containsAll(requiredQualifiers); + } + + public static boolean + containsAllInterceptionBindings(Set expectedBindings, + Set existingBindings, + BeanManagerImpl manager) { + final Set expected = + manager.extractInterceptorBindingsForQualifierInstance( + QualifierInstance.of( + expectedBindings, + manager.getServices().get(MetaAnnotationStore.class))); + return expected.isEmpty() + ? false + : manager + .extractInterceptorBindingsForQualifierInstance(existingBindings) + .containsAll(expected); + } + + /** + * Retains only beans which are enabled. + * + * @param beans The mutable set of beans to filter + * @param beanManager The bean manager + * @return a mutable set of enabled beans + */ + public static > Set + removeDisabledBeans(Set beans, final BeanManagerImpl beanManager) { + if (beans.isEmpty()) { + return beans; + } else { + for (Iterator iterator = beans.iterator(); iterator.hasNext();) { + if (!isBeanEnabled(iterator.next(), beanManager.getEnabled())) { + iterator.remove(); + } + } + return beans; + } + } + + public static boolean isBeanEnabled(Bean bean, ModuleEnablement enabled) { + if (bean.isAlternative()) { + boolean isEnabled = false; + if (enabled.isEnabledAlternativeClass(bean.getBeanClass())) { + isEnabled = true; + } else { + for (Class stereotype : bean.getStereotypes()) { + if (enabled.isEnabledAlternativeStereotype(stereotype)) { + isEnabled = true; + break; + } + } + } + // For synthetic enabled alternatives, the ModuleEnablement may not yet be + // aware of them + if (!isEnabled && ((bean instanceof WeldBean && + ((WeldBean)bean).getPriority() != null) || + bean instanceof Prioritized)) { + isEnabled = true; + } + return isEnabled; + } else if (bean instanceof AbstractProducerBean) { + AbstractProducerBean receiverBean = + (AbstractProducerBean)bean; + return isBeanEnabled(receiverBean.getDeclaringBean(), enabled); + } else if (bean instanceof DecoratorImpl) { + return enabled.isDecoratorEnabled(bean.getBeanClass()); + } else if (bean instanceof InterceptorImpl) { + return enabled.isInterceptorEnabled(bean.getBeanClass()); + } else { + return true; + } + } + + /** + * Is alternative. + * + * @param annotated the annotated + * @param mergedStereotypes merged stereotypes + * @return true if alternative, false otherwise + */ + public static boolean + isAlternative(EnhancedAnnotated annotated, + MergedStereotypes mergedStereotypes) { + return annotated.isAnnotationPresent(Alternative.class) || + mergedStereotypes.isAlternative(); + } + + public static EnhancedAnnotatedConstructor + getBeanConstructorStrict(EnhancedAnnotatedType type) { + EnhancedAnnotatedConstructor constructor = getBeanConstructor(type); + if (constructor == null) { + throw UtilLogger.LOG.unableToFindConstructor(type); + } + return constructor; + } + + public static EnhancedAnnotatedConstructor + getBeanConstructor(EnhancedAnnotatedType type) { + Collection> + initializerAnnotatedConstructors = + type.getEnhancedConstructors(Inject.class); + BeanLogger.LOG.foundInjectableConstructors(initializerAnnotatedConstructors, + type); + EnhancedAnnotatedConstructor constructor = null; + if (initializerAnnotatedConstructors.size() > 1) { + throw UtilLogger.LOG.ambiguousConstructor( + type, initializerAnnotatedConstructors); + } else if (initializerAnnotatedConstructors.size() == 1) { + constructor = initializerAnnotatedConstructors.iterator().next(); + BeanLogger.LOG.foundOneInjectableConstructor(constructor, type); + } else if (type.getNoArgsEnhancedConstructor() != null) { + constructor = type.getNoArgsEnhancedConstructor(); + BeanLogger.LOG.foundDefaultConstructor(constructor, type); + } + if (constructor != null) { + if (!constructor.getEnhancedParameters(Disposes.class).isEmpty()) { + throw BeanLogger.LOG.parameterAnnotationNotAllowedOnConstructor( + "@Disposes", constructor, + Formats.formatAsStackTraceElement(constructor.getJavaMember())); + } + if (!constructor.getEnhancedParameters(Observes.class).isEmpty()) { + throw BeanLogger.LOG.parameterAnnotationNotAllowedOnConstructor( + "@Observes", constructor, + Formats.formatAsStackTraceElement(constructor.getJavaMember())); + } + if (!constructor.getEnhancedParameters(ObservesAsync.class).isEmpty()) { + throw BeanLogger.LOG.parameterAnnotationNotAllowedOnConstructor( + "@ObservesAsync", constructor, + Formats.formatAsStackTraceElement(constructor.getJavaMember())); + } + } + return constructor; + } + + /** + * Injects EJBs and other EE resources. + * + * @param resourceInjectionsHierarchy + * @param beanInstance + * @param ctx + */ + public static void injectEEFields( + Iterable>> resourceInjectionsHierarchy, + T beanInstance, CreationalContext ctx) { + for (Set> resourceInjections : + resourceInjectionsHierarchy) { + for (ResourceInjection resourceInjection : resourceInjections) { + resourceInjection.injectResourceReference(beanInstance, ctx); + } + } + } + + /** + * Gets the declared bean type + * + * @return The bean type + */ + public static Type getDeclaredBeanType(Class clazz) { + Type[] actualTypeArguments = Reflections.getActualTypeArguments(clazz); + if (actualTypeArguments.length == 1) { + return actualTypeArguments[0]; + } else { + return null; + } + } + + /** + * Injects bound fields + * + * @param instance The instance to inject into + */ + public static void injectBoundFields( + T instance, CreationalContext creationalContext, + BeanManagerImpl manager, + Iterable> injectableFields) { + for (FieldInjectionPoint injectableField : injectableFields) { + injectableField.inject(instance, manager, creationalContext); + } + } + + public static void injectFieldsAndInitializers( + T instance, CreationalContext ctx, BeanManagerImpl beanManager, + List>> + injectableFields, + List>> + initializerMethods) { + if (injectableFields.size() != initializerMethods.size()) { + throw UtilLogger.LOG.invalidQuantityInjectableFieldsAndInitializerMethods( + injectableFields, initializerMethods); + } + for (int i = 0; i < injectableFields.size(); i++) { + injectBoundFields(instance, ctx, beanManager, injectableFields.get(i)); + callInitializers(instance, ctx, beanManager, initializerMethods.get(i)); + } + } + + /** + * Calls all initializers of the bean + * + * @param instance The bean instance + */ + public static void callInitializers( + T instance, CreationalContext creationalContext, + BeanManagerImpl manager, + Iterable> initializerMethods) { + for (MethodInjectionPoint initializer : initializerMethods) { + initializer.invoke(instance, null, manager, creationalContext, + CreationException.class); + } + } + + public static boolean isInterceptor(AnnotatedType annotatedItem) { + return annotatedItem.isAnnotationPresent( + javax.interceptor.Interceptor.class); + } + + public static + boolean isDecorator(EnhancedAnnotatedType annotatedItem) { + return annotatedItem.isAnnotationPresent(Decorator.class); + } + + public static Set + mergeInQualifiers(BeanManagerImpl manager, Collection qualifiers, + Annotation[] newQualifiers) { + Set result = new HashSet(); + + if (qualifiers != null && !(qualifiers.isEmpty())) { + result.addAll(qualifiers); + } + if (newQualifiers != null && newQualifiers.length > 0) { + final MetaAnnotationStore store = + manager.getServices().get(MetaAnnotationStore.class); + Set checkedNewQualifiers = new HashSet(); + for (Annotation qualifier : newQualifiers) { + if (!store.getBindingTypeModel(qualifier.annotationType()).isValid()) { + throw UtilLogger.LOG.annotationNotQualifier(qualifier); + } + Class annotationType = qualifier.annotationType(); + if (!annotationType.isAnnotationPresent(Repeatable.class)) { + for (Annotation annotation : checkedNewQualifiers) { + if (annotationType.equals(annotation.annotationType())) { + throw UtilLogger.LOG.redundantQualifier( + qualifier, Arrays.toString(newQualifiers)); } - } else if (bean instanceof AbstractProducerBean) { - AbstractProducerBean receiverBean = (AbstractProducerBean) bean; - return isBeanEnabled(receiverBean.getDeclaringBean(), enabled); - } else if (bean instanceof DecoratorImpl) { - return enabled.isDecoratorEnabled(bean.getBeanClass()); - } else if (bean instanceof InterceptorImpl) { - return enabled.isInterceptorEnabled(bean.getBeanClass()); - } else { - return true; - } - } - - /** - * Is alternative. - * - * @param annotated the annotated - * @param mergedStereotypes merged stereotypes - * @return true if alternative, false otherwise - */ - public static boolean isAlternative(EnhancedAnnotated annotated, MergedStereotypes mergedStereotypes) { - return annotated.isAnnotationPresent(Alternative.class) || mergedStereotypes.isAlternative(); - } - - public static EnhancedAnnotatedConstructor getBeanConstructorStrict(EnhancedAnnotatedType type) { - EnhancedAnnotatedConstructor constructor = getBeanConstructor(type); - if (constructor == null) { - throw UtilLogger.LOG.unableToFindConstructor(type); - } - return constructor; - } - - public static EnhancedAnnotatedConstructor getBeanConstructor(EnhancedAnnotatedType type) { - Collection> initializerAnnotatedConstructors = type - .getEnhancedConstructors(Inject.class); - BeanLogger.LOG.foundInjectableConstructors(initializerAnnotatedConstructors, type); - EnhancedAnnotatedConstructor constructor = null; - if (initializerAnnotatedConstructors.size() > 1) { - throw UtilLogger.LOG.ambiguousConstructor(type, initializerAnnotatedConstructors); - } else if (initializerAnnotatedConstructors.size() == 1) { - constructor = initializerAnnotatedConstructors.iterator().next(); - BeanLogger.LOG.foundOneInjectableConstructor(constructor, type); - } else if (type.getNoArgsEnhancedConstructor() != null) { - constructor = type.getNoArgsEnhancedConstructor(); - BeanLogger.LOG.foundDefaultConstructor(constructor, type); - } - if (constructor != null) { - if (!constructor.getEnhancedParameters(Disposes.class).isEmpty()) { - throw BeanLogger.LOG.parameterAnnotationNotAllowedOnConstructor("@Disposes", constructor, - Formats.formatAsStackTraceElement(constructor.getJavaMember())); - } - if (!constructor.getEnhancedParameters(Observes.class).isEmpty()) { - throw BeanLogger.LOG.parameterAnnotationNotAllowedOnConstructor("@Observes", constructor, - Formats.formatAsStackTraceElement(constructor.getJavaMember())); - } - if (!constructor.getEnhancedParameters(ObservesAsync.class).isEmpty()) { - throw BeanLogger.LOG.parameterAnnotationNotAllowedOnConstructor("@ObservesAsync", constructor, - Formats.formatAsStackTraceElement(constructor.getJavaMember())); - } - } - return constructor; - } - - /** - * Injects EJBs and other EE resources. - * - * @param resourceInjectionsHierarchy - * @param beanInstance - * @param ctx - */ - public static void injectEEFields(Iterable>> resourceInjectionsHierarchy, - T beanInstance, CreationalContext ctx) { - for (Set> resourceInjections : resourceInjectionsHierarchy) { - for (ResourceInjection resourceInjection : resourceInjections) { - resourceInjection.injectResourceReference(beanInstance, ctx); - } - } - } - - /** - * Gets the declared bean type - * - * @return The bean type - */ - public static Type getDeclaredBeanType(Class clazz) { - Type[] actualTypeArguments = Reflections.getActualTypeArguments(clazz); - if (actualTypeArguments.length == 1) { - return actualTypeArguments[0]; - } else { - return null; - } - } - - /** - * Injects bound fields - * - * @param instance The instance to inject into - */ - public static void injectBoundFields(T instance, CreationalContext creationalContext, BeanManagerImpl manager, - Iterable> injectableFields) { - for (FieldInjectionPoint injectableField : injectableFields) { - injectableField.inject(instance, manager, creationalContext); - } - } - - public static void injectFieldsAndInitializers(T instance, CreationalContext ctx, BeanManagerImpl beanManager, - List>> injectableFields, - List>> initializerMethods) { - if (injectableFields.size() != initializerMethods.size()) { - throw UtilLogger.LOG.invalidQuantityInjectableFieldsAndInitializerMethods(injectableFields, initializerMethods); - } - for (int i = 0; i < injectableFields.size(); i++) { - injectBoundFields(instance, ctx, beanManager, injectableFields.get(i)); - callInitializers(instance, ctx, beanManager, initializerMethods.get(i)); - } - } - - /** - * Calls all initializers of the bean - * - * @param instance The bean instance - */ - public static void callInitializers(T instance, CreationalContext creationalContext, BeanManagerImpl manager, - Iterable> initializerMethods) { - for (MethodInjectionPoint initializer : initializerMethods) { - initializer.invoke(instance, null, manager, creationalContext, CreationException.class); - } - } - - public static boolean isInterceptor(AnnotatedType annotatedItem) { - return annotatedItem.isAnnotationPresent(javax.interceptor.Interceptor.class); - } - - public static boolean isDecorator(EnhancedAnnotatedType annotatedItem) { - return annotatedItem.isAnnotationPresent(Decorator.class); - } - - public static Set mergeInQualifiers(BeanManagerImpl manager, Collection qualifiers, Annotation[] newQualifiers) { - Set result = new HashSet(); - - if (qualifiers != null && !(qualifiers.isEmpty())) { - result.addAll(qualifiers); - } - if (newQualifiers != null && newQualifiers.length > 0) { - final MetaAnnotationStore store = manager.getServices().get(MetaAnnotationStore.class); - Set checkedNewQualifiers = new HashSet(); - for (Annotation qualifier : newQualifiers) { - if (!store.getBindingTypeModel(qualifier.annotationType()).isValid()) { - throw UtilLogger.LOG.annotationNotQualifier(qualifier); - } - Class annotationType = qualifier.annotationType(); - if (!annotationType.isAnnotationPresent(Repeatable.class)) { - for (Annotation annotation : checkedNewQualifiers) { - if(annotationType.equals(annotation.annotationType())) { - throw UtilLogger.LOG.redundantQualifier(qualifier, Arrays.toString(newQualifiers)); - } - } - } - checkedNewQualifiers.add(qualifier); - } - result.addAll(checkedNewQualifiers); - } - return result; - } - - /** - * Illegal bean types are ignored except for array and primitive types and unless {@link Typed} is used. - * - * @return the set of bean types from an annotated element - */ - public static Set getTypes(EnhancedAnnotated annotated) { - // array and primitive types require special treatment - if (annotated.getJavaClass().isArray() || annotated.getJavaClass().isPrimitive()) { - return ImmutableSet.builder().addAll(annotated.getBaseType(), Object.class).build(); - } else { - if (annotated.isAnnotationPresent(Typed.class)) { - return ImmutableSet.builder().addAll(getTypedTypes(Reflections.buildTypeMap(annotated.getTypeClosure()), - annotated.getJavaClass(), annotated.getAnnotation(Typed.class))).build(); - } else { - if (annotated.getJavaClass().isInterface()) { - return getLegalBeanTypes(annotated.getTypeClosure(), annotated, Object.class); - } - return getLegalBeanTypes(annotated.getTypeClosure(), annotated); - } - } - } - - /** - * Bean types of a bean that uses the {@link Typed} annotation. - */ - public static Set getTypedTypes(Map, Type> typeClosure, Class rawType, Typed typed) { - Set types = new HashSet(); - for (Class specifiedClass : typed.value()) { - Type tmp = typeClosure.get(specifiedClass); - if (tmp != null) { - types.add(tmp); - } else { - throw BeanLogger.LOG.typedClassNotInHierarchy(specifiedClass.getName(), rawType, Formats.formatTypes(typeClosure.values())); - } - } - types.add(Object.class); - return types; - } - - /** - * Indicates if the type is a simple Web Bean - * - * @param clazz The type to inspect - * @return True if simple Web Bean, false otherwise - */ - public static boolean isTypeManagedBeanOrDecoratorOrInterceptor(AnnotatedType annotatedType) { - Class javaClass = annotatedType.getJavaClass(); - return !javaClass.isEnum() && !Extension.class.isAssignableFrom(javaClass) - && Reflections.isTopLevelOrStaticNestedClass(javaClass) && !Reflections.isParameterizedTypeWithWildcard(javaClass) - && hasSimpleCdiConstructor(annotatedType); - } - - /** - * - * @param classFileInfo - * @param checkTypeModifiers - this flag reflects whether Jandex version including fix for JANDEX-37 could be used - * @return - */ - public static boolean isTypeManagedBeanOrDecoratorOrInterceptor(ClassFileInfo classFileInfo, boolean checkTypeModifiers) { - - boolean isTypeManagedBean = ((classFileInfo.getModifiers() & BytecodeUtils.ENUM) == 0) && !classFileInfo.isAssignableTo(Extension.class) - && classFileInfo.hasCdiConstructor() - && (!Modifier.isAbstract(classFileInfo.getModifiers()) || classFileInfo.isAnnotationDeclared(Decorator.class)); - if (checkTypeModifiers) { - return isTypeManagedBean && (classFileInfo.isTopLevelClass() || Modifier.isStatic(classFileInfo.getModifiers())); - } else { - return isTypeManagedBean; - } - } - - public static boolean isDecoratorDeclaringInAppropriateConstructor(ClassFileInfo classFileInfo) { - return !classFileInfo.hasCdiConstructor() && classFileInfo.isAnnotationDeclared(Decorator.class); - } - - public static boolean isDecoratorDeclaringInAppropriateConstructor(AnnotatedType annotatedType) { - return !hasSimpleCdiConstructor(annotatedType) && annotatedType.isAnnotationPresent(Decorator.class); - } - - public static boolean hasSimpleCdiConstructor(AnnotatedType type) { - for (AnnotatedConstructor constructor : type.getConstructors()) { - if (constructor.getParameters().isEmpty()) { - return true; - } - if (constructor.isAnnotationPresent(Inject.class)) { - return true; - } - } - return false; - } - - /** - * Determines if this Java class should be vetoed as a result of presence of {@link Veto} annotations. - */ - public static boolean isVetoed(Class javaClass) { - if (javaClass.isAnnotationPresent(Vetoed.class)) { - return true; - } - return isPackageVetoed(javaClass.getPackage()); - } - - public static boolean isVetoed(AnnotatedType type) { - if (type.isAnnotationPresent(Vetoed.class)) { - return true; - } - return isPackageVetoed(type.getJavaClass().getPackage()); - } - - private static boolean isPackageVetoed(Package pkg) { - return pkg != null && pkg.isAnnotationPresent(Vetoed.class); - } - - /** - * Generates a unique signature for {@link BeanAttributes}. - */ - public static String createBeanAttributesId(BeanAttributes attributes) { - StringBuilder builder = new StringBuilder(); - builder.append(attributes.getName()); + } + } + checkedNewQualifiers.add(qualifier); + } + result.addAll(checkedNewQualifiers); + } + return result; + } + + /** + * Illegal bean types are ignored except for array and primitive types and + * unless {@link Typed} is used. + * + * @return the set of bean types from an annotated element + */ + public static Set getTypes(EnhancedAnnotated annotated) { + // array and primitive types require special treatment + if (annotated.getJavaClass().isArray() || + annotated.getJavaClass().isPrimitive()) { + return ImmutableSet.builder() + .addAll(annotated.getBaseType(), Object.class) + .build(); + } else { + if (annotated.isAnnotationPresent(Typed.class)) { + return ImmutableSet.builder() + .addAll(getTypedTypes( + Reflections.buildTypeMap(annotated.getTypeClosure()), + annotated.getJavaClass(), annotated.getAnnotation(Typed.class))) + .build(); + } else { + if (annotated.getJavaClass().isInterface()) { + return getLegalBeanTypes(annotated.getTypeClosure(), annotated, + Object.class); + } + return getLegalBeanTypes(annotated.getTypeClosure(), annotated); + } + } + } + + /** + * Bean types of a bean that uses the {@link Typed} annotation. + */ + public static Set getTypedTypes(Map, Type> typeClosure, + Class rawType, Typed typed) { + Set types = new HashSet(); + for (Class specifiedClass : typed.value()) { + Type tmp = typeClosure.get(specifiedClass); + if (tmp != null) { + types.add(tmp); + } else { + throw BeanLogger.LOG.typedClassNotInHierarchy( + specifiedClass.getName(), rawType, + Formats.formatTypes(typeClosure.values())); + } + } + types.add(Object.class); + return types; + } + + /** + * Indicates if the type is a simple Web Bean + * + * @param clazz The type to inspect + * @return True if simple Web Bean, false otherwise + */ + public static boolean + isTypeManagedBeanOrDecoratorOrInterceptor(AnnotatedType annotatedType) { + Class javaClass = annotatedType.getJavaClass(); + return !javaClass.isEnum() && + !Extension.class.isAssignableFrom(javaClass) && + Reflections.isTopLevelOrStaticNestedClass(javaClass) && + !Reflections.isParameterizedTypeWithWildcard(javaClass) && + hasSimpleCdiConstructor(annotatedType); + } + + /** + * + * @param classFileInfo + * @param checkTypeModifiers - this flag reflects whether Jandex version + * including fix for JANDEX-37 could be used + * @return + */ + public static boolean + isTypeManagedBeanOrDecoratorOrInterceptor(ClassFileInfo classFileInfo, + boolean checkTypeModifiers) { + + boolean isTypeManagedBean = + ((classFileInfo.getModifiers() & BytecodeUtils.ENUM) == 0) && + !classFileInfo.isAssignableTo(Extension.class) && + classFileInfo.hasCdiConstructor() && + (!Modifier.isAbstract(classFileInfo.getModifiers()) || + classFileInfo.isAnnotationDeclared(Decorator.class)); + if (checkTypeModifiers) { + return isTypeManagedBean && + (classFileInfo.isTopLevelClass() || + Modifier.isStatic(classFileInfo.getModifiers())); + } else { + return isTypeManagedBean; + } + } + + public static boolean + isDecoratorDeclaringInAppropriateConstructor(ClassFileInfo classFileInfo) { + return !classFileInfo.hasCdiConstructor() && + classFileInfo.isAnnotationDeclared(Decorator.class); + } + + public static boolean + isDecoratorDeclaringInAppropriateConstructor(AnnotatedType annotatedType) { + return !hasSimpleCdiConstructor(annotatedType) && + annotatedType.isAnnotationPresent(Decorator.class); + } + + public static boolean hasSimpleCdiConstructor(AnnotatedType type) { + for (AnnotatedConstructor constructor : type.getConstructors()) { + if (constructor.getParameters().isEmpty()) { + return true; + } + if (constructor.isAnnotationPresent(Inject.class)) { + return true; + } + } + return false; + } + + /** + * Determines if this Java class should be vetoed as a result of presence of + * {@link Veto} annotations. + */ + public static boolean isVetoed(Class javaClass) { + if (javaClass.isAnnotationPresent(Vetoed.class)) { + return true; + } + return isPackageVetoed(javaClass.getPackage()); + } + + public static boolean isVetoed(AnnotatedType type) { + if (type.isAnnotationPresent(Vetoed.class)) { + return true; + } + return isPackageVetoed(type.getJavaClass().getPackage()); + } + + private static boolean isPackageVetoed(Package pkg) { + return pkg != null && pkg.isAnnotationPresent(Vetoed.class); + } + + /** + * Generates a unique signature for {@link BeanAttributes}. + */ + public static String createBeanAttributesId(BeanAttributes attributes) { + StringBuilder builder = new StringBuilder(); + builder.append(attributes.getName()); + builder.append(","); + builder.append(attributes.getScope().getName()); + builder.append(","); + builder.append(attributes.isAlternative()); + builder.append(AnnotatedTypes.createAnnotationCollectionId( + attributes.getQualifiers())); + builder.append(createTypeCollectionId(attributes.getStereotypes())); + builder.append(createTypeCollectionId(attributes.getTypes())); + return builder.toString(); + } + + /** + * Generates a unique signature of a collection of types. + */ + public static String + createTypeCollectionId(Collection types) { + StringBuilder builder = new StringBuilder(); + List sortedTypes = new ArrayList(types); + Collections.sort(sortedTypes, TypeComparator.INSTANCE); + builder.append("["); + for (Iterator iterator = sortedTypes.iterator(); + iterator.hasNext();) { + builder.append(createTypeId(iterator.next())); + if (iterator.hasNext()) { builder.append(","); - builder.append(attributes.getScope().getName()); - builder.append(","); - builder.append(attributes.isAlternative()); - builder.append(AnnotatedTypes.createAnnotationCollectionId(attributes.getQualifiers())); - builder.append(createTypeCollectionId(attributes.getStereotypes())); - builder.append(createTypeCollectionId(attributes.getTypes())); - return builder.toString(); - } - - /** - * Generates a unique signature of a collection of types. - */ - public static String createTypeCollectionId(Collection types) { - StringBuilder builder = new StringBuilder(); - List sortedTypes = new ArrayList(types); - Collections.sort(sortedTypes, TypeComparator.INSTANCE); - builder.append("["); - for (Iterator iterator = sortedTypes.iterator(); iterator.hasNext();) { - builder.append(createTypeId(iterator.next())); - if (iterator.hasNext()) { - builder.append(","); - } - } - builder.append("]"); - return builder.toString(); - } - - /** - * Creates a unique signature for a {@link Type}. - */ - private static String createTypeId(Type type) { - if (type instanceof Class) { - return Reflections.> cast(type).getName(); - } - if (type instanceof ParameterizedType) { - ParameterizedType parameterizedType = (ParameterizedType) type; - StringBuilder builder = new StringBuilder(); - builder.append(createTypeId(parameterizedType.getRawType())); - builder.append("<"); - for (int i = 0; i < parameterizedType.getActualTypeArguments().length; i++) { - builder.append(createTypeId(parameterizedType.getActualTypeArguments()[i])); - if (i != parameterizedType.getActualTypeArguments().length - 1) { - builder.append(","); - } - } - builder.append(">"); - return builder.toString(); - } - if (type instanceof TypeVariable) { - return Reflections.> cast(type).getName(); - } - if (type instanceof GenericArrayType) { - return createTypeId(Reflections. cast(type).getGenericComponentType()); - } - throw new java.lang.IllegalArgumentException("Unknown type " + type); - } - - private static class TypeComparator implements Comparator, Serializable { - private static final long serialVersionUID = -2162735176891985078L; - private static final TypeComparator INSTANCE = new TypeComparator(); - - @Override - public int compare(Type o1, Type o2) { - return createTypeId(o1).compareTo(createTypeId(o2)); - } - } - - public static > X checkEnhancedAnnotatedAvailable(X enhancedAnnotated) { - if (enhancedAnnotated == null) { - throw new IllegalStateException("Enhanced metadata should not be used at runtime."); - } - return enhancedAnnotated; - } - - public static boolean hasBuiltinScope(Bean bean) { - return RequestScoped.class.equals(bean.getScope()) || SessionScoped.class.equals(bean.getScope()) || ApplicationScoped.class.equals(bean.getScope()) - || ConversationScoped.class.equals(bean.getScope()) || Dependent.class.equals(bean.getScope()); - } - - public static Class getBeanDefiningAnnotationScope(AnnotatedType annotatedType) { - for (Annotation annotation : annotatedType.getAnnotations()) { - if (annotation.annotationType().isAnnotationPresent(NormalScope.class) || annotation.annotationType().equals(Dependent.class)) { - return annotation.annotationType(); - } - } - return null; - } - - /** - * @param types The initial set of types - * @param annotated - * @param additionalTypes Types to add to the initial set - * @return the set of legal bean types - */ - public static Set getLegalBeanTypes(Set types, Object baseType, Type... additionalTypes) { - if (additionalTypes != null && additionalTypes.length > 0) { - // Micro-optimization is not possible - return omitIllegalBeanTypes(types, baseType).addAll(additionalTypes).build(); - } - for (Type type : types) { - if (Types.isIllegalBeanType(type)) { - return omitIllegalBeanTypes(types, baseType).build(); - } - } - return types; - } - - static ImmutableSet.Builder omitIllegalBeanTypes(Set types, Object baseType) { - ImmutableSet.Builder builder = ImmutableSet.builder(); - for (Type type : types) { - if (Types.isIllegalBeanType(type)) { - MetadataLogger.LOG.illegalBeanTypeIgnored(type, baseType); - } else { - builder.add(type); - } - } - return builder; - } - - /** - * @param contextual - * @param contextualStore - * @return the identifier for the given contextual - * @see #getIdentifier(Contextual, ContextualStore, ServiceRegistry) - */ - public static BeanIdentifier getIdentifier(Contextual contextual, ContextualStore contextualStore) { - return getIdentifier(contextual, contextualStore, null); - } - - /** - * @param contextual - * @param serviceRegistry - * @return the identifier for the given contextual - * @see #getIdentifier(Contextual, ContextualStore, ServiceRegistry) - */ - public static BeanIdentifier getIdentifier(Contextual contextual, ServiceRegistry serviceRegistry) { - return getIdentifier(contextual, null, serviceRegistry); - } - - /** - * - * @param bean - * @return true if final methods should be ignored when checking proxyability - */ - public static boolean shouldIgnoreFinalMethods(Bean bean) { - if (bean instanceof AbstractBean) { - AbstractBean abstractBean = (AbstractBean) bean; - return abstractBean.isIgnoreFinalMethods(); - } - return false; - } - - public static Bean unwrap(Bean bean) { - if (bean instanceof ForwardingBean) { - ForwardingBean forwarding = (ForwardingBean) bean; - return forwarding.delegate(); - } - return bean; - } - - /** - * A slightly optimized way to get the bean identifier - there is not need to call ContextualStore.putIfAbsent() for passivation capable beans because it's - * already called during bootstrap. See also {@link BeanManagerImpl#addBean(Bean)}. - * - * @param contextual - * @param contextualStore - * @param serviceRegistry - * @return the identifier for the given contextual - */ - private static BeanIdentifier getIdentifier(Contextual contextual, ContextualStore contextualStore, ServiceRegistry serviceRegistry) { - if (contextual instanceof RIBean) { - return ((RIBean) contextual).getIdentifier(); - } - if (contextualStore == null) { - contextualStore = serviceRegistry.get(ContextualStore.class); - } - return contextualStore.putIfAbsent(contextual); - } - + } + } + builder.append("]"); + return builder.toString(); + } + + /** + * Creates a unique signature for a {@link Type}. + */ + private static String createTypeId(Type type) { + if (type instanceof Class) { + return Reflections.>cast(type).getName(); + } + if (type instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType)type; + StringBuilder builder = new StringBuilder(); + builder.append(createTypeId(parameterizedType.getRawType())); + builder.append("<"); + for (int i = 0; i < parameterizedType.getActualTypeArguments().length; + i++) { + builder.append( + createTypeId(parameterizedType.getActualTypeArguments()[i])); + if (i != parameterizedType.getActualTypeArguments().length - 1) { + builder.append(","); + } + } + builder.append(">"); + return builder.toString(); + } + if (type instanceof TypeVariable) { + return Reflections.>cast(type).getName(); + } + if (type instanceof GenericArrayType) { + return createTypeId( + Reflections.cast(type).getGenericComponentType()); + } + throw new java.lang.IllegalArgumentException("Unknown type " + type); + } + + private static class TypeComparator + implements Comparator, Serializable { + private static final long serialVersionUID = -2162735176891985078L; + private static final TypeComparator INSTANCE = new TypeComparator(); + + @Override + public int compare(Type o1, Type o2) { + return createTypeId(o1).compareTo(createTypeId(o2)); + } + } + + public static > + X checkEnhancedAnnotatedAvailable(X enhancedAnnotated) { + if (enhancedAnnotated == null) { + throw new IllegalStateException( + "Enhanced metadata should not be used at runtime."); + } + return enhancedAnnotated; + } + + public static boolean hasBuiltinScope(Bean bean) { + return RequestScoped.class.equals(bean.getScope()) || + SessionScoped.class.equals(bean.getScope()) || + ApplicationScoped.class.equals(bean.getScope()) || + ConversationScoped.class.equals(bean.getScope()) || + Dependent.class.equals(bean.getScope()); + } + + public static Class + getBeanDefiningAnnotationScope(AnnotatedType annotatedType) { + for (Annotation annotation : annotatedType.getAnnotations()) { + if (annotation.annotationType().isAnnotationPresent(NormalScope.class) || + annotation.annotationType().equals(Dependent.class)) { + return annotation.annotationType(); + } + } + return null; + } + + /** + * @param types The initial set of types + * @param annotated + * @param additionalTypes Types to add to the initial set + * @return the set of legal bean types + */ + public static Set getLegalBeanTypes(Set types, Object baseType, + Type... additionalTypes) { + if (additionalTypes != null && additionalTypes.length > 0) { + // Micro-optimization is not possible + return omitIllegalBeanTypes(types, baseType) + .addAll(additionalTypes) + .build(); + } + for (Type type : types) { + if (Types.isIllegalBeanType(type)) { + return omitIllegalBeanTypes(types, baseType).build(); + } + } + return types; + } + + static ImmutableSet.Builder omitIllegalBeanTypes(Set types, + Object baseType) { + ImmutableSet.Builder builder = ImmutableSet.builder(); + for (Type type : types) { + if (Types.isIllegalBeanType(type)) { + MetadataLogger.LOG.illegalBeanTypeIgnored(type, baseType); + } else { + builder.add(type); + } + } + return builder; + } + + /** + * @param contextual + * @param contextualStore + * @return the identifier for the given contextual + * @see #getIdentifier(Contextual, ContextualStore, ServiceRegistry) + */ + public static BeanIdentifier getIdentifier(Contextual contextual, + ContextualStore contextualStore) { + return getIdentifier(contextual, contextualStore, null); + } + + /** + * @param contextual + * @param serviceRegistry + * @return the identifier for the given contextual + * @see #getIdentifier(Contextual, ContextualStore, ServiceRegistry) + */ + public static BeanIdentifier getIdentifier(Contextual contextual, + ServiceRegistry serviceRegistry) { + return getIdentifier(contextual, null, serviceRegistry); + } + + /** + * + * @param bean + * @return true if final methods should be ignored when checking + * proxyability + */ + public static boolean shouldIgnoreFinalMethods(Bean bean) { + if (bean instanceof AbstractBean) { + AbstractBean abstractBean = (AbstractBean)bean; + return abstractBean.isIgnoreFinalMethods(); + } + return false; + } + + public static Bean unwrap(Bean bean) { + if (bean instanceof ForwardingBean) { + ForwardingBean forwarding = (ForwardingBean)bean; + return forwarding.delegate(); + } + return bean; + } + + /** + * A slightly optimized way to get the bean identifier - there is not need to + * call ContextualStore.putIfAbsent() for passivation capable beans because + * it's already called during bootstrap. See also {@link + * BeanManagerImpl#addBean(Bean)}. + * + * @param contextual + * @param contextualStore + * @param serviceRegistry + * @return the identifier for the given contextual + */ + private static BeanIdentifier getIdentifier(Contextual contextual, + ContextualStore contextualStore, + ServiceRegistry serviceRegistry) { + if (contextual instanceof RIBean) { + return ((RIBean)contextual).getIdentifier(); + } + if (contextualStore == null) { + contextualStore = serviceRegistry.get(ContextualStore.class); + } + return contextualStore.putIfAbsent(contextual); + } } diff --git a/impl/src/main/java/org/jboss/weld/util/CustomClassComparator.java b/impl/src/main/java/org/jboss/weld/util/CustomClassComparator.java new file mode 100644 index 0000000000..1d6fc1d87b --- /dev/null +++ b/impl/src/main/java/org/jboss/weld/util/CustomClassComparator.java @@ -0,0 +1,65 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.util; + +import java.util.Comparator; + +/** + * This comparator sorts classes alphabetically based on {@link Class#getName()} + * with notable difference that all classes starting with {@code java.*} or + * {@code javax.*} come after all other classes. + * + * E.g. a set of these classes {javax.bar.Baz, java.something.Foo, bar.baz.Quax, + * mypackage.indeed.SomeBean} would be sorted in the following manner - + * {bar.baz.Quax, mypackage.indeed.SomeBean, java.something.Foo, javax.bar.Baz}. + */ +public class CustomClassComparator implements Comparator> { + + private final String javaPrefix = "java."; + private final String javaxPrefix = "javax."; + + @Override + public int compare(Class o1, Class o2) { + String firstClassName = o1.getName(); + String secondClassName = o2.getName(); + // if no class starts with java.* or javax.* or if both start with it, + // perform standard comparison if only one starts with this prefix, it goes + // later + boolean firstClassHasJavaPrefix = firstClassName.startsWith(javaPrefix) || + firstClassName.startsWith(javaxPrefix); + boolean secondClassHasJavaPrefix = secondClassName.startsWith(javaPrefix) || + secondClassName.startsWith(javaxPrefix); + if (firstClassHasJavaPrefix) { + if (secondClassHasJavaPrefix) { + // both classes prefixed + return firstClassName.compareTo(secondClassName); + } else { + // first class prefixed, second class not + return 1; + } + } else { + if (secondClassHasJavaPrefix) { + // first class is not prefixed, second class is + return -1; + } else { + // neither class is prefixed + return firstClassName.compareTo(secondClassName); + } + } + } +} diff --git a/impl/src/main/java/org/jboss/weld/util/Proxies.java b/impl/src/main/java/org/jboss/weld/util/Proxies.java index a77f357acf..e2d6e62064 100644 --- a/impl/src/main/java/org/jboss/weld/util/Proxies.java +++ b/impl/src/main/java/org/jboss/weld/util/Proxies.java @@ -21,14 +21,17 @@ import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; import java.util.Set; - import javax.enterprise.inject.spi.Bean; - import org.jboss.weld.bean.proxy.ProxyInstantiator; import org.jboss.weld.bootstrap.api.ServiceRegistry; import org.jboss.weld.config.WeldConfiguration; @@ -36,6 +39,8 @@ import org.jboss.weld.logging.UtilLogger; import org.jboss.weld.logging.ValidatorLogger; import org.jboss.weld.util.collections.Arrays2; +import org.jboss.weld.util.collections.ImmutableList; +import org.jboss.weld.util.collections.ImmutableMap; import org.jboss.weld.util.reflection.Reflections; /** @@ -49,230 +54,281 @@ @SuppressWarnings({"ThrowableResultOfMethodCallIgnored", "NullableProblems"}) public class Proxies { - public static class TypeInfo { + public static class TypeInfo { - private final Set> interfaces; - private final Set> classes; + private static final String DEFAULT_PACKAGE = ""; - private TypeInfo() { - super(); - this.interfaces = new LinkedHashSet>(); - this.classes = new LinkedHashSet>(); - } + private final List> interfaces; + private final List> classes; + private final Map classToPackageMap; - public Class getSuperClass() { - if (classes.isEmpty()) { - return Object.class; - } - Iterator> it = classes.iterator(); - Class superclass = it.next(); - while (it.hasNext()) { - Class clazz = it.next(); - if (superclass.isAssignableFrom(clazz)) { - superclass = clazz; - } - } - return superclass; - } + private TypeInfo(Set types) { + List> foundInterfaces = new ArrayList<>(); + List> foundClasses = new ArrayList<>(); + Map classToPackage = new HashMap<>(); - public Class getSuperInterface() { - if (interfaces.isEmpty()) { - return null; - } - Iterator> it = interfaces.iterator(); - Class superclass = it.next(); - while (it.hasNext()) { - Class clazz = it.next(); - if (superclass.isAssignableFrom(clazz)) { - superclass = clazz; - } - } - return superclass; - } + types.stream().forEach( + type -> add(type, foundInterfaces, foundClasses, classToPackage)); - private TypeInfo add(Type type) { - if (type instanceof Class) { - Class clazz = (Class) type; - if (clazz.isInterface()) { - interfaces.add(clazz); - } else { - classes.add(clazz); - } - } else if (type instanceof ParameterizedType) { - add(((ParameterizedType) type).getRawType()); - } else { - throw UtilLogger.LOG.cannotProxyNonClassType(type); - } - return this; - } + // sort both collections and create immutable collections + Collections.sort(foundClasses, Comparator.comparing(Class::getName)); + Collections.sort(foundInterfaces, new CustomClassComparator()); + this.interfaces = ImmutableList.copyOf(foundInterfaces); + this.classes = ImmutableList.copyOf(foundClasses); + this.classToPackageMap = ImmutableMap.copyOf(classToPackage); + } - public Set> getClasses() { - return Collections.unmodifiableSet(classes); + // only invoked during object construction, arrays are then immutable + private TypeInfo add(Type type, List> foundInterfaces, + List> foundClasses, + Map classToPackageMap) { + if (type instanceof Class) { + Class clazz = (Class)type; + classToPackageMap.put(clazz.getName(), + clazz.getPackage() == null + ? DEFAULT_PACKAGE + : clazz.getPackage().getName()); + if (clazz.isInterface()) { + foundInterfaces.add(clazz); + } else { + foundClasses.add(clazz); } + } else if (type instanceof ParameterizedType) { + add(((ParameterizedType)type).getRawType(), foundInterfaces, + foundClasses, classToPackageMap); + } else { + throw UtilLogger.LOG.cannotProxyNonClassType(type); + } + return this; + } - public Set> getInterfaces() { - return Collections.unmodifiableSet(interfaces); + public Class getSuperClass() { + if (classes.isEmpty()) { + return Object.class; + } + Iterator> it = classes.iterator(); + Class superclass = it.next(); + while (it.hasNext()) { + Class clazz = it.next(); + if (superclass.isAssignableFrom(clazz)) { + superclass = clazz; } + } + return superclass; + } - public static TypeInfo of(Set types) { - TypeInfo typeInfo = new TypeInfo(); - for (Type type : types) { - typeInfo.add(type); - } - return typeInfo; + public Class getSuperInterface() { + if (interfaces.isEmpty()) { + return null; + } + Iterator> it = interfaces.iterator(); + Class superclass = it.next(); + while (it.hasNext()) { + Class clazz = it.next(); + if (superclass.isAssignableFrom(clazz)) { + superclass = clazz; } - + } + return superclass; } - private Proxies() { - } + public List> getClasses() { return classes; } - /** - * Indicates if a class is proxyable - * - * @param type The class to test - * @return True if proxyable, false otherwise - */ - public static boolean isTypeProxyable(Type type, ServiceRegistry services) { - return getUnproxyableTypeException(type, services) == null; - } + public List> getInterfaces() { return interfaces; } - public static UnproxyableResolutionException getUnproxyableTypeException(Type type, ServiceRegistry services) { - return getUnproxyableTypeException(type, null, services, false); + public String getPackageNameForClass(Class clazz) { + return classToPackageMap.get(clazz.getName()); } - /** - * Indicates if a set of types are all proxyable - * - * @param declaringBean with types to test - * @return True if proxyable, false otherwise - */ - public static boolean isTypesProxyable(Bean declaringBean, ServiceRegistry services) { - return getUnproxyableTypesException(declaringBean, services) == null; + public static TypeInfo of(Set types) { + return new TypeInfo(types); } - - /** - * Indicates if a set of types are all proxyable - * - * @param types The types to test - * @return True if proxyable, false otherwise - */ - public static boolean isTypesProxyable(Iterable types, ServiceRegistry services) { - return getUnproxyableTypesException(types, services) == null; + } + + private Proxies() {} + + /** + * Indicates if a class is proxyable + * + * @param type The class to test + * @return True if proxyable, false otherwise + */ + public static boolean isTypeProxyable(Type type, ServiceRegistry services) { + return getUnproxyableTypeException(type, services) == null; + } + + public static UnproxyableResolutionException + getUnproxyableTypeException(Type type, ServiceRegistry services) { + return getUnproxyableTypeException(type, null, services, false); + } + + /** + * Indicates if a set of types are all proxyable + * + * @param declaringBean with types to test + * @return True if proxyable, false otherwise + */ + public static boolean isTypesProxyable(Bean declaringBean, + ServiceRegistry services) { + return getUnproxyableTypesException(declaringBean, services) == null; + } + + /** + * Indicates if a set of types are all proxyable + * + * @param types The types to test + * @return True if proxyable, false otherwise + */ + public static boolean isTypesProxyable(Iterable types, + ServiceRegistry services) { + return getUnproxyableTypesException(types, services) == null; + } + + public static UnproxyableResolutionException + getUnproxyableTypesException(Bean declaringBean, + ServiceRegistry services) { + if (declaringBean == null) { + throw new java.lang.IllegalArgumentException("Null declaring bean!"); } - public static UnproxyableResolutionException getUnproxyableTypesException(Bean declaringBean, ServiceRegistry services) { - if (declaringBean == null) { - throw new java.lang.IllegalArgumentException("Null declaring bean!"); - } - - return getUnproxyableTypesExceptionInt(declaringBean.getTypes(), declaringBean, services); + return getUnproxyableTypesExceptionInt(declaringBean.getTypes(), + declaringBean, services); + } + + public static UnproxyableResolutionException + getUnproxyableTypesException(Iterable types, + ServiceRegistry services) { + return getUnproxyableTypesExceptionInt(types, null, services); + } + + public static UnproxyableResolutionException + getUnproxyableTypeException(Type type, Bean declaringBean, + ServiceRegistry services, + boolean ignoreFinalMethods) { + if (type instanceof Class || type instanceof ParameterizedType || + type instanceof GenericArrayType) { + return getUnproxyableClassException(Reflections.getRawType(type), + declaringBean, services, + ignoreFinalMethods); } - - public static UnproxyableResolutionException getUnproxyableTypesException(Iterable types, ServiceRegistry services) { - return getUnproxyableTypesExceptionInt(types, null, services); + return ValidatorLogger.LOG.notProxyableUnknown( + type, getDeclaringBeanInfo(declaringBean)); + } + + // --- private + + private static UnproxyableResolutionException + getUnproxyableTypesExceptionInt(Iterable types, + Bean declaringBean, + ServiceRegistry services) { + for (Type apiType : types) { + if (Object.class.equals(apiType)) { + continue; + } + UnproxyableResolutionException e = + getUnproxyableTypeException(apiType, declaringBean, services, false); + if (e != null) { + return e; + } } - - public static UnproxyableResolutionException getUnproxyableTypeException(Type type, Bean declaringBean, ServiceRegistry services, boolean ignoreFinalMethods) { - if (type instanceof Class || type instanceof ParameterizedType || type instanceof GenericArrayType) { - return getUnproxyableClassException(Reflections.getRawType(type), declaringBean, services, ignoreFinalMethods); - } - return ValidatorLogger.LOG.notProxyableUnknown(type, getDeclaringBeanInfo(declaringBean)); + return null; + } + + private static UnproxyableResolutionException + getUnproxyableClassException(Class clazz, Bean declaringBean, + ServiceRegistry services, + boolean ignoreFinalMethods) { + if (clazz.isInterface()) { + return null; } - // --- private - - private static UnproxyableResolutionException getUnproxyableTypesExceptionInt(Iterable types, Bean declaringBean, ServiceRegistry services) { - for (Type apiType : types) { - if (Object.class.equals(apiType)) { - continue; - } - UnproxyableResolutionException e = getUnproxyableTypeException(apiType, declaringBean, services, false); - if (e != null) { - return e; - } - } - return null; + Constructor constructor = null; + try { + constructor = SecurityActions.getDeclaredConstructor(clazz); + } catch (Exception ignored) { } - private static UnproxyableResolutionException getUnproxyableClassException(Class clazz, Bean declaringBean, ServiceRegistry services, - boolean ignoreFinalMethods) { - if (clazz.isInterface()) { - return null; - } - - Constructor constructor = null; - try { - constructor = SecurityActions.getDeclaredConstructor(clazz); - } catch (Exception ignored) { - } - - if (clazz.isPrimitive()) { - return ValidatorLogger.LOG.notProxyablePrimitive(clazz, getDeclaringBeanInfo(declaringBean)); - } else if (Reflections.isArrayType(clazz)) { - return ValidatorLogger.LOG.notProxyableArrayType(clazz, getDeclaringBeanInfo(declaringBean)); - } else if (Reflections.isFinal(clazz)) { - return ValidatorLogger.LOG.notProxyableFinalType(clazz, getDeclaringBeanInfo(declaringBean)); + if (clazz.isPrimitive()) { + return ValidatorLogger.LOG.notProxyablePrimitive( + clazz, getDeclaringBeanInfo(declaringBean)); + } else if (Reflections.isArrayType(clazz)) { + return ValidatorLogger.LOG.notProxyableArrayType( + clazz, getDeclaringBeanInfo(declaringBean)); + } else if (Reflections.isFinal(clazz)) { + return ValidatorLogger.LOG.notProxyableFinalType( + clazz, getDeclaringBeanInfo(declaringBean)); + } else { + Method finalMethod = Reflections.getNonPrivateNonStaticFinalMethod(clazz); + if (finalMethod != null) { + if (ignoreFinalMethods || + Beans.shouldIgnoreFinalMethods(declaringBean) || + services.get(WeldConfiguration.class) + .isFinalMethodIgnored(clazz.getName())) { + ValidatorLogger.LOG.notProxyableFinalMethodIgnored( + finalMethod, getDeclaringBeanInfo(declaringBean)); } else { - Method finalMethod = Reflections.getNonPrivateNonStaticFinalMethod(clazz); - if (finalMethod != null) { - if (ignoreFinalMethods || Beans.shouldIgnoreFinalMethods(declaringBean) - || services.get(WeldConfiguration.class).isFinalMethodIgnored(clazz.getName())) { - ValidatorLogger.LOG.notProxyableFinalMethodIgnored(finalMethod, getDeclaringBeanInfo(declaringBean)); - } else { - return ValidatorLogger.LOG.notProxyableFinalMethod(clazz, finalMethod, getDeclaringBeanInfo(declaringBean)); - } - } + return ValidatorLogger.LOG.notProxyableFinalMethod( + clazz, finalMethod, getDeclaringBeanInfo(declaringBean)); } - - UnproxyableResolutionException exception = services.get(ProxyInstantiator.class).validateNoargConstructor(constructor, clazz, declaringBean); - if (exception != null) { - return exception; - } - - return null; + } } - public static Object getDeclaringBeanInfo(Bean bean) { - return (bean != null) ? bean : ""; + UnproxyableResolutionException exception = + services.get(ProxyInstantiator.class) + .validateNoargConstructor(constructor, clazz, declaringBean); + if (exception != null) { + return exception; } - /** - * - * @param interfaces - * @return the sorted set of interfaces - */ - public static LinkedHashSet> sortInterfacesHierarchy(Set> interfaces) { - LinkedHashSet> sorted = new LinkedHashSet<>(interfaces.size()); - processSuperinterface(null, interfaces, sorted); - if (interfaces.size() != sorted.size()) { - // Interface may not processed due to incomplete type closure - Set> unprocessed = new HashSet<>(interfaces); - unprocessed.removeAll(sorted); - for (Class unprocessedInterface : unprocessed) { - processSuperinterface(unprocessedInterface, interfaces, sorted); - sorted.add(unprocessedInterface); - } - } - return sorted; + return null; + } + + public static Object getDeclaringBeanInfo(Bean bean) { + return (bean != null) + ? bean + : ""; + } + + /** + * + * @param interfaces + * @return the sorted set of interfaces + */ + public static LinkedHashSet> + sortInterfacesHierarchy(Set> interfaces) { + LinkedHashSet> sorted = new LinkedHashSet<>(interfaces.size()); + processSuperinterface(null, interfaces, sorted); + if (interfaces.size() != sorted.size()) { + // Interface may not processed due to incomplete type closure + Set> unprocessed = new HashSet<>(interfaces); + unprocessed.removeAll(sorted); + for (Class unprocessedInterface : unprocessed) { + processSuperinterface(unprocessedInterface, interfaces, sorted); + sorted.add(unprocessedInterface); + } } - - private static void processSuperinterface(Class superinterface, Set> interfaces, LinkedHashSet> sorted) { - for (Class interfaceClass : interfaces) { - if (isInterfaceExtending(interfaceClass, superinterface)) { - processSuperinterface(interfaceClass, interfaces, sorted); - sorted.add(interfaceClass); - } - } + return sorted; + } + + private static void processSuperinterface(Class superinterface, + Set> interfaces, + LinkedHashSet> sorted) { + for (Class interfaceClass : interfaces) { + if (isInterfaceExtending(interfaceClass, superinterface)) { + processSuperinterface(interfaceClass, interfaces, sorted); + sorted.add(interfaceClass); + } } - - private static boolean isInterfaceExtending(Class interfaceClass, Class superinterface) { - if (interfaceClass.equals(superinterface)) { - return false; - } else if (superinterface == null) { - return interfaceClass.getInterfaces().length == 0; - } else { - return Arrays2.contains(interfaceClass.getInterfaces(), superinterface); - } + } + + private static boolean isInterfaceExtending(Class interfaceClass, + Class superinterface) { + if (interfaceClass.equals(superinterface)) { + return false; + } else if (superinterface == null) { + return interfaceClass.getInterfaces().length == 0; + } else { + return Arrays2.contains(interfaceClass.getInterfaces(), superinterface); } + } } diff --git a/impl/src/main/java/org/jboss/weld/util/bytecode/ClassFileUtils.java b/impl/src/main/java/org/jboss/weld/util/bytecode/ClassFileUtils.java deleted file mode 100644 index 1316d16ff8..0000000000 --- a/impl/src/main/java/org/jboss/weld/util/bytecode/ClassFileUtils.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * JBoss, Home of Professional Open Source - * Copyright 2008, Red Hat, Inc., and individual contributors - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * Licensed 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.jboss.weld.util.bytecode; - -import org.jboss.classfilewriter.ClassFile; -import org.jboss.weld.serialization.spi.ProxyServices; - -import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.security.ProtectionDomain; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Utility class for loading a ClassFile into a classloader. Allows to use either old approach directly via CL - * methods, or delegation to integrator through {@code ProxyServices}. - * - * Also contains logic needed to crack open CL methods should that approach be used - this is invoked from WeldStartup. - * - * As we need to be able to define classes with different ProtectionDomain, we still have to crack open CL methods - * via setAccessible() which means there will be IllegalAccess warnings. Unsafe is no longer an option on JDK 12+.. - * This mostly concerns Weld SE, EE integrators should already go through new SPI hence avoiding this problem. - * - * @author Stuart Douglas - * @author Matej Novotny - */ -public class ClassFileUtils { - - private static java.lang.reflect.Method defineClass1, defineClass2; - private static AtomicBoolean classLoaderMethodsMadeAccessible = new AtomicBoolean(false); - - private ClassFileUtils() { - } - - /** - * This method cracks open {@code ClassLoader#defineClass()} methods by calling {@code setAccessible()}. - * - * It is invoked during {@code WeldStartup#startContainer()} and only in case the integrator does not - * fully implement {@link ProxyServices}. - **/ - public static void makeClassLoaderMethodsAccessible() { - // the AtomicBoolean make sure this gets invoked only once as WeldStartup is triggered per deployment - if (classLoaderMethodsMadeAccessible.compareAndSet(false, true)) { - try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws Exception { - Class cl = Class.forName("java.lang.ClassLoader"); - final String name = "defineClass"; - - defineClass1 = cl.getDeclaredMethod(name, String.class, byte[].class, int.class, int.class); - defineClass2 = cl.getDeclaredMethod(name, String.class, byte[].class, int.class, int.class, ProtectionDomain.class); - defineClass1.setAccessible(true); - defineClass2.setAccessible(true); - return null; - } - }); - } catch (PrivilegedActionException pae) { - throw new RuntimeException("cannot initialize ClassPool", pae.getException()); - } - } - } - - /** - * Converts the class to a java.lang.Class object. Once this method is called, further modifications are not - * allowed any more. - *

- *

- * The class file represented by the given CtClass is loaded by the given class loader to construct a - * java.lang.Class object. Since a private method on the class loader is invoked through the reflection API, - * the caller must have permissions to do that. - *

- *

- * An easy way to obtain ProtectionDomain object is to call getProtectionDomain() in - * java.lang.Class. It returns the domain that the class belongs to. - *

- *

- * This method is provided for convenience. If you need more complex functionality, you should write your own class loader. - * - * @param loader the class loader used to load this class. For example, the loader returned by getClassLoader() - * can be used for this parameter. - * @param domain the protection domain for the class. If it is null, the default domain created by - * java.lang.ClassLoader is - */ - public static Class toClass(ClassFile ct, ClassLoader loader, ProtectionDomain domain) { - try { - byte[] b = ct.toBytecode(); - java.lang.reflect.Method method; - Object[] args; - if (domain == null) { - method = defineClass1; - args = new Object[] { ct.getName(), b, 0, b.length }; - } else { - method = defineClass2; - args = new Object[] { ct.getName(), b, 0, b.length, domain }; - } - - return toClass2(method, loader, args); - } catch (RuntimeException e) { - throw e; - } catch (java.lang.reflect.InvocationTargetException e) { - throw new RuntimeException(e.getTargetException()); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * Delegates proxy creation via {@link ProxyServices} to the integrator. - */ - public static Class toClass(ClassFile ct, Class originalClass, ProxyServices proxyServices, ProtectionDomain domain) { - try { - byte[] bytecode = ct.toBytecode(); - Class result; - if (domain == null) { - result = proxyServices.defineClass(originalClass, ct.getName(), bytecode, 0, bytecode.length); - } else { - result = proxyServices.defineClass(originalClass, ct.getName(), bytecode, 0, bytecode.length, domain); - } - return result; - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private static synchronized Class toClass2(Method method, ClassLoader loader, Object[] args) throws Exception { - Class clazz = Class.class.cast(method.invoke(loader, args)); - return clazz; - } - -} diff --git a/impl/src/main/java11/org/jboss/weld/bean/proxy/util/WeldDefaultProxyServices.java b/impl/src/main/java11/org/jboss/weld/bean/proxy/util/WeldDefaultProxyServices.java new file mode 100644 index 0000000000..269b785b88 --- /dev/null +++ b/impl/src/main/java11/org/jboss/weld/bean/proxy/util/WeldDefaultProxyServices.java @@ -0,0 +1,240 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.bean.proxy.util; + +import java.lang.invoke.MethodHandles; +import java.security.ProtectionDomain; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import org.jboss.weld.bean.proxy.ProxyFactory; +import org.jboss.weld.exceptions.UnsupportedOperationException; +import org.jboss.weld.logging.BeanLogger; +import org.jboss.weld.serialization.spi.ProxyServices; + +/** + * This class is a default implementation of ProxyServices that will only be + * loaded if no other implementation is detected. It supports class defining and + * attempts to use {@link MethodHandles.Lookup} if possible making it JDK 11+ + * friendly. For classes in signed JARs and classes from Java internal packages, + * we are forced to use custom class loader. + */ +public class WeldDefaultProxyServices implements ProxyServices { + + // a map of parent CL -> our CL serving as a cache + private ConcurrentMap clMap = + new ConcurrentHashMap(); + + public ClassLoader getClassLoader(final Class proxiedBeanType) { + throw new UnsupportedOperationException( + "WeldDefaultProxyServices.getClassLoader(Class) is not " + + "implemented."); + } + + public Class loadBeanClass(final String className) { + throw new UnsupportedOperationException( + "WeldDefaultProxyServices.loadBeanClass(String) is not implemented."); + } + + @Override + public Class defineClass(Class originalClass, String className, + byte[] classBytes, int off, int len) + throws ClassFormatError { + return defineClass(originalClass, className, classBytes, off, len, null); + } + + @Override + public Class defineClass(Class originalClass, String className, + byte[] classBytes, int off, int len, + ProtectionDomain protectionDomain) + throws ClassFormatError { + ClassLoader originalLoader = originalClass.getClassLoader(); + if (originalLoader == null) { + originalLoader = Thread.currentThread().getContextClassLoader(); + // is it's still null we cannot solve this issue and we need to throw an + // exception + if (originalLoader == null) { + throw BeanLogger.LOG.cannotDetermineClassLoader(className, + originalClass); + } + } + try { + // this is one of the classes we define into our own packages, we need to + // use a CL approach + if (className.startsWith(ProxyFactory.WELD_PROXY_PREFIX)) { + return defineWithClassLoader(className, classBytes, classBytes.length, + originalLoader, protectionDomain); + } else { + // these classes go into existing packages, we will use MethodHandles to + // define them + return defineWithMethodLookup(className, classBytes, originalClass, + originalLoader); + } + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public Class loadClass(Class originalClass, String classBinaryName) + throws ClassNotFoundException { + ClassLoader loader = originalClass.getClassLoader(); + // if the CL is null, we will use TCCL + if (loader == null) { + loader = Thread.currentThread().getContextClassLoader(); + // the following should not happen, but if it does, we need to throw an + // exception + if (loader == null) { + throw BeanLogger.LOG.cannotDetermineClassLoader(classBinaryName, + originalClass); + } + } + if (clMap.containsKey(loader)) { + loader = clMap.get(loader); + } + return loader.loadClass(classBinaryName); + } + + @Override + public boolean supportsClassDefining() { + return true; + } + + @Override + public void cleanup() { + clMap.clear(); + } + + /** + * Defines the proxy with {@link WeldProxyDeclaringCL}. + * + * @param classToDefineName name of the class to be defined + * @param classBytes class bytes + * @param length length of the class data + * @param loader class loader to be wrapped + * @param domain {@link ProtectionDomain} + * @return + */ + private Class defineWithClassLoader(String classToDefineName, + byte[] classBytes, int length, + ClassLoader loader, + ProtectionDomain domain) { + WeldProxyDeclaringCL delegatingClassLoader = returnWeldCL(loader); + if (domain == null) { + return delegatingClassLoader.publicDefineClass(classToDefineName, + classBytes, 0, length); + } else { + return delegatingClassLoader.publicDefineClass( + classToDefineName, classBytes, 0, length, domain); + } + } + + /** + * For a given {@link ClassLoader}, return relevant {@link + * WeldProxyDeclaringCL}. + * + * @param loader class loader + * @return instance of {@link WeldProxyDeclaringCL} + */ + private WeldProxyDeclaringCL returnWeldCL(ClassLoader loader) { + if (loader instanceof WeldProxyDeclaringCL) { + return (WeldProxyDeclaringCL)loader; + } + return clMap.computeIfAbsent(loader, cl -> new WeldProxyDeclaringCL(cl)); + } + + /** + * Defines the proxy using {@link MethodHandles.Lookup}. + * + * @param classToDefineName name of the class to be defined + * @param classBytes class bytes + * @param originalClass the original class from which we derived this proxy; + * this is used to get {@Lookup} object + * @param loader class loader that loaded the original class + * @return + */ + private Class defineWithMethodLookup(String classToDefineName, + byte[] classBytes, + Class originalClass, + ClassLoader loader) { + Module thisModule = WeldDefaultProxyServices.class.getModule(); + try { + Class lookupBaseClass; + try { + // In case of decorators, it looks like we sometimes need the original + // class instead + lookupBaseClass = loader.loadClass( + classToDefineName.substring(0, classToDefineName.indexOf("$"))); + } catch (Exception e) { + lookupBaseClass = originalClass; + } + Module lookupClassModule = lookupBaseClass.getModule(); + if (!thisModule.canRead(lookupClassModule)) { + // we need to read the other module in order to have privateLookup + // access see javadoc for MethodHandles.privateLookupIn() + thisModule.addReads(lookupClassModule); + } + MethodHandles.Lookup lookup = MethodHandles.privateLookupIn( + lookupBaseClass, MethodHandles.lookup()); + return lookup.defineClass(classBytes); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + /** + * NOOP under JDK 11+ + */ + public static void makeClassLoaderMethodsAccessible() {} + + /** + * A class loader that should only be used to load Weld-prefixed proxies + * meaning those that have non-existent packages. This is a workaround for + * JMPS approach ({@code MethodHandles.Lookup}) not being able to fulfil this + * scenario. + * + * This CL will cause issues if used to define proxies for beans with private + * access (which shouldn't happen). It also makes (de)serialization) difficult + * because no other CL will know of our proxies. + */ + private class WeldProxyDeclaringCL extends ClassLoader { + + WeldProxyDeclaringCL(ClassLoader parent) { super(parent); } + + public final Class publicDefineClass(String name, byte[] b, int off, + int len) { + try { + // just being paranoid - try loading class first + return super.loadClass(name); + } catch (ClassNotFoundException e) { + return super.defineClass(name, b, off, len); + } + } + + public final Class publicDefineClass(String name, byte[] b, int off, + int len, ProtectionDomain pd) { + try { + // just being paranoid - try loading class first + return super.loadClass(name); + } catch (ClassNotFoundException e) { + return super.defineClass(name, b, off, len, pd); + } + } + } +} diff --git a/impl/src/test/java/foo/bar/Foo.java b/impl/src/test/java/foo/bar/Foo.java new file mode 100644 index 0000000000..76c041b125 --- /dev/null +++ b/impl/src/test/java/foo/bar/Foo.java @@ -0,0 +1,23 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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 foo.bar; + +/** + * Used by {@link org.jboss.weld.tests.unit.comparator.CustomComparatorTest} + */ +public class Foo {} diff --git a/impl/src/test/java/foo/bar/quax/Quax.java b/impl/src/test/java/foo/bar/quax/Quax.java new file mode 100644 index 0000000000..7f21695344 --- /dev/null +++ b/impl/src/test/java/foo/bar/quax/Quax.java @@ -0,0 +1,23 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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 foo.bar.quax; + +/** + * Used by {@link org.jboss.weld.tests.unit.comparator.CustomComparatorTest} + */ +public class Quax {} diff --git a/impl/src/test/java/org/jboss/weld/tests/unit/comparator/CustomComparatorTest.java b/impl/src/test/java/org/jboss/weld/tests/unit/comparator/CustomComparatorTest.java new file mode 100644 index 0000000000..cb01ab2b3b --- /dev/null +++ b/impl/src/test/java/org/jboss/weld/tests/unit/comparator/CustomComparatorTest.java @@ -0,0 +1,83 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.unit.comparator; + +import foo.bar.Foo; +import foo.bar.quax.Quax; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.jboss.weld.SimpleCDI; +import org.jboss.weld.util.CustomClassComparator; +import org.junit.Assert; +import org.junit.Test; + +/** + * Tests sorting collections with {@link CustomClassComparator}. + */ +public class CustomComparatorTest { + + @Test + public void testComparator() { + List> testedList = prepareList(new ArrayList<>(), false); + List> expectedList = prepareList(new ArrayList<>(), true); + // sort the list + Collections.sort(testedList, new CustomClassComparator()); + // assert + assertListsEqual(expectedList, testedList); + } + + private List> prepareList(List> list, boolean sorted) { + Class clazz1 = Principal.class; + Class clazz2 = CustomClassComparator.class; + Class clazz3 = CustomComparatorTest.class; + Class clazz4 = Class.class; + Class clazz5 = SimpleCDI.class; + Class clazz6 = Foo.class; + Class clazz7 = Quax.class; + + if (sorted) { + list.add(clazz6); + list.add(clazz7); + list.add(clazz5); + list.add(clazz3); + list.add(clazz2); + list.add(clazz4); + list.add(clazz1); + } else { + list.add(clazz1); + list.add(clazz2); + list.add(clazz3); + list.add(clazz4); + list.add(clazz5); + list.add(clazz6); + list.add(clazz7); + } + return list; + } + + // compare based on class names as class itself doesn't implement equals + private void assertListsEqual(List> expected, + List> actual) { + Assert.assertEquals(expected.size(), actual.size()); + for (int i = 0; i < expected.size(); i++) { + Assert.assertEquals(expected.get(i).getName(), actual.get(i).getName()); + } + } +} diff --git a/inject-tck-runner/pom.xml b/inject-tck-runner/pom.xml index 571214a7f8..ec398f749e 100644 --- a/inject-tck-runner/pom.xml +++ b/inject-tck-runner/pom.xml @@ -3,7 +3,7 @@ weld-core-parent org.jboss.weld - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../pom.xml 4.0.0 diff --git a/inject-tck-runner/src/test/java/org/jboss/weld/atinject/tck/AllDiscoveryBeansXml.java b/inject-tck-runner/src/test/java/org/jboss/weld/atinject/tck/AllDiscoveryBeansXml.java new file mode 100644 index 0000000000..51f053823c --- /dev/null +++ b/inject-tck-runner/src/test/java/org/jboss/weld/atinject/tck/AllDiscoveryBeansXml.java @@ -0,0 +1,76 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.atinject.tck; + +import java.net.URL; +import java.util.Collections; +import java.util.List; +import org.jboss.weld.bootstrap.spi.BeanDiscoveryMode; +import org.jboss.weld.bootstrap.spi.BeansXml; +import org.jboss.weld.bootstrap.spi.Metadata; +import org.jboss.weld.bootstrap.spi.Scanning; + +public class AllDiscoveryBeansXml implements BeansXml { + public static final AllDiscoveryBeansXml INSTANCE = + new AllDiscoveryBeansXml(); + + @Override + public List> getEnabledAlternativeStereotypes() { + return Collections.emptyList(); + } + + @Override + public List> getEnabledAlternativeClasses() { + return Collections.emptyList(); + } + + @Override + public List> getEnabledDecorators() { + return Collections.emptyList(); + } + + @Override + public List> getEnabledInterceptors() { + return Collections.emptyList(); + } + + @Override + public Scanning getScanning() { + return Scanning.EMPTY_SCANNING; + } + + @Override + public URL getUrl() { + return null; + } + + @Override + public BeanDiscoveryMode getBeanDiscoveryMode() { + return BeanDiscoveryMode.ALL; + } + + @Override + public String getVersion() { + return null; + } + + @Override + public boolean isTrimmed() { + return false; + } +} diff --git a/inject-tck-runner/src/test/java/org/jboss/weld/atinject/tck/AtInjectTCK.java b/inject-tck-runner/src/test/java/org/jboss/weld/atinject/tck/AtInjectTCK.java index 33f2e171a2..22c1fec8a6 100644 --- a/inject-tck-runner/src/test/java/org/jboss/weld/atinject/tck/AtInjectTCK.java +++ b/inject-tck-runner/src/test/java/org/jboss/weld/atinject/tck/AtInjectTCK.java @@ -17,19 +17,25 @@ package org.jboss.weld.atinject.tck; +import java.util.Arrays; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; import junit.framework.Test; import org.atinject.tck.Tck; import org.atinject.tck.auto.Car; import org.atinject.tck.auto.Convertible; +import org.atinject.tck.auto.DriversSeat; import org.atinject.tck.auto.FuelTank; import org.atinject.tck.auto.Seat; import org.atinject.tck.auto.Tire; import org.atinject.tck.auto.V8Engine; import org.atinject.tck.auto.accessories.Cupholder; +import org.atinject.tck.auto.accessories.SpareTire; +import org.jboss.arquillian.container.weld.embedded.mock.BeanDeploymentArchiveImpl; +import org.jboss.arquillian.container.weld.embedded.mock.FlatDeployment; import org.jboss.arquillian.container.weld.embedded.mock.TestContainer; - -import javax.enterprise.inject.spi.Bean; -import javax.enterprise.inject.spi.BeanManager; +import org.jboss.weld.bootstrap.api.Environments; +import org.jboss.weld.bootstrap.spi.BeanDeploymentArchive; /** * Configure the AtInject TCK for use with the 299 RI @@ -38,35 +44,39 @@ */ public class AtInjectTCK { - /** - * Create JUnit TestSuite - * - * @return - */ - public static Test suite() { - // Create and start the TestContainer, which takes care of starting the container, deploying the - // classes, starting the contexts etc. - TestContainer container = new TestContainer( + /** + * Create JUnit TestSuite + * + * @return + */ + public static Test suite() { + // Create and start the TestContainer, which takes care of starting the + // container, deploying the classes, starting the contexts etc. + BeanDeploymentArchive archive = new BeanDeploymentArchiveImpl( + AllDiscoveryBeansXml.INSTANCE, + Arrays.asList(Convertible.class, Seat.class, DriversSeat.class, + V8Engine.class, Cupholder.class, FuelTank.class, + Tire.class, SpareTire.class), + Environments.SE); + TestContainer container = new TestContainer( + new FlatDeployment(archive, new AtInjectTCKExtension())); - // The classes to deploy as beans - Convertible.class, - Seat.class, - V8Engine.class, - Cupholder.class, - FuelTank.class, - Tire.class, - // Producer Methods allowing to expose DriversSeat, SpareTire, @Named("spare") SpareTire, @Drivers Seat - Producers.class - ); - container.startContainer(); + container.startContainer(); - // Our entry point is the single bean deployment archive - BeanManager beanManager = container.getBeanManager(container.getDeployment().getBeanDeploymentArchives().iterator().next()); + // Our entry point is the single bean deployment archive + BeanManager beanManager = + container.getBeanManager(container.getDeployment() + .getBeanDeploymentArchives() + .iterator() + .next()); - // Obtain a reference to the Car and pass it to the TCK to generate the testsuite - Bean bean = beanManager.resolve(beanManager.getBeans(Car.class)); - Car instance = (Car) beanManager.getReference(bean, Car.class, beanManager.createCreationalContext(bean)); + // Obtain a reference to the Car and pass it to the TCK to generate the + // testsuite + Bean bean = beanManager.resolve(beanManager.getBeans(Car.class)); + Car instance = (Car)beanManager.getReference( + bean, Car.class, beanManager.createCreationalContext(bean)); - return Tck.testsFor(instance, false /* supportsStatic */, true /* supportsPrivate */); - } + return Tck.testsFor(instance, false /* supportsStatic */, + true /* supportsPrivate */); + } } diff --git a/inject-tck-runner/src/test/java/org/jboss/weld/atinject/tck/AtInjectTCKExtension.java b/inject-tck-runner/src/test/java/org/jboss/weld/atinject/tck/AtInjectTCKExtension.java new file mode 100644 index 0000000000..6280047929 --- /dev/null +++ b/inject-tck-runner/src/test/java/org/jboss/weld/atinject/tck/AtInjectTCKExtension.java @@ -0,0 +1,72 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.atinject.tck; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import javax.enterprise.event.Observes; +import javax.enterprise.inject.spi.Extension; +import javax.enterprise.inject.spi.ProcessAnnotatedType; +import javax.enterprise.util.AnnotationLiteral; +import javax.inject.Qualifier; +import org.atinject.tck.auto.Convertible; +import org.atinject.tck.auto.Drivers; +import org.atinject.tck.auto.DriversSeat; +import org.atinject.tck.auto.accessories.SpareTire; +import org.jboss.weld.literal.NamedLiteral; + +public class AtInjectTCKExtension implements Extension { + public void convertible(@Observes ProcessAnnotatedType pat) { + pat.configureAnnotatedType() + .filterFields( + field -> "spareTire".equals(field.getJavaMember().getName())) + // add @Spare to the injection point, because the bean doesn't have + // @Default; see also below + .forEach(field -> field.add(SpareLiteral.INSTANCE)); + } + + public void driversSeat(@Observes ProcessAnnotatedType pat) { + pat.configureAnnotatedType().add(DriversLiteral.INSTANCE); + } + + public void spareTire(@Observes ProcessAnnotatedType pat) { + pat.configureAnnotatedType() + .add(new NamedLiteral("spare")) + // add @Spare to prevent adding @Default, otherwise there would be 2 + // beans for the Tire type + .add(SpareLiteral.INSTANCE); + } + + static final class DriversLiteral + extends AnnotationLiteral implements Drivers { + static final DriversLiteral INSTANCE = new DriversLiteral(); + + private DriversLiteral() {} + } + + @Qualifier + @Retention(RetentionPolicy.RUNTIME) + @interface Spare {} + + static final class SpareLiteral + extends AnnotationLiteral implements Spare { + static final SpareLiteral INSTANCE = new SpareLiteral(); + + private SpareLiteral() {} + } +} diff --git a/inject-tck-runner/src/test/java/org/jboss/weld/atinject/tck/Producers.java b/inject-tck-runner/src/test/java/org/jboss/weld/atinject/tck/Producers.java deleted file mode 100644 index e2e9b91c4d..0000000000 --- a/inject-tck-runner/src/test/java/org/jboss/weld/atinject/tck/Producers.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * JBoss, Home of Professional Open Source - * Copyright 2010, Red Hat, Inc., and individual contributors - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * Licensed 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.jboss.weld.atinject.tck; - -import org.atinject.tck.auto.Drivers; -import org.atinject.tck.auto.DriversSeat; -import org.atinject.tck.auto.Seat; -import org.atinject.tck.auto.Tire; -import org.atinject.tck.auto.accessories.SpareTire; - -import javax.enterprise.inject.New; -import javax.enterprise.inject.Produces; -import javax.enterprise.inject.Typed; -import javax.inject.Named; -import javax.inject.Qualifier; -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * Producer methods for the @Inject TCK beans we need greater control over - * - * @author pmuir - */ -public class Producers { - - /** - * Producer method for a bean with qualifier @Drivers and types Seat, Object - * - * @return - */ - @Produces - @Drivers - public Seat produceAtDriversSeat(@New DriversSeat driversSeat) { - return driversSeat; - } - - /** - * Producer method for a bean with default qualifiers and type DriversSeat only - * - * @return - */ - @Produces - @Typed(DriversSeat.class) - public DriversSeat produceDriversSeat(@New DriversSeat driversSeat) { - return driversSeat; - } - - @Qualifier - @Retention(RUNTIME) - @Target({TYPE, METHOD, FIELD, PARAMETER}) - @Documented - private @interface Spare { - - } - - /** - * Producer method for a bean with qualifier @Named("spare") and types Tire, Object. - *

- * Use the @Spare qualifier to stop @Default being applied - */ - @Produces - @Named("spare") - @Spare - public Tire produceAtNamedSpareTire(@New SpareTire spareTire) { - return spareTire; - } - - /** - * Producer method for bean with default qualifiers and type SpareTire only - */ - @Produces - @Typed(SpareTire.class) - public SpareTire produceSpareTire(@New SpareTire spareTire) { - return spareTire; - } - -} diff --git a/jboss-as/pom.xml b/jboss-as/pom.xml index 6fc0307386..4485639254 100644 --- a/jboss-as/pom.xml +++ b/jboss-as/pom.xml @@ -8,7 +8,7 @@ org.jboss.weld weld-core-parent - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../pom.xml @@ -30,27 +30,12 @@ - 3.1.5-SNAPSHOT - - - - - ${project.build.directory}/wildfly-patched/wildfly-${wildfly.download.version} - - ${project.build.directory}/patch.xml - - patch-config-wildfly-14-weld-3.1.xml - - ${project.build.directory}/patch.zip - - - ${project.build.directory}/wildfly-original/wildfly-${wildfly.download.version} - 18.0.1.Final + 3.1.11-SNAPSHOT ${cdi.tck-2-0.version} - 1.3.0 - 2.0.1.Final + 1.6.3 + 2.1.1.Final @@ -84,72 +69,39 @@ weld-web ${weld.update.version} - - jakarta.enterprise - cdi-tck-ext-lib - ${cdi.tck.version} - - - download-wfly - - ${project.build.directory}/wildfly-original/wildfly-${wildfly.download.version} - - ${project.build.directory}/wildfly-patched/wildfly-${wildfly.download.version} - - ${project.build.directory}/wildfly-patched/wildfly-${wildfly.download.version} - - - - - maven-dependency-plugin - - - unpack-wildfly - prepare-package - - unpack - - - - - org.wildfly - wildfly-dist - ${wildfly.download.version} - tar.gz - false - ${project.build.directory}/wildfly-original - - - - - - - - maven-resources-plugin - - - copy-resources - - prepare-package - - copy-resources - - - ${project.build.directory}/wildfly-patched - - - ${project.build.directory}/wildfly-original - - - - - - - - + tck2Deps + + true + + !tck12 + + + + + jakarta.enterprise + cdi-tck-ext-lib + ${cdi.tck.version} + + + + + tck1Deps + + false + + tck12 + + + + + org.jboss.cdi.tck + cdi-tck-ext-lib + ${cdi.tck.version} + + update-jboss-as @@ -264,13 +216,6 @@ - - - org.apache.ant - ant-nodeps - 1.8.1 - - org.apache.maven.plugins @@ -316,68 +261,9 @@ - - wfly-patch-gen - - - - - com.googlecode.maven-download-plugin - download-maven-plugin - - - download-patch-file - prepare-package - - wget - - - https://raw.githubusercontent.com/weld/build/master/wildfly/${patch.file.name} - ${project.build.directory} - patch.xml - - - - - - org.jboss.as - patch-gen-maven-plugin - - - create-patch-file - package - - generate-patch - - - ${wildflyOriginal} - ${wildflyPatched} - ${patchConfigFile} - ${patchOutputFile} - - - - - - - - - - - com.googlecode.maven-download-plugin - download-maven-plugin - ${download.maven.plugin} - - - org.jboss.as - patch-gen-maven-plugin - ${patch.gen.plugin} - - - org.apache.maven.plugins diff --git a/jboss-tck-runner/pom.xml b/jboss-tck-runner/pom.xml index 66ed128977..a32ff096fc 100644 --- a/jboss-tck-runner/pom.xml +++ b/jboss-tck-runner/pom.xml @@ -3,7 +3,7 @@ weld-core-parent org.jboss.weld - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../pom.xml 4.0.0 @@ -67,62 +67,6 @@ weld-porting-package-tck - - jakarta.enterprise - cdi-tck-api - ${cdi.tck.version} - - - jakarta.el - jakarta.el-api - - - - - - jakarta.enterprise - cdi-tck-impl - ${cdi.tck.version} - xml - suite - test - - - jakarta.el - jakarta.el-api - - - jakarta.faces - jakarta.faces-api - - - container-se-api - org.jboss.arquillian.container - - - - - - jakarta.enterprise - cdi-tck-impl - ${cdi.tck.version} - test - - - jakarta.el - jakarta.el-api - - - jakarta.faces - jakarta.faces-api - - - container-se-api - org.jboss.arquillian.container - - - - org.glassfish jakarta.el @@ -132,7 +76,6 @@ org.jboss.spec.javax.faces jboss-jsf-api_2.3_spec - @@ -224,6 +167,73 @@ + tck2 + + true + + !tck12 + + + + + jakarta.enterprise + cdi-tck-api + ${cdi.tck.version} + + + jakarta.el + jakarta.el-api + + + + + + jakarta.enterprise + cdi-tck-impl + ${cdi.tck.version} + xml + suite + test + + + jakarta.el + jakarta.el-api + + + jakarta.faces + jakarta.faces-api + + + container-se-api + org.jboss.arquillian.container + + + + + + jakarta.enterprise + cdi-tck-impl + ${cdi.tck.version} + test + + + jakarta.el + jakarta.el-api + + + jakarta.faces + jakarta.faces-api + + + container-se-api + org.jboss.arquillian.container + + + + + + + tck12 false @@ -233,7 +243,70 @@ ${cdi.tck-1-2.version} + 1.5.3 + + + org.jboss.cdi.tck + cdi-tck-api + ${cdi.tck.version} + + + javax.el + el-api + + + + + + org.jboss.cdi.tck + cdi-tck-impl + ${cdi.tck.version} + xml + suite + test + + + javax.el + el-api + + + javax.faces + javax.faces-api + + + javax.xml.ws + jaxws-api + + + + + + org.jboss.cdi.tck + cdi-tck-impl + ${cdi.tck.version} + test + + + javax.el + el-api + + + javax.faces + javax.faces-api + + + javax.xml.ws + jaxws-api + + + + + com.sun.xml.messaging.saaj + saaj-impl + ${saaj.impl.version} + + @@ -522,8 +595,9 @@ org.jacoco jacoco-maven-plugin + - jakarta.enterprise.* + org/jboss/cdi/tck/**/* jacoco.agent diff --git a/modules/ejb/pom.xml b/modules/ejb/pom.xml index c63701cd10..df2592474a 100644 --- a/modules/ejb/pom.xml +++ b/modules/ejb/pom.xml @@ -3,7 +3,7 @@ weld-core-parent org.jboss.weld - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml 4.0.0 @@ -52,7 +52,7 @@ org.jboss.spec.javax.ejb jboss-ejb-api_3.2_spec - + com.github.spotbugs diff --git a/modules/jsf/pom.xml b/modules/jsf/pom.xml index 5acfa393e7..1a8bb882e4 100644 --- a/modules/jsf/pom.xml +++ b/modules/jsf/pom.xml @@ -3,7 +3,7 @@ weld-core-parent org.jboss.weld - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml 4.0.0 @@ -62,7 +62,7 @@ jdk15 test - + com.github.spotbugs @@ -70,7 +70,7 @@ true - + findbugs diff --git a/modules/jta/pom.xml b/modules/jta/pom.xml index 01d7e01b0d..71b81f4dfb 100644 --- a/modules/jta/pom.xml +++ b/modules/jta/pom.xml @@ -3,7 +3,7 @@ weld-core-parent org.jboss.weld - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml 4.0.0 @@ -47,7 +47,7 @@ org.jboss.weld weld-spi - + com.github.spotbugs @@ -55,7 +55,7 @@ true - + findbugs diff --git a/modules/web/pom.xml b/modules/web/pom.xml index 6079fd11e1..94a8814760 100644 --- a/modules/web/pom.xml +++ b/modules/web/pom.xml @@ -3,7 +3,7 @@ weld-core-parent org.jboss.weld - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../../pom.xml 4.0.0 @@ -71,7 +71,7 @@ junit test - + com.github.spotbugs diff --git a/modules/web/src/main/java/org/jboss/weld/module/web/logging/ServletLogger.java b/modules/web/src/main/java/org/jboss/weld/module/web/logging/ServletLogger.java index 659e8ab3c0..9a2e390d92 100644 --- a/modules/web/src/main/java/org/jboss/weld/module/web/logging/ServletLogger.java +++ b/modules/web/src/main/java/org/jboss/weld/module/web/logging/ServletLogger.java @@ -38,63 +38,111 @@ @MessageLogger(projectCode = WELD_PROJECT_CODE) public interface ServletLogger extends WeldLogger { - ServletLogger LOG = Logger.getMessageLogger(ServletLogger.class, Category.SERVLET.getName()); - - @SuppressWarnings("weldlog:method-interface") - @Message(id = 707, value = "Non Http-Servlet lifecycle not defined") - IllegalStateException onlyHttpServletLifecycleDefined(); - - @SuppressWarnings("weldlog:method-interface") - @LogMessage(level = Level.TRACE) - @Message(id = 708, value = "Initializing request {0}", format = Format.MESSAGE_FORMAT) - void requestInitialized(Object param1); - - @SuppressWarnings("weldlog:method-interface") - @LogMessage(level = Level.TRACE) - @Message(id = 709, value = "Destroying request {0}", format = Format.MESSAGE_FORMAT) - void requestDestroyed(Object param1); - - @SuppressWarnings("weldlog:method-interface") - @Message(id = 710, value = "Cannot inject {0} outside of a Servlet request", format = Format.MESSAGE_FORMAT) - IllegalStateException cannotInjectObjectOutsideOfServletRequest(Object param1, @Cause Throwable cause); - - @SuppressWarnings("weldlog:method-interface") - @LogMessage(level = Level.WARN) - @Message(id = 711, value = "Context activation pattern {0} ignored as it is overriden by the integrator.", format = Format.MESSAGE_FORMAT) - void webXmlMappingPatternIgnored(String pattern); - - @SuppressWarnings("weldlog:method-interface") - @LogMessage(level = Level.WARN) - @Message(id = 712, value = "Unable to dissociate context {0} from the storage {1}", format = Format.MESSAGE_FORMAT) - void unableToDissociateContext(Object context, Object storage); - - @SuppressWarnings({"weldlog:method-interface","weldlog:method-sig"}) - @Message(id = 713, value = "Unable to inject ServletContext. None is associated with {0}, {1}", format = Format.MESSAGE_FORMAT) - IllegalStateException cannotInjectServletContext(ClassLoader classLoader, ServletContextService service); - - @SuppressWarnings("weldlog:method-interface") - @LogMessage(level = Level.WARN) - @Message(id = 714, value = "HttpContextLifecycle guard leak detected. The Servlet container is not fully compliant. The value was {0}", format = Format.MESSAGE_FORMAT) - void guardLeak(int value); - - @SuppressWarnings("weldlog:method-interface") - @LogMessage(level = Level.WARN) - @Message(id = 715, value = "HttpContextLifecycle guard not set. The Servlet container is not fully compliant.", format = Format.MESSAGE_FORMAT) - void guardNotSet(); - - @SuppressWarnings("weldlog:method-interface") - @LogMessage(level = Level.INFO) - @Message(id = 716, value = "Running in Servlet 2.x environment. Asynchronous request support is disabled.") - void servlet2Environment(); - - @SuppressWarnings("weldlog:method-interface") - @LogMessage(level = Level.WARN) - @Message(id = 717, value = "Unable to deactivate context {0} when destroying request {1}", format = Format.MESSAGE_FORMAT) - void unableToDeactivateContext(Object context, Object request); - - @SuppressWarnings("weldlog:method-interface") - @LogMessage(level = Level.WARN) - @Message(id = 718, value = "No EEModuleDescriptor defined for bean archive with ID: {0}. @Initialized and @Destroyed events for ApplicationScoped may be fired twice.", format = Format.MESSAGE_FORMAT) - void noEeModuleDescriptor(Object beanArchiveId); - -} \ No newline at end of file + ServletLogger LOG = + Logger.getMessageLogger(ServletLogger.class, Category.SERVLET.getName()); + + @SuppressWarnings("weldlog:method-interface") + @Message(id = 707, value = "Non Http-Servlet lifecycle not defined") + IllegalStateException onlyHttpServletLifecycleDefined(); + + @SuppressWarnings("weldlog:method-interface") + @LogMessage(level = Level.TRACE) + @Message(id = 708, value = "Initializing request {0}", + format = Format.MESSAGE_FORMAT) + void + requestInitialized(Object param1); + + @SuppressWarnings("weldlog:method-interface") + @LogMessage(level = Level.TRACE) + @Message(id = 709, value = "Destroying request {0}", + format = Format.MESSAGE_FORMAT) + void + requestDestroyed(Object param1); + + @SuppressWarnings("weldlog:method-interface") + @Message(id = 710, value = "Cannot inject {0} outside of a Servlet request", + format = Format.MESSAGE_FORMAT) + IllegalStateException + cannotInjectObjectOutsideOfServletRequest(Object param1, + @Cause Throwable cause); + + @SuppressWarnings("weldlog:method-interface") + @LogMessage(level = Level.WARN) + @Message(id = 711, + value = "Context activation pattern {0} ignored as it is " + + "overriden by the integrator.", + format = Format.MESSAGE_FORMAT) + void + webXmlMappingPatternIgnored(String pattern); + + @SuppressWarnings("weldlog:method-interface") + @LogMessage(level = Level.WARN) + @Message(id = 712, + value = "Unable to dissociate context {0} from the storage {1}", + format = Format.MESSAGE_FORMAT) + void + unableToDissociateContext(Object context, Object storage); + + @SuppressWarnings({"weldlog:method-interface", "weldlog:method-sig"}) + @Message( + id = 713, + value = + "Unable to inject ServletContext. None is associated with {0}, {1}", + format = Format.MESSAGE_FORMAT) + IllegalStateException + cannotInjectServletContext(ClassLoader classLoader, + ServletContextService service); + + @SuppressWarnings("weldlog:method-interface") + @LogMessage(level = Level.WARN) + @Message(id = 714, + value = "HttpContextLifecycle guard leak detected. The Servlet " + + "container is not fully compliant. The value was {0}", + format = Format.MESSAGE_FORMAT) + void + guardLeak(int value); + + @SuppressWarnings("weldlog:method-interface") + @LogMessage(level = Level.WARN) + @Message(id = 715, + value = "HttpContextLifecycle guard not set. The Servlet " + + "container is not fully compliant.", + format = Format.MESSAGE_FORMAT) + void + guardNotSet(); + + @SuppressWarnings("weldlog:method-interface") + @LogMessage(level = Level.INFO) + @Message(id = 716, value = "Running in Servlet 2.x environment. " + + "Asynchronous request support is disabled.") + void + servlet2Environment(); + + @SuppressWarnings("weldlog:method-interface") + @LogMessage(level = Level.WARN) + @Message( + id = 717, + value = "Unable to deactivate context {0} when destroying request {1}", + format = Format.MESSAGE_FORMAT) + void + unableToDeactivateContext(Object context, Object request); + + @SuppressWarnings("weldlog:method-interface") + @LogMessage(level = Level.WARN) + @Message(id = 718, + value = "No EEModuleDescriptor defined for bean archive with ID: " + + "{0}. @Initialized and @Destroyed events for " + + "ApplicationScoped may be fired twice.", + format = Format.MESSAGE_FORMAT) + void + noEeModuleDescriptor(Object beanArchiveId); + + @LogMessage(level = Level.DEBUG) + @Message(id = 719, + value = "An active HttpSessionDestructionContext detected. This " + + "is likely a leftover from previous sessions that ended " + + "exceptionally. This context will be terminated.", + format = Format.MESSAGE_FORMAT) + void + destructionContextLeak(); +} diff --git a/modules/web/src/main/java/org/jboss/weld/module/web/servlet/HttpContextLifecycle.java b/modules/web/src/main/java/org/jboss/weld/module/web/servlet/HttpContextLifecycle.java index 44347f6a1b..93db8caa21 100644 --- a/modules/web/src/main/java/org/jboss/weld/module/web/servlet/HttpContextLifecycle.java +++ b/modules/web/src/main/java/org/jboss/weld/module/web/servlet/HttpContextLifecycle.java @@ -18,7 +18,6 @@ import java.lang.annotation.Annotation; import java.util.Collections; - import javax.enterprise.context.BeforeDestroyed; import javax.enterprise.context.Destroyed; import javax.enterprise.context.Initialized; @@ -27,7 +26,6 @@ import javax.servlet.ServletRequestListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; - import org.jboss.weld.Container; import org.jboss.weld.bootstrap.BeanDeploymentModule; import org.jboss.weld.bootstrap.BeanDeploymentModules; @@ -47,7 +45,8 @@ import org.jboss.weld.util.reflection.Reflections; /** - * Takes care of setting up and tearing down CDI contexts around an HTTP request and dispatching context lifecycle events. + * Takes care of setting up and tearing down CDI contexts around an HTTP request + * and dispatching context lifecycle events. * * @author Jozef Hartinger * @author Marko Luksa @@ -55,344 +54,405 @@ */ public class HttpContextLifecycle implements Service { - public static final String ASYNC_STARTED_ATTR_NAME = "org.jboss.weld.context.asyncStarted"; - - private static final String HTTP_SESSION = "org.jboss.weld." + HttpSession.class.getName(); - - private static final String INCLUDE_HEADER = "javax.servlet.include.request_uri"; - private static final String FORWARD_HEADER = "javax.servlet.forward.request_uri"; - private static final String REQUEST_DESTROYED = HttpContextLifecycle.class.getName() + ".request.destroyed"; - - private static final String GUARD_PARAMETER_NAME = "org.jboss.weld.context.ignore.guard.marker"; - private static final Object GUARD_PARAMETER_VALUE = new Object(); - - private HttpSessionDestructionContext sessionDestructionContextCache; - private HttpSessionContext sessionContextCache; - private HttpRequestContext requestContextCache; - - private volatile Boolean conversationActivationEnabled; - private final boolean ignoreForwards; - private final boolean ignoreIncludes; - - private final BeanManagerImpl beanManager; - private final ConversationContextActivator conversationContextActivator; - private final HttpContextActivationFilter contextActivationFilter; - - private final FastEvent requestInitializedEvent; - private final FastEvent requestBeforeDestroyedEvent; - private final FastEvent requestDestroyedEvent; - private final FastEvent sessionInitializedEvent; - private final FastEvent sessionBeforeDestroyedEvent; - private final FastEvent sessionDestroyedEvent; - - private final ServletApiAbstraction servletApi; - - private final ServletContextService servletContextService; - - private final Container container; - private final BeanDeploymentModule module; - - private static final ThreadLocal nestedInvocationGuard = new ThreadLocal(); - private final boolean nestedInvocationGuardEnabled; - - private static class Counter { - private int value = 1; + public static final String ASYNC_STARTED_ATTR_NAME = + "org.jboss.weld.context.asyncStarted"; + + private static final String HTTP_SESSION = + "org.jboss.weld." + HttpSession.class.getName(); + + private static final String INCLUDE_HEADER = + "javax.servlet.include.request_uri"; + private static final String FORWARD_HEADER = + "javax.servlet.forward.request_uri"; + private static final String REQUEST_DESTROYED = + HttpContextLifecycle.class.getName() + ".request.destroyed"; + + private static final String GUARD_PARAMETER_NAME = + "org.jboss.weld.context.ignore.guard.marker"; + private static final Object GUARD_PARAMETER_VALUE = new Object(); + + private HttpSessionDestructionContext sessionDestructionContextCache; + private HttpSessionContext sessionContextCache; + private HttpRequestContext requestContextCache; + + private volatile Boolean conversationActivationEnabled; + private final boolean ignoreForwards; + private final boolean ignoreIncludes; + + private final BeanManagerImpl beanManager; + private final ConversationContextActivator conversationContextActivator; + private final HttpContextActivationFilter contextActivationFilter; + + private final FastEvent requestInitializedEvent; + private final FastEvent requestBeforeDestroyedEvent; + private final FastEvent requestDestroyedEvent; + private final FastEvent sessionInitializedEvent; + private final FastEvent sessionBeforeDestroyedEvent; + private final FastEvent sessionDestroyedEvent; + + private final ServletApiAbstraction servletApi; + + private final ServletContextService servletContextService; + + private final Container container; + private final BeanDeploymentModule module; + + private static final ThreadLocal nestedInvocationGuard = + new ThreadLocal(); + private final boolean nestedInvocationGuardEnabled; + + private static class Counter { + private int value = 1; + } + + public HttpContextLifecycle( + BeanManagerImpl beanManager, + HttpContextActivationFilter contextActivationFilter, + boolean ignoreForwards, boolean ignoreIncludes, + boolean lazyConversationContext, boolean nestedInvocationGuardEnabled) { + this.beanManager = beanManager; + this.conversationContextActivator = + new ConversationContextActivator(beanManager, lazyConversationContext); + this.conversationActivationEnabled = null; + this.ignoreForwards = ignoreForwards; + this.ignoreIncludes = ignoreIncludes; + this.contextActivationFilter = contextActivationFilter; + this.requestInitializedEvent = FastEvent.of( + HttpServletRequest.class, beanManager, Initialized.Literal.REQUEST); + this.requestBeforeDestroyedEvent = FastEvent.of( + HttpServletRequest.class, beanManager, BeforeDestroyed.Literal.REQUEST); + this.requestDestroyedEvent = FastEvent.of( + HttpServletRequest.class, beanManager, Destroyed.Literal.REQUEST); + this.sessionInitializedEvent = FastEvent.of(HttpSession.class, beanManager, + Initialized.Literal.SESSION); + this.sessionBeforeDestroyedEvent = FastEvent.of( + HttpSession.class, beanManager, BeforeDestroyed.Literal.SESSION); + this.sessionDestroyedEvent = + FastEvent.of(HttpSession.class, beanManager, Destroyed.Literal.SESSION); + this.servletApi = + beanManager.getServices().get(ServletApiAbstraction.class); + this.servletContextService = + beanManager.getServices().get(ServletContextService.class); + this.nestedInvocationGuardEnabled = nestedInvocationGuardEnabled; + this.container = Container.instance(beanManager); + BeanDeploymentModules beanDeploymentModules = + beanManager.getServices().get(BeanDeploymentModules.class); + this.module = beanDeploymentModules != null + ? beanDeploymentModules.getModule(beanManager) + : null; + } + + private HttpSessionDestructionContext getSessionDestructionContext() { + if (sessionDestructionContextCache == null) { + this.sessionDestructionContextCache = + beanManager.instance() + .select(HttpSessionDestructionContext.class) + .get(); } + return sessionDestructionContextCache; + } - public HttpContextLifecycle(BeanManagerImpl beanManager, HttpContextActivationFilter contextActivationFilter, boolean ignoreForwards, - boolean ignoreIncludes, boolean lazyConversationContext, boolean nestedInvocationGuardEnabled) { - this.beanManager = beanManager; - this.conversationContextActivator = new ConversationContextActivator(beanManager, lazyConversationContext); - this.conversationActivationEnabled = null; - this.ignoreForwards = ignoreForwards; - this.ignoreIncludes = ignoreIncludes; - this.contextActivationFilter = contextActivationFilter; - this.requestInitializedEvent = FastEvent.of(HttpServletRequest.class, beanManager, Initialized.Literal.REQUEST); - this.requestBeforeDestroyedEvent = FastEvent.of(HttpServletRequest.class, beanManager, BeforeDestroyed.Literal.REQUEST); - this.requestDestroyedEvent = FastEvent.of(HttpServletRequest.class, beanManager, Destroyed.Literal.REQUEST); - this.sessionInitializedEvent = FastEvent.of(HttpSession.class, beanManager, Initialized.Literal.SESSION); - this.sessionBeforeDestroyedEvent = FastEvent.of(HttpSession.class, beanManager, BeforeDestroyed.Literal.SESSION); - this.sessionDestroyedEvent = FastEvent.of(HttpSession.class, beanManager, Destroyed.Literal.SESSION); - this.servletApi = beanManager.getServices().get(ServletApiAbstraction.class); - this.servletContextService = beanManager.getServices().get(ServletContextService.class); - this.nestedInvocationGuardEnabled = nestedInvocationGuardEnabled; - this.container = Container.instance(beanManager); - BeanDeploymentModules beanDeploymentModules = beanManager.getServices().get(BeanDeploymentModules.class); - this.module = beanDeploymentModules != null ? beanDeploymentModules.getModule(beanManager) : null; + private HttpSessionContext getSessionContext() { + if (sessionContextCache == null) { + this.sessionContextCache = + beanManager.instance().select(HttpSessionContext.class).get(); } + return sessionContextCache; + } - private HttpSessionDestructionContext getSessionDestructionContext() { - if (sessionDestructionContextCache == null) { - this.sessionDestructionContextCache = beanManager.instance().select(HttpSessionDestructionContext.class).get(); - } - return sessionDestructionContextCache; - } - - private HttpSessionContext getSessionContext() { - if (sessionContextCache == null) { - this.sessionContextCache = beanManager.instance().select(HttpSessionContext.class).get(); - } - return sessionContextCache; + public HttpRequestContext getRequestContext() { + if (requestContextCache == null) { + this.requestContextCache = + beanManager.instance().select(HttpRequestContext.class).get(); } - - public HttpRequestContext getRequestContext() { - if (requestContextCache == null) { - this.requestContextCache = beanManager.instance().select(HttpRequestContext.class).get(); + return requestContextCache; + } + + public void contextInitialized(ServletContext ctx) { + servletContextService.contextInitialized(ctx); + fireEventForApplicationScope(ctx, Initialized.Literal.APPLICATION); + } + + public void contextDestroyed(ServletContext ctx) { + // TODO WELD-2282 Firing these two right after each other does not really + // make sense + fireEventForApplicationScope(ctx, BeforeDestroyed.Literal.APPLICATION); + fireEventForApplicationScope(ctx, Destroyed.Literal.APPLICATION); + } + + private void fireEventForApplicationScope(ServletContext ctx, + Annotation qualifier) { + if (module != null) { + // Deliver events sequentially + synchronized (container) { + if (module.isWebModule()) { + module.fireEvent(ServletContext.class, ctx, qualifier); + } else { + // fallback for backward compatibility + ServletLogger.LOG.noEeModuleDescriptor(beanManager); + final EventMetadata metadata = new EventMetadataImpl( + ServletContext.class, null, Collections.singleton(qualifier)); + beanManager.getAccessibleLenientObserverNotifier().fireEvent( + ServletContext.class, ctx, metadata, qualifier); } - return requestContextCache; + } } - - public void contextInitialized(ServletContext ctx) { - servletContextService.contextInitialized(ctx); - fireEventForApplicationScope(ctx, Initialized.Literal.APPLICATION); + } + + public void sessionCreated(HttpSession session) { + SessionHolder.sessionCreated(session); + conversationContextActivator.sessionCreated(session); + sessionInitializedEvent.fire(session); + } + + public void sessionDestroyed(HttpSession session) { + // Mark the session context and conversation contexts to destroy + // instances when appropriate + deactivateSessionDestructionContext(session); + boolean destroyed = getSessionContext().destroy(session); + SessionHolder.clear(); + RequestScopedCache.endRequest(); + if (destroyed) { + // we are outside of a request (the session timed out) and therefore the + // session was destroyed immediately we can fire the + // @Destroyed(SessionScoped.class) event immediately + sessionDestroyedEvent.fire(session); + } else { + // the old session won't be available at the time we destroy this request + // let's store its reference until then + if (getRequestContext() instanceof HttpRequestContextImpl) { + HttpServletRequest request = + Reflections.cast(getRequestContext()) + .getHttpServletRequest(); + request.setAttribute(HTTP_SESSION, session); + } } + } - public void contextDestroyed(ServletContext ctx) { - // TODO WELD-2282 Firing these two right after each other does not really make sense - fireEventForApplicationScope(ctx, BeforeDestroyed.Literal.APPLICATION); - fireEventForApplicationScope(ctx, Destroyed.Literal.APPLICATION); + private void deactivateSessionDestructionContext(HttpSession session) { + HttpSessionDestructionContext context = getSessionDestructionContext(); + if (context.isActive()) { + context.deactivate(); + context.dissociate(session); } - - private void fireEventForApplicationScope(ServletContext ctx, Annotation qualifier) { - if (module != null) { - // Deliver events sequentially - synchronized (container) { - if (module.isWebModule()) { - module.fireEvent(ServletContext.class, ctx, qualifier); - } else { - // fallback for backward compatibility - ServletLogger.LOG.noEeModuleDescriptor(beanManager); - final EventMetadata metadata = new EventMetadataImpl(ServletContext.class, null, Collections.singleton(qualifier)); - beanManager.getAccessibleLenientObserverNotifier().fireEvent(ServletContext.class, ctx, metadata, qualifier); - } - } + } + + public void requestInitialized(HttpServletRequest request, + ServletContext ctx) { + if (nestedInvocationGuardEnabled) { + Counter counter = nestedInvocationGuard.get(); + Object marker = request.getAttribute(GUARD_PARAMETER_NAME); + if (counter != null && marker != null) { + // this is a nested invocation, increment the counter and ignore this + // invocation + counter.value++; + return; + } else { + if (counter != null && marker == null) { + /* + * This request has not been processed yet but the guard is set + * already. That indicates, that the guard leaked from a previous + * request processing - most likely the Servlet container did not + * invoke listener methods symmetrically. Log a warning and recover by + * re-initializing the guard + */ + ServletLogger.LOG.guardLeak(counter.value); } + // this is the initial (outer) invocation + nestedInvocationGuard.set(new Counter()); + request.setAttribute(GUARD_PARAMETER_NAME, GUARD_PARAMETER_VALUE); + } } - - public void sessionCreated(HttpSession session) { - SessionHolder.sessionCreated(session); - conversationContextActivator.sessionCreated(session); - sessionInitializedEvent.fire(session); + if (ignoreForwards && isForwardedRequest(request)) { + return; } - - public void sessionDestroyed(HttpSession session) { - // Mark the session context and conversation contexts to destroy - // instances when appropriate - deactivateSessionDestructionContext(session); - boolean destroyed = getSessionContext().destroy(session); - SessionHolder.clear(); - RequestScopedCache.endRequest(); - if (destroyed) { - // we are outside of a request (the session timed out) and therefore the session was destroyed immediately - // we can fire the @Destroyed(SessionScoped.class) event immediately - sessionDestroyedEvent.fire(session); - } else { - // the old session won't be available at the time we destroy this request - // let's store its reference until then - if (getRequestContext() instanceof HttpRequestContextImpl) { - HttpServletRequest request = Reflections. cast(getRequestContext()).getHttpServletRequest(); - request.setAttribute(HTTP_SESSION, session); - } - } + if (ignoreIncludes && isIncludedRequest(request)) { + return; } - - private void deactivateSessionDestructionContext(HttpSession session) { - HttpSessionDestructionContext context = getSessionDestructionContext(); - if (context.isActive()) { - context.deactivate(); - context.dissociate(session); - } + if (!contextActivationFilter.accepts(request)) { + return; } - public void requestInitialized(HttpServletRequest request, ServletContext ctx) { - if (nestedInvocationGuardEnabled) { - Counter counter = nestedInvocationGuard.get(); - Object marker = request.getAttribute(GUARD_PARAMETER_NAME); - if (counter != null && marker != null) { - // this is a nested invocation, increment the counter and ignore this invocation - counter.value++; - return; - } else { - if (counter != null && marker == null) { - /* - * This request has not been processed yet but the guard is set already. That indicates, that the guard leaked from a previous request - * processing - most likely the Servlet container did not invoke listener methods symmetrically. Log a warning and recover by - * re-initializing the guard - */ - ServletLogger.LOG.guardLeak(counter.value); - } - // this is the initial (outer) invocation - nestedInvocationGuard.set(new Counter()); - request.setAttribute(GUARD_PARAMETER_NAME, GUARD_PARAMETER_VALUE); - } - } - if (ignoreForwards && isForwardedRequest(request)) { - return; - } - if (ignoreIncludes && isIncludedRequest(request)) { - return; - } - if (!contextActivationFilter.accepts(request)) { - return; - } - - ServletLogger.LOG.requestInitialized(request); - - SessionHolder.requestInitialized(request); + ServletLogger.LOG.requestInitialized(request); - getRequestContext().associate(request); - getSessionContext().associate(request); - if (conversationActivationEnabled) { - conversationContextActivator.associateConversationContext(request); - } - - getRequestContext().activate(); - getSessionContext().activate(); - - try { - if (conversationActivationEnabled) { - conversationContextActivator.activateConversationContext(request); - } - requestInitializedEvent.fire(request); - } catch (RuntimeException e) { - try { - requestDestroyed(request); - } catch (Exception ignored) { - // ignored in order to let the original exception be thrown - } - /* - * If the servlet container happens to call the destroyed callback again, ignore it. - */ - request.setAttribute(REQUEST_DESTROYED, Boolean.TRUE); - throw e; - } + // cleanup any leftover destruction context on this thread, see WELD-2631 + if (getSessionDestructionContext().isActive()) { + ServletLogger.LOG.destructionContextLeak(); + getSessionDestructionContext().deactivate(); } - public void requestDestroyed(HttpServletRequest request) { - if (isRequestDestroyed(request)) { - return; - } - if (nestedInvocationGuardEnabled) { - Counter counter = nestedInvocationGuard.get(); - if (counter != null) { - counter.value--; - if (counter.value > 0) { - return; // this is a nested invocation, ignore it - } else { - nestedInvocationGuard.remove(); // this is the outer invocation - request.removeAttribute(GUARD_PARAMETER_NAME); - } - } else { - ServletLogger.LOG.guardNotSet(); - return; - } - } - if (ignoreForwards && isForwardedRequest(request)) { - return; - } - if (ignoreIncludes && isIncludedRequest(request)) { - return; - } - if (!contextActivationFilter.accepts(request)) { - return; - } + SessionHolder.requestInitialized(request); - ServletLogger.LOG.requestDestroyed(request); - - try { - conversationContextActivator.deactivateConversationContext(request); - /* - * If this request has been switched to async then do not invalidate the context now as it will be invalidated at the end of the async operation. - */ - if (servletApi.isAsyncSupported() && servletApi.isAsyncStarted(request)) { - // Note that we can't use isAsyncStarted() because it may return false after dispatch - request.setAttribute(ASYNC_STARTED_ATTR_NAME, true); - } else { - getRequestContext().invalidate(); - } - - // fire @BeforeDestroyed(RequestScoped.class) - requestBeforeDestroyedEvent.fire(request); - safelyDeactivate(getRequestContext(), request); - // fire @Destroyed(RequestScoped.class) - requestDestroyedEvent.fire(request); - - Object destroyedHttpSession = request.getAttribute(HTTP_SESSION); - // fire @BeforeDestroyed(SessionScoped.class) - if (destroyedHttpSession != null) { - sessionBeforeDestroyedEvent.fire((HttpSession) destroyedHttpSession); - } - safelyDeactivate(getSessionContext(), request); - // fire @Destroyed(SessionScoped.class) - if (destroyedHttpSession != null) { - sessionDestroyedEvent.fire((HttpSession) destroyedHttpSession); - } - } finally { - safelyDissociate(getRequestContext(), request); - // WFLY-1533 Underlying HTTP session may be invalid - safelyDissociate(getSessionContext(), request); - - // Catch block is inside the activator method so that we're able to log the context - conversationContextActivator.disassociateConversationContext(request); - - SessionHolder.clear(); - } + getRequestContext().associate(request); + getSessionContext().associate(request); + if (conversationActivationEnabled) { + conversationContextActivator.associateConversationContext(request); } - public boolean isConversationActivationSet() { - return conversationActivationEnabled != null; + getRequestContext().activate(); + getSessionContext().activate(); + + try { + if (conversationActivationEnabled) { + conversationContextActivator.activateConversationContext(request); + } + requestInitializedEvent.fire(request); + } catch (RuntimeException e) { + try { + requestDestroyed(request); + } catch (Exception ignored) { + // ignored in order to let the original exception be thrown + } + /* + * If the servlet container happens to call the destroyed callback again, + * ignore it. + */ + request.setAttribute(REQUEST_DESTROYED, Boolean.TRUE); + throw e; } + } - public void setConversationActivationEnabled(boolean conversationActivationEnabled) { - this.conversationActivationEnabled = conversationActivationEnabled; + public void requestDestroyed(HttpServletRequest request) { + if (isRequestDestroyed(request)) { + return; } - - @Override - public void cleanup() { + if (nestedInvocationGuardEnabled) { + Counter counter = nestedInvocationGuard.get(); + if (counter != null) { + counter.value--; + if (counter.value > 0) { + return; // this is a nested invocation, ignore it + } else { + nestedInvocationGuard.remove(); // this is the outer invocation + request.removeAttribute(GUARD_PARAMETER_NAME); + } + } else { + ServletLogger.LOG.guardNotSet(); + return; + } } - - /** - * Some Servlet containers fire HttpServletListeners for include requests (inner requests caused by calling the include method of RequestDispatcher). This - * causes problems with context shut down as context manipulation is not reentrant. This method detects if this request is an included request or not. - */ - private boolean isIncludedRequest(HttpServletRequest request) { - return request.getAttribute(INCLUDE_HEADER) != null; + if (ignoreForwards && isForwardedRequest(request)) { + return; } - - /** - * Some Servlet containers fire HttpServletListeners for forward requests (inner requests caused by calling the forward method of RequestDispatcher). This - * causes problems with context shut down as context manipulation is not reentrant. This method detects if this request is an forwarded request or not. - */ - private boolean isForwardedRequest(HttpServletRequest request) { - return request.getAttribute(FORWARD_HEADER) != null; + if (ignoreIncludes && isIncludedRequest(request)) { + return; } - - /** - * The way servlet containers react to an exception that occurs in a {@link ServletRequestListener} differs among servlet listeners. In certain containers - * the destroyed callback may be invoked multiple times, causing the latter invocations to fail as thread locals have already been unset. We use the - * {@link #REQUEST_DESTROYED} flag to indicate that all further invocations of the - * {@link ServletRequestListener#requestDestroyed(javax.servlet.ServletRequestEvent)} should be ignored by Weld. - */ - private boolean isRequestDestroyed(HttpServletRequest request) { - return request.getAttribute(REQUEST_DESTROYED) != null; + if (!contextActivationFilter.accepts(request)) { + return; } - private void safelyDissociate(BoundContext context, T storage) { - try { - context.dissociate(storage); - } catch (Exception e) { - ServletLogger.LOG.unableToDissociateContext(context, storage); - ServletLogger.LOG.catchingDebug(e); - } + ServletLogger.LOG.requestDestroyed(request); + + try { + conversationContextActivator.deactivateConversationContext(request); + /* + * If this request has been switched to async then do not invalidate the + * context now as it will be invalidated at the end of the async + * operation. + */ + if (servletApi.isAsyncSupported() && servletApi.isAsyncStarted(request)) { + // Note that we can't use isAsyncStarted() because it may return false + // after dispatch + request.setAttribute(ASYNC_STARTED_ATTR_NAME, true); + } else { + getRequestContext().invalidate(); + } + + // fire @BeforeDestroyed(RequestScoped.class) + requestBeforeDestroyedEvent.fire(request); + safelyDeactivate(getRequestContext(), request); + // fire @Destroyed(RequestScoped.class) + requestDestroyedEvent.fire(request); + + Object destroyedHttpSession = request.getAttribute(HTTP_SESSION); + // fire @BeforeDestroyed(SessionScoped.class) + if (destroyedHttpSession != null) { + sessionBeforeDestroyedEvent.fire((HttpSession)destroyedHttpSession); + } + safelyDeactivate(getSessionContext(), request); + // fire @Destroyed(SessionScoped.class) + if (destroyedHttpSession != null) { + sessionDestroyedEvent.fire((HttpSession)destroyedHttpSession); + } + } finally { + safelyDissociate(getRequestContext(), request); + // WFLY-1533 Underlying HTTP session may be invalid + safelyDissociate(getSessionContext(), request); + + // Catch block is inside the activator method so that we're able to log + // the context + conversationContextActivator.disassociateConversationContext(request); + + SessionHolder.clear(); } - - private void safelyDeactivate(ManagedContext context, HttpServletRequest request) { - try { - context.deactivate(); - } catch (Exception e) { - ServletLogger.LOG.unableToDeactivateContext(context, request); - ServletLogger.LOG.catchingDebug(e); - } + } + + public boolean isConversationActivationSet() { + return conversationActivationEnabled != null; + } + + public void + setConversationActivationEnabled(boolean conversationActivationEnabled) { + this.conversationActivationEnabled = conversationActivationEnabled; + } + + @Override + public void cleanup() {} + + /** + * Some Servlet containers fire HttpServletListeners for include requests + * (inner requests caused by calling the include method of RequestDispatcher). + * This causes problems with context shut down as context manipulation is not + * reentrant. This method detects if this request is an included request or + * not. + */ + private boolean isIncludedRequest(HttpServletRequest request) { + return request.getAttribute(INCLUDE_HEADER) != null; + } + + /** + * Some Servlet containers fire HttpServletListeners for forward requests + * (inner requests caused by calling the forward method of RequestDispatcher). + * This causes problems with context shut down as context manipulation is not + * reentrant. This method detects if this request is an forwarded request or + * not. + */ + private boolean isForwardedRequest(HttpServletRequest request) { + return request.getAttribute(FORWARD_HEADER) != null; + } + + /** + * The way servlet containers react to an exception that occurs in a {@link + * ServletRequestListener} differs among servlet listeners. In certain + * containers the destroyed callback may be invoked multiple times, causing + * the latter invocations to fail as thread locals have already been unset. We + * use the + * {@link #REQUEST_DESTROYED} flag to indicate that all further invocations of + * the + * {@link + * ServletRequestListener#requestDestroyed(javax.servlet.ServletRequestEvent)} + * should be ignored by Weld. + */ + private boolean isRequestDestroyed(HttpServletRequest request) { + return request.getAttribute(REQUEST_DESTROYED) != null; + } + + private void safelyDissociate(BoundContext context, T storage) { + try { + context.dissociate(storage); + } catch (Exception e) { + ServletLogger.LOG.unableToDissociateContext(context, storage); + ServletLogger.LOG.catchingDebug(e); } - + } + + private void safelyDeactivate(ManagedContext context, + HttpServletRequest request) { + try { + context.deactivate(); + } catch (Exception e) { + ServletLogger.LOG.unableToDeactivateContext(context, request); + ServletLogger.LOG.catchingDebug(e); + } + } } diff --git a/pom.xml b/pom.xml index bcf773b454..5abe3dce31 100644 --- a/pom.xml +++ b/pom.xml @@ -3,14 +3,14 @@ 4.0.0 weld-core-parent pom - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT Weld Parent org.jboss.weld weld-parent - 40 + 45 @@ -24,15 +24,20 @@ yyyy-MM-dd HH:mm + 1.8 1.8 + + + 11 + ${maven.build.timestamp} -Xmx1024m - 2.3.2 + 2.3.3 @@ -43,54 +48,49 @@ 2.0 - 6.2 - 3.1 - 1.4.0.Final - 2.5.1 - 2.3.2 - 2.0.1.Final - 1.0.1.Final + 6.5.0 + 1.7.0.Alpha10 + 2.5.5 + 2.5.4 + 2.1.0.Final + 1.0.2.Final 1.1.0.Final 1.0.0.CR3 - 1.0.0.CR1 + 1.0.2 1 - 2.5.3 1.2.10.Final - 2.0.6.SP1 - 1.2.4.Final - 1.06 - 3.1.10 - 3.1.11 - 2.1.2-b04 - 2.4.15 - 2.20 - 0.7.9 - 2.0.3.Final - 1.2.1 + 2.0.7.SP2 + 1.2.5.Final + 4.5.3.0 + 4.5.3 + 2.2.1-b05 + 2.4.21 + 2.58.0 + 0.8.7 + 2.4.2.Final + 1.2.2 3.0.2 2.0.0.Final 3.0.0.Final - 3.2.1.Final - 2.0.1.Final - 1.2.2.GA + 3.4.3.Final + 2.2.1.Final + 2.1.18.Final 2.0.0.Final - 2.3.14 + 2.3.17 2.3.6 1.2.7 - 4.12 + 4.13.2 1.2.17 - 1.0.1 - 2.3 1.2.6 1.1.0-beta-1 - 3.1.3 + 3.1.4 6.14.3 - 1.78 - 3.1.SP2 - 1.0.2.Final - 2.2.0.Final + 1.82 + 3.1.SP4 + 1.0.3.Final + 3.0.1.Final @@ -121,12 +121,6 @@ ${groovy.version} - - commons-httpclient - commons-httpclient - ${apache.httpclient.version} - - jakarta.activation jakarta.activation-api @@ -203,12 +197,6 @@ ${atinject.tck.version} - - org.databene - contiperf - ${contiperf.version} - - org.glassfish.web el-impl @@ -528,7 +516,6 @@ - org.codehaus.cargo cargo-maven2-plugin @@ -544,39 +531,6 @@ jacoco-maven-plugin ${jacoco.version} - - - org.codehaus.mojo - selenium-maven-plugin - ${selenium.maven.plugin.version} - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - [3.1.0,) - - checkstyle - - - - - - - - - - - @@ -585,11 +539,6 @@ org.apache.maven.plugins maven-checkstyle-plugin - - - org.eclipse.m2e - lifecycle-mapping - @@ -688,7 +637,7 @@ run - + @@ -699,7 +648,7 @@ - + @@ -802,4 +751,17 @@ + + + + + jboss-public-repository-group + JBoss Public Repository Group + https://repository.jboss.org/nexus/content/groups/public + default + + true + + + diff --git a/porting-package/pom.xml b/porting-package/pom.xml index 271911b3d0..32bf7e9111 100644 --- a/porting-package/pom.xml +++ b/porting-package/pom.xml @@ -3,7 +3,7 @@ weld-core-parent org.jboss.weld - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../pom.xml 4.0.0 @@ -30,7 +30,7 @@ org.jboss.weld weld-core-impl - + org.jboss.weld.module weld-jsf diff --git a/probe/core/pom.xml b/probe/core/pom.xml index 4348c8e21d..262a96fdd8 100644 --- a/probe/core/pom.xml +++ b/probe/core/pom.xml @@ -3,7 +3,7 @@ weld-probe-parent org.jboss.weld.probe - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../pom.xml @@ -87,6 +87,13 @@ false + + org.apache.maven.plugins + maven-source-plugin + + true + + @@ -119,7 +126,7 @@ org.mockito mockito-core - 2.19.0 + 4.3.1 @@ -141,7 +148,6 @@ maven-resources-plugin - 2.6 copy-resources diff --git a/probe/pom.xml b/probe/pom.xml index 7fbbf6b73e..f07126b51b 100644 --- a/probe/pom.xml +++ b/probe/pom.xml @@ -10,7 +10,7 @@ org.jboss.weld weld-core-parent ../pom.xml - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT Weld's inspection and debugging support diff --git a/probe/tests/pom.xml b/probe/tests/pom.xml index 2a02fb8fee..a3c95b495d 100644 --- a/probe/tests/pom.xml +++ b/probe/tests/pom.xml @@ -3,72 +3,72 @@ weld-probe-parent org.jboss.weld.probe - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../pom.xml 4.0.0 org.jboss.weld.probe weld-probe-tests - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT - 1.1.2 - 2.4.0 - 9.0.31 + 1.1.4 + 2.7.0 + 9.0.58 - + junit junit test - + org.jboss.weld.probe weld-probe-core - + org.jboss.weld weld-core-test-common - + jakarta.enterprise jakarta.enterprise.cdi-api provided - + org.jboss.spec.javax.ejb jboss-ejb-api_3.2_spec - + org.jboss.arquillian.junit arquillian-junit-container - + org.jboss.shrinkwrap shrinkwrap-impl-base - + org.glassfish javax.json ${json.version} provided - + org.jboss.spec.javax.servlet jboss-servlet-api_4.0_spec - + net.sourceforge.htmlunit htmlunit @@ -79,7 +79,7 @@ json-path ${json.path.version} - + org.jboss.arquillian arquillian-bom @@ -294,7 +294,7 @@ - + jacoco @@ -311,7 +311,7 @@ org.jboss.weld.tests.* - org.jboss.weld.probe.tests.* + org.jboss.weld.probe.tests.* jacoco.agent diff --git a/tests-arquillian/pom.xml b/tests-arquillian/pom.xml index 8589e08229..527aeaced8 100644 --- a/tests-arquillian/pom.xml +++ b/tests-arquillian/pom.xml @@ -3,7 +3,7 @@ weld-core-parent org.jboss.weld - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../pom.xml 4.0.0 @@ -22,9 +22,6 @@ http://weld.cdi-spec.org - - 2.9 127.0.0.1 @@ -48,12 +45,6 @@ shrinkwrap-impl-base - - org.databene - contiperf - test - - jakarta.enterprise jakarta.enterprise.cdi-api @@ -322,7 +313,7 @@ [9,) - + diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/AllTestRunner.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/AllTestRunner.java deleted file mode 100644 index 4a4fc60079..0000000000 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/AllTestRunner.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.jboss.weld.tests; - -import org.jboss.shrinkwrap.api.asset.Asset; -import org.jboss.shrinkwrap.impl.base.URLPackageScanner; -import org.junit.runners.Suite; -import org.junit.runners.model.InitializationError; -import org.junit.runners.model.RunnerBuilder; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -public class AllTestRunner extends Suite { - public AllTestRunner(Class superClass, RunnerBuilder builder) throws InitializationError { - super(builder, superClass, getAllClasses()); - } - - private static Class[] getAllClasses() { - final List> classes = new ArrayList>(); - final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - URLPackageScanner.newInstance( - true, - classLoader, - new URLPackageScanner.Callback() { - @Override - public void classFound(String className, Asset asset) { - if (!className.endsWith("Test")) { - return; - } - if (className.substring(className.lastIndexOf('.') + 1).length() <= 4) { - return; - } - try { - classes.add(classLoader.loadClass(className)); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - }, - AllTestRunner.class.getPackage().getName()).scanPackage(); - //ExampleTest.class.getPackage()).scanPackage(); - - Collections.sort(classes, new Comparator>() { - public int compare(Class o1, Class o2) { - return o1.getPackage().getName().compareTo(o2.getPackage().getName()); - } - }); - return classes.toArray(new Class[]{}); - } -} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/Categories.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/Categories.java deleted file mode 100644 index 1950607588..0000000000 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/Categories.java +++ /dev/null @@ -1,201 +0,0 @@ -package org.jboss.weld.tests; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.junit.experimental.categories.Category; -import org.junit.runner.Description; -import org.junit.runner.manipulation.Filter; -import org.junit.runner.manipulation.NoTestsRemainException; -import org.junit.runners.Suite; -import org.junit.runners.model.InitializationError; -import org.junit.runners.model.RunnerBuilder; - -/** - * From a given set of test classes, runs only the classes and methods that are - * annotated with either the category given with the @IncludeCategory - * annotation, or a subtype of that category. - *

- * Note that, for now, annotating suites with {@code @Category} has no effect. - * Categories must be annotated on the direct method or class. - *

- * Example: - *

- *

- * public interface FastTests {
- * }
- *
- * public interface SlowTests {
- * }
- *
- * public static class A {
- * 	@Test
- * 	public void a() {
- * 		fail();
- *     }
- *
- * 	@Category(SlowTests.class)
- * 	@Test
- * 	public void b() {
- *     }
- * }
- *
- * @Category( { SlowTests.class, FastTests.class })
- * public static class B {
- * 	@Test
- * 	public void c() {
- *
- *     }
- * }
- *
- * @RunWith(Categories.class)
- * @IncludeCategory(SlowTests.class)
- * @SuiteClasses( { A.class, B.class })
- * // Note that Categories is a kind of Suite
- * public static class SlowTestSuite {
- * }
- * 
- */ -public class Categories extends Suite { - @Retention(RetentionPolicy.RUNTIME) - public @interface IncludeCategory { - Class[] value(); - } - - @Retention(RetentionPolicy.RUNTIME) - public @interface ExcludeCategory { - Class[] value(); - } - - public static class CategoryFilter extends Filter { - public static CategoryFilter include(Class... categoryType) { - return new CategoryFilter(categoryType, null); - } - - public static CategoryFilter include(Class categoryType) { - return new CategoryFilter(new Class[]{categoryType}, null); - } - - private final Class[] fIncluded; - - private final Class[] fExcluded; - - public CategoryFilter(Class[] includedCategory, Class[] excludedCategory) { - fIncluded = includedCategory; - fExcluded = excludedCategory; - } - - @Override - public String describe() { - return ((fIncluded == null || fIncluded.length == 1) ? "category " : "categories ") + join(", ", fIncluded); - } - - private String join(String seperator, Class... values) { - if (values == null || values.length == 0) { - return ""; - } - StringBuilder sb = new StringBuilder(values[0].toString()); - for (int i = 1; i < values.length; i++) { - sb.append(seperator).append(values[i].toString()); - } - return sb.toString(); - } - - @Override - public boolean shouldRun(Description description) { - if (hasCorrectCategoryAnnotation(description)) { - return true; - } - for (Description each : description.getChildren()) { - if (shouldRun(each)) { - return true; - } - } - return false; - } - - private boolean hasCorrectCategoryAnnotation(Description description) { - List> categories = categories(description); - if (categories.isEmpty()) { - return fIncluded == null; - } - - if (!methodContainsAnyExcludedCategories(categories, fExcluded)) { - return methodContainsAllIncludedCategories(categories, fIncluded); - } - return false; - } - - private List> categories(Description description) { - ArrayList> categories = new ArrayList>(); - categories.addAll(Arrays.asList(directCategories(description))); - categories.addAll(Arrays.asList(directCategories(parentDescription(description)))); - return categories; - } - - private Description parentDescription(Description description) { - return Description.createSuiteDescription(description.getTestClass()); - } - - private Class[] directCategories(Description description) { - Category annotation = description.getAnnotation(Category.class); - if (annotation == null) { - return new Class[0]; - } - return annotation.value(); - } - - private boolean methodContainsAnyExcludedCategories(List> categories, Class[] excludedCategories) { - if (excludedCategories != null) { - for (Class eachExcluded : excludedCategories) { - if (containsCategory(categories, eachExcluded)) { - return true; - } - } - } - return false; - } - - private boolean methodContainsAllIncludedCategories(List> categories, Class[] includedCategories) { - if (includedCategories != null) { - for (Class eachIncluded : includedCategories) { - if (!containsCategory(categories, eachIncluded)) { - return false; - } - } - } - return true; - } - - private boolean containsCategory(List> categories, Class categoryToMatch) { - for (Class each : categories) { - if (categoryToMatch.isAssignableFrom(each)) { - return true; - } - } - return false; - } - } - - public Categories(Class klass, RunnerBuilder builder) throws InitializationError { - super(klass, builder); - try { - filter(new CategoryFilter(getIncludedCategory(klass), getExcludedCategory(klass))); - } catch (NoTestsRemainException e) { - throw new InitializationError(e); - } - } - - private Class[] getIncludedCategory(Class klass) { - IncludeCategory annotation = klass.getAnnotation(IncludeCategory.class); - return annotation == null ? null : annotation.value(); - } - - private Class[] getExcludedCategory(Class klass) { - ExcludeCategory annotation = klass.getAnnotation(ExcludeCategory.class); - return annotation == null ? null : annotation.value(); - } -} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/IntegrationPerformanceSuite.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/IntegrationPerformanceSuite.java deleted file mode 100644 index 0eda627c69..0000000000 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/IntegrationPerformanceSuite.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * JBoss, Home of Professional Open Source - * Copyright 2009, Red Hat Middleware LLC, and individual contributors - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * Licensed 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.jboss.weld.tests; - -import org.jboss.weld.tests.Categories.ExcludeCategory; -import org.jboss.weld.tests.Categories.IncludeCategory; -import org.jboss.weld.tests.category.Broken; -import org.jboss.weld.tests.category.Integration; -import org.jboss.weld.tests.category.Performance; -import org.junit.runner.RunWith; -import org.junit.runners.Suite.SuiteClasses; - -/** - * IntegrationSuite - * - * @author Aslak Knutsen - * @version $Revision: $ - */ -@RunWith(Categories.class) -@IncludeCategory({Integration.class, Performance.class}) -@ExcludeCategory(Broken.class) -@SuiteClasses(AllTests.class) -public class IntegrationPerformanceSuite { - -} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/NormalPerformanceSuite.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/NormalPerformanceSuite.java deleted file mode 100644 index 3ff6173a90..0000000000 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/NormalPerformanceSuite.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * JBoss, Home of Professional Open Source - * Copyright 2009, Red Hat Middleware LLC, and individual contributors - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * Licensed 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.jboss.weld.tests; - -import org.jboss.weld.tests.Categories.ExcludeCategory; -import org.jboss.weld.tests.Categories.IncludeCategory; -import org.jboss.weld.tests.category.Broken; -import org.jboss.weld.tests.category.Integration; -import org.jboss.weld.tests.category.Performance; -import org.junit.runner.RunWith; -import org.junit.runners.Suite.SuiteClasses; - -/** - * IntegrationSuite - * - * @author Aslak Knutsen - * @version $Revision: $ - */ -@RunWith(Categories.class) -@IncludeCategory(Performance.class) -@ExcludeCategory({Broken.class, Integration.class}) -@SuiteClasses(AllTests.class) -public class NormalPerformanceSuite { -} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/alternatives/customBeanPriority/CustomBeanPriorityTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/alternatives/customBeanPriority/CustomBeanPriorityTest.java index 86c1f727f2..42a8412f09 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/alternatives/customBeanPriority/CustomBeanPriorityTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/alternatives/customBeanPriority/CustomBeanPriorityTest.java @@ -18,7 +18,6 @@ import javax.enterprise.inject.spi.Extension; import javax.inject.Inject; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.BeanArchive; @@ -30,28 +29,31 @@ import org.junit.runner.RunWith; /** - * Tests that you can create a custom bean via (Weld)BeanConfigurator and give it a priority hence selecting it. + * Tests that you can create a custom bean via (Weld)BeanConfigurator and give + * it a priority hence selecting it. * @author Matej Novotny */ @RunWith(Arquillian.class) public class CustomBeanPriorityTest { - @Deployment - public static JavaArchive createTestArchive() { - return ShrinkWrap.create(BeanArchive.class, Utils.getDeploymentNameAsHash(CustomBeanPriorityTest.class)) - .addClasses(CustomBeanPriorityTest.class, MyExtension.class, PlainFoo.class, FooAlternative.class) - .addAsServiceProvider(Extension.class, MyExtension.class); - } + @Deployment + public static JavaArchive createTestArchive() { + return ShrinkWrap + .create(BeanArchive.class, + Utils.getDeploymentNameAsHash(CustomBeanPriorityTest.class)) + .addClasses(CustomBeanPriorityTest.class, MyExtension.class, + PlainFoo.class, FooAlternative.class) + .addAsServiceProvider(Extension.class, MyExtension.class); + } - @Inject - PlainFoo foo; + @Inject PlainFoo foo; - @Inject - FooAlternative alternative; + @Inject FooAlternative alternative; - @Test - public void contextLifecycleEventFiredForPostConstructCallbackActivation() { - Assert.assertEquals("bar", alternative.ping()); - Assert.assertEquals("bar", foo.ping()); - } + @Test + public void contextLifecycleEventFiredForPostConstructCallbackActivation() { + Assert.assertEquals("bar", alternative.ping()); + Assert.assertEquals("bar", foo.ping()); + Assert.assertEquals(1, MyExtension.PSB_OBSERVED); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/alternatives/customBeanPriority/MyExtension.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/alternatives/customBeanPriority/MyExtension.java index 806deaea25..46ca48f08d 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/alternatives/customBeanPriority/MyExtension.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/alternatives/customBeanPriority/MyExtension.java @@ -22,7 +22,7 @@ import javax.enterprise.inject.Default; import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.Extension; - +import javax.enterprise.inject.spi.ProcessSyntheticBean; import org.jboss.weld.bootstrap.event.WeldAfterBeanDiscovery; /** @@ -31,15 +31,22 @@ */ public class MyExtension implements Extension { - public void observe(@Observes WeldAfterBeanDiscovery abd, BeanManager bm) { - // register an alternative bean via configurator with priority - abd.addBean() - .beanClass(FooAlternative.class) - .types(Object.class, FooAlternative.class, PlainFoo.class) - .createWith((ctx) -> new FooAlternative()) - .alternative(true) - .priority(100) - .qualifiers(Any.Literal.INSTANCE, Default.Literal.INSTANCE) - .scope(Dependent.class); - } + public static int PSB_OBSERVED = 0; + + public void observe(@Observes WeldAfterBeanDiscovery abd, BeanManager bm) { + // register an alternative bean via configurator with priority + abd.addBean() + .beanClass(FooAlternative.class) + .types(Object.class, FooAlternative.class, PlainFoo.class) + .createWith((ctx) -> new FooAlternative()) + .alternative(true) + .priority(100) + .qualifiers(Any.Literal.INSTANCE, Default.Literal.INSTANCE) + .scope(Dependent.class); + } + + public void + observeProcessBean(@Observes ProcessSyntheticBean psb) { + PSB_OBSERVED++; + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/beanManager/annotatedType/CreateAnnotatedTypeWithIdTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/beanManager/annotatedType/CreateAnnotatedTypeWithIdTest.java index bcd4de5b92..c215d354ed 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/beanManager/annotatedType/CreateAnnotatedTypeWithIdTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/beanManager/annotatedType/CreateAnnotatedTypeWithIdTest.java @@ -20,16 +20,14 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import java.net.URL; -import java.net.URLClassLoader; - +import java.security.ProtectionDomain; import javax.enterprise.context.Dependent; import javax.enterprise.inject.spi.AnnotatedMethod; import javax.enterprise.inject.spi.AnnotatedType; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.classfilewriter.AccessFlag; +import org.jboss.classfilewriter.ClassFactory; import org.jboss.classfilewriter.ClassFile; import org.jboss.classfilewriter.code.CodeAttribute; import org.jboss.shrinkwrap.api.Archive; @@ -41,7 +39,6 @@ import org.jboss.weld.resources.ClassTransformer; import org.jboss.weld.test.util.Utils; import org.jboss.weld.tests.category.EmbeddedContainer; -import org.jboss.weld.util.bytecode.ClassFileUtils; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -55,40 +52,77 @@ @RunWith(Arquillian.class) public class CreateAnnotatedTypeWithIdTest { - @Deployment - public static Archive createTestArchive() { - return ShrinkWrap.create(BeanArchive.class, Utils.getDeploymentNameAsHash(CreateAnnotatedTypeWithIdTest.class)).addClass(Component.class); - } + @Deployment + public static Archive createTestArchive() { + return ShrinkWrap + .create(BeanArchive.class, Utils.getDeploymentNameAsHash( + CreateAnnotatedTypeWithIdTest.class)) + .addClass(Component.class); + } - @Test - public void testCreateAnnotatedTypeWithId(BeanManagerImpl beanManager) { - AnnotatedType annotatedType = beanManager.createAnnotatedType(Component.class); - assertTrue(annotatedType.isAnnotationPresent(Dependent.class)); - assertFalse(hasPongMethod(annotatedType)); - // Create a different class with the same name - ClassFile componentClassFile = new ClassFile(Component.class.getName(), Object.class.getName()); - // Add void pong() - CodeAttribute b = componentClassFile.addMethod(AccessFlag.of(AccessFlag.PUBLIC, AccessFlag.SYNTHETIC), "pong", "V").getCodeAttribute(); - b.returnInstruction(); - Class componentClass = ClassFileUtils.toClass(componentClassFile, new URLClassLoader(new URL[] {}), null); - @SuppressWarnings("unchecked") - BackedAnnotatedType newAnnotatedType = (BackedAnnotatedType) beanManager.createAnnotatedType(componentClass, - componentClass.getName() + componentClass.getClassLoader().hashCode()); - assertFalse(newAnnotatedType.isAnnotationPresent(Dependent.class)); - assertTrue(hasPongMethod(newAnnotatedType)); - // Dispose annotated type - AnnotatedTypeIdentifier identifier = newAnnotatedType.getIdentifier(); - beanManager.disposeAnnotatedType(componentClass, componentClass.getName() + componentClass.getClassLoader().hashCode()); - assertNull(beanManager.getServices().get(ClassTransformer.class).getSlimAnnotatedTypeById(identifier)); - } + @Test + public void testCreateAnnotatedTypeWithId(BeanManagerImpl beanManager) { + AnnotatedType annotatedType = + beanManager.createAnnotatedType(Component.class); + assertTrue(annotatedType.isAnnotationPresent(Dependent.class)); + assertFalse(hasPongMethod(annotatedType)); + ClassFactory factory = (loader, name, b, off, len, protectionDomain) -> { + if (loader instanceof SimpleClassLoader) { + return ((SimpleClassLoader)loader) + .publicDefineClass(name, b, off, len, protectionDomain); + } else { + throw new RuntimeException("ClassLoader needs to be an instance of " + + "SimpleClassLoader but was: " + loader); + } + }; + // Create a different class with the same name + // we need to define this class in a new CL to avoid duplicate declaration - + // hence we use CFW way to define it + ClassFile componentClassFile = + new ClassFile(Component.class.getName(), Object.class.getName(), + new SimpleClassLoader(Component.class.getClassLoader()), + factory, new String[] {}); + // Add void pong() + CodeAttribute b = + componentClassFile + .addMethod(AccessFlag.of(AccessFlag.PUBLIC, AccessFlag.SYNTHETIC), + "pong", "V") + .getCodeAttribute(); + b.returnInstruction(); + Class componentClass = componentClassFile.define(); + @SuppressWarnings("unchecked") + BackedAnnotatedType newAnnotatedType = + (BackedAnnotatedType)beanManager.createAnnotatedType( + componentClass, componentClass.getName() + + componentClass.getClassLoader().hashCode()); + assertFalse(newAnnotatedType.isAnnotationPresent(Dependent.class)); + assertTrue(hasPongMethod(newAnnotatedType)); + // Dispose annotated type + AnnotatedTypeIdentifier identifier = newAnnotatedType.getIdentifier(); + beanManager.disposeAnnotatedType( + componentClass, + componentClass.getName() + componentClass.getClassLoader().hashCode()); + assertNull(beanManager.getServices() + .get(ClassTransformer.class) + .getSlimAnnotatedTypeById(identifier)); + } - private boolean hasPongMethod(AnnotatedType annotatedType) { - for (AnnotatedMethod annotatedMethod : annotatedType.getMethods()) { - if (annotatedMethod.getJavaMember().getName().equals("pong")) { - return true; - } - } - return false; + private boolean hasPongMethod(AnnotatedType annotatedType) { + for (AnnotatedMethod annotatedMethod : annotatedType.getMethods()) { + if (annotatedMethod.getJavaMember().getName().equals("pong")) { + return true; + } } + return false; + } + private static class SimpleClassLoader extends ClassLoader { + + SimpleClassLoader(ClassLoader parent) { super(parent); } + + public final Class publicDefineClass(String name, byte[] b, int off, + int len, ProtectionDomain pd) { + return super.defineClass(name, b, off, len, pd); + } + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/BuiltInBeanPassivationCapableTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/BuiltInBeanPassivationCapableTest.java index 45948ac04d..947e64677e 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/BuiltInBeanPassivationCapableTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/BuiltInBeanPassivationCapableTest.java @@ -25,13 +25,11 @@ import static org.jboss.weld.tests.builtinBeans.Checker.checkUserTransaction; import java.security.Principal; - import javax.enterprise.event.Event; import javax.enterprise.inject.Instance; import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.InjectionPoint; import javax.transaction.UserTransaction; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.Archive; @@ -47,90 +45,109 @@ @RunWith(Arquillian.class) public class BuiltInBeanPassivationCapableTest { - @Deployment - public static Archive deploy() { - return ShrinkWrap.create(BeanArchive.class, Utils.getDeploymentNameAsHash(BuiltInBeanPassivationCapableTest.class)).intercept(FooInterceptor.class) - // WELD-1048 - .decorate(AnimalDecorator.class) - .addPackage(BuiltInBeanPassivationCapableTest.class.getPackage()) - .addClass(Utils.class); - } + @Deployment + public static Archive deploy() { + return ShrinkWrap + .create(BeanArchive.class, Utils.getDeploymentNameAsHash( + BuiltInBeanPassivationCapableTest.class)) + .intercept(FooInterceptor.class) + // WELD-1048 + .decorate(AnimalDecorator.class) + .addPackage(BuiltInBeanPassivationCapableTest.class.getPackage()) + .addClass(Utils.class); + } - @Test - @Category({Integration.class, Broken.class}) - public void testPrincipal(Principal principal) throws Throwable { - Principal principal1 = Utils.deserialize(Utils.serialize(principal)); - Assert.assertTrue(checkPrincipal(principal1)); - } + @Test + @Category({Integration.class, Broken.class}) + public void testPrincipal(Principal principal) throws Throwable { + Principal principal1 = Utils.deserialize(Utils.serialize(principal)); + Assert.assertTrue(checkPrincipal(principal1)); + } - @Test - public void testUserTransactionBean(UserTransaction userTransaction) throws Throwable { - UserTransaction userTransaction1 = Utils.deserialize(Utils.serialize(userTransaction)); - Assert.assertTrue(checkUserTransaction(userTransaction1)); - } + @Test + public void testUserTransactionBean(UserTransaction userTransaction) + throws Throwable { + // proxy for this class will be declared using our CL hence the + // deserialization also needs to use the same CL + UserTransaction userTransaction1 = + Utils.deserialize(Utils.serialize(userTransaction), + userTransaction.getClass().getClassLoader()); + Assert.assertTrue(checkUserTransaction(userTransaction1)); + } - @Test - public void testBeanManagerBean(BeanManager beanManager) throws Throwable { - BeanManager beanManager1 = Utils.deserialize(Utils.serialize(beanManager)); - Assert.assertTrue(checkBeanManager(beanManager1)); - Assert.assertTrue(checkEquality(beanManager, beanManager1)); - } + @Test + public void testBeanManagerBean(BeanManager beanManager) throws Throwable { + BeanManager beanManager1 = Utils.deserialize(Utils.serialize(beanManager)); + Assert.assertTrue(checkBeanManager(beanManager1)); + Assert.assertTrue(checkEquality(beanManager, beanManager1)); + } - @Test - public void testInstance(Consumer consumer) throws Throwable { - Instance instance = consumer.getCow(); - Instance instance1 = Utils.deserialize(Utils.serialize(instance)); - Assert.assertTrue(checkInstance(instance1)); - Assert.assertTrue(checkEquality(instance, instance1)); - } + @Test + public void testInstance(Consumer consumer) throws Throwable { + Instance instance = consumer.getCow(); + Instance instance1 = Utils.deserialize(Utils.serialize(instance)); + Assert.assertTrue(checkInstance(instance1)); + Assert.assertTrue(checkEquality(instance, instance1)); + } - @Test - public void testEvent(Consumer consumer, CowEventObserver observer) throws Throwable { - Event event = consumer.getEvent(); - Event event1 = Utils.deserialize(Utils.serialize(event)); - Assert.assertTrue(checkEvent(event1, observer)); - Assert.assertTrue(checkEquality(event, event1)); - } + @Test + public void testEvent(Consumer consumer, CowEventObserver observer) + throws Throwable { + Event event = consumer.getEvent(); + Event event1 = Utils.deserialize(Utils.serialize(event)); + Assert.assertTrue(checkEvent(event1, observer)); + Assert.assertTrue(checkEquality(event, event1)); + } - @Test - public void testFieldInjectionPoint(FieldInjectionPointConsumer consumer) throws Throwable { - Dog.reset(); - consumer.ping(); - InjectionPoint injectionPoint = Dog.getInjectionPoint(); - InjectionPoint injectionPoint1 = Utils.deserialize(Utils.serialize(injectionPoint)); - Assert.assertTrue(checkInjectionPoint(injectionPoint1, FieldInjectionPointConsumer.class)); - Assert.assertTrue(checkEquality(injectionPoint, injectionPoint1)); - } + @Test + public void testFieldInjectionPoint(FieldInjectionPointConsumer consumer) + throws Throwable { + Dog.reset(); + consumer.ping(); + InjectionPoint injectionPoint = Dog.getInjectionPoint(); + InjectionPoint injectionPoint1 = + Utils.deserialize(Utils.serialize(injectionPoint)); + Assert.assertTrue(checkInjectionPoint(injectionPoint1, + FieldInjectionPointConsumer.class)); + Assert.assertTrue(checkEquality(injectionPoint, injectionPoint1)); + } - @Test - public void testConstructorInjectionPoint(ConstructorInjectionPointConsumer consumer) throws Throwable { - Dog.reset(); - consumer.ping(); - InjectionPoint injectionPoint = Dog.getInjectionPoint(); - InjectionPoint injectionPoint1 = Utils.deserialize(Utils.serialize(injectionPoint)); - Assert.assertTrue(checkInjectionPoint(injectionPoint1, ConstructorInjectionPointConsumer.class)); - Assert.assertTrue(checkEquality(injectionPoint, injectionPoint1)); - } + @Test + public void + testConstructorInjectionPoint(ConstructorInjectionPointConsumer consumer) + throws Throwable { + Dog.reset(); + consumer.ping(); + InjectionPoint injectionPoint = Dog.getInjectionPoint(); + InjectionPoint injectionPoint1 = + Utils.deserialize(Utils.serialize(injectionPoint)); + Assert.assertTrue(checkInjectionPoint( + injectionPoint1, ConstructorInjectionPointConsumer.class)); + Assert.assertTrue(checkEquality(injectionPoint, injectionPoint1)); + } - @Test - public void testMethodInjectionPoint(MethodInjectionPointConsumer consumer) throws Throwable { - Dog.reset(); - consumer.ping(); - InjectionPoint injectionPoint = Dog.getInjectionPoint(); - InjectionPoint injectionPoint1 = Utils.deserialize(Utils.serialize(injectionPoint)); - Assert.assertTrue(checkInjectionPoint(injectionPoint1, MethodInjectionPointConsumer.class)); - Assert.assertTrue(checkEquality(injectionPoint, injectionPoint1)); - } + @Test + public void testMethodInjectionPoint(MethodInjectionPointConsumer consumer) + throws Throwable { + Dog.reset(); + consumer.ping(); + InjectionPoint injectionPoint = Dog.getInjectionPoint(); + InjectionPoint injectionPoint1 = + Utils.deserialize(Utils.serialize(injectionPoint)); + Assert.assertTrue(checkInjectionPoint(injectionPoint1, + MethodInjectionPointConsumer.class)); + Assert.assertTrue(checkEquality(injectionPoint, injectionPoint1)); + } - @Test - public void testAllOnBean(Consumer consumer) throws Throwable { - consumer.check(); - Consumer consumer1 = Utils.deserialize(Utils.serialize(consumer)); - consumer1.check(); - } + @Test + public void testAllOnBean(Consumer consumer) throws Throwable { + consumer.check(); + Consumer consumer1 = Utils.deserialize(Utils.serialize(consumer)); + consumer1.check(); + } - @Test - public void testInjectedBeanMetadata(Sheep sheep) throws Throwable { - Utils.deserialize(Utils.serialize(sheep)); - } + @Test + public void testInjectedBeanMetadata(Sheep sheep) throws Throwable { + Utils.deserialize(Utils.serialize(sheep)); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/ee/servlet/session/EagerHttpSessionTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/ee/servlet/session/EagerHttpSessionTest.java index 6c0e6f8fb9..cbf4c1d062 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/ee/servlet/session/EagerHttpSessionTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/ee/servlet/session/EagerHttpSessionTest.java @@ -18,10 +18,10 @@ import static org.junit.Assert.assertFalse; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.WebClient; import java.net.URL; - import javax.servlet.http.HttpSession; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -34,11 +34,9 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebClient; - /** - * Test that an invocation of an injected {@link HttpSession} (provided by {@link org.jboss.weld.module.web.HttpSessionBean}) triggers session creation. + * Test that an invocation of an injected {@link HttpSession} (provided by + * {@link org.jboss.weld.module.web.HttpSessionBean}) triggers session creation. * * @author Martin Kouba * @see WELD-2346 @@ -47,26 +45,24 @@ @Category(Integration.class) public class EagerHttpSessionTest { - @ArquillianResource - private URL url; - - @Deployment(testable = false) - public static WebArchive createTestArchive() { - return ShrinkWrap - .create(WebArchive.class, - Utils.getDeploymentNameAsHash(EagerHttpSessionTest.class, - Utils.ARCHIVE_TYPE.WAR)) - .addClasses(TestServlet.class, EagerHttpSessionTest.class) - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); - } + @ArquillianResource private URL url; - @Test - public void testHttpSession() throws Exception { - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(true); - Page page = client.getPage(url + "/test"); - String id = page.getWebResponse().getContentAsString(); - assertFalse(id.isEmpty()); - } + @Deployment(testable = false) + public static WebArchive createTestArchive() { + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash(EagerHttpSessionTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addClasses(TestServlet.class, EagerHttpSessionTest.class) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } + @Test + public void testHttpSession() throws Exception { + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + Page page = client.getPage(url + "/test"); + String id = page.getWebResponse().getContentAsString(); + assertFalse(id.isEmpty()); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/broken/interceptor/UnavailableInterceptedBeanMetadataTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/broken/interceptor/UnavailableInterceptedBeanMetadataTest.java index 7ee92e640e..49963cf505 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/broken/interceptor/UnavailableInterceptedBeanMetadataTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/broken/interceptor/UnavailableInterceptedBeanMetadataTest.java @@ -18,10 +18,12 @@ import static org.junit.Assert.assertEquals; +import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.WebClient; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -34,29 +36,31 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; -import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebClient; - @Category(Integration.class) @RunWith(Arquillian.class) public class UnavailableInterceptedBeanMetadataTest { - @Deployment(testable = false) - public static WebArchive createTestArchive() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(UnavailableInterceptedBeanMetadataTest.class, Utils.ARCHIVE_TYPE.WAR)) - .addClasses(FooServlet.class, FooServletInterceptor.class, FooServletInterceptorBinding.class) - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); - } + @Deployment(testable = false) + public static WebArchive createTestArchive() { + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash( + UnavailableInterceptedBeanMetadataTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addClasses(FooServlet.class, FooServletInterceptor.class, + FooServletInterceptorBinding.class) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } - @ArquillianResource - private URL contextPath; + @ArquillianResource private URL contextPath; - @Test - public void testMetadataIsNotAvailable() throws FailingHttpStatusCodeException, MalformedURLException, IOException { - WebClient webClient = new WebClient(); - webClient.setThrowExceptionOnFailingStatusCode(true); - Page page = webClient.getPage(contextPath + "FooServlet"); - assertEquals("OK", page.getWebResponse().getContentAsString().trim()); - } + @Test + public void testMetadataIsNotAvailable() + throws FailingHttpStatusCodeException, MalformedURLException, + IOException { + WebClient webClient = new WebClient(); + webClient.getOptions().setThrowExceptionOnFailingStatusCode(false); + Page page = webClient.getPage(contextPath + "FooServlet"); + assertEquals("OK", page.getWebResponse().getContentAsString().trim()); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/ActualBean.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/ActualBean.java new file mode 100644 index 0000000000..62b31ed65c --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/ActualBean.java @@ -0,0 +1,30 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.builtinBeans.metadata.multiple.decorators.interceptors; + +import javax.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class ActualBean implements SomeInterface { + + @Override + @SomeBinding + public String ping() { + return "pong"; + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/DecoratorOne.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/DecoratorOne.java new file mode 100644 index 0000000000..fab7e4adf9 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/DecoratorOne.java @@ -0,0 +1,39 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.builtinBeans.metadata.multiple.decorators.interceptors; + +import javax.annotation.Priority; +import javax.decorator.Decorator; +import javax.decorator.Delegate; +import javax.enterprise.inject.Decorated; +import javax.enterprise.inject.spi.Bean; +import javax.inject.Inject; + +@Decorator +@Priority(1) +public class DecoratorOne implements SomeInterface { + + @Delegate @Inject SomeInterface delegate; + + @Inject @Decorated Bean metadata; + + @Override + public String ping() { + return metadata.getBeanClass().getSimpleName() + delegate.ping(); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/DecoratorTwo.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/DecoratorTwo.java new file mode 100644 index 0000000000..32d82b2439 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/DecoratorTwo.java @@ -0,0 +1,39 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.builtinBeans.metadata.multiple.decorators.interceptors; + +import javax.annotation.Priority; +import javax.decorator.Decorator; +import javax.decorator.Delegate; +import javax.enterprise.inject.Decorated; +import javax.enterprise.inject.spi.Bean; +import javax.inject.Inject; + +@Decorator +@Priority(2) +public class DecoratorTwo implements SomeInterface { + + @Delegate @Inject SomeInterface delegate; + + @Inject @Decorated Bean metadata; + + @Override + public String ping() { + return metadata.getBeanClass().getSimpleName() + delegate.ping(); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/InterceptorOne.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/InterceptorOne.java new file mode 100644 index 0000000000..4212041ceb --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/InterceptorOne.java @@ -0,0 +1,39 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.builtinBeans.metadata.multiple.decorators.interceptors; + +import javax.annotation.Priority; +import javax.enterprise.inject.Intercepted; +import javax.enterprise.inject.spi.Bean; +import javax.inject.Inject; +import javax.interceptor.AroundInvoke; +import javax.interceptor.Interceptor; +import javax.interceptor.InvocationContext; + +@Interceptor +@Priority(1) +@SomeBinding +public class InterceptorOne { + + @Inject @Intercepted Bean metadata; + + @AroundInvoke + public Object intercept(InvocationContext ctx) throws Exception { + return ctx.proceed() + metadata.getBeanClass().getSimpleName(); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/InterceptorTwo.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/InterceptorTwo.java new file mode 100644 index 0000000000..e2b2dd9345 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/InterceptorTwo.java @@ -0,0 +1,39 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.builtinBeans.metadata.multiple.decorators.interceptors; + +import javax.annotation.Priority; +import javax.enterprise.inject.Intercepted; +import javax.enterprise.inject.spi.Bean; +import javax.inject.Inject; +import javax.interceptor.AroundInvoke; +import javax.interceptor.Interceptor; +import javax.interceptor.InvocationContext; + +@Interceptor +@Priority(1) +@SomeBinding +public class InterceptorTwo { + + @Inject @Intercepted Bean metadata; + + @AroundInvoke + public Object intercept(InvocationContext ctx) throws Exception { + return ctx.proceed() + metadata.getBeanClass().getSimpleName(); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/MultipleDecoratorsMetadataTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/MultipleDecoratorsMetadataTest.java new file mode 100644 index 0000000000..ede3166a77 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/MultipleDecoratorsMetadataTest.java @@ -0,0 +1,50 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.builtinBeans.metadata.multiple.decorators.interceptors; + +import javax.inject.Inject; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.BeanArchive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.weld.test.util.Utils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(Arquillian.class) +public class MultipleDecoratorsMetadataTest { + + @Deployment + public static Archive getDeployment() { + return ShrinkWrap + .create(BeanArchive.class, Utils.getDeploymentNameAsHash( + MultipleDecoratorsMetadataTest.class)) + .addPackage(MultipleDecoratorsMetadataTest.class.getPackage()); + } + + @Inject SomeInterface bean; + + @Test + public void beanMetadataAvailableTest() { + String beanClass = ActualBean.class.getSimpleName(); + String expected = beanClass + beanClass + "pong" + beanClass + beanClass; + Assert.assertEquals(expected, bean.ping()); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/SomeBinding.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/SomeBinding.java new file mode 100644 index 0000000000..066cd96d92 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/SomeBinding.java @@ -0,0 +1,33 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.builtinBeans.metadata.multiple.decorators.interceptors; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import javax.interceptor.InterceptorBinding; + +@InterceptorBinding +@Inherited +@Target({TYPE, METHOD}) +@Retention(RUNTIME) +public @interface SomeBinding {} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/SomeInterface.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/SomeInterface.java new file mode 100644 index 0000000000..f3633c05c4 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/builtinBeans/metadata/multiple/decorators/interceptors/SomeInterface.java @@ -0,0 +1,23 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.builtinBeans.metadata.multiple.decorators.interceptors; + +public interface SomeInterface { + + String ping(); +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/category/Slow.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/category/Slow.java index 22b0aaa845..bc8d2c562d 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/category/Slow.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/category/Slow.java @@ -16,15 +16,10 @@ */ package org.jboss.weld.tests.category; -import org.jboss.weld.tests.NormalSuite; - /** - * Marker Interface for JUnit Category marking a Slow running test.
- * Used to exclude Integration and Performance tests from {@link NormalSuite} + * Marker Interface for JUnit Category marking a Slow running test. * * @author Aslak Knutsen * @version $Revision: $ */ -public interface Slow { - -} +public interface Slow {} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ClassDefiningWithProducerTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ClassDefiningWithProducerTest.java new file mode 100644 index 0000000000..06aadbdf09 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ClassDefiningWithProducerTest.java @@ -0,0 +1,61 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.classDefining; + +import javax.inject.Inject; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.BeanArchive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.weld.test.util.Utils; +import org.jboss.weld.tests.classDefining.a.BeanWithProducer; +import org.jboss.weld.tests.classDefining.b.BeanInterface; +import org.jboss.weld.tests.classDefining.c.AppScopedBean; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests that we are able to define a proxy class for producer method that + * returns a type from different package. In JDK 11+ this means we need to + * perform lookup in correct module. + */ +@RunWith(Arquillian.class) +public class ClassDefiningWithProducerTest { + + @Deployment + public static Archive deploy() { + return ShrinkWrap + .create(BeanArchive.class, Utils.getDeploymentNameAsHash( + ClassDefiningWithProducerTest.class)) + .addClass(ClassDefiningWithProducerTest.class) + .addClass(BeanWithProducer.class) + .addClass(BeanInterface.class) + .addClass(AppScopedBean.class); + } + + @Inject BeanWithProducer bean; + + @Test + public void testProxyDefinitionWorks() { + // invoke the method + Assert.assertEquals(666, bean.ping()); + Assert.assertEquals(666, bean.pingNested()); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/a/BeanWithProducer.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/a/BeanWithProducer.java new file mode 100644 index 0000000000..3bc3eb990f --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/a/BeanWithProducer.java @@ -0,0 +1,55 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.classDefining.a; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; +import javax.inject.Inject; +import org.jboss.weld.tests.classDefining.b.BeanInterface; +import org.jboss.weld.tests.classDefining.c.AppScopedBean; + +@ApplicationScoped +public class BeanWithProducer { + + @Inject private AppScopedBean bean; + + private int number; + private int number2; + + @Produces + @ApplicationScoped + public BeanInterface createTestInterface() { + return x -> number = x; + } + + @Produces + @ApplicationScoped + public BeanInterface.NestedInterface createNestedInterface() { + return x -> number2 = x; + } + + public int ping() { + bean.passNumberToInterface(); + return number; + } + + public int pingNested() { + bean.passNumberToNestedInterface(); + return number2; + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/b/BeanInterface.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/b/BeanInterface.java new file mode 100644 index 0000000000..5e975d5b3f --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/b/BeanInterface.java @@ -0,0 +1,29 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.classDefining.b; + +@FunctionalInterface +public interface BeanInterface { + + void setNumber(int number); + + @FunctionalInterface + interface NestedInterface { + void setNumber(int number); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/c/AppScopedBean.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/c/AppScopedBean.java new file mode 100644 index 0000000000..6641df8304 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/c/AppScopedBean.java @@ -0,0 +1,34 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.classDefining.c; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import org.jboss.weld.tests.classDefining.b.BeanInterface; + +@ApplicationScoped +public class AppScopedBean { + + @Inject private BeanInterface intf; + + @Inject private BeanInterface.NestedInterface nested; + + public void passNumberToInterface() { intf.setNumber(666); } + + public void passNumberToNestedInterface() { nested.setNumber(666); } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/IntegrationSuite.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/AMuchBetterPrincipal.java similarity index 55% rename from tests-arquillian/src/test/java/org/jboss/weld/tests/IntegrationSuite.java rename to tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/AMuchBetterPrincipal.java index 48b61825b3..41c4c37c8e 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/IntegrationSuite.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/AMuchBetterPrincipal.java @@ -1,6 +1,6 @@ /* * JBoss, Home of Professional Open Source - * Copyright 2009, Red Hat Middleware LLC, and individual contributors + * Copyright 2019, Red Hat, Inc., and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * @@ -14,23 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jboss.weld.tests; -import org.jboss.weld.tests.Categories.ExcludeCategory; -import org.jboss.weld.tests.category.Broken; -import org.jboss.weld.tests.category.Performance; -import org.junit.runner.RunWith; -import org.junit.runners.Suite.SuiteClasses; +package org.jboss.weld.tests.classDefining.inherited; + +import java.security.Principal; /** - * IntegrationSuite - * - * @author Aslak Knutsen - * @version $Revision: $ + * Naming is intentional, this class alphabetically precedes Principal */ -@RunWith(Categories.class) -@ExcludeCategory({Broken.class, Performance.class}) -@SuiteClasses(AllTests.class) -public class IntegrationSuite { - -} +public interface AMuchBetterPrincipal extends Principal {} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/BeanProducer.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/BeanProducer.java new file mode 100644 index 0000000000..9f0f61252d --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/BeanProducer.java @@ -0,0 +1,55 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.classDefining.inherited; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; +import org.jboss.weld.tests.classDefining.inherited.base.AncestorInterface; +import org.jboss.weld.tests.classDefining.inherited.extending.MyInterface; + +@ApplicationScoped +public class BeanProducer { + + // produce a proxied bean for a type with interface hierarchy + @Produces + @ApplicationScoped + public MyInterface produceBean() { + return new MyInterface() { + @Override + public String anotherPing() { + return MyInterface.class.getSimpleName(); + } + + @Override + public String ping() { + return AncestorInterface.class.getSimpleName(); + } + }; + } + + @Produces + @ApplicationScoped + public AMuchBetterPrincipal producePrincipal() { + return new AMuchBetterPrincipal() { + @Override + public String getName() { + return AMuchBetterPrincipal.class.getSimpleName(); + } + }; + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/ConsumerBean.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/ConsumerBean.java new file mode 100644 index 0000000000..6eac393883 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/ConsumerBean.java @@ -0,0 +1,34 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.classDefining.inherited; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import org.jboss.weld.tests.classDefining.inherited.extending.MyInterface; + +@ApplicationScoped +public class ConsumerBean { + + @Inject MyInterface bean; + + @Inject AMuchBetterPrincipal principal; + + public MyInterface getProducedInterfaceBean() { return bean; } + + public AMuchBetterPrincipal getPrincipal() { return principal; } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/ProxyForHierarchicalInterfaceTypeTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/ProxyForHierarchicalInterfaceTypeTest.java new file mode 100644 index 0000000000..4abe6df0f8 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/ProxyForHierarchicalInterfaceTypeTest.java @@ -0,0 +1,81 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.classDefining.inherited; + +import javax.inject.Inject; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.BeanArchive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.weld.test.util.Utils; +import org.jboss.weld.tests.classDefining.inherited.base.AncestorInterface; +import org.jboss.weld.tests.classDefining.inherited.extending.MyInterface; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests that you can create a proxy (specifically under JDK 11) from producer + * that returns a hierarchical interface type. E.g. tests that the resulting + * proxy name has package corresponding to its class name. + * + * One of the proxies is built on an interface extending Principal, this is + * deliberate as that lies in java.* package which gets special treatment. + */ +@RunWith(Arquillian.class) +public class ProxyForHierarchicalInterfaceTypeTest { + + @Deployment + public static Archive deploy() { + return ShrinkWrap + .create(BeanArchive.class, + Utils.getDeploymentNameAsHash( + ProxyForHierarchicalInterfaceTypeTest.class)) + .addClass(AncestorInterface.class) + .addClass(MyInterface.class) + .addClass(ConsumerBean.class) + .addClass(BeanProducer.class) + .addClass(AMuchBetterPrincipal.class); + } + + @Inject ConsumerBean bean; + + @Test + public void testProxyDefinitionWorks() { + // invoke the method, the verification lies mainly in not getting errors + // when creating proxy + MyInterface interfaceBean = this.bean.getProducedInterfaceBean(); + Assert.assertEquals(MyInterface.class.getSimpleName(), + interfaceBean.anotherPing()); + Assert.assertEquals(AncestorInterface.class.getSimpleName(), + interfaceBean.ping()); + // assert that the proxy from hierarchical interface starts with package and + // class of the most specific interface we know of + Assert.assertTrue(interfaceBean.getClass().getName().startsWith( + "org.jboss.weld.tests.classDefining.inherited.extending.MyInterface")); + + AMuchBetterPrincipal principal = this.bean.getPrincipal(); + Assert.assertEquals(AMuchBetterPrincipal.class.getSimpleName(), + principal.getName()); + // assert that the proxy created from Principal and custom class has the + // package of custom class + Assert.assertTrue(principal.getClass().getName().startsWith( + "org.jboss.weld.tests.classDefining.inherited.AMuchBetterPrincipal")); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/AllTests.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/base/AncestorInterface.java similarity index 68% rename from tests-arquillian/src/test/java/org/jboss/weld/tests/AllTests.java rename to tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/base/AncestorInterface.java index 891990250d..dba57671ce 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/AllTests.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/base/AncestorInterface.java @@ -1,6 +1,6 @@ /* * JBoss, Home of Professional Open Source - * Copyright 2009, Red Hat Middleware LLC, and individual contributors + * Copyright 2019, Red Hat, Inc., and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * @@ -14,17 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jboss.weld.tests; -import org.junit.runner.RunWith; +package org.jboss.weld.tests.classDefining.inherited.base; /** - * Dummy test class to scan classpath for all Tests. - * - * @author Aslak Knutsen - * @version $Revision: $ + * Name matters - it deliberately alphabetically precedes MyInterface to verify + * correct proxy name */ -@RunWith(AllTestRunner.class) -public class AllTests { +public interface AncestorInterface { + String ping(); } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/extending/MyInterface.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/extending/MyInterface.java new file mode 100644 index 0000000000..0f95093c11 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/inherited/extending/MyInterface.java @@ -0,0 +1,25 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.classDefining.inherited.extending; + +import org.jboss.weld.tests.classDefining.inherited.base.AncestorInterface; + +public interface MyInterface extends AncestorInterface { + + String anotherPing(); +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/ProducerBean.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/ProducerBean.java new file mode 100644 index 0000000000..918339365a --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/ProducerBean.java @@ -0,0 +1,49 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.classDefining.interfaceOrdering; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; +import org.jboss.weld.tests.classDefining.interfaceOrdering.b.B; +import org.jboss.weld.tests.classDefining.interfaceOrdering.b.Two; + +@ApplicationScoped +public class ProducerBean { + + @Produces + @ApplicationScoped + public B produceB() { + return new B() { + @Override + public String pingB() { + return "B"; + } + + @Override + public String pingA() { + return "A"; + } + }; + } + + @Produces + @ApplicationScoped + public Two produceTwo() { + return new Two(); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/ProducerProxyDefinedInMostSpecificClassTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/ProducerProxyDefinedInMostSpecificClassTest.java new file mode 100644 index 0000000000..3bfcead4ce --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/ProducerProxyDefinedInMostSpecificClassTest.java @@ -0,0 +1,85 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.classDefining.interfaceOrdering; + +import javax.inject.Inject; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.BeanArchive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.weld.test.util.Utils; +import org.jboss.weld.tests.classDefining.interfaceOrdering.a.A; +import org.jboss.weld.tests.classDefining.interfaceOrdering.a.One; +import org.jboss.weld.tests.classDefining.interfaceOrdering.b.B; +import org.jboss.weld.tests.classDefining.interfaceOrdering.b.Two; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Verifies that a proxy for a producer-created bean starts with the package and + * class of the most concrete class/interface. This should prevent problems in + * JPMS where each class/interface can come from various module that don't have + * bidirectional read between them. + */ +@RunWith(Arquillian.class) +public class ProducerProxyDefinedInMostSpecificClassTest { + + @Deployment + public static Archive deploy() { + return ShrinkWrap + .create(BeanArchive.class, + Utils.getDeploymentNameAsHash( + ProducerProxyDefinedInMostSpecificClassTest.class)) + .addClass(ProducerProxyDefinedInMostSpecificClassTest.class) + .addClass(A.class) + .addClass(B.class) + .addClass(One.class) + .addClass(Two.class) + .addClass(ProducerBean.class); + } + + @Inject B someB; + + @Inject Two two; + + @Test + public void testProxyNameForInterfaceBasedBean() { + // first test that bean can be used + someB.pingB(); + // then assert its name up to the first occurrence of "$" + // in this case, we want the package and class name to the that of B which + // is the most specific interface implemented + Assert.assertEquals(B.class.getName(), + someB.getClass().getName().substring( + 0, someB.getClass().getName().indexOf("$"))); + } + + @Test + public void testProxyNameForClassBasedBean() { + // first test that bean can be used + two.pingTwo(); + // then assert its name up to the first occurrence of "$" + // in this case, we want the package and class name to the that of Two which + // is the most specific class of the bean + Assert.assertEquals(Two.class.getName(), + two.getClass().getName().substring( + 0, two.getClass().getName().indexOf("$"))); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/a/A.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/a/A.java new file mode 100644 index 0000000000..13d700573a --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/a/A.java @@ -0,0 +1,23 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.classDefining.interfaceOrdering.a; + +public interface A { + + String pingA(); +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/a/One.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/a/One.java new file mode 100644 index 0000000000..5ea0c84d9c --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/a/One.java @@ -0,0 +1,26 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.classDefining.interfaceOrdering.a; + +import javax.enterprise.inject.Vetoed; + +@Vetoed +public class One { + + public String pingOne() { return "one"; } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/b/B.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/b/B.java new file mode 100644 index 0000000000..2c66eb4222 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/b/B.java @@ -0,0 +1,25 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.classDefining.interfaceOrdering.b; + +import org.jboss.weld.tests.classDefining.interfaceOrdering.a.A; + +public interface B extends A { + + String pingB(); +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/b/Two.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/b/Two.java new file mode 100644 index 0000000000..9826944724 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/interfaceOrdering/b/Two.java @@ -0,0 +1,27 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.classDefining.interfaceOrdering.b; + +import javax.enterprise.inject.Vetoed; +import org.jboss.weld.tests.classDefining.interfaceOrdering.a.One; + +@Vetoed +public class Two extends One { + + public String pingTwo() { return "two"; } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/cache/RequestScopedCacheLeakTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/cache/RequestScopedCacheLeakTest.java index 1819be8f08..8a4f1c8158 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/cache/RequestScopedCacheLeakTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/cache/RequestScopedCacheLeakTest.java @@ -16,12 +16,11 @@ */ package org.jboss.weld.tests.contexts.cache; +import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; +import com.gargoylesoftware.htmlunit.WebClient; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; - -import org.junit.Assert; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -30,52 +29,59 @@ import org.jboss.shrinkwrap.api.spec.WebArchive; import org.jboss.weld.test.util.Utils; import org.jboss.weld.tests.category.Integration; +import org.junit.Assert; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; -import com.gargoylesoftware.htmlunit.WebClient; - @RunWith(Arquillian.class) @Category(Integration.class) public class RequestScopedCacheLeakTest { - @ArquillianResource - private URL contextPath; + @ArquillianResource private URL contextPath; - @Deployment(testable = false) - public static WebArchive getDeployment() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(RequestScopedCacheLeakTest.class, Utils.ARCHIVE_TYPE.WAR)).addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml") - .addClasses(SimpleServlet.class, ConversationScopedBean.class); - } + @Deployment(testable = false) + public static WebArchive getDeployment() { + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash(RequestScopedCacheLeakTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml") + .addClasses(SimpleServlet.class, ConversationScopedBean.class); + } - @Test - public void test() throws Exception { - WebClient webClient = new WebClient(); - webClient.setThrowExceptionOnFailingStatusCode(false); - for (int i = 0; i < 100; i++) { - // first, send out a hundred of poisoning requests - // each of these should leave a thread in a broken state - sendRequest(webClient, i, true); - } - for (int i = 0; i < 100; i++) { - // now send out normal requests to see if they are affected by the thread's broken state - String result = sendRequest(webClient, i, false); - Assert.assertFalse("Invalid state detected after " + (i + 1) + " requests", result.startsWith("bar")); - } + @Test + public void test() throws Exception { + WebClient webClient = new WebClient(); + webClient.getOptions().setThrowExceptionOnFailingStatusCode(false); + for (int i = 0; i < 100; i++) { + // first, send out a hundred of poisoning requests + // each of these should leave a thread in a broken state + sendRequest(webClient, i, true); } - - private String sendRequest(WebClient webClient, int sequence, boolean poison) throws FailingHttpStatusCodeException, MalformedURLException, IOException { - final String path = getPath("getAndSet", sequence, poison); - return webClient.getPage(path).getWebResponse().getContentAsString().trim(); + for (int i = 0; i < 100; i++) { + // now send out normal requests to see if they are affected by the + // thread's broken state + String result = sendRequest(webClient, i, false); + Assert.assertFalse("Invalid state detected after " + (i + 1) + + " requests", + result.startsWith("bar")); } + } + + private String sendRequest(WebClient webClient, int sequence, boolean poison) + throws FailingHttpStatusCodeException, MalformedURLException, + IOException { + final String path = getPath("getAndSet", sequence, poison); + return webClient.getPage(path).getWebResponse().getContentAsString().trim(); + } - private String getPath(String test, int sequence, boolean poison) { - String path = contextPath + "/servlet?action=" + test + "&sequence=" + sequence; - if (poison) { - path += "&poison=true"; - } - return path; + private String getPath(String test, int sequence, boolean poison) { + String path = + contextPath + "/servlet?action=" + test + "&sequence=" + sequence; + if (poison) { + path += "&poison=true"; } + return path; + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/ClientConversationContextTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/ClientConversationContextTest.java index b328878d86..ca2354a696 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/ClientConversationContextTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/ClientConversationContextTest.java @@ -35,10 +35,16 @@ import static org.junit.Assert.assertEquals; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.html.HtmlAnchor; +import com.gargoylesoftware.htmlunit.html.HtmlElement; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.html.HtmlSpan; +import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; import java.net.URL; import java.util.HashSet; import java.util.Set; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -52,14 +58,6 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebClient; -import com.gargoylesoftware.htmlunit.html.HtmlAnchor; -import com.gargoylesoftware.htmlunit.html.HtmlElement; -import com.gargoylesoftware.htmlunit.html.HtmlPage; -import com.gargoylesoftware.htmlunit.html.HtmlSpan; -import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; - /** * @author Nicklas Karlsson * @author Dan Allen @@ -69,265 +67,344 @@ @RunWith(Arquillian.class) public class ClientConversationContextTest { - public static final String CID_REQUEST_PARAMETER_NAME = "cid"; - - @ArquillianResource - private URL url; - - @Deployment(testable = false) - public static WebArchive createDeployment() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(ClientConversationContextTest.class, Utils.ARCHIVE_TYPE.WAR)) - .addClasses(ConversationTestPhaseListener.class, Cloud.class, Thunderstorm.class, Hailstorm.class, Hurricane.class, Snowstorm.class, - LockingIssueBean.class, Tornado.class) - .addAsWebInfResource(ClientConversationContextTest.class.getPackage(), "web.xml", "web.xml") - .addAsWebInfResource(ClientConversationContextTest.class.getPackage(), "faces-config.xml", "faces-config.xml") - .addAsWebResource(ClientConversationContextTest.class.getPackage(), "cloud.xhtml", "cloud.xhtml") - .addAsWebResource(ClientConversationContextTest.class.getPackage(), "tornado.xhtml", "tornado.xhtml") - .addAsWebResource(ClientConversationContextTest.class.getPackage(), "thunderstorm.xhtml", "thunderstorm.xhtml") - .addAsWebResource(ClientConversationContextTest.class.getPackage(), "snowstorm.xhtml", "/winter/snowstorm.xhtml") - .addAsWebResource(ClientConversationContextTest.class.getPackage(), "hailstorm.xhtml", "hailstorm.xhtml") - .addAsWebResource(ClientConversationContextTest.class.getPackage(), "locking-issue.xhtml", "locking-issue.xhtml") - .addAsWebResource(ClientConversationContextTest.class.getPackage(), "blizzard.xhtml", "blizzard.xhtml") - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); - } - - @Test - public void testConversationNotPropagatedByHLink() throws Exception { - WebClient client = new WebClient(); - - // Access the start page - HtmlPage cloud = client.getPage(getPath("/cloud.jsf")); - String cloudName = getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName").getTextContent(); - assertEquals(Cloud.NAME, cloudName); - - // Now start a conversation and check the cloud name changes - HtmlPage blizzard = getFirstMatchingElement(cloud, HtmlSubmitInput.class, "blizzard").click(); - cloudName = getFirstMatchingElement(blizzard, HtmlSpan.class, "cloudName").getTextContent(); - assertEquals("henry", cloudName); - - // Now use the h:link to navigate back and check the conversation isn't propagated - cloud = getFirstMatchingElement(blizzard, HtmlAnchor.class, "cloud-link").click(); - cloudName = getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName").getTextContent(); - assertEquals(Cloud.NAME, cloudName); - } - - @Test - public void testConversationPropagationToNonExistentConversationLeadsException() throws Exception { - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(false); - Page page = client.getPage(getPath("/cloud.jsf", "org.jboss.jsr299")); - - Assert.assertEquals(500, page.getWebResponse().getStatusCode()); - } - - @Test - public void testRedirectToConversation() throws Exception { - WebClient client = new WebClient(); - HtmlPage page = client.getPage(getPath("/cloud.jsf")); - HtmlPage snowstorm = getFirstMatchingElement(page, HtmlSubmitInput.class, "snow").click(); - String name = getFirstMatchingElement(snowstorm, HtmlSpan.class, "snowstormName").getTextContent(); - assertEquals(Snowstorm.NAME, name); - snowstorm = getFirstMatchingElement(snowstorm, HtmlSubmitInput.class, "go").click(); - name = getFirstMatchingElement(snowstorm, HtmlSpan.class, "snowstormName").getTextContent(); - assertEquals(Snowstorm.NAME, name); - } - - // WELD-755 - @Test - public void testEndAndBeginInSameRequestsKeepsSameCid() throws Exception { - WebClient client = new WebClient(); - HtmlPage page = client.getPage(getPath("/tornado.jsf")); - String name = getFirstMatchingElement(page, HtmlSpan.class, "tornadoName").getTextContent(); - assertEquals("Pete", name); - page = getFirstMatchingElement(page, HtmlSubmitInput.class, "beginConversation").click(); - name = getFirstMatchingElement(page, HtmlSpan.class, "tornadoName").getTextContent(); - assertEquals("Shane", name); - page = getFirstMatchingElement(page, HtmlSubmitInput.class, "endAndBeginConversation").click(); - name = getFirstMatchingElement(page, HtmlSpan.class, "tornadoName").getTextContent(); - assertEquals("Shane", name); - } - - @Test - public void testLockingIssue() throws Exception { - /* - * click start - * click redirect - * click dummy - * refresh browser or retry url. - */ - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(false); - HtmlPage page = client.getPage(getPath("/locking-issue.jsf")); - assertEquals("Gavin", getFirstMatchingElement(page, HtmlSpan.class, "name").getTextContent()); - page = getFirstMatchingElement(page, HtmlSubmitInput.class, "start").click(); - assertEquals("Pete", getFirstMatchingElement(page, HtmlSpan.class, "name").getTextContent()); - String cid = getCid(page); - getFirstMatchingElement(page, HtmlSubmitInput.class, "dummy").click(); - page = client.getPage(getPath("/locking-issue.jsf?cid=" + cid)); - assertEquals("Pete", getFirstMatchingElement(page, HtmlSpan.class, "name").getTextContent()); - } - - @Test - public void testExceptionInPreDestroy() throws Exception { - WebClient client = new WebClient(); - - // First, try a transient conversation - - // Access a page that throws an exception - client.getPage(getPath("/thunderstorm.jsf")); - - // Then access another page that doesn't and check the contexts are ok - HtmlPage cloud = client.getPage(getPath("/cloud.jsf")); - String cloudName = getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName").getTextContent(); - assertEquals(Cloud.NAME, cloudName); - - // Now start a conversation and access the page that throws an exception - // again - HtmlPage thunderstorm = getFirstMatchingElement(cloud, HtmlSubmitInput.class, "beginConversation").click(); - - String thunderstormName = getFirstMatchingElement(thunderstorm, HtmlSpan.class, "thunderstormName").getTextContent(); - assertEquals(Thunderstorm.NAME, thunderstormName); - cloud = getFirstMatchingElement(thunderstorm, HtmlSubmitInput.class, "cloud").click(); - - // And navigate to another page, checking the conversation exists by - // verifying that state is maintained - cloudName = getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName").getTextContent(); - assertEquals("bob", cloudName); - } - - @Test - public void testInvalidateCallsPreDestroy() throws Exception { - WebClient client = new WebClient(); - - // Now start a conversation - HtmlPage cloud = client.getPage(getPath("/cloud.jsf")); - cloud = getFirstMatchingElement(cloud, HtmlSubmitInput.class, "hurricane").click(); - - // Invalidate the session - cloud = getFirstMatchingElement(cloud, HtmlSubmitInput.class, "invalidateSession").click(); - String cloudDestroyed = getFirstMatchingElement(cloud, HtmlSpan.class, "cloudDestroyed").getTextContent(); - assertEquals("true", cloudDestroyed); - } - - @Test - public void testInvalidateThenRedirect() throws Exception { - WebClient client = new WebClient(); - - // Now start a conversation - HtmlPage cloud = client.getPage(getPath("/cloud.jsf")); - cloud = getFirstMatchingElement(cloud, HtmlSubmitInput.class, "hurricane").click(); - - // Now invalidate the session and redirect - cloud = getFirstMatchingElement(cloud, HtmlSubmitInput.class, "sleet").click(); - - // Check that we are still working by verifying the page rendered - String cloudName = getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName").getTextContent(); - assertEquals(Cloud.NAME, cloudName); - } - - @Test - public void testExceptionInPostConstruct() throws Exception { - WebClient client = new WebClient(); - - // First, try a transient conversation - - client.setThrowExceptionOnFailingStatusCode(false); - - // Access a page that throws an exception - client.getPage(getPath("/hailstorm.jsf")); - - // Then access another page that doesn't and check the contexts are ok - HtmlPage cloud = client.getPage(getPath("/cloud.jsf")); - String cloudName = getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName").getTextContent(); - assertEquals(Cloud.NAME, cloudName); - - // Now start a conversation and access the page that throws an exception - // again - Page hailstorm = getFirstMatchingElement(cloud, HtmlSubmitInput.class, "hail").click(); - - String cid = getCid(hailstorm); - - cloud = client.getPage(getPath("/cloud.jsf", cid)); - - // And navigate to another page, checking the conversation exists by - // verifying that state is maintained - cloudName = getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName").getTextContent(); - assertEquals("gavin", cloudName); + public static final String CID_REQUEST_PARAMETER_NAME = "cid"; + + @ArquillianResource private URL url; + + @Deployment(testable = false) + public static WebArchive createDeployment() { + return ShrinkWrap + .create(WebArchive.class, Utils.getDeploymentNameAsHash( + ClientConversationContextTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addClasses(ConversationTestPhaseListener.class, Cloud.class, + Thunderstorm.class, Hailstorm.class, Hurricane.class, + Snowstorm.class, LockingIssueBean.class, Tornado.class) + .addAsWebInfResource(ClientConversationContextTest.class.getPackage(), + "web.xml", "web.xml") + .addAsWebInfResource(ClientConversationContextTest.class.getPackage(), + "faces-config.xml", "faces-config.xml") + .addAsWebResource(ClientConversationContextTest.class.getPackage(), + "cloud.xhtml", "cloud.xhtml") + .addAsWebResource(ClientConversationContextTest.class.getPackage(), + "tornado.xhtml", "tornado.xhtml") + .addAsWebResource(ClientConversationContextTest.class.getPackage(), + "thunderstorm.xhtml", "thunderstorm.xhtml") + .addAsWebResource(ClientConversationContextTest.class.getPackage(), + "snowstorm.xhtml", "/winter/snowstorm.xhtml") + .addAsWebResource(ClientConversationContextTest.class.getPackage(), + "hailstorm.xhtml", "hailstorm.xhtml") + .addAsWebResource(ClientConversationContextTest.class.getPackage(), + "locking-issue.xhtml", "locking-issue.xhtml") + .addAsWebResource(ClientConversationContextTest.class.getPackage(), + "blizzard.xhtml", "blizzard.xhtml") + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } + + @Test + public void testConversationNotPropagatedByHLink() throws Exception { + WebClient client = new WebClient(); + + // Access the start page + HtmlPage cloud = client.getPage(getPath("/cloud.jsf")); + String cloudName = + getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName") + .getTextContent(); + assertEquals(Cloud.NAME, cloudName); + + // Now start a conversation and check the cloud name changes + HtmlPage blizzard = + getFirstMatchingElement(cloud, HtmlSubmitInput.class, "blizzard") + .click(); + cloudName = getFirstMatchingElement(blizzard, HtmlSpan.class, "cloudName") + .getTextContent(); + assertEquals("henry", cloudName); + + // Now use the h:link to navigate back and check the conversation isn't + // propagated + cloud = getFirstMatchingElement(blizzard, HtmlAnchor.class, "cloud-link") + .click(); + cloudName = getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName") + .getTextContent(); + assertEquals(Cloud.NAME, cloudName); + } + + @Test + public void + testConversationPropagationToNonExistentConversationLeadsException() + throws Exception { + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + Page page = client.getPage(getPath("/cloud.jsf", "org.jboss.jsr299")); + + Assert.assertEquals(500, page.getWebResponse().getStatusCode()); + } + + @Test + public void testRedirectToConversation() throws Exception { + WebClient client = new WebClient(); + HtmlPage page = client.getPage(getPath("/cloud.jsf")); + HtmlPage snowstorm = + getFirstMatchingElement(page, HtmlSubmitInput.class, "snow").click(); + String name = + getFirstMatchingElement(snowstorm, HtmlSpan.class, "snowstormName") + .getTextContent(); + assertEquals(Snowstorm.NAME, name); + snowstorm = + getFirstMatchingElement(snowstorm, HtmlSubmitInput.class, "go").click(); + name = getFirstMatchingElement(snowstorm, HtmlSpan.class, "snowstormName") + .getTextContent(); + assertEquals(Snowstorm.NAME, name); + } + + // WELD-755 + @Test + public void testEndAndBeginInSameRequestsKeepsSameCid() throws Exception { + WebClient client = new WebClient(); + HtmlPage page = client.getPage(getPath("/tornado.jsf")); + String name = getFirstMatchingElement(page, HtmlSpan.class, "tornadoName") + .getTextContent(); + assertEquals("Pete", name); + page = getFirstMatchingElement(page, HtmlSubmitInput.class, + "beginConversation") + .click(); + name = getFirstMatchingElement(page, HtmlSpan.class, "tornadoName") + .getTextContent(); + assertEquals("Shane", name); + page = getFirstMatchingElement(page, HtmlSubmitInput.class, + "endAndBeginConversation") + .click(); + name = getFirstMatchingElement(page, HtmlSpan.class, "tornadoName") + .getTextContent(); + assertEquals("Shane", name); + } + + @Test + public void testLockingIssue() throws Exception { + /* + * click start + * click redirect + * click dummy + * refresh browser or retry url. + */ + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + HtmlPage page = client.getPage(getPath("/locking-issue.jsf")); + assertEquals( + "Gavin", + getFirstMatchingElement(page, HtmlSpan.class, "name").getTextContent()); + page = + getFirstMatchingElement(page, HtmlSubmitInput.class, "start").click(); + assertEquals( + "Pete", + getFirstMatchingElement(page, HtmlSpan.class, "name").getTextContent()); + String cid = getCid(page); + getFirstMatchingElement(page, HtmlSubmitInput.class, "dummy").click(); + page = client.getPage(getPath("/locking-issue.jsf?cid=" + cid)); + assertEquals( + "Pete", + getFirstMatchingElement(page, HtmlSpan.class, "name").getTextContent()); + } + + @Test + public void testExceptionInPreDestroy() throws Exception { + WebClient client = new WebClient(); + + // First, try a transient conversation + + // Access a page that throws an exception + client.getPage(getPath("/thunderstorm.jsf")); + + // Then access another page that doesn't and check the contexts are ok + HtmlPage cloud = client.getPage(getPath("/cloud.jsf")); + String cloudName = + getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName") + .getTextContent(); + assertEquals(Cloud.NAME, cloudName); + + // Now start a conversation and access the page that throws an exception + // again + HtmlPage thunderstorm = + getFirstMatchingElement(cloud, HtmlSubmitInput.class, + "beginConversation") + .click(); + + String thunderstormName = + getFirstMatchingElement(thunderstorm, HtmlSpan.class, + "thunderstormName") + .getTextContent(); + assertEquals(Thunderstorm.NAME, thunderstormName); + cloud = + getFirstMatchingElement(thunderstorm, HtmlSubmitInput.class, "cloud") + .click(); + + // And navigate to another page, checking the conversation exists by + // verifying that state is maintained + cloudName = getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName") + .getTextContent(); + assertEquals("bob", cloudName); + } + + @Test + public void testInvalidateCallsPreDestroy() throws Exception { + WebClient client = new WebClient(); + + // Now start a conversation + HtmlPage cloud = client.getPage(getPath("/cloud.jsf")); + cloud = getFirstMatchingElement(cloud, HtmlSubmitInput.class, "hurricane") + .click(); + + // Invalidate the session + cloud = getFirstMatchingElement(cloud, HtmlSubmitInput.class, + "invalidateSession") + .click(); + String cloudDestroyed = + getFirstMatchingElement(cloud, HtmlSpan.class, "cloudDestroyed") + .getTextContent(); + assertEquals("true", cloudDestroyed); + } + + @Test + public void testInvalidateThenRedirect() throws Exception { + WebClient client = new WebClient(); + + // Now start a conversation + HtmlPage cloud = client.getPage(getPath("/cloud.jsf")); + cloud = getFirstMatchingElement(cloud, HtmlSubmitInput.class, "hurricane") + .click(); + + // Now invalidate the session and redirect + cloud = + getFirstMatchingElement(cloud, HtmlSubmitInput.class, "sleet").click(); + + // Check that we are still working by verifying the page rendered + String cloudName = + getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName") + .getTextContent(); + assertEquals(Cloud.NAME, cloudName); + } + + @Test + public void testExceptionInPostConstruct() throws Exception { + WebClient client = new WebClient(); + + // First, try a transient conversation + + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + + // Access a page that throws an exception + client.getPage(getPath("/hailstorm.jsf")); + + // Then access another page that doesn't and check the contexts are ok + HtmlPage cloud = client.getPage(getPath("/cloud.jsf")); + String cloudName = + getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName") + .getTextContent(); + assertEquals(Cloud.NAME, cloudName); + + // Now start a conversation and access the page that throws an exception + // again + Page hailstorm = + getFirstMatchingElement(cloud, HtmlSubmitInput.class, "hail").click(); + + String cid = getCid(hailstorm); + + cloud = client.getPage(getPath("/cloud.jsf", cid)); + + // And navigate to another page, checking the conversation exists by + // verifying that state is maintained + cloudName = getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName") + .getTextContent(); + assertEquals("gavin", cloudName); + } + + @Test + public void testSuppressedConversationPropagation() throws Exception { + WebClient client = new WebClient(); + + // Access the start page + HtmlPage cloud = client.getPage(getPath("/cloud.jsf")); + assertEquals(Cloud.NAME, + getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName") + .getTextContent()); + + // Now start a conversation and check the cloud name changes + HtmlPage page1 = + getFirstMatchingElement(cloud, HtmlSubmitInput.class, Cloud.CUMULUS) + .click(); + assertEquals(Cloud.CUMULUS, + getFirstMatchingElement(page1, HtmlSpan.class, "cloudName") + .getTextContent()); + String cid = getCid(page1); + + // Activate the conversation from a GET request + HtmlPage page2 = client.getPage(getPath("/cloud.jsf", cid)); + assertEquals(Cloud.CUMULUS, + getFirstMatchingElement(page2, HtmlSpan.class, "cloudName") + .getTextContent()); + + // Send a GET request with the "cid" parameter and suppressed conversation + // propagation (using conversationPropagation=none) + HtmlPage page3 = client.getPage(getPath("/cloud.jsf", cid) + + "&conversationPropagation=none"); + assertEquals(Cloud.NAME, + getFirstMatchingElement(page3, HtmlSpan.class, "cloudName") + .getTextContent()); + + // Test again using the proprietary "nocid" parameter (kept for backwards + // compatibility) + HtmlPage page4 = client.getPage(getPath("/cloud.jsf", cid) + ("&nocid=" + + "true")); + assertEquals(Cloud.NAME, + getFirstMatchingElement(page4, HtmlSpan.class, "cloudName") + .getTextContent()); + } + + protected String getPath(String viewId, String cid) { + StringBuilder builder = new StringBuilder(url.toString()); + builder.append(viewId); + if (cid != null) { + builder.append("?"); + builder.append(CID_REQUEST_PARAMETER_NAME); + builder.append("="); + builder.append(cid); } + return builder.toString(); + } - @Test - public void testSuppressedConversationPropagation() throws Exception { - WebClient client = new WebClient(); - - // Access the start page - HtmlPage cloud = client.getPage(getPath("/cloud.jsf")); - assertEquals(Cloud.NAME, getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName").getTextContent()); - - // Now start a conversation and check the cloud name changes - HtmlPage page1 = getFirstMatchingElement(cloud, HtmlSubmitInput.class, Cloud.CUMULUS).click(); - assertEquals(Cloud.CUMULUS, getFirstMatchingElement(page1, HtmlSpan.class, "cloudName").getTextContent()); - String cid = getCid(page1); - - // Activate the conversation from a GET request - HtmlPage page2 = client.getPage(getPath("/cloud.jsf", cid)); - assertEquals(Cloud.CUMULUS, getFirstMatchingElement(page2, HtmlSpan.class, "cloudName").getTextContent()); + protected String getPath(String viewId) { return getPath(viewId, null); } - // Send a GET request with the "cid" parameter and suppressed conversation propagation (using conversationPropagation=none) - HtmlPage page3 = client.getPage(getPath("/cloud.jsf", cid) + "&conversationPropagation=none"); - assertEquals(Cloud.NAME, getFirstMatchingElement(page3, HtmlSpan.class, "cloudName").getTextContent()); + protected Set getElements(HtmlElement rootElement, + Class elementClass) { + Set result = new HashSet(); - // Test again using the proprietary "nocid" parameter (kept for backwards compatibility) - HtmlPage page4 = client.getPage(getPath("/cloud.jsf", cid) + "&nocid=true"); - assertEquals(Cloud.NAME, getFirstMatchingElement(page4, HtmlSpan.class, "cloudName").getTextContent()); + for (HtmlElement element : rootElement.getHtmlElementDescendants()) { + result.addAll(getElements(element, elementClass)); } - protected String getPath(String viewId, String cid) { - StringBuilder builder = new StringBuilder(url.toString()); - builder.append(viewId); - if (cid != null) { - builder.append("?"); - builder.append(CID_REQUEST_PARAMETER_NAME); - builder.append("="); - builder.append(cid); - } - return builder.toString(); + if (elementClass.isInstance(rootElement)) { + result.add(elementClass.cast(rootElement)); } + return result; + } - protected String getPath(String viewId) { - return getPath(viewId, null); + protected String getCid(Page page) { + String url = page.getUrl().toString(); + if (url.indexOf("cid=") != url.lastIndexOf("cid=")) { + throw new IllegalArgumentException("Invalid URL " + url); } + return url.substring(url.indexOf("cid=") + 4); + } - protected Set getElements(HtmlElement rootElement, Class elementClass) { - Set result = new HashSet(); + protected T + getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { - for (HtmlElement element : rootElement.getChildElements()) { - result.addAll(getElements(element, elementClass)); - } - - if (elementClass.isInstance(rootElement)) { - result.add(elementClass.cast(rootElement)); - } - return result; - - } - - protected String getCid(Page page) { - String url = page.getUrl().toString(); - if (url.indexOf("cid=") != url.lastIndexOf("cid=")) { - throw new IllegalArgumentException("Invalid URL " + url); - } - return url.substring(url.indexOf("cid=") + 4); + Set inputs = getElements(page.getBody(), elementClass); + for (T input : inputs) { + if (input.getId().contains(id)) { + return input; + } } - - protected T getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { - - Set inputs = getElements(page.getBody(), elementClass); - for (T input : inputs) { - if (input.getId().contains(id)) { - return input; - } - } - return null; - } - + return null; + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/emptycid/EmptyCidConversationRestorationTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/emptycid/EmptyCidConversationRestorationTest.java index 66663ad946..497f5b6e1b 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/emptycid/EmptyCidConversationRestorationTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/emptycid/EmptyCidConversationRestorationTest.java @@ -18,10 +18,12 @@ import static org.junit.Assert.assertEquals; +import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; +import com.gargoylesoftware.htmlunit.TextPage; +import com.gargoylesoftware.htmlunit.WebClient; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -34,10 +36,6 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; -import com.gargoylesoftware.htmlunit.TextPage; -import com.gargoylesoftware.htmlunit.WebClient; - /** * * @author Martin Kouba @@ -47,22 +45,25 @@ @RunWith(Arquillian.class) public class EmptyCidConversationRestorationTest { - @ArquillianResource - URL contextPath; - - @Deployment(testable = false) - public static WebArchive createTestArchive() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(EmptyCidConversationRestorationTest.class, Utils.ARCHIVE_TYPE.WAR)).addClass(EchoServlet.class) - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); - } + @ArquillianResource URL contextPath; - @Test - public void testEmptyCidDoesNotTriggerConversationRestoration() throws FailingHttpStatusCodeException, - MalformedURLException, IOException { - WebClient webClient = new WebClient(); - webClient.setThrowExceptionOnFailingStatusCode(true); - TextPage page = webClient.getPage(contextPath + "echo?say=Hello&cid="); - assertEquals("Hello", page.getContent()); - } + @Deployment(testable = false) + public static WebArchive createTestArchive() { + return ShrinkWrap + .create(WebArchive.class, Utils.getDeploymentNameAsHash( + EmptyCidConversationRestorationTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addClass(EchoServlet.class) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } + @Test + public void testEmptyCidDoesNotTriggerConversationRestoration() + throws FailingHttpStatusCodeException, MalformedURLException, + IOException { + WebClient webClient = new WebClient(); + webClient.getOptions().setThrowExceptionOnFailingStatusCode(false); + TextPage page = webClient.getPage(contextPath + "echo?say=Hello&cid="); + assertEquals("Hello", page.getContent()); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/exceptionInPhaseListener/ClientConversationContextTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/exceptionInPhaseListener/ClientConversationContextTest.java index e4e2e07a1c..9378a5f4b8 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/exceptionInPhaseListener/ClientConversationContextTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/exceptionInPhaseListener/ClientConversationContextTest.java @@ -35,10 +35,15 @@ import static org.junit.Assert.assertEquals; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.html.HtmlElement; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.html.HtmlSpan; +import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; import java.net.URL; import java.util.HashSet; import java.util.Set; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -51,13 +56,6 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebClient; -import com.gargoylesoftware.htmlunit.html.HtmlElement; -import com.gargoylesoftware.htmlunit.html.HtmlPage; -import com.gargoylesoftware.htmlunit.html.HtmlSpan; -import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; - /** * @author Nicklas Karlsson * @author Dan Allen @@ -66,88 +64,99 @@ @RunWith(Arquillian.class) public class ClientConversationContextTest { - public static final String CID_REQUEST_PARAMETER_NAME = "cid"; - - @Deployment(testable = false) - public static WebArchive createDeployment() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(ClientConversationContextTest.class, Utils.ARCHIVE_TYPE.WAR)) - .addClasses(ConversationTestPhaseListener.class, Cloud.class) - .addAsWebInfResource(ClientConversationContextTest.class.getPackage(), "web.xml", "web.xml") - .addAsWebInfResource(ClientConversationContextTest.class.getPackage(), "faces-config.xml", "faces-config.xml") - .addAsWebResource(ClientConversationContextTest.class.getPackage(), "cloud.jsf", "cloud.jspx") - .addAsWebResource(ClientConversationContextTest.class.getPackage(), "thunderstorm.jsf", "thunderstorm.jspx") - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + public static final String CID_REQUEST_PARAMETER_NAME = "cid"; + + @Deployment(testable = false) + public static WebArchive createDeployment() { + return ShrinkWrap + .create(WebArchive.class, Utils.getDeploymentNameAsHash( + ClientConversationContextTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addClasses(ConversationTestPhaseListener.class, Cloud.class) + .addAsWebInfResource(ClientConversationContextTest.class.getPackage(), + "web.xml", "web.xml") + .addAsWebInfResource(ClientConversationContextTest.class.getPackage(), + "faces-config.xml", "faces-config.xml") + .addAsWebResource(ClientConversationContextTest.class.getPackage(), + "cloud.jsf", "cloud.jspx") + .addAsWebResource(ClientConversationContextTest.class.getPackage(), + "thunderstorm.jsf", "thunderstorm.jspx") + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } + + @ArquillianResource private URL url; + + @Test + public void testExceptionPhaseListener() throws Exception { + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + + // First, try a transient conversation + + // Access a page that throws an exception + client.getPage(getPath("/thunderstorm.jsf")); + + // Then access another page that doesn't and check the contexts are ok + HtmlPage cloud = client.getPage(getPath("/cloud.jsf")); + String cloudName = + getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName") + .getTextContent(); + assertEquals(Cloud.NAME, cloudName); + + // Now start a conversation + HtmlPage thunderstorm = + getFirstMatchingElement(cloud, HtmlSubmitInput.class, + "beginConversation") + .click(); + String cid = getCid(thunderstorm); + + // and access the page that throws an exception again + getFirstMatchingElement(cloud, HtmlSubmitInput.class, "thunderstorm") + .click(); + + cloud = client.getPage(getPath("/cloud.jsf", cid)); + + // And navigate to another page, checking the conversation exists by + // verifying that state is maintained + cloudName = getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName") + .getTextContent(); + assertEquals("gavin", cloudName); + } + + protected String getPath(String viewId, String cid) { + return getPath(viewId) + "?" + CID_REQUEST_PARAMETER_NAME + "=" + cid; + } + + protected String getPath(String viewId) { return url + viewId; } + + protected String getCid(Page page) { + String url = page.getUrl().toString(); + return url.substring(url.indexOf("cid=") + 4); + } + + protected Set getElements(HtmlElement rootElement, + Class elementClass) { + Set result = new HashSet(); + + for (HtmlElement element : rootElement.getHtmlElementDescendants()) { + result.addAll(getElements(element, elementClass)); } - @ArquillianResource - private URL url; - - @Test - public void testExceptionPhaseListener() throws Exception { - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(false); - - // First, try a transient conversation - - - // Access a page that throws an exception - client.getPage(getPath("/thunderstorm.jsf")); - - // Then access another page that doesn't and check the contexts are ok - HtmlPage cloud = client.getPage(getPath("/cloud.jsf")); - String cloudName = getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName").getTextContent(); - assertEquals(Cloud.NAME, cloudName); - - // Now start a conversation - HtmlPage thunderstorm = getFirstMatchingElement(cloud, HtmlSubmitInput.class, "beginConversation").click(); - String cid = getCid(thunderstorm); - - // and access the page that throws an exception again - getFirstMatchingElement(cloud, HtmlSubmitInput.class, "thunderstorm").click(); - - cloud = client.getPage(getPath("/cloud.jsf", cid)); - - // And navigate to another page, checking the conversation exists by verifying that state is maintained - cloudName = getFirstMatchingElement(cloud, HtmlSpan.class, "cloudName").getTextContent(); - assertEquals("gavin", cloudName); + if (elementClass.isInstance(rootElement)) { + result.add(elementClass.cast(rootElement)); } + return result; + } - protected String getPath(String viewId, String cid) { - return getPath(viewId) + "?" + CID_REQUEST_PARAMETER_NAME + "=" + cid; - } - - protected String getPath(String viewId) { - return url + viewId; - } + protected T + getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { - protected String getCid(Page page) { - String url = page.getUrl().toString(); - return url.substring(url.indexOf("cid=") + 4); + Set inputs = getElements(page.getBody(), elementClass); + for (T input : inputs) { + if (input.getId().contains(id)) { + return input; + } } - - protected Set getElements(HtmlElement rootElement, Class elementClass) { - Set result = new HashSet(); - - for (HtmlElement element : rootElement.getChildElements()) { - result.addAll(getElements(element, elementClass)); - } - - if (elementClass.isInstance(rootElement)) { - result.add(elementClass.cast(rootElement)); - } - return result; - - } - - protected T getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { - - Set inputs = getElements(page.getBody(), elementClass); - for (T input : inputs) { - if (input.getId().contains(id)) { - return input; - } - } - return null; - } - + return null; + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/servlet/ServletConversationTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/servlet/ServletConversationTest.java index a51dfc684e..e348043a00 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/servlet/ServletConversationTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/servlet/ServletConversationTest.java @@ -20,10 +20,16 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.TextPage; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.html.HtmlElement; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; +import com.gargoylesoftware.htmlunit.html.HtmlTextInput; import java.net.URL; import java.util.HashSet; import java.util.Set; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -36,14 +42,6 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.TextPage; -import com.gargoylesoftware.htmlunit.WebClient; -import com.gargoylesoftware.htmlunit.html.HtmlElement; -import com.gargoylesoftware.htmlunit.html.HtmlPage; -import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; -import com.gargoylesoftware.htmlunit.html.HtmlTextInput; - /** * * @author Jozef Hartinger @@ -53,230 +51,243 @@ @RunWith(Arquillian.class) public class ServletConversationTest { - @ArquillianResource - private URL url; - - @Deployment(testable = false) - public static WebArchive getDeployment() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(ServletConversationTest.class, Utils.ARCHIVE_TYPE.WAR)) - .addClasses(Message.class, Servlet.class, DestroyedConversationObserver.class) - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml") - .addAsWebResource(ServletConversationTest.class.getPackage(), "message.html", "message.html"); + @ArquillianResource private URL url; + + @Deployment(testable = false) + public static WebArchive getDeployment() { + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash(ServletConversationTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addClasses(Message.class, Servlet.class, + DestroyedConversationObserver.class) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml") + .addAsWebResource(ServletConversationTest.class.getPackage(), + "message.html", "message.html"); + } + + @Test + public void testTransientConversation() throws Exception { + WebClient client = new WebClient(); + TextPage page = client.getPage(getPath("/display", null)); + assertTrue(page.getContent().contains("message: Hello")); + assertTrue(page.getContent().contains("cid: [null]")); + assertTrue(page.getContent().contains("transient: true")); + } + + @Test + public void testLongRunningConversation() throws Exception { + WebClient client = new WebClient(); + + // begin conversation + TextPage initialPage = client.getPage(getPath("/begin", null)); + String content = initialPage.getContent(); + assertTrue(content.contains("message: Hello")); + assertTrue(content.contains("transient: false")); + + String cid = getCid(content); + + // verify conversation is not transient + { + TextPage page = client.getPage(getPath("/display", cid)); + assertTrue(page.getContent().contains("message: Hello")); + assertTrue(page.getContent().contains("cid: [" + cid + "]")); + assertTrue(page.getContent().contains("transient: false")); } - @Test - public void testTransientConversation() throws Exception { - WebClient client = new WebClient(); - TextPage page = client.getPage(getPath("/display", null)); - assertTrue(page.getContent().contains("message: Hello")); - assertTrue(page.getContent().contains("cid: [null]")); - assertTrue(page.getContent().contains("transient: true")); + // modify conversation state + { + TextPage page = client.getPage(getPath("/set", cid) + "&message=Hi"); + assertTrue(page.getContent().contains("message: Hi")); + assertTrue(page.getContent().contains("cid: [" + cid + "]")); + assertTrue(page.getContent().contains("transient: false")); } - @Test - public void testLongRunningConversation() throws Exception { - WebClient client = new WebClient(); - - // begin conversation - TextPage initialPage = client.getPage(getPath("/begin", null)); - String content = initialPage.getContent(); - assertTrue(content.contains("message: Hello")); - assertTrue(content.contains("transient: false")); - - String cid = getCid(content); - - // verify conversation is not transient - { - TextPage page = client.getPage(getPath("/display", cid)); - assertTrue(page.getContent().contains("message: Hello")); - assertTrue(page.getContent().contains("cid: [" + cid + "]")); - assertTrue(page.getContent().contains("transient: false")); - } - - // modify conversation state - { - TextPage page = client.getPage(getPath("/set", cid) + "&message=Hi"); - assertTrue(page.getContent().contains("message: Hi")); - assertTrue(page.getContent().contains("cid: [" + cid + "]")); - assertTrue(page.getContent().contains("transient: false")); - } - - // verify conversation state - { - TextPage page = client.getPage(getPath("/display", cid)); - assertTrue(page.getContent().contains("message: Hi")); - assertTrue(page.getContent().contains("cid: [" + cid + "]")); - assertTrue(page.getContent().contains("transient: false")); - } - - // end conversation - { - TextPage page = client.getPage(getPath("/end", cid)); - assertTrue(page.getContent().contains("message: Hi")); - assertTrue(page.getContent().contains("transient: true")); - } - - // verify that the conversation can no longer be restored - { - client.setThrowExceptionOnFailingStatusCode(false); - Page page = client.getPage(getPath("/display", cid)); - assertEquals(500, page.getWebResponse().getStatusCode()); - } + // verify conversation state + { + TextPage page = client.getPage(getPath("/display", cid)); + assertTrue(page.getContent().contains("message: Hi")); + assertTrue(page.getContent().contains("cid: [" + cid + "]")); + assertTrue(page.getContent().contains("transient: false")); } - @Test - public void testPost() throws Exception { - WebClient client = new WebClient(); - - // begin conversation - TextPage initialPage = client.getPage(getPath("/begin", null)); - String content = initialPage.getContent(); - assertTrue(content.contains("message: Hello")); - assertTrue(content.contains("transient: false")); - - String cid = getCid(content); - - // submit a form - { - HtmlPage form = client.getPage(url.toString() + "/message.html"); - getFirstMatchingElement(form, HtmlTextInput.class, "message").setValueAttribute("Hola!"); - getFirstMatchingElement(form, HtmlTextInput.class, "cid").setValueAttribute(cid); - TextPage page = getFirstMatchingElement(form, HtmlSubmitInput.class, "submit").click(); - - assertTrue(page.getContent().contains("message: Hola!")); - assertTrue(page.getContent().contains("cid: [" + cid + "]")); - assertTrue(page.getContent().contains("transient: false")); - } - - // verify conversation state - { - TextPage page = client.getPage(getPath("/display", cid)); - assertTrue(page.getContent().contains("message: Hola!")); - assertTrue(page.getContent().contains("cid: [" + cid + "]")); - assertTrue(page.getContent().contains("transient: false")); - } + // end conversation + { + TextPage page = client.getPage(getPath("/end", cid)); + assertTrue(page.getContent().contains("message: Hi")); + assertTrue(page.getContent().contains("transient: true")); } - @Test - public void testRedirect() throws Exception { - WebClient client = new WebClient(); - - // begin conversation - TextPage initialPage = client.getPage(getPath("/begin", null)); - String content = initialPage.getContent(); - assertTrue(content.contains("message: Hello")); - assertTrue(content.contains("transient: false")); - - String cid = getCid(content); - - // Do a redirect. Verify that the conversation is not propagated (In this case, the application must manage this request - // parameter.) - TextPage page = client.getPage(getPath("/redirect", cid)); - assertTrue(page.getContent().contains("message: Hello")); - assertTrue(page.getContent().contains("cid: [null]")); - assertTrue(page.getContent().contains("transient: true")); + // verify that the conversation can no longer be restored + { + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + Page page = client.getPage(getPath("/display", cid)); + assertEquals(500, page.getWebResponse().getStatusCode()); + } + } + + @Test + public void testPost() throws Exception { + WebClient client = new WebClient(); + + // begin conversation + TextPage initialPage = client.getPage(getPath("/begin", null)); + String content = initialPage.getContent(); + assertTrue(content.contains("message: Hello")); + assertTrue(content.contains("transient: false")); + + String cid = getCid(content); + + // submit a form + { + HtmlPage form = client.getPage(url.toString() + "/message.html"); + getFirstMatchingElement(form, HtmlTextInput.class, "message") + .setValueAttribute("Hola!"); + getFirstMatchingElement(form, HtmlTextInput.class, "cid") + .setValueAttribute(cid); + TextPage page = + getFirstMatchingElement(form, HtmlSubmitInput.class, "submit") + .click(); + + assertTrue(page.getContent().contains("message: Hola!")); + assertTrue(page.getContent().contains("cid: [" + cid + "]")); + assertTrue(page.getContent().contains("transient: false")); } - @Test - public void testInvalidatingSessionDestroysConversation() throws Exception { - WebClient client = new WebClient(); - - // begin conversation 1 - TextPage initialPage1 = client.getPage(getPath("/begin", null)); - String content = initialPage1.getContent(); - assertTrue(content.contains("message: Hello")); - assertTrue(content.contains("transient: false")); - String cid1 = getCid(content); - - // begin conversation 1 - TextPage initialPage2 = client.getPage(getPath("/begin", null)); - String content2 = initialPage2.getContent(); - assertTrue(content2.contains("message: Hello")); - assertTrue(content2.contains("transient: false")); - String cid2 = getCid(content2); - - assertFalse(cid1.equals(cid2)); - - /* - * Invalidate the session. This should destroy the currently associated conversation (with cid1) as well as the - * not-currently-associated conversation (with cid2). - */ - { - client.getPage(getPath("/invalidateSession", cid1)); - } - - // verify destroyed conversations - { - TextPage page = client.getPage(getPath("/listDestroyedMessages", null)); - assertTrue(page.getContent().contains("DestroyedMessages:")); - assertTrue(page.getContent().contains("")); - assertTrue(page.getContent().contains("")); - } - { - TextPage page = client.getPage(getPath("/listConversationsDestroyedWhileBeingAssociated", null)); - assertTrue(page.getContent().contains("ConversationsDestroyedWhileBeingAssociated:")); - assertTrue(page.getContent().contains("<" + cid1 + ">")); - } - { - TextPage page = client.getPage(getPath("/listConversationsDestroyedWhileBeingDisassociated", null)); - assertTrue(page.getContent().contains("ConversationsDestroyedWhileBeingDisassociated:")); - assertTrue(page.getContent().contains("<" + cid2 + ">")); - } - - // Verify that the conversation 1 cannot be associated - { - client.setThrowExceptionOnFailingStatusCode(false); - Page page = client.getPage(getPath("/display", cid1)); - assertEquals(500, page.getWebResponse().getStatusCode()); - } - - // Verify that the conversation 2 cannot be associated - { - client.setThrowExceptionOnFailingStatusCode(false); - Page page = client.getPage(getPath("/display", cid2)); - assertEquals(500, page.getWebResponse().getStatusCode()); - } + // verify conversation state + { + TextPage page = client.getPage(getPath("/display", cid)); + assertTrue(page.getContent().contains("message: Hola!")); + assertTrue(page.getContent().contains("cid: [" + cid + "]")); + assertTrue(page.getContent().contains("transient: false")); + } + } + + @Test + public void testRedirect() throws Exception { + WebClient client = new WebClient(); + + // begin conversation + TextPage initialPage = client.getPage(getPath("/begin", null)); + String content = initialPage.getContent(); + assertTrue(content.contains("message: Hello")); + assertTrue(content.contains("transient: false")); + + String cid = getCid(content); + + // Do a redirect. Verify that the conversation is not propagated (In this + // case, the application must manage this request parameter.) + TextPage page = client.getPage(getPath("/redirect", cid)); + assertTrue(page.getContent().contains("message: Hello")); + assertTrue(page.getContent().contains("cid: [null]")); + assertTrue(page.getContent().contains("transient: true")); + } + + @Test + public void testInvalidatingSessionDestroysConversation() throws Exception { + WebClient client = new WebClient(); + + // begin conversation 1 + TextPage initialPage1 = client.getPage(getPath("/begin", null)); + String content = initialPage1.getContent(); + assertTrue(content.contains("message: Hello")); + assertTrue(content.contains("transient: false")); + String cid1 = getCid(content); + + // begin conversation 1 + TextPage initialPage2 = client.getPage(getPath("/begin", null)); + String content2 = initialPage2.getContent(); + assertTrue(content2.contains("message: Hello")); + assertTrue(content2.contains("transient: false")); + String cid2 = getCid(content2); + + assertFalse(cid1.equals(cid2)); + + /* + * Invalidate the session. This should destroy the currently associated + * conversation (with cid1) as well as the not-currently-associated + * conversation (with cid2). + */ + { client.getPage(getPath("/invalidateSession", cid1)); } + + // verify destroyed conversations + { + TextPage page = client.getPage(getPath("/listDestroyedMessages", null)); + assertTrue(page.getContent().contains("DestroyedMessages:")); + assertTrue(page.getContent().contains("")); + assertTrue(page.getContent().contains("")); + } + { + TextPage page = client.getPage( + getPath("/listConversationsDestroyedWhileBeingAssociated", null)); + assertTrue(page.getContent().contains( + "ConversationsDestroyedWhileBeingAssociated:")); + assertTrue(page.getContent().contains("<" + cid1 + ">")); + } + { + TextPage page = client.getPage( + getPath("/listConversationsDestroyedWhileBeingDisassociated", null)); + assertTrue(page.getContent().contains( + "ConversationsDestroyedWhileBeingDisassociated:")); + assertTrue(page.getContent().contains("<" + cid2 + ">")); } - protected String getCid(String content) { - return content.substring(content.indexOf("cid: [") + 6, content.indexOf("]")); + // Verify that the conversation 1 cannot be associated + { + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + Page page = client.getPage(getPath("/display", cid1)); + assertEquals(500, page.getWebResponse().getStatusCode()); } - protected String getPath(String viewId, String cid) { - StringBuilder builder = new StringBuilder(url.toString()); - builder.append("/servlet"); - builder.append(viewId); - if (cid != null) { - builder.append("?"); - builder.append("cid"); - builder.append("="); - builder.append(cid); - } - return builder.toString(); + // Verify that the conversation 2 cannot be associated + { + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + Page page = client.getPage(getPath("/display", cid2)); + assertEquals(500, page.getWebResponse().getStatusCode()); } + } + + protected String getCid(String content) { + return content.substring(content.indexOf("cid: [") + 6, + content.indexOf("]")); + } + + protected String getPath(String viewId, String cid) { + StringBuilder builder = new StringBuilder(url.toString()); + builder.append("/servlet"); + builder.append(viewId); + if (cid != null) { + builder.append("?"); + builder.append("cid"); + builder.append("="); + builder.append(cid); + } + return builder.toString(); + } - protected T getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { + protected T + getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { - Set inputs = getElements(page.getBody(), elementClass); - for (T input : inputs) { - if (input.getId().contains(id)) { - return input; - } - } - return null; + Set inputs = getElements(page.getBody(), elementClass); + for (T input : inputs) { + if (input.getId().contains(id)) { + return input; + } } + return null; + } - protected Set getElements(HtmlElement rootElement, Class elementClass) { - Set result = new HashSet(); - - for (HtmlElement element : rootElement.getChildElements()) { - result.addAll(getElements(element, elementClass)); - } + protected Set getElements(HtmlElement rootElement, + Class elementClass) { + Set result = new HashSet(); - if (elementClass.isInstance(rootElement)) { - result.add(elementClass.cast(rootElement)); - } - return result; + for (HtmlElement element : rootElement.getHtmlElementDescendants()) { + result.addAll(getElements(element, elementClass)); + } + if (elementClass.isInstance(rootElement)) { + result.add(elementClass.cast(rootElement)); } + return result; + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/sessiontimeout/ConversationContextDestroyedOnSessionTimeoutTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/sessiontimeout/ConversationContextDestroyedOnSessionTimeoutTest.java index cbb88bcc0d..4ebbe55cb7 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/sessiontimeout/ConversationContextDestroyedOnSessionTimeoutTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/sessiontimeout/ConversationContextDestroyedOnSessionTimeoutTest.java @@ -18,10 +18,11 @@ import static org.junit.Assert.assertEquals; +import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; +import com.gargoylesoftware.htmlunit.WebClient; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -35,45 +36,53 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; -import com.gargoylesoftware.htmlunit.WebClient; - /** - * This test only verifies that PreDestroy callback is called correctly on a conversation scoped bean when the HTTP session - * times out (i.e. before a long-running operation on the same bean instance ends). However, it was originally intended to - * simulate thread locals leaking scenario from WELD-1802 (see the stack in the server log for details). - * - * Note that testing thread locals leaks would require a more advanced container setup (e.g. limit the number of threads - * processing HTTP requests). + * This test only verifies that PreDestroy callback is called correctly on a + * conversation scoped bean when the HTTP session times out. * * @author Martin Kouba + * @author Matej Novotny */ @Category(Integration.class) @RunWith(Arquillian.class) public class ConversationContextDestroyedOnSessionTimeoutTest { - @ArquillianResource - private URL contextPath; - - @Deployment(testable = false) - public static WebArchive createTestArchive() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(ConversationContextDestroyedOnSessionTimeoutTest.class, Utils.ARCHIVE_TYPE.WAR)).addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml") - .addClasses(Foo.class, TestServlet.class, ActionSequence.class, SessionListener.class); - } + @ArquillianResource private URL contextPath; - @Test - public void testConversationContextDestroyedCorrectly() throws FailingHttpStatusCodeException, MalformedURLException, - IOException { - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(false); - String cid = client.getPage(contextPath + "/init").getWebResponse().getContentAsString(); - ActionSequence sequence = new ActionSequence(); - sequence.add(Foo.class.getSimpleName() + "pingStart"); - sequence.add(SessionListener.class.getSimpleName() + "destroyed"); - sequence.add(Foo.class.getSimpleName() + "destroy"); - sequence.add(Foo.class.getSimpleName() + "pingEnd"); - assertEquals(sequence.dataToCsv(), client.getPage(contextPath + "/test" + "?cid=" + cid).getWebResponse() - .getContentAsString().trim()); - } + @Deployment(testable = false) + public static WebArchive createTestArchive() { + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash( + ConversationContextDestroyedOnSessionTimeoutTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml") + .addClasses(Foo.class, TestServlet.class, ActionSequence.class, + SessionListener.class); + } + @Test + public void testConversationContextDestroyedCorrectly() + throws FailingHttpStatusCodeException, MalformedURLException, IOException, + InterruptedException { + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + String cid = client.getPage(contextPath + "/init") + .getWebResponse() + .getContentAsString(); + ActionSequence sequence = new ActionSequence(); + sequence.add(Foo.class.getSimpleName() + "init"); + sequence.add(Foo.class.getSimpleName() + "ping"); + sequence.add(SessionListener.class.getSimpleName() + "destroyed"); + sequence.add(Foo.class.getSimpleName() + "destroy"); + // we need to wait over 1s for session to timeout and then attempt to send + // another request + Thread.sleep(1200L); + assertEquals(sequence.dataToCsv(), client + .getPage(contextPath + "/test" + + "?cid=" + cid) + .getWebResponse() + .getContentAsString() + .trim()); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/sessiontimeout/Foo.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/sessiontimeout/Foo.java index 50df7dfff2..a762b2538a 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/sessiontimeout/Foo.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/sessiontimeout/Foo.java @@ -17,44 +17,26 @@ package org.jboss.weld.tests.contexts.conversation.sessiontimeout; import java.io.Serializable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.enterprise.context.ConversationScoped; - import org.jboss.weld.test.util.ActionSequence; @SuppressWarnings("serial") @ConversationScoped public class Foo implements Serializable { - volatile CountDownLatch doneSignal; - - public void pong() { - } - - public void ping() { - doneSignal = new CountDownLatch(1); - ActionSequence.addAction(Foo.class.getSimpleName()+"pingStart"); - try { - doneSignal.await(3000l, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - ActionSequence.addAction(Foo.class.getSimpleName()+"pingEnd"); - } - - @PostConstruct - public void init() { - ActionSequence.addAction(Foo.class.getSimpleName()+"init"); - } + public void ping() { + ActionSequence.addAction(Foo.class.getSimpleName() + "ping"); + } - @PreDestroy - public void destroy() { - ActionSequence.addAction(Foo.class.getSimpleName()+"destroy"); - doneSignal.countDown(); - } + @PostConstruct + public void init() { + ActionSequence.addAction(Foo.class.getSimpleName() + "init"); + } + @PreDestroy + public void destroy() { + ActionSequence.addAction(Foo.class.getSimpleName() + "destroy"); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/sessiontimeout/TestServlet.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/sessiontimeout/TestServlet.java index f2e6dc0916..c6797e39d7 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/sessiontimeout/TestServlet.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/sessiontimeout/TestServlet.java @@ -18,7 +18,6 @@ package org.jboss.weld.tests.contexts.conversation.sessiontimeout; import java.io.IOException; - import javax.enterprise.context.Conversation; import javax.inject.Inject; import javax.servlet.ServletException; @@ -26,33 +25,30 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - import org.jboss.weld.test.util.ActionSequence; @SuppressWarnings("serial") @WebServlet(urlPatterns = "/*") public class TestServlet extends HttpServlet { - @Inject - private Foo foo; - - @Inject - private Conversation conversation; - - @Override - protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - resp.setContentType("text/plain"); - if ("/init".equals(req.getPathInfo())) { - req.getSession(true); - conversation.begin(); - foo.pong(); - resp.getWriter().println(conversation.getId()); - } else { - ActionSequence.reset(); - req.getSession().setMaxInactiveInterval(1); - // It's highly unlikely that the session times out before Foo waits until the latch is counted down - foo.ping(); - resp.getWriter().println(ActionSequence.getSequence().dataToCsv()); - } + @Inject private Foo foo; + + @Inject private Conversation conversation; + + @Override + protected void service(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.setContentType("text/plain"); + if ("/init".equals(req.getPathInfo())) { + ActionSequence.reset(); + req.getSession(true); + req.getSession().setMaxInactiveInterval(1); + conversation.begin(); + foo.ping(); + resp.getWriter().println(conversation.getId()); + } else { + // we waited for >1 sec so session should timeout + resp.getWriter().println(ActionSequence.getSequence().dataToCsv()); } + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/timeout/ConversationTimeoutTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/timeout/ConversationTimeoutTest.java index dae4288368..38747685a0 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/timeout/ConversationTimeoutTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/timeout/ConversationTimeoutTest.java @@ -19,8 +19,9 @@ import static org.junit.Assert.assertEquals; +import com.gargoylesoftware.htmlunit.TextPage; +import com.gargoylesoftware.htmlunit.WebClient; import java.net.URL; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.RunAsClient; import org.jboss.arquillian.junit.Arquillian; @@ -34,58 +35,58 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.TextPage; -import com.gargoylesoftware.htmlunit.WebClient; - /** * @author Marko Luksa - * + * * Timeout tests that address WELD-1452 */ @RunWith(Arquillian.class) @Category(Integration.class) public class ConversationTimeoutTest { - @ArquillianResource - private URL url; + @ArquillianResource private URL url; + + @Deployment(testable = false) + public static WebArchive getDeployment() { + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash(ConversationTimeoutTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addPackage(ConversationTimeoutTest.class.getPackage()) + .addAsWebInfResource(ConversationTimeoutTest.class.getPackage(), + "web.xml", "web.xml") + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } - @Deployment(testable = false) - public static WebArchive getDeployment() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(ConversationTimeoutTest.class, Utils.ARCHIVE_TYPE.WAR)) - .addPackage(ConversationTimeoutTest.class.getPackage()) - .addAsWebInfResource(ConversationTimeoutTest.class.getPackage(), "web.xml", "web.xml") - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); - } + @Test + @RunAsClient + public void testConversationTimesout() throws Exception { + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); - @Test - @RunAsClient - public void testConversationTimesout() throws Exception { - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(false); - - TextPage page = client.getPage(url + "/servlet/beginConversation"); - String cid = page.getContent(); + TextPage page = client.getPage(url + "/servlet/beginConversation"); + String cid = page.getContent(); - Thread.sleep(1000); // wait for conversation to time out + Thread.sleep(1000); // wait for conversation to time out - page = client.getPage(url + "/servlet/testConversation?cid=" + cid); - assertEquals(TimeoutFilter.NON_EXISTENT_CONVERSATION, page.getContent()); - } + page = client.getPage(url + "/servlet/testConversation?cid=" + cid); + assertEquals(TimeoutFilter.NON_EXISTENT_CONVERSATION, page.getContent()); + } - @Test - @RunAsClient - public void testConversationDoesNotTimeoutOnRedirect() throws Exception { - WebClient client = new WebClient(); + @Test + @RunAsClient + public void testConversationDoesNotTimeoutOnRedirect() throws Exception { + WebClient client = new WebClient(); - TextPage page = client.getPage(url + "/servlet/beginConversation"); - String cid = page.getContent(); + TextPage page = client.getPage(url + "/servlet/beginConversation"); + String cid = page.getContent(); - // Conversation will expire in middle of request but should not timeout - page = client.getPage(url + "/servlet/makeLongRequest?cid=" + cid); - assertEquals(cid, page.getContent()); + // Conversation will expire in middle of request but should not timeout + page = client.getPage(url + "/servlet/makeLongRequest?cid=" + cid); + assertEquals(cid, page.getContent()); - // Simulate redirect - page = client.getPage(url + "/servlet/testConversation?cid=" + cid); - assertEquals(cid, page.getContent()); - } + // Simulate redirect + page = client.getPage(url + "/servlet/testConversation?cid=" + cid); + assertEquals(cid, page.getContent()); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/timeout/concurrent/ConversationLockTimeoutTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/timeout/concurrent/ConversationLockTimeoutTest.java index b375d0f736..8ff0fd4206 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/timeout/concurrent/ConversationLockTimeoutTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/timeout/concurrent/ConversationLockTimeoutTest.java @@ -16,17 +16,16 @@ */ package org.jboss.weld.tests.contexts.conversation.timeout.concurrent; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.TextPage; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.util.Cookie; import java.net.URL; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; - -import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.TextPage; -import com.gargoylesoftware.htmlunit.WebClient; -import com.gargoylesoftware.htmlunit.util.Cookie; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -47,95 +46,114 @@ @Category(Integration.class) public class ConversationLockTimeoutTest { - private static final String JSESSIONID = "JSESSIONID"; - - @ArquillianResource - private URL url; - - @Deployment(testable = false) - public static WebArchive getDeployment() { - WebArchive testDeployment = ShrinkWrap - .create(WebArchive.class, Utils.getDeploymentNameAsHash(ConversationLockTimeoutTest.class, Utils.ARCHIVE_TYPE.WAR)) - .addPackage(ConversationLockTimeoutTest.class.getPackage()) - .addClass(Timer.class) - .addAsWebInfResource(ConversationLockTimeoutTest.class.getPackage(), "web.xml", "web.xml") - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml") - .addAsResource(PropertiesBuilder.newBuilder().set(ConfigurationKey.CONVERSATION_CONCURRENT_ACCESS_TIMEOUT.get(), "3000").build(), - "weld.properties"); - return testDeployment; + private static final String JSESSIONID = "JSESSIONID"; + + @ArquillianResource private URL url; + + @Deployment(testable = false) + public static WebArchive getDeployment() { + WebArchive testDeployment = + ShrinkWrap + .create(WebArchive.class, Utils.getDeploymentNameAsHash( + ConversationLockTimeoutTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addPackage(ConversationLockTimeoutTest.class.getPackage()) + .addClass(Timer.class) + .addAsWebInfResource(ConversationLockTimeoutTest.class.getPackage(), + "web.xml", "web.xml") + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml") + .addAsResource( + PropertiesBuilder.newBuilder() + .set(ConfigurationKey.CONVERSATION_CONCURRENT_ACCESS_TIMEOUT + .get(), + "3000") + .build(), + "weld.properties"); + return testDeployment; + } + + @Test + public void testLongerConversationLockTimeout() throws Exception { + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + + TextPage initPage = + client.getPage(url + "inspect?mode=" + InspectServlet.MODE_INIT); + String cid = extractCid(initPage.getContent()); + Assert.assertNotNull(cid); + Assert.assertFalse(cid.isEmpty()); + String jsessionid = + client.getCookieManager().getCookie(JSESSIONID).getValue(); + Assert.assertNotNull(jsessionid); + Assert.assertFalse(jsessionid.isEmpty()); + + ExecutorService executorService = Executors.newFixedThreadPool(2); + WebRequest longTask = + new WebRequest(InspectServlet.MODE_LONG_TASK, url, cid, jsessionid); + WebRequest busyRequest = + new WebRequest(InspectServlet.MODE_BUSY_REQUEST, url, cid, jsessionid); + + final Future longTaskFuture = executorService.submit(longTask); + Timer timer = Timer.startNew(1000l); + final Future busyRequestFuture = + executorService.submit(busyRequest); + timer.setSleepInterval(100l) + .setDelay(2, TimeUnit.SECONDS) + .addStopCondition( + () -> longTaskFuture.isDone() || busyRequestFuture.isDone()) + .start(); + + Assert.assertEquals("OK", longTaskFuture.get()); + Assert.assertEquals("Conversation locked", busyRequestFuture.get()); + executorService.shutdown(); + } + + /** + * Note - htmlunit WebClient instance is not thread-safe. + */ + private class WebRequest implements Callable { + + private String mode; + + private URL contextPath; + + private String cid; + + private String jsessionid; + + public WebRequest(String mode, URL contextPath, String cid, + String jsessionid) { + super(); + this.mode = mode; + this.contextPath = contextPath; + this.cid = cid; + this.jsessionid = jsessionid; } - @Test - public void testLongerConversationLockTimeout() throws Exception { - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(true); - - TextPage initPage = client.getPage(url + "inspect?mode=" + InspectServlet.MODE_INIT); - String cid = extractCid(initPage.getContent()); - Assert.assertNotNull(cid); - Assert.assertFalse(cid.isEmpty()); - String jsessionid = client.getCookieManager().getCookie(JSESSIONID).getValue(); - Assert.assertNotNull(jsessionid); - Assert.assertFalse(jsessionid.isEmpty()); - - ExecutorService executorService = Executors.newFixedThreadPool(2); - WebRequest longTask = new WebRequest(InspectServlet.MODE_LONG_TASK, url, cid, jsessionid); - WebRequest busyRequest = new WebRequest(InspectServlet.MODE_BUSY_REQUEST, url, cid, jsessionid); - - final Future longTaskFuture = executorService.submit(longTask); - Timer timer = Timer.startNew(1000l); - final Future busyRequestFuture = executorService.submit(busyRequest); - timer.setSleepInterval(100l).setDelay(2, TimeUnit.SECONDS).addStopCondition(() -> longTaskFuture.isDone() || busyRequestFuture.isDone()).start(); - - Assert.assertEquals("OK", longTaskFuture.get()); - Assert.assertEquals("Conversation locked", busyRequestFuture.get()); - executorService.shutdown(); - } - - /** - * Note - htmlunit WebClient instance is not thread-safe. - */ - private class WebRequest implements Callable { - - private String mode; - - private URL contextPath; - - private String cid; - - private String jsessionid; - - public WebRequest(String mode, URL contextPath, String cid, String jsessionid) { - super(); - this.mode = mode; - this.contextPath = contextPath; - this.cid = cid; - this.jsessionid = jsessionid; - } - - @Override - public String call() throws Exception { - - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(false); - client.getCookieManager().addCookie(new Cookie(contextPath.getHost(), JSESSIONID, jsessionid)); + @Override + public String call() throws Exception { - Page page = client.getPage(contextPath + "inspect?mode=" + mode + "&cid=" + cid); + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + client.getCookieManager().addCookie( + new Cookie(contextPath.getHost(), JSESSIONID, jsessionid)); - if (!(page instanceof TextPage)) { - return "" + page.getWebResponse().getStatusCode(); - } - TextPage textPage = (TextPage) page; - return textPage.getContent(); - } + Page page = + client.getPage(contextPath + "inspect?mode=" + mode + "&cid=" + cid); + if (!(page instanceof TextPage)) { + return "" + page.getWebResponse().getStatusCode(); + } + TextPage textPage = (TextPage)page; + return textPage.getContent(); } + } - private String extractCid(String content) { - String[] tokens = content.split("::"); - if (tokens.length != 2) { - throw new IllegalArgumentException(); - } - return tokens[0]; + private String extractCid(String content) { + String[] tokens = content.split("::"); + if (tokens.length != 2) { + throw new IllegalArgumentException(); } + return tokens[0]; + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/weld1262/Weld1262Test.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/weld1262/Weld1262Test.java index 8fa07ad7ed..a23cc328c1 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/weld1262/Weld1262Test.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/conversation/weld1262/Weld1262Test.java @@ -3,10 +3,14 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.html.HtmlElement; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.html.HtmlSpan; +import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; import java.net.URL; import java.util.HashSet; import java.util.Set; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -19,89 +23,95 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.WebClient; -import com.gargoylesoftware.htmlunit.html.HtmlElement; -import com.gargoylesoftware.htmlunit.html.HtmlPage; -import com.gargoylesoftware.htmlunit.html.HtmlSpan; -import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; - /** - * + * * @author tremes - * + * */ @Category(Integration.class) @RunWith(Arquillian.class) public class Weld1262Test { - @ArquillianResource - URL url; - - @Deployment(testable = false) - public static WebArchive createDeployment() { - - return ShrinkWrap - .create(WebArchive.class, Utils.getDeploymentNameAsHash(Weld1262Test.class, Utils.ARCHIVE_TYPE.WAR)) - .addClasses(Crossroad.class,Guide.class) - .addAsWebResource(Weld1262Test.class.getPackage(), "crossroad.xhtml", "crossroad.xhtml") - .addAsWebResource(Weld1262Test.class.getPackage(), "road.xhtml", "road.xhtml") - .addAsWebInfResource(Weld1262Test.class.getPackage(), "web.xml", "web.xml") - .addAsWebInfResource(Weld1262Test.class.getPackage(), "faces-config.xml", "faces-config.xml") - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); - - } - - @Test - public void testConversationPropagatedByNavigationHandler() throws Exception { - - HtmlPage main = startConversation(); - HtmlPage road = getFirstMatchingElement(main, HtmlSubmitInput.class, "guide").click(); - assertEquals("Guide is active",getFirstMatchingElement(road,HtmlSpan.class, "guideMessage").getTextContent()); - - } - - @Test - public void testConversationNotPropagatedByFacesRedirect() throws Exception { - - HtmlPage main = startConversation(); - HtmlPage road = getFirstMatchingElement(main, HtmlSubmitInput.class, "redirect").click(); - assertEquals("Guide is not active",getFirstMatchingElement(road,HtmlSpan.class, "guideMessage").getTextContent()); - } - - public HtmlPage startConversation() throws Exception{ - - WebClient client = new WebClient(); - HtmlPage main = client.getPage(url.toString().concat("crossroad.jsf")); - - main = getFirstMatchingElement(main, HtmlSubmitInput.class, "begin").click(); - String cid = getFirstMatchingElement(main, HtmlSpan.class, "cid").getTextContent(); - assertTrue(Integer.valueOf(cid) > 0); - return main; - } - - protected T getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { - - Set inputs = getElements(page.getBody(), elementClass); - for (T input : inputs) { - if (input.getId().contains(id)) { - return input; - } - } - return null; + @ArquillianResource URL url; + + @Deployment(testable = false) + public static WebArchive createDeployment() { + + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash(Weld1262Test.class, + Utils.ARCHIVE_TYPE.WAR)) + .addClasses(Crossroad.class, Guide.class) + .addAsWebResource(Weld1262Test.class.getPackage(), "crossroad.xhtml", + "crossroad.xhtml") + .addAsWebResource(Weld1262Test.class.getPackage(), "road.xhtml", + "road.xhtml") + .addAsWebInfResource(Weld1262Test.class.getPackage(), "web.xml", + "web.xml") + .addAsWebInfResource(Weld1262Test.class.getPackage(), + "faces-config.xml", "faces-config.xml") + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } + + @Test + public void testConversationPropagatedByNavigationHandler() throws Exception { + + HtmlPage main = startConversation(); + HtmlPage road = + getFirstMatchingElement(main, HtmlSubmitInput.class, "guide").click(); + assertEquals("Guide is active", + getFirstMatchingElement(road, HtmlSpan.class, "guideMessage") + .getTextContent()); + } + + @Test + public void testConversationNotPropagatedByFacesRedirect() throws Exception { + + HtmlPage main = startConversation(); + HtmlPage road = + getFirstMatchingElement(main, HtmlSubmitInput.class, "redirect") + .click(); + assertEquals("Guide is not active", + getFirstMatchingElement(road, HtmlSpan.class, "guideMessage") + .getTextContent()); + } + + public HtmlPage startConversation() throws Exception { + + WebClient client = new WebClient(); + HtmlPage main = client.getPage(url.toString().concat("crossroad.jsf")); + + main = + getFirstMatchingElement(main, HtmlSubmitInput.class, "begin").click(); + String cid = + getFirstMatchingElement(main, HtmlSpan.class, "cid").getTextContent(); + assertTrue(Integer.valueOf(cid) > 0); + return main; + } + + protected T + getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { + + Set inputs = getElements(page.getBody(), elementClass); + for (T input : inputs) { + if (input.getId().contains(id)) { + return input; + } } - - protected Set getElements(HtmlElement rootElement, Class elementClass) { - Set result = new HashSet(); + return null; + } - for (HtmlElement element : rootElement.getChildElements()) { - result.addAll(getElements(element, elementClass)); - } + protected Set getElements(HtmlElement rootElement, + Class elementClass) { + Set result = new HashSet(); - if (elementClass.isInstance(rootElement)) { - result.add(elementClass.cast(rootElement)); - } - return result; + for (HtmlElement element : rootElement.getHtmlElementDescendants()) { + result.addAll(getElements(element, elementClass)); + } + if (elementClass.isInstance(rootElement)) { + result.add(elementClass.cast(rootElement)); } - + return result; + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/errorpage/ErrorPageTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/errorpage/ErrorPageTest.java index 4af260e061..9539c4212d 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/errorpage/ErrorPageTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/errorpage/ErrorPageTest.java @@ -17,12 +17,15 @@ package org.jboss.weld.tests.contexts.errorpage; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.html.HtmlDivision; +import com.gargoylesoftware.htmlunit.html.HtmlElement; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; +import com.gargoylesoftware.htmlunit.html.HtmlTextInput; import java.net.URL; import java.util.HashSet; import java.util.Set; - -import org.junit.Assert; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -31,21 +34,15 @@ import org.jboss.shrinkwrap.api.spec.WebArchive; import org.jboss.weld.test.util.Utils; import org.jboss.weld.tests.category.Integration; +import org.junit.Assert; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.WebClient; -import com.gargoylesoftware.htmlunit.html.HtmlDivision; -import com.gargoylesoftware.htmlunit.html.HtmlElement; -import com.gargoylesoftware.htmlunit.html.HtmlPage; -import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; -import com.gargoylesoftware.htmlunit.html.HtmlTextInput; - /** - *

This test was mostly developed to test the scenario related to WELD-29. Essentially - * a JSF action throws an exception, and the error page is then rendered during which - * all relevant scopes for CDI are tested.

+ *

This test was mostly developed to test the scenario related to WELD-29. + * Essentially a JSF action throws an exception, and the error page is then + * rendered during which all relevant scopes for CDI are tested.

* * @author David Allen */ @@ -53,65 +50,75 @@ @RunWith(Arquillian.class) public class ErrorPageTest { - @ArquillianResource - private URL url; - - @Deployment(testable = false) - public static WebArchive createDeployment() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(ErrorPageTest.class, Utils.ARCHIVE_TYPE.WAR)) - .addClasses(Storm.class, Rain.class) - .addAsWebInfResource(ErrorPageTest.class.getPackage(), "web.xml", "web.xml") - .addAsWebInfResource(ErrorPageTest.class.getPackage(), "faces-config.xml", "faces-config.xml") - .addAsWebResource(ErrorPageTest.class.getPackage(), "error.xhtml", "error.xhtml") - .addAsWebResource(ErrorPageTest.class.getPackage(), "storm.xhtml", "storm.xhtml") - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + @ArquillianResource private URL url; + + @Deployment(testable = false) + public static WebArchive createDeployment() { + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash(ErrorPageTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addClasses(Storm.class, Rain.class) + .addAsWebInfResource(ErrorPageTest.class.getPackage(), "web.xml", + "web.xml") + .addAsWebInfResource(ErrorPageTest.class.getPackage(), + "faces-config.xml", "faces-config.xml") + .addAsWebResource(ErrorPageTest.class.getPackage(), "error.xhtml", + "error.xhtml") + .addAsWebResource(ErrorPageTest.class.getPackage(), "storm.xhtml", + "storm.xhtml") + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } + + @Test + public void testActionMethodExceptionDoesNotDestroyContext() + throws Exception { + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + + HtmlPage page = client.getPage(getPath("/storm.jsf")); + HtmlSubmitInput disasterButton = + getFirstMatchingElement(page, HtmlSubmitInput.class, "disasterButton"); + HtmlTextInput strength = + getFirstMatchingElement(page, HtmlTextInput.class, "stormStrength"); + strength.setValueAttribute("10"); + page = disasterButton.click(); + Assert.assertEquals("Application Error", page.getTitleText()); + + HtmlDivision conversationValue = + getFirstMatchingElement(page, HtmlDivision.class, "conversation"); + Assert.assertEquals("10", conversationValue.asNormalizedText()); + + HtmlDivision requestValue = + getFirstMatchingElement(page, HtmlDivision.class, "request"); + Assert.assertEquals("medium", requestValue.asNormalizedText()); + } + + protected String getPath(String page) { return url.toString() + page; } + + protected Set getElements(HtmlElement rootElement, + Class elementClass) { + Set result = new HashSet(); + + for (HtmlElement element : rootElement.getHtmlElementDescendants()) { + result.addAll(getElements(element, elementClass)); } - - @Test - public void testActionMethodExceptionDoesNotDestroyContext() throws Exception { - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(false); - - HtmlPage page = client.getPage(getPath("/storm.jsf")); - HtmlSubmitInput disasterButton = getFirstMatchingElement(page, HtmlSubmitInput.class, "disasterButton"); - HtmlTextInput strength = getFirstMatchingElement(page, HtmlTextInput.class, "stormStrength"); - strength.setValueAttribute("10"); - page = disasterButton.click(); - Assert.assertEquals("Application Error", page.getTitleText()); - - HtmlDivision conversationValue = getFirstMatchingElement(page, HtmlDivision.class, "conversation"); - Assert.assertEquals("10", conversationValue.asText()); - - HtmlDivision requestValue = getFirstMatchingElement(page, HtmlDivision.class, "request"); - Assert.assertEquals("medium", requestValue.asText()); - } - - protected String getPath(String page) { - return url.toString() + page; - } - - protected Set getElements(HtmlElement rootElement, Class elementClass) { - Set result = new HashSet(); - - for (HtmlElement element : rootElement.getChildElements()) { - result.addAll(getElements(element, elementClass)); - } - - if (elementClass.isInstance(rootElement)) { - result.add(elementClass.cast(rootElement)); - } - return result; + if (elementClass.isInstance(rootElement)) { + result.add(elementClass.cast(rootElement)); } + return result; + } - protected T getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { + protected T + getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { - Set inputs = getElements(page.getBody(), elementClass); - for (T input : inputs) { - if (input.getId().contains(id)) { - return input; - } - } - return null; + Set inputs = getElements(page.getBody(), elementClass); + for (T input : inputs) { + if (input.getId().contains(id)) { + return input; + } } + return null; + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/session/weld1155/SessionScopedProducerTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/session/weld1155/SessionScopedProducerTest.java index 6a100dfe9b..2afa36c6d6 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/session/weld1155/SessionScopedProducerTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/session/weld1155/SessionScopedProducerTest.java @@ -16,6 +16,9 @@ */ package org.jboss.weld.tests.contexts.session.weld1155; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.util.Cookie; import java.net.URL; import java.util.LinkedList; import java.util.List; @@ -24,8 +27,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; - -import com.gargoylesoftware.htmlunit.util.Cookie; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -40,9 +41,6 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebClient; - /** * @see https://issues.jboss.org/browse/WELD-1155 * @@ -53,56 +51,60 @@ @Category(Integration.class) public class SessionScopedProducerTest { - @ArquillianResource - private volatile URL url; + @ArquillianResource private volatile URL url; - private final WebClient client = new WebClient(); + private final WebClient client = new WebClient(); - private final ExecutorService executor = Executors.newCachedThreadPool(); + private final ExecutorService executor = Executors.newCachedThreadPool(); - @Deployment(testable = false) - public static Archive getDeployment() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(SessionScopedProducerTest.class, Utils.ARCHIVE_TYPE.WAR)).addClasses(Producer.class, Product.class, TestServlet.class, SessionScopedBean.class) - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); - } + @Deployment(testable = false) + public static Archive getDeployment() { + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash(SessionScopedProducerTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addClasses(Producer.class, Product.class, TestServlet.class, + SessionScopedBean.class) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } - @Test - public void test() throws Exception { - client.getPage(url.toString() + "/initial"); - Set cookies = client.getCookieManager().getCookies(); + @Test + public void test() throws Exception { + client.getPage(url.toString() + "/initial"); + Set cookies = client.getCookieManager().getCookies(); - List> requests = new LinkedList>(); - requests.add(new ConcurrentRequest(cookies)); - requests.add(new ConcurrentRequest(cookies)); + List> requests = new LinkedList>(); + requests.add(new ConcurrentRequest(cookies)); + requests.add(new ConcurrentRequest(cookies)); - for (Future result : executor.invokeAll(requests)) { - result.get(); - } + for (Future result : executor.invokeAll(requests)) { + result.get(); } + } - @After - public void shutdown() { - executor.shutdownNow(); - } + @After + public void shutdown() { + executor.shutdownNow(); + } - private class ConcurrentRequest implements Callable { + private class ConcurrentRequest implements Callable { - private final WebClient client; + private final WebClient client; - public ConcurrentRequest(Set cookies) { - client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(false); - for (Cookie cookie : cookies) { - client.getCookieManager().addCookie(cookie); - } - } + public ConcurrentRequest(Set cookies) { + client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + for (Cookie cookie : cookies) { + client.getCookieManager().addCookie(cookie); + } + } - public Void call() throws Exception { - Page page = client.getPage(url); - if (page.getWebResponse().getStatusCode() == 500) { - throw new RuntimeException(page.getWebResponse().getContentAsString()); - } - return null; - } + public Void call() throws Exception { + Page page = client.getPage(url); + if (page.getWebResponse().getStatusCode() == 500) { + throw new RuntimeException(page.getWebResponse().getContentAsString()); + } + return null; } + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/sessionInvalidation/InvalidateSessionTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/sessionInvalidation/InvalidateSessionTest.java index f0abee07c8..9ba6f67a79 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/sessionInvalidation/InvalidateSessionTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/sessionInvalidation/InvalidateSessionTest.java @@ -22,7 +22,9 @@ import com.gargoylesoftware.htmlunit.html.HtmlInput; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; -import org.junit.Assert; +import java.net.URL; +import java.util.HashSet; +import java.util.Set; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -31,14 +33,11 @@ import org.jboss.shrinkwrap.api.spec.WebArchive; import org.jboss.weld.test.util.Utils; import org.jboss.weld.tests.category.Integration; +import org.junit.Assert; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import java.net.URL; -import java.util.HashSet; -import java.util.Set; - /** *

Check what happens when session.invalidate() is called.

* @@ -47,78 +46,85 @@ @Category(Integration.class) @RunWith(Arquillian.class) public class InvalidateSessionTest { - @Deployment(testable = false) - public static WebArchive createDeployment() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(InvalidateSessionTest.class, Utils.ARCHIVE_TYPE.WAR)) - .addClasses(Storm.class, SomeBean.class) - .addAsWebInfResource(InvalidateSessionTest.class.getPackage(), "web.xml", "web.xml") - .addAsWebInfResource(InvalidateSessionTest.class.getPackage(), "faces-config.xml", "faces-config.xml") - .addAsWebResource(InvalidateSessionTest.class.getPackage(), "storm.jsf", "storm.jspx") - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); - } - - @ArquillianResource - private URL url; - - /* - * description = "WELD-380, WELD-403" - */ - @Test - public void testInvalidateSessionCalled() throws Exception { - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(true); - - HtmlPage page = client.getPage(getPath("/storm.jsf")); - HtmlSubmitInput invalidateSessionButton = getFirstMatchingElement(page, HtmlSubmitInput.class, "invalidateSessionButton"); - page = invalidateSessionButton.click(); - HtmlInput inputField = getFirstMatchingElement(page, HtmlInput.class, "prop"); - Assert.assertEquals(Storm.PROPERTY_VALUE, inputField.getValueAttribute()); - - // Make another request to verify that the session bean value is not the - // one from the previous invalidated session. - page = client.getPage(getPath("/storm.jsf")); - inputField = getFirstMatchingElement(page, HtmlInput.class, "prop"); - Assert.assertEquals(SomeBean.DEFAULT_PROPERTY_VALUE, inputField.getValueAttribute()); + @Deployment(testable = false) + public static WebArchive createDeployment() { + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash(InvalidateSessionTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addClasses(Storm.class, SomeBean.class) + .addAsWebInfResource(InvalidateSessionTest.class.getPackage(), + "web.xml", "web.xml") + .addAsWebInfResource(InvalidateSessionTest.class.getPackage(), + "faces-config.xml", "faces-config.xml") + .addAsWebResource(InvalidateSessionTest.class.getPackage(), "storm.jsf", + "storm.jspx") + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } + + @ArquillianResource private URL url; + + /* + * description = "WELD-380, WELD-403" + */ + @Test + public void testInvalidateSessionCalled() throws Exception { + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + + HtmlPage page = client.getPage(getPath("/storm.jsf")); + HtmlSubmitInput invalidateSessionButton = getFirstMatchingElement( + page, HtmlSubmitInput.class, "invalidateSessionButton"); + page = invalidateSessionButton.click(); + HtmlInput inputField = + getFirstMatchingElement(page, HtmlInput.class, "prop"); + Assert.assertEquals(Storm.PROPERTY_VALUE, inputField.getValueAttribute()); + + // Make another request to verify that the session bean value is not the + // one from the previous invalidated session. + page = client.getPage(getPath("/storm.jsf")); + inputField = getFirstMatchingElement(page, HtmlInput.class, "prop"); + Assert.assertEquals(SomeBean.DEFAULT_PROPERTY_VALUE, + inputField.getValueAttribute()); + } + + /* + * description = "WELD-461" + */ + @Test + public void testNoDoubleDestructionOnExternalRedirect() throws Exception { + WebClient client = new WebClient(); + HtmlPage page = client.getPage(getPath("/storm.jsf")); + HtmlSubmitInput button = + getFirstMatchingElement(page, HtmlSubmitInput.class, "redirectButton"); + button.click(); + } + + protected String getPath(String page) { return url + page; } + + protected Set getElements(HtmlElement rootElement, + Class elementClass) { + Set result = new HashSet(); + + for (HtmlElement element : rootElement.getHtmlElementDescendants()) { + result.addAll(getElements(element, elementClass)); } - /* - * description = "WELD-461" - */ - @Test - public void testNoDoubleDestructionOnExternalRedirect() throws Exception { - WebClient client = new WebClient(); - HtmlPage page = client.getPage(getPath("/storm.jsf")); - HtmlSubmitInput button = getFirstMatchingElement(page, HtmlSubmitInput.class, "redirectButton"); - button.click(); + if (elementClass.isInstance(rootElement)) { + result.add(elementClass.cast(rootElement)); } + return result; + } - protected String getPath(String page) { - return url + page; - } - - protected Set getElements(HtmlElement rootElement, Class elementClass) { - Set result = new HashSet(); - - for (HtmlElement element : rootElement.getChildElements()) { - result.addAll(getElements(element, elementClass)); - } - - if (elementClass.isInstance(rootElement)) { - result.add(elementClass.cast(rootElement)); - } - return result; + protected T + getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { + Set inputs = getElements(page.getBody(), elementClass); + for (T input : inputs) { + if (input.getId().contains(id)) { + return input; + } } - - protected T getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { - - Set inputs = getElements(page.getBody(), elementClass); - for (T input : inputs) { - if (input.getId().contains(id)) { - return input; - } - } - return null; - } - + return null; + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/weld1159/ContextDeadlockTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/weld1159/ContextDeadlockTest.java index e0e635fb38..797319424c 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/weld1159/ContextDeadlockTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/contexts/weld1159/ContextDeadlockTest.java @@ -16,6 +16,7 @@ */ package org.jboss.weld.tests.contexts.weld1159; +import com.gargoylesoftware.htmlunit.WebClient; import java.net.SocketTimeoutException; import java.net.URL; import java.util.LinkedList; @@ -25,7 +26,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -40,26 +40,26 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.WebClient; - /** - * - * Reproduces deadlock between creation locks in the application and session context. - * + * + * Reproduces deadlock between creation locks in the application and session + * context. + * * Two pairs of beans are constructed in parallel: * * SessionScopedFoo -> ApplicationScopedFoo * ApplicationScopedBar -> SessionScopedBar * - * We use a {@link CountDownLatch} to simulate that both threads get into state when the first bean of the pair - * (SessionScopedFoo and ApplicationScopedFoo) is created and before the dependency is created. This causes deadlock - * because the first thread + * We use a {@link CountDownLatch} to simulate that both threads get into state + * when the first bean of the pair (SessionScopedFoo and ApplicationScopedFoo) + * is created and before the dependency is created. This causes deadlock because + * the first thread * * - owns the session lock * - waits for application lock * * whereas the second thread - * + * * - owns the application lock * - waits for the session lock * @@ -69,55 +69,58 @@ @RunWith(Arquillian.class) @Category(Integration.class) public class ContextDeadlockTest { - - @ArquillianResource - private volatile URL url; - private final WebClient client = new WebClient(); - - private final ExecutorService executor = Executors.newCachedThreadPool(); + @ArquillianResource private volatile URL url; - @Deployment(testable = false) - public static Archive getDeployment() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(ContextDeadlockTest.class, Utils.ARCHIVE_TYPE.WAR)) - .addClasses(AbstractBean.class, ApplicationScopedFoo.class, ApplicationScopedBar.class, SessionScopedFoo.class, SessionScopedBar.class, - TestServlet.class) - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); - } + private final WebClient client = new WebClient(); - @Test - public void test() throws Exception { - client.setTimeout(15000); + private final ExecutorService executor = Executors.newCachedThreadPool(); - List> requests = new LinkedList>(); - requests.add(new ConcurrentRequest(url.toString() + "/foo")); - requests.add(new ConcurrentRequest(url.toString() + "/bar")); + @Deployment(testable = false) + public static Archive getDeployment() { + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash(ContextDeadlockTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addClasses(AbstractBean.class, ApplicationScopedFoo.class, + ApplicationScopedBar.class, SessionScopedFoo.class, + SessionScopedBar.class, TestServlet.class) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } - for (Future result : executor.invokeAll(requests)) { - result.get(); - } - } + @Test + public void test() throws Exception { + client.getOptions().setTimeout(15000); - @After - public void shutdown() { - executor.shutdownNow(); + List> requests = new LinkedList>(); + requests.add(new ConcurrentRequest(url.toString() + "/foo")); + requests.add(new ConcurrentRequest(url.toString() + "/bar")); + + for (Future result : executor.invokeAll(requests)) { + result.get(); } + } + + @After + public void shutdown() { + executor.shutdownNow(); + } - private class ConcurrentRequest implements Callable { + private class ConcurrentRequest implements Callable { - private final String url; + private final String url; - public ConcurrentRequest(String url) { - this.url = url; - } + public ConcurrentRequest(String url) { this.url = url; } - public Void call() throws Exception { - try { - client.getPage(url); - } catch (SocketTimeoutException e) { - throw new RuntimeException("The request for " + url + " timed out. It is very likely that a deadlock occured."); - } - return null; - } + public Void call() throws Exception { + try { + client.getPage(url); + } catch (SocketTimeoutException e) { + throw new RuntimeException( + "The request for " + url + + " timed out. It is very likely that a deadlock occured."); + } + return null; } + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/AbstractDecorator.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/AbstractDecorator.java new file mode 100644 index 0000000000..d6cbc894f7 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/AbstractDecorator.java @@ -0,0 +1,33 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.decorators.defaultmethod.notDecorated; + +import javax.decorator.Decorator; +import javax.decorator.Delegate; +import javax.inject.Inject; + +@Decorator +public abstract class AbstractDecorator implements InterfaceWithDefaultMethod { + + @Inject @Delegate InterfaceWithDefaultMethod delegate; + + @Override + public String decoratedMethod() { + return AbstractDecorator.class.getSimpleName() + delegate.decoratedMethod(); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/DecoratingInterfaceWithDefaultMethodTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/DecoratingInterfaceWithDefaultMethodTest.java new file mode 100644 index 0000000000..c83b8c4b93 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/DecoratingInterfaceWithDefaultMethodTest.java @@ -0,0 +1,62 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.decorators.defaultmethod.notDecorated; + +import javax.inject.Inject; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.BeanArchive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.weld.test.util.Utils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Decorator on an interface that only decorated non-default method. Contains a + * variant for standard and abstract decorators. + * + * See also WELD-2647 + */ +@RunWith(Arquillian.class) +public class DecoratingInterfaceWithDefaultMethodTest { + @Deployment + public static Archive deploy() { + return ShrinkWrap + .create(BeanArchive.class, + Utils.getDeploymentNameAsHash( + DecoratingInterfaceWithDefaultMethodTest.class)) + .decorate(NonAbstractDecorator.class) + .decorate(AbstractDecorator.class) + .addPackage( + DecoratingInterfaceWithDefaultMethodTest.class.getPackage()); + } + + @Inject FooBean bean; + + @Test + public void testDecoratorOnInterfaceWithDefaultMethod() { + Assert.assertEquals(InterfaceWithDefaultMethod.class.getSimpleName(), + bean.defaultPing()); + Assert.assertEquals(AbstractDecorator.class.getSimpleName() + + FooBean.class.getSimpleName() + + NonAbstractDecorator.class.getSimpleName(), + bean.decoratedMethod()); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/FooBean.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/FooBean.java new file mode 100644 index 0000000000..0983821454 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/FooBean.java @@ -0,0 +1,29 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.decorators.defaultmethod.notDecorated; + +import javax.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class FooBean implements InterfaceWithDefaultMethod { + + @Override + public String decoratedMethod() { + return FooBean.class.getSimpleName(); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/InterfaceWithDefaultMethod.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/InterfaceWithDefaultMethod.java new file mode 100644 index 0000000000..ac2d8292dc --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/InterfaceWithDefaultMethod.java @@ -0,0 +1,27 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.decorators.defaultmethod.notDecorated; + +public interface InterfaceWithDefaultMethod extends PlainInterface { + + default String defaultPing() { + return InterfaceWithDefaultMethod.class.getSimpleName(); + } + + String decoratedMethod(); +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/NonAbstractDecorator.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/NonAbstractDecorator.java new file mode 100644 index 0000000000..dddd3c6e88 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/NonAbstractDecorator.java @@ -0,0 +1,34 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.decorators.defaultmethod.notDecorated; + +import javax.decorator.Decorator; +import javax.decorator.Delegate; +import javax.inject.Inject; + +@Decorator +public class NonAbstractDecorator implements InterfaceWithDefaultMethod { + + @Inject @Delegate InterfaceWithDefaultMethod delegate; + + @Override + public String decoratedMethod() { + return delegate.decoratedMethod() + + NonAbstractDecorator.class.getSimpleName(); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/PlainInterface.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/PlainInterface.java new file mode 100644 index 0000000000..96533dd23d --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/PlainInterface.java @@ -0,0 +1,22 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.decorators.defaultmethod.notDecorated; + +public interface PlainInterface { + String defaultPing(); +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/DecoratingInterfaceWithDefaultMethodAndGenericsTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/DecoratingInterfaceWithDefaultMethodAndGenericsTest.java new file mode 100644 index 0000000000..8b78df3bcc --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/DecoratingInterfaceWithDefaultMethodAndGenericsTest.java @@ -0,0 +1,58 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.decorators.defaultmethod.notDecorated.generic; + +import javax.inject.Inject; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.BeanArchive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.weld.test.util.Utils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Similar to {@code DecoratingInterfaceWithDefaultMethodTest} but the interface + * uses generics. + */ +@RunWith(Arquillian.class) +public class DecoratingInterfaceWithDefaultMethodAndGenericsTest { + + @Deployment + public static Archive deploy() { + return ShrinkWrap + .create(BeanArchive.class, + Utils.getDeploymentNameAsHash( + DecoratingInterfaceWithDefaultMethodAndGenericsTest.class)) + .decorate(DecoratorClass.class) + .addPackage(DecoratingInterfaceWithDefaultMethodAndGenericsTest + .class.getPackage()); + } + + @Inject SomeBean bean; + + @Test + public void testDecoratorOnInterfaceWithDefaultMethod() { + Assert.assertEquals("foo", bean.defaultMethod().getString()); + Assert.assertEquals(DecoratorClass.class.getSimpleName() + + SomeBean.class.getSimpleName(), + bean.ping()); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/DecoratorClass.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/DecoratorClass.java new file mode 100644 index 0000000000..a08791c944 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/DecoratorClass.java @@ -0,0 +1,33 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.decorators.defaultmethod.notDecorated.generic; + +import javax.decorator.Decorator; +import javax.decorator.Delegate; +import javax.inject.Inject; + +@Decorator +public class DecoratorClass implements GenericInterfaceWithDefaultMethod { + + @Inject @Delegate GenericInterfaceWithDefaultMethod delegate; + + @Override + public String ping() { + return DecoratorClass.class.getSimpleName() + delegate.ping(); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/NormalSuite.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/Foo.java similarity index 56% rename from tests-arquillian/src/test/java/org/jboss/weld/tests/NormalSuite.java rename to tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/Foo.java index dbc50be7d3..5352c0b351 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/NormalSuite.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/Foo.java @@ -1,6 +1,6 @@ /* * JBoss, Home of Professional Open Source - * Copyright 2009, Red Hat Middleware LLC, and individual contributors + * Copyright 2019, Red Hat, Inc., and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * @@ -14,22 +14,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jboss.weld.tests; -import org.jboss.weld.tests.Categories.ExcludeCategory; -import org.jboss.weld.tests.category.Broken; -import org.jboss.weld.tests.category.Slow; -import org.junit.runner.RunWith; -import org.junit.runners.Suite.SuiteClasses; +package org.jboss.weld.tests.decorators.defaultmethod.notDecorated.generic; /** - * IntegrationSuite - * - * @author Aslak Knutsen - * @version $Revision: $ + * Dummy class used for generic syntax */ -@RunWith(Categories.class) -@ExcludeCategory({Broken.class, Slow.class}) -@SuiteClasses(AllTests.class) -public class NormalSuite { +public class Foo { + + private K typeParam; + private L string; + + public Foo(K typeParam, L string) { + this.typeParam = typeParam; + this.string = string; + } + + public L getString() { return string; } + + public K getTypeParam() { return typeParam; } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/GenericInterface.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/GenericInterface.java new file mode 100644 index 0000000000..6c1a55bc4f --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/GenericInterface.java @@ -0,0 +1,22 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.decorators.defaultmethod.notDecorated.generic; + +public interface GenericInterface { + Foo defaultMethod(); +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/GenericInterfaceWithDefaultMethod.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/GenericInterfaceWithDefaultMethod.java new file mode 100644 index 0000000000..f430ae12af --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/GenericInterfaceWithDefaultMethod.java @@ -0,0 +1,26 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.decorators.defaultmethod.notDecorated.generic; + +public interface GenericInterfaceWithDefaultMethod + extends GenericInterface { + + default Foo defaultMethod() { return new Foo<>(1, "foo"); } + + String ping(); +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/SomeBean.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/SomeBean.java new file mode 100644 index 0000000000..ab18c7a96f --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/decorators/defaultmethod/notDecorated/generic/SomeBean.java @@ -0,0 +1,29 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2019, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.decorators.defaultmethod.notDecorated.generic; + +import javax.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class SomeBean implements GenericInterfaceWithDefaultMethod { + + @Override + public String ping() { + return SomeBean.class.getSimpleName(); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/el/weld1280/Weld1280Test.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/el/weld1280/Weld1280Test.java index 46244361e6..3c2bb890cf 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/el/weld1280/Weld1280Test.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/el/weld1280/Weld1280Test.java @@ -2,8 +2,9 @@ import static org.junit.Assert.assertTrue; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.html.HtmlPage; import java.net.URL; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -16,9 +17,6 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import com.gargoylesoftware.htmlunit.WebClient; -import com.gargoylesoftware.htmlunit.html.HtmlPage; - /** * * @author tremes @@ -29,26 +27,31 @@ @RunWith(Arquillian.class) public class Weld1280Test { - @ArquillianResource - URL url; - - @Deployment(testable = false) - public static WebArchive createDeployment() { - - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(Weld1280Test.class, Utils.ARCHIVE_TYPE.WAR)).addClasses(WeldTestPhaseListener.class, HelloBean.class) - .addAsWebResource(Weld1280Test.class.getPackage(), "index.xhtml", "index.xhtml") - .addAsWebInfResource(Weld1280Test.class.getPackage(), "web.xml", "web.xml") - .addAsWebInfResource(Weld1280Test.class.getPackage(), "faces-config.xml", "faces-config.xml") - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); - - } - - @Test - public void testELContextOfDepedentScopeBean() throws Exception { - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(false); - HtmlPage main = client.getPage(url); - assertTrue(main.getBody().asText().contains("Hello from dependent scope bean")); - } - + @ArquillianResource URL url; + + @Deployment(testable = false) + public static WebArchive createDeployment() { + + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash(Weld1280Test.class, + Utils.ARCHIVE_TYPE.WAR)) + .addClasses(WeldTestPhaseListener.class, HelloBean.class) + .addAsWebResource(Weld1280Test.class.getPackage(), "index.xhtml", + "index.xhtml") + .addAsWebInfResource(Weld1280Test.class.getPackage(), "web.xml", + "web.xml") + .addAsWebInfResource(Weld1280Test.class.getPackage(), + "faces-config.xml", "faces-config.xml") + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } + + @Test + public void testELContextOfDepedentScopeBean() throws Exception { + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + HtmlPage main = client.getPage(url); + assertTrue(main.getBody().asNormalizedText().contains( + "Hello from dependent scope bean")); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/async/stage/CustomExecutorServices.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/async/stage/CustomExecutorServices.java index 0b1f1c3028..a3bf3bafe5 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/async/stage/CustomExecutorServices.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/async/stage/CustomExecutorServices.java @@ -18,29 +18,25 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; - import org.jboss.weld.executor.AbstractExecutorServices; import org.jboss.weld.executor.DaemonThreadFactory; public class CustomExecutorServices extends AbstractExecutorServices { - static final String PREFIX = "weld-worker-test"; - - private final transient ExecutorService taskExecutor = Executors - .newSingleThreadExecutor(new DaemonThreadFactory(new ThreadGroup(DaemonThreadFactory.WELD_WORKERS), PREFIX)); + static final String PREFIX = "weld-worker-test"; - /** - * Provides access to the executor service used for asynchronous tasks. - * - * @return the ExecutorService for this manager - */ - public ExecutorService getTaskExecutor() { - return taskExecutor; - } + private final transient ExecutorService taskExecutor = + Executors.newSingleThreadExecutor(new DaemonThreadFactory(PREFIX)); - @Override - protected int getThreadPoolSize() { - return 1; - } + /** + * Provides access to the executor service used for asynchronous tasks. + * + * @return the ExecutorService for this manager + */ + public ExecutorService getTaskExecutor() { return taskExecutor; } + @Override + protected int getThreadPoolSize() { + return 1; + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/tx/AbstractHtmlUnit.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/tx/AbstractHtmlUnit.java index 2d25e334d9..f3e5bf16dc 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/tx/AbstractHtmlUnit.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/tx/AbstractHtmlUnit.java @@ -18,39 +18,36 @@ import com.gargoylesoftware.htmlunit.html.HtmlElement; import com.gargoylesoftware.htmlunit.html.HtmlPage; - import java.util.HashSet; import java.util.Set; public abstract class AbstractHtmlUnit { - public AbstractHtmlUnit() { - super(); - } + public AbstractHtmlUnit() { super(); } - protected T getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { + protected T + getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { - Set inputs = getElements(page.getBody(), elementClass); - for (T input : inputs) { - if (input.getId().contains(id)) { - return input; - } - } - return null; + Set inputs = getElements(page.getBody(), elementClass); + for (T input : inputs) { + if (input.getId().contains(id)) { + return input; + } } + return null; + } - protected Set getElements(HtmlElement rootElement, Class elementClass) { - Set result = new HashSet(); - - for (HtmlElement element : rootElement.getChildElements()) { - result.addAll(getElements(element, elementClass)); - } - - if (elementClass.isInstance(rootElement)) { - result.add(elementClass.cast(rootElement)); - } - return result; + protected Set getElements(HtmlElement rootElement, + Class elementClass) { + Set result = new HashSet(); + for (HtmlElement element : rootElement.getHtmlElementDescendants()) { + result.addAll(getElements(element, elementClass)); } + if (elementClass.isInstance(rootElement)) { + result.add(elementClass.cast(rootElement)); + } + return result; + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/BeanConfiguratorTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/BeanConfiguratorTest.java index 8bebaa8efc..2fbfdf52fd 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/BeanConfiguratorTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/BeanConfiguratorTest.java @@ -23,15 +23,14 @@ import java.util.List; import java.util.Set; - import javax.enterprise.context.Dependent; import javax.enterprise.context.RequestScoped; import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.Instance; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.Extension; import javax.enterprise.util.TypeLiteral; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.ShrinkWrap; @@ -48,91 +47,142 @@ @RunWith(Arquillian.class) public class BeanConfiguratorTest { - @Deployment - public static WebArchive createTestArchive() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(BeanConfiguratorTest.class, Utils.ARCHIVE_TYPE.WAR)) - .addPackage(BeanConfiguratorTest.class.getPackage()) - .addAsServiceProvider(Extension.class, BuilderExtension.class) - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); - } - - @SuppressWarnings({ "unchecked", "serial" }) - @Test - public void testConfigurator(BeanManager beanManager) throws Exception { - Set> beans = beanManager.getBeans("bar"); - assertEquals(1, beans.size()); - Bean fooBean = (Bean) beans.iterator().next(); - assertEquals(Dependent.class, fooBean.getScope()); - Foo foo1 = (Foo) beanManager.getReference(fooBean, Foo.class, beanManager.createCreationalContext(fooBean)); - Foo foo2 = (Foo) beanManager.getReference(fooBean, Foo.class, beanManager.createCreationalContext(fooBean)); - assertFalse(foo1.getId().equals(foo2.getId())); - - beans = beanManager.getBeans(Foo.class, Juicy.Literal.INSTANCE); - assertEquals(1, beans.size()); - fooBean = (Bean) beans.iterator().next(); - Foo foo = (Foo) beanManager.getReference(fooBean, Foo.class, beanManager.createCreationalContext(fooBean)); - foo.ping(); - - beans = beanManager.getBeans(Integer.class, Random.Literal.INSTANCE); - assertEquals(1, beans.size()); - Bean randomBean = (Bean) beans.iterator().next(); - CreationalContext ctx = beanManager.createCreationalContext(randomBean); - Integer random = (Integer) beanManager.getReference(randomBean, Integer.class, ctx); - assertNotNull(random); - assertTrue(random >= 0 && random < 1000); - randomBean.destroy(random, ctx); - assertTrue(BuilderExtension.DISPOSED.get()); - - beans = beanManager.getBeans(Long.class, AnotherRandom.Literal.INSTANCE); - assertEquals(1, beans.size()); - Bean anotherRandomBean = (Bean) beans.iterator().next(); - Long anotherRandom = (Long) beanManager.getReference(anotherRandomBean, Long.class, - beanManager.createCreationalContext(anotherRandomBean)); - assertNotNull(anotherRandom); - assertEquals(Long.valueOf(foo.getId() * 2), anotherRandom); - - beans = beanManager.getBeans(Bar.class); - assertEquals(1, beans.size()); - Bean barBean = (Bean) beans.iterator().next(); - assertEquals(Dependent.class, barBean.getScope()); - - beans = beanManager.getBeans(new TypeLiteral>() { - }.getType(), Juicy.Literal.INSTANCE); - assertEquals(1, beans.size()); - Bean> listBean = (Bean>) beans.iterator().next(); - assertEquals(Dependent.class, listBean.getScope()); - List list = (List) beanManager.getReference(listBean, new TypeLiteral>() { - }.getType(), beanManager.createCreationalContext(listBean)); - assertNotNull(list); - assertEquals(1, list.size()); - assertEquals("FOO", list.get(0)); - - beans = beanManager.getBeans(VetoedBean.class, Random.Literal.INSTANCE); - assertEquals(1, beans.size()); - fooBean = (Bean) beans.iterator().next(); - assertEquals(Dependent.class, fooBean.getScope()); - Foo randomFoo = (Foo) beanManager.getReference(fooBean, Foo.class, beanManager.createCreationalContext(listBean)); - assertEquals(Long.valueOf(-1), randomFoo.getId()); - - beans = beanManager.getBeans(Configuration.class); - assertEquals(1, beans.size()); - Bean configBean = (Bean) beans.iterator().next(); - assertEquals(Dependent.class, configBean.getScope()); - Configuration configuration = (Configuration) beanManager.getReference(configBean, Configuration.class, beanManager.createCreationalContext(configBean)); - assertEquals(1, configuration.getId()); - - beans = beanManager.getBeans(Integer.class, Bla.Literal.of("dependent")); - assertEquals(1, beans.size()); - Bean blaBean = (Bean) beans.iterator().next(); - assertEquals(Dependent.class, blaBean.getScope()); - beans = beanManager.getBeans(Integer.class, Bla.Literal.of("model")); - assertEquals(1, beans.size()); - blaBean = (Bean) beans.iterator().next(); - assertEquals(RequestScoped.class, blaBean.getScope()); - beans = beanManager.getBeans(Integer.class, Bla.Literal.of("more")); - assertEquals(1, beans.size()); - blaBean = (Bean) beans.iterator().next(); - assertEquals(RequestScoped.class, blaBean.getScope()); - } - + @Deployment + public static WebArchive createTestArchive() { + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash(BeanConfiguratorTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addPackage(BeanConfiguratorTest.class.getPackage()) + .addAsServiceProvider(Extension.class, BuilderExtension.class) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } + + @SuppressWarnings({"unchecked", "serial"}) + @Test + public void testConfigurator(BeanManager beanManager) throws Exception { + Set> beans = beanManager.getBeans("bar"); + assertEquals(1, beans.size()); + Bean fooBean = (Bean)beans.iterator().next(); + assertEquals(Dependent.class, fooBean.getScope()); + Foo foo1 = (Foo)beanManager.getReference( + fooBean, Foo.class, beanManager.createCreationalContext(fooBean)); + Foo foo2 = (Foo)beanManager.getReference( + fooBean, Foo.class, beanManager.createCreationalContext(fooBean)); + assertFalse(foo1.getId().equals(foo2.getId())); + + beans = beanManager.getBeans(Foo.class, Juicy.Literal.INSTANCE); + assertEquals(1, beans.size()); + fooBean = (Bean)beans.iterator().next(); + Foo foo = (Foo)beanManager.getReference( + fooBean, Foo.class, beanManager.createCreationalContext(fooBean)); + foo.ping(); + + // bean is deliberately created via new creational context and + // BM.getReference + beans = beanManager.getBeans(Integer.class, Random.Literal.INSTANCE); + assertEquals(0, DependentBean.TIMES_DESTROY_INVOKED); + assertEquals(1, beans.size()); + Bean randomBean = (Bean)beans.iterator().next(); + CreationalContext ctx = + beanManager.createCreationalContext(randomBean); + Integer random = + (Integer)beanManager.getReference(randomBean, Integer.class, ctx); + assertNotNull(random); + assertTrue(random >= 0 && random < 1000); + assertEquals(0, DependentBean.TIMES_DESTROY_INVOKED); + randomBean.destroy(random, ctx); + assertTrue(BuilderExtension.DISPOSED.get()); + assertEquals(2, DependentBean.TIMES_DESTROY_INVOKED); + + // same as above but using Instance + DependentBean.resetCounter(); + BuilderExtension.DISPOSED.set(false); + Instance integerInstance = beanManager.createInstance().select( + Integer.class, Random.Literal.INSTANCE); + assertEquals(0, DependentBean.TIMES_DESTROY_INVOKED); + random = integerInstance.get(); + assertNotNull(random); + assertTrue(random >= 0 && random < 1000); + assertEquals(0, DependentBean.TIMES_DESTROY_INVOKED); + integerInstance.destroy(random); + assertTrue(BuilderExtension.DISPOSED.get()); + assertEquals(2, DependentBean.TIMES_DESTROY_INVOKED); + + // same as above but with plain injection + DependentBean.resetCounter(); + BuilderExtension.DISPOSED.set(false); + Instance injectingBeanInstance = + beanManager.createInstance().select( + BeanInjectingSyntheticInteger.class); + BeanInjectingSyntheticInteger bean = injectingBeanInstance.get(); + assertNotNull(bean); + Integer beanValue = bean.getNumber(); + assertTrue(beanValue >= 0 && beanValue < 1000); + injectingBeanInstance.destroy(bean); + assertTrue(BuilderExtension.DISPOSED.get()); + assertEquals(2, DependentBean.TIMES_DESTROY_INVOKED); + + beans = beanManager.getBeans(Long.class, AnotherRandom.Literal.INSTANCE); + assertEquals(1, beans.size()); + Bean anotherRandomBean = (Bean)beans.iterator().next(); + Long anotherRandom = (Long)beanManager.getReference( + anotherRandomBean, Long.class, + beanManager.createCreationalContext(anotherRandomBean)); + assertNotNull(anotherRandom); + assertEquals(Long.valueOf(foo.getId() * 2), anotherRandom); + + beans = beanManager.getBeans(Bar.class); + assertEquals(1, beans.size()); + Bean barBean = (Bean)beans.iterator().next(); + assertEquals(Dependent.class, barBean.getScope()); + + beans = beanManager.getBeans(new TypeLiteral>() {}.getType(), + Juicy.Literal.INSTANCE); + assertEquals(1, beans.size()); + Bean> listBean = (Bean>)beans.iterator().next(); + assertEquals(Dependent.class, listBean.getScope()); + List list = (List)beanManager.getReference( + listBean, new TypeLiteral>() {}.getType(), + beanManager.createCreationalContext(listBean)); + assertNotNull(list); + assertEquals(1, list.size()); + assertEquals("FOO", list.get(0)); + + beans = beanManager.getBeans(VetoedBean.class, Random.Literal.INSTANCE); + assertEquals(1, beans.size()); + fooBean = (Bean)beans.iterator().next(); + assertEquals(Dependent.class, fooBean.getScope()); + Foo randomFoo = (Foo)beanManager.getReference( + fooBean, Foo.class, beanManager.createCreationalContext(listBean)); + assertEquals(Long.valueOf(-1), randomFoo.getId()); + + beans = beanManager.getBeans(Configuration.class); + assertEquals(1, beans.size()); + Bean configBean = + (Bean)beans.iterator().next(); + assertEquals(Dependent.class, configBean.getScope()); + Configuration configuration = (Configuration)beanManager.getReference( + configBean, Configuration.class, + beanManager.createCreationalContext(configBean)); + assertEquals(1, configuration.getId()); + + beans = beanManager.getBeans(Integer.class, Bla.Literal.of("dependent")); + assertEquals(1, beans.size()); + Bean blaBean = (Bean)beans.iterator().next(); + assertEquals(Dependent.class, blaBean.getScope()); + beans = beanManager.getBeans(Integer.class, Bla.Literal.of("model")); + assertEquals(1, beans.size()); + blaBean = (Bean)beans.iterator().next(); + assertEquals(RequestScoped.class, blaBean.getScope()); + beans = beanManager.getBeans(Integer.class, Bla.Literal.of("more")); + assertEquals(1, beans.size()); + blaBean = (Bean)beans.iterator().next(); + assertEquals(RequestScoped.class, blaBean.getScope()); + + beans = beanManager.getBeans(String.class); + assertEquals(1, beans.size()); + Bean stringBean = (Bean)beans.iterator().next(); + assertEquals(3, stringBean.getQualifiers().size()); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/BeanInjectingSyntheticInteger.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/BeanInjectingSyntheticInteger.java new file mode 100644 index 0000000000..93beeaa7db --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/BeanInjectingSyntheticInteger.java @@ -0,0 +1,29 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.extensions.custombeans; + +import javax.enterprise.context.Dependent; +import javax.inject.Inject; + +@Dependent +public class BeanInjectingSyntheticInteger { + + @Random @Inject Integer injectedBean; + + public Integer getNumber() { return injectedBean; } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/BuilderExtension.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/BuilderExtension.java index 7de4c8e64c..78d2f1762f 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/BuilderExtension.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/BuilderExtension.java @@ -20,10 +20,12 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; - +import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.Dependent; import javax.enterprise.event.Observes; +import javax.enterprise.inject.Any; import javax.enterprise.inject.Model; +import javax.enterprise.inject.literal.NamedLiteral; import javax.enterprise.inject.spi.AfterBeanDiscovery; import javax.enterprise.inject.spi.AnnotatedType; import javax.enterprise.inject.spi.BeanManager; @@ -37,56 +39,112 @@ */ public class BuilderExtension implements Extension { - static final AtomicBoolean DISPOSED = new AtomicBoolean(false); - - public void processAnnotatedType(@Observes ProcessAnnotatedType event) { - event.veto(); - } - - @SuppressWarnings("serial") - public void afterBeanDiscovery(@Observes AfterBeanDiscovery event, BeanManager beanManager) { - - AnnotatedType annotatedType = beanManager.createAnnotatedType(Foo.class); - - // Read from bean attributes, change the name and remove @Model stereotype - // Note that we have to set the scope manually as it's initialized to @RequestScoped through the bean attributes - event.addBean().beanClass(Foo.class).read(beanManager.createBeanAttributes(annotatedType)).name("bar") - .stereotypes(Collections.emptySet()).scope(Dependent.class).produceWith((i) -> { - Foo foo = new Foo(); - foo.postConstruct(); - return foo; - }); - - // Read from AT, add qualifier, set id - event.addBean().read(annotatedType).id("BAZinga").addQualifier(Juicy.Literal.INSTANCE); - - // Read from AT, set the scope - event.addBean().read(beanManager.createAnnotatedType(Bar.class)).scope(Dependent.class); - - // Test simple produceWith callback - event.addBean().addType(Integer.class).addQualifier(Random.Literal.INSTANCE) - .produceWith((i) -> new java.util.Random().nextInt(1000)).disposeWith((beanInstance, instance) -> DISPOSED.set(true)); - - // Test produceWith callback with Instance param - event.addBean().addType(Long.class).addQualifier(AnotherRandom.Literal.INSTANCE) - .produceWith((i) -> i.select(Foo.class, Juicy.Literal.INSTANCE).get().getId() * 2); - - // Test TypeLiteral - List list = new ArrayList(); - list.add("FOO"); - event.addBean().addType(new TypeLiteral>() { - }).addQualifier(Juicy.Literal.INSTANCE).produceWith((i) -> list); - - // Test transitive type closure - event.addBean().addTransitiveTypeClosure(Foo.class).addQualifier(Random.Literal.INSTANCE) - .produceWith((i) -> new Foo(-1l)); - - // Test default qualifiers - event.addBean().addType(Configuration.class).produceWith((i) -> new Configuration(1)); - - // Test default scopes - event.addBean().addQualifier(Bla.Literal.of("dependent")).addType(Integer.class).createWith((ctx) -> 1); - event.addBean().addQualifier(Bla.Literal.of("model")).addStereotype(Model.class).addType(Integer.class).createWith((ctx) -> 2); - event.addBean().addQualifier(Bla.Literal.of("more")).addStereotype(Model.class).addStereotype(SuperCoolStereotype.class).addType(Integer.class).createWith((ctx) -> 3); - } + static final AtomicBoolean DISPOSED = new AtomicBoolean(false); + + public void processAnnotatedType( + @Observes ProcessAnnotatedType event) { + event.veto(); + } + + @SuppressWarnings("serial") + public void afterBeanDiscovery(@Observes AfterBeanDiscovery event, + BeanManager beanManager) { + + AnnotatedType annotatedType = + beanManager.createAnnotatedType(Foo.class); + + // Read from bean attributes, change the name and remove @Model stereotype + // Note that we have to set the scope manually as it's initialized to + // @RequestScoped through the bean attributes + event.addBean() + .beanClass(Foo.class) + .read(beanManager.createBeanAttributes(annotatedType)) + .name("bar") + .stereotypes(Collections.emptySet()) + .scope(Dependent.class) + .produceWith((i) -> { + Foo foo = new Foo(); + foo.postConstruct(); + return foo; + }); + + // Read from AT, add qualifier, set id + event.addBean() + .read(annotatedType) + .id("BAZinga") + .addQualifier(Juicy.Literal.INSTANCE); + + // Read from AT, set the scope + event.addBean() + .read(beanManager.createAnnotatedType(Bar.class)) + .scope(Dependent.class); + + // Test simple produceWith callback + event.addBean() + .addType(Integer.class) + .addQualifier(Random.Literal.INSTANCE) + .produceWith((i) -> { + i.select(DependentBean.class).get(); // create dependent instance + return new java.util.Random().nextInt(1000); + }) + .disposeWith((beanInstance, instance) -> { + instance.select(DependentBean.class) + .get(); // create dependent instance + DISPOSED.set(true); + }); + + // Test produceWith callback with Instance param + event.addBean() + .addType(Long.class) + .addQualifier(AnotherRandom.Literal.INSTANCE) + .produceWith( + (i) + -> i.select(Foo.class, Juicy.Literal.INSTANCE).get().getId() * + 2); + + // Test TypeLiteral + List list = new ArrayList(); + list.add("FOO"); + event.addBean() + .addType(new TypeLiteral>() {}) + .addQualifier(Juicy.Literal.INSTANCE) + .produceWith((i) -> list); + + // Test transitive type closure + event.addBean() + .addTransitiveTypeClosure(Foo.class) + .addQualifier(Random.Literal.INSTANCE) + .produceWith((i) -> new Foo(-1l)); + + // Test default qualifiers + event.addBean() + .addType(Configuration.class) + .produceWith((i) -> new Configuration(1)); + + // Test default scopes + event.addBean() + .addQualifier(Bla.Literal.of("dependent")) + .addType(Integer.class) + .createWith((ctx) -> 1); + event.addBean() + .addQualifier(Bla.Literal.of("model")) + .addStereotype(Model.class) + .addType(Integer.class) + .createWith((ctx) -> 2); + event.addBean() + .addQualifier(Bla.Literal.of("more")) + .addStereotype(Model.class) + .addStereotype(SuperCoolStereotype.class) + .addType(Integer.class) + .createWith((ctx) -> 3); + + // add a bean testing that when a bean has @Named and @Any, @Default will be + // added automatically + event.addBean() + .beanClass(String.class) + .addType(String.class) + .addQualifiers(NamedLiteral.of("string"), Any.Literal.INSTANCE) + .createWith(a -> "foo") + .scope(ApplicationScoped.class); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/DependentBean.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/DependentBean.java new file mode 100644 index 0000000000..35420ac0fd --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/DependentBean.java @@ -0,0 +1,39 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.extensions.custombeans; + +import javax.annotation.PreDestroy; +import javax.enterprise.context.Dependent; + +/** + * Serves as a counter of how many times a pre-destroy was called. + * Initialized only from within extension's produceWith and disposeWith methods + * via Instance + */ +@Dependent +public class DependentBean { + + public static int TIMES_DESTROY_INVOKED = 0; + + public static void resetCounter() { TIMES_DESTROY_INVOKED = 0; } + + @PreDestroy + public void destroy() { + TIMES_DESTROY_INVOKED++; + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/alternative/CustomPrioritizedBeanFiresProcessBeanEventTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/alternative/CustomPrioritizedBeanFiresProcessBeanEventTest.java new file mode 100644 index 0000000000..a03c2bee9a --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/alternative/CustomPrioritizedBeanFiresProcessBeanEventTest.java @@ -0,0 +1,57 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.extensions.custombeans.alternative; + +import javax.enterprise.inject.spi.Extension; +import javax.inject.Inject; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.BeanArchive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.jboss.weld.test.util.Utils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests that registering a synthetic enabled alternative via {@code Bean} + * that implements {@code Prioritized} will fire {@code ProcessBean} event. + */ +@RunWith(Arquillian.class) +public class CustomPrioritizedBeanFiresProcessBeanEventTest { + + @Deployment + public static JavaArchive createTestArchive() { + return ShrinkWrap + .create(BeanArchive.class, + Utils.getDeploymentNameAsHash( + CustomPrioritizedBeanFiresProcessBeanEventTest.class)) + .addClasses(Foo.class, MyExtension.class, FooBean.class) + .addAsServiceProvider(Extension.class, MyExtension.class); + } + + @Inject Foo foo; + + @Test + public void testBeanTriggeredEvents() { + Assert.assertEquals(2, MyExtension.PB_TRIGGERED); + Assert.assertEquals(1, MyExtension.PSB_TRIGGERED); + Assert.assertEquals(FooBean.class.getSimpleName(), foo.ping()); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/alternative/Foo.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/alternative/Foo.java new file mode 100644 index 0000000000..048291496a --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/alternative/Foo.java @@ -0,0 +1,32 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.extensions.custombeans.alternative; + +import javax.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class Foo { + + private final String val; + + public Foo() { val = Foo.class.getSimpleName(); } + + public Foo(String val) { this.val = val; } + + public String ping() { return val; } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/alternative/FooBean.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/alternative/FooBean.java new file mode 100644 index 0000000000..03b58d9427 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/alternative/FooBean.java @@ -0,0 +1,96 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.extensions.custombeans.alternative; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.Default; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.InjectionPoint; +import javax.enterprise.inject.spi.Prioritized; + +public class FooBean implements Bean, Prioritized { + @Override + public Class getBeanClass() { + return Foo.class; + } + + @Override + public Set getInjectionPoints() { + return Collections.EMPTY_SET; + } + + @Override + public boolean isNullable() { + return false; + } + + @Override + public Foo create(CreationalContext creationalContext) { + return new Foo(FooBean.class.getSimpleName()); + } + + @Override + public void destroy(Foo instance, CreationalContext creationalContext) {} + + private Set immutableSet(T... items) { + Set set = new HashSet(); + Collections.addAll(set, items); + return Collections.unmodifiableSet(set); + } + + @Override + public Set getTypes() { + return immutableSet(Object.class, Foo.class); + } + + @Override + public Set getQualifiers() { + return immutableSet(Default.Literal.INSTANCE); + } + + @Override + public Class getScope() { + return ApplicationScoped.class; + } + + @Override + public String getName() { + return null; + } + + @Override + public Set> getStereotypes() { + return Collections.EMPTY_SET; + } + + @Override + public boolean isAlternative() { + return true; + } + + @Override + public int getPriority() { + return 1; + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/alternative/MyExtension.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/alternative/MyExtension.java new file mode 100644 index 0000000000..12939245da --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/custombeans/alternative/MyExtension.java @@ -0,0 +1,40 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2021, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.extensions.custombeans.alternative; + +import javax.enterprise.event.Observes; +import javax.enterprise.inject.spi.AfterBeanDiscovery; +import javax.enterprise.inject.spi.Extension; +import javax.enterprise.inject.spi.ProcessBean; +import javax.enterprise.inject.spi.ProcessSyntheticBean; + +public class MyExtension implements Extension { + + public static int PB_TRIGGERED = 0; + public static int PSB_TRIGGERED = 0; + + public void observeABD(@Observes AfterBeanDiscovery abd) { + abd.addBean(new FooBean()); + } + + public void obsevePB(@Observes ProcessBean psb) { PB_TRIGGERED++; } + + public void obsevePSB(@Observes ProcessSyntheticBean psb) { + PSB_TRIGGERED++; + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/atd/minvaluepriority/AfterTypeDiscoveryObserver.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/atd/minvaluepriority/AfterTypeDiscoveryObserver.java new file mode 100644 index 0000000000..a2337bf1e3 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/atd/minvaluepriority/AfterTypeDiscoveryObserver.java @@ -0,0 +1,39 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2020, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.extensions.lifecycle.atd.minvaluepriority; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.enterprise.event.Observes; +import javax.enterprise.inject.spi.AfterTypeDiscovery; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.Extension; + +public class AfterTypeDiscoveryObserver implements Extension { + + private List> initialAlternatives = null; + + public void observeAfterTypeDiscovery(@Observes AfterTypeDiscovery event, + BeanManager beanManager) { + + initialAlternatives = Collections.unmodifiableList( + new ArrayList>(event.getAlternatives())); + } + + public List> getInitialAlternatives() { return initialAlternatives; } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/atd/minvaluepriority/MinValuePriorityAlternative.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/atd/minvaluepriority/MinValuePriorityAlternative.java new file mode 100644 index 0000000000..1954c8d6b4 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/atd/minvaluepriority/MinValuePriorityAlternative.java @@ -0,0 +1,24 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2020, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.extensions.lifecycle.atd.minvaluepriority; + +import javax.annotation.Priority; +import javax.enterprise.inject.Alternative; + +@Alternative +@Priority(Integer.MIN_VALUE) +public class MinValuePriorityAlternative {} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/atd/minvaluepriority/MinValuePriorityTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/atd/minvaluepriority/MinValuePriorityTest.java new file mode 100644 index 0000000000..5662799969 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/atd/minvaluepriority/MinValuePriorityTest.java @@ -0,0 +1,63 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2020, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.extensions.lifecycle.atd.minvaluepriority; + +import static org.junit.Assert.assertEquals; + +import javax.enterprise.inject.spi.Extension; +import javax.inject.Inject; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.BeanArchive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.weld.test.util.Utils; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * This tests the sorting of alternatives by priority when one of the priorities + * is {@link Integer.MIN_VALUE}. This previously caused an integer overflow in + * the sorting, and resulted in an incorrect ordering. + * + * @author Karl von Randow + * @see WELD-2628 + */ +@RunWith(Arquillian.class) +public class MinValuePriorityTest { + + @Deployment + public static Archive createTestArchive() { + return ShrinkWrap + .create(BeanArchive.class, + Utils.getDeploymentNameAsHash(MinValuePriorityTest.class)) + .addPackage(AfterTypeDiscoveryObserver.class.getPackage()) + .addAsServiceProvider(Extension.class, + AfterTypeDiscoveryObserver.class); + } + + @Inject AfterTypeDiscoveryObserver extension; + + @Test + public void testInitialAlternatives() { + assertEquals(extension.getInitialAlternatives().size(), 2); + assertEquals(extension.getInitialAlternatives().get(0), + MinValuePriorityAlternative.class); + assertEquals(extension.getInitialAlternatives().get(1), + NormalAlternative.class); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/atd/minvaluepriority/NormalAlternative.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/atd/minvaluepriority/NormalAlternative.java new file mode 100644 index 0000000000..cad772769c --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/atd/minvaluepriority/NormalAlternative.java @@ -0,0 +1,24 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2020, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed 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.jboss.weld.tests.extensions.lifecycle.atd.minvaluepriority; + +import javax.annotation.Priority; +import javax.enterprise.inject.Alternative; + +@Alternative +@Priority(100) +public class NormalAlternative {} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/FirstProcessor.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/FirstProcessor.java index 1b6bb1d267..5996a7a2b6 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/FirstProcessor.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/FirstProcessor.java @@ -17,7 +17,6 @@ package org.jboss.weld.tests.instance.enhanced; import javax.annotation.PreDestroy; - import org.jboss.weld.test.util.ActionSequence; /** @@ -26,18 +25,13 @@ */ public class FirstProcessor implements Processor { - @Override - public void ping() { - ActionSequence.addAction("firstPing"); - } - - @Override - public int getPriority() { - return 1; - } + @Override + public void ping() { + ActionSequence.addAction("firstPing"); + } - @PreDestroy - void destroy() { - ActionSequence.addAction("firstDestroy"); - } + @PreDestroy + void destroy() { + ActionSequence.addAction("firstDestroy"); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/Processor.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/Processor.java index 9eef2604fb..01024e72c0 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/Processor.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/Processor.java @@ -22,7 +22,5 @@ */ public interface Processor { - void ping(); - - int getPriority(); + void ping(); } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/SecondProcessor.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/SecondProcessor.java index 2e876a9f4a..2d37c395a1 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/SecondProcessor.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/SecondProcessor.java @@ -18,7 +18,6 @@ import javax.annotation.PreDestroy; import javax.enterprise.context.ApplicationScoped; - import org.jboss.weld.test.util.ActionSequence; /** @@ -28,18 +27,13 @@ @ApplicationScoped public class SecondProcessor implements Processor { - @Override - public void ping() { - ActionSequence.addAction("secondPing"); - } - - @Override - public int getPriority() { - return 10; - } + @Override + public void ping() { + ActionSequence.addAction("secondPing"); + } - @PreDestroy - void destroy() { - ActionSequence.addAction("secondDestroy"); - } + @PreDestroy + void destroy() { + ActionSequence.addAction("secondDestroy"); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/WeldInstanceTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/WeldInstanceTest.java index fcde2df4d7..85056041fd 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/WeldInstanceTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/enhanced/WeldInstanceTest.java @@ -20,15 +20,13 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; -import java.math.BigDecimal; import java.util.Iterator; import java.util.List; - import javax.enterprise.context.Dependent; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.Archive; @@ -48,85 +46,115 @@ @RunWith(Arquillian.class) public class WeldInstanceTest { - @Deployment - public static Archive createTestArchive() { - return ShrinkWrap.create(BeanArchive.class, Utils.getDeploymentNameAsHash(WeldInstanceTest.class)).addPackage(WeldInstanceTest.class.getPackage()) - .addClass(ActionSequence.class); + @Deployment + public static Archive createTestArchive() { + return ShrinkWrap + .create(BeanArchive.class, + Utils.getDeploymentNameAsHash(WeldInstanceTest.class)) + .addPackage(WeldInstanceTest.class.getPackage()) + .addClass(ActionSequence.class); + } + + @Test + public void testIsResolvable(Client client) { + ActionSequence.reset(); + assertNotNull(client); + assertTrue(client.getAlphaInstance().isResolvable()); + assertFalse(client.getBigDecimalInstance().isResolvable()); + } + + @Test + public void testGetHandler(Client client, BeanManager beanManager) { + ActionSequence.reset(); + assertNotNull(client); + + Bean alphaBean = beanManager.resolve(beanManager.getBeans(Alpha.class)); + WeldInstance instance = client.getAlphaInstance(); + + Handler alpha1 = instance.getHandler(); + assertEquals(alphaBean, alpha1.getBean()); + assertEquals(Dependent.class, alpha1.getBean().getScope()); + + String alpha2Id; + + // Test try-with-resource + try (Handler alpha2 = instance.getHandler()) { + alpha2Id = alpha2.get().getId(); + assertFalse(alpha1.get().getId().equals(alpha2Id)); } - @Test - public void testIsResolvable(Client client) { - ActionSequence.reset(); - assertNotNull(client); - assertTrue(client.getAlphaInstance().isResolvable()); - assertFalse(client.getBigDecimalInstance().isResolvable()); - } + List sequence = ActionSequence.getSequenceData(); + assertEquals(1, sequence.size()); + assertEquals(alpha2Id, sequence.get(0)); - @Test - public void testGetHandler(Client client, BeanManager beanManager) { - ActionSequence.reset(); - assertNotNull(client); - - Bean alphaBean = beanManager.resolve(beanManager.getBeans(Alpha.class)); - WeldInstance instance = client.getAlphaInstance(); - - Handler alpha1 = instance.getHandler(); - assertEquals(alphaBean, alpha1.getBean()); - assertEquals(Dependent.class, alpha1.getBean().getScope()); - - String alpha2Id; - - // Test try-with-resource - try (Handler alpha2 = instance.getHandler()) { - alpha2Id = alpha2.get().getId(); - assertFalse(alpha1.get().getId().equals(alpha2Id)); - } - - List sequence = ActionSequence.getSequenceData(); - assertEquals(1, sequence.size()); - assertEquals(alpha2Id, sequence.get(0)); - - alpha1.destroy(); - // Subsequent invocations are no-op - alpha1.destroy(); - - sequence = ActionSequence.getSequenceData(); - assertEquals(2, sequence.size()); - assertEquals(alpha1.get().getId(), sequence.get(1)); - - // Test normal scoped bean is also destroyed - WeldInstance bravoInstance = client.getInstance().select(Bravo.class); - String bravoId = bravoInstance.get().getId(); - try (Handler bravo = bravoInstance.getHandler()) { - assertEquals(bravoId, bravo.get().getId()); - ActionSequence.reset(); - } - sequence = ActionSequence.getSequenceData(); - assertEquals(1, sequence.size()); - assertEquals(bravoId, sequence.get(0)); - } + alpha1.destroy(); + // Subsequent invocations are no-op + alpha1.destroy(); - @Test - public void testHandlers(WeldInstance instance) { - ActionSequence.reset(); - assertTrue(instance.isAmbiguous()); - for (Handler handler : instance.handlers()) { - handler.get().ping(); - if (handler.getBean().getScope().equals(Dependent.class)) { - handler.destroy(); - } - } - assertEquals(3, ActionSequence.getSequenceSize()); - ActionSequence.assertSequenceDataContainsAll("firstPing", "secondPing", "firstDestroy"); - - ActionSequence.reset(); - assertTrue(instance.isAmbiguous()); - for (Iterator> iterator = instance.handlers().iterator(); iterator.hasNext();) { - try (Handler handler = iterator.next()) { - handler.get().ping(); - } - } - assertEquals(4, ActionSequence.getSequenceSize()); - ActionSequence.assertSequenceDataContainsAll("firstPing", "secondPing", "firstDestroy", "secondDestroy"); + sequence = ActionSequence.getSequenceData(); + assertEquals(2, sequence.size()); + + // Test normal scoped bean is also destroyed + WeldInstance bravoInstance = + client.getInstance().select(Bravo.class); + String bravoId = bravoInstance.get().getId(); + try (Handler bravo = bravoInstance.getHandler()) { + assertEquals(bravoId, bravo.get().getId()); + ActionSequence.reset(); + } + sequence = ActionSequence.getSequenceData(); + assertEquals(1, sequence.size()); + assertEquals(bravoId, sequence.get(0)); + } + + @Test + public void testGetAfterDestroyingContextualInstance(Client client) { + ActionSequence.reset(); + assertNotNull(client); + + Handler alphaHandle = client.getAlphaInstance().getHandler(); + // trigger bean creation + alphaHandle.get(); + // trigger bean destruction + alphaHandle.destroy(); + // verify that the destruction happened + List sequence = ActionSequence.getSequenceData(); + assertEquals(1, sequence.size()); + + // try to invoke Handle.get() again; this should throw an exception + try { + alphaHandle.get(); + fail("Invoking Handle.get() after destroying contextual instance " + + "should throw an exception."); + } catch (IllegalStateException e) { + // expected + } + } + + @Test + public void testHandlers(WeldInstance instance) { + ActionSequence.reset(); + assertTrue(instance.isAmbiguous()); + for (Handler handler : instance.handlers()) { + handler.get().ping(); + if (handler.getBean().getScope().equals(Dependent.class)) { + handler.destroy(); + } + } + assertEquals(3, ActionSequence.getSequenceSize()); + ActionSequence.assertSequenceDataContainsAll("firstPing", "secondPing", + "firstDestroy"); + + ActionSequence.reset(); + assertTrue(instance.isAmbiguous()); + for (Iterator> iterator = instance.handlers().iterator(); + iterator.hasNext();) { + try (Handler handler = iterator.next()) { + handler.get().ping(); + } } + assertEquals(4, ActionSequence.getSequenceSize()); + ActionSequence.assertSequenceDataContainsAll( + "firstPing", "secondPing", "firstDestroy", "secondDestroy"); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/interceptors/bridgemethods/hierarchy/InterceptorBridgeMethodTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/interceptors/bridgemethods/hierarchy/InterceptorBridgeMethodTest.java index ffc441d05c..c2c73baed7 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/interceptors/bridgemethods/hierarchy/InterceptorBridgeMethodTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/interceptors/bridgemethods/hierarchy/InterceptorBridgeMethodTest.java @@ -39,137 +39,145 @@ @RunWith(Arquillian.class) public class InterceptorBridgeMethodTest { - @Deployment - public static JavaArchive createTestArchive() { - return ShrinkWrap - .create(BeanArchive.class, - Utils.getDeploymentNameAsHash(InterceptorBridgeMethodTest.class)) - .intercept(MissileInterceptor.class) - .addPackage(InterceptorBridgeMethodTest.class.getPackage()) - .addClass(ActionSequence.class); - } + @Deployment + public static JavaArchive createTestArchive() { + return ShrinkWrap + .create(BeanArchive.class, Utils.getDeploymentNameAsHash( + InterceptorBridgeMethodTest.class)) + .intercept(MissileInterceptor.class) + .addPackage(InterceptorBridgeMethodTest.class.getPackage()) + .addClass(ActionSequence.class); + } - @Test - public void testChild(@Juicy Child child) { - // Child extends Parent implements Base - reset(); - child.invokeA("foo"); - verify(Child.class); - reset(); - child.getA(); - verify(Parent.class); - reset(); - child.invokeB("foo"); - verify(Parent.class); - reset(); - child.getB(); - verify(Parent.class); - reset(); - child.invokeDefault("foo"); - verify(Parent.class); + @Test + public void testChild(@Juicy Child child) { + // Child extends Parent implements Base + reset(); + child.invokeA("foo"); + verify(Child.class); + reset(); + child.getA(); + verify(Parent.class); + reset(); + child.invokeB("foo"); + verify(Parent.class); + reset(); + child.getB(); + verify(Parent.class); + reset(); + child.invokeDefault("foo"); + verify(Parent.class); - reset(); - Parent parent = child; - parent.invokeA("foo"); - verify(Child.class); - } + reset(); + Parent parent = child; + parent.invokeA("foo"); + verify(Child.class); + } - @Test - public void testJuicyBase(@Juicy Base base) { - // Child gets injected - reset(); - base.invokeA("foo"); - verify(Child.class); - reset(); - base.getA(); - verify(Parent.class); - reset(); - base.invokeB("foo"); - verify(Parent.class); - reset(); - base.getB(); - verify(Parent.class); - reset(); - base.invokeDefault("foo"); - verify(Parent.class); + @Test + public void testJuicyBase(@Juicy Base base) { + // Child gets injected + reset(); + base.invokeA("foo"); + verify(Child.class); + reset(); + base.getA(); + verify(Parent.class); + reset(); + base.invokeB("foo"); + verify(Parent.class); + reset(); + base.getB(); + verify(Parent.class); + reset(); + base.invokeDefault("foo"); + verify(Parent.class); + } - } + @Test + public void testSpecialBase(SpecialBase special) { + // SpecialChild gets injected + reset(); + special.getA(); + verify(SpecialChild.class); + reset(); + special.invokeB("foo"); + verify(SpecialChild.class); + reset(); + special.getB(); + verify(SpecialParent.class); + reset(); + special.invokeDefault("foo"); + verify(Base.class); + } - @Test - public void testSpecialBase(SpecialBase special) { - // SpecialChild gets injected - reset(); - special.getA(); - verify(SpecialChild.class); - reset(); - special.invokeB("foo"); - verify(SpecialChild.class); - reset(); - special.getB(); - verify(SpecialParent.class); - reset(); - special.invokeDefault("foo"); - verify(Base.class); - } + @Test + @Ignore("WELD-2424") + public void testSpecialBaseInvokeA(SpecialBase special) { + // SpecialChild gets injected + reset(); + special.invokeA("foo"); + verify(SpecialParent.class); + } - @Test - @Ignore("WELD-2424") - public void testSpecialBaseInvokeA(SpecialBase special) { - // SpecialChild gets injected - reset(); - special.invokeA("foo"); - verify(SpecialParent.class); - } + @Test + public void testSpecialChild(SpecialChild child) { + // SpecialChild extends AbstractParent implements SpecialBase + reset(); + child.invokeA("foo"); + verify(SpecialParent.class); + reset(); + child.getA(); + verify(SpecialChild.class); + reset(); + child.invokeB("foo"); + verify(SpecialChild.class); + reset(); + child.getB(); + verify(SpecialParent.class); + reset(); + child.invokeDefault("foo"); + verify(Base.class); + } - @Test - public void testSpecialChild(SpecialChild child) { - // SpecialChild extends AbstractParent implements SpecialBase - reset(); - child.invokeA("foo"); - verify(SpecialParent.class); - reset(); - child.getA(); - verify(SpecialChild.class); - reset(); - child.invokeB("foo"); - verify(SpecialChild.class); - reset(); - child.getB(); - verify(SpecialParent.class); - reset(); - child.invokeDefault("foo"); - verify(Base.class); - } + @Test + public void testSpecialBaseAsInterface(SpecialBase specialBase) { + // SpecialBase extends Base + reset(); + specialBase.invokeA("foo"); + verify(SpecialParent.class); + reset(); + } - @Test - public void testAbstractParent(SpecialParent parent) { - // SpecialChild gets injected - reset(); - parent.invokeA("foo"); - verify(SpecialParent.class); - reset(); - parent.getA(); - verify(SpecialChild.class); - reset(); - parent.invokeB("foo"); - verify(SpecialChild.class); - reset(); - parent.getB(); - verify(SpecialParent.class); - reset(); - parent.invokeDefault("foo"); - verify(Base.class); - } + @Test + public void testAbstractParent(SpecialParent parent) { + // SpecialChild gets injected + reset(); + parent.invokeA("foo"); + verify(SpecialParent.class); + reset(); + parent.getA(); + verify(SpecialChild.class); + reset(); + parent.invokeB("foo"); + verify(SpecialChild.class); + reset(); + parent.getB(); + verify(SpecialParent.class); + reset(); + parent.invokeDefault("foo"); + verify(Base.class); + } - private void reset() { - MissileInterceptor.INTERCEPTED.set(false); - ActionSequence.reset(); - } - - private void verify(Class expectedClazz) { - assertTrue(MissileInterceptor.INTERCEPTED.get()); - assertEquals(1, ActionSequence.getSequenceSize()); - assertEquals(expectedClazz.getName(), ActionSequence.getSequenceData().get(0)); - } + private void reset() { + MissileInterceptor.INTERCEPTED.set(false); + ActionSequence.reset(); + } + private void verify(Class expectedClazz) { + assertTrue(MissileInterceptor.INTERCEPTED.get()); + assertEquals(1, ActionSequence.getSequenceSize()); + assertEquals(expectedClazz.getName(), + ActionSequence.getSequenceData().get(0)); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/interceptors/generic/SimpleWeldClassTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/interceptors/generic/SimpleWeldClassTest.java index 06bb2a4451..d78d9cd1af 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/interceptors/generic/SimpleWeldClassTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/interceptors/generic/SimpleWeldClassTest.java @@ -18,9 +18,6 @@ import java.util.Collection; import java.util.List; - -import org.junit.Assert; - import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.Archive; @@ -36,6 +33,7 @@ import org.jboss.weld.resources.SharedObjectCache; import org.jboss.weld.test.util.Utils; import org.jboss.weld.util.Beans; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -43,26 +41,32 @@ * @author Marius Bogoevici */ @RunWith(Arquillian.class) -public class SimpleWeldClassTest -{ - @Deployment - public static Archive deploy() - { - return ShrinkWrap.create(BeanArchive.class, Utils.getDeploymentNameAsHash(SimpleWeldClassTest.class)) - .addPackage(SimpleWeldClassTest.class.getPackage()); - } - - /* - * description = "WELD-568" - */ - @Test - public void testWeldClassForGenericSuperclass() { - TypeStore ts = new TypeStore(); - EnhancedAnnotatedType weldClass = new ClassTransformer(ts, new SharedObjectCache(), ReflectionCacheFactory.newInstance(ts), RegistrySingletonProvider.STATIC_INSTANCE).getEnhancedAnnotatedType(StringProcessor.class, AnnotatedTypeIdentifier.NULL_BDA_ID); - Collection> methods = weldClass.getEnhancedMethods(); - //assert methods.size() == 2; - List> interceptableMethods = Beans.getInterceptableMethods(weldClass); - Assert.assertEquals(3, interceptableMethods.size()); - } +public class SimpleWeldClassTest { + @Deployment + public static Archive deploy() { + return ShrinkWrap + .create(BeanArchive.class, + Utils.getDeploymentNameAsHash(SimpleWeldClassTest.class)) + .addPackage(SimpleWeldClassTest.class.getPackage()); + } + /* + * description = "WELD-568" + */ + @Test + public void testWeldClassForGenericSuperclass() { + TypeStore ts = new TypeStore(); + EnhancedAnnotatedType weldClass = + new ClassTransformer(ts, new SharedObjectCache(), + ReflectionCacheFactory.newInstance(ts), + RegistrySingletonProvider.STATIC_INSTANCE) + .getEnhancedAnnotatedType(StringProcessor.class, + AnnotatedTypeIdentifier.NULL_BDA_ID); + Collection> methods = + weldClass.getEnhancedMethods(); + // assert methods.size() == 2; + List> interceptableMethods = + Beans.getInterceptableMethods(weldClass); + Assert.assertEquals(5, interceptableMethods.size()); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/jsf/weld1037/Weld1037Test.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/jsf/weld1037/Weld1037Test.java index e255f61dcf..6bb429820c 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/jsf/weld1037/Weld1037Test.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/jsf/weld1037/Weld1037Test.java @@ -17,12 +17,13 @@ package org.jboss.weld.tests.jsf.weld1037; -import java.net.URL; - -import javax.servlet.http.HttpServletResponse; +import static org.junit.Assert.assertEquals; import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.WebClientOptions; +import java.net.URL; +import javax.servlet.http.HttpServletResponse; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.RunAsClient; import org.jboss.arquillian.junit.Arquillian; @@ -36,8 +37,6 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import static org.junit.Assert.assertEquals; - /** * @author Marko Luksa */ @@ -45,26 +44,33 @@ @RunWith(Arquillian.class) public class Weld1037Test { - @Deployment - public static WebArchive deployment() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(Weld1037Test.class, Utils.ARCHIVE_TYPE.WAR)) - .addClass(RedirectBean.class) - .addAsWebResource(Weld1037Test.class.getPackage(), "doRedirect.xhtml", "doRedirect.xhtml") - .addAsWebInfResource(Weld1037Test.class.getPackage(), "web.xml", "web.xml") - .addAsWebInfResource(Weld1037Test.class.getPackage(), "faces-config.xml", "faces-config.xml") - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); - } - - @Test - @RunAsClient - public void testRedirectInPreRenderViewAction(@ArquillianResource URL url) throws Exception { - WebClient client = new WebClient(); - client.setRedirectEnabled(false); - client.setThrowExceptionOnFailingStatusCode(false); - - Page page = client.getPage(url + "/doRedirect.faces"); - assertEquals("Expected redirect:", HttpServletResponse.SC_MOVED_TEMPORARILY, page.getWebResponse().getStatusCode()); - } + @Deployment + public static WebArchive deployment() { + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash(Weld1037Test.class, + Utils.ARCHIVE_TYPE.WAR)) + .addClass(RedirectBean.class) + .addAsWebResource(Weld1037Test.class.getPackage(), "doRedirect.xhtml", + "doRedirect.xhtml") + .addAsWebInfResource(Weld1037Test.class.getPackage(), "web.xml", + "web.xml") + .addAsWebInfResource(Weld1037Test.class.getPackage(), + "faces-config.xml", "faces-config.xml") + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } + @Test + @RunAsClient + public void testRedirectInPreRenderViewAction(@ArquillianResource URL url) + throws Exception { + WebClient client = new WebClient(); + WebClientOptions options = client.getOptions(); + options.setRedirectEnabled(false); + options.setThrowExceptionOnFailingStatusCode(false); + Page page = client.getPage(url + "/doRedirect.faces"); + assertEquals("Expected redirect:", HttpServletResponse.SC_MOVED_TEMPORARILY, + page.getWebResponse().getStatusCode()); + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/jsp/JspTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/jsp/JspTest.java index 71cb9a73b9..851fc25f2b 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/jsp/JspTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/jsp/JspTest.java @@ -33,11 +33,9 @@ * limitations under the License. */ -import java.net.URL; - import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.WebClient; -import org.junit.Assert; +import java.net.URL; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -46,6 +44,7 @@ import org.jboss.shrinkwrap.api.spec.WebArchive; import org.jboss.weld.test.util.Utils; import org.jboss.weld.tests.category.Integration; +import org.junit.Assert; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -57,30 +56,32 @@ @Category(Integration.class) @RunWith(Arquillian.class) public class JspTest { - @Deployment(testable = false) - public static WebArchive createDeployment() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(JspTest.class, Utils.ARCHIVE_TYPE.WAR)) - .addAsWebInfResource(JspTest.class.getPackage(), "web.xml", "web.xml") - .addAsWebInfResource(JspTest.class.getPackage(), "faces-config.xml", "faces-config.xml") - .addAsWebResource(JspTest.class.getPackage(), "index.jsp", "index.jsp") - .addAsWebResource(JspTest.class.getPackage(), "home.jspx", "home.jspx") - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); - } + @Deployment(testable = false) + public static WebArchive createDeployment() { + return ShrinkWrap + .create(WebArchive.class, Utils.getDeploymentNameAsHash( + JspTest.class, Utils.ARCHIVE_TYPE.WAR)) + .addAsWebInfResource(JspTest.class.getPackage(), "web.xml", "web.xml") + .addAsWebInfResource(JspTest.class.getPackage(), "faces-config.xml", + "faces-config.xml") + .addAsWebResource(JspTest.class.getPackage(), "index.jsp", "index.jsp") + .addAsWebResource(JspTest.class.getPackage(), "home.jspx", "home.jspx") + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } - @ArquillianResource - private URL url; + @ArquillianResource private URL url; - @Test - public void testConversationPropagationToNonExistentConversationLeadsException() throws Exception { - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(false); - Page page = client.getPage(getPath("/index.jsp")); + @Test + public void + testConversationPropagationToNonExistentConversationLeadsException() + throws Exception { + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + Page page = client.getPage(getPath("/index.jsp")); - Assert.assertEquals(200, page.getWebResponse().getStatusCode()); - Assert.assertTrue(page.getUrl().toString().contains("home.jsf")); - } + Assert.assertEquals(200, page.getWebResponse().getStatusCode()); + Assert.assertTrue(page.getUrl().toString().contains("home.jsf")); + } - protected String getPath(String page) { - return url + page; - } + protected String getPath(String page) { return url + page; } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/producer/field/named/NamedProducerTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/producer/field/named/NamedProducerTest.java index 6cc4f489d2..3a1141d0ae 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/producer/field/named/NamedProducerTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/producer/field/named/NamedProducerTest.java @@ -22,6 +22,9 @@ import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; import com.gargoylesoftware.htmlunit.html.HtmlTextInput; +import java.net.URL; +import java.util.HashSet; +import java.util.Set; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -35,10 +38,6 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import java.net.URL; -import java.util.HashSet; -import java.util.Set; - /** *

Check what happens when session.invalidate() is called.

* @@ -47,80 +46,90 @@ @Category(Integration.class) @RunWith(Arquillian.class) public class NamedProducerTest { - @Deployment(testable = false) - public static WebArchive createDeployment() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(NamedProducerTest.class, Utils.ARCHIVE_TYPE.WAR)) - .addClasses(User.class, NewUserAction.class, Employee.class, SaveAction.class) - .addAsWebInfResource(NamedProducerTest.class.getPackage(), "web.xml", "web.xml") - .addAsWebInfResource(NamedProducerTest.class.getPackage(), "faces-config.xml", "faces-config.xml") - .addAsWebResource(NamedProducerTest.class.getPackage(), "view.xhtml", "view.xhtml") - .addAsWebResource(NamedProducerTest.class.getPackage(), "home.xhtml", "home.xhtml") - .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); - } - - @ArquillianResource - private URL url; - - /* - * description = "forum post" - */ - @Test - public void testNamedProducerWorks() throws Exception { - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(false); - - HtmlPage page = client.getPage(getPath("/view.jsf")); - // Check the page rendered ok - Assert.assertNotNull(getFirstMatchingElement(page, HtmlSubmitInput.class, "saveButton")); + @Deployment(testable = false) + public static WebArchive createDeployment() { + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash(NamedProducerTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addClasses(User.class, NewUserAction.class, Employee.class, + SaveAction.class) + .addAsWebInfResource(NamedProducerTest.class.getPackage(), "web.xml", + "web.xml") + .addAsWebInfResource(NamedProducerTest.class.getPackage(), + "faces-config.xml", "faces-config.xml") + .addAsWebResource(NamedProducerTest.class.getPackage(), "view.xhtml", + "view.xhtml") + .addAsWebResource(NamedProducerTest.class.getPackage(), "home.xhtml", + "home.xhtml") + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } + + @ArquillianResource private URL url; + + /* + * description = "forum post" + */ + @Test + public void testNamedProducerWorks() throws Exception { + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + + HtmlPage page = client.getPage(getPath("/view.jsf")); + // Check the page rendered ok + Assert.assertNotNull( + getFirstMatchingElement(page, HtmlSubmitInput.class, "saveButton")); + } + + /* + * description = "WELD-404" + */ + @Test + public void testNamedProducerFieldLoosesValues() throws Exception { + WebClient client = new WebClient(); + + HtmlPage page = client.getPage(getPath("/home.jsf")); + // Check the page rendered ok + HtmlSubmitInput saveButton = + getFirstMatchingElement(page, HtmlSubmitInput.class, "saveButton"); + HtmlTextInput employeeFieldName = + getFirstMatchingElement(page, HtmlTextInput.class, "employeeFieldName"); + HtmlTextInput employeeMethodName = getFirstMatchingElement( + page, HtmlTextInput.class, "employeeMethodName"); + + Assert.assertNotNull(employeeFieldName); + Assert.assertNotNull(employeeMethodName); + Assert.assertNotNull(saveButton); + + employeeFieldName.setValueAttribute("Pete"); + employeeMethodName.setValueAttribute("Gavin"); + saveButton.click(); + } + + protected String getPath(String page) { return url + page; } + + protected Set getElements(HtmlElement rootElement, + Class elementClass) { + Set result = new HashSet(); + + for (HtmlElement element : rootElement.getHtmlElementDescendants()) { + result.addAll(getElements(element, elementClass)); } - /* - * description = "WELD-404" - */ - @Test - public void testNamedProducerFieldLoosesValues() throws Exception { - WebClient client = new WebClient(); - - HtmlPage page = client.getPage(getPath("/home.jsf")); - // Check the page rendered ok - HtmlSubmitInput saveButton = getFirstMatchingElement(page, HtmlSubmitInput.class, "saveButton"); - HtmlTextInput employeeFieldName = getFirstMatchingElement(page, HtmlTextInput.class, "employeeFieldName"); - HtmlTextInput employeeMethodName = getFirstMatchingElement(page, HtmlTextInput.class, "employeeMethodName"); - - Assert.assertNotNull(employeeFieldName); - Assert.assertNotNull(employeeMethodName); - Assert.assertNotNull(saveButton); - - employeeFieldName.setValueAttribute("Pete"); - employeeMethodName.setValueAttribute("Gavin"); - saveButton.click(); + if (elementClass.isInstance(rootElement)) { + result.add(elementClass.cast(rootElement)); } - - protected String getPath(String page) { - return url + page; - } - - protected Set getElements(HtmlElement rootElement, Class elementClass) { - Set result = new HashSet(); - - for (HtmlElement element : rootElement.getChildElements()) { - result.addAll(getElements(element, elementClass)); - } - - if (elementClass.isInstance(rootElement)) { - result.add(elementClass.cast(rootElement)); - } - return result; - - } - - protected T getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { - Set inputs = getElements(page.getBody(), elementClass); - for (T input : inputs) { - if (input.getId().contains(id)) { - return input; - } - } - return null; + return result; + } + + protected T + getFirstMatchingElement(HtmlPage page, Class elementClass, String id) { + Set inputs = getElements(page.getBody(), elementClass); + for (T input : inputs) { + if (input.getId().contains(id)) { + return input; + } } + return null; + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/resources/EMFFactoryTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/resources/EMFFactoryTest.java index 8394c555ad..631e36fc07 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/resources/EMFFactoryTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/resources/EMFFactoryTest.java @@ -16,10 +16,11 @@ */ package org.jboss.weld.tests.resources; -import java.net.URL; +import static org.junit.Assert.assertEquals; import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.WebClient; +import java.net.URL; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -34,65 +35,74 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import static org.junit.Assert.assertEquals; - @Category(Integration.class) @RunWith(Arquillian.class) public class EMFFactoryTest { - public static final Asset PERSISTENCE_XML = new ByteArrayAsset("java:jboss/datasources/ExampleDS".getBytes()); - public static final Asset EMPTY_BEANS_XML = new ByteArrayAsset("".getBytes()); + public static final Asset PERSISTENCE_XML = new ByteArrayAsset( + ("java:jboss/datasources/ExampleDS") + .getBytes()); + public static final Asset EMPTY_BEANS_XML = + new ByteArrayAsset("".getBytes()); - @Deployment(testable = false) - public static Archive deploy() { - return ShrinkWrap.create(WebArchive.class, Utils.getDeploymentNameAsHash(EMFFactoryTest.class, Utils.ARCHIVE_TYPE.WAR)) - .addClasses(JPAResourceProducerSingletonEJB_StaticField.class, ProducedViaStaticFieldOnEJB.class, EMFConsumer1.class) - .addClasses(JPAResourceProducerManagedBean_InstanceField.class, ProducedViaInstanceFieldOnManagedBean.class, EMFConsumer2.class) - .addClasses(JPAResourceProducerManagedBean_StaticField.class, ProducedViaStaticFieldOnManagedBean.class, EMFConsumer3.class) - .addAsResource(PERSISTENCE_XML, "META-INF/persistence.xml") - .addAsWebInfResource(EMPTY_BEANS_XML, "beans.xml"); - } + @Deployment(testable = false) + public static Archive deploy() { + return ShrinkWrap + .create(WebArchive.class, + Utils.getDeploymentNameAsHash(EMFFactoryTest.class, + Utils.ARCHIVE_TYPE.WAR)) + .addClasses(JPAResourceProducerSingletonEJB_StaticField.class, + ProducedViaStaticFieldOnEJB.class, EMFConsumer1.class) + .addClasses(JPAResourceProducerManagedBean_InstanceField.class, + ProducedViaInstanceFieldOnManagedBean.class, + EMFConsumer2.class) + .addClasses(JPAResourceProducerManagedBean_StaticField.class, + ProducedViaStaticFieldOnManagedBean.class, + EMFConsumer3.class) + .addAsResource(PERSISTENCE_XML, "META-INF/persistence.xml") + .addAsWebInfResource(EMPTY_BEANS_XML, "beans.xml"); + } - @ArquillianResource - private URL url; + @ArquillianResource private URL url; - /* - * description = "WELD-632" - */ - @Test - public void testStaticEJBEMFProducerField() throws Exception { - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(false); - Page page = client.getPage(getPath("emfconsumer1")); + /* + * description = "WELD-632" + */ + @Test + public void testStaticEJBEMFProducerField() throws Exception { + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + Page page = client.getPage(getPath("emfconsumer1")); - assertEquals(200, page.getWebResponse().getStatusCode()); - } + assertEquals(200, page.getWebResponse().getStatusCode()); + } - /* - * description = "WELD-632" - */ - @Test - public void testInstanceManagedBeanEMFProducerField() throws Exception { - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(false); - Page page = client.getPage(getPath("emfconsumer2")); + /* + * description = "WELD-632" + */ + @Test + public void testInstanceManagedBeanEMFProducerField() throws Exception { + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + Page page = client.getPage(getPath("emfconsumer2")); - assertEquals(200, page.getWebResponse().getStatusCode()); - } + assertEquals(200, page.getWebResponse().getStatusCode()); + } - /* - * description = "WELD-632" - */ - @Test - public void testStaticManagedBeanEMFProducerField() throws Exception { - WebClient client = new WebClient(); - client.setThrowExceptionOnFailingStatusCode(false); - Page page = client.getPage(getPath("emfconsumer3")); + /* + * description = "WELD-632" + */ + @Test + public void testStaticManagedBeanEMFProducerField() throws Exception { + WebClient client = new WebClient(); + client.getOptions().setThrowExceptionOnFailingStatusCode(false); + Page page = client.getPage(getPath("emfconsumer3")); - assertEquals(200, page.getWebResponse().getStatusCode()); - } + assertEquals(200, page.getWebResponse().getStatusCode()); + } - protected String getPath(String viewId) { - return url + viewId; - } + protected String getPath(String viewId) { return url + viewId; } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/resources/proxy/weld1782/Controller.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/resources/proxy/weld1782/Controller.java index 11c881b403..cb90e5ea80 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/resources/proxy/weld1782/Controller.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/resources/proxy/weld1782/Controller.java @@ -17,7 +17,6 @@ package org.jboss.weld.tests.resources.proxy.weld1782; import java.util.concurrent.CountDownLatch; - import javax.enterprise.context.ApplicationScoped; /** @@ -27,19 +26,12 @@ @ApplicationScoped public class Controller { - private CountDownLatch msgDeliveredLatch = new CountDownLatch(1); - private CountDownLatch contextDestroyedLatch = new CountDownLatch(1); - - public CountDownLatch getMsgDeliveredLatch() { - return msgDeliveredLatch; - } + private final CountDownLatch msgDeliveredLatch = new CountDownLatch(1); + private final CountDownLatch contextDestroyedLatch = new CountDownLatch(1); - public CountDownLatch getContextDestroyedLatch() { - return contextDestroyedLatch; - } + public CountDownLatch getMsgDeliveredLatch() { return msgDeliveredLatch; } - public void resetLatches() { - msgDeliveredLatch = new CountDownLatch(1); - contextDestroyedLatch = new CountDownLatch(1); - } + public CountDownLatch getContextDestroyedLatch() { + return contextDestroyedLatch; + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/servlet/dispatch/TestBean.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/servlet/dispatch/TestBean.java index bac11cfd97..1b7e067b43 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/servlet/dispatch/TestBean.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/servlet/dispatch/TestBean.java @@ -16,36 +16,47 @@ */ package org.jboss.weld.tests.servlet.dispatch; +import java.util.concurrent.Phaser; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import javax.enterprise.context.ApplicationScoped; @ApplicationScoped public class TestBean { - private int constructions; - private int destructions; - - public void constructed() { - constructions++; + private int constructions; + private int destructions; + private Phaser phaser; + + public void constructed() { + constructions++; + phaser.register(); + } + + public void destroyed() { + destructions++; + phaser.arriveAndDeregister(); + } + + public boolean isOk() { + try { + // either the phaser has already reached stability (phase 0 and + // terminated) or we wait for it + phaser.awaitAdvanceInterruptibly(0, 2l, TimeUnit.SECONDS); + } catch (InterruptedException | TimeoutException e) { + throw new IllegalStateException( + "Waiting for Phaser stability failed, exception throws was: " + e); } + return (constructions == destructions) && + (constructions + destructions > 0); + } - public void destroyed() { - destructions++; - } + public void reset() { + constructions = destructions = 0; + phaser = new Phaser(); + } - public boolean isOk() { - return (constructions == destructions) && (constructions + destructions > 0); - } - - public void reset() { - constructions = destructions = 0; - } - - public int getConstructions() { - return constructions; - } - - public int getDestructions() { - return destructions; - } + public int getConstructions() { return constructions; } + public int getDestructions() { return destructions; } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/util/WildFly8DeploymentExceptionTransformer.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/util/WildFly8DeploymentExceptionTransformer.java index a3a71e14cb..bc9473ba41 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/util/WildFly8DeploymentExceptionTransformer.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/util/WildFly8DeploymentExceptionTransformer.java @@ -17,73 +17,77 @@ package org.jboss.weld.tests.util; import java.util.List; - import javax.enterprise.inject.spi.DefinitionException; import javax.enterprise.inject.spi.DeploymentException; - -import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.jboss.arquillian.container.spi.client.container.DeploymentExceptionTransformer; import org.jboss.weld.exceptions.IllegalStateException; /** - * TEMPORARY WORKAROUND - temporary replacement for NOOP {@link org.jboss.as.arquillian.container.ExceptionTransformer} used by - * WildFly managed container. + * TEMPORARY WORKAROUND - temporary replacement for NOOP {@link + * org.jboss.as.arquillian.container.ExceptionTransformer} used by WildFly + * managed container. * * See AS7-1197 for more details. * * @see WildFly8Extension * @author Martin Kouba */ -public class WildFly8DeploymentExceptionTransformer implements DeploymentExceptionTransformer { +public class WildFly8DeploymentExceptionTransformer + implements DeploymentExceptionTransformer { - private static final String[] DEPLOYMENT_EXCEPTION_FRAGMENTS = new String[] { - "org.jboss.weld.exceptions.DeploymentException", "org.jboss.weld.exceptions.UnserializableDependencyException", - "org.jboss.weld.exceptions.InconsistentSpecializationException", - "org.jboss.weld.exceptions.NullableDependencyException" }; + private static final String[] DEPLOYMENT_EXCEPTION_FRAGMENTS = new String[] { + "org.jboss.weld.exceptions.DeploymentException", + "org.jboss.weld.exceptions.UnserializableDependencyException", + "org.jboss.weld.exceptions.InconsistentSpecializationException", + "org.jboss.weld.exceptions.NullableDependencyException"}; - private static final String[] DEFINITION_EXCEPTION_FRAGMENTS = new String[] { "org.jboss.weld.exceptions.DefinitionException" }; + private static final String[] DEFINITION_EXCEPTION_FRAGMENTS = + new String[] {"org.jboss.weld.exceptions.DefinitionException"}; - private static final String[] ISE_EXCEPTION_FRAGMENTS = new String[] { "org.jboss.weld.exceptions.IllegalStateException" }; + private static final String[] ISE_EXCEPTION_FRAGMENTS = + new String[] {"org.jboss.weld.exceptions.IllegalStateException"}; - public Throwable transform(Throwable throwable) { + public Throwable transform(Throwable throwable) { - // Arquillian sometimes returns InvocationException with nested AS7 - // exception and sometimes AS7 exception itself - @SuppressWarnings("unchecked") - List throwableList = ExceptionUtils.getThrowableList(throwable); - if (throwableList.isEmpty()) - return throwable; + // Arquillian sometimes returns InvocationException with nested AS7 + // exception and sometimes AS7 exception itself + @SuppressWarnings("unchecked") + List throwableList = ExceptionUtils.getThrowableList(throwable); + if (throwableList.isEmpty()) + return throwable; - Throwable root = null; + Throwable root = null; - if (throwableList.size() == 1) { - root = throwable; - } else { - root = ExceptionUtils.getRootCause(throwable); - } - - if (root instanceof DeploymentException || root instanceof DefinitionException || root instanceof IllegalStateException) { - return root; - } - if (isFragmentFound(DEPLOYMENT_EXCEPTION_FRAGMENTS, root)) { - return new DeploymentException(root.getMessage()); - } - if (isFragmentFound(DEFINITION_EXCEPTION_FRAGMENTS, root)) { - return new DefinitionException(root.getMessage()); - } - if (isFragmentFound(ISE_EXCEPTION_FRAGMENTS, root)) { - return new IllegalStateException(root.getMessage()); - } - return throwable; + if (throwableList.size() == 1) { + root = throwable; + } else { + root = ExceptionUtils.getRootCause(throwable); } - private boolean isFragmentFound(String[] fragments, Throwable rootException) { - for (String fragment : fragments) { - if (rootException.getMessage().contains(fragment)) { - return true; - } - } - return false; + if (root instanceof DeploymentException || + root instanceof DefinitionException || + root instanceof IllegalStateException) { + return root; + } + if (isFragmentFound(DEPLOYMENT_EXCEPTION_FRAGMENTS, root)) { + return new DeploymentException(root.getMessage()); } + if (isFragmentFound(DEFINITION_EXCEPTION_FRAGMENTS, root)) { + return new DefinitionException(root.getMessage()); + } + if (isFragmentFound(ISE_EXCEPTION_FRAGMENTS, root)) { + return new IllegalStateException(root.getMessage()); + } + return throwable; + } + private boolean isFragmentFound(String[] fragments, Throwable rootException) { + for (String fragment : fragments) { + if (rootException.getMessage().contains(fragment)) { + return true; + } + } + return false; + } } diff --git a/tests-common/pom.xml b/tests-common/pom.xml index 9ff151f987..568fa75f08 100644 --- a/tests-common/pom.xml +++ b/tests-common/pom.xml @@ -3,7 +3,7 @@ weld-core-parent org.jboss.weld - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../pom.xml 4.0.0 diff --git a/tests/pom.xml b/tests/pom.xml index 7948956c50..47cc0e220a 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -3,7 +3,7 @@ weld-core-parent org.jboss.weld - 3.1.5-SNAPSHOT + 3.1.11-SNAPSHOT ../pom.xml 4.0.0 diff --git a/tests/src/main/java/org/jboss/weld/mock/cluster/AbstractClusterTest.java b/tests/src/main/java/org/jboss/weld/mock/cluster/AbstractClusterTest.java index b04ebad0e7..ebdb01c0b0 100644 --- a/tests/src/main/java/org/jboss/weld/mock/cluster/AbstractClusterTest.java +++ b/tests/src/main/java/org/jboss/weld/mock/cluster/AbstractClusterTest.java @@ -16,10 +16,19 @@ */ package org.jboss.weld.mock.cluster; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import java.util.Collection; +import java.util.Map; import org.jboss.arquillian.container.weld.embedded.mock.BeanDeploymentArchiveImpl; import org.jboss.arquillian.container.weld.embedded.mock.FlatDeployment; import org.jboss.arquillian.container.weld.embedded.mock.TestContainer; import org.jboss.weld.Container; +import org.jboss.weld.bean.proxy.util.WeldDefaultProxyServices; import org.jboss.weld.bootstrap.api.Singleton; import org.jboss.weld.context.bound.BoundSessionContext; import org.jboss.weld.manager.BeanManagerImpl; @@ -28,89 +37,88 @@ import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.lang.reflect.Field; -import java.util.Collection; -import java.util.Map; - public class AbstractClusterTest { - private Singleton singleton; - - @SuppressWarnings("unchecked") - @BeforeClass - public void beforeClass() throws Exception { - singleton = (Singleton) getInstanceField().get(null); - getInstanceField().set(null, new SwitchableSingletonProvider().create(Container.class)); - } - - private static Field getInstanceField() throws Exception { - Field field = Container.class.getDeclaredField("instance"); - field.setAccessible(true); - return field; - } - - @AfterClass - public void afterClass() throws Exception { - getInstanceField().set(null, singleton); - } - - protected TestContainer bootstrapContainer(int id, Collection> classes) { - // Bootstrap container - SwitchableSingletonProvider.use(id); - - TestContainer container = new TestContainer(new FlatDeployment(new BeanDeploymentArchiveImpl(classes))); - container.getDeployment().getServices().add(ProxyServices.class, new SwitchableCLProxyServices()); - container.startContainer(); - container.ensureRequestActive(); - - return container; - } - - protected static BeanManagerImpl getBeanManager(TestContainer container) { - return (BeanManagerImpl) container.getBeanManager(container.getDeployment().getBeanDeploymentArchives().iterator().next()); - } - - protected void use(int id) { - SwitchableSingletonProvider.use(id); - } - - protected void replicateSession(int fromId, TestContainer fromContainer, int toId, TestContainer toContainer) throws Exception { - // Mimic replicating the session - first serialize the objects - byte[] bytes = serialize(fromContainer.getSessionStore()); - use(toId); - - // Deactivate the other store - BoundSessionContext sessionContext = toContainer.instance().select(BoundSessionContext.class).get(); - sessionContext.deactivate(); - sessionContext.dissociate(toContainer.getSessionStore()); - - // then copy them into the other session store - toContainer.getSessionStore().putAll(Reflections.>cast(deserialize(bytes))); - sessionContext.associate(toContainer.getSessionStore()); - - // then activate again - sessionContext.activate(); - use(fromId); - } - - protected byte[] serialize(Object instance) throws IOException { - ByteArrayOutputStream bytes = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(bytes); - out.writeObject(instance); - return bytes.toByteArray(); - } - - protected Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException { - ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes)); - return in.readObject(); - } - - protected void useNewClassLoader(ClassLoader parentClassLoader) { - ((SwitchableCLProxyServices) Container.instance().services().get(ProxyServices.class)).useNewClassLoader(parentClassLoader); - } + private Singleton singleton; + + @SuppressWarnings("unchecked") + @BeforeClass + public void beforeClass() throws Exception { + singleton = (Singleton)getInstanceField().get(null); + getInstanceField().set( + null, new SwitchableSingletonProvider().create(Container.class)); + } + + private static Field getInstanceField() throws Exception { + Field field = Container.class.getDeclaredField("instance"); + field.setAccessible(true); + return field; + } + + @AfterClass + public void afterClass() throws Exception { + getInstanceField().set(null, singleton); + } + + protected TestContainer bootstrapContainer(int id, + Collection> classes) { + // Bootstrap container + SwitchableSingletonProvider.use(id); + + TestContainer container = new TestContainer( + new FlatDeployment(new BeanDeploymentArchiveImpl(classes))); + container.getDeployment().getServices().add(ProxyServices.class, + new WeldDefaultProxyServices()); + container.startContainer(); + container.ensureRequestActive(); + + return container; + } + + protected static BeanManagerImpl getBeanManager(TestContainer container) { + return (BeanManagerImpl)container.getBeanManager( + container.getDeployment() + .getBeanDeploymentArchives() + .iterator() + .next()); + } + + protected void use(int id) { SwitchableSingletonProvider.use(id); } + + protected void replicateSession(int fromId, TestContainer fromContainer, + int toId, TestContainer toContainer) + throws Exception { + // Mimic replicating the session - first serialize the objects + byte[] bytes = serialize(fromContainer.getSessionStore()); + use(toId); + + // Deactivate the other store + BoundSessionContext sessionContext = + toContainer.instance().select(BoundSessionContext.class).get(); + sessionContext.deactivate(); + sessionContext.dissociate(toContainer.getSessionStore()); + + // then copy them into the other session store + toContainer.getSessionStore().putAll( + Reflections.>cast(deserialize(bytes))); + sessionContext.associate(toContainer.getSessionStore()); + + // then activate again + sessionContext.activate(); + use(fromId); + } + + protected byte[] serialize(Object instance) throws IOException { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(bytes); + out.writeObject(instance); + return bytes.toByteArray(); + } + + protected Object deserialize(byte[] bytes) + throws IOException, ClassNotFoundException { + ObjectInputStream in = + new ObjectInputStream(new ByteArrayInputStream(bytes)); + return in.readObject(); + } } diff --git a/tests/src/main/java/org/jboss/weld/mock/cluster/SwitchableCLProxyServices.java b/tests/src/main/java/org/jboss/weld/mock/cluster/SwitchableCLProxyServices.java deleted file mode 100644 index d4c5b50ae7..0000000000 --- a/tests/src/main/java/org/jboss/weld/mock/cluster/SwitchableCLProxyServices.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * JBoss, Home of Professional Open Source - * Copyright 2008, Red Hat, Inc. and/or its affiliates, and individual contributors - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * Licensed 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.jboss.weld.mock.cluster; - -import org.jboss.weld.bean.proxy.util.SimpleProxyServices; -import org.jboss.weld.exceptions.WeldException; - -/** - * Uses a special CL to hold the proxies and allows a test to switch to a new - * CL. This is useful for testing cluster environments where the VMs are - * different and thus the CL would also be different between serialization and - * deserialization. - * - * @author David Allen - */ -public class SwitchableCLProxyServices extends SimpleProxyServices { - private ClassLoader currentClassLoader; - - @Override - public ClassLoader getClassLoader(Class type) { - if (currentClassLoader == null) { - ClassLoader baseClassLoader = super.getClassLoader(type); - useNewClassLoader(baseClassLoader); - } - return currentClassLoader; - } - - @Override - public Class loadBeanClass(String className) { - try { - return currentClassLoader.loadClass(className); - } catch (ClassNotFoundException e) { - throw new WeldException(e); - } - } - - public void useNewClassLoader(ClassLoader parentClassLoader) { - currentClassLoader = new ClusterClassLoader(parentClassLoader); - } -}