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