001/* 002 * (C) Copyright 2018 Nuxeo (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 * pierre 018 */ 019package org.nuxeo.ecm.core.io.avro; 020 021import java.io.IOException; 022import java.nio.ByteBuffer; 023 024import org.apache.avro.Schema; 025import org.apache.avro.Schema.Field; 026import org.apache.avro.generic.GenericData; 027import org.apache.avro.generic.GenericRecord; 028import org.nuxeo.ecm.core.api.Blob; 029import org.nuxeo.ecm.core.api.Blobs; 030import org.nuxeo.ecm.core.api.model.impl.primitives.BlobProperty; 031import org.nuxeo.runtime.RuntimeServiceException; 032import org.nuxeo.runtime.avro.AvroMapper; 033import org.nuxeo.runtime.avro.AvroService; 034 035/** 036 * @since 10.2 037 */ 038public class BlobPropertyMapper extends AvroMapper<BlobProperty, Object> { 039 040 public BlobPropertyMapper(AvroService service) { 041 super(service); 042 } 043 044 @Override 045 public Object fromAvro(Schema schema, Object input) { 046 switch (schema.getType()) { 047 case NULL: 048 if (input == null) { 049 return null; 050 } 051 throw new NonNullValueException(); 052 case UNION: 053 for (Schema sub : schema.getTypes()) { 054 try { 055 return service.fromAvro(sub, BlobProperty.class, input); 056 } catch (NonNullValueException e) { 057 // this exception is thrown when a null value is expected and not found 058 // this happens for schema unions [null, schema] 059 } 060 } 061 throw new RuntimeServiceException(CANNOT_MAP_FROM + schema.getType()); 062 case RECORD: 063 try { 064 GenericRecord record = (GenericRecord) input; 065 String mimeType = (String) record.get(service.encodeName(AvroConstants.MIME_TYPE)); 066 String encoding = (String) record.get(AvroConstants.ENCODING); 067 byte[] bytes = ((ByteBuffer) record.get(AvroConstants.DATA)).array(); 068 Blob b = Blobs.createBlob(bytes, mimeType, encoding); 069 b.setFilename((String) record.get(AvroConstants.CONTENT_NAME)); 070 b.setDigest((String) record.get(AvroConstants.DIGEST)); 071 return b; 072 } catch (IOException e) { 073 throw new RuntimeServiceException(CANNOT_MAP_FROM + schema.getType(), e); 074 } 075 default: 076 throw new RuntimeServiceException(CANNOT_MAP_FROM + schema.getType()); 077 } 078 } 079 080 @Override 081 public Object toAvro(Schema schema, BlobProperty input) { 082 switch (schema.getType()) { 083 case NULL: 084 if (input == null) { 085 return null; 086 } 087 throw new NonNullValueException(); 088 case UNION: 089 for (Schema s : schema.getTypes()) { 090 try { 091 return service.toAvro(s, input); 092 } catch (NonNullValueException e) { 093 // ignore 094 } 095 } 096 throw new RuntimeServiceException(CANNOT_MAP_TO + schema.getType()); 097 case RECORD: 098 GenericRecord record = new GenericData.Record(schema); 099 for (Field f : schema.getFields()) { 100 if (AvroConstants.DATA.equals(f.name())) { 101 Blob blob = (Blob) input.getValue(); 102 try { 103 record.put(f.name(), ByteBuffer.wrap(blob.getByteArray())); 104 } catch (IOException e) { 105 throw new RuntimeServiceException(CANNOT_MAP_TO + schema.getType(), e); 106 } 107 } else { 108 record.put(f.name(), service.toAvro(f.schema(), input.get(service.decodeName(f.name())))); 109 } 110 } 111 return record; 112 default: 113 throw new RuntimeServiceException(CANNOT_MAP_TO + schema.getType()); 114 } 115 } 116 117}