001/*
002 *  Copyright 2013 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.plugins.skincommons;
017
018import java.io.File;
019import java.io.FileReader;
020import java.io.FileWriter;
021import java.io.IOException;
022import java.io.Writer;
023import java.time.ZonedDateTime;
024import java.time.format.DateTimeFormatter;
025import java.util.Date;
026import java.util.List;
027
028import org.apache.avalon.framework.component.Component;
029import org.apache.avalon.framework.logger.AbstractLogEnabled;
030import org.apache.avalon.framework.service.ServiceException;
031import org.apache.avalon.framework.service.ServiceManager;
032import org.apache.avalon.framework.service.Serviceable;
033import org.apache.avalon.framework.thread.ThreadSafe;
034import org.apache.commons.io.IOUtils;
035
036import org.ametys.core.user.CurrentUserProvider;
037import org.ametys.core.user.UserIdentity;
038import org.ametys.runtime.parameter.ParameterHelper;
039
040/**
041 * Component to manage lock on skin directories.
042 *
043 */
044public class SkinLockManager extends AbstractLogEnabled implements Component, ThreadSafe, Serviceable
045{
046    /** The Avalon role name */
047    public static final String ROLE = SkinLockManager.class.getName();
048    
049    private CurrentUserProvider _userProvider;
050    
051    @Override
052    public void service(ServiceManager smanager) throws ServiceException
053    {
054        _userProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE);
055    }
056    
057    /**
058     * Determines if the current user can write in skin directory
059     * @param file The skin directory
060     * @return <code>true</code> if the skin directory is not locked by another user
061     * @throws IOException If an error occurred
062     */
063    public boolean canWrite (File file) throws IOException
064    {
065        return getLockOwner(file).equals(_userProvider.getUser());
066    }
067    
068    /**
069     * Create or update .lock file
070     * @param file The skin directory
071     * @param toolId The id of tool responsible for lock.
072     * @throws IOException If an error occurred
073     */
074    public void updateLockFile (File file, String toolId) throws IOException
075    {
076        File lockFile = new File(file, ".lock");
077        if (lockFile.exists())
078        {
079            lockFile.delete();
080        }
081        lockFile.createNewFile();
082        
083        try (Writer writer = new FileWriter(lockFile);)
084        {
085            IOUtils.write(UserIdentity.userIdentityToString(_userProvider.getUser()) + "\n", writer);
086            IOUtils.write(ParameterHelper.getISODateTimeFormatter().format(ZonedDateTime.now()) + "\n", writer);
087            IOUtils.write(toolId, writer);
088        }
089    }
090    
091    /**
092     * Remove lock file
093     * @param file The skin directory
094     */
095    public void unlock (File file)
096    {
097        File lockFile = new File(file, ".lock");
098        if (lockFile.exists())
099        {
100            lockFile.delete();
101        }
102    }
103    
104    /**
105     * Determines if the skin directory is locked
106     * @param file The skin directory
107     * @return <code>true</code> if the skin directory is locked
108     */
109    public boolean isLocked (File file)
110    {
111        File lockFile = new File(file, ".lock");
112        return lockFile.exists();
113    }
114    
115    /**
116     * Get lock owner
117     * @param file The skin directory
118     * @return The lock owner or null.
119     * @throws IOException if an error occurs while manipulating files
120     */
121    public UserIdentity getLockOwner (File file) throws IOException
122    {
123        File lockFile = new File(file, ".lock");
124        if (!lockFile.exists())
125        {
126            return null;
127        }
128        
129        try (FileReader reader = new FileReader(lockFile);)
130        {
131            List<String> lines = IOUtils.readLines(reader);
132            
133            if (!lines.isEmpty())
134            {
135                return UserIdentity.stringToUserIdentity(lines.get(0));
136            }
137            
138            return null;
139        }
140    }
141    
142    /**
143     * Get tool responsible for lock
144     * @param file The skin directory
145     * @return The tool responsible for lock or <code>null</code>
146     * @throws IOException if an error occurs while manipulating files
147     */
148    public String getLockTool (File file)  throws IOException
149    {
150        File lockFile = new File(file, ".lock");
151        if (!lockFile.exists())
152        {
153            return null;
154        }
155        
156        try (FileReader reader = new FileReader(lockFile);)
157        {
158            List<String> lines = IOUtils.readLines(reader);
159            
160            if (!lines.isEmpty() && lines.size() > 2)
161            {
162                return lines.get(2);
163            }
164            
165            return null;
166        }
167    }
168    
169    /**
170     * Get the last modified date
171     * @param file The skin directory
172     * @return the last modified date
173     * @throws IOException if an error occurs while manipulating files
174     */
175    public Date lastModified (File file) throws IOException
176    {
177        File lockFile = new File(file, ".lock");
178        if (!lockFile.exists())
179        {
180            return null;
181        }
182        
183        try (FileReader reader = new FileReader(lockFile);)
184        {
185            List<String> lines = IOUtils.readLines(reader);
186            
187            if (!lines.isEmpty() && lines.size() > 1)
188            {
189                return Date.from(ZonedDateTime.parse(lines.get(1), DateTimeFormatter.ISO_DATE_TIME).toInstant());
190            }
191            
192            return null;
193        }
194        catch (IndexOutOfBoundsException e)
195        {
196            return null;
197        }
198    }
199}