001/* 002 * (C) Copyright 2008-2016 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 * Nuxeo - initial API and implementation 018 */ 019package org.nuxeo.ecm.platform.filemanager.core.listener; 020 021import java.io.Serializable; 022 023import org.apache.commons.logging.Log; 024import org.apache.commons.logging.LogFactory; 025import org.nuxeo.ecm.core.api.Blob; 026import org.nuxeo.ecm.core.api.DocumentModel; 027import org.nuxeo.ecm.core.api.PropertyException; 028import org.nuxeo.ecm.core.api.model.Property; 029import org.nuxeo.ecm.core.event.Event; 030import org.nuxeo.ecm.core.event.EventContext; 031import org.nuxeo.ecm.core.event.EventListener; 032import org.nuxeo.ecm.core.event.impl.DocumentEventContext; 033import org.nuxeo.ecm.core.schema.FacetNames; 034import org.nuxeo.ecm.core.utils.BlobsExtractor; 035import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeEntry; 036import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeRegistry; 037import org.nuxeo.ecm.platform.types.Type; 038import org.nuxeo.ecm.platform.types.TypeManager; 039import org.nuxeo.runtime.api.Framework; 040 041/** 042 * Listener responsible for computing the mimetype of a new or edited blob and the common:icon field if necessary. 043 * <p> 044 * The logic of this event listener is divided into static public methods to make it easy to override this event 045 * listener with a custom implementation. 046 * 047 * @author ogrisel 048 */ 049public class MimetypeIconUpdater implements EventListener { 050 051 protected Log log = LogFactory.getLog(MimetypeIconUpdater.class); 052 053 public static final String ICON_SCHEMA = "common"; 054 055 public static final String ICON_FIELD = ICON_SCHEMA + ":" + "icon"; 056 057 public static final String MAIN_BLOB_FIELD = "file:content"; 058 059 public static final String MAIN_BLOB_SCHEMA = "file"; 060 061 protected static final String OCTET_STREAM_MT = "application/octet-stream"; 062 063 public final BlobsExtractor blobExtractor = new BlobsExtractor(); 064 065 MimetypeRegistry mimetypeService; 066 067 public MimetypeRegistry getMimetypeRegistry() { 068 if (mimetypeService == null) { 069 mimetypeService = Framework.getService(MimetypeRegistry.class); 070 } 071 072 return mimetypeService; 073 } 074 075 public void handleEvent(Event event) { 076 077 EventContext ctx = event.getContext(); 078 if (ctx instanceof DocumentEventContext) { 079 080 DocumentEventContext docCtx = (DocumentEventContext) ctx; 081 DocumentModel doc = docCtx.getSourceDocument(); 082 083 // Don't update icon for immutable documents 084 if (doc.hasFacet(FacetNames.IMMUTABLE)) { 085 return; 086 } 087 088 try { 089 // ensure the document main icon is not null 090 setDefaultIcon(doc); 091 092 // update mimetypes of blobs in the document 093 for (Property prop : blobExtractor.getBlobsProperties(doc)) { 094 if (prop.isDirty()) { 095 updateBlobProperty(doc, getMimetypeRegistry(), prop); 096 } 097 } 098 099 // update the document icon and size according to the main blob 100 if (doc.hasSchema(MAIN_BLOB_SCHEMA) && doc.getProperty(MAIN_BLOB_FIELD).isDirty()) { 101 updateIconAndSizeFields(doc, getMimetypeRegistry(), 102 doc.getProperty(MAIN_BLOB_FIELD).getValue(Blob.class)); 103 } 104 } catch (PropertyException e) { 105 e.addInfo("Error in MimetypeIconUpdater listener"); 106 throw e; 107 } 108 } 109 } 110 111 /** 112 * Update the mimetype of a blob along with the icon and size fields of the document if the blob is the main blob of 113 * the document. 114 */ 115 public void updateBlobProperty(DocumentModel doc, MimetypeRegistry mimetypeService, Property dirtyProperty) { 116 String fieldPath = dirtyProperty.getXPath(); 117 if (!fieldPath.contains(":")) { 118 // for schema without prefix: we need to add schema name as prefix 119 fieldPath = dirtyProperty.getSchema().getName() + ":" + fieldPath; 120 } 121 122 Blob blob = dirtyProperty.getValue(Blob.class); 123 if (blob != null && (blob.getMimeType() == null || blob.getMimeType().equals(OCTET_STREAM_MT))) { 124 // update the mimetype (if not set) using the the mimetype registry 125 // service 126 blob = mimetypeService.updateMimetype(blob); 127 doc.setPropertyValue(fieldPath, (Serializable) blob); 128 } 129 } 130 131 private void updateIconAndSizeFields(DocumentModel doc, MimetypeRegistry mimetypeService, Blob blob) 132 throws PropertyException { 133 // update the icon field of the document 134 if (blob != null && !doc.isFolder()) { 135 MimetypeEntry mimetypeEntry = mimetypeService.getMimetypeEntryByMimeType(blob.getMimeType()); 136 updateIconField(mimetypeEntry, doc); 137 } else { 138 // reset to document type icon 139 updateIconField(null, doc); 140 } 141 } 142 143 /** 144 * If the icon field is empty, initialize it to the document type icon 145 */ 146 public void setDefaultIcon(DocumentModel doc) { 147 if (doc.hasSchema(ICON_SCHEMA) && doc.getProperty(ICON_FIELD).getValue(String.class) == null) { 148 updateIconField(null, doc); 149 } 150 } 151 152 /** 153 * Compute the main icon of a Nuxeo document based on the mimetype of the main attached blob with of fallback on the 154 * document type generic icon. 155 */ 156 public void updateIconField(MimetypeEntry mimetypeEntry, DocumentModel doc) { 157 String iconPath = null; 158 if (mimetypeEntry != null && mimetypeEntry.getIconPath() != null) { 159 iconPath = "/icons/" + mimetypeEntry.getIconPath(); 160 } else { 161 TypeManager typeManager = Framework.getService(TypeManager.class); 162 if (typeManager == null) { 163 return; 164 } 165 Type uiType = typeManager.getType(doc.getType()); 166 if (uiType != null) { 167 iconPath = uiType.getIcon(); 168 } 169 } 170 if (iconPath != null && doc.hasSchema(ICON_SCHEMA)) { 171 doc.setPropertyValue(ICON_FIELD, iconPath); 172 } 173 } 174 175}