com.silverwrist.dynamo.unistore.TextPartImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.silverwrist.dynamo.unistore.TextPartImpl.java

Source

/*
 * 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 <http://www.mozilla.org/MPL/>.
 * 
 * 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 <erbo@silcom.com>,
 * 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.Namespaces;
import com.silverwrist.dynamo.db.NamespaceCache;
import com.silverwrist.dynamo.event.*;
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 PostDynamicUpdate m_post;
    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;

    /*--------------------------------------------------------------------------------
     * Constructors
     *--------------------------------------------------------------------------------
     */

    TextPartImpl(TextPartOps ops, NamespaceCache nscache, PostDynamicUpdate post, MessageImpl parent, Map params)
            throws DatabaseException {
        m_ops = ops;
        m_nscache = nscache;
        m_post = post;
        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

    TextPartImpl(PostDynamicUpdate post, MessageImpl parent, int part, QualifiedNameKey identity) {
        m_ops = null;
        m_nscache = null;
        m_post = post;
        m_parent = parent;
        m_part = part;
        m_identity = identity;
        m_mimetype = null;
        m_size = -1;
        m_linecount = -1;
        m_nread = 0;
        m_lastread = null;
        m_properties = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT);

    } // end constructor

    /*--------------------------------------------------------------------------------
     * Overrides from class Object
     *--------------------------------------------------------------------------------
     */

    public String toString() {
        if (m_ops == null)
            return "(deleted text part)";
        return "message " + m_parent.getMessageID() + ", text part " + m_identity.toString();

    } // end toString

    /*--------------------------------------------------------------------------------
     * Implementations from interface ObjectProvider
     *--------------------------------------------------------------------------------
     */

    /**
     * Retrieves an object from this <CODE>ObjectProvider</CODE>.
     *
     * @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) {
        if (m_ops == null)
            throw new NoSuchObjectException(this.toString(), namespace, 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 <CODE>SecureObjectStore</CODE>.
     *
     * @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 <CODE>SecureObjectStore</CODE>.
     * @return The previous object that was set into the <CODE>SecureObjectStore</CODE> under this namespace and name, or
     *         <CODE>null</CODE> 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 <CODE>SecureObjectStore</CODE>.
     */
    public Object setObject(DynamoUser caller, String namespace, String name, Object value)
            throws DatabaseException, DynamoSecurityException {
        if (m_ops == null)
            throw new DatabaseException(TextPartImpl.class, "UniStoreMessages", "part.deleted");
        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

        m_post.postUpdate(new MessagePartPropertyUpdateEvent(this, namespace, name));
        return rc;

    } // end setObject

    /**
     * Removes an object from this <CODE>SecureObjectStore</CODE>.
     *
     * @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 <CODE>SecureObjectStore</CODE> under this namespace and name, or
     *         <CODE>null</CODE> 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 <CODE>SecureObjectStore</CODE>.
     */
    public Object removeObject(DynamoUser caller, String namespace, String name)
            throws DatabaseException, DynamoSecurityException {
        if (m_ops == null)
            throw new DatabaseException(TextPartImpl.class, "UniStoreMessages", "part.deleted");
        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

        m_post.postUpdate(new MessagePartPropertyUpdateEvent(this, namespace, name));
        return rc;

    } // end removeObject

    /**
     * Returns a collection of all object namespaces that have been set into this <CODE>SecureObjectStore</CODE>.
     *
     * @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 {
        if (m_ops == null)
            return Collections.EMPTY_LIST;

        // 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; i < ids.length; i++)
            rc.add(m_nscache.namespaceIdToName(ids[i]));
        return Collections.unmodifiableList(rc);

    } // end getNamespaces

    /**
     * Returns a collection of all object names that have been set into this <CODE>SecureObjectStore</CODE> 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 {
        if (m_ops == null)
            return Collections.EMPTY_LIST;

        // 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 == null) ? -1L : m_parent.getMessageID();

    } // end getMessageID

    public UniStoreMessage getMessage() {
        return m_parent;

    } // end getMessage

    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 {
        if (m_ops == null)
            throw new DatabaseException(TextPartImpl.class, "UniStoreMessages", "part.deleted");
        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

        m_post.postUpdate(new MessagePartRead(this));

    } // end touchRead

    public synchronized void delete(DynamoUser caller) throws DatabaseException, DynamoSecurityException {
        if (m_ops == null)
            throw new DatabaseException(TextPartImpl.class, "UniStoreMessages", "part.deleted");
        m_parent.testPermission(caller, Namespaces.UNISTORE_PERMISSIONS_NAMESPACE, "delete.part", "no.deletePart");

        // Cut this object loose from the parent.
        m_parent.deletedTextPart(m_part, m_identity);

        // Zap it from the database.
        m_ops.delete(m_parent.getMessageID(), m_part);

        baleeted(); // BALEETED!

    } // end delete

    /*--------------------------------------------------------------------------------
     * Implementations from interface UniStoreTextPart
     *--------------------------------------------------------------------------------
     */

    public int getLineCount() {
        return m_linecount;

    } // end getLineCount

    public synchronized String getText() throws DatabaseException {
        if (m_ops == null)
            throw new DatabaseException(TextPartImpl.class, "UniStoreMessages", "part.deleted");
        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 {
        if (m_ops == null)
            throw new DatabaseException(TextPartImpl.class, "UniStoreMessages", "part.deleted");
        return new StringReader(this.getText());

    } // end getTextAsReader

    /*--------------------------------------------------------------------------------
     * External operations
     *--------------------------------------------------------------------------------
     */

    void precacheText(String txt) {
        m_text = new SoftReference(txt);

    } // end txt

    void resetPartNumber(int new_num) {
        m_part = new_num;

    } // end resetPartNumber

    /**
     * Called after the part has been deleted, either alone or through the entire message being deleted.  This
     * method nulls out the internal data of the object and posts a "part-deleted" notification.<P>
     * See <A HREF="http://www.homestarrunner.com/sbemail50.html">this page</A> for the source of the method name.
     */
    synchronized void baleeted() {
        // Cut loose most of our data before we post an update event.
        m_ops = null;
        m_nscache = null;
        m_mimetype = null;
        m_size = -1;
        m_linecount = -1;
        m_nread = 0;
        m_lastread = null;
        m_properties.clear();
        if (m_text != null)
            m_text.clear();
        m_text = null;

        // Post the "deleted" notification event.
        m_post.postUpdate(new MessagePartDeletedEvent(this));

        // Now cut loose the rest of our data.
        m_post = null;
        m_parent = null;
        m_part = -1;
        m_identity = null;

    } // end baleeted

} // end class TextPartImpl