001/*
002*  Copyright 2016 Anyware Services
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 */
016package org.ametys.workspaces.repository.maintenance;
017
018import java.util.Map;
019
020import javax.jcr.RepositoryException;
021
022import org.apache.commons.lang.StringUtils;
023import org.apache.jackrabbit.core.config.RepositoryConfig;
024import org.joda.time.Duration;
025import org.joda.time.format.PeriodFormatter;
026import org.joda.time.format.PeriodFormatterBuilder;
027import org.slf4j.Logger;
028
029import org.ametys.plugins.repositoryapp.RepositoryProvider;
030import org.ametys.runtime.plugin.component.LogEnabled;
031
032/**
033 * Jackrabbit maintenance tasks implementations should extends this class.
034 */
035public abstract class AbstractMaintenanceTask implements LogEnabled
036{
037    /** TaskProgress */
038    protected TaskProgress _progress;
039
040    /** The repository config */
041    protected RepositoryConfig _repositoryConfig;
042
043    /** The repository provider. */
044    protected RepositoryProvider _repositoryProvider;
045    
046    /** Logger for traces */
047    protected Logger _logger;
048    
049    private boolean _isFinished;
050    
051    /**
052     * Execute the task
053     * @param repositoryConfig The RepositoryConfig object, used to create new Repository instance.
054     * @throws RepositoryException If an error with the repository occurs while the task is executed.
055     */
056    public void execute(RepositoryConfig repositoryConfig) throws RepositoryException 
057    {
058        _repositoryConfig = repositoryConfig;
059
060        long startTime = System.currentTimeMillis();
061        
062        setLogger();
063
064        _logger.info("Executing task.");
065
066        try
067        {
068            // task specific initialization.
069            initialize();
070
071            // Mark the task as running.
072            setRunning();
073
074            // Perform the task.
075            apply();
076
077            // Mark the task as finished.
078            setFinished();
079        }
080        catch (Exception e)
081        {
082            setInErrorState(e);
083            throw e;
084        }
085        finally
086        {
087            close();
088
089            _logger.info("End of the task.");
090
091            long elapsedTime = System.currentTimeMillis() - startTime;
092            _logger.info("Done in " + _getFormattedDuration(elapsedTime));
093        }
094    }
095
096    /**
097     * Initialize the tasks.
098     * This method can also create the {@link TaskProgress} object bounded to the task.
099     * @throws RepositoryException If a repository exception
100     */
101    protected void initialize() throws RepositoryException
102    {
103        return;
104    }
105    
106    /**
107     * Set the tasks logger.
108     */
109    protected abstract void setLogger();
110    
111    @Override
112    public void setLogger(Logger logger)
113    {
114        _logger = logger;
115    }
116
117    /**
118     * Apply the tasks (within the execute method()).
119     * @throws RepositoryException If a repository exception
120     */
121    protected abstract void apply() throws RepositoryException;
122
123    /**
124     * Close the tasks
125     * @throws RepositoryException If a repository exception
126     */
127    protected void close() throws RepositoryException
128    {
129        return;
130    }
131
132    /**
133     * Get progress information.
134     * @return a map containing information on the progress status.
135     */
136    public Map<String, Object> getProgressInfo() 
137    {
138        if (_progress != null)
139        {
140            return _progress.getProgressInfo();
141        }
142        else
143        {
144            return null;
145        }
146    }
147
148    /**
149     * Is the execution of the task finished?
150     * @return true if finished
151     */
152    public boolean isFinished()
153    {
154        return _isFinished;
155    }
156
157    private synchronized void setRunning()
158    {
159        if (_progress != null)
160        {
161            _progress.setRunning();
162        }
163    }
164
165    private synchronized void setFinished()
166    {
167        if (_progress != null)
168        {
169            _progress.setFinished();
170        }
171
172        _isFinished = true;
173    }
174
175    private synchronized void setInErrorState(Exception e)
176    {
177        _logger.error(e.getLocalizedMessage(), e);
178
179        if (_progress != null)
180        {
181            _progress.setInErrorState(e);
182        }
183
184        _isFinished = true;
185    }
186
187    /**
188     * Transforms millisecond to a formatted string representing a duration.
189     * @param elapsedTime milleseconds corresponding to the duration.
190     * @return Pretty formatted string.
191     */
192    protected String _getFormattedDuration(long elapsedTime)
193    {
194        Duration duration = new Duration(elapsedTime);
195        PeriodFormatter formatter = new PeriodFormatterBuilder()
196                .appendHours()
197                .appendSuffix("h")
198                .appendMinutes()
199                .appendSuffix("m")
200                .appendSeconds()
201                .appendSuffix("s")
202                .toFormatter();
203        String formatted = formatter.print(duration.toPeriod());
204        return StringUtils.defaultIfEmpty(formatted, "0s");
205    }
206}