jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mreut...@apache.org
Subject svn commit: r611221 - in /jackrabbit/sandbox/jackrabbit-imap-persistence: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/jackrabbit/ src/main/java/org/apache/jackrabbit/persistence/
Date Fri, 11 Jan 2008 16:15:53 GMT
Author: mreutegg
Date: Fri Jan 11 08:15:49 2008
New Revision: 611221

URL: http://svn.apache.org/viewvc?rev=611221&view=rev
Log:
Experimental / incomplete implementation of an ImapPersistenceManager and ImapDataStore.

Added:
    jackrabbit/sandbox/jackrabbit-imap-persistence/   (with props)
    jackrabbit/sandbox/jackrabbit-imap-persistence/README.txt   (with props)
    jackrabbit/sandbox/jackrabbit-imap-persistence/pom.xml   (with props)
    jackrabbit/sandbox/jackrabbit-imap-persistence/src/
    jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/
    jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/
    jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/
    jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/
    jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/
    jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/
    jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ByteArrayDataSource.java
  (with props)
    jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/IDMimeMessage.java
  (with props)
    jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapDataRecord.java
  (with props)
    jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapDataStore.java
  (with props)
    jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapPersistenceManager.java
  (with props)
    jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapUtil.java
  (with props)

Propchange: jackrabbit/sandbox/jackrabbit-imap-persistence/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Fri Jan 11 08:15:49 2008
@@ -0,0 +1,4 @@
+*.iml
+*.ipr
+*.iws
+target

Added: jackrabbit/sandbox/jackrabbit-imap-persistence/README.txt
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-imap-persistence/README.txt?rev=611221&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-imap-persistence/README.txt (added)
+++ jackrabbit/sandbox/jackrabbit-imap-persistence/README.txt Fri Jan 11 08:15:49 2008
@@ -0,0 +1,40 @@
+This is an experimental implementation of a BundlePersistenceManager
+and DataStore using an IMAP email server.
+
+Bundles are stored as individual messages. The node hiearchy is represented
+as the structure of an threaded email conversation. That is, the parent
+node pointer of a bundle is reflected in an email as a In-Reply-To header.
+
+The ImapPersistenceManager is not transactional! If an error occurs while
+committing changes the workspace may become inconsistent and unreadable!
+
+The ImapDataStore distributes a DataRecord over multiple messages. The
+default 'block size' is 1 MB.
+
+Both ImapPersistenceManager and ImapDataStore support the following parameters:
+
+- url (e.g. imap://localhost/) -> mandatory
+- username -> mandatory
+- password -> mandatory
+- useSsl -> defaults to false
+- useTls -> defaults to false
+
+ImapPersistenceManager also supports the following parameters:
+
+- bundleFolderName -> defaults to 'bundles'
+- nodeReferencesFolderName -> defaults to 'nodeReferences'
+
+ImapDataStore also supports the following parameter:
+
+- dataStoreFolderName -> defaults to 'dataStore'
+
+
+The methods related to data store garbage collection are not yet implemented.
+
+Tested with dovecot [1] on Fedora Core [2].
+
+
+References:
+
+[1] http://www.dovecot.org/
+[2] http://fedoraproject.org/
\ No newline at end of file

Propchange: jackrabbit/sandbox/jackrabbit-imap-persistence/README.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/sandbox/jackrabbit-imap-persistence/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-imap-persistence/pom.xml?rev=611221&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-imap-persistence/pom.xml (added)
+++ jackrabbit/sandbox/jackrabbit-imap-persistence/pom.xml Fri Jan 11 08:15:49 2008
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.
+  -->
+
+<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 ">
+  <modelVersion>4.0.0</modelVersion>
+
+  <!-- ====================================================================== -->
+  <!-- P R O J E C T  D E S C R I P T I O N                                   -->
+  <!-- ====================================================================== -->
+
+  <parent>
+    <groupId>org.apache</groupId>
+    <artifactId>apache</artifactId>
+    <version>4</version>
+  </parent>
+
+  <groupId>org.apache.jackrabbit</groupId>
+  <artifactId>jackrabbit-imap-persistence</artifactId>
+  <name>Apache Jackrabbit</name>
+  <version>1.5-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>jackrabbit-core</artifactId>
+      <version>1.5-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <version>1.3.0</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.mail</groupId>
+      <artifactId>mail</artifactId>
+      <version>1.4</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.activation</groupId>
+      <artifactId>activation</artifactId>
+      <version>1.1</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.jcr</groupId>
+      <artifactId>jcr</artifactId>
+      <version>1.0</version>
+    </dependency>
+  </dependencies>
+
+</project>

Propchange: jackrabbit/sandbox/jackrabbit-imap-persistence/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ByteArrayDataSource.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ByteArrayDataSource.java?rev=611221&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ByteArrayDataSource.java
(added)
+++ jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ByteArrayDataSource.java
Fri Jan 11 08:15:49 2008
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.jackrabbit.persistence;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.activation.DataSource;
+
+public class ByteArrayDataSource implements DataSource {
+
+    private final byte[] data;
+
+    public ByteArrayDataSource(byte[] data) {
+        this.data = data;
+    }
+
+    public String getContentType() {
+        return "application/octet-stream";
+    }
+
+    public InputStream getInputStream() throws IOException {
+        return new ByteArrayInputStream(data);
+    }
+
+    public String getName() {
+        return "data";
+    }
+
+    public OutputStream getOutputStream() throws IOException {
+        throw new IOException("this data source is read-only");
+    }
+
+}

Propchange: jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ByteArrayDataSource.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/IDMimeMessage.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/IDMimeMessage.java?rev=611221&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/IDMimeMessage.java
(added)
+++ jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/IDMimeMessage.java
Fri Jan 11 08:15:49 2008
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.jackrabbit.persistence;
+
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.internet.MimeMessage;
+
+public class IDMimeMessage extends MimeMessage {
+
+    private final String id;
+
+    public IDMimeMessage(Session session, String id) {
+        super(session);
+        this.id = id;
+    }
+
+    protected void updateMessageID() throws MessagingException {
+        setHeader("Message-ID", id);
+    }
+}

Propchange: jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/IDMimeMessage.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapDataRecord.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapDataRecord.java?rev=611221&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapDataRecord.java
(added)
+++ jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapDataRecord.java
Fri Jan 11 08:15:49 2008
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.jackrabbit.persistence;
+
+import java.io.InputStream;
+
+import org.apache.jackrabbit.core.data.DataIdentifier;
+import org.apache.jackrabbit.core.data.DataRecord;
+import org.apache.jackrabbit.core.data.DataStoreException;
+
+public class ImapDataRecord implements DataRecord {
+
+    private final DataIdentifier identifier;
+
+    private final long length;
+
+    private final ImapDataStore store;
+
+    public ImapDataRecord(String id, long length, ImapDataStore store) {
+        this.identifier = new DataIdentifier(id);
+        this.length = length;
+        this.store = store;
+    }
+
+    public DataIdentifier getIdentifier() {
+        return identifier;
+    }
+
+    public long getLength() throws DataStoreException {
+        return length;
+    }
+
+    public InputStream getStream() throws DataStoreException {
+        return store.getDataRecordStream(identifier);
+    }
+
+}

Propchange: jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapDataRecord.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapDataStore.java?rev=611221&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapDataStore.java
(added)
+++ jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapDataStore.java
Fri Jan 11 08:15:49 2008
@@ -0,0 +1,366 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.jackrabbit.persistence;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.SequenceInputStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Properties;
+
+import javax.activation.DataHandler;
+import javax.activation.DataSource;
+import javax.jcr.RepositoryException;
+import javax.mail.BodyPart;
+import javax.mail.Folder;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.Store;
+import javax.mail.URLName;
+import javax.mail.Flags.Flag;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+import javax.mail.search.MessageIDTerm;
+
+import org.apache.jackrabbit.core.data.DataIdentifier;
+import org.apache.jackrabbit.core.data.DataRecord;
+import org.apache.jackrabbit.core.data.DataStore;
+import org.apache.jackrabbit.core.data.DataStoreException;
+import org.apache.jackrabbit.core.persistence.bundle.util.TrackingInputStream;
+import org.apache.jackrabbit.uuid.UUID;
+
+public class ImapDataStore implements DataStore {
+
+    private static final String NEXT_DATA_BLOCK_HEADER_NAME = "Next-Data-Block-Reference";
+
+    private Properties props = new Properties();
+
+    private Session session = null;
+
+    private Store store = null;
+
+    private Folder dataStoreFolder = null;
+
+    private String url = null;
+
+    private String username = null;
+
+    private String password = null;
+
+    private String dataStoreFolderName = "dataStore";
+
+    private boolean useSsl = false;
+
+    private boolean useTls = false;
+
+    private long blockSize = 1024;
+
+    private long updateModifiedDateIfBefore = 0;
+
+    public void init(String homeDir) throws RepositoryException {
+        session = Session.getInstance(props);
+        try {
+            store = session.getStore(new URLName(url));
+            store.connect(username, password);
+            Folder f = store.getDefaultFolder();
+            dataStoreFolder = f.getFolder(dataStoreFolderName);
+            if (!dataStoreFolder.exists()) {
+                if (!dataStoreFolder.create(Folder.HOLDS_MESSAGES)) {
+                    store.close();
+                    throw new RepositoryException("unable to create data store folder");
+                }
+            }
+            dataStoreFolder.open(Folder.READ_WRITE);
+        } catch (MessagingException e) {
+            throw new RepositoryException(e);
+        }
+    }
+
+    public DataRecord addRecord(InputStream stream) throws DataStoreException {
+        String id = UUID.randomUUID().toString();
+        TrackingInputStream in = new TrackingInputStream(stream);
+        String currentId = id;
+        try {
+            // break data into pieces
+            int read;
+            byte[] buffer = new byte[4096];
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            Message firstMessage = null;
+            for (Iterator it = splitStream(in); it.hasNext();) {
+                out.reset();
+                InputStream is = (InputStream) it.next();
+                while ((read = is.read(buffer)) != -1) {
+                    out.write(buffer, 0, read);
+                }
+                MimeMessage message = new IDMimeMessage(session, ImapUtil.createMessageID(currentId));
+                if (!currentId.equals(id)) {
+                    // this is an additional message, set In-Reply-To
+                    message.setHeader("In-Reply-To", ImapUtil.createMessageID(id));
+                } else {
+                    // first message
+                    firstMessage = message;
+                }
+                message.setSubject(currentId);
+                message.setFlag(Flag.SEEN, true);
+                message.setSentDate(new Date());
+                if (it.hasNext()) {
+                    currentId = UUID.randomUUID().toString();
+                    message.setHeader(NEXT_DATA_BLOCK_HEADER_NAME, ImapUtil.createMessageID(currentId));
+                }
+                BodyPart body = new MimeBodyPart();
+                DataSource source = new ByteArrayDataSource(out.toByteArray());
+                body.setDataHandler(new DataHandler(source));
+                body.setFileName(source.getName());
+                MimeMultipart multipart = new MimeMultipart();
+                multipart.addBodyPart(body);
+                message.setContent(multipart);
+                if (firstMessage != message) {
+                    dataStoreFolder.appendMessages(new Message[]{message});
+                }
+            }
+            firstMessage.setHeader("Data-Record-Length", String.valueOf(in.getPosition()));
+            dataStoreFolder.appendMessages(new Message[]{firstMessage});
+            return new ImapDataRecord(id, in.getPosition(), this);
+        } catch (IOException e) {
+            throw new DataStoreException(e);
+        } catch (MessagingException e) {
+            throw new DataStoreException(e);
+        } finally {
+            try {
+                in.close();
+            } catch (IOException e) {
+                // ignore
+            }
+        }
+    }
+
+    public void clearInUse() {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void close() throws DataStoreException {
+        if (store != null) {
+            try {
+                store.close();
+            } catch (MessagingException e) {
+                throw new DataStoreException(e);
+            }
+        }
+    }
+
+    public int deleteAllOlderThan(long min) throws DataStoreException {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    public Iterator getAllIdentifiers() throws DataStoreException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public int getMinRecordLength() {
+        return (int) blockSize / 2 * 1024;
+    }
+
+    public DataRecord getRecord(DataIdentifier identifier)
+            throws DataStoreException {
+        try {
+            String id = identifier.toString();
+            Message[] messages = dataStoreFolder.search(new MessageIDTerm(ImapUtil.createMessageID(id)));
+            if (messages.length == 0) {
+                throw new DataStoreException("data record with id " + id + " not found");
+            }
+            String[] values = messages[0].getHeader("Data-Record-Length");
+            if (values == null || values.length == 0) {
+                throw new DataStoreException("no Data-Record-Length header set");
+            }
+            updateModifiedDate(messages[0]);
+            long length;
+            try {
+                length = Long.parseLong(values[0]);
+            } catch (NumberFormatException e) {
+                throw new DataStoreException("malformed Data-Record-Length header: " + values[0]);
+            }
+
+            return new ImapDataRecord(identifier.toString(), length, this);
+        } catch (MessagingException e) {
+            throw new DataStoreException(e);
+        }
+    }
+
+    public void updateModifiedDateOnAccess(long before) {
+        updateModifiedDateIfBefore = before;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getDataStoreFolderName() {
+        return dataStoreFolderName;
+    }
+
+    public void setDataStoreFolderName(String dataStoreFolderName) {
+        this.dataStoreFolderName = dataStoreFolderName;
+    }
+
+    public boolean isUseSsl() {
+        return useSsl;
+    }
+
+    public void setUseSsl(boolean useSsl) {
+        this.useSsl = useSsl;
+        if (useSsl) {
+            props.setProperty("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
+            props.setProperty("mail.imap.socketFactory.fallback", "false");
+            props.setProperty("mail.imap.socketFactory.port", "993");
+        }
+    }
+
+    public boolean isUseTls() {
+        return useTls;
+    }
+
+    public void setUseTls(boolean useTls) {
+        this.useTls = useTls;
+        if (useTls) {
+            props.setProperty("mail.imap.starttls.enable", "true");
+        }
+    }
+
+    InputStream getDataRecordStream(DataIdentifier identifier)
+            throws DataStoreException {
+        String msgId = ImapUtil.createMessageID(identifier.toString());
+        final List msgList = new ArrayList();
+        try {
+            while (msgId != null) {
+                Message[] messages = dataStoreFolder.search(new MessageIDTerm(msgId));
+                if (messages.length == 0) {
+                    throw new DataStoreException("truncated data record");
+                }
+                msgList.add(messages[0]);
+                String[] values = messages[0].getHeader(NEXT_DATA_BLOCK_HEADER_NAME);
+                if (values != null && values.length > 0) {
+                    msgId = values[0];
+                } else {
+                    // no more messages
+                    msgId = null;
+                }
+            }
+        } catch (MessagingException e1) {
+            throw new DataStoreException(e1);
+        }
+        return new SequenceInputStream(new Enumeration() {
+
+            private Iterator it = msgList.iterator();
+
+            public boolean hasMoreElements() {
+                return it.hasNext();
+            }
+
+            public Object nextElement() {
+                Message msg = (Message) it.next();
+                try {
+                    MimeMultipart multipart = (MimeMultipart) msg.getContent();
+                    return multipart.getBodyPart(0).getInputStream();
+                } catch (IOException e) {
+                    throw new NoSuchElementException();
+                } catch (MessagingException e) {
+                    throw new NoSuchElementException();
+                }
+            }
+
+        });
+    }
+
+    private void updateModifiedDate(Message message) throws MessagingException {
+        if (message.getSentDate().getTime() < updateModifiedDateIfBefore) {
+            message.setSentDate(new Date());
+            message.saveChanges();
+        }
+    }
+
+    private Iterator splitStream(TrackingInputStream in) {
+        final InputStream bufferedIn = new BufferedInputStream(in);
+        return new Iterator() {
+
+            public boolean hasNext() {
+                bufferedIn.mark(1);
+                try {
+                    try {
+                        return bufferedIn.read() != -1;
+                    } finally {
+                        bufferedIn.reset();
+                    }
+                } catch (IOException e) {
+                    return false;
+                }
+            }
+
+            public Object next() {
+                return new InputStream() {
+
+                    private long count = blockSize * 1024;
+
+                    public int read() throws IOException {
+                        if (--count >= 0) {
+                            return bufferedIn.read();
+                        } else {
+                            return -1;
+                        }
+                    }
+
+                };
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+
+        };
+    }
+}

Propchange: jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapDataStore.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapPersistenceManager.java?rev=611221&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapPersistenceManager.java
(added)
+++ jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapPersistenceManager.java
Fri Jan 11 08:15:49 2008
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.jackrabbit.persistence;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Date;
+import java.util.Properties;
+
+import javax.activation.DataHandler;
+import javax.activation.DataSource;
+import javax.mail.BodyPart;
+import javax.mail.Folder;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.Store;
+import javax.mail.URLName;
+import javax.mail.Flags.Flag;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+import javax.mail.search.MessageIDTerm;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.NodeIdIterator;
+import org.apache.jackrabbit.core.persistence.PMContext;
+import org.apache.jackrabbit.core.persistence.bundle.AbstractBundlePersistenceManager;
+import org.apache.jackrabbit.core.persistence.bundle.util.BundleBinding;
+import org.apache.jackrabbit.core.persistence.bundle.util.ErrorHandling;
+import org.apache.jackrabbit.core.persistence.bundle.util.NodePropBundle;
+import org.apache.jackrabbit.core.persistence.util.Serializer;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.NoSuchItemStateException;
+import org.apache.jackrabbit.core.state.NodeReferences;
+import org.apache.jackrabbit.core.state.NodeReferencesId;
+
+public class ImapPersistenceManager extends AbstractBundlePersistenceManager {
+
+    private BundleBinding binding;
+
+    private Properties props = new Properties();
+
+    private Session session = null;
+
+    private Store store = null;
+
+    private Folder bundleFolder = null;
+
+    private Folder nodeReferences = null;
+
+    private String url = null;
+
+    private String username = null;
+
+    private String password = null;
+
+    private boolean useSsl = false;
+
+    private boolean useTls = false;
+
+    public void init(PMContext context) throws Exception {
+        super.init(context);
+        binding = new BundleBinding(new ErrorHandling(ErrorHandling.IGNORE_MISSING_BLOBS),
null, getNsIndex(), getNameIndex(), context.getDataStore());
+        session = Session.getInstance(props);
+        store = session.getStore(new URLName(url));
+        store.connect(username, password);
+        Folder f = store.getDefaultFolder();
+        bundleFolder = f.getFolder("bundles");
+        if (!bundleFolder.exists()) {
+            if (!bundleFolder.create(Folder.HOLDS_MESSAGES)) {
+                store.close();
+                throw new Exception("unable to create bundles folder");
+            }
+        }
+        bundleFolder.open(Folder.READ_WRITE);
+        nodeReferences = f.getFolder("noderefs");
+        if (!nodeReferences.exists()) {
+            if (!nodeReferences.create(Folder.HOLDS_MESSAGES)) {
+                store.close();
+                throw new Exception("unable to create node references folder");
+            }
+        }
+        nodeReferences.open(Folder.READ_WRITE);
+    }
+
+    public void close() throws Exception {
+        if (store != null) {
+            store.close();
+        }
+    }
+
+    protected void destroy(NodeReferences refs) throws ItemStateException {
+        try {
+            Message[] messages = nodeReferences.search(createMessageIDTerm(refs.getTargetId()));
+            if (messages.length == 0) {
+                throw new ItemStateException("node refs with id " + refs.getTargetId() +
" not found");
+            }
+            for (int i = 0; i < messages.length; i++) {
+                messages[i].setFlag(Flag.DELETED, true);
+                messages[i].saveChanges();
+            }
+            nodeReferences.expunge();
+        } catch (MessagingException e) {
+            throw new ItemStateException(e.toString());
+        }
+    }
+
+    protected void destroyBundle(NodePropBundle bundle)
+            throws ItemStateException {
+        try {
+            Message[] messages = bundleFolder.search(createMessageIDTerm(bundle.getId()));
+            if (messages.length == 0) {
+                throw new ItemStateException("bundle with id " + bundle.getId() + " not found");
+            }
+            for (int i = 0; i < messages.length; i++) {
+                messages[i].setFlag(Flag.DELETED, true);
+            }
+            bundleFolder.expunge();
+        } catch (MessagingException e) {
+            throw new ItemStateException(e.toString());
+        }
+    }
+
+    protected boolean existsBundle(NodeId id) throws ItemStateException {
+        try {
+            return bundleFolder.search(createMessageIDTerm(id)).length > 0;
+        } catch (MessagingException e) {
+            throw new ItemStateException(e.toString());
+        }
+    }
+
+    protected BundleBinding getBinding() {
+        return binding;
+    }
+
+    public NodeReferences load(NodeReferencesId id)
+            throws NoSuchItemStateException, ItemStateException {
+        try {
+            Message[] messages = nodeReferences.search(createMessageIDTerm(id.getTargetId()));
+            if (messages.length == 0) {
+                return null;
+            }
+            MimeMultipart multipart = (MimeMultipart) messages[0].getContent();
+            InputStream in = multipart.getBodyPart(0).getInputStream();
+            try {
+                NodeReferences refs = new NodeReferences(id);
+                Serializer.deserialize(refs, in);
+                return refs;
+            } finally {
+                in.close();
+            }
+        } catch (MessagingException e) {
+            throw new ItemStateException(e.toString());
+        } catch (IOException e) {
+            throw new ItemStateException(e.toString());
+        } catch (Exception e) {
+            throw new ItemStateException(e.toString());
+        }
+    }
+
+    protected NodePropBundle loadBundle(NodeId id) throws ItemStateException {
+        try {
+            Message[] messages = bundleFolder.search(createMessageIDTerm(id));
+            if (messages.length == 0) {
+                return null;
+            }
+            MimeMultipart multipart = (MimeMultipart) messages[0].getContent();
+            InputStream in = multipart.getBodyPart(0).getInputStream();
+            try {
+                return getBinding().readBundle(new DataInputStream(in), id);
+            } finally {
+                in.close();
+            }
+        } catch (MessagingException e) {
+            throw new ItemStateException(e.toString());
+        } catch (IOException e) {
+            throw new ItemStateException(e.toString());
+        }
+    }
+
+    protected void store(NodeReferences refs) throws ItemStateException {
+        try {
+            if (exists(refs.getId())) {
+                destroy(refs);
+            }
+            String id = refs.getTargetId().getUUID().toString();
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            Serializer.serialize(refs, out);
+            MimeMessage message = new IDMimeMessage(session, ImapUtil.createMessageID(id));
+            message.setSubject(id);
+            message.setFlag(Flag.SEEN, true);
+            message.setSentDate(new Date());
+            BodyPart body = new MimeBodyPart();
+            DataSource source = new ByteArrayDataSource(out.toByteArray());
+            body.setDataHandler(new DataHandler(source));
+            body.setFileName(source.getName());
+            MimeMultipart multipart = new MimeMultipart();
+            multipart.addBodyPart(body);
+            message.setContent(multipart);
+            nodeReferences.appendMessages(new Message[]{message});
+        } catch (MessagingException e) {
+            throw new ItemStateException(e.toString());
+        } catch (Exception e) {
+            throw new ItemStateException(e.toString());
+        }
+    }
+
+    protected void storeBundle(NodePropBundle bundle)
+            throws ItemStateException {
+        try {
+            String id = bundle.getId().getUUID().toString();
+            if (!bundle.isNew()) {
+                destroyBundle(bundle);
+            }
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            binding.writeBundle(new DataOutputStream(out), bundle);
+            MimeMessage message = new IDMimeMessage(session, ImapUtil.createMessageID(id));
+            message.setSubject(id);
+            message.setFlag(Flag.SEEN, true);
+            message.setSentDate(new Date());
+            if (bundle.getParentId() != null) {
+                message.setHeader("In-Reply-To", ImapUtil.createMessageID(bundle.getParentId().getUUID().toString()));
+            }
+            BodyPart body = new MimeBodyPart();
+            DataSource source = new ByteArrayDataSource(out.toByteArray());
+            body.setDataHandler(new DataHandler(source));
+            body.setFileName(source.getName());
+            MimeMultipart multipart = new MimeMultipart();
+            multipart.addBodyPart(body);
+            message.setContent(multipart);
+            bundleFolder.appendMessages(new Message[]{message});
+        } catch (IOException e) {
+            throw new ItemStateException(e.toString());
+        } catch (MessagingException e) {
+            throw new ItemStateException(e.toString());
+        }
+    }
+
+    public boolean exists(NodeReferencesId id) throws ItemStateException {
+        try {
+            return nodeReferences.search(createMessageIDTerm(id.getTargetId())).length >
0;
+        } catch (MessagingException e) {
+            throw new ItemStateException(e.toString());
+        }
+    }
+
+    public NodeIdIterator getAllNodeIds(NodeId arg0, int arg1) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public boolean isUseSsl() {
+        return useSsl;
+    }
+
+    public void setUseSsl(boolean useSsl) {
+        this.useSsl = useSsl;
+        if (useSsl) {
+            props.setProperty("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
+            props.setProperty("mail.imap.socketFactory.fallback", "false");
+            props.setProperty("mail.imap.socketFactory.port", "993");
+        }
+    }
+
+    public boolean isUseTls() {
+        return useTls;
+    }
+
+    public void setUseTls(boolean useTls) {
+        this.useTls = useTls;
+        if (useTls) {
+            props.setProperty("mail.imap.starttls.enable", "true");
+        }
+    }
+
+    private MessageIDTerm createMessageIDTerm(NodeId id) {
+        return new MessageIDTerm(ImapUtil.createMessageID(id.getUUID().toString()));
+    }
+}

Propchange: jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapPersistenceManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapUtil.java?rev=611221&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapUtil.java
(added)
+++ jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapUtil.java
Fri Jan 11 08:15:49 2008
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.jackrabbit.persistence;
+
+public class ImapUtil {
+
+    public static String createMessageID(String uuid) {
+        return "<" + uuid + "@jackrabbit.apache.org>";
+    }
+}

Propchange: jackrabbit/sandbox/jackrabbit-imap-persistence/src/main/java/org/apache/jackrabbit/persistence/ImapUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message