This patch finishes (hopefully) the implementation of attributes on
Mail (Bug 18471).
The implementation largely follows Noels plan:
- change sqlResources.xml to accomodate the extra
field:
- change create
- add updateMessageAttributesSQL
- add retrieveMessageAttributesSQL
- change JDBCMailRepository to store the BLOB if the
the updateMessageAttributesSQL is present *AND*
there are attributes
- change JDBCMailRepository to retrieve the BLOB if
the retrieveMessageAttributesSQL is present
- comment out updateMessageAttributesSQL and
retrieveMessageAttributesSQL by default in
sqlResources.xml
-In JDBCMailRepository, log and discard the SQLException of the
table hasn't be updated to allow the operation.
In addition it was necessary to add methods to MailImpl for
getting/setting the attributes HashMap directly, those methods are not
exposed in the Mail interface.
The comment out part of updateMessageAttributesSQL and
retrieveMessageAttributesSQL is only done for the Mail repository the
spool repository has them commented in.
It was necessary to have distinct insertMsgSQL statements one for use
with repositories with attributes and one for repositories without,
the version for inserting messages containing attributes are commented
out for Mail repository but not for spool repositories.
Note the feature will only work with spool database repositories, if
the spool table in the database are recreated, this should not be a
compatibility problem as entries in spool are of a temporary nature.
Also I have added a removeAllAttributes to the Mail interface to allow
such an operation to be fast (as compared to removing each attribute
individually in a loop over attributeNames), and a hasAttributes
method which returns true if the Mail instance has any attributes set.
--
S�ren Hilmer, M.Sc.
R&D manager Phone: +45 70 27 64 00
TietoEnator IT+ Fax: +45 70 27 64 40
Ved Lunden 12 Direct: +45 87 46 64 57
DK-8230 �byh�j Email: [EMAIL PROTECTED]
? src/java/ep
? src/java/org/apache/james/transport/mailets/SetMailAttribute.java
? src/java/org/apache/james/transport/matchers/HasMailAttribute.java
? tools/lib/activation.jar
? tools/lib/mail.jar
Index: src/conf/sqlResources.xml
===================================================================
RCS file: /home/cvspublic/jakarta-james/src/conf/sqlResources.xml,v
retrieving revision 1.19
diff -u -w -b -r1.19 sqlResources.xml
--- src/conf/sqlResources.xml 23 Jun 2003 01:53:27 -0000 1.19
+++ src/conf/sqlResources.xml 25 Jun 2003 13:26:18 -0000
@@ -171,8 +171,20 @@
<!-- Statements used to update the body of a message stored in this repository. -->
<sql name="updateMessageBodySQL">UPDATE ${table} SET message_body = ? WHERE message_name = ? AND repository_name = ?</sql>
+ <!-- Statements used to update the attributes of a message stored in this repository.
+ <sql name="updateMessageAttributesSQL">UPDATE ${table} SET message_attributes = ? WHERE message_name = ? AND repository_name = ?</sql>-->
+
<!-- Statements used to insert a message into this repository. -->
- <sql name="insertMessageSQL">INSERT INTO ${table} (message_name, repository_name, message_state, error_message, sender, recipients, remote_host, remote_addr, last_updated, message_body) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)</sql>
+ <sql name="insertMessageSQL">INSERT INTO ${table} (message_name,
+ repository_name, message_state, error_message, sender, recipients,
+ remote_host, remote_addr, last_updated, message_body) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)</sql>
+
+ <!-- Statements used to insert a message with attributes into this repository.
+ <sql name="insertMessageSQL">INSERT INTO ${table} (message_name,
+ repository_name, message_state, error_message, sender, recipients,
+ remote_host, remote_addr, last_updated, message_body,
+ message_attributes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)</sql>
+ -->
<!-- Statements used to retrieve a message stored in this repository. -->
<sql name="retrieveMessageSQL">SELECT message_state, error_message, sender, recipients, remote_host, remote_addr, last_updated FROM ${table} WHERE message_name = ? AND repository_name = ?</sql>
@@ -180,6 +192,9 @@
<!-- Statements used to retrieve the body of a message stored in this repository. -->
<sql name="retrieveMessageBodySQL">SELECT message_body FROM ${table} WHERE message_name = ? AND repository_name = ?</sql>
+ <!-- Statements used to retrieve the attributes of a message stored in this repository.
+ <sql name="retrieveMessageAttributesSQL">SELECT message_attributes FROM ${table} WHERE message_name = ? AND repository_name = ?</sql>-->
+
<!-- Statements used to retrieve the size of the body of a message stored in this repository. -->
<!-- NOTE: This statement is optional and need not be implemented for a particular database to be supported. -->
<sql name="retrieveMessageBodySizeSQL" db="mssql">SELECT datalength(message_body) FROM ${table} WHERE message_name = ? AND repository_name = ?</sql>
@@ -205,6 +220,7 @@
remote_host varchar (255) NOT NULL ,
remote_addr varchar (20) NOT NULL ,
message_body longblob NOT NULL ,
+ message_attributes longblob NOT NULL ,
last_updated datetime NOT NULL,
PRIMARY KEY (repository_name, message_name)
)
@@ -220,6 +236,7 @@
remote_host varchar (255) NOT NULL ,
remote_addr varchar (20) NOT NULL ,
message_body varchar NOT NULL ,
+ message_attributes varchar NOT NULL ,
last_updated timestamp NOT NULL,
PRIMARY KEY (repository_name, message_name)
)
@@ -235,6 +252,7 @@
[remote_host] [varchar] (255) NOT NULL ,
[remote_addr] [varchar] (20) NOT NULL ,
[message_body] [image] NOT NULL ,
+ [message_attributes] [image] NOT NULL ,
[last_updated] [datetime] NOT NULL,
PRIMARY KEY (repository_name, message_name)
)
@@ -250,6 +268,7 @@
remote_host varchar2(100) NOT NULL ,
remote_addr varchar2(20) NOT NULL ,
message_body long raw NOT NULL ,
+ message_attributes long raw NOT NULL ,
last_updated date NOT NULL ,
PRIMARY KEY (repository_name, message_name)
)
@@ -266,6 +285,7 @@
remote_host varchar (255) NOT NULL ,
remote_addr varchar (20) NOT NULL ,
message_body bytea NOT NULL ,
+ message_attributes bytea NOT NULL ,
last_updated timestamp NOT NULL,
PRIMARY KEY (repository_name, message_name)
)
@@ -281,6 +301,7 @@
remote_host varchar (100) NOT NULL ,
remote_addr varchar (20) NOT NULL ,
message_body long byte NOT NULL ,
+ message_attributes long byte NOT NULL ,
last_updated date NOT NULL,
PRIMARY KEY (repository_name, message_name)
)
@@ -302,8 +323,19 @@
<!-- Statements used to update the body of a message stored in this repository. -->
<sql name="updateMessageBodySQL">UPDATE ${table} SET message_body = ? WHERE message_name = ? AND repository_name = ?</sql>
- <!-- Statements used to insert a message into this repository. -->
+ <!-- Statements used to update the attributes of a message stored in this repository. -->
+ <sql name="updateMessageAttributesSQL">UPDATE ${table} SET message_attributes = ? WHERE message_name = ? AND repository_name = ?</sql>
+
+ <!-- Statements used to insert a message into this repository.
<sql name="insertMessageSQL">INSERT INTO ${table} (message_name, repository_name, message_state, error_message, sender, recipients, remote_host, remote_addr, last_updated, message_body) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)</sql>
+ -->
+
+ <!-- Statements used to insert a message with attributes into this repository. -->
+ <sql name="insertMessageSQL">INSERT INTO ${table} (message_name,
+ repository_name, message_state, error_message, sender, recipients,
+ remote_host, remote_addr, last_updated, message_body,
+ message_attributes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)</sql>
+
<!-- Statements used to retrieve a message stored in this repository. -->
<sql name="retrieveMessageSQL">SELECT message_state, error_message, sender, recipients, remote_host, remote_addr, last_updated FROM ${table} WHERE message_name = ? AND repository_name = ?</sql>
@@ -311,6 +343,9 @@
<!-- Statements used to retrieve the body of a message stored in this repository. -->
<sql name="retrieveMessageBodySQL">SELECT message_body FROM ${table} WHERE message_name = ? AND repository_name = ?</sql>
+ <!-- Statements used to retrieve the attributes of a message stored in this repository. -->
+ <sql name="retrieveMessageAttributesSQL">SELECT message_attributes FROM ${table} WHERE message_name = ? AND repository_name = ?</sql>
+
<!-- Statements used to retrieve the size of the body of a message stored in this repository. -->
<!-- NOTE: This statement is optional and need not be implemented for a particular database to be supported. -->
<sql name="retrieveMessageBodySizeSQL" db="mssql">SELECT datalength(message_body) FROM ${table} WHERE message_name = ? AND repository_name = ?</sql>
@@ -336,6 +371,7 @@
remote_host varchar (255) NOT NULL ,
remote_addr varchar (20) NOT NULL ,
message_body varchar NOT NULL ,
+ message_attributes varchar NOT NULL ,
last_updated timestamp NOT NULL,
PRIMARY KEY (message_name, repository_name)
)
@@ -351,6 +387,7 @@
remote_host varchar (255) NOT NULL ,
remote_addr varchar (20) NOT NULL ,
message_body longblob NOT NULL ,
+ message_attributes longblob NOT NULL ,
last_updated datetime NOT NULL,
PRIMARY KEY (message_name, repository_name)
)
@@ -366,6 +403,7 @@
[remote_host] [varchar] (255) NOT NULL ,
[remote_addr] [varchar] (20) NOT NULL ,
[message_body] [image] NOT NULL ,
+ [message_attributes] [image] NOT NULL ,
[last_updated] [datetime] NOT NULL,
PRIMARY KEY (message_name, repository_name)
)
@@ -381,6 +419,7 @@
remote_host varchar2(255) NOT NULL ,
remote_addr varchar2(20) NOT NULL ,
message_body long raw NOT NULL ,
+ message_attributes long raw NOT NULL ,
last_updated date NOT NULL ,
PRIMARY KEY (message_name, repository_name)
)
@@ -396,6 +435,7 @@
remote_host varchar (255) NOT NULL ,
remote_addr varchar (20) NOT NULL ,
message_body bytea NOT NULL ,
+ message_attributes bytea NOT NULL ,
last_updated timestamp NOT NULL,
PRIMARY KEY (message_name, repository_name)
)
@@ -411,6 +451,7 @@
remote_host varchar (255) NOT NULL ,
remote_addr varchar (20) NOT NULL ,
message_body long byte NOT NULL ,
+ message_attributes long byte NOT NULL ,
last_updated date NOT NULL,
PRIMARY KEY (message_name, repository_name)
)
Index: src/java/org/apache/james/core/MailImpl.java
===================================================================
RCS file: /home/cvspublic/jakarta-james/src/java/org/apache/james/core/MailImpl.java,v
retrieving revision 1.25
diff -u -w -b -r1.25 MailImpl.java
--- src/java/org/apache/james/core/MailImpl.java 26 Apr 2003 10:00:54 -0000 1.25
+++ src/java/org/apache/james/core/MailImpl.java 25 Jun 2003 13:26:18 -0000
@@ -569,6 +569,30 @@
}
/**
+ * This method is necessary, when Mail repositories needs to deal
+ * explicitly with storing Mail attributes as a Serializable
+ * Note: This method is not exposed in the Mail interface,
+ * it is for internal use by James only.
+ * @return Serializable of the entire attributes collection
+ **/
+ public HashMap getAttributesRaw ()
+ {
+ return attributes;
+ }
+
+ /**
+ * This method is necessary, when Mail repositories needs to deal
+ * explicitly with retriving Mail attributes as a Serializable
+ * Note: This method is not exposed in the Mail interface,
+ * it is for internal use by James only.
+ * @return Serializable of the entire attributes collection
+ **/
+ public void setAttributesRaw (HashMap attr)
+ {
+ this.attributes = (attr == null) ? new HashMap() : attr;
+ }
+
+ /**
* @see org.apache.mailet.Mail#getAttribute(String)
*/
public Serializable getAttribute(String key) {
@@ -587,9 +611,21 @@
return (Serializable)attributes.remove(key);
}
/**
+ * @see org.apache.mailet.Mail#removeAllAttributes()
+ */
+ public void removeAllAttributes() {
+ attributes.clear();
+ }
+ /**
* @see org.apache.mailet.Mail#getAttributeNames()
*/
public Iterator getAttributeNames() {
return attributes.keySet().iterator();
+ }
+ /**
+ * @see org.apache.mailet.Mail#hasAttributes()
+ */
+ public boolean hasAttributes() {
+ return !attributes.isEmpty();
}
}
Index: src/java/org/apache/james/mailrepository/JDBCMailRepository.java
===================================================================
RCS file: /home/cvspublic/jakarta-james/src/java/org/apache/james/mailrepository/JDBCMailRepository.java,v
retrieving revision 1.44
diff -u -w -b -r1.44 JDBCMailRepository.java
--- src/java/org/apache/james/mailrepository/JDBCMailRepository.java 1 Jun 2003 00:02:49 -0000 1.44
+++ src/java/org/apache/james/mailrepository/JDBCMailRepository.java 25 Jun 2003 13:26:18 -0000
@@ -62,6 +62,8 @@
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
@@ -550,6 +552,43 @@
theJDBCUtil.closeJDBCStatement(localUpdateMessage);
}
+ //Determine whether attribues are used and available for storing
+ //Do we have updateMessageAttributesSQL?
+ String updateMessageAttrSql =
+ sqlQueries.getSqlString("updateMessageAttributesSQL", false);
+ if (updateMessageAttrSql!=null && mc.hasAttributes()) {
+ PreparedStatement updateMessageAttr = null;
+ try {
+ updateMessageAttr =
+ conn.prepareStatement(updateMessageAttrSql);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ try {
+ oos.writeObject(((MailImpl)mc).getAttributesRaw());
+ oos.flush();
+ ByteArrayInputStream attrInputStream =
+ new ByteArrayInputStream(baos.toByteArray());
+ updateMessageAttr.setBinaryStream(1, attrInputStream, baos.size());
+ } finally {
+ try {
+ if (oos != null) {
+ oos.close();
+ }
+ } catch (IOException ioe) {
+ getLogger().debug("JDBCMailRepository: Unexpected exception while closing output stream.");
+ }
+ }
+ updateMessageAttr.setString(2, mc.getName());
+ updateMessageAttr.setString(3, repositoryName);
+ updateMessageAttr.execute();
+ } catch (SQLException sqle) {
+ getLogger().info("JDBCMailRepository: Trying to update mail attributes failed.",sqle);
+
+ } finally {
+ theJDBCUtil.closeJDBCStatement(updateMessageAttr);
+ }
+ }
+
//Determine whether the message body has changed, and possibly avoid
// updating the database.
MimeMessage messageBody = mc.getMessage();
@@ -598,8 +637,10 @@
//Insert the record into the database
PreparedStatement insertMessage = null;
try {
+ String insertMessageSQL = sqlQueries.getSqlString("insertMessageSQL", true);
+ int number_of_parameters = getNumberOfParameters (insertMessageSQL);
insertMessage =
- conn.prepareStatement(sqlQueries.getSqlString("insertMessageSQL", true));
+ conn.prepareStatement(insertMessageSQL);
insertMessage.setString(1, mc.getName());
insertMessage.setString(2, repositoryName);
insertMessage.setString(3, mc.getState());
@@ -644,6 +685,28 @@
closeOutputStreams(headerOut, bodyOut);
}
//Store the headers in the database
+
+ //Store attributes
+ if (number_of_parameters > 10) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ try {
+ oos.writeObject(((MailImpl)mc).getAttributesRaw());
+ oos.flush();
+ ByteArrayInputStream attrInputStream =
+ new ByteArrayInputStream(baos.toByteArray());
+ insertMessage.setBinaryStream(11, attrInputStream, baos.size());
+ } finally {
+ try {
+ if (oos != null) {
+ oos.close();
+ }
+ } catch (IOException ioe) {
+ getLogger().debug("JDBCMailRepository: Unexpected exception while closing output stream.");
+ }
+ }
+ }
+
insertMessage.execute();
} finally {
theJDBCUtil.closeJDBCStatement(insertMessage);
@@ -705,7 +768,68 @@
}
return null;
}
+ //Determine whether attribues are used and retrieve them
+ //Do we have retrieveAttributesSQL?
+ String retrieveMessageAttrSql =
+ sqlQueries.getSqlString("retrieveMessageAttributesSQL", false);
+ PreparedStatement retrieveMessageAttr = null;
+ HashMap attributes = null;
+ if (retrieveMessageAttrSql!=null) {
+ ResultSet rsMessageAttr = null;
+ try {
+ retrieveMessageAttr =
+ conn.prepareStatement(retrieveMessageAttrSql);
+
+ retrieveMessageAttr.setString(1, key);
+ retrieveMessageAttr.setString(2, repositoryName);
+ rsMessageAttr = retrieveMessageAttr.executeQuery();
+
+ if (rsMessageAttr.next()) {
+ try {
+ byte[] serialized_attr = rsMessageAttr.getBytes(1);
+ ByteArrayInputStream bais = new ByteArrayInputStream (serialized_attr);
+ ObjectInputStream ois = new ObjectInputStream (bais);
+ attributes = (HashMap)ois.readObject();
+ ois.close();
+ } catch (IOException ioe) {
+ if (getLogger().isDebugEnabled()) {
+ StringBuffer debugBuffer =
+ new StringBuffer(64)
+ .append("Exception reading attributes ")
+ .append(key)
+ .append(" in ")
+ .append(repositoryName);
+ getLogger().debug(debugBuffer.toString(), ioe);
+ }
+ }
+ } else {
+ if (getLogger().isDebugEnabled()) {
+ StringBuffer debugBuffer =
+ new StringBuffer(64)
+ .append("Did not find a record (attributes) ")
+ .append(key)
+ .append(" in ")
+ .append(repositoryName);
+ getLogger().debug(debugBuffer.toString());
+ }
+ }
+ } catch (SQLException sqle) {
+ synchronized (System.err) {
+ System.err.println("Error retrieving message");
+ System.err.println(sqle.getMessage());
+ System.err.println(sqle.getErrorCode());
+ System.err.println(sqle.getSQLState());
+ System.err.println(sqle.getNextException());
+ sqle.printStackTrace();
+ }
+ } finally {
+ theJDBCUtil.closeJDBCResultSet(rsMessageAttr);
+ theJDBCUtil.closeJDBCStatement(retrieveMessageAttr);
+ }
+ }
+
MailImpl mc = new MailImpl();
+ mc.setAttributesRaw (attributes);
mc.setName(key);
mc.setState(rsMessage.getString(1));
mc.setErrorMessage(rsMessage.getString(2));
@@ -845,6 +969,7 @@
((repository.repositoryName == repositoryName) || ((repository.repositoryName != null) && repository.repositoryName.equals(repositoryName)));
}
+
/**
* Provide a hash code that is consistent with equals for this class
*
@@ -860,6 +985,23 @@
}
return result;
}
+
+ /**
+ * This method calculates number of parameters in a prepared statement SQL String.
+ * It does so by counting the number of '?' in the string
+ * @param sqlstring to return parameter count for
+ * @return number of parameters
+ **/
+ private int getNumberOfParameters (String sqlstring) {
+ //it is alas a java 1.4 feature to be able to call
+ //getParameterMetaData which could provide us with the parameterCount
+ char[] chars = sqlstring.toCharArray();
+ int count = 0;
+ for (int i = 0; i < chars.length; i++) {
+ count += chars[i]=='?' ? 1 : 0;
+ }
+ return count;
+ }
/**
* Closes output streams used to update message
Index: src/java/org/apache/mailet/Mail.java
===================================================================
RCS file: /home/cvspublic/jakarta-james/src/java/org/apache/mailet/Mail.java,v
retrieving revision 1.9
diff -u -w -b -r1.9 Mail.java
--- src/java/org/apache/mailet/Mail.java 26 Apr 2003 10:00:55 -0000 1.9
+++ src/java/org/apache/mailet/Mail.java 25 Jun 2003 13:26:19 -0000
@@ -189,6 +189,10 @@
*/
Iterator getAttributeNames();
/**
+ * @return true if this Mail instance has any attributes set.
+ **/
+ boolean hasAttributes();
+ /**
* Removes the attribute with the given name from this Mail instance. After
* removal, subsequent calls to getAttribute(java.lang.String) to retrieve
* the attribute's value will return null.
@@ -199,6 +203,10 @@
* was bound to the name)
*/
Serializable removeAttribute(String name);
+ /**
+ * Removes all the attributes associated with this Mail instance.
+ **/
+ void removeAllAttributes();
/**
* Binds an object to a given attribute name in this Mail instance. If the name
* specified is already used for an attribute, this method will remove the old
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]