简体   繁体   English

在JBoss Wildfly中使用EJB和JAR进行EAR部署-如何从EJB项目中加载JAR的文件夹或资源中的所有文件?

[英]EAR deployment with EJB and JAR in JBoss Wildfly - how to load all files in folder or resources in JAR from within EJB project?

I want to load and process json schema files from within two different deployments, the first being a WAR with JAX-RS endpoint and the second an EAR with Singleton- EJB + a resources JAR containing the schema files (I've read that packaging resources files for use in EJBs is only possible when bundling them in a separate JAR inside the EAR). 我想从两个不同的部署中加载和处理json模式文件,第一个是具有JAX-RS端点的WAR ,第二个是具有Singleton- EJBEAR +包含模式文件的资源JAR (我已经阅读了打包资源仅当将它们捆绑在EAR内部的单独JAR中时,才可以在EJB中使用这些文件。

Development environment is eclipse 2019-03 with JBoss Wildfly 16. JBoss Wildfly 16的开发环境将在2019-03月出现。

WAR deployment with JAX-RS endpoint 使用JAX-RS端点进行WAR部署

The WAR part is fine, I have an @ApplicationScoped Bean and can access the schema files located in src/main/webapp/schemas/ via ServletContext, see the following code snippet: WAR部分很好,我有一个@ApplicationScoped Bean,可以通过ServletContext访问src/main/webapp/schemas/的模式文件,请参见以下代码片段:

@ForWarDeployment
@ApplicationScoped
public class JsonSchemaValidatorWar extends JsonSchemaValidatorBase {
...
@PostConstruct
public void init() {
    Consumer<Path> readSchema = schemaFile -> {
        String schemaName = schemaFile.getName(schemaFile.getNameCount() - 1).toString();
        JsonSchema js = jvs.readSchema(schemaFile);
        map.put(schemaName, js); // this is a concurrent hash map in base class
        log.info("Schema " + schemaName + " added: " + js.toJson());
    };
    URI schemaFolder;
    try {
        schemaFolder = servletContext.getResource("/schemas").toURI();
        try (Stream<Path> paths = Files.walk(Paths.get(schemaFolder))) {
            paths.filter(Files::isRegularFile).forEach(readSchema);
        }
    } catch (URISyntaxException | IOException e) {
        throw new RuntimeException("Error loading schema files!", e);
    }
}

Output on first request: 根据第一个请求输出:

... (default task-1) Schema person.schema.json added: {"$id": ... ...(默认任务1)已添加架构person.schema.json:{“ $ id”:...

EAR deployment with EJB and resources JAR 使用EJB和资源JAR进行EAR部署

The EJB part is tricky, I haven't found a solution for reading all schema files yet. EJB部分很棘手,我还没有找到读取所有模式文件的解决方案。

What I currently have is a multi-module maven project with the following structure: 我目前拥有的是一个具有以下结构的多模块Maven项目:

- parent
- | ear 
- | ejb3
- | resources

pom.xml for parent project 父项目的pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>mdv</groupId>
  <artifactId>json-parent</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>

  <modules>
    <module>json-ejb3</module>
    <module>json-ear</module>
    <module>json-resources</module>
  </modules>

  <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
</project>

pom.xml for ear project pom.xml用于耳朵项目

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>mdv</groupId>
        <artifactId>json-parent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>json-ear</artifactId>
    <packaging>ear</packaging>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>mdv</groupId>
            <artifactId>json-ejb3</artifactId>
            <version>${project.version}</version>
            <type>ejb</type>
        </dependency>
        <dependency>
            <groupId>mdv</groupId>
            <artifactId>json-resources</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-ear-plugin</artifactId>
                <version>3.0.1</version>
                <configuration>
                    <version>7</version>
                    <defaultLibBundleDir>lib</defaultLibBundleDir>
                    <earSourceDirectory>${basedir}/src/main/resources</earSourceDirectory>
                    <outputFileNameMapping>@{artifactId}@@{dashClassifier?}@.@{extension}@</outputFileNameMapping>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

pom.xml for resources project pom.xml资源项目

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>mdv</groupId>
        <artifactId>json-parent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>json-resources</artifactId>
</project>

pom.xml for ejb3 project ejb3项目的pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>mdv</groupId>
        <artifactId>json-parent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>json-ejb3</artifactId>
    <packaging>ejb</packaging>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-ejb-plugin</artifactId>
                <version>3.0.1</version>
                <configuration>
                    <ejbVersion>3.2</ejbVersion>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
        <!-- contains a json schema processing library and the class JsonSchemaValidatorEjb -->
            <groupId>mdv</groupId>
            <artifactId>json</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

The problem with loading schema files in EJB 在EJB中加载模式文件的问题

I want to load the schema files in an @ApplicationScoped bean for use in a Singleton EJB, the corresponding class is JsonSchemaValidatorService : 我想将架构文件加载到@ApplicationScoped bean中以用于Singleton EJB,相应的类是JsonSchemaValidatorService

package mdv;

import java.util.logging.Logger;

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.inject.Inject;

import json.ForEjbDeployment;
import json.IJsonSchemaValidator;

@Singleton
@Startup
public class JsonSchemaValidatorService {

    Logger log = Logger.getLogger("JsonSchemaValidatorService");

    @Inject
    @ForEjbDeployment
    IJsonSchemaValidator jsonSchemaValidator;
    // this is where json schema files should be loaded

    public JsonSchemaValidatorService() {
        //
    }

    @PostConstruct
    public void init() {
        log.info("Started JsonSchemaValidatorService.");
        log.info("Loaded schemas in jsonSchemaValidator: " + jsonSchemaValidator.getLoadedSchemas());
    }

}

The class for loading json schema files in EJB environment is this bean: 在EJB环境中加载json模式文件的类是以下bean:

package json;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.function.Consumer;
import java.util.logging.Logger;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.resource.spi.IllegalStateException;

import org.leadpony.justify.api.JsonSchema;

@ForEjbDeployment
@ApplicationScoped
public class JsonSchemaValidatorEjb extends JsonSchemaValidatorBase {

    Logger log = Logger.getLogger("JsonSchemaValidator");

    public JsonSchemaValidatorEjb() {
        //
    }

    @PostConstruct
    public void init() {
        try {
            // This is where I can't manage to get a list of the json schema files and process them
            final ClassLoader loader = Thread.currentThread().getContextClassLoader();
            try(
                    final InputStream is = loader.getResourceAsStream("schemas");
                    final InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
                    final BufferedReader br = new BufferedReader(isr)) {
                log.info("schema files in directory: ");
                br.lines().forEach(x -> log.info(x));
            }
        } catch (Exception e) {
            throw new RuntimeException("Error trying to parse schema files!", e);
        }
    }
}

No Exception is thrown but also no files will be found in the directory provided, eg "schemas". 没有抛出异常,但是在提供的目录中也找不到文件,例如“ schemas”。 The shortened output after EJB started is: EJB启动之后的缩短输出为:

[JsonSchemaValidatorService] Started JsonSchemaValidatorService.
[JsonSchemaValidator] schema files in directory: 
[JsonSchemaValidatorService] Loaded schemas in jsonSchemaValidator: {}

The file structure of the deployed ear is this: 部署的耳朵的文件结构是这样的:

- lib
| - icu4j.jar
| - javax.json-api.jar
| - javax.json.jar
| - json-resources.jar // jar with resources, in this case the schemas
| | - schemas
| | | - person.schema.json
| - json.jar // jar containing @ApplicationScoped beans for war und ejb
| - justify.jar // json schema processing library used
- META-INF
| - maven
| | ...
| - schemas
| | - person.schema.json
| - application.xml
| - MANIFEST.MF
- schemas
| -person.schema.json
- json-ejb3.jar

As you can see I have managed to bundle the schemas folder and the single json schema file in multiple locations, but none of this works. 如您所见,我设法将schemas文件夹和单个json模式文件捆绑在多个位置,但是这些都不起作用。

Is this even possible to achieve? 这甚至有可能实现吗? Am I wrong with the path specified at getResourceAsStream("schemas") ? 我在getResourceAsStream("schemas")指定的路径上错了吗?

The goal is to load all existing json schema files at startup to parse them to JsonSchema objects once to validate them later on (it will be a message-driven bean, by the way). 目标是在启动时加载所有现有的json模式文件,以将其解析为JsonSchema对象一次,以在以后进行验证(顺便说一下,它将是消息驱动的bean)。

Finally I found a nice solution that works both in Servlet and EJB context and eliminates the need for distinguishing between them. 最终,我找到了一个既可以在Servlet也可以在EJB上下文中工作的不错的解决方案,并且不需要区分它们。

Since I am not able to list the files inside the schemas folder from within an EJB but access and read single files I came up with the idea to use an auto-generated – at build time – file containing the list of all JSON schema files and using this to process the schemas 由于我无法从EJB内列出schemas文件夹内的文件,但是可以访问和读取单个文件,因此我想到了使用自动生成的(在构建时)文件的想法,该文件包含所有JSON模式文件和使用它来处理架构

Moving EJB to WAR deployment 将EJB迁移到WAR部署

First I followed the advice from @IllyaKysil and moved my EJB from an EAR deployment to the already existing and working WAR deployment 首先,我遵循@IllyaKysil的建议,将EJB从EAR部署迁移到已经存在且可以正常使用的WAR部署

Move schema files into JAR 将架构文件移入JAR

The original approach had the JSON schema files in both WAR and EAR deployments. 原始方法在WAR和EAR部署中都具有JSON模式文件。 I now have the files inside src/main/resources/schemas folder of the JAR project which I have a maven dependency on in the WAR project. 现在,我将文件保存在JAR项目的src/main/resources/schemas文件夹中,该文件在WAR项目中具有maven依赖性。 Result structure of archive is: 归档的结果结构为:

| jee7-test.war
| - WEB-INF
| | - lib
| | | - json-validator-0.0.1-SNAPSHOT.jar
| | | | - schemas
| | | | | - person.schema.json
| | | | | - schemaList.txt

Generate schemaList.txt at build 在生成时生成schemaList.txt

Using the maven antrun plugin a file is created in src/main/resources/schemas with each file in the schemas directory with an extension of .schema.json on a seperate line: 使用maven antrun插件在src/main/resources/schemas创建一个文件,每个文件都在schemas目录中,并以.schema.json扩展名单独出现:

<plugin>
   <artifactId>maven-antrun-plugin</artifactId>
   <version>1.8</version>
   <executions>
      <execution>
         <phase>generate-sources</phase>
         <configuration>
            <target>
               <fileset id="schemaFiles"
                  dir="src/main/resources/schemas/" includes="*.schema.json" />
               <pathconvert pathsep="${line.separator}"
                  property="schemaFileList" refid="schemaFiles">
                  <map from="${basedir}\src\main\resources\schemas\" to="" />
               </pathconvert>
               <echo
               file="${basedir}\src\main\resources\schemas\schemaList.txt">${schemaFileList}</echo>
            </target>
         </configuration>
         <goals>
            <goal>run</goal>
         </goals>
      </execution>
   </executions>
</plugin>

Content of generated file then is: 生成的文件的内容为:

person.schema.json

Reading schemaList.txt and parsing schemas 读取schemaList.txt并解析架构

Final step is reading the file with the list of JSON schema files and process each line to parse the corresponding schema file: 最后一步是读取包含JSON模式文件列表的文件,并处理每一行以解析相应的模式文件:

@ApplicationScoped
public class JsonSchemaValidator implements IJsonSchemaValidator {

    protected JsonValidationService jvs = JsonValidationService.newInstance();
    protected ConcurrentHashMap<String, JsonSchema> schemaMap = new ConcurrentHashMap<String, JsonSchema>();
    private Logger log = Logger.getLogger("JsonSchemaValidator");

    public JsonSchemaValidator() {
        //
    }

    private String SCHEMA_FOLDER = "schemas/";
    private String SCHEMA_LIST_FILE = "schemaList.txt";

    @PostConstruct
    public void init() {
        try {
            final ClassLoader loader = Thread.currentThread().getContextClassLoader();
            // load file containing list of JSON schema files
            try (final InputStream is = loader.getResourceAsStream(SCHEMA_FOLDER + SCHEMA_LIST_FILE);
                    final InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
                    final BufferedReader br = new BufferedReader(isr)) {
                // each line is a name of a JSON schema file that has to be processed
                br.lines().forEach(line -> readSchema(line, loader));
            }
            log.info("Number of JsonSchema objects in schemaMap: " + schemaMap.size());
            log.info("Keys in schemaMap: ");
            schemaMap.forEachKey(1L, key -> log.info(key));
        } catch (Exception e) {
            throw new RuntimeException("Error trying to parse schema files!", e);
        }
    }

    private void readSchema(String schemaFileName, ClassLoader classLoader) {
        // only use part of the file name to first dot, which leaves me with "person"
        // for "person.schema.json" file name
        String schemaName = schemaFileName.substring(0, schemaFileName.indexOf("."));
        JsonSchema js = jvs.readSchema(classLoader.getResourceAsStream(SCHEMA_FOLDER + schemaFileName));
        // put JsonSchema object in map with schema name as key
        schemaMap.put(schemaName, js);
        log.info("Schema " + schemaName + " added: " + js.toJson());
    }

    @Override
    public List<Problem> validate(String json, String schemaName) {
        List<Problem> result = new ArrayList<Problem>();
        JsonSchema jsonSchema = schemaMap.get(schemaName);
        JsonReader reader = jvs.createReader(new StringReader(json), jsonSchema, ProblemHandler.collectingTo(result));
        reader.read();

        return result;
    }

    @Override
    public Map<String, JsonSchema> getLoadedSchemas() {
        return Collections.unmodifiableMap(schemaMap);
    }
}

Result 结果

JSON strings from input can now be validated against a JSON schema without the need to parse the schema over and over again 现在可以针对JSON模式验证来自输入的JSON字符串,而无需一遍又一遍地解析该模式

@Inject
IJsonSchemaValidator jsv;
...
List<Problem> problems = jsv.validate(inputJson, "person");

Logged output after JsonSchemaValidator instance has been created: 创建JsonSchemaValidator实例后的日志输出:

Schema person added: {"$id":"....}
Number of JsonSchema objects in schemaMap: 1
Keys in schemaMap: 
person

The way to iterate over your schemas is answered in How to list the files inside a JAR file? 如何在JAR文件中列出文件?中提供了遍历模式的方法 .

Given that, there is no reason these resources cannot be in the same jar as your EJBs. 鉴于此,这些资源没有理由不能与EJB位于同一jar中。 They only need to be in a separate jar in the EAR/lib directory if you need to access them from other jars or WARs in the EAR. 如果您需要从EAR中的其他jar或WAR访问它们,则仅需要将它们放在EAR / lib目录中的单独jar中。

You do not need to be concerned with jboss-deployment-structure.xml unless you're doing something funky - which you are not. 除非您正在做一些时髦的事情,否则您无需关心jboss-deployment-structure.xml ,而实际上并非如此。

Also, you cannot read resources from inside the EAR itself, such as your ear/META-INF/schemas . 同样,您不能从EAR本身内部读取资源,例如您的ear/META-INF/schemas This counts as funky and you will still need the solution indicated above to iterate. 这算是时髦,您仍然需要上面指出的解决方案进行迭代。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM