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.CheckArg;
032 import org.jboss.dna.common.util.Logger;
033 import org.jboss.dna.graph.GraphI18n;
034 import org.jboss.dna.graph.properties.Binary;
035 import org.jboss.dna.graph.properties.ValueComparators;
036
037 /**
038 * An implementation of {@link Binary} that keeps the binary data in-memory.
039 *
040 * @author Randall Hauch
041 */
042 @Immutable
043 public class InMemoryBinary implements Binary {
044
045 protected static final Set<String> ALGORITHMS_NOT_FOUND_AND_LOGGED = new CopyOnWriteArraySet<String>();
046 private static final String SHA1DIGEST_NAME = "SHA-1";
047 private static final byte[] NO_HASH = new byte[] {};
048
049 /**
050 */
051 private static final long serialVersionUID = 8792863149767123559L;
052
053 protected static final byte[] EMPTY_CONTENT = new byte[0];
054
055 private final byte[] bytes;
056 private byte[] sha1hash;
057
058 public InMemoryBinary( byte[] bytes ) {
059 CheckArg.isNotNull(bytes, "bytes");
060 this.bytes = bytes;
061 }
062
063 /**
064 * {@inheritDoc}
065 */
066 public long getSize() {
067 return this.bytes.length;
068 }
069
070 /**
071 * {@inheritDoc}
072 *
073 * @see org.jboss.dna.graph.properties.Binary#getHash()
074 */
075 public byte[] getHash() {
076 if (sha1hash == null) {
077 // Omnipotent, so doesn't matter if we recompute in concurrent threads ...
078 try {
079 sha1hash = getHash(SHA1DIGEST_NAME);
080 } catch (NoSuchAlgorithmException e) {
081 if (ALGORITHMS_NOT_FOUND_AND_LOGGED.add(SHA1DIGEST_NAME)) {
082 Logger.getLogger(getClass()).error(e, GraphI18n.messageDigestNotFound, SHA1DIGEST_NAME);
083 }
084 sha1hash = NO_HASH;
085 }
086 }
087 return sha1hash;
088 }
089
090 /**
091 * Get the hash of the contents, using the digest identified by the supplied name.
092 *
093 * @param digestName the name of the hashing function (or {@link MessageDigest message digest}) that should be used
094 * @return the hash of the contents as a byte array
095 * @throws NoSuchAlgorithmException if the supplied algorithm could not be found
096 */
097 protected byte[] getHash( String digestName ) throws NoSuchAlgorithmException {
098 MessageDigest digest = MessageDigest.getInstance(digestName);
099 assert digest != null;
100 return digest.digest(bytes);
101 }
102
103 /**
104 * {@inheritDoc}
105 */
106 public byte[] getBytes() {
107 return this.bytes;
108 }
109
110 /**
111 * {@inheritDoc}
112 */
113 public InputStream getStream() {
114 return new ByteArrayInputStream(this.bytes);
115 }
116
117 /**
118 * {@inheritDoc}
119 */
120 public void acquire() {
121 // do nothing
122 }
123
124 /**
125 * {@inheritDoc}
126 */
127 public void release() {
128 // do nothing
129 }
130
131 /**
132 * {@inheritDoc}
133 */
134 public int compareTo( Binary o ) {
135 return ValueComparators.BINARY_COMPARATOR.compare(this, o);
136 }
137
138 /**
139 * {@inheritDoc}
140 */
141 @Override
142 public boolean equals( Object obj ) {
143 if (obj == this) return true;
144 if (obj instanceof Binary) {
145 Binary that = (Binary)obj;
146 if (this.getSize() != that.getSize()) return false;
147 return ValueComparators.BINARY_COMPARATOR.compare(this, that) == 0;
148 }
149 return false;
150 }
151
152 /**
153 * {@inheritDoc}
154 */
155 @Override
156 public String toString() {
157 StringBuilder sb = new StringBuilder(super.toString());
158 sb.append(" len=").append(getSize()).append("; [");
159 int len = (int)Math.min(getSize(), 20l);
160 for (int i = 0; i != len; ++i) {
161 if (i != 0) sb.append(',');
162 sb.append(this.bytes[i]);
163 }
164 return sb.toString();
165 }
166
167 }