001/* 002 * #%L 003 * Netarchivesuite - archive 004 * %% 005 * Copyright (C) 2005 - 2018 The Royal Danish Library, 006 * the National Library of France and the Austrian National Library. 007 * %% 008 * This program is free software: you can redistribute it and/or modify 009 * it under the terms of the GNU Lesser General Public License as 010 * published by the Free Software Foundation, either version 2.1 of the 011 * License, or (at your option) any later version. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Lesser Public License for more details. 017 * 018 * You should have received a copy of the GNU General Lesser Public 019 * License along with this program. If not, see 020 * <http://www.gnu.org/licenses/lgpl-2.1.html>. 021 * #L% 022 */ 023package dk.netarkivet.archive.arcrepositoryadmin; 024 025import java.util.HashMap; 026import java.util.HashSet; 027import java.util.Map; 028import java.util.Set; 029 030import dk.netarkivet.archive.arcrepository.distribute.StoreMessage; 031import dk.netarkivet.common.distribute.Channels; 032import dk.netarkivet.common.distribute.arcrepository.Replica; 033import dk.netarkivet.common.distribute.arcrepository.ReplicaStoreState; 034import dk.netarkivet.common.exceptions.ArgumentNotValid; 035import dk.netarkivet.common.exceptions.IllegalState; 036import dk.netarkivet.common.exceptions.UnknownID; 037 038/** 039 * The administrator class for the ArcRepository when dealing with an database instead of a file (alternative to 040 * AdminData). 041 */ 042public final class DatabaseAdmin implements Admin { 043 044 /** The access interface to the administration database. */ 045 private ReplicaCacheDatabase database; 046 /** The current instance of this class, to avoid multiple instantiations. */ 047 private static DatabaseAdmin instance; 048 /** Administration of store messages. */ 049 private Map<String, StoreMessage> storeEntries = new HashMap<String, StoreMessage>(); 050 051 /** 052 * Constructor. Initialises the access to the database. 053 */ 054 private DatabaseAdmin() { 055 database = ReplicaCacheDatabase.getInstance(); 056 } 057 058 /** 059 * Retrieval of a singleton DatabaseAdmin. Ensures that this class is not instantiated multiple times. 060 * 061 * @return The current instance of this class. 062 */ 063 public static synchronized DatabaseAdmin getInstance() { 064 if (instance == null) { 065 instance = new DatabaseAdmin(); 066 } 067 return instance; 068 } 069 070 /** 071 * Method for adding an entry for administration. 072 * 073 * @param filename The name of the file to be stored. 074 * @param msg The StoreMessage of the entry. 075 * @param checksum The checksum of the entry. 076 * @throws ArgumentNotValid If either the filename or checksum is either null or the empty string. 077 */ 078 @Override 079 public void addEntry(String filename, StoreMessage msg, String checksum) throws ArgumentNotValid { 080 ArgumentNotValid.checkNotNullOrEmpty(filename, "String filename"); 081 ArgumentNotValid.checkNotNullOrEmpty(checksum, "String checksum"); 082 083 // insert this into the entries map. 084 storeEntries.put(filename, msg); 085 086 // insert into database. 087 database.insertNewFileForUpload(filename, checksum); 088 } 089 090 /** 091 * Method for telling whether a file entry exists. 092 * 093 * @param filename The name of the file, the existence of whose entry is to be determined. 094 * @return Whether the entry exists. 095 * @throws ArgumentNotValid If the filename is either null or empty. 096 */ 097 @Override 098 public boolean hasEntry(String filename) throws ArgumentNotValid { 099 ArgumentNotValid.checkNotNullOrEmpty(filename, "String filename"); 100 101 // See if the file can be found in the database. 102 return database.existsFileInDB(filename); 103 } 104 105 /** 106 * Returns the ReplicaStoreState of a given file in a specific replica. 107 * 108 * @param filename The name of the file for the ReplicaStoreState. 109 * @param replicaChannelName The name of the identification channel for uniquely identifying the replica of for the 110 * ReplicaStoreState. 111 * @return The ReplicaStoreState of a given file in a specific replica. 112 * @throws ArgumentNotValid If the filename or the replica id is null or the empty string. 113 */ 114 @Override 115 public ReplicaStoreState getState(String filename, String replicaChannelName) throws ArgumentNotValid { 116 ArgumentNotValid.checkNotNullOrEmpty(filename, "String filename"); 117 ArgumentNotValid.checkNotNullOrEmpty(replicaChannelName, "String replicaChannelName"); 118 119 Replica rep = Channels.retrieveReplicaFromIdentifierChannel(replicaChannelName); 120 121 // retrieve the ReplicaStoreState from the database. 122 return database.getReplicaStoreState(filename, rep.getId()); 123 } 124 125 /** 126 * Determines whether a given file in a specific replica has a valid replica store state. By valid means a replica 127 * store state other that UNKNOWN_UPLOAD_STATE. 128 * <p> 129 * TODO Find out if the assumption that all upload states besides UNKNOWN_UPLOAD_STATE are acceptable! 130 * 131 * @param filename The name of the file for the ReplicaStoreState. 132 * @param repChannelId The identification channel of the replica for the ReplicaStoreState. 133 * @return Whether a given file in a specific replica has a valid store state. 134 * @throws ArgumentNotValid If either the filenames or the replica identification channel is null or the empty 135 * string. 136 */ 137 @Override 138 public boolean hasState(String filename, String repChannelId) throws ArgumentNotValid { 139 ArgumentNotValid.checkNotNullOrEmpty(filename, "String filename"); 140 ArgumentNotValid.checkNotNullOrEmpty(repChannelId, "String repChannelId"); 141 142 // retrieve the replica 143 Replica rep = Channels.retrieveReplicaFromIdentifierChannel(repChannelId); 144 145 // retrieve the state for the entry for the replica and filename 146 ReplicaStoreState state = database.getReplicaStoreState(filename, rep.getId()); 147 148 // return whether the entry has a known upload state 149 return state != ReplicaStoreState.UNKNOWN_UPLOAD_STATE; 150 } 151 152 /** 153 * Sets the store state of an entry to a specific value. 154 * 155 * @param filename The name of the file for the entry. 156 * @param repChannelId The identification channel of the replica for the entry. 157 * @param state The new state for the entry. 158 * @throws ArgumentNotValid If the ReplicaStoreState is null, or if either the filename or the replica 159 * identification channel is either null or the empty string. 160 */ 161 @Override 162 public void setState(String filename, String repChannelId, ReplicaStoreState state) throws ArgumentNotValid { 163 ArgumentNotValid.checkNotNull(state, "ReplicaStoreState state"); 164 ArgumentNotValid.checkNotNullOrEmpty(filename, "String filename"); 165 ArgumentNotValid.checkNotNullOrEmpty(repChannelId, "String repChannelId"); 166 167 // retrieve the replica 168 Replica rep = Channels.retrieveReplicaFromIdentifierChannel(repChannelId); 169 170 // update the database. 171 database.setReplicaStoreState(filename, rep.getId(), state); 172 } 173 174 /** 175 * Determines whether the StoreMessage of a given file exists. 176 * 177 * @param filename The name of the file to which the existence of the StoreMessage should be determined. 178 * @return Whether the StoreMessage of the file exists. 179 * @throws ArgumentNotValid If the filename is null or the empty string. 180 */ 181 @Override 182 public boolean hasReplyInfo(String filename) throws ArgumentNotValid { 183 ArgumentNotValid.checkNotNullOrEmpty(filename, "String filename"); 184 185 // check if a entry for the file can be found in the map. 186 return storeEntries.containsKey(filename); 187 } 188 189 /** 190 * Retrieves the StoreMessage of a specific file. 191 * 192 * @param filename The name of the file whose StoreMessage should be retrieved. 193 * @return The StoreMessage corresponding to the file. A null is returned if the corresponding StoreMessage is not 194 * found. 195 * @throws ArgumentNotValid If the filename is either null or the empty string. 196 */ 197 @Override 198 public StoreMessage removeReplyInfo(String filename) throws ArgumentNotValid { 199 ArgumentNotValid.checkNotNullOrEmpty(filename, "String filename"); 200 201 // extract the entry from the 202 return storeEntries.remove(filename); 203 } 204 205 /** 206 * Assign a StoreMessage to a specific filename. If the filename is already associated with a StoreMessage, then 207 * this StoreMessage will be overwritten by the new StoreMessage. 208 * 209 * @param filename The name of the file to have a StoreMessage assigned. 210 * @param msg The StoreMessage to be assigned to a file. 211 * @throws ArgumentNotValid If the StoreMessage is null or if the filename is either null or the empty string. 212 */ 213 @Override 214 public void setReplyInfo(String filename, StoreMessage msg) throws ArgumentNotValid { 215 ArgumentNotValid.checkNotNull(msg, "StoreMessage msg"); 216 ArgumentNotValid.checkNotNullOrEmpty(filename, "String filename"); 217 218 // put into the map, and overwrite any existing mapping. 219 storeEntries.put(filename, msg); 220 } 221 222 /** 223 * Retrieves the checksum of a given file. 224 * 225 * @param filename The name of the file, whose checksum should be retrieved. 226 * @return The checksum of the file. 227 * @throws ArgumentNotValid If the filename is either null or the empty string. 228 */ 229 @Override 230 public String getCheckSum(String filename) throws ArgumentNotValid { 231 ArgumentNotValid.checkNotNullOrEmpty(filename, "String filename"); 232 233 // Ensure that we have the file requested. 234 if (!hasEntry(filename)) { 235 throw new UnknownID("Don't know anything about file '" + filename + "'"); 236 } 237 238 // Retrieve the checksum for a specific entry. 239 return database.getChecksum(filename); 240 } 241 242 /** 243 * Sets the checksum of a given file. 244 * <p> 245 * It should not be possible to change the checksum in the database through arcrepository. 246 * 247 * @param filename The name of the file to have the checksum changed. 248 * @param checksum The new checksum for the file. 249 * @throws ArgumentNotValid If either the filename or the checksum is either null or the empty string. 250 * @throws IllegalState Always, since it is not allowed for arcrepository to change the checksum of a completed 251 * upload. 252 */ 253 @Override 254 public void setCheckSum(String filename, String checksum) throws ArgumentNotValid, IllegalState { 255 ArgumentNotValid.checkNotNullOrEmpty(filename, "String filename"); 256 ArgumentNotValid.checkNotNullOrEmpty(checksum, "String checksum"); 257 258 // This will not be implemented. 259 throw new IllegalState("It is not possible to change the checksum of a " 260 + " file in the database! Only the checksum of a specific " + "replicafileinfo."); 261 } 262 263 /** 264 * Retrieves a set of the names for all the known files. 265 * 266 * @return A set of the names for all the known file. 267 */ 268 @Override 269 public Set<String> getAllFileNames() { 270 // initialise the set 271 Set<String> res = new HashSet<String>(); 272 // put the collection of filenames into the set. 273 res.addAll(database.retrieveAllFilenames()); 274 // return the set. 275 return res; 276 } 277 278 /** 279 * Retrieves a set with the name of the files with a specific ReplicaStoreState in a specific replica. 280 * 281 * @param rep The replica where the files belong. 282 * @param state The ReplicaStoreState for the files. 283 * @return A set with the names of the files with a specific ReplicaStoreState in a specific replica. 284 * @throws ArgumentNotValid If the Replica or the ReplicaStoreState is null. 285 */ 286 @Override 287 public Set<String> getAllFileNames(Replica rep, ReplicaStoreState state) throws ArgumentNotValid { 288 ArgumentNotValid.checkNotNull(rep, "Replica rep"); 289 ArgumentNotValid.checkNotNull(state, "ReplicaStoreState state"); 290 291 // initialise the set 292 Set<String> res = new HashSet<String>(); 293 // put the collection of filenames into the set. 294 res.addAll(database.retrieveFilenamesForReplicaEntries(rep.getId(), state)); 295 // return the set. 296 return res; 297 } 298 299 /** 300 * Close and cleanup of this class. 301 */ 302 @Override 303 public void close() { 304 storeEntries.clear(); 305 database.cleanup(); 306 instance = null; 307 } 308}