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