001/* 002 * (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nuxeo - initial API and implementation 016 * 017 * $Id$ 018 */ 019 020package org.nuxeo.ecm.platform.filemanager.core.listener; 021 022import java.io.IOException; 023import java.security.DigestInputStream; 024import java.security.MessageDigest; 025import java.security.NoSuchAlgorithmException; 026import java.util.List; 027 028import org.apache.commons.logging.Log; 029import org.apache.commons.logging.LogFactory; 030import org.nuxeo.common.utils.Base64; 031import org.nuxeo.ecm.core.api.Blob; 032import org.nuxeo.ecm.core.api.DocumentModel; 033import org.nuxeo.ecm.core.api.PropertyException; 034import org.nuxeo.ecm.core.api.model.Property; 035import org.nuxeo.ecm.core.event.Event; 036import org.nuxeo.ecm.core.event.EventContext; 037import org.nuxeo.ecm.core.event.EventListener; 038import org.nuxeo.ecm.core.event.impl.DocumentEventContext; 039import org.nuxeo.ecm.platform.filemanager.api.FileManager; 040import org.nuxeo.runtime.api.Framework; 041 042import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.ABOUT_TO_CREATE; 043import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.BEFORE_DOC_UPDATE; 044 045public class DigestComputer implements EventListener { 046 047 private boolean initDone = false; 048 049 private List<String> xpathFields; 050 051 private String digestAlgo = "sha-256"; 052 053 private Boolean activateDigestComputation = false; 054 055 private static final Log log = LogFactory.getLog(DigestComputer.class); 056 057 private boolean initIfNeeded() { 058 if (!initDone) { 059 FileManager fm = Framework.getService(FileManager.class); 060 xpathFields = fm.getFields(); 061 digestAlgo = fm.getDigestAlgorithm(); 062 activateDigestComputation = fm.isDigestComputingEnabled(); 063 initDone = true; 064 } 065 return initDone; 066 } 067 068 private void addDigestToDocument(DocumentModel doc) { 069 for (String xpathField : xpathFields) { 070 Property blobProp = null; 071 try { 072 blobProp = doc.getProperty(xpathField); 073 } catch (PropertyException e) { 074 log.debug("Property " + xpathField + " not found on doc, skipping"); 075 } 076 if (blobProp != null && !blobProp.isPhantom() && blobProp.isDirty()) { 077 try { 078 Blob blob = (Blob) blobProp.getValue(); 079 if (blob != null) { 080 String digest = computeDigest(blob); 081 if (!digest.equals(blob.getDigest())) { 082 blob.setDigest(digest); 083 } 084 } 085 } catch (PropertyException | IOException e) { 086 log.error("Error while trying to save blob digest", e); 087 } 088 } 089 } 090 } 091 092 private String computeDigest(Blob blob) throws IOException { 093 094 MessageDigest md; 095 try { 096 md = MessageDigest.getInstance(digestAlgo); 097 } catch (NoSuchAlgorithmException e) { 098 throw new RuntimeException(e); 099 } 100 101 DigestInputStream dis = new DigestInputStream(blob.getStream(), md); 102 while (dis.available() > 0) { 103 dis.read(); 104 } 105 byte[] b = md.digest(); 106 return Base64.encodeBytes(b); 107 } 108 109 public void handleEvent(Event event) { 110 if (!initIfNeeded()) { 111 return; 112 } 113 114 if (!activateDigestComputation) { 115 return; 116 } 117 118 EventContext ctx = event.getContext(); 119 String evt = event.getName(); 120 if (ABOUT_TO_CREATE.equals(evt) || BEFORE_DOC_UPDATE.equals(evt)) { 121 122 if (ctx instanceof DocumentEventContext) { 123 DocumentEventContext docCtx = (DocumentEventContext) ctx; 124 DocumentModel doc = docCtx.getSourceDocument(); 125 if (doc == null || doc.isProxy()) { 126 return; 127 } 128 addDigestToDocument(doc); 129 } 130 } 131 } 132 133}