diff --git a/conf-sso/sp/dynamo.xml b/conf-sso/sp/dynamo.xml index 80a898d..e140cf5 100644 --- a/conf-sso/sp/dynamo.xml +++ b/conf-sso/sp/dynamo.xml @@ -94,6 +94,13 @@ + + + + + + + diff --git a/conf/dynamo-venice.xml b/conf/dynamo-venice.xml index 68a9812..945cddf 100644 --- a/conf/dynamo-venice.xml +++ b/conf/dynamo-venice.xml @@ -93,6 +93,13 @@ + + + + + + + diff --git a/conf/venice-db-init-mysql.sql b/conf/venice-db-init-mysql.sql index a404317..ffaebab 100644 --- a/conf/venice-db-init-mysql.sql +++ b/conf/venice-db-init-mysql.sql @@ -274,7 +274,7 @@ CREATE TABLE us_text ( last_read DATETIME, # timestamp of when it was last read data MEDIUMTEXT, # the text (16 Mb available) PRIMARY KEY (msgid, part), - INDEX by_name (msgid, ident_nsid, ident_name) + UNIQUE INDEX by_name (msgid, ident_nsid, ident_name) ); # UniStore: Text message part properties @@ -300,7 +300,7 @@ CREATE TABLE us_binary ( last_read DATETIME, # timestamp of when it was last read data MEDIUMBLOB, # the actual data (16 Mb of space available) PRIMARY KEY (msgid, part), - INDEX by_name (msgid, ident_nsid, ident_name) + UNIQUE INDEX by_name (msgid, ident_nsid, ident_name) ); # UniStore: Binary message part properties diff --git a/src/baseutil/com/silverwrist/util/CacheInputStream.java b/src/baseutil/com/silverwrist/util/CacheInputStream.java new file mode 100644 index 0000000..512bae3 --- /dev/null +++ b/src/baseutil/com/silverwrist/util/CacheInputStream.java @@ -0,0 +1,148 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.util; + +import java.io.*; + +public class CacheInputStream extends FilterInputStream +{ + /*--------------------------------------------------------------------------- + * Static data members + *--------------------------------------------------------------------------- + */ + + private static final int MAX_MEMORY = 65536; + + /*--------------------------------------------------------------------------- + * Attributes + *--------------------------------------------------------------------------- + */ + + private File m_tempfile = null; + private int m_length = 0; + + /*--------------------------------------------------------------------------- + * Constructor + *--------------------------------------------------------------------------- + */ + + public CacheInputStream(String temp_prefix, InputStream data) throws IOException + { + super(new ByteArrayInputStream(new byte[0])); // dummy value + + boolean complete = false; + OutputStream imstm = null; + try + { // Copy data to a temporary stream. + ByteArrayOutputStream imstm_byte = new ByteArrayOutputStream(); + imstm = imstm_byte; + byte[] buf = new byte[4096]; + int rd = data.read(buf); + while (rd>=0) + { // a simple copy loop, but with a twist + if (rd>0) + { // if we go over memory limits, we'll have to create a tempfile + // and spill there... + if ((imstm_byte!=null) && ((rd + m_length)>MAX_MEMORY)) + { // get the source for the copy + ByteArrayInputStream copy_src = + new ByteArrayInputStream(imstm_byte.toByteArray()); + + // get the destination for the copy + m_tempfile = File.createTempFile(temp_prefix,null); + imstm = new FileOutputStream(m_tempfile); + + // copy it and close the byte stream + IOUtils.copy(copy_src,imstm); + IOUtils.shutdown(copy_src); + IOUtils.shutdown(imstm_byte); + imstm_byte = null; + + } // end if + + // write data to the intermediate stream + imstm.write(buf,0,rd); + m_length += rd; + + } // end if + + rd = data.read(buf); + + } // end while + + if (imstm_byte!=null) + this.in = new ByteArrayInputStream(imstm_byte.toByteArray()); + else + { // close the file output stream, create a file input stream + IOUtils.shutdown(imstm); + imstm = null; + this.in = new FileInputStream(m_tempfile); + + } // end else + + complete = true; + + } // end try + finally + { // close down the intermediate stream + IOUtils.shutdown(imstm); + if (!complete && (m_tempfile!=null)) + { // delete the temporary file + m_tempfile.delete(); + m_tempfile = null; + + } // end if + + } // end finally + + } // end constructor + + /*--------------------------------------------------------------------------- + * Overrides from class FilterInputStream + *--------------------------------------------------------------------------- + */ + + public void close() throws IOException + { + try + { // call through and close the stream + super.close(); + + } // end try + finally + { // delete the temp file as well + if (m_tempfile!=null) + m_tempfile.delete(); + m_tempfile = null; + + } // end finally + + } // end close + + /*--------------------------------------------------------------------------- + * External operations + *--------------------------------------------------------------------------- + */ + + int getLength() + { + return m_length; + + } // end getLength + +} // end class CacheInputStream diff --git a/src/dynamo-framework/com/silverwrist/dynamo/Namespaces.java b/src/dynamo-framework/com/silverwrist/dynamo/Namespaces.java index 67f3123..5ee1964 100644 --- a/src/dynamo-framework/com/silverwrist/dynamo/Namespaces.java +++ b/src/dynamo-framework/com/silverwrist/dynamo/Namespaces.java @@ -86,4 +86,10 @@ public interface Namespaces public static final String SPELLCHECKER_PROPERTIES_NAMESPACE = "http://www.silverwrist.com/NS/dynamo/2003/06/07/spellchecker.properties"; + /** + * Namespace for the permissions for the Universal Message Store (UniStore). + */ + public static final String UNISTORE_PERMISSIONS_NAMESPACE = + "http://www.silverwrist.com/NS/dynamo/2003/06/10/unistore.permissions"; + } // end interface Namespaces diff --git a/src/dynamo-framework/com/silverwrist/dynamo/dict/supplemental.dict b/src/dynamo-framework/com/silverwrist/dynamo/dict/supplemental.dict index 890b0ec..1633f4a 100644 --- a/src/dynamo-framework/com/silverwrist/dynamo/dict/supplemental.dict +++ b/src/dynamo-framework/com/silverwrist/dynamo/dict/supplemental.dict @@ -3,6 +3,7 @@ advogato ain't anime anla'shok +avaltus bajor bios boitano @@ -22,6 +23,7 @@ cst deflector deflectors delenn +denise didn't dilithium docking @@ -39,10 +41,12 @@ faux fett followup franklin +fsck fucking gamey hairstyle hairstyles +harasser hasn't haven't he'd @@ -52,6 +56,7 @@ i'd i'll i'm i've +imho inducers it'd khan @@ -86,6 +91,7 @@ privs propping psi pst +quid refit refitting replicator @@ -115,6 +121,7 @@ starfleet starship straightening stunted +tarred terrence they're turbolift @@ -126,6 +133,7 @@ url utne valen veni +wasn't we'll we're we've diff --git a/src/dynamo-framework/com/silverwrist/dynamo/iface/UniStore.java b/src/dynamo-framework/com/silverwrist/dynamo/iface/UniStore.java new file mode 100644 index 0000000..70a65b6 --- /dev/null +++ b/src/dynamo-framework/com/silverwrist/dynamo/iface/UniStore.java @@ -0,0 +1,26 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.dynamo.iface; + +import com.silverwrist.dynamo.except.DatabaseException; + +public interface UniStore +{ + public UniStoreMessage getMessage(long msgid) throws DatabaseException; + +} // end interface UniStore diff --git a/src/dynamo-framework/com/silverwrist/dynamo/iface/UniStoreTextPart.java b/src/dynamo-framework/com/silverwrist/dynamo/iface/UniStoreTextPart.java index 4126da5..243327d 100644 --- a/src/dynamo-framework/com/silverwrist/dynamo/iface/UniStoreTextPart.java +++ b/src/dynamo-framework/com/silverwrist/dynamo/iface/UniStoreTextPart.java @@ -18,13 +18,14 @@ package com.silverwrist.dynamo.iface; import java.io.Reader; +import com.silverwrist.dynamo.except.DatabaseException; public interface UniStoreTextPart extends UniStorePart { public int getLineCount(); - public String getText(); + public String getText() throws DatabaseException; - public Reader getTextAsReader(); + public Reader getTextAsReader() throws DatabaseException; } // end interface UniStoreTextPart diff --git a/src/dynamo-framework/com/silverwrist/dynamo/unistore/BinaryPartImpl.java b/src/dynamo-framework/com/silverwrist/dynamo/unistore/BinaryPartImpl.java new file mode 100644 index 0000000..ea5b185 --- /dev/null +++ b/src/dynamo-framework/com/silverwrist/dynamo/unistore/BinaryPartImpl.java @@ -0,0 +1,454 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.dynamo.unistore; + +import java.io.*; +import java.sql.Blob; +import java.sql.SQLException; +import java.util.*; +import org.apache.commons.collections.*; +import com.silverwrist.dynamo.db.NamespaceCache; +import com.silverwrist.dynamo.except.*; +import com.silverwrist.dynamo.iface.*; +import com.silverwrist.dynamo.util.*; + +class BinaryPartImpl implements UniStoreBinaryPart +{ + /*-------------------------------------------------------------------------------- + * Internal class implementing a Blob return + *-------------------------------------------------------------------------------- + */ + + private class ReturnBlob implements Blob + { + /*==================================================================== + * Attributes + *==================================================================== + */ + + private byte[] m_data; // the actual blob data + + /*==================================================================== + * Constructor + *==================================================================== + */ + + ReturnBlob(byte[] data) + { + m_data = data; + + } // end constructor + + /*==================================================================== + * Implementations from interface Blob + *==================================================================== + */ + + public long length() + { + return m_size; + + } // end length + + public byte[] getBytes(long pos, int length) throws SQLException + { + if ((pos<1) || (pos>(long)m_size)) + throw new SQLException("invalid position value"); + if ((length<=0) || ((pos + length - 1)>(long)m_size)) + throw new SQLException("invalid length value"); + byte[] rc = new byte[length]; + System.arraycopy(m_data,(int)pos,rc,0,length); + return rc; + + } // end getBytes + + public InputStream getBinaryStream() + { + return new ByteArrayInputStream(m_data); + + } // end getBinaryStream + + public long position(byte[] pattern, long start) throws SQLException + { + throw new SQLException("position() method not implemented"); + + } // end position + + public long position(Blob pattern, long start) throws SQLException + { + throw new SQLException("position() method not implemented"); + + } // end position + + public int setBytes(long pos, byte[] bytes) throws SQLException + { + throw new SQLException("setBytes() method not implemented"); + + } // end setBytes + + public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException + { + throw new SQLException("setBytes() method not implemented"); + + } // end setBytes + + public OutputStream setBinaryStream(long pos) throws SQLException + { + throw new SQLException("setBinaryStream() method not implemented"); + + } // end setBinaryStream + + public void truncate(long len) throws SQLException + { + throw new SQLException("truncate() method not implemented"); + + } // end truncate + + } // end class ReturnBlob + + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private BinaryPartOps m_ops; + private NamespaceCache m_nscache; + private MessageImpl m_parent; + private int m_part; + private QualifiedNameKey m_identity; + private String m_mimetype; + private int m_size; + private String m_filename; + private int m_nread; + private java.util.Date m_lastread; + private ReferenceMap m_properties; + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + BinaryPartImpl(BinaryPartOps ops, NamespaceCache nscache, MessageImpl parent, Map params) throws DatabaseException + { + m_ops = ops; + m_nscache = nscache; + m_parent = parent; + m_part = ((Integer)(params.get(MessageOps.PARAM_PART))).intValue(); + PropertyKey pk = (PropertyKey)(params.get(MessageOps.PARAM_IDENTITY)); + m_identity = new QualifiedNameKey(nscache.namespaceIdToName(pk.getNamespaceID()),pk.getName()); + m_mimetype = (String)(params.get(MessageOps.PARAM_MIMETYPE)); + Integer tmp = (Integer)(params.get(MessageOps.PARAM_SIZE)); + if (tmp!=null) + m_size = tmp.intValue(); + m_filename = (String)(params.get(MessageOps.PARAM_FILENAME)); + m_nread = ((Integer)(params.get(MessageOps.PARAM_READS))).intValue(); + m_lastread = (java.util.Date)(params.get(MessageOps.PARAM_LASTREAD)); + m_properties = new ReferenceMap(ReferenceMap.HARD,ReferenceMap.SOFT); + + } // end constructor + + /*-------------------------------------------------------------------------------- + * Implementations from interface ObjectProvider + *-------------------------------------------------------------------------------- + */ + + /** + * Retrieves an object from this ObjectProvider. + * + * @param namespace The namespace to interpret the name relative to. + * @param name The name of the object to be retrieved. + * @return The object reference specified. + */ + public Object getObject(String namespace, String name) + { + try + { // convert the namespace name to an ID here + PropertyKey key = new PropertyKey(m_nscache.namespaceNameToId(namespace),name); + Object rc = null; + synchronized (this) + { // start by looking in the properties map + rc = m_properties.get(key); + if (rc==null) + { // no use - need to try the database + rc = m_ops.getProperty(m_parent.getMessageID(),m_part,key); + if (rc!=null) + m_properties.put(key,rc); + + } // end if + + } // end synchronized block + + if (rc==null) + throw new NoSuchObjectException(this.toString(),namespace,name); + return rc; + + } // end try + catch (DatabaseException e) + { // translate into our NoSuchObjectException but retain the DatabaseException + throw new NoSuchObjectException(this.toString(),namespace,name,e); + + } // end catch + + } // end getObject + + /*-------------------------------------------------------------------------------- + * Implementations from interface SecureObjectStore + *-------------------------------------------------------------------------------- + */ + + /** + * Sets an object into this SecureObjectStore. + * + * @param caller The user performing the operation. + * @param namespace The namespace to interpret the name relative to. + * @param name The name of the object to be set. + * @param value The object to set into the SecureObjectStore. + * @return The previous object that was set into the SecureObjectStore under this namespace and name, or + * null if there was no such object. + * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error setting the object value. + * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to + * set this object value into this SecureObjectStore. + */ + public Object setObject(DynamoUser caller, String namespace, String name, Object value) + throws DatabaseException, DynamoSecurityException + { + m_parent.testPermission(caller,namespace,"set.property","no.setProperty"); + Object rc = null; + // convert the namespace name to an ID here + PropertyKey key = new PropertyKey(m_nscache.namespaceNameToId(namespace),name); + synchronized (this) + { // start by setting the database value + rc = m_ops.setProperty(m_parent.getMessageID(),m_part,key,value); + + // and cache it, too + m_properties.put(key,value); + + } // end synchronized block + + // TODO: m_post.postUpdate(new GlobalPropertyUpdateEvent(this,namespace,name)); + return rc; + + } // end setObject + + /** + * Removes an object from this SecureObjectStore. + * + * @param caller The user performing the operation. + * @param namespace The namespace to interpret the name relative to. + * @param name The name of the object to be removed. + * @return The previous object that was set into the SecureObjectStore under this namespace and name, or + * null if there was no such object. + * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error removing the object value. + * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to + * remove this object value from this SecureObjectStore. + */ + public Object removeObject(DynamoUser caller, String namespace, String name) + throws DatabaseException, DynamoSecurityException + { + m_parent.testPermission(caller,namespace,"remove.property","no.removeProperty"); + Object rc = null; + // convert the namespace name to an ID here + PropertyKey key = new PropertyKey(m_nscache.namespaceNameToId(namespace),name); + synchronized (this) + { // start by killing the database value + rc = m_ops.removeProperty(m_parent.getMessageID(),m_part,key); + + // and remove the cached value, too + m_properties.remove(key); + + } // end synchronized block + + // TODO: m_post.postUpdate(new GlobalPropertyUpdateEvent(this,namespace,name)); + return rc; + + } // end removeObject + + /** + * Returns a collection of all object namespaces that have been set into this SecureObjectStore. + * + * @return A {@link java.util.Collection Collection} containing {@link java.lang.String String} objects specifying + * all the object namespaces. + * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the namespace list. + */ + public Collection getNamespaces() throws DatabaseException + { + // call through to the database to get the list of namespace IDs + int[] ids = m_ops.getPropertyNamespaceIDs(m_parent.getMessageID(),m_part); + + ArrayList rc = new ArrayList(ids.length); + for (int i=0; iSecureObjectStore under + * a given namespace. + * + * @param namespace The namespace to look for names under. + * @return A {@link java.util.Collection Collection} containing {@link java.lang.String String} objects + * specifying all the object names for this namespace. + * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the object name list. + */ + public Collection getNamesForNamespace(String namespace) throws DatabaseException + { + // call through to the database to get the data for this namespace + int nsid = m_nscache.namespaceNameToId(namespace); + Map data = m_ops.getAllProperties(m_parent.getMessageID(),m_part,nsid); + + // we both create the return value and cache the data values + ArrayList rc = new ArrayList(data.size()); + synchronized (this) + { // do the transfer... + Iterator it = data.entrySet().iterator(); + while (it.hasNext()) + { // copy one entry at a time + Map.Entry ntry = (Map.Entry)(it.next()); + rc.add(ntry.getKey().toString()); + m_properties.put(new PropertyKey(nsid,ntry.getKey().toString()),ntry.getValue()); + + } // end while + + } // end synchronized block + + return Collections.unmodifiableList(rc); + + } // end getNamesForNamespace + + /*-------------------------------------------------------------------------------- + * Implementations from interface UniStorePart + *-------------------------------------------------------------------------------- + */ + + public long getMessageID() + { + return m_parent.getMessageID(); + + } // end getMessageID + + public int getPartIndex() + { + return m_part; + + } // end getPartIndex + + public QualifiedNameKey getPartIdentity() + { + return m_identity; + + } // end getPartIdentity + + public String getMimeType() + { + return m_mimetype; + + } // end getMimeType + + public int getSize() + { + return m_size; + + } // end getSize + + public int getNumReads() + { + return m_nread; + + } // end getNumReads + + public java.util.Date getLastReadDate() + { + return m_lastread; + + } // end getLastReadDate + + public void touchRead() throws DatabaseException + { + synchronized (this) + { // touch the database, then the local values + java.util.Date tmp = m_ops.touchRead(m_parent.getMessageID(),m_part); + m_nread++; + m_lastread = tmp; + + } // end synchronized block + + // TODO: post an update? + + } // end touchRead + + /*-------------------------------------------------------------------------------- + * Implementations from interface DataItem + *-------------------------------------------------------------------------------- + */ + + public String getName() + { + return m_filename; + + } // end getName + + public InputStream getDataStream() throws IOException + { + try + { // call through to the database to get the data stream + return m_ops.getData(m_parent.getMessageID(),m_part); + + } // end try + catch (DatabaseException e) + { // create an IOException and chain this one onto it + IOException ioe = new IOException("Database error retrieving data stream"); + ioe.initCause(e); + throw ioe; + + } // end catch + + } // end getDataStream + + public Blob getBlob() throws SQLException + { + try + { // load the data from the database and create the Blob around it + byte[] data = new byte[m_size]; + m_ops.getData(m_parent.getMessageID(),m_part,data); + return new ReturnBlob(data); + + } // end try + catch (DatabaseException e) + { // create a SQLException and chain this one onto it + SQLException se = new SQLException("Database error retrieving data stream"); + se.initCause(e); + throw se; + + } // end catch + catch (IOException e) + { // create a SQLException and chain this one onto it + SQLException se = new SQLException("I/O error retrieving data stream"); + se.initCause(e); + throw se; + + } // end catch + + } // end getBlob + + /*-------------------------------------------------------------------------------- + * Implementations from interface UniStoreBinaryPart + *-------------------------------------------------------------------------------- + */ + +} // end class BinaryPartImpl diff --git a/src/dynamo-framework/com/silverwrist/dynamo/unistore/BinaryPartOps.java b/src/dynamo-framework/com/silverwrist/dynamo/unistore/BinaryPartOps.java new file mode 100644 index 0000000..50e63a5 --- /dev/null +++ b/src/dynamo-framework/com/silverwrist/dynamo/unistore/BinaryPartOps.java @@ -0,0 +1,62 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.dynamo.unistore; + +import java.io.*; +import java.util.*; +import com.silverwrist.util.*; +import com.silverwrist.dynamo.db.OpsBase; +import com.silverwrist.dynamo.except.*; +import com.silverwrist.dynamo.iface.*; +import com.silverwrist.dynamo.util.*; + +abstract class BinaryPartOps extends OpsBase +{ + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + protected BinaryPartOps(DBConnectionPool pool) + { + super(pool); + + } // end constructor + + /*-------------------------------------------------------------------------------- + * Abstract operations + *-------------------------------------------------------------------------------- + */ + + abstract Object getProperty(long msgid, int part, PropertyKey key) throws DatabaseException; + + abstract Object setProperty(long msgid, int part, PropertyKey key, Object value) throws DatabaseException; + + abstract Object removeProperty(long msgid, int part, PropertyKey key) throws DatabaseException; + + abstract int[] getPropertyNamespaceIDs(long msgid, int part) throws DatabaseException; + + abstract Map getAllProperties(long msgid, int part, int namespace) throws DatabaseException; + + abstract java.util.Date touchRead(long msgid, int part) throws DatabaseException; + + abstract CacheInputStream getData(long msgid, int part) throws IOException, DatabaseException; + + abstract int getData(long msgid, int part, byte[] here) throws IOException, DatabaseException; + +} // end class BinaryPartOps diff --git a/src/dynamo-framework/com/silverwrist/dynamo/unistore/BinaryPartOps_mysql.java b/src/dynamo-framework/com/silverwrist/dynamo/unistore/BinaryPartOps_mysql.java new file mode 100644 index 0000000..c55e1c2 --- /dev/null +++ b/src/dynamo-framework/com/silverwrist/dynamo/unistore/BinaryPartOps_mysql.java @@ -0,0 +1,506 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.dynamo.unistore; + +import java.io.*; +import java.sql.*; +import java.util.*; +import com.silverwrist.util.*; +import com.silverwrist.dynamo.except.*; +import com.silverwrist.dynamo.iface.*; +import com.silverwrist.dynamo.util.*; + +class BinaryPartOps_mysql extends BinaryPartOps +{ + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private PropertySerializer m_psz; // reference to property serializer + private DBUtilities m_utils; + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + BinaryPartOps_mysql(DBConnectionPool pool) + { + super(pool); + m_psz = (PropertySerializer)(pool.queryService(PropertySerializer.class)); + m_utils = (DBUtilities)(pool.queryService(DBUtilities.class)); + + } // end constructor + + /*-------------------------------------------------------------------------------- + * Overrides from class OpsBase + *-------------------------------------------------------------------------------- + */ + + public void dispose() + { + m_psz = null; + m_utils = null; + super.dispose(); + + } // end dispose + + /*-------------------------------------------------------------------------------- + * Abstract implementations from class BinaryPartOps + *-------------------------------------------------------------------------------- + */ + + Object getProperty(long msgid, int part, PropertyKey key) throws DatabaseException + { + Connection conn = null; + PreparedStatement stmt = null; + ResultSet rs = null; + String rc_str = null; + try + { // get a connection + conn = getConnection(); + + // look up the property + stmt = conn.prepareStatement("SELECT prop_value FROM us_binary_prop WHERE msgid = ? AND part = ? AND nsid = ? " + + "AND prop_name = ?;"); + stmt.setLong(1,msgid); + stmt.setInt(2,part); + stmt.setInt(3,key.getNamespaceID()); + stmt.setString(4,key.getName()); + rs = stmt.executeQuery(); + if (!(rs.next())) + return null; // property not found + + rc_str = rs.getString(1); + + } // end try + catch (SQLException e) + { // translate to a general DatabaseException + throw generalException(e); + + } // end catch + finally + { // shut everything down + SQLUtils.shutdown(rs); + SQLUtils.shutdown(stmt); + SQLUtils.shutdown(conn); + + } // end finally + + // Deserialize the property value. + Object rc = m_psz.deserializeProperty(rc_str); + if (rc!=null) + return rc; + + // deserialization exception - throw it + DatabaseException de = new DatabaseException(BinaryPartOps_mysql.class,"UniStoreMessages","property.deserialize"); + de.setParameter(0,key.getName()); + throw de; + + } // end getProperty + + Object setProperty(long msgid, int part, PropertyKey key, Object value) throws DatabaseException + { + String serialized_value = m_psz.serializeProperty(value); + if (serialized_value==null) + { // serialization exception - throw it + DatabaseException de = new DatabaseException(BinaryPartOps_mysql.class,"UniStoreMessages","property.serialize"); + de.setParameter(0,key.getName()); + throw de; + + } // end if + + String old_value = null; + Connection conn = null; + PreparedStatement stmt = null; + Statement stmt2 = null; + ResultSet rs = null; + try + { // get a connection + conn = getConnection(); + + // lock the table + stmt2 = conn.createStatement(); + stmt2.executeUpdate("LOCK TABLES us_binary_prop WRITE;"); + + // look to see if the property value is already there + stmt = conn.prepareStatement("SELECT prop_value FROM us_binary_prop WHERE msgid = ? AND part = ? AND nsid = ? " + + "AND prop_name = ?;"); + stmt.setLong(1,msgid); + stmt.setInt(2,part); + stmt.setInt(3,key.getNamespaceID()); + stmt.setString(4,key.getName()); + rs = stmt.executeQuery(); + if (rs.next()) + old_value = rs.getString(1); + SQLUtils.shutdown(rs); + rs = null; + SQLUtils.shutdown(stmt); + + if (old_value!=null) + { // prepare the statement to update the existing record + stmt = conn.prepareStatement("UPDATE us_binary_prop SET prop_value = ? WHERE msgid = ? AND part = ? " + + "AND nsid = ? AND prop_name = ?;"); + stmt.setString(1,serialized_value); + stmt.setLong(2,msgid); + stmt.setInt(3,part); + stmt.setInt(4,key.getNamespaceID()); + stmt.setString(5,key.getName()); + + } // end if + else + { // prepare the statement to insert a new record + stmt = conn.prepareStatement("INSERT INTO us_binary_prop (msgid, part, nsid, prop_name, prop_value) " + + "VALUES (?, ?, ?, ?, ?);"); + stmt.setLong(1,msgid); + stmt.setInt(2,part); + stmt.setInt(3,key.getNamespaceID()); + stmt.setString(4,key.getName()); + stmt.setString(5,serialized_value); + + } // end else + + stmt.executeUpdate(); // execute it! + + } // end try + catch (SQLException e) + { // translate to a general DatabaseException + throw generalException(e); + + } // end catch + finally + { // shut everything down + MySQLUtils.unlockTables(conn); + SQLUtils.shutdown(rs); + SQLUtils.shutdown(stmt); + SQLUtils.shutdown(stmt2); + SQLUtils.shutdown(conn); + + } // end finally + + if (old_value==null) + return null; // no previous value + + // Deserialize the property value. + Object rc = m_psz.deserializeProperty(old_value); + if (rc!=null) + return rc; + + // deserialization exception - throw it + DatabaseException de = new DatabaseException(BinaryPartOps_mysql.class,"UniStoreMessages","property.deserialize"); + de.setParameter(0,key.getName()); + throw de; + + } // end setProperty + + Object removeProperty(long msgid, int part, PropertyKey key) throws DatabaseException + { + String old_value = null; + Connection conn = null; + PreparedStatement stmt = null; + Statement stmt2 = null; + ResultSet rs = null; + try + { // get a connection + conn = getConnection(); + + // lock the table + stmt2 = conn.createStatement(); + stmt2.executeUpdate("LOCK TABLES us_binary_prop WRITE;"); + + // look to see if the property value is already there + stmt = conn.prepareStatement("SELECT prop_value FROM us_binary_prop WHERE msgid = ? AND part = ? AND nsid = ? " + + "AND prop_name = ?;"); + stmt.setLong(1,msgid); + stmt.setInt(2,part); + stmt.setInt(3,key.getNamespaceID()); + stmt.setString(4,key.getName()); + rs = stmt.executeQuery(); + if (rs.next()) + old_value = rs.getString(1); + else + return null; // no need to remove anything + SQLUtils.shutdown(rs); + rs = null; + SQLUtils.shutdown(stmt); + + // delete the database row + stmt = conn.prepareStatement("DELETE FROM us_binary_prop WHERE msgid = ? AND part = ? AND nsid = ? " + + "AND prop_name = ?;"); + stmt.setLong(1,msgid); + stmt.setInt(2,part); + stmt.setInt(3,key.getNamespaceID()); + stmt.setString(4,key.getName()); + stmt.executeUpdate(); + + } // end try + catch (SQLException e) + { // translate to a general DatabaseException + throw generalException(e); + + } // end catch + finally + { // shut everything down + MySQLUtils.unlockTables(conn); + SQLUtils.shutdown(rs); + SQLUtils.shutdown(stmt); + SQLUtils.shutdown(stmt2); + SQLUtils.shutdown(conn); + + } // end finally + + // Deserialize the property value. + Object rc = m_psz.deserializeProperty(old_value); + if (rc!=null) + return rc; + + // deserialization exception - throw it + DatabaseException de = new DatabaseException(BinaryPartOps_mysql.class,"UniStoreMessages","property.deserialize"); + de.setParameter(0,key.getName()); + throw de; + + } // end removeProperty + + int[] getPropertyNamespaceIDs(long msgid, int part) throws DatabaseException + { + Connection conn = null; + PreparedStatement stmt = null; + ResultSet rs = null; + try + { // get a connection + conn = getConnection(); + + // execute the query! + stmt = conn.prepareStatement("SELECT DISTINCT nsid FROM us_binary_prop WHERE msgid = ? AND part = ?;"); + stmt.setLong(1,msgid); + stmt.setInt(2,part); + rs = stmt.executeQuery(); + + // read out a list of the namespace IDs + ArrayList tmp = new ArrayList(); + while (rs.next()) + tmp.add(new Integer(rs.getInt(1))); + + // create and return the array + int[] rc = new int[tmp.size()]; + for (int i=0; i. + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.dynamo.unistore; + +import java.util.*; +import com.silverwrist.dynamo.db.OpsBase; +import com.silverwrist.dynamo.except.*; +import com.silverwrist.dynamo.iface.*; + +abstract class ManagerOps extends OpsBase +{ + /*-------------------------------------------------------------------------------- + * Static data members + *-------------------------------------------------------------------------------- + */ + + static final String PARAM_MSGID = "msgid"; + static final String PARAM_PARENT = "parent"; + static final String PARAM_SEQ = "seq"; + static final String PARAM_CREATOR = "creator"; + static final String PARAM_POSTED = "posted"; + static final String PARAM_ACLID = "aclid"; + + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private MessageOps m_msgops = null; + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + protected ManagerOps(DBConnectionPool pool) + { + super(pool); + + } // end constructor + + /*-------------------------------------------------------------------------------- + * Overrides from class OpsBase + *-------------------------------------------------------------------------------- + */ + + public void dispose() + { + if (m_msgops!=null) + m_msgops.dispose(); + m_msgops = null; + super.dispose(); + + } // end dispose + + /*-------------------------------------------------------------------------------- + * Abstract operations + *-------------------------------------------------------------------------------- + */ + + protected abstract MessageOps createMessageOps(DBConnectionPool pool); + + abstract Map getMessageData(long msgid) throws DatabaseException; + + /*-------------------------------------------------------------------------------- + * External operations + *-------------------------------------------------------------------------------- + */ + + synchronized MessageOps getMessageOps() + { + if (m_msgops==null) + m_msgops = createMessageOps(getPool()); + return m_msgops; + + } // return getMessageOps + + /*-------------------------------------------------------------------------------- + * External static operations + *-------------------------------------------------------------------------------- + */ + + static ManagerOps get(DBConnectionPool pool) throws ConfigException + { + return (ManagerOps)get(pool,ManagerOps.class.getClassLoader(),ManagerOps.class.getName() + "_","ManagerOps"); + + } // end get + +} // end class ManagerOps diff --git a/src/dynamo-framework/com/silverwrist/dynamo/unistore/ManagerOps_mysql.java b/src/dynamo-framework/com/silverwrist/dynamo/unistore/ManagerOps_mysql.java new file mode 100644 index 0000000..925fd33 --- /dev/null +++ b/src/dynamo-framework/com/silverwrist/dynamo/unistore/ManagerOps_mysql.java @@ -0,0 +1,119 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.dynamo.unistore; + +import java.sql.*; +import java.util.*; +import com.silverwrist.util.*; +import com.silverwrist.dynamo.except.*; +import com.silverwrist.dynamo.iface.*; + +public class ManagerOps_mysql extends ManagerOps +{ + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private DBUtilities m_utils; + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + public ManagerOps_mysql(DBConnectionPool pool) + { + super(pool); + m_utils = (DBUtilities)(pool.queryService(DBUtilities.class)); + + } // end constructor + + /*-------------------------------------------------------------------------------- + * Overrides from class ManagerOps + *-------------------------------------------------------------------------------- + */ + + public void dispose() + { + m_utils = null; + super.dispose(); + + } // end dispose + + /*-------------------------------------------------------------------------------- + * Abstract implementations from class ManagerOps + *-------------------------------------------------------------------------------- + */ + + protected MessageOps createMessageOps(DBConnectionPool pool) + { + return new MessageOps_mysql(pool); + + } // end createMessageOps + + Map getMessageData(long msgid) throws DatabaseException + { + Connection conn = null; + PreparedStatement stmt = null; + ResultSet rs = null; + try + { // get a connection + conn = getConnection(); + + // prepare and execute a statement to find the header data + stmt = conn.prepareStatement("SELECT parent, seq, creator, posted, aclid FROM us_head WHERE msgid = ?;"); + stmt.setLong(1,msgid); + rs = stmt.executeQuery(); + if (!(rs.next())) + { // the message was not found + DatabaseException de = new DatabaseException(ManagerOps_mysql.class,"UniStoreMessages","no.message"); + de.setParameter(0,String.valueOf(msgid)); + throw de; + + } // end if + + // build the return value + HashMap rc = new HashMap(); + rc.put(PARAM_MSGID,new Long(msgid)); + rc.put(PARAM_PARENT,new Long(rs.getLong(1))); + rc.put(PARAM_SEQ,new Integer(rs.getInt(2))); + rc.put(PARAM_CREATOR,new Integer(rs.getInt(3))); + rc.put(PARAM_POSTED,m_utils.getDateTime(rs,4)); + int tmp = rs.getInt(5); + if (!(rs.wasNull())) + rc.put(PARAM_ACLID,new Integer(tmp)); + return rc; + + } // end try + catch (SQLException e) + { // translate to a general DatabaseException + throw generalException(e); + + } // end catch + finally + { // shut everything down + SQLUtils.shutdown(rs); + SQLUtils.shutdown(stmt); + SQLUtils.shutdown(conn); + + } // end finally + + } // end getMessageData + +} // end class ManagerOps_mysql diff --git a/src/dynamo-framework/com/silverwrist/dynamo/unistore/MessageImpl.java b/src/dynamo-framework/com/silverwrist/dynamo/unistore/MessageImpl.java new file mode 100644 index 0000000..de72334 --- /dev/null +++ b/src/dynamo-framework/com/silverwrist/dynamo/unistore/MessageImpl.java @@ -0,0 +1,567 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.dynamo.unistore; + +import java.security.acl.AclNotFoundException; +import java.util.*; +import org.apache.commons.collections.*; +import org.apache.log4j.Logger; +import com.silverwrist.dynamo.Namespaces; +import com.silverwrist.dynamo.db.NamespaceCache; +import com.silverwrist.dynamo.db.UserManagement; +import com.silverwrist.dynamo.except.*; +import com.silverwrist.dynamo.iface.*; +import com.silverwrist.dynamo.security.SecurityReferenceMonitor; +import com.silverwrist.dynamo.util.*; + +class MessageImpl implements UniStoreMessage +{ + /*-------------------------------------------------------------------------------- + * Static data members + *-------------------------------------------------------------------------------- + */ + + private static Logger logger = Logger.getLogger(MessageImpl.class); + + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private MessageOps m_ops; // database operations object + private NamespaceCache m_nscache; // namespace cache + private SecurityReferenceMonitor m_srm; // security reference monitor + private UserManagement m_users; // user manager + private long m_id; // the message ID + private long m_parentid; // the parent message ID + private int m_seq; // sequence within parent + private int m_creator; // UID of creator + private java.util.Date m_posted; // date message was posted + private int m_aclid = -1; // ACL id + private ReferenceMap m_properties; // properties cache + private int m_text_count = -1; // number of text parts + private int m_binary_count = -1; // number of binary parts + private ReferenceMap m_part_to_text; // mapping from part index to text part + private ReferenceMap m_pk_to_text; // mapping from property key to text part + private ReferenceMap m_part_to_binary; // mapping from part index to binary part + private ReferenceMap m_pk_to_binary; // mapping from property key to binary part + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + MessageImpl(MessageOps ops, NamespaceCache nscache, SecurityReferenceMonitor srm, UserManagement users, Map params) + { + m_ops = ops; + m_nscache = nscache; + m_srm = srm; + m_users = users; + m_id = ((Long)(params.get(ManagerOps.PARAM_MSGID))).longValue(); + m_parentid = ((Long)(params.get(ManagerOps.PARAM_PARENT))).longValue(); + m_seq = ((Integer)(params.get(ManagerOps.PARAM_SEQ))).intValue(); + m_creator = ((Integer)(params.get(ManagerOps.PARAM_CREATOR))).intValue(); + m_posted = (java.util.Date)(params.get(ManagerOps.PARAM_POSTED)); + Integer tmp = (Integer)(params.get(ManagerOps.PARAM_ACLID)); + if (tmp!=null) + m_aclid = tmp.intValue(); + m_properties = new ReferenceMap(ReferenceMap.HARD,ReferenceMap.SOFT); + m_part_to_text = new ReferenceMap(ReferenceMap.HARD,ReferenceMap.SOFT); + m_pk_to_text = new ReferenceMap(ReferenceMap.HARD,ReferenceMap.SOFT); + m_part_to_binary = new ReferenceMap(ReferenceMap.HARD,ReferenceMap.SOFT); + m_pk_to_binary = new ReferenceMap(ReferenceMap.HARD,ReferenceMap.SOFT); + + } // end constructor + + /*-------------------------------------------------------------------------------- + * Implementations from interface ObjectProvider + *-------------------------------------------------------------------------------- + */ + + /** + * Retrieves an object from this ObjectProvider. + * + * @param namespace The namespace to interpret the name relative to. + * @param name The name of the object to be retrieved. + * @return The object reference specified. + */ + public Object getObject(String namespace, String name) + { + try + { // convert the namespace name to an ID here + PropertyKey key = new PropertyKey(m_nscache.namespaceNameToId(namespace),name); + Object rc = null; + synchronized (this) + { // start by looking in the properties map + rc = m_properties.get(key); + if (rc==null) + { // no use - need to try the database + rc = m_ops.getProperty(m_id,key); + if (rc!=null) + m_properties.put(key,rc); + + } // end if + + } // end synchronized block + + if (rc==null) + throw new NoSuchObjectException(this.toString(),namespace,name); + return rc; + + } // end try + catch (DatabaseException e) + { // translate into our NoSuchObjectException but retain the DatabaseException + throw new NoSuchObjectException(this.toString(),namespace,name,e); + + } // end catch + + } // end getObject + + /*-------------------------------------------------------------------------------- + * Implementations from interface SecureObjectStore + *-------------------------------------------------------------------------------- + */ + + /** + * Sets an object into this message's properties. + * + * @param caller The user performing the operation. + * @param namespace The namespace to interpret the name relative to. + * @param name The name of the object to be set. + * @param value The object to set into the message's properties. + * @return The previous object that was set into the message's properties under this namespace and name, or + * null if there was no such object. + * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error setting the object value. + * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to + * set this object value into this message's properties. + */ + public Object setObject(DynamoUser caller, String namespace, String name, Object value) + throws DatabaseException, DynamoSecurityException + { + testPermission(caller,namespace,"set.property","no.setProperty"); + Object rc = null; + // convert the namespace name to an ID here + PropertyKey key = new PropertyKey(m_nscache.namespaceNameToId(namespace),name); + synchronized (this) + { // start by setting the database value + rc = m_ops.setProperty(m_id,key,value); + + // and cache it, too + m_properties.put(key,value); + + } // end synchronized block + + // TODO: m_post.postUpdate(new GlobalPropertyUpdateEvent(this,namespace,name)); + return rc; + + } // end setObject + + /** + * Removes an object from this message's properties. + * + * @param caller The user performing the operation. + * @param namespace The namespace to interpret the name relative to. + * @param name The name of the object to be removed. + * @return The previous object that was set into the message's properties under this namespace and name, or + * null if there was no such object. + * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error removing the object value. + * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to + * remove this object value from this message's properties. + */ + public Object removeObject(DynamoUser caller, String namespace, String name) + throws DatabaseException, DynamoSecurityException + { + testPermission(caller,namespace,"remove.property","no.removeProperty"); + Object rc = null; + // convert the namespace name to an ID here + PropertyKey key = new PropertyKey(m_nscache.namespaceNameToId(namespace),name); + synchronized (this) + { // start by killing the database value + rc = m_ops.removeProperty(m_id,key); + + // and remove the cached value, too + m_properties.remove(key); + + } // end synchronized block + + // TODO: m_post.postUpdate(new GlobalPropertyUpdateEvent(this,namespace,name)); + return rc; + + } // end removeObject + + /** + * Returns a collection of all object namespaces that have been set into this message's properties. + * + * @return A {@link java.util.Collection Collection} containing {@link java.lang.String String} objects specifying + * all the object namespaces. + * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the namespace list. + */ + public Collection getNamespaces() throws DatabaseException + { + // call through to the database to get the list of namespace IDs + int[] ids = m_ops.getPropertyNamespaceIDs(m_id); + + ArrayList rc = new ArrayList(ids.length); + for (int i=0; i. + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.dynamo.unistore; + +import java.util.*; +import com.silverwrist.dynamo.db.OpsBase; +import com.silverwrist.dynamo.except.*; +import com.silverwrist.dynamo.iface.*; +import com.silverwrist.dynamo.util.*; + +abstract class MessageOps extends OpsBase +{ + /*-------------------------------------------------------------------------------- + * Static data members + *-------------------------------------------------------------------------------- + */ + + static final String PARAM_PART = "part"; + static final String PARAM_IDENTITY = "identity"; + static final String PARAM_MIMETYPE = "mimetype"; + static final String PARAM_SIZE = "size"; + static final String PARAM_LINECOUNT = "linecount"; + static final String PARAM_READS = "reads"; + static final String PARAM_LASTREAD = "lastread"; + static final String PARAM_FILENAME = "filename"; + + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private TextPartOps m_textops = null; + private BinaryPartOps m_binaryops = null; + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + protected MessageOps(DBConnectionPool pool) + { + super(pool); + + } // end constructor + + /*-------------------------------------------------------------------------------- + * Overrides from class OpsBase + *-------------------------------------------------------------------------------- + */ + + public void dispose() + { + if (m_textops!=null) + m_textops.dispose(); + m_textops = null; + if (m_binaryops!=null) + m_binaryops.dispose(); + m_binaryops = null; + super.dispose(); + + } // end dispose + + /*-------------------------------------------------------------------------------- + * Abstract operations + *-------------------------------------------------------------------------------- + */ + + protected abstract TextPartOps createTextPartOps(DBConnectionPool pool); + + protected abstract BinaryPartOps createBinaryPartOps(DBConnectionPool pool); + + abstract Object getProperty(long msgid, PropertyKey key) throws DatabaseException; + + abstract Object setProperty(long msgid, PropertyKey key, Object value) throws DatabaseException; + + abstract Object removeProperty(long msgid, PropertyKey key) throws DatabaseException; + + abstract int[] getPropertyNamespaceIDs(long msgid) throws DatabaseException; + + abstract Map getAllProperties(long msgid, int namespace) throws DatabaseException; + + abstract void setParentMessageID(long msgid, long parent) throws DatabaseException; + + abstract void setSequence(long msgid, int seq) throws DatabaseException; + + abstract void setAclID(long msgid, int aclid) throws DatabaseException; + + abstract int getNumTextParts(long msgid) throws DatabaseException; + + abstract int getNumBinaryParts(long msgid) throws DatabaseException; + + abstract Map loadTextPart(long msgid, int part) throws DatabaseException; + + abstract Map loadTextPart(long msgid, PropertyKey identity) throws DatabaseException; + + abstract Map loadBinaryPart(long msgid, int part) throws DatabaseException; + + abstract Map loadBinaryPart(long msgid, PropertyKey identity) throws DatabaseException; + + /*-------------------------------------------------------------------------------- + * External operations + *-------------------------------------------------------------------------------- + */ + + synchronized TextPartOps getTextPartOps() + { + if (m_textops==null) + m_textops = createTextPartOps(getPool()); + return m_textops; + + } // end getTextPartOps + + synchronized BinaryPartOps getBinaryPartOps() + { + if (m_binaryops==null) + m_binaryops = createBinaryPartOps(getPool()); + return m_binaryops; + + } // end getBinaryPartOps + +} // end class MessageOps diff --git a/src/dynamo-framework/com/silverwrist/dynamo/unistore/MessageOps_mysql.java b/src/dynamo-framework/com/silverwrist/dynamo/unistore/MessageOps_mysql.java new file mode 100644 index 0000000..1911c20 --- /dev/null +++ b/src/dynamo-framework/com/silverwrist/dynamo/unistore/MessageOps_mysql.java @@ -0,0 +1,793 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.dynamo.unistore; + +import java.sql.*; +import java.util.*; +import com.silverwrist.util.*; +import com.silverwrist.dynamo.except.*; +import com.silverwrist.dynamo.iface.*; +import com.silverwrist.dynamo.util.*; + +class MessageOps_mysql extends MessageOps +{ + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private PropertySerializer m_psz; // reference to property serializer + private DBUtilities m_utils; + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + MessageOps_mysql(DBConnectionPool pool) + { + super(pool); + m_psz = (PropertySerializer)(pool.queryService(PropertySerializer.class)); + m_utils = (DBUtilities)(pool.queryService(DBUtilities.class)); + + } // end constructor + + /*-------------------------------------------------------------------------------- + * Overrides from class MessageOps + *-------------------------------------------------------------------------------- + */ + + public void dispose() + { + m_psz = null; + m_utils = null; + super.dispose(); + + } // end dispose + + /*-------------------------------------------------------------------------------- + * Abstract operations + *-------------------------------------------------------------------------------- + */ + + protected TextPartOps createTextPartOps(DBConnectionPool pool) + { + return new TextPartOps_mysql(pool); + + } // end createTextPartOps + + protected BinaryPartOps createBinaryPartOps(DBConnectionPool pool) + { + return new BinaryPartOps_mysql(pool); + + } // end createBinaryPartOps + + Object getProperty(long msgid, PropertyKey key) throws DatabaseException + { + Connection conn = null; + PreparedStatement stmt = null; + ResultSet rs = null; + String rc_str = null; + try + { // get a connection + conn = getConnection(); + + // look up the property + stmt = conn.prepareStatement("SELECT prop_value FROM us_prop WHERE msgid = ? AND nsid = ? AND prop_name = ?;"); + stmt.setLong(1,msgid); + stmt.setInt(2,key.getNamespaceID()); + stmt.setString(3,key.getName()); + rs = stmt.executeQuery(); + if (!(rs.next())) + return null; // property not found + + rc_str = rs.getString(1); + + } // end try + catch (SQLException e) + { // translate to a general DatabaseException + throw generalException(e); + + } // end catch + finally + { // shut everything down + SQLUtils.shutdown(rs); + SQLUtils.shutdown(stmt); + SQLUtils.shutdown(conn); + + } // end finally + + // Deserialize the property value. + Object rc = m_psz.deserializeProperty(rc_str); + if (rc!=null) + return rc; + + // deserialization exception - throw it + DatabaseException de = new DatabaseException(MessageOps_mysql.class,"UniStoreMessages","property.deserialize"); + de.setParameter(0,key.getName()); + throw de; + + } // end getProperty + + Object setProperty(long msgid, PropertyKey key, Object value) throws DatabaseException + { + String serialized_value = m_psz.serializeProperty(value); + if (serialized_value==null) + { // serialization exception - throw it + DatabaseException de = new DatabaseException(MessageOps_mysql.class,"UniStoreMessages","property.serialize"); + de.setParameter(0,key.getName()); + throw de; + + } // end if + + String old_value = null; + Connection conn = null; + PreparedStatement stmt = null; + Statement stmt2 = null; + ResultSet rs = null; + try + { // get a connection + conn = getConnection(); + + // lock the table + stmt2 = conn.createStatement(); + stmt2.executeUpdate("LOCK TABLES us_prop WRITE;"); + + // look to see if the property value is already there + stmt = conn.prepareStatement("SELECT prop_value FROM us_prop WHERE msgid = ? AND nsid = ? AND prop_name = ?;"); + stmt.setLong(1,msgid); + stmt.setInt(2,key.getNamespaceID()); + stmt.setString(3,key.getName()); + rs = stmt.executeQuery(); + if (rs.next()) + old_value = rs.getString(1); + SQLUtils.shutdown(rs); + rs = null; + SQLUtils.shutdown(stmt); + + if (old_value!=null) + { // prepare the statement to update the existing record + stmt = conn.prepareStatement("UPDATE us_prop SET prop_value = ? WHERE msgid = ? AND nsid = ? " + + "AND prop_name = ?;"); + stmt.setString(1,serialized_value); + stmt.setLong(2,msgid); + stmt.setInt(3,key.getNamespaceID()); + stmt.setString(4,key.getName()); + + } // end if + else + { // prepare the statement to insert a new record + stmt = conn.prepareStatement("INSERT INTO us_prop (msgid, nsid, prop_name, prop_value) VALUES (?, ?, ?, ?);"); + stmt.setLong(1,msgid); + stmt.setInt(2,key.getNamespaceID()); + stmt.setString(3,key.getName()); + stmt.setString(4,serialized_value); + + } // end else + + stmt.executeUpdate(); // execute it! + + } // end try + catch (SQLException e) + { // translate to a general DatabaseException + throw generalException(e); + + } // end catch + finally + { // shut everything down + MySQLUtils.unlockTables(conn); + SQLUtils.shutdown(rs); + SQLUtils.shutdown(stmt); + SQLUtils.shutdown(stmt2); + SQLUtils.shutdown(conn); + + } // end finally + + if (old_value==null) + return null; // no previous value + + // Deserialize the property value. + Object rc = m_psz.deserializeProperty(old_value); + if (rc!=null) + return rc; + + // deserialization exception - throw it + DatabaseException de = new DatabaseException(MessageOps_mysql.class,"UniStoreMessages","property.deserialize"); + de.setParameter(0,key.getName()); + throw de; + + } // end setProperty + + Object removeProperty(long msgid, PropertyKey key) throws DatabaseException + { + String old_value = null; + Connection conn = null; + PreparedStatement stmt = null; + Statement stmt2 = null; + ResultSet rs = null; + try + { // get a connection + conn = getConnection(); + + // lock the table + stmt2 = conn.createStatement(); + stmt2.executeUpdate("LOCK TABLES us_prop WRITE;"); + + // look to see if the property value is already there + stmt = conn.prepareStatement("SELECT prop_value FROM us_prop WHERE msgid = ? AND nsid = ? AND prop_name = ?;"); + stmt.setLong(1,msgid); + stmt.setInt(2,key.getNamespaceID()); + stmt.setString(3,key.getName()); + rs = stmt.executeQuery(); + if (rs.next()) + old_value = rs.getString(1); + else + return null; // no need to remove anything + SQLUtils.shutdown(rs); + rs = null; + SQLUtils.shutdown(stmt); + + // delete the database row + stmt = conn.prepareStatement("DELETE FROM us_prop WHERE msgid = ? AND nsid = ? AND prop_name = ?;"); + stmt.setLong(1,msgid); + stmt.setInt(2,key.getNamespaceID()); + stmt.setString(3,key.getName()); + stmt.executeUpdate(); + + } // end try + catch (SQLException e) + { // translate to a general DatabaseException + throw generalException(e); + + } // end catch + finally + { // shut everything down + MySQLUtils.unlockTables(conn); + SQLUtils.shutdown(rs); + SQLUtils.shutdown(stmt); + SQLUtils.shutdown(stmt2); + SQLUtils.shutdown(conn); + + } // end finally + + // Deserialize the property value. + Object rc = m_psz.deserializeProperty(old_value); + if (rc!=null) + return rc; + + // deserialization exception - throw it + DatabaseException de = new DatabaseException(MessageOps_mysql.class,"UniStoreMessages","property.deserialize"); + de.setParameter(0,key.getName()); + throw de; + + } // end removeProperty + + int[] getPropertyNamespaceIDs(long msgid) throws DatabaseException + { + Connection conn = null; + PreparedStatement stmt = null; + ResultSet rs = null; + try + { // get a connection + conn = getConnection(); + + // execute the query! + stmt = conn.prepareStatement("SELECT DISTINCT nsid FROM us_prop WHERE msgid = ?;"); + stmt.setLong(1,msgid); + rs = stmt.executeQuery(); + + // read out a list of the namespace IDs + ArrayList tmp = new ArrayList(); + while (rs.next()) + tmp.add(new Integer(rs.getInt(1))); + + // create and return the array + int[] rc = new int[tmp.size()]; + for (int i=0; i. + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.dynamo.unistore; + +import java.io.*; +import java.lang.ref.*; +import java.util.*; +import org.apache.commons.collections.*; +import com.silverwrist.dynamo.db.NamespaceCache; +import com.silverwrist.dynamo.except.*; +import com.silverwrist.dynamo.iface.*; +import com.silverwrist.dynamo.util.*; + +class TextPartImpl implements UniStoreTextPart +{ + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private TextPartOps m_ops; + private NamespaceCache m_nscache; + private MessageImpl m_parent; + private int m_part; + private QualifiedNameKey m_identity; + private String m_mimetype; + private int m_size; + private int m_linecount; + private int m_nread; + private java.util.Date m_lastread; + private ReferenceMap m_properties; + private SoftReference m_text = null; + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + TextPartImpl(TextPartOps ops, NamespaceCache nscache, MessageImpl parent, Map params) throws DatabaseException + { + m_ops = ops; + m_nscache = nscache; + m_parent = parent; + m_part = ((Integer)(params.get(MessageOps.PARAM_PART))).intValue(); + PropertyKey pk = (PropertyKey)(params.get(MessageOps.PARAM_IDENTITY)); + m_identity = new QualifiedNameKey(nscache.namespaceIdToName(pk.getNamespaceID()),pk.getName()); + m_mimetype = (String)(params.get(MessageOps.PARAM_MIMETYPE)); + Integer tmp = (Integer)(params.get(MessageOps.PARAM_SIZE)); + if (tmp!=null) + m_size = tmp.intValue(); + tmp = (Integer)(params.get(MessageOps.PARAM_LINECOUNT)); + if (tmp!=null) + m_linecount = tmp.intValue(); + m_nread = ((Integer)(params.get(MessageOps.PARAM_READS))).intValue(); + m_lastread = (java.util.Date)(params.get(MessageOps.PARAM_LASTREAD)); + m_properties = new ReferenceMap(ReferenceMap.HARD,ReferenceMap.SOFT); + + } // end constructor + + /*-------------------------------------------------------------------------------- + * Implementations from interface ObjectProvider + *-------------------------------------------------------------------------------- + */ + + /** + * Retrieves an object from this ObjectProvider. + * + * @param namespace The namespace to interpret the name relative to. + * @param name The name of the object to be retrieved. + * @return The object reference specified. + */ + public Object getObject(String namespace, String name) + { + try + { // convert the namespace name to an ID here + PropertyKey key = new PropertyKey(m_nscache.namespaceNameToId(namespace),name); + Object rc = null; + synchronized (this) + { // start by looking in the properties map + rc = m_properties.get(key); + if (rc==null) + { // no use - need to try the database + rc = m_ops.getProperty(m_parent.getMessageID(),m_part,key); + if (rc!=null) + m_properties.put(key,rc); + + } // end if + + } // end synchronized block + + if (rc==null) + throw new NoSuchObjectException(this.toString(),namespace,name); + return rc; + + } // end try + catch (DatabaseException e) + { // translate into our NoSuchObjectException but retain the DatabaseException + throw new NoSuchObjectException(this.toString(),namespace,name,e); + + } // end catch + + } // end getObject + + /*-------------------------------------------------------------------------------- + * Implementations from interface SecureObjectStore + *-------------------------------------------------------------------------------- + */ + + /** + * Sets an object into this SecureObjectStore. + * + * @param caller The user performing the operation. + * @param namespace The namespace to interpret the name relative to. + * @param name The name of the object to be set. + * @param value The object to set into the SecureObjectStore. + * @return The previous object that was set into the SecureObjectStore under this namespace and name, or + * null if there was no such object. + * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error setting the object value. + * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to + * set this object value into this SecureObjectStore. + */ + public Object setObject(DynamoUser caller, String namespace, String name, Object value) + throws DatabaseException, DynamoSecurityException + { + m_parent.testPermission(caller,namespace,"set.property","no.setProperty"); + Object rc = null; + // convert the namespace name to an ID here + PropertyKey key = new PropertyKey(m_nscache.namespaceNameToId(namespace),name); + synchronized (this) + { // start by setting the database value + rc = m_ops.setProperty(m_parent.getMessageID(),m_part,key,value); + + // and cache it, too + m_properties.put(key,value); + + } // end synchronized block + + // TODO: m_post.postUpdate(new GlobalPropertyUpdateEvent(this,namespace,name)); + return rc; + + } // end setObject + + /** + * Removes an object from this SecureObjectStore. + * + * @param caller The user performing the operation. + * @param namespace The namespace to interpret the name relative to. + * @param name The name of the object to be removed. + * @return The previous object that was set into the SecureObjectStore under this namespace and name, or + * null if there was no such object. + * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error removing the object value. + * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to + * remove this object value from this SecureObjectStore. + */ + public Object removeObject(DynamoUser caller, String namespace, String name) + throws DatabaseException, DynamoSecurityException + { + m_parent.testPermission(caller,namespace,"remove.property","no.removeProperty"); + Object rc = null; + // convert the namespace name to an ID here + PropertyKey key = new PropertyKey(m_nscache.namespaceNameToId(namespace),name); + synchronized (this) + { // start by killing the database value + rc = m_ops.removeProperty(m_parent.getMessageID(),m_part,key); + + // and remove the cached value, too + m_properties.remove(key); + + } // end synchronized block + + // TODO: m_post.postUpdate(new GlobalPropertyUpdateEvent(this,namespace,name)); + return rc; + + } // end removeObject + + /** + * Returns a collection of all object namespaces that have been set into this SecureObjectStore. + * + * @return A {@link java.util.Collection Collection} containing {@link java.lang.String String} objects specifying + * all the object namespaces. + * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the namespace list. + */ + public Collection getNamespaces() throws DatabaseException + { + // call through to the database to get the list of namespace IDs + int[] ids = m_ops.getPropertyNamespaceIDs(m_parent.getMessageID(),m_part); + + ArrayList rc = new ArrayList(ids.length); + for (int i=0; iSecureObjectStore under + * a given namespace. + * + * @param namespace The namespace to look for names under. + * @return A {@link java.util.Collection Collection} containing {@link java.lang.String String} objects + * specifying all the object names for this namespace. + * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the object name list. + */ + public Collection getNamesForNamespace(String namespace) throws DatabaseException + { + // call through to the database to get the data for this namespace + int nsid = m_nscache.namespaceNameToId(namespace); + Map data = m_ops.getAllProperties(m_parent.getMessageID(),m_part,nsid); + + // we both create the return value and cache the data values + ArrayList rc = new ArrayList(data.size()); + synchronized (this) + { // do the transfer... + Iterator it = data.entrySet().iterator(); + while (it.hasNext()) + { // copy one entry at a time + Map.Entry ntry = (Map.Entry)(it.next()); + rc.add(ntry.getKey().toString()); + m_properties.put(new PropertyKey(nsid,ntry.getKey().toString()),ntry.getValue()); + + } // end while + + } // end synchronized block + + return Collections.unmodifiableList(rc); + + } // end getNamesForNamespace + + /*-------------------------------------------------------------------------------- + * Implementations from interface UniStorePart + *-------------------------------------------------------------------------------- + */ + + public long getMessageID() + { + return m_parent.getMessageID(); + + } // end getMessageID + + public int getPartIndex() + { + return m_part; + + } // end getPartIndex + + public QualifiedNameKey getPartIdentity() + { + return m_identity; + + } // end getPartIdentity + + public String getMimeType() + { + return m_mimetype; + + } // end getMimeType + + public int getSize() + { + return m_size; + + } // end getSize + + public int getNumReads() + { + return m_nread; + + } // end getNumReads + + public java.util.Date getLastReadDate() + { + return m_lastread; + + } // end getLastReadDate + + public void touchRead() throws DatabaseException + { + synchronized (this) + { // touch the database, then the local values + java.util.Date tmp = m_ops.touchRead(m_parent.getMessageID(),m_part); + m_nread++; + m_lastread = tmp; + + } // end synchronized block + + // TODO: post an update? + + } // end touchRead + + /*-------------------------------------------------------------------------------- + * Implementations from interface UniStoreTextPart + *-------------------------------------------------------------------------------- + */ + + public int getLineCount() + { + return m_linecount; + + } // end getLineCount + + public synchronized String getText() throws DatabaseException + { + String rc = null; + if (m_text!=null) + rc = (String)(m_text.get()); + if (rc==null) + { // load text fom database and reload to reference + rc = m_ops.getText(m_parent.getMessageID(),m_part); + m_text = new SoftReference(rc); + + } // end if + + return rc; + + } // end getText + + public Reader getTextAsReader() throws DatabaseException + { + return new StringReader(this.getText()); + + } // end getTextAsReader + +} // end class TextPartImpl diff --git a/src/dynamo-framework/com/silverwrist/dynamo/unistore/TextPartOps.java b/src/dynamo-framework/com/silverwrist/dynamo/unistore/TextPartOps.java new file mode 100644 index 0000000..4983f03 --- /dev/null +++ b/src/dynamo-framework/com/silverwrist/dynamo/unistore/TextPartOps.java @@ -0,0 +1,58 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.dynamo.unistore; + +import java.util.*; +import com.silverwrist.dynamo.db.OpsBase; +import com.silverwrist.dynamo.except.*; +import com.silverwrist.dynamo.iface.*; +import com.silverwrist.dynamo.util.*; + +abstract class TextPartOps extends OpsBase +{ + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + protected TextPartOps(DBConnectionPool pool) + { + super(pool); + + } // end constructor + + /*-------------------------------------------------------------------------------- + * Abstract operations + *-------------------------------------------------------------------------------- + */ + + abstract Object getProperty(long msgid, int part, PropertyKey key) throws DatabaseException; + + abstract Object setProperty(long msgid, int part, PropertyKey key, Object value) throws DatabaseException; + + abstract Object removeProperty(long msgid, int part, PropertyKey key) throws DatabaseException; + + abstract int[] getPropertyNamespaceIDs(long msgid, int part) throws DatabaseException; + + abstract Map getAllProperties(long msgid, int part, int namespace) throws DatabaseException; + + abstract java.util.Date touchRead(long msgid, int part) throws DatabaseException; + + abstract String getText(long msgid, int part) throws DatabaseException; + +} // end class TextPartOps diff --git a/src/dynamo-framework/com/silverwrist/dynamo/unistore/TextPartOps_mysql.java b/src/dynamo-framework/com/silverwrist/dynamo/unistore/TextPartOps_mysql.java new file mode 100644 index 0000000..46aacd2 --- /dev/null +++ b/src/dynamo-framework/com/silverwrist/dynamo/unistore/TextPartOps_mysql.java @@ -0,0 +1,458 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.dynamo.unistore; + +import java.sql.*; +import java.util.*; +import com.silverwrist.util.*; +import com.silverwrist.dynamo.except.*; +import com.silverwrist.dynamo.iface.*; +import com.silverwrist.dynamo.util.*; + +class TextPartOps_mysql extends TextPartOps +{ + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private PropertySerializer m_psz; // reference to property serializer + private DBUtilities m_utils; + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + TextPartOps_mysql(DBConnectionPool pool) + { + super(pool); + m_psz = (PropertySerializer)(pool.queryService(PropertySerializer.class)); + m_utils = (DBUtilities)(pool.queryService(DBUtilities.class)); + + } // end constructor + + /*-------------------------------------------------------------------------------- + * Overrides from class OpsBase + *-------------------------------------------------------------------------------- + */ + + public void dispose() + { + m_psz = null; + m_utils = null; + super.dispose(); + + } // end dispose + + /*-------------------------------------------------------------------------------- + * Abstract implementations from class TextPartOps + *-------------------------------------------------------------------------------- + */ + + Object getProperty(long msgid, int part, PropertyKey key) throws DatabaseException + { + Connection conn = null; + PreparedStatement stmt = null; + ResultSet rs = null; + String rc_str = null; + try + { // get a connection + conn = getConnection(); + + // look up the property + stmt = conn.prepareStatement("SELECT prop_value FROM us_text_prop WHERE msgid = ? AND part = ? AND nsid = ? " + + "AND prop_name = ?;"); + stmt.setLong(1,msgid); + stmt.setInt(2,part); + stmt.setInt(3,key.getNamespaceID()); + stmt.setString(4,key.getName()); + rs = stmt.executeQuery(); + if (!(rs.next())) + return null; // property not found + + rc_str = rs.getString(1); + + } // end try + catch (SQLException e) + { // translate to a general DatabaseException + throw generalException(e); + + } // end catch + finally + { // shut everything down + SQLUtils.shutdown(rs); + SQLUtils.shutdown(stmt); + SQLUtils.shutdown(conn); + + } // end finally + + // Deserialize the property value. + Object rc = m_psz.deserializeProperty(rc_str); + if (rc!=null) + return rc; + + // deserialization exception - throw it + DatabaseException de = new DatabaseException(TextPartOps_mysql.class,"UniStoreMessages","property.deserialize"); + de.setParameter(0,key.getName()); + throw de; + + } // end getProperty + + Object setProperty(long msgid, int part, PropertyKey key, Object value) throws DatabaseException + { + String serialized_value = m_psz.serializeProperty(value); + if (serialized_value==null) + { // serialization exception - throw it + DatabaseException de = new DatabaseException(TextPartOps_mysql.class,"UniStoreMessages","property.serialize"); + de.setParameter(0,key.getName()); + throw de; + + } // end if + + String old_value = null; + Connection conn = null; + PreparedStatement stmt = null; + Statement stmt2 = null; + ResultSet rs = null; + try + { // get a connection + conn = getConnection(); + + // lock the table + stmt2 = conn.createStatement(); + stmt2.executeUpdate("LOCK TABLES us_text_prop WRITE;"); + + // look to see if the property value is already there + stmt = conn.prepareStatement("SELECT prop_value FROM us_text_prop WHERE msgid = ? AND part = ? AND nsid = ? " + + "AND prop_name = ?;"); + stmt.setLong(1,msgid); + stmt.setInt(2,part); + stmt.setInt(3,key.getNamespaceID()); + stmt.setString(4,key.getName()); + rs = stmt.executeQuery(); + if (rs.next()) + old_value = rs.getString(1); + SQLUtils.shutdown(rs); + rs = null; + SQLUtils.shutdown(stmt); + + if (old_value!=null) + { // prepare the statement to update the existing record + stmt = conn.prepareStatement("UPDATE us_text_prop SET prop_value = ? WHERE msgid = ? AND part = ? " + + "AND nsid = ? AND prop_name = ?;"); + stmt.setString(1,serialized_value); + stmt.setLong(2,msgid); + stmt.setInt(3,part); + stmt.setInt(4,key.getNamespaceID()); + stmt.setString(5,key.getName()); + + } // end if + else + { // prepare the statement to insert a new record + stmt = conn.prepareStatement("INSERT INTO us_text_prop (msgid, part, nsid, prop_name, prop_value) " + + "VALUES (?, ?, ?, ?, ?);"); + stmt.setLong(1,msgid); + stmt.setInt(2,part); + stmt.setInt(3,key.getNamespaceID()); + stmt.setString(4,key.getName()); + stmt.setString(5,serialized_value); + + } // end else + + stmt.executeUpdate(); // execute it! + + } // end try + catch (SQLException e) + { // translate to a general DatabaseException + throw generalException(e); + + } // end catch + finally + { // shut everything down + MySQLUtils.unlockTables(conn); + SQLUtils.shutdown(rs); + SQLUtils.shutdown(stmt); + SQLUtils.shutdown(stmt2); + SQLUtils.shutdown(conn); + + } // end finally + + if (old_value==null) + return null; // no previous value + + // Deserialize the property value. + Object rc = m_psz.deserializeProperty(old_value); + if (rc!=null) + return rc; + + // deserialization exception - throw it + DatabaseException de = new DatabaseException(TextPartOps_mysql.class,"UniStoreMessages","property.deserialize"); + de.setParameter(0,key.getName()); + throw de; + + } // end setProperty + + Object removeProperty(long msgid, int part, PropertyKey key) throws DatabaseException + { + String old_value = null; + Connection conn = null; + PreparedStatement stmt = null; + Statement stmt2 = null; + ResultSet rs = null; + try + { // get a connection + conn = getConnection(); + + // lock the table + stmt2 = conn.createStatement(); + stmt2.executeUpdate("LOCK TABLES us_text_prop WRITE;"); + + // look to see if the property value is already there + stmt = conn.prepareStatement("SELECT prop_value FROM us_text_prop WHERE msgid = ? AND part = ? AND nsid = ? " + + "AND prop_name = ?;"); + stmt.setLong(1,msgid); + stmt.setInt(2,part); + stmt.setInt(3,key.getNamespaceID()); + stmt.setString(4,key.getName()); + rs = stmt.executeQuery(); + if (rs.next()) + old_value = rs.getString(1); + else + return null; // no need to remove anything + SQLUtils.shutdown(rs); + rs = null; + SQLUtils.shutdown(stmt); + + // delete the database row + stmt = conn.prepareStatement("DELETE FROM us_text_prop WHERE msgid = ? AND part = ? AND nsid = ? " + + "AND prop_name = ?;"); + stmt.setLong(1,msgid); + stmt.setInt(2,part); + stmt.setInt(3,key.getNamespaceID()); + stmt.setString(4,key.getName()); + stmt.executeUpdate(); + + } // end try + catch (SQLException e) + { // translate to a general DatabaseException + throw generalException(e); + + } // end catch + finally + { // shut everything down + MySQLUtils.unlockTables(conn); + SQLUtils.shutdown(rs); + SQLUtils.shutdown(stmt); + SQLUtils.shutdown(stmt2); + SQLUtils.shutdown(conn); + + } // end finally + + // Deserialize the property value. + Object rc = m_psz.deserializeProperty(old_value); + if (rc!=null) + return rc; + + // deserialization exception - throw it + DatabaseException de = new DatabaseException(TextPartOps_mysql.class,"UniStoreMessages","property.deserialize"); + de.setParameter(0,key.getName()); + throw de; + + } // end removeProperty + + int[] getPropertyNamespaceIDs(long msgid, int part) throws DatabaseException + { + Connection conn = null; + PreparedStatement stmt = null; + ResultSet rs = null; + try + { // get a connection + conn = getConnection(); + + // execute the query! + stmt = conn.prepareStatement("SELECT DISTINCT nsid FROM us_text_prop WHERE msgid = ? AND part = ?;"); + stmt.setLong(1,msgid); + stmt.setInt(2,part); + rs = stmt.executeQuery(); + + // read out a list of the namespace IDs + ArrayList tmp = new ArrayList(); + while (rs.next()) + tmp.add(new Integer(rs.getInt(1))); + + // create and return the array + int[] rc = new int[tmp.size()]; + for (int i=0; i. + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.dynamo.unistore; + +import java.util.*; +import org.apache.log4j.Logger; +import org.w3c.dom.*; +import com.silverwrist.util.*; +import com.silverwrist.util.xml.*; +import com.silverwrist.dynamo.db.NamespaceCache; +import com.silverwrist.dynamo.db.UserManagement; +import com.silverwrist.dynamo.except.*; +import com.silverwrist.dynamo.iface.*; +import com.silverwrist.dynamo.security.SecurityReferenceMonitor; +import com.silverwrist.dynamo.util.*; + +public class UniStoreManager implements NamedObject, ComponentInitialize, ComponentShutdown, UniStore +{ + /*-------------------------------------------------------------------------------- + * Static data members + *-------------------------------------------------------------------------------- + */ + + private static Logger logger = Logger.getLogger(UniStoreManager.class); + + private static int DEFAULT_MSGCACHE_HARD = 100; + private static int DEFAULT_MSGCACHE_SOFT = 1000; + + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private String m_name; // name of this object + private NamespaceCache m_ns_cache; // namespace cache object + private ManagerOps m_ops; // database operations object + private SecurityReferenceMonitor m_srm; // security reference monitor + private UserManagement m_users; // user management object + private HardSoftCache m_msgcache; // message cache + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + public UniStoreManager() + { // do nothing + } // end constructor + + /*-------------------------------------------------------------------------------- + * Implementations from interface NamedObject + *-------------------------------------------------------------------------------- + */ + + public String getName() + { + return m_name; + + } // end getName + + /*-------------------------------------------------------------------------------- + * Implementations from interface ComponentInitialize + *-------------------------------------------------------------------------------- + */ + + /** + * Initialize the component. + * + * @param config_root Pointer to the section of the Dynamo XML configuration file that configures this + * particular component. This is to be considered "read-only" by the component. + * @param services An implementation of {@link com.silverwrist.dynamo.iface.ServiceProvider ServiceProvider} + * which provides initialization services to the component. This will include an implementation + * of {@link com.silverwrist.dynamo.iface.ObjectProvider ObjectProvider} which may be used to + * get information about other objects previously initialized by the application. + * @exception com.silverwrist.dynamo.except.ConfigException If an error is encountered in the component + * configuration. + */ + public void initialize(Element config_root, ServiceProvider services) throws ConfigException + { + logger.info("UniStoreManager initializing"); + XMLLoader loader = XMLLoader.get(); + String conn_name = null; + String nscache_name = null; + String srm_name = null; + String users_name = null; + int msgcache_hard = DEFAULT_MSGCACHE_HARD, msgcache_soft = DEFAULT_MSGCACHE_SOFT; + try + { // verify the right node name + loader.verifyNodeName(config_root,"object"); + + // get the object's name + m_name = loader.getAttribute(config_root,"name"); + + // get the database configuration connection + DOMElementHelper config_root_h = new DOMElementHelper(config_root); + Element elt = loader.getSubElement(config_root_h,"database"); + conn_name = loader.getAttribute(elt,"connection"); + nscache_name = loader.getAttribute(elt,"namespaces"); + + // get the security reference monitor name + elt = loader.getSubElement(config_root_h,"security"); + srm_name = loader.getAttribute(elt,"object"); + + // get the user management object name + elt = loader.getSubElement(config_root_h,"user-manager"); + users_name = loader.getAttribute(elt,"object"); + + // get the message cache configuration + elt = config_root_h.getSubElement("message-cache"); + if (elt!=null) + { // load the limits + msgcache_hard = loader.getAttributeInt(elt,"hardlimit",DEFAULT_MSGCACHE_HARD); + msgcache_soft = loader.getAttributeInt(elt,"softlimit",DEFAULT_MSGCACHE_SOFT); + + } // end if + + } // end try + catch (XMLLoadException e) + { // error loading XML config data + throw new ConfigException(e); + + } // end catch + + // Create the message cache. + m_msgcache = new HardSoftCache(msgcache_hard,msgcache_soft); + + // Get the database connection pool and namespace cache. + DBConnectionPool pool = GetObjectUtils.getDatabaseConnection(services,conn_name); + m_ns_cache = + (NamespaceCache)(GetObjectUtils.getDynamoComponent(services,NamespaceCache.class,nscache_name)); + + // Get the operations object. + m_ops = ManagerOps.get(pool); + + // Get the security reference monitor and user manager object.. + m_srm = (SecurityReferenceMonitor)(GetObjectUtils.getDynamoComponent(services,SecurityReferenceMonitor.class, + srm_name)); + m_users = (UserManagement)(GetObjectUtils.getDynamoComponent(services,UserManagement.class,users_name)); + + } // end initialize + + /*-------------------------------------------------------------------------------- + * Implementations from interface ComponentShutdown + *-------------------------------------------------------------------------------- + */ + + public void shutdown() + { + m_msgcache.clear(); + m_srm = null; + m_users = null; + m_ns_cache = null; + m_ops.dispose(); + m_ops = null; + + } // end shutdown + + /*-------------------------------------------------------------------------------- + * Implementations from interface UniStore + *-------------------------------------------------------------------------------- + */ + + public synchronized UniStoreMessage getMessage(long msgid) throws DatabaseException + { + Long key = new Long(msgid); + MessageImpl rc = (MessageImpl)(m_msgcache.get(key)); + if (rc==null) + { // need to look it up in the database! + Map params = m_ops.getMessageData(msgid); + rc = new MessageImpl(m_ops.getMessageOps(),m_ns_cache,m_srm,m_users,params); + params.clear(); + m_msgcache.put(key,rc); + + } // end if + + return rc; + + } // end getMessage + +} // end class UniStoreManager diff --git a/src/dynamo-framework/com/silverwrist/dynamo/unistore/UniStoreMessages.properties b/src/dynamo-framework/com/silverwrist/dynamo/unistore/UniStoreMessages.properties new file mode 100644 index 0000000..e540dfe --- /dev/null +++ b/src/dynamo-framework/com/silverwrist/dynamo/unistore/UniStoreMessages.properties @@ -0,0 +1,28 @@ +# The contents of this file are subject to the Mozilla Public License Version 1.1 +# (the "License"); you may not use this file except in compliance with the License. +# You may obtain a copy of the License at . +# +# Software distributed under the License is distributed on an "AS IS" basis, WITHOUT +# WARRANTY OF ANY KIND, either express or implied. See the License for the specific +# language governing rights and limitations under the License. +# +# The Original Code is the Venice Web Communities System. +# +# The Initial Developer of the Original Code is Eric J. Bowersox , +# for Silverwrist Design Studios. Portions created by Eric J. Bowersox are +# Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. +# +# Contributor(s): +# --------------------------------------------------------------------------------- +# This file has been localized for the en_US locale +no.message=Unable to find the message with ID #{0} in the Universal Message Store. +property.serialize=The value of property "{0}" could not be serialized. +property.deserialize=The value of property "{0}" could not be deserialized. +no.setProperty=You are not authorized to set properties on message #{0}. +no.removeProperty=You are not authorized to remove properties from message #{0}. +no.setParent=You are not authorized to change the parent message information of message #{0}. +no.setACL=You are not authorized to change the access control list of message #{0}. +bad.loadText.part=Unable to find text part #{0} of message #{1} in the Universal Message Store. +bad.loadText.id=Unable to find text part with ID {0}::{1} in message #{2} in the Universal Message Store. +bad.loadBinary.part=Unable to find binary part #{0} of message #{1} in the Universal Message Store. +bad.loadBinary.id=Unable to find binary part with ID {0}::{1} in message #{2} in the Universal Message Store.