我有一个XPage应用程序应该通过IMAP(和SSL)从GMail读取邮件并将它们存储在nsf数据库中。
为此,我需要JavaMail 1.5。
在阅读了一些帖子之后,我得出的结论是我必须构建自己的OSGI-Plugin。 在John Dalsgaard关于http://www.dalsgaard-data.eu/blog/wrap-an-existing-jar-file-into-a-plug-in/的博客之后,我能够将JavaMail 1.5 jar文件包装到OSGI-Plugin中。该插件导出所有JavaMail包,因此我可以在我的XPage应用程序中使用它们。
在我的XPage中有一些java代码试图建立与GMail的连接。但是连接总是超时,所以我打开了javamail的调试选项。调试显示我的java代码仍然使用javamail 1.3(由domino服务器提供的)。
因此我将我的java代码移到了OSGI-Plugin并导出了包,所以我仍然可以在我的XPage中使用它。打开javamail的调试显示正确的版本1.5。但是现在我得到例外javax.mail.NoSuchProviderException
,无论我是使用imap
还是imaps
作为协议。
我错过了什么?为什么我不能在osgi-plugin中使用javamail 1.5 jar文件?
答案 0 :(得分:1)
javax.mail的代码实际上并不是OSGi友好的。它使用Thread上下文ClassLoader来查找实例化实现。
你可以通过以下方式欺骗它:
E.g:
Thread thread = Thread.currentThread();
ClassLoader previousCl = thread.getContextClassLoader();
thread.setContextClassLoader(IMAPStore.class.getClassLoader());
try {
session.getStore("imaps");
} finally {
thread.setContextClassLoader(previousCl);
}
请注意,我没有对此进行测试,但解决方案看起来应该类似。您可能必须将更多javax.mail命令放入try块(例如,获取会话)。
不那么丑陋的solutoin
如果你跳过javax.mail API的使用并直接使用imap的类,那么一个不那么难看的解决方案。
E.g:
Session session = Session.getDefaultInstance(...);
Store imapStore = new IMAPStore(session, url);
通常在Java EE中使用SPI或类似解决方案时,可以通过跳过工厂机制(使用线程上下文类加载器和其他技巧)并直接实例化实现类来实现相同的功能。
<强>更新强>
在commant中声明有一个例外:
com.sun.mail.handlers.multipart_mixed incompatible with javax.activation.DataContentHandler
原因似乎是javax.activation。*包在OSGi容器中可用两次。它来自JDK,它也来自其中一个捆绑。问题类似here,原因也来自重复的包。
然而,真正的原因是再次使用Thread Context ClassLoader。如果您查看引发异常的源代码,您将看到Thread Context Classloader用于加载类。这是一个问题,因为我猜TCC是系统类加载器,而javax.mail连接到javax.activation包。
我现在可以想象以下选项:
答案 1 :(得分:0)
我在maven中心找到了这个罐子:
http://search.maven.org/#artifactdetails|javax.mail|javax.mail-api|1.5.2|jar
它似乎是一个有效的OSGi包。也许这有帮助吗?
答案 2 :(得分:0)
你真的需要Java 1.5.2邮件吗?我不这么认为。您需要的是Google enhanced IMAP classes和代码I wrote in January。简而言之:
/** ========================================================================= *
* 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;
}
}
如果这对您有用,请告诉我们