[英]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- EJB的EAR +包含模式文件的资源JAR (我已经阅读了打包资源仅当将它们捆绑在EAR内部的单独JAR中时,才可以在EJB中使用这些文件。
Development environment is eclipse 2019-03 with JBoss Wildfly 16. JBoss Wildfly 16的开发环境将在2019-03月出现。
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”:...
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
<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>
<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>
<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>
<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>
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模式文件和使用它来处理架构
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部署
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
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
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);
}
}
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.