将 Cloudinary 与 Adob​​e AEM 集成

Posted

技术标签:

【中文标题】将 Cloudinary 与 Adob​​e AEM 集成【英文标题】:Integrating Cloudinary with Adobe AEM 【发布时间】:2020-04-26 12:45:27 【问题描述】:

我正在尝试将 Adob​​e AEM 6.3(在 Java 1.8 上运行)与 Cloudinary SDK 集成。我已经完成了以下操作,但是一直遇到我无法解决的异常。有没有人将 Cloudinary 与 AEM 集成并遇到类似问题?

    pom.xml 中添加依赖,用于编译代码。
<dependency>
  <groupId>com.cloudinary</groupId>
  <artifactId>cloudinary-core</artifactId>
  <version>1.24.0</version>  
</dependency>  
<dependency>
  <groupId>com.cloudinary</groupId>
  <artifactId>cloudinary-http44</artifactId>
  <version>1.24.0</version>         
</dependency>

    构建 OSGI 插件以确保 AEM 获取正确的 jar 文件。为此,我按照create a third party RESTful service example 的步骤进行操作。要构建捆绑包,我必须明确下载以下 jar 文件:cloudinary-1.0.14.jar, cloudinary-core-1.21.0.jar, cloudinary-http44-1.21.0.jar, commons-codec-1.10.jar, commons-collections-3.2.2.jar, commons-lang3-3.1.jar, commons-logging-1.2.jar, httpclient-4.4.jar, httpmime-4.4.jar, jsp-api-2.0.jar

    尽管创建了一个包含 httpclient 的包,但在尝试将图像上传到 Cloudinary 时出现以下异常。这是代码和异常。

代码 sn-p

import com.cloudinary.*;
..
Cloudinary cloudinary = new Cloudinary("<<credentials>>");
...

File toUpload = new File("/Users/akshayranganath/Downloads/background-2633962_1280.jpg");

try 
  Map uploadResult = cloudinary.uploader().upload(toUpload, ObjectUtils.emptyMap());
 catch (IOException e) 
  // TODO Auto-generated catch block
  e.printStackTrace();

异常

Caused by: java.lang.NoClassDefFoundError: javax/net/ssl/HostnameVerifier
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
    at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.defineClass(BundleWiringImpl.java:2370)
    at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.findClass(BundleWiringImpl.java:2154)
    at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1542)
    at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:79)
    at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:2018)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
    at org.apache.http.impl.conn.SchemeRegistryFactory.createDefault(SchemeRegistryFactory.java:52)
    at org.apache.http.impl.client.AbstractHttpClient.createClientConnectionManager(AbstractHttpClient.java:321)
    at org.apache.http.impl.client.AbstractHttpClient.getConnectionManager(AbstractHttpClient.java:484)
    at org.apache.http.impl.client.AbstractHttpClient.createHttpContext(AbstractHttpClient.java:301)
    at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:818)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
    at com.cloudinary.Uploader.callApi(Uploader.java:317)
    at com.cloudinary.Uploader.upload(Uploader.java:57)
    at com.aem.community.core.models.HelloWorldModel.init(HelloWorldModel.java:59)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.sling.models.impl.ModelAdapterFactory.invokePostConstruct(ModelAdapterFactory.java:792)
    at org.apache.sling.models.impl.ModelAdapterFactory.createObject(ModelAdapterFactory.java:607)
    ... 211 common frames omitted
Caused by: java.lang.ClassNotFoundException: javax.net.ssl.HostnameVerifier not found by MyBundle [550]
    at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1574)
    at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:79)
    at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:2018)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
    ... 236 common frames omitted

这是我第一次使用 AEM,我可能没有遵循正确的步骤。请让我知道是否有人能够解决此问题。

更新

根据 Alexander 的建议和来自另一个来源的指针,我将以下代码添加到父 pom.xml 文件中。

<plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <version>3.5.0</version>
    <configuration>
        <instructions>
        <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
        <Embed-Directory>OSGI-INF/lib</Embed-Directory>
        <Embed-Transitive>true</Embed-Transitive>
        </instructions>
    </configuration>
</plugin>

进行此更改后,cloudinary 库被添加到包中。这是 AEM 的输出:http://localhost:4502/system/console/bundles

Embedded-Artifacts: OSGI-INF/lib/cloudinary-http44-1.21.0.jar; g="com.cloudinary"; a="cloudinary-http44"; v="1.21.0", OSGI-INF/lib/commons-lang3-3.1.jar; g="org.apache.commons"; a="commons-lang3"; v="3.1", OSGI-INF/lib/httpclient-4.4.jar; g="org.apache.httpcomponents"; a="httpclient"; v="4.4", OSGI-INF/lib/httpcore-4.4.jar; g="org.apache.httpcomponents"; a="httpcore"; v="4.4", OSGI-INF/lib/commons-logging-1.2.jar; g="commons-logging"; a="commons-logging"; v="1.2", OSGI-INF/lib/commons-codec-1.9.jar; g="commons-codec"; a="commons-codec"; v="1.9", OSGI-INF/lib/httpmime-4.4.jar; g="org.apache.httpcomponents"; a="httpmime"; v="4.4", OSGI-INF/lib/cloudinary-core-1.21.0.jar; g="com.cloudinary"; a="cloudinary-core"; v="1.21.0"

但是,我现在收到一条错误消息:

org.apache.avalon.framework.logger -- Cannot be resolved
org.apache.log -- Cannot be resolved

我可以通过添加依赖项Avalon framework 来解决org.apache.avalon.framework.logger 错误。但是,我无法克服org.apache.log 问题。似乎是版本冲突导致了问题。

当我包含Cloudinary http44 library 时,这个新错误就开始了。这个库似乎没有直接引用日志记录(有关依赖关系,请参阅here)。由于这个错误,应用程序仍然无法从 Installed 进入 Active 状态。

【问题讨论】:

Cloudinary 已经作为 OSGi 包提供。链接文档应该是您完全手动创建 OSGi 包的最后手段。查看maven-bundle-pluginEmbed-Dependency 指令。这应该解决所有依赖项。但无论如何,这个问题是 OSGi 专家的问题 - 并且可能仍然是一项繁琐的任务。祝你好运。 谢谢你,亚历山大。在哪里可以找到 Cloudinary OSGi 捆绑包? Cloudinary SDK jar 文件似乎不是所需的 OSGI 格式。 对不起,这是我的错。我的意思是它是一个 Maven 神器。您可以将此类 jar 文件嵌入到您自己的包中,而无需将其作为全局 OSGi 包公开。您可以使用Embed-Dependency 来做到这一点。因此,您只需要 pom.xml 中的依赖项和嵌入指令 - 而不是下载 jar 文件并手动创建包。我明天尝试为您创建一个工作示例 pom.xml 作为答案。 谢谢你,亚历山大。我按照您的建议进行了更改并解决了问题的一部分。但是,现在似乎还有另一个错误,我已经用附加信息更新了原始问题。 对于记录器依赖问题,从 .m2 文件夹中删除两者,然后重试。 【参考方案1】:

Cloudinary-libs 可作为 Maven 工件使用。此类 JAR 文件可以作为私有库与 ma​​ven-bundle-plugin 一起放入您的包中。

以下示例适用于我(即使使用 Cloudinary 测试帐户)

...
<plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <extensions>true</extensions>
    <executions>
        <execution>
            <!-- Create the bundle late in the compile-phase instead of the package-phase.
                 So the generated OSGi meta-data is available during JUnit tests. -->
            <id>run-before-tests</id>
            <phase>process-classes</phase>
            <goals>
                <goal>bundle</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <instructions>
            <Bundle-Name>Test Bundle</Bundle-Name>
            <Embed-Dependency>*;groupId=com.cloudinary;scope=compile|runtime</Embed-Dependency>
            <Embed-Directory>OSGI-INF/lib</Embed-Directory> <!-- not needed, but nice -->
            <Embed-Transitive>true</Embed-Transitive>
        </instructions>
    </configuration>
</plugin>
...

<dependencies>
    <dependency>
        <groupId>com.cloudinary</groupId>
        <artifactId>cloudinary-core</artifactId>
        <version>1.24.0</version>
    </dependency>
    <dependency>
        <groupId>com.cloudinary</groupId>
        <artifactId>cloudinary-http44</artifactId>
        <version>1.24.0</version>
    </dependency>
    ...

一般来说,嵌入一个外部库可以是简单、繁琐甚至是不可能的。这取决于导入的工件的依赖关系。

手动检查依赖树!(例如https://mvnrepository.com/)

你必须摆弄 3 条指令:

嵌入依赖

这是放在你的包中的库。小心使用星号运算符,否则您可能会包含太多依赖项(如果 AEM 很容易占据互联网的一半)。但不要包含的太少!提取构建的 bundle.jar,查看实际包含的内容(如果是 cloudinary,这很容易)。

导入包

通常这些库有太多的依赖关系,特别是如果库来自其他生态系统(如 Spring 或 JEE 容器),或者有很多半可选的依赖项。使用此设置,您可以告诉 OSGi,即使某些依赖项不可用,也可以激活捆绑包。

这是一个真实的例子:

<Import-Package>
    !com.sun.msv.*,
    !org.apache.log4j.jmx.*,
    !sun.misc.*,
    !org.jboss.logging.*,
    !org.apache.zookeeper.*,
    *
</Import-Package>

导出包

通常,库应该是捆绑私有的。但有时你必须以不同的方式导入,或者 lib 会自动执行某些操作。因此,您应该始终在系统控制台中检查您的捆绑包正在导出的内容。如果不正确,您必须手动修改此设置:

这是一个例子:

<Export-Package>
    !*.internal,
    !*.internal.*,
    !*.impl,
    !*.impl.*,
    com.mycompany.myproject.mybundle.*
</Export-Package>

默认情况下,所有包* 都会被导出,除了它们被命名为implinternal。他们的子包也是私有的(!*.impl.* 规则)。如果默认值不起作用,则使用此指令仅导出您需要的内容。

无论您导出什么,都会进入全球 OSGi 空间。此外,AEM 和 Sling-Bundle 并不完美,也不是 100% 没有错误,请确保

不应更改开箱即用 AEM 捆绑包的启动/关闭顺序 代码的部署、重新部署或取消部署不应启动/停止任何开箱即用的 AEM 捆绑包。

如果您不确保这一点,您可能会遇到奇怪的部署问题 - 很难找到/解决。

因此,最好不要导出任何 AEM 开箱即用捆绑包导入的任何内容。其他一切仅供专家使用。甚至他们也高估了自己,低估了手动修补 AEM 的长期成本。

PS:_removeheaders 指令可以删除所有运行时不需要的 osgi 指令。但只有这样做,如果你想向公众提供一个捆绑包并让它完全闪亮。我会把它留在里面,因为它是某种文档。

【讨论】:

以上是关于将 Cloudinary 与 Adob​​e AEM 集成的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式读取 Adob​​e 游戏变量/与游戏/游戏机器人交互

如何导出与 Flash Player 8 兼容的 Adob​​e Flash cc 文件?

在 Adob​​e 和浏览器都将结束 Adob​​e Flash 之后,有啥方法可以运行 Web 应用程序

在 HTML5 画布模式下使用带有外部 JavaScript 文件的 Adob​​e Animate CC

将 Flex 转换为 Adob​​e Air

使用 axios 直接将图片上传到 cloudinary