/* * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. * * The Sun Project JXTA(TM) Software License * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. The end-user documentation included with the redistribution, if any, must * include the following acknowledgment: "This product includes software * developed by Sun Microsystems, Inc. for JXTA(TM) technology." * Alternately, this acknowledgment may appear in the software itself, if * and wherever such third-party acknowledgments normally appear. * * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must * not be used to endorse or promote products derived from this software * without prior written permission. For written permission, please contact * Project JXTA at http://www.jxta.org. * * 5. Products derived from this software may not be called "JXTA", nor may * "JXTA" appear in their name, without prior written permission of Sun. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * JXTA is a registered trademark of Sun Microsystems, Inc. in the United * States and other countries. * * Please see the license information page at : * <http://www.jxta.org/project/www/license.html> for instructions on use of * the license in source files. * * ==================================================================== * * This software consists of voluntary contributions made by many individuals * on behalf of Project JXTA. For more information on Project JXTA, please see * http://www.jxta.org. * * This license is based on the BSD license adopted by the Apache Foundation. */ package net.jxta.endpoint; import net.jxta.document.MimeMediaType; import net.jxta.document.TextDocument; import net.jxta.logging.Logging; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.lang.ref.SoftReference; import java.util.logging.Level; import java.util.logging.Logger; /** * A Message Element using JXTA TextDocument for the element data. */ public class TextDocumentMessageElement extends TextMessageElement { /** * Log4J Logger */ private static final Logger LOG = Logger.getLogger(TextDocumentMessageElement.class.getName()); /** * The data for this element. */ protected TextDocument doc; /** * Create a new Message Element from the provided Document. * * @param name Name of the Element. May be the empty string ("") or null if * the Element is not named. * @param doc A Document containing the contents of this element. * @param sig optional message digest/digital signature elemnent. If * no signature is to be specified, pass null. */ public TextDocumentMessageElement(String name, TextDocument doc, MessageElement sig) { super(name, doc.getMimeType(), sig); this.doc = doc; } /** * {@inheritDoc} */ @Override public boolean equals(Object target) { if (this == target) { return true; } if (target instanceof MessageElement) { if (!super.equals(target)) { return false; } if (target instanceof TextMessageElement) { // have to do a slow char by char comparison. Still better than the stream since it saves encoding. // XXX 20020615 bondolo@jxta.org the performance of this could be much improved. TextMessageElement likeMe = (TextMessageElement) target; try { Reader myReader = getReader(); Reader itsReader = likeMe.getReader(); int mine; int its; do { mine = myReader.read(); its = itsReader.read(); if (mine != its) { return false; } // content didn't match } while ((-1 != mine) && (-1 != its)); return ((-1 == mine) && (-1 == its)); // end at the same time? } catch (IOException fatal) { throw new IllegalStateException("MessageElements could not be compared." + fatal); } } else { // have to do a slow stream comparison. // XXX 20020615 bondolo@jxta.org the performance of this could be much improved. MessageElement likeMe = (MessageElement) target; try { InputStream myStream = getStream(); InputStream itsStream = likeMe.getStream(); int mine; int its; do { mine = myStream.read(); its = itsStream.read(); if (mine != its) { return false; } // content didn't match } while ((-1 != mine) && (-1 != its)); return ((-1 == mine) && (-1 == its)); // end at the same time? } catch (IOException fatal) { throw new IllegalStateException("MessageElements could not be compared." + fatal); } } } return false; // not a new message element } /** * {@inheritDoc} */ @Override public int hashCode() { int result = super.hashCode() * 6037 + // a prime toString().hashCode(); return result; } /** * {@inheritDoc} */ @Override public synchronized String toString() { String result; if (null != cachedToString) { result = cachedToString.get(); if (null != result) { return result; } } if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("creating toString of " + getClass().getName() + "@" + super.hashCode()); } result = doc.toString(); cachedToString = new SoftReference<String>(result); return result; } /** * {@inheritDoc} */ @Override public MimeMediaType getMimeType() { return doc.getMimeType(); } /** * {@inheritDoc} */ @Override public String getFileExtension() { return doc.getFileExtension(); } /** * {@inheritDoc} */ public InputStream getStream() throws IOException { byte[] sending = getBytes(false); return new ByteArrayInputStream(sending); } /** * {@inheritDoc} */ @Override public void sendToStream(OutputStream sendTo) throws IOException { byte[] sending = getBytes(false); sendTo.write(sending, 0, sending.length); } /** * {@inheritDoc} */ public Reader getReader() throws IOException { return doc.getReader(); } /** * {@inheritDoc} */ @Override public void sendToWriter(Writer sendTo) throws IOException { doc.sendToWriter(sendTo); } /** * {@inheritDoc} */ @Override public byte[] getBytes(boolean copy) { byte[] result; if (null != cachedGetBytes) { result = cachedGetBytes.get(); if (null != result) { if (copy) { byte[] theCopy = new byte[result.length]; System.arraycopy(theCopy, 0, result, 0, result.length); } else { return result; } } } if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("creating getBytes of " + getClass().getName() + '@' + Integer.toHexString(hashCode())); } String charset = type.getParameter("charset"); if (null == charset) { result = toString().getBytes(); } else { try { result = toString().getBytes(charset); } catch (UnsupportedEncodingException caught) { if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.log(Level.WARNING, "MessageElement Data could not be generated", caught); } throw new IllegalStateException("MessageElement Data could not be generated due to " + caught.getMessage()); } } // if this is supposed to be a shared buffer then we can cache it. if (!copy) { cachedGetBytes = new SoftReference<byte[]>(result); } return result; } /** * {@inheritDoc} */ @Override public long getCharLength() { return toString().length(); } /** * {@inheritDoc} */ @Override public char[] getChars(boolean copy) { char[] result; if (null != cachedGetChars) { result = cachedGetChars.get(); if (null != result) { if (copy) { char[] theCopy = new char[result.length]; System.arraycopy(theCopy, 0, result, 0, result.length); } else { return result; } } } if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("creating getChars of " + getClass().getName() + '@' + Integer.toHexString(hashCode())); } String asString = toString(); result = asString.toCharArray(); // if this is supposed to be a shared buffer then we can cache it. if (!copy) { cachedGetChars = new SoftReference<char[]>(result); } return result; } }