Osgi 将JavaMail 1.5与XPages一起使用
我有一个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。但是现在我得到了异常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
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类的类加载器
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更友好的技术。如果你能找到,请把它贴在这里:)
/** ========================================================================= *
* 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;
}
}