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 *     Thomas Roger <troger@nuxeo.com>
018 */
019
020package org.nuxeo.ecm.quota.count;
021
022import static org.jboss.seam.annotations.Install.FRAMEWORK;
023
024import java.io.Serializable;
025import java.util.List;
026import java.util.Map;
027
028import javax.faces.application.FacesMessage;
029import javax.faces.component.UIComponent;
030import javax.faces.context.FacesContext;
031import javax.faces.validator.ValidatorException;
032
033import org.apache.commons.logging.Log;
034import org.apache.commons.logging.LogFactory;
035import org.jboss.seam.ScopeType;
036import org.jboss.seam.annotations.Create;
037import org.jboss.seam.annotations.Factory;
038import org.jboss.seam.annotations.In;
039import org.jboss.seam.annotations.Install;
040import org.jboss.seam.annotations.Name;
041import org.jboss.seam.annotations.Scope;
042import org.nuxeo.common.utils.SizeUtils;
043import org.nuxeo.ecm.core.api.CoreSession;
044import org.nuxeo.ecm.core.api.DocumentModel;
045import org.nuxeo.ecm.core.work.api.Work.State;
046import org.nuxeo.ecm.core.work.api.WorkManager;
047import org.nuxeo.ecm.platform.ui.web.api.NavigationContext;
048import org.nuxeo.ecm.quota.QuotaStatsService;
049import org.nuxeo.ecm.quota.QuotaStatsUpdater;
050import org.nuxeo.ecm.quota.size.QuotaAware;
051import org.nuxeo.ecm.quota.size.QuotaDisplayValue;
052import org.nuxeo.launcher.config.ConfigurationGenerator;
053import org.nuxeo.runtime.api.Framework;
054import org.nuxeo.runtime.services.config.ConfigurationService;
055
056/**
057 * @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a>
058 * @since 5.5
059 */
060@Name("quotaStatsActions")
061@Scope(ScopeType.CONVERSATION)
062@Install(precedence = FRAMEWORK)
063public class QuotaStatsActions implements Serializable {
064
065    protected Log log = LogFactory.getLog(QuotaStatsActions.class);
066
067    private static final long serialVersionUID = -1L;
068
069    /** @since 9.3 */
070    public static final String QUOTA_MAX_SIZE_PROP = "nuxeo.quota.maxsize";
071
072    /** @since 9.3 */
073    public static final String QUOTA_MAX_SIZE_DEFAULT= "999 GB";
074
075    @In(create = true)
076    protected transient CoreSession documentManager;
077
078    @In(create = true)
079    protected transient NavigationContext navigationContext;
080
081    @In(create = true)
082    protected Map<String, String> messages;
083
084    private transient ConfigurationGenerator setupConfigGenerator;
085
086    protected QuotaStatsService quotaStatsService;
087
088    protected boolean activateQuotaOnUsersWorkspaces;
089
090    protected long maxQuotaOnUsersWorkspaces = -1;
091
092    protected WorkManager workManager;
093
094    protected long configuredMaxQuotaSize;
095
096    @Create
097    public void initialize() {
098        initQuotaActivatedOnUserWorkspaces();
099        initConfiguredMaxQuotaSize();
100    }
101
102    public List<QuotaStatsUpdater> getQuotaStatsUpdaters() {
103        QuotaStatsService quotaStatsService = Framework.getService(QuotaStatsService.class);
104        return quotaStatsService.getQuotaStatsUpdaters();
105    }
106
107    public void launchInitialComputation(String updaterName) {
108        launchInitialComputation(updaterName, documentManager.getRepositoryName());
109    }
110
111    public void launchInitialComputation(String updaterName, String repositoryName) {
112        QuotaStatsService quotaStatsService = Framework.getService(QuotaStatsService.class);
113        quotaStatsService.launchInitialStatisticsComputation(updaterName, repositoryName, null);
114    }
115
116    public String getStatus(String updaterName) {
117        QuotaStatsService quotaStatsService = Framework.getService(QuotaStatsService.class);
118        return quotaStatsService.getProgressStatus(updaterName, documentManager.getRepositoryName());
119    }
120
121    @Factory(value = "currentQuotaDoc", scope = ScopeType.EVENT)
122    public QuotaAware getQuotaDoc() {
123        DocumentModel doc = navigationContext.getCurrentDocument();
124        return doc.getAdapter(QuotaAware.class);
125    }
126
127    public void validateQuotaSize(FacesContext context, UIComponent component, Object value) {
128        String strValue = value.toString();
129        Long quotaValue = -1L;
130        boolean quotaAllowed = true;
131        try {
132            quotaValue = Long.parseLong(strValue);
133        } catch (NumberFormatException e) {
134            FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, messages.get("wrong format"), null);
135            // also add global message
136            context.addMessage(null, message);
137            throw new ValidatorException(message);
138        }
139
140        quotaAllowed = getQuotaStatsService().canSetMaxQuota(quotaValue, navigationContext.getCurrentDocument(),
141                documentManager);
142        if (quotaAllowed) {
143            return;
144        }
145        FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
146                messages.get("label.quotaException.QuotaCanNotBeSet"), null);
147        // also add global message
148        context.addMessage(null, message);
149        throw new ValidatorException(message);
150    }
151
152    public QuotaDisplayValue formatQuota(long value, long max) {
153        QuotaDisplayValue qdv = new QuotaDisplayValue(value, max);
154        return qdv;
155    }
156
157    public double getMinQuotaSliderValue(long totalSize) {
158        long minSize = 100 * 1024;
159        // 11.528
160        if (totalSize > minSize) {
161            return Math.log(totalSize + minSize);
162        } else {
163            return Math.log(minSize);
164        }
165    }
166
167    public long getMinQuotaSliderValue() {
168        return 102400;// 100KB
169    }
170
171    public long getMaxQuotaSliderValue() {
172        long maxQuotaSize = -1L;
173        DocumentModel doc = navigationContext.getCurrentDocument();
174        if (doc != null) {
175            maxQuotaSize = getQuotaStatsService().getQuotaFromParent(doc, documentManager);
176        }
177        return maxQuotaSize > 0 ? maxQuotaSize : configuredMaxQuotaSize;
178    }
179
180    /**
181     * @since 9.3
182     */
183    protected void initConfiguredMaxQuotaSize() {
184        ConfigurationService configurationService = Framework.getService(ConfigurationService.class);
185        String max = configurationService.getProperty(QUOTA_MAX_SIZE_PROP, QUOTA_MAX_SIZE_DEFAULT);
186        try {
187            configuredMaxQuotaSize = SizeUtils.parseSizeInBytes(max);
188        } catch (NumberFormatException e) {
189            log.error("Invalid value for configuration property " + QUOTA_MAX_SIZE_PROP + ": " + max
190                    + "; using default: " + QUOTA_MAX_SIZE_DEFAULT);
191            configuredMaxQuotaSize = SizeUtils.parseSizeInBytes(QUOTA_MAX_SIZE_DEFAULT);
192        }
193    }
194
195    /**
196     * @since 5.7
197     */
198    public void saveQuotaActivatedOnUsersWorkspaces() {
199        long maxSize = -1;
200        if (isActivateQuotaOnUsersWorkspaces()) {
201            maxSize = getMaxQuotaOnUsersWorkspaces();
202        }
203        getQuotaStatsService().activateQuotaOnUserWorkspaces(maxSize, documentManager);
204        getQuotaStatsService().launchSetMaxQuotaOnUserWorkspaces(maxSize, documentManager.getRootDocument(),
205                documentManager);
206    }
207
208    /**
209     * @since 5.7
210     */
211    public void initQuotaActivatedOnUserWorkspaces() {
212        long quota = getQuotaStatsService().getQuotaSetOnUserWorkspaces(documentManager);
213        setActivateQuotaOnUsersWorkspaces(quota == -1 ? false : true);
214        setMaxQuotaOnUsersWorkspaces(quota);
215    }
216
217    public boolean workQueuesInProgess() {
218        WorkManager workManager = getWorkManager();
219        long running = workManager.getQueueSize("quota", State.RUNNING);
220        long scheduled = workManager.getQueueSize("quota", State.SCHEDULED);
221        return running + scheduled > 0;
222    }
223
224    public boolean isQuotaSetOnCurrentDocument() {
225        DocumentModel doc = navigationContext.getCurrentDocument();
226        // the quota info set on the userworkspaces root should be ignored
227        if ("UserWorkspacesRoot".equals(doc.getType())) {
228            return true;
229        }
230        QuotaAware qa = doc.getAdapter(QuotaAware.class);
231        if (qa == null) {
232            return false;
233        }
234        long maxSize = qa.getMaxQuota();
235        return maxSize > 0;
236    }
237
238    public boolean isActivateQuotaOnUsersWorkspaces() {
239        return activateQuotaOnUsersWorkspaces;
240    }
241
242    public void setActivateQuotaOnUsersWorkspaces(boolean activateQuotaOnUsersWorkspaces) {
243        this.activateQuotaOnUsersWorkspaces = activateQuotaOnUsersWorkspaces;
244    }
245
246    public long getMaxQuotaOnUsersWorkspaces() {
247        return maxQuotaOnUsersWorkspaces;
248    }
249
250    public void setMaxQuotaOnUsersWorkspaces(long maxQuotaOnUsersWorkspaces) {
251        this.maxQuotaOnUsersWorkspaces = maxQuotaOnUsersWorkspaces;
252    }
253
254    QuotaStatsService getQuotaStatsService() {
255        if (quotaStatsService == null) {
256            quotaStatsService = Framework.getService(QuotaStatsService.class);
257        }
258        return quotaStatsService;
259    }
260
261    protected WorkManager getWorkManager() {
262        if (workManager == null) {
263            workManager = Framework.getService(WorkManager.class);
264        }
265        return workManager;
266    }
267}