001 /*
002 * JBoss, Home of Professional Open Source.
003 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
004 * as indicated by the @author tags. See the copyright.txt file in the
005 * distribution for a full listing of individual contributors.
006 *
007 * This is free software; you can redistribute it and/or modify it
008 * under the terms of the GNU Lesser General Public License as
009 * published by the Free Software Foundation; either version 2.1 of
010 * the License, or (at your option) any later version.
011 *
012 * This software is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this software; if not, write to the Free
019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021 */
022 package org.jboss.dna.graph.properties.basic;
023
024 import java.io.ByteArrayInputStream;
025 import java.io.InputStream;
026 import java.security.MessageDigest;
027 import java.security.NoSuchAlgorithmException;
028 import java.util.Set;
029 import java.util.concurrent.CopyOnWriteArraySet;
030 import net.jcip.annotations.Immutable;
031 import org.jboss.dna.common.util.Base64;
032 import org.jboss.dna.common.util.CheckArg;
033 import org.jboss.dna.common.util.Logger;
034 import org.jboss.dna.graph.GraphI18n;
035 import org.jboss.dna.graph.properties.Binary;
036 import org.jboss.dna.graph.properties.ValueComparators;
037
038 /**
039 * An implementation of {@link Binary} that keeps the binary data in-memory.
040 *
041 * @author Randall Hauch
042 */
043 @Immutable
044 public class InMemoryBinary implements Binary {
045
046 protected static final Set<String> ALGORITHMS_NOT_FOUND_AND_LOGGED = new CopyOnWriteArraySet<String>();
047 private static final String SHA1DIGEST_NAME = "SHA-1";
048 private static final byte[] NO_HASH = new byte[] {};
049
050 /**
051 */
052 private static final long serialVersionUID = 8792863149767123559L;
053
054 protected static final byte[] EMPTY_CONTENT = new byte[0];
055
056 private final byte[] bytes;
057 private byte[] sha1hash;
058
059 public InMemoryBinary( byte[] bytes ) {
060 CheckArg.isNotNull(bytes, "bytes");
061 this.bytes = bytes;
062 }
063
064 /**
065 * {@inheritDoc}
066 */
067 public long getSize() {
068 return this.bytes.length;
069 }
070
071 /**
072 * {@inheritDoc}
073 *
074 * @see org.jboss.dna.graph.properties.Binary#getHash()
075 */
076 public byte[] getHash() {
077 if (sha1hash == null) {
078 // Omnipotent, so doesn't matter if we recompute in concurrent threads ...
079 try {
080 sha1hash = getHash(SHA1DIGEST_NAME);
081 } catch (NoSuchAlgorithmException e) {
082 if (ALGORITHMS_NOT_FOUND_AND_LOGGED.add(SHA1DIGEST_NAME)) {
083 Logger.getLogger(getClass()).error(e, GraphI18n.messageDigestNotFound, SHA1DIGEST_NAME);
084 }
085 sha1hash = NO_HASH;
086 }
087 }
088 return sha1hash;
089 }
090
091 /**
092 * Get the hash of the contents, using the digest identified by the supplied name.
093 *
094 * @param digestName the name of the hashing function (or {@link MessageDigest message digest}) that should be used
095 * @return the hash of the contents as a byte array
096 * @throws NoSuchAlgorithmException if the supplied algorithm could not be found
097 */
098 protected byte[] getHash( String digestName ) throws NoSuchAlgorithmException {
099 MessageDigest digest = MessageDigest.getInstance(digestName);
100 assert digest != null;
101 return digest.digest(bytes);
102 }
103
104 /**
105 * {@inheritDoc}
106 */
107 public byte[] getBytes() {
108 return this.bytes;
109 }
110
111 /**
112 * {@inheritDoc}
113 */
114 public InputStream getStream() {
115 return new ByteArrayInputStream(this.bytes);
116 }
117
118 /**
119 * {@inheritDoc}
120 */
121 public void acquire() {
122 // do nothing
123 }
124
125 /**
126 * {@inheritDoc}
127 */
128 public void release() {
129 // do nothing
130 }
131
132 /**
133 * {@inheritDoc}
134 */
135 public int compareTo( Binary o ) {
136 return ValueComparators.BINARY_COMPARATOR.compare(this, o);
137 }
138
139 /**
140 * {@inheritDoc}
141 */
142 @Override
143 public boolean equals( Object obj ) {
144 if (obj == this) return true;
145 if (obj instanceof Binary) {
146 Binary that = (Binary)obj;
147 if (this.getSize() != that.getSize()) return false;
148 return ValueComparators.BINARY_COMPARATOR.compare(this, that) == 0;
149 }
150 return false;
151 }
152
153 /**
154 * {@inheritDoc}
155 */
156 @Override
157 public String toString() {
158 StringBuilder sb = new StringBuilder(super.toString());
159 sb.append(" len=").append(getSize()).append("; [");
160 sb.append(Base64.encodeBytes(this.bytes));
161 return sb.toString();
162 }
163
164 }