Osgi 将JavaMail 1.5与XPages一起使用

Osgi 将JavaMail 1.5与XPages一起使用,osgi,xpages,jakarta-mail,Osgi,Xpages,Jakarta Mail,我有一个XPage应用程序,可以通过IMAP(和SSL)读取来自GMail的邮件,并将它们存储在nsf数据库中 为此,我需要JavaMail 1.5 在阅读了一些帖子后,我得出结论,我必须构建自己的OSGI插件。 继John Dalsgaard关于的博客之后,我能够将JavaMail 1.5 jar文件包装到OSGI插件中。该插件导出所有JavaMail包,以便我可以在XPage应用程序中使用它们 在我的XPage中,有一些java代码试图建立到GMail的连接。但是连接总是超时,所以我打开了j

我有一个XPage应用程序,可以通过IMAP(和SSL)读取来自GMail的邮件,并将它们存储在nsf数据库中

为此,我需要JavaMail 1.5

在阅读了一些帖子后,我得出结论,我必须构建自己的OSGI插件。 继John Dalsgaard关于的博客之后,我能够将JavaMail 1.5 jar文件包装到OSGI插件中。该插件导出所有JavaMail包,以便我可以在XPage应用程序中使用它们

在我的XPage中,有一些java代码试图建立到GMail的连接。但是连接总是超时,所以我打开了javamail的调试选项。调试表明我的java代码仍然使用javamail 1.3(domino服务器提供的版本)

因此,我将java代码移到了OSGI插件中,并导出了该包,这样我仍然可以在XPage中使用它。打开debug for javamail显示了正确的版本1.5。但是现在我得到了异常
javax.mail.NoSuchProviderException
,不管我是使用
imap
还是
imaps
作为协议


我错过了什么?为什么我不能在osgi插件中使用javamail 1.5 jar文件?

我在maven central中找到了这个jar:


它似乎是一个有效的OSGi包。也许这会有所帮助?

javax.mail的代码并不真正对OSGi友好。它使用线程上下文类加载器查找实例化实现

您可以通过以下方式对此进行欺骗:

  • 将javax.mail和com.sun.mail.imap安装到OSGi容器中。版本1.5.2具有OSGi清单头,因此应该可以工作
  • 调用javax.mail api中加载提供程序的函数时,请将线程上下文类加载器设置为肯定知道imap类的类加载器
例如:

请注意,我没有对此进行测试,但解决方案应该类似。您可能需要在try块中放入更多javax.mail命令(例如获取会话)

不那么难看的解决方案

一个不那么难看的解决方案是跳过javax.mailapi的使用,直接使用imap类

例如:

在JavaEE中使用SPI或类似解决方案时,通常可以通过跳过工厂机制(使用线程上下文类加载器和其他技巧)并直接实例化实现类来实现相同的功能

更新

commant中规定有一个例外:

com.sun.mail.handlers.multipart_mixed incompatible with javax.activation.DataContentHandler
原因似乎是javax.activation.*包在OSGi容器中有两次可用。它来自JDK,也来自其中一个捆绑包。问题与此类似,原因也来自重复的软件包

然而,真正的原因是再次使用线程上下文类加载器。如果查看引发异常的源代码,您将看到线程上下文类加载器用于加载该类。这是一个问题,因为我猜TCC是系统类加载器,而javax.mail是连接到javax.activation包的

我现在可以想象以下选项:

  • 删除javax.activation包。这可能会解决问题,因为在这种情况下,每个捆绑包都会连接到系统包。但是,您仍然可以在以后获取ClassNotFoundExceptions。。。与类加载器错误实践作斗争:)
  • 从系统包中删除javax.activation。在这种情况下,每个人都将连接到捆绑包。然而,同样的问题也可能发生,javax.activation bundle(或TCC)无法看到应该加载的类
  • 在stacktrace中找到一个可以更改TCC的点,并设置一个可以查看所有必需类的类加载器。这也是单核技术的常见技巧(如在原始示例中,但现在用于此函数调用)
  • 找到一种具有这些特性但对OSGi更友好的技术。如果你能找到,请把它贴在这里:)

您真的需要Java 1.5.2邮件吗?我不这么认为。你需要的是代码和代码。简言之:

/** ========================================================================= *
 * Copyright (C) 2014 Stephan H. Wissel                                       *
 *                                                                            *
 *  @author     Stephan H. Wissel <stephan@wissel.net>                        *  
 *                                                                            *
 * @version     0.1                                                           *
 * ========================================================================== *
 *                                                                            *
 * 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 com.notessensei.gimap;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import javax.mail.Address;
import javax.mail.FetchProfile;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;

import lotus.domino.Database;
import lotus.domino.Document;
import lotus.domino.Item;
import lotus.domino.NotesException;
import lotus.domino.NotesFactory;
import lotus.domino.NotesThread;

import com.sun.mail.gimap.GmailFolder;
import com.sun.mail.gimap.GmailMessage;
import com.sun.mail.gimap.GmailSSLStore;

public class GMail2Notes {

    public static int   MAX_TEST_COUNT  = 50;

    public static void main(String[] args) throws NotesException, MessagingException {

        if (args.length < 3) {
            System.out.println("GMail2Notes username@gmail.com password nsfFileName");
            System.exit(1);
        }

        System.out.println("Starting for " + args[0] + " to " + args[2]);
        NotesThread.sinitThread();
        lotus.domino.Session s = NotesFactory.createSession();
        Database db = s.getDatabase("", args[2]);
        GMail2Notes g2n = new GMail2Notes(args[0], args[1]);
        g2n.addExcludedLabel("Spam");
        g2n.addExcludedLabel("Trash");
        int resultCount = g2n.importMessages(s, db, "All Mail");
        System.out.print("Messages imported:");
        System.out.println(resultCount);
        NotesThread.stermThread();
        System.out.println("Done");
    }

    private final String        userName;
    private final String        passWord;
    private GmailSSLStore       store           = null;
    // set it to false for complete import
    private boolean             isTestMode      = true;

    // Labels we don not want to import
    private final List<String>    excludedLabels  = new ArrayList<String>();

    public GMail2Notes(String usr, String pwd) {
        this.userName = usr;
        this.passWord = pwd;
    }

    /**
     * Add a folder name to the list we are not interested in
     *
     * @param label
     */
    public void addExcludedLabel(String label) {
        this.excludedLabels.add(label);
    }

    public List<String> getSystemFolderNames() throws MessagingException {
        List<String> result = new ArrayList<String>();
        GmailSSLStore store = this.getStore();
        Folder[] folders = store.getFolder("[Gmail]").list();
        for (Folder f : folders) {
            result.add(f.getName());
        }
        return result;
    }

    public int importMessages(lotus.domino.Session s, Database db, String systemFolderName) throws MessagingException {
        int result = 0;

        // The object to move message to
        Mime2Doc md = new Mime2Doc();

        // Getting gMail ready
        GmailFolder f = this.getSystemFolder(systemFolderName);
        f.open(Folder.READ_ONLY);
        Message[] messages = f.getMessages();
        FetchProfile profile = new FetchProfile();
        profile.add(GmailFolder.FetchProfileItem.CONTENT_INFO);
        profile.add(GmailFolder.FetchProfileItem.LABELS);
        profile.add(GmailFolder.FetchProfileItem.MSGID);
        profile.add(GmailFolder.FetchProfileItem.SIZE);

        f.fetch(messages, profile);
        int count = 0;
        for (Message message : messages) {
            result += this.importOneMessage(s, db, md, message);

            // For testing we don't run through all of them
            count++;
            if (this.isTestMode && count >= MAX_TEST_COUNT) {
                break;
            }
        }
        if (f.isOpen()) {
            f.close(false);
        }
        this.cleanup();
        System.out.println("Done");

        return result;
    }

    /**
     * We need a delivered date so documents don't show up in SEND
     *
     * @param doc
     * @param sender
     */
    private void adjustDeliveredDate(Document doc, Address sender) {
        String senderName = sender.toString();
        if (!senderName.equalsIgnoreCase((this.userName))) {
            try {
                Item PostedDate = doc.getFirstItem("PostedDate");
                doc.copyItem(PostedDate, "DeliveredDate");
                doc.save();
                PostedDate.recycle();
            } catch (NotesException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * Strips leading \ from messages
     *
     * @param rawLabel
     * @return label Stripped from Backslash
     */
    private String cleanLabel(String rawLabel) {
        return (rawLabel.startsWith("\\") ? rawLabel.substring(1) : rawLabel).trim();
    }

    private void cleanup() {
        if (this.store != null && this.store.isConnected()) {
            try {
                this.store.close();
            } catch (MessagingException e) {
                e.printStackTrace();
            }
        }
        this.store = null;
    }

    private GmailSSLStore getStore() throws MessagingException {
        if (this.store != null) {
            return this.store;
        }
        Properties props = System.getProperties();
        props.setProperty("mail.imaps.connectiontimeout", "5000");
        props.setProperty("mail.imaps.host", "imap.gmail.com");
        props.setProperty("mail.imaps.partialfetch", "false");
        props.setProperty("mail.imaps.port", "993");
        props.setProperty("mail.imaps.timeout", "5000");
        props.setProperty("mail.mime.base64.ignoreerrors", "true");
        props.setProperty("mail.store.protocol", "gimaps");

        Session session = Session.getDefaultInstance(props, null);
        this.store = (GmailSSLStore) session.getStore("gimaps");
        this.store.connect(this.userName, this.passWord);
        // Ready for connection
        return this.store;
    }

    /**
    * can be: All Mail, Drafts, Important, Sent Mail, Spam, Starred, Trash
    **/
    private GmailFolder getSystemFolder(String folderName) throws MessagingException {
        GmailSSLStore store = this.getStore();
        Folder folder = store.getFolder("[Gmail]").getFolder(folderName);
        return (GmailFolder) folder;

    }

    private int importOneMessage(lotus.domino.Session s, Database db, Mime2Doc md, Message message) {
        int result = 0;
        try {
            GmailMessage g = (GmailMessage) message;
            Address sender = g.getSender();
            String[] labels = g.getLabels();
            System.out.print(g.getMessageID());
            if (labels != null) {
                System.out.print(", ");
                System.out.print(Arrays.toString(labels));
            }

            if (this.processThisMessage(labels)) {
                result = 1;
                Document doc = db.createDocument();
                InputStream in = g.getMimeStream();
                md.importMail(s, in, doc);
                this.moveDocToFolders(doc, labels);
                this.adjustDeliveredDate(doc, sender);
                System.out.println(" - processed");
            } else {
                System.out.println(" - skipped");
            }
        } catch (Exception e) {
            // TODO: record the message for follow-up
            e.printStackTrace();
        }
        return result;
    }

    /**
     * Moves doc to folders as needed
     *
     * @param doc
     * @param labels
     */
    private void moveDocToFolders(Document doc, String[] labels) {
        if (labels != null) {
            for (String label : labels) {
                this.movetoMatchingFolder(doc, label);
            }
        }
    }

    private void movetoMatchingFolder(Document doc, String folderCandidate) {
        // TODO handle the SENT folder, Draft folder
        if (folderCandidate != null && !folderCandidate.trim().equals("")) {
            try {
                String realFolder = this.cleanLabel(folderCandidate);
                if (realFolder.equalsIgnoreCase("inbox")) {
                    doc.putInFolder("($Inbox)");
                } else if (realFolder.equalsIgnoreCase("drafts")) {
                    // TODO handle Drafts
                } else if (realFolder.equalsIgnoreCase("sent")) {
                    // TODO handle SENT
                } else {
                    doc.putInFolder(realFolder, true);
                }
            } catch (NotesException e) {
                e.printStackTrace();
            }
        }
    }

    private boolean processThisMessage(String[] messageLabels) {
        boolean result = true;

        // If the message has no labels we do process it
        if (messageLabels != null && messageLabels.length < 1) {
            for (String rawLabel : messageLabels) {
                String cleanLabel = this.cleanLabel(rawLabel);
                if (this.excludedLabels.contains(cleanLabel)) {
                    result = false;
                    break;
                }
            }
        }
        return result;
    }

}
/**==========================================================================================================================================================================================================================================================================================================================================================================================*
*版权所有(C)2014 Stephan H.Wissel*
*                                                                            *
*@作者Stephan H.Wissel*
*                                                                            *
*@version 0.1*
* ========================================================================== *
*                                                                            *
*根据Apache许可证2.0版(“许可证”)获得许可。你可以*
*除非符合许可证,否则不得使用此文件。您可以获得*
*许可证副本,地址为*
*                                                                            *
*除非适用法律要求或书面同意,软件*
*根据许可证进行的分发是按“原样”分发的,没有*
*明示或暗示的任何种类的保证或条件。见*
*管理权限和限制的特定语言的许可证*
*根据许可证*
*                                                                            *
* ========================================================================== */
包com.notessensei.gimap;
导入java.io.InputStream;
导入java.util.ArrayList;
导入java.util.array;
导入java.util.List;
导入java.util.Properties;
导入javax.mail.Address;
导入javax.mail.FetchProfile;
导入javax.mail.Folder;
导入javax.mail.Message;
导入javax.mail.MessaginException;
导入javax.mail.Session;
导入lotus.domino.Database;
导入lotus.domino.Document;
导入lotus.domino.It
com.sun.mail.handlers.multipart_mixed incompatible with javax.activation.DataContentHandler
/** ========================================================================= *
 * Copyright (C) 2014 Stephan H. Wissel                                       *
 *                                                                            *
 *  @author     Stephan H. Wissel <stephan@wissel.net>                        *  
 *                                                                            *
 * @version     0.1                                                           *
 * ========================================================================== *
 *                                                                            *
 * 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 com.notessensei.gimap;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import javax.mail.Address;
import javax.mail.FetchProfile;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;

import lotus.domino.Database;
import lotus.domino.Document;
import lotus.domino.Item;
import lotus.domino.NotesException;
import lotus.domino.NotesFactory;
import lotus.domino.NotesThread;

import com.sun.mail.gimap.GmailFolder;
import com.sun.mail.gimap.GmailMessage;
import com.sun.mail.gimap.GmailSSLStore;

public class GMail2Notes {

    public static int   MAX_TEST_COUNT  = 50;

    public static void main(String[] args) throws NotesException, MessagingException {

        if (args.length < 3) {
            System.out.println("GMail2Notes username@gmail.com password nsfFileName");
            System.exit(1);
        }

        System.out.println("Starting for " + args[0] + " to " + args[2]);
        NotesThread.sinitThread();
        lotus.domino.Session s = NotesFactory.createSession();
        Database db = s.getDatabase("", args[2]);
        GMail2Notes g2n = new GMail2Notes(args[0], args[1]);
        g2n.addExcludedLabel("Spam");
        g2n.addExcludedLabel("Trash");
        int resultCount = g2n.importMessages(s, db, "All Mail");
        System.out.print("Messages imported:");
        System.out.println(resultCount);
        NotesThread.stermThread();
        System.out.println("Done");
    }

    private final String        userName;
    private final String        passWord;
    private GmailSSLStore       store           = null;
    // set it to false for complete import
    private boolean             isTestMode      = true;

    // Labels we don not want to import
    private final List<String>    excludedLabels  = new ArrayList<String>();

    public GMail2Notes(String usr, String pwd) {
        this.userName = usr;
        this.passWord = pwd;
    }

    /**
     * Add a folder name to the list we are not interested in
     *
     * @param label
     */
    public void addExcludedLabel(String label) {
        this.excludedLabels.add(label);
    }

    public List<String> getSystemFolderNames() throws MessagingException {
        List<String> result = new ArrayList<String>();
        GmailSSLStore store = this.getStore();
        Folder[] folders = store.getFolder("[Gmail]").list();
        for (Folder f : folders) {
            result.add(f.getName());
        }
        return result;
    }

    public int importMessages(lotus.domino.Session s, Database db, String systemFolderName) throws MessagingException {
        int result = 0;

        // The object to move message to
        Mime2Doc md = new Mime2Doc();

        // Getting gMail ready
        GmailFolder f = this.getSystemFolder(systemFolderName);
        f.open(Folder.READ_ONLY);
        Message[] messages = f.getMessages();
        FetchProfile profile = new FetchProfile();
        profile.add(GmailFolder.FetchProfileItem.CONTENT_INFO);
        profile.add(GmailFolder.FetchProfileItem.LABELS);
        profile.add(GmailFolder.FetchProfileItem.MSGID);
        profile.add(GmailFolder.FetchProfileItem.SIZE);

        f.fetch(messages, profile);
        int count = 0;
        for (Message message : messages) {
            result += this.importOneMessage(s, db, md, message);

            // For testing we don't run through all of them
            count++;
            if (this.isTestMode && count >= MAX_TEST_COUNT) {
                break;
            }
        }
        if (f.isOpen()) {
            f.close(false);
        }
        this.cleanup();
        System.out.println("Done");

        return result;
    }

    /**
     * We need a delivered date so documents don't show up in SEND
     *
     * @param doc
     * @param sender
     */
    private void adjustDeliveredDate(Document doc, Address sender) {
        String senderName = sender.toString();
        if (!senderName.equalsIgnoreCase((this.userName))) {
            try {
                Item PostedDate = doc.getFirstItem("PostedDate");
                doc.copyItem(PostedDate, "DeliveredDate");
                doc.save();
                PostedDate.recycle();
            } catch (NotesException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * Strips leading \ from messages
     *
     * @param rawLabel
     * @return label Stripped from Backslash
     */
    private String cleanLabel(String rawLabel) {
        return (rawLabel.startsWith("\\") ? rawLabel.substring(1) : rawLabel).trim();
    }

    private void cleanup() {
        if (this.store != null && this.store.isConnected()) {
            try {
                this.store.close();
            } catch (MessagingException e) {
                e.printStackTrace();
            }
        }
        this.store = null;
    }

    private GmailSSLStore getStore() throws MessagingException {
        if (this.store != null) {
            return this.store;
        }
        Properties props = System.getProperties();
        props.setProperty("mail.imaps.connectiontimeout", "5000");
        props.setProperty("mail.imaps.host", "imap.gmail.com");
        props.setProperty("mail.imaps.partialfetch", "false");
        props.setProperty("mail.imaps.port", "993");
        props.setProperty("mail.imaps.timeout", "5000");
        props.setProperty("mail.mime.base64.ignoreerrors", "true");
        props.setProperty("mail.store.protocol", "gimaps");

        Session session = Session.getDefaultInstance(props, null);
        this.store = (GmailSSLStore) session.getStore("gimaps");
        this.store.connect(this.userName, this.passWord);
        // Ready for connection
        return this.store;
    }

    /**
    * can be: All Mail, Drafts, Important, Sent Mail, Spam, Starred, Trash
    **/
    private GmailFolder getSystemFolder(String folderName) throws MessagingException {
        GmailSSLStore store = this.getStore();
        Folder folder = store.getFolder("[Gmail]").getFolder(folderName);
        return (GmailFolder) folder;

    }

    private int importOneMessage(lotus.domino.Session s, Database db, Mime2Doc md, Message message) {
        int result = 0;
        try {
            GmailMessage g = (GmailMessage) message;
            Address sender = g.getSender();
            String[] labels = g.getLabels();
            System.out.print(g.getMessageID());
            if (labels != null) {
                System.out.print(", ");
                System.out.print(Arrays.toString(labels));
            }

            if (this.processThisMessage(labels)) {
                result = 1;
                Document doc = db.createDocument();
                InputStream in = g.getMimeStream();
                md.importMail(s, in, doc);
                this.moveDocToFolders(doc, labels);
                this.adjustDeliveredDate(doc, sender);
                System.out.println(" - processed");
            } else {
                System.out.println(" - skipped");
            }
        } catch (Exception e) {
            // TODO: record the message for follow-up
            e.printStackTrace();
        }
        return result;
    }

    /**
     * Moves doc to folders as needed
     *
     * @param doc
     * @param labels
     */
    private void moveDocToFolders(Document doc, String[] labels) {
        if (labels != null) {
            for (String label : labels) {
                this.movetoMatchingFolder(doc, label);
            }
        }
    }

    private void movetoMatchingFolder(Document doc, String folderCandidate) {
        // TODO handle the SENT folder, Draft folder
        if (folderCandidate != null && !folderCandidate.trim().equals("")) {
            try {
                String realFolder = this.cleanLabel(folderCandidate);
                if (realFolder.equalsIgnoreCase("inbox")) {
                    doc.putInFolder("($Inbox)");
                } else if (realFolder.equalsIgnoreCase("drafts")) {
                    // TODO handle Drafts
                } else if (realFolder.equalsIgnoreCase("sent")) {
                    // TODO handle SENT
                } else {
                    doc.putInFolder(realFolder, true);
                }
            } catch (NotesException e) {
                e.printStackTrace();
            }
        }
    }

    private boolean processThisMessage(String[] messageLabels) {
        boolean result = true;

        // If the message has no labels we do process it
        if (messageLabels != null && messageLabels.length < 1) {
            for (String rawLabel : messageLabels) {
                String cleanLabel = this.cleanLabel(rawLabel);
                if (this.excludedLabels.contains(cleanLabel)) {
                    result = false;
                    break;
                }
            }
        }
        return result;
    }

}