001/* 002 * (C) Copyright 2006-2014 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Bogdan Stefanescu 018 * Florent Guillaume 019 */ 020package org.nuxeo.ecm.core.api.model.impl.primitives; 021 022import java.io.ByteArrayInputStream; 023import java.io.Serializable; 024import java.util.Map; 025 026import org.apache.commons.lang.ObjectUtils; 027import org.nuxeo.ecm.core.api.Blob; 028import org.nuxeo.ecm.core.api.NuxeoException; 029import org.nuxeo.ecm.core.api.PropertyException; 030import org.nuxeo.ecm.core.api.model.Property; 031import org.nuxeo.ecm.core.api.model.PropertyConversionException; 032import org.nuxeo.ecm.core.api.model.PropertyNotFoundException; 033import org.nuxeo.ecm.core.api.model.impl.MapProperty; 034import org.nuxeo.ecm.core.api.model.impl.ScalarProperty; 035import org.nuxeo.ecm.core.schema.types.Field; 036 037/** 038 * Blob property, reading and writing from a {@link Blob} object. 039 */ 040public class BlobProperty extends MapProperty { 041 042 private static final long serialVersionUID = 1L; 043 044 private static final String NAME = "name"; 045 046 private static final String MIME_TYPE = "mime-type"; 047 048 private static final String ENCODING = "encoding"; 049 050 private static final String DIGEST = "digest"; 051 052 private static final String LENGTH = "length"; 053 054 protected Serializable value; 055 056 public BlobProperty(Property parent, Field field, int flags) { 057 super(parent, field, flags); 058 } 059 060 @Override 061 public Serializable getDefaultValue() { 062 return null; 063 } 064 065 @Override 066 public Serializable internalGetValue() throws PropertyException { 067 return value; 068 } 069 070 @Override 071 public void internalSetValue(Serializable value) throws PropertyException { 072 this.value = value; 073 } 074 075 @Override 076 public final Object clone() throws CloneNotSupportedException { 077 return (BlobProperty) super.clone(); 078 } 079 080 @Override 081 public boolean isNormalized(Object value) { 082 return value == null || ((value instanceof Blob) && (value instanceof Serializable)); 083 } 084 085 @Override 086 public Serializable normalize(Object value) throws PropertyConversionException { 087 if (isNormalized(value)) { 088 // TODO specific blob support? 089 return (Serializable) value; 090 } 091 throw new PropertyConversionException(value.getClass(), Blob.class); 092 } 093 094 @SuppressWarnings("unchecked") 095 @Override 096 public <T> T convertTo(Serializable value, Class<T> toType) throws PropertyConversionException { 097 if (value == null) { 098 return null; 099 } 100 if (Blob.class.isAssignableFrom(toType)) { 101 return (T) value; 102 } 103 throw new PropertyConversionException(value.getClass(), toType); 104 } 105 106 @Override 107 public Object newInstance() { 108 return new ByteArrayInputStream("".getBytes()); // TODO not serializable 109 } 110 111 @Override 112 public boolean isContainer() { 113 return false; 114 } 115 116 @SuppressWarnings("unchecked") 117 @Override 118 public void setValue(Object value) throws PropertyException { 119 if (value instanceof Map) { 120 setMap(getValue(), (Map<String, Object>) value); 121 setIsModified(); 122 } else { 123 super.setValue(value); 124 } 125 } 126 127 @Override 128 protected boolean isSameValue(Serializable value1, Serializable value2) { 129 // for now, blob property are considered always as dirty when update - see NXP-16322 130 return false; 131 } 132 133 @Override 134 public void init(Serializable value) throws PropertyException { 135 if (value == null) { 136 // IGNORE null values - properties will be 137 // considered PHANTOMS 138 return; 139 } 140 if (value instanceof Blob) { 141 internalSetValue(value); 142 } 143 removePhantomFlag(); 144 } 145 146 @Override 147 public Serializable getValueForWrite() throws PropertyException { 148 return getValue(); 149 } 150 151 @Override 152 protected Property internalGetChild(Field field) { 153 return new ScalarMemberProperty(this, field, isPhantom() ? IS_PHANTOM : 0); 154 } 155 156 protected void setMap(Object object, Map<String, Object> value) throws PropertyException { 157 if (object == null) { 158 throw new NuxeoException("Trying to access a member of a null object"); 159 } 160 if (!(object instanceof Blob)) { 161 throw new NuxeoException("Not a Blob: " + object); 162 } 163 Blob blob = (Blob) object; 164 for (Entry<String, Object> entry : value.entrySet()) { 165 String name = entry.getKey(); 166 Object v = entry.getValue(); 167 setMemberValue(blob, name, v); 168 } 169 } 170 171 protected void setMemberValue(Blob blob, String name, Object value) throws PropertyNotFoundException { 172 if (NAME.equals(name)) { 173 blob.setFilename((String) value); 174 } else if (MIME_TYPE.equals(name)) { 175 blob.setMimeType((String) value); 176 } else if (ENCODING.equals(name)) { 177 blob.setEncoding((String) value); 178 } else if (DIGEST.equals(name)) { 179 blob.setDigest((String) value); 180 } else { 181 throw new PropertyNotFoundException(name); 182 } 183 } 184 185 protected Object getMemberValue(Object object, String name) throws PropertyException { 186 if (object == null) { 187 throw new NuxeoException("Trying to access a member of a null object: " + name); 188 } 189 if (!(object instanceof Blob)) { 190 throw new NuxeoException("Not a Blob: " + object); 191 } 192 Blob blob = (Blob) object; 193 if (NAME.equals(name)) { 194 return blob.getFilename(); 195 } else if (MIME_TYPE.equals(name)) { 196 return blob.getMimeType(); 197 } else if (ENCODING.equals(name)) { 198 return blob.getEncoding(); 199 } else if (DIGEST.equals(name)) { 200 return blob.getDigest(); 201 } else if (LENGTH.equals(name)) { 202 return Long.valueOf(blob.getLength()); 203 } else { 204 throw new PropertyNotFoundException(name); 205 } 206 } 207 208 protected void setMemberValue(Object object, String name, Object value) throws PropertyException { 209 if (object == null) { 210 throw new NuxeoException("Trying to access a member of a null object: " + name); 211 } 212 if (!(object instanceof Blob)) { 213 throw new NuxeoException("Not a Blob: " + object); 214 } 215 Blob blob = (Blob) object; 216 setMemberValue(blob, name, value); 217 } 218 219 public static class ScalarMemberProperty extends ScalarProperty { 220 221 private static final long serialVersionUID = 1L; 222 223 public ScalarMemberProperty(Property parent, Field field, int flags) { 224 super(parent, field, flags); 225 } 226 227 @Override 228 public void internalSetValue(Serializable value) throws PropertyException { 229 ((BlobProperty) parent).setMemberValue(parent.getValue(), getName(), value); 230 } 231 232 @Override 233 public Serializable internalGetValue() throws PropertyException { 234 Object value = ((BlobProperty) parent).getMemberValue(parent.getValue(), getName()); 235 if (value != null && !(value instanceof Serializable)) { 236 throw new PropertyException("Non serializable value: " + value); 237 } 238 return (Serializable) value; 239 } 240 } 241 242 @Override 243 public boolean isSameAs(Property property) throws PropertyException { 244 if (!(property instanceof BlobProperty)) { 245 return false; 246 } 247 BlobProperty other = (BlobProperty) property; 248 return ObjectUtils.equals(getValue(), other.getValue()); 249 } 250 251}