001/*
002 * #%L
003 * Netarchivesuite - wayback
004 * %%
005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University 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.wayback;
024
025import java.io.File;
026import java.io.IOException;
027
028import org.apache.commons.logging.Log;
029import org.apache.commons.logging.LogFactory;
030import org.archive.wayback.ResourceStore;
031import org.archive.wayback.core.CaptureSearchResult;
032import org.archive.wayback.core.Resource;
033import org.archive.wayback.exception.ResourceNotAvailableException;
034import org.archive.wayback.resourcestore.resourcefile.ResourceFactory;
035
036import dk.netarkivet.common.CommonSettings;
037import dk.netarkivet.common.distribute.arcrepository.ArcRepositoryClientFactory;
038import dk.netarkivet.common.distribute.arcrepository.Replica;
039import dk.netarkivet.common.distribute.arcrepository.ViewerArcRepositoryClient;
040import dk.netarkivet.common.utils.Settings;
041
042/**
043 * This is the connector between netarchivesuite and wayback. And is based on the NetarchiveResourceStore, and the
044 * implementations of ResourceStore distributed with wayback-1.4.2.
045 */
046public class NetarchiveCacheResourceStore implements ResourceStore {
047
048    /** JMS ArcRepositoryClient. */
049    private ViewerArcRepositoryClient client;
050
051    /** Logger. */
052    private Log logger = LogFactory.getLog(getClass().getName());
053    /** The filecache being used by this class. */
054    private LRUCache fileCache;
055    /** The replica being used by this class. */
056    private Replica replicaUsed;
057
058    /**
059     * Constructor. Initiates the caching mechanism.
060     */
061    public NetarchiveCacheResourceStore() {
062        fileCache = LRUCache.getInstance();
063        client = ArcRepositoryClientFactory.getViewerInstance();
064        replicaUsed = Replica.getReplicaFromId(Settings.get(CommonSettings.USE_REPLICA_ID));
065    }
066
067    /**
068     * Transforms search result into a resource, according to the ResourceStore interface.
069     *
070     * @param captureSearchResult the search result.
071     * @return a valid resource containing metadata and a link to the ARC or warc-record
072     * @throws ResourceNotAvailableException if something went wrong fetching the record.
073     */
074    public Resource retrieveResource(CaptureSearchResult captureSearchResult) throws ResourceNotAvailableException {
075        long offset;
076
077        String arcfile = captureSearchResult.getFile();
078        offset = captureSearchResult.getOffset();
079
080        logger.info("Received request for resource from file '" + arcfile + "' at offset '" + offset + "'");
081
082        // Try to lookup the file in the cache
083        // make synchronized to disallow more than one using
084        // the cache at any one time
085        synchronized (fileCache) {
086            File wantedFile = fileCache.get(arcfile);
087            try {
088                if (wantedFile != null && wantedFile.exists()) {
089                    logger.debug("Found the file '" + arcfile + "' in the cache. ");
090                    return ResourceFactory.getResource(wantedFile, offset);
091                } else {
092                    logger.debug("The file '" + arcfile + "' was not found in the cache. ");
093                    // Get file from bitarchive, and place it in the cachedir
094                    // directory
095                    File fileFromBitarchive = new File(fileCache.getCacheDir(), arcfile);
096                    client.getFile(arcfile, replicaUsed, fileFromBitarchive);
097                    // put into the cache
098                    fileCache.put(arcfile, fileFromBitarchive);
099                    logger.info("File '" + arcfile + "' downloaded from archive and put into the cache '"
100                            + fileCache.getCacheDir().getAbsolutePath() + "'.");
101                    return ResourceFactory.getResource(fileFromBitarchive, offset);
102                }
103            } catch (IOException e) {
104                logger.error("Error looking for non existing resource", e);
105                throw new ResourceNotAvailableException(this.getClass().getName() + "Throws Exception when accessing "
106                        + "CaptureResult given from Wayback.");
107            }
108        }
109    }
110
111    /**
112     * Shuts down this resource store, closing the arcrepository client.
113     *
114     * @throws IOException if an exception ocurred while closing the client.
115     */
116    public void shutdown() throws IOException {
117        // Close JMS connection.
118        client.close();
119    }
120}