46.3. 生成的组件子项目
概述
用于构建新组件的 Maven 子项目位于 camel-api-example/camel-api-example-component 项目目录下。在本节中,我们将详细介绍生成的示例代码,并描述它的工作原理。
在组件 POM 中提供 Java API
Java API 必须作为组件 POM 中的依赖项提供。例如,示例 Java API 定义为组件 POM 文件中的依赖项,camel-api-example-component/pom.xml,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
...
<dependencies>
...
<dependency>
<groupId>org.jboss.fuse.example</groupId>
<artifactId>camel-api-example-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
...
</dependencies>
...
</project>在组件 POM 中提供 Javadoc 元数据
如果您要将 Javadoc 元数据用于所有或部分 Java API,则必须提供 Javadoc 作为组件 POM 中的依赖项。关于这个依赖项需要注意两个方面:
Javadoc 的 Maven 协调几乎与 Java API 相同,但还必须指定
classifier元素,如下所示:<classifier>javadoc</classifier>
您必须声明 Javadoc 以具有
提供的范围,如下所示:<scope>provided</scope>
例如,在组件 POM 中,Javadoc 依赖项定义如下:
<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
...
<dependencies>
...
<!-- Component API javadoc in provided scope to read API signatures -->
<dependency>
<groupId>org.jboss.fuse.example</groupId>
<artifactId>camel-api-example-api</artifactId>
<version>1.0-SNAPSHOT</version>
<classifier>javadoc</classifier>
<scope>provided</scope>
</dependency>
...
</dependencies>
...
</project>定义 Example 文件 Hello 的文件元数据。
ExampleFileHello 的元数据在签名文件中提供。通常,必须手动创建此文件,但它具有非常简单的格式,它由方法签名列表(每行一个)组成。示例代码在目录中提供了签名文件 file-sig-api.txt,在目录中提供 camel-api-example-component/signatures,其中包含以下内容:
public String sayHi(); public String greetMe(String name); public String greetUs(String name1, String name2);
有关签名文件格式的详情,请参考 “签名文件元数据”一节。
配置 API 映射
API 组件框架的主要功能之一是它自动生成代码来执行 API 映射。也就是说,生成 stub 代码,将端点 URI 映射到 Java API 上的方法调用。API 映射的基本输入有:Java API、Javadoc 元数据和/或签名文件元数据。
执行 API 映射的组件是 camel-api-component-maven-plugin Maven 插件,该插件在组件 POM 中配置。以下从组件 POM 中提取显示 camel-api-component-maven-plugin 插件的配置方式:
<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
...
<build>
<defaultGoal>install</defaultGoal>
<plugins>
...
<!-- generate Component source and test source -->
<plugin>
<groupId>org.apache.camel</groupId>
<artifactId>camel-api-component-maven-plugin</artifactId>
<executions>
<execution>
<id>generate-test-component-classes</id>
<goals>
<goal>fromApis</goal>
</goals>
<configuration>
<apis>
<api>
<apiName>hello-file</apiName>
<proxyClass>org.jboss.fuse.example.api.ExampleFileHello</proxyClass>
<fromSignatureFile>signatures/file-sig-api.txt</fromSignatureFile>
</api>
<api>
<apiName>hello-javadoc</apiName>
<proxyClass>org.jboss.fuse.example.api.ExampleJavadocHello</proxyClass>
<fromJavadoc/>
</api>
</apis>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
...
</build>
...
</project>
该插件由 configuration 元素配置,它包含单个 apis 子元素来配置 Java API 的类。每个 API 类都由 api 元素配置,如下所示:
apiNameAPI 名称是 API 类的短名称,用作端点 URI 的
endpoint-prefix部分。注意如果 API 仅包含单个 Java 类,您可以将
apiName元素留空,以便endpoint-prefix变得冗余,您可以使用 “单个 API 类的 URI 格式”一节 中显示的格式指定端点 URI。proxyClass- proxy class 元素指定 API 类的完全限定域名。
fromJavadoc-
如果 API 类附带 Javadoc 元数据,则必须通过将
fromJavadoc元素和 Javadoc 本身包含在 Maven 文件中指定,作为提供的依赖项(请参阅 “在组件 POM 中提供 Javadoc 元数据”一节)。 fromSignatureFile如果 API 类由签名文件元数据附带,您必须通过包含
fromSignatureFile元素来指示这一点,其中此元素的内容指定签名文件的位置。注意签名文件不会包含在 Maven 构建的最终软件包中,因为这些文件仅在构建时需要,而不需要在运行时。
生成的组件实现
API 组件由以下核心类组成(必须为每个 Camel 组件实施),在 camel-api-example-component/src/main/java 目录下:
ExampleComponent-
代表组件本身。此类充当端点实例的工厂(例如,
ExampleEndpoint的实例)。 ExampleEndpoint-
代表端点 URI。此类充当消费者端点的工厂(例如,
ExampleConsumer)和 producer 端点的工厂(如ExampleProducer)。 ExampleConsumer- 代表消费者端点的一个集合实例,它能够消耗来自端点 URI 中指定的位置的消息。
ExampleProducer- 代表制作者端点的一个集合实例,它能够发送消息到端点 URI 中指定的位置。
ExampleConfiguration可用于定义端点 URI 选项。此配置类定义的 URI 选项 不与任何 特定的 API 类关联。也就是说,您可以将这些 URI 选项与任何 API 类或方法组合。例如,这非常有用,例如,如果您需要声明用户名和密码凭证才能连接到远程服务。
ExampleConfiguration类的主要目的是为实例化 API 类或实施 API 接口的类所需的参数提供值。例如,它们可以是 constructor 参数,也可以是 factory 方法或类的参数值。要实现 URI 选项(在此类中),您需要做的所有操作都是实施访问者方法对,
获得选项和设置。组件框架自动解析端点 URI,并在运行时注入选项值。
ExampleComponent 类
生成的 ExampleComponent 类定义如下:
// Java
package org.jboss.fuse.example;
import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.util.component.AbstractApiComponent;
import org.jboss.fuse.example.internal.ExampleApiCollection;
import org.jboss.fuse.example.internal.ExampleApiName;
/**
* Represents the component that manages {@link ExampleEndpoint}.
*/
@UriEndpoint(scheme = "example", consumerClass = ExampleConsumer.class, consumerPrefix = "consumer")
public class ExampleComponent extends AbstractApiComponent<ExampleApiName, ExampleConfiguration, ExampleApiCollection> {
public ExampleComponent() {
super(ExampleEndpoint.class, ExampleApiName.class, ExampleApiCollection.getCollection());
}
public ExampleComponent(CamelContext context) {
super(context, ExampleEndpoint.class, ExampleApiName.class, ExampleApiCollection.getCollection());
}
@Override
protected ExampleApiName getApiName(String apiNameStr) throws IllegalArgumentException {
return ExampleApiName.fromValue(apiNameStr);
}
@Override
protected Endpoint createEndpoint(String uri, String methodName, ExampleApiName apiName,
ExampleConfiguration endpointConfiguration) {
return new ExampleEndpoint(uri, this, apiName, methodName, endpointConfiguration);
}
}
此类中的重要方法是 createEndpoint,它会创建新的端点实例。通常,您不需要更改组件类中的任何默认代码。但是,如果存在与这个组件相同的生命周期的其他对象,您可能需要从组件类提供这些对象(例如,通过添加方法来创建这些对象或将这些对象注入组件)。
ExampleEndpoint 类
生成的 ExampleEndpoint 类定义如下:
// Java
package org.jboss.fuse.example;
import java.util.Map;
import org.apache.camel.Consumer;
import org.apache.camel.Processor;
import org.apache.camel.Producer;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.util.component.AbstractApiEndpoint;
import org.apache.camel.util.component.ApiMethod;
import org.apache.camel.util.component.ApiMethodPropertiesHelper;
import org.jboss.fuse.example.api.ExampleFileHello;
import org.jboss.fuse.example.api.ExampleJavadocHello;
import org.jboss.fuse.example.internal.ExampleApiCollection;
import org.jboss.fuse.example.internal.ExampleApiName;
import org.jboss.fuse.example.internal.ExampleConstants;
import org.jboss.fuse.example.internal.ExamplePropertiesHelper;
/**
* Represents a Example endpoint.
*/
@UriEndpoint(scheme = "example", consumerClass = ExampleConsumer.class, consumerPrefix = "consumer")
public class ExampleEndpoint extends AbstractApiEndpoint<ExampleApiName, ExampleConfiguration> {
// TODO create and manage API proxy
private Object apiProxy;
public ExampleEndpoint(String uri, ExampleComponent component,
ExampleApiName apiName, String methodName, ExampleConfiguration endpointConfiguration) {
super(uri, component, apiName, methodName, ExampleApiCollection.getCollection().getHelper(apiName), endpointConfiguration);
}
public Producer createProducer() throws Exception {
return new ExampleProducer(this);
}
public Consumer createConsumer(Processor processor) throws Exception {
// make sure inBody is not set for consumers
if (inBody != null) {
throw new IllegalArgumentException("Option inBody is not supported for consumer endpoint");
}
final ExampleConsumer consumer = new ExampleConsumer(this, processor);
// also set consumer.* properties
configureConsumer(consumer);
return consumer;
}
@Override
protected ApiMethodPropertiesHelper<ExampleConfiguration> getPropertiesHelper() {
return ExamplePropertiesHelper.getHelper();
}
protected String getThreadProfileName() {
return ExampleConstants.THREAD_PROFILE_NAME;
}
@Override
protected void afterConfigureProperties() {
// TODO create API proxy, set connection properties, etc.
switch (apiName) {
case HELLO_FILE:
apiProxy = new ExampleFileHello();
break;
case HELLO_JAVADOC:
apiProxy = new ExampleJavadocHello();
break;
default:
throw new IllegalArgumentException("Invalid API name " + apiName);
}
}
@Override
public Object getApiProxy(ApiMethod method, Map<String, Object> args) {
return apiProxy;
}
}
在 API 组件框架的上下文中,端点类执行的关键步骤之一是创建 API 代理。API 代理是目标 Java API 的一个实例,其方法由端点调用。由于 Java API 通常由多个类组成,因此根据 URI 中显示的 端点前缀(调用 URI,使用常规形式 ://端点)来选择适当的 API 类。
ExampleConsumer 类
生成的 ExampleConsumer 类定义如下:
// Java
package org.jboss.fuse.example;
import org.apache.camel.Processor;
import org.apache.camel.util.component.AbstractApiConsumer;
import org.jboss.fuse.example.internal.ExampleApiName;
/**
* The Example consumer.
*/
public class ExampleConsumer extends AbstractApiConsumer<ExampleApiName, ExampleConfiguration> {
public ExampleConsumer(ExampleEndpoint endpoint, Processor processor) {
super(endpoint, processor);
}
}ExampleProducer 类
生成的 ExampleProducer 类定义如下:
// Java
package org.jboss.fuse.example;
import org.apache.camel.util.component.AbstractApiProducer;
import org.jboss.fuse.example.internal.ExampleApiName;
import org.jboss.fuse.example.internal.ExamplePropertiesHelper;
/**
* The Example producer.
*/
public class ExampleProducer extends AbstractApiProducer<ExampleApiName, ExampleConfiguration> {
public ExampleProducer(ExampleEndpoint endpoint) {
super(endpoint, ExamplePropertiesHelper.getHelper());
}
}ExampleConfiguration 类
生成的 ExampleConfiguration 类定义如下:
// Java
package org.jboss.fuse.example;
import org.apache.camel.spi.UriParams;
/**
* Component configuration for Example component.
*/
@UriParams
public class ExampleConfiguration {
// TODO add component configuration properties
}
要向此类中添加 URI 选项 (选项 ),定义相应类型的字段,并实施对应的访问者方法对,获取选项 和设置Option。组件框架自动解析端点 URI,并在运行时注入选项值。
此类用于定义 常规 URI 选项,可与任何 API 方法结合使用。要定义与特定 API 方法相关联的 URI 选项,请在 API 组件 Maven 插件中配置额外的选项。详情请查看 第 47.7 节 “额外选项”。
URI 格式
回想到 API 组件 URI 的一般格式:
scheme://endpoint-prefix/endpoint?Option1=Value1&...&OptionN=ValueN
通常,URI 映射到 Java API 上的特定方法调用。例如,假设您想调用 API 方法,例如 JavadocHello.greetMe ("Jane Doe"),将构建 URI,如下所示:
- scheme
-
API 组件方案,如您使用 Maven archetype 生成代码时指定。在这种情况下,方案是
。 - endpoint-prefix
API 名称,它映射到
camel-api-component-maven-pluginMaven 插件配置定义的 API 类。对于ExampleJavadocHello类,相关配置是:<configuration> <apis> <api> <apiName>hello-javadoc</apiName> <proxyClass>org.jboss.fuse.example.api.ExampleJavadocHello</proxyClass> <fromJavadoc/> </api> ... </apis> </configuration>显示所需的
endpoint-prefix是hello-javadoc。- 端点
-
端点映射到方法名称,即greetMe。 - Option1=Value1
-
URI 选项指定方法参数。
greetMe (String name)方法采用单个参数,名称,它可以指定为name=Jane%20Doe。如果要为选项定义默认值,可以通过覆盖interceptProperties方法进行此操作(请参阅 第 46.4 节 “编程模型”)。
将 URI 放入一起,我们看到我们可以使用以下 URI 调用 ExampleJavadocHello.greetMe ("Jane Doe") :
example://hello-javadoc/greetMe?name=Jane%20Doe
默认组件实例
要将 示例 URI 方案映射到默认组件实例,Maven archetype 在 camel-api-example-component 子项目下创建以下文件:
src/main/resources/META-INF/services/org/apache/camel/component/example
这个资源文件可让 Camel 内核识别与 示例 URI 方案关联的组件。每当您在路由中使用 example:// URI 时,Camel 会搜索 classpath 来查找对应的 示例 资源文件。示例文件 包含以下内容:
class=org.jboss.fuse.example.ExampleComponent
这可让 Camel 内核创建 ExampleComponent 组件的默认实例。如果您重构组件类的名称,您只需要编辑此文件的唯一时间。