001/* 002 * (C) Copyright 2006-2012 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 * <a href="mailto:tdelprat@nuxeo.com">Tiry</a> 018 */ 019 020package org.nuxeo.ecm.quota.size; 021 022import org.apache.commons.logging.Log; 023import org.apache.commons.logging.LogFactory; 024import org.nuxeo.ecm.core.api.DocumentModel; 025import org.nuxeo.ecm.core.api.PropertyException; 026import org.nuxeo.ecm.core.api.model.DeltaLong; 027import org.nuxeo.ecm.quota.QuotaStatsService; 028import org.nuxeo.ecm.quota.QuotaUtils; 029import org.nuxeo.runtime.api.Framework; 030 031/** 032 * Adapter to manage a DocumentModel that supports Quotas 033 * 034 * @author <a href="mailto:tdelprat@nuxeo.com">Tiry</a> 035 * @since 5.6 036 */ 037public class QuotaAwareDocument implements QuotaAware { 038 039 public static final String DOCUMENTS_SIZE_STATISTICS_FACET = "DocumentsSizeStatistics"; 040 041 public static final String DOCUMENTS_SIZE_INNER_SIZE_PROPERTY = "dss:innerSize"; 042 043 public static final String DOCUMENTS_SIZE_TOTAL_SIZE_PROPERTY = "dss:totalSize"; 044 045 public static final String DOCUMENTS_SIZE_TRASH_SIZE_PROPERTY = "dss:sizeTrash"; 046 047 public static final String DOCUMENTS_SIZE_VERSIONS_SIZE_PROPERTY = "dss:sizeVersions"; 048 049 public static final String DOCUMENTS_SIZE_MAX_SIZE_PROPERTY = "dss:maxSize"; 050 051 protected DocumentModel doc; 052 053 protected static final Log log = LogFactory.getLog(QuotaAwareDocument.class); 054 055 public QuotaAwareDocument(DocumentModel doc) { 056 this.doc = doc; 057 } 058 059 @Override 060 public DocumentModel getDoc() { 061 return doc; 062 } 063 064 @Override 065 public long getInnerSize() { 066 try { 067 Number size = (Number) doc.getPropertyValue(DOCUMENTS_SIZE_INNER_SIZE_PROPERTY); 068 return size == null ? 0 : size.longValue(); 069 } catch (PropertyException e) { 070 return 0; 071 } 072 } 073 074 @Override 075 public long getTotalSize() { 076 try { 077 Number size = (Number) doc.getPropertyValue(DOCUMENTS_SIZE_TOTAL_SIZE_PROPERTY); 078 return size == null ? 0 : size.longValue(); 079 } catch (PropertyException e) { 080 return 0; 081 } 082 } 083 084 @Override 085 public long getTrashSize() { 086 try { 087 Number size = (Number) doc.getPropertyValue(DOCUMENTS_SIZE_TRASH_SIZE_PROPERTY); 088 return size == null ? 0 : size.longValue(); 089 } catch (PropertyException e) { 090 return 0; 091 } 092 } 093 094 @Override 095 public long getVersionsSize() { 096 try { 097 Number size = (Number) doc.getPropertyValue(DOCUMENTS_SIZE_VERSIONS_SIZE_PROPERTY); 098 return size == null ? 0 : size.longValue(); 099 } catch (PropertyException e) { 100 return 0; 101 } 102 } 103 104 protected Number addDelta(String property, long delta) { 105 Number oldValue = (Number) doc.getPropertyValue(property); 106 DeltaLong newValue = DeltaLong.valueOf(oldValue, delta); 107 doc.setPropertyValue(property, newValue); 108 return newValue; 109 } 110 111 @Override 112 public void addInnerSize(long delta) { 113 Number inner = addDelta(DOCUMENTS_SIZE_INNER_SIZE_PROPERTY, delta); 114 if (log.isDebugEnabled()) { 115 log.debug("Setting quota (inner size) : " + inner + " on document " + doc.getId()); 116 } 117 } 118 119 @Override 120 public void addTotalSize(long delta) { 121 Number total = addDelta(DOCUMENTS_SIZE_TOTAL_SIZE_PROPERTY, delta); 122 if (log.isDebugEnabled()) { 123 log.debug("Setting quota (total size) : " + total + " on document " + doc.getId()); 124 } 125 } 126 127 @Override 128 public void addTrashSize(long delta) { 129 Number trash = addDelta(DOCUMENTS_SIZE_TRASH_SIZE_PROPERTY, delta); 130 if (log.isDebugEnabled()) { 131 log.debug("Setting quota (trash size):" + trash + " on document " + doc.getId()); 132 } 133 } 134 135 @Override 136 public void addVersionsSize(long delta) { 137 Number versions = addDelta(DOCUMENTS_SIZE_VERSIONS_SIZE_PROPERTY, delta); 138 if (log.isDebugEnabled()) { 139 log.debug("Setting quota (versions size): " + versions + " on document " + doc.getId()); 140 } 141 } 142 143 @Override 144 public void save() { 145 doc.putContextData(DocumentsSizeUpdater.DISABLE_QUOTA_CHECK_LISTENER, Boolean.TRUE); 146 QuotaUtils.disableListeners(doc); 147 DocumentModel origDoc = doc; 148 doc = doc.getCoreSession().saveDocument(doc); 149 QuotaUtils.clearContextData(doc); 150 QuotaUtils.clearContextData(origDoc); 151 } 152 153 @Override 154 public long getMaxQuota() { 155 try { 156 Long size = (Long) doc.getPropertyValue(DOCUMENTS_SIZE_MAX_SIZE_PROPERTY); 157 return size == null ? -1 : size.longValue(); 158 } catch (PropertyException e) { 159 return -1; 160 } 161 } 162 163 @Override 164 public void setMaxQuota(long maxSize) { 165 setMaxQuota(maxSize, false); 166 } 167 168 @Override 169 public void setMaxQuota(long maxSize, boolean skipValidation) { 170 if (!skipValidation) { 171 QuotaStatsService quotaStatsService = Framework.getService(QuotaStatsService.class); 172 if (!(quotaStatsService.canSetMaxQuota(maxSize, doc, doc.getCoreSession()))) { 173 throw new QuotaExceededException(doc, "Can not set " + maxSize 174 + ". Quota exceeded because the quota set on one of the children."); 175 } 176 } 177 doc.setPropertyValue(DOCUMENTS_SIZE_MAX_SIZE_PROPERTY, maxSize); 178 } 179 180 @Override 181 public QuotaInfo getQuotaInfo() { 182 return new QuotaInfo(getInnerSize(), getTotalSize(), getTrashSize(), getVersionsSize(), getMaxQuota()); 183 } 184 185 /** 186 * @since 5.7 187 */ 188 @Override 189 public void resetInfos() { 190 // we reset by setting actual values and not null, because we expect to apply deltas to those 191 // and col = col + delta wouldn't work if the database had col = null 192 doc.setPropertyValue(DOCUMENTS_SIZE_INNER_SIZE_PROPERTY, 0L); 193 doc.setPropertyValue(DOCUMENTS_SIZE_TOTAL_SIZE_PROPERTY, 0L); 194 doc.setPropertyValue(DOCUMENTS_SIZE_TRASH_SIZE_PROPERTY, 0L); 195 doc.setPropertyValue(DOCUMENTS_SIZE_VERSIONS_SIZE_PROPERTY, 0L); 196 doc.setPropertyValue(DOCUMENTS_SIZE_MAX_SIZE_PROPERTY, null); 197 } 198 199}