netinf.node.resolution.bocaching.impl.BOCacheImpl.java Source code

Java tutorial

Introduction

Here is the source code for netinf.node.resolution.bocaching.impl.BOCacheImpl.java

Source

/*
 * Copyright (C) 2009-2011 University of Paderborn, Computer Networks Group
 * (Full list of owners see http://www.netinf.org/about-2/license)
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *     * Neither the name of the University of Paderborn nor the names of its contributors may be used to endorse
 *       or promote products derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package netinf.node.resolution.bocaching.impl;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import netinf.common.datamodel.DataObject;
import netinf.common.datamodel.DefinedAttributePurpose;
import netinf.common.datamodel.attribute.Attribute;
import netinf.common.datamodel.attribute.DefinedAttributeIdentification;
import netinf.common.exceptions.NetInfCheckedException;
import netinf.common.log.demo.DemoLevel;
import netinf.common.security.Hashing;
import netinf.common.utils.DatamodelUtils;
import netinf.common.utils.Utils;
import netinf.node.resolution.bocaching.BOCache;
import netinf.node.transferdispatcher.TransferDispatcher;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;

import com.google.inject.Inject;

/**
 * The Class BOCacheImpl.
 * 
 * @author PG Augnet 2, University of Paderborn
 */
public class BOCacheImpl implements BOCache {

    private static final Logger LOG = Logger.getLogger(BOCacheImpl.class);

    private final HTTPFileServer server;
    private final Set<String> cached;
    private TransferDispatcher transferDispatcher;

    @Inject
    public BOCacheImpl(HTTPFileServer server) throws NetInfCheckedException {
        super();
        this.server = server;
        this.server.start();
        cached = new HashSet<String>();
        rebuildCache();

        transferDispatcher = TransferDispatcher.getInstance();
    }

    @Override
    public boolean cache(DataObject dataObject) {
        String hash = DatamodelUtils.getHash(dataObject);
        String directory = server.getDirectory(); // .replace('\\', '/')

        if (!directory.endsWith(File.separator)) {
            directory += File.separator;
        }
        if (hash == null) {
            LOG.info("DataObject has no Hash and will not be cached");
            return false;
        }

        if (!contains(dataObject)) {
            LOG.log(DemoLevel.DEMO, "(BOCache ) Cache file...");
            List<Attribute> locators = dataObject
                    .getAttributesForPurpose(DefinedAttributePurpose.LOCATOR_ATTRIBUTE.toString());
            for (Attribute attr : locators) {
                DataInputStream fis = null;
                String url = attr.getValue(String.class);
                try {
                    String destination = directory + hash + ".tmp";
                    transferDispatcher.getStreamAndSave(url, destination, true);

                    // start reading
                    fis = new DataInputStream(new FileInputStream(destination));

                    // skip manually added content-type
                    int skipSize = fis.readInt();
                    for (int i = 0; i < skipSize; i++) {
                        fis.read();
                    }

                    byte[] hashBytes = Hashing.hashSHA1(fis);
                    IOUtils.closeQuietly(fis);
                    if (hash.equalsIgnoreCase(Utils.hexStringFromBytes(hashBytes))) {
                        LOG.info("Hash of downloaded file is valid: " + url);
                        LOG.log(DemoLevel.DEMO, "(NODE ) Hash of downloaded file is valid. Will be cached.");
                        File old = new File(destination);
                        File newFile = new File(destination.substring(0, destination.lastIndexOf('.')));
                        old.renameTo(newFile);
                        addLocator(dataObject);
                        cached.add(newFile.getName());

                        return true;
                    } else {
                        LOG.log(DemoLevel.DEMO, "(NODE ) Hash of downloaded file is invalid. Trying next locator");
                        LOG.warn("Hash of downloaded file is not valid: " + url);
                        LOG.warn("Trying next locator");
                    }

                } catch (FileNotFoundException ex) {
                    LOG.warn("Error downloading:" + url);
                } catch (IOException e) {
                    LOG.warn("Error hashing:" + url);
                } catch (Exception e) {
                    LOG.warn("Error hashing, but file was OK: " + url);
                    // e.printStackTrace();
                } finally {
                    IOUtils.closeQuietly(fis);
                    rebuildCache();
                }
            }
            LOG.warn("Could not find reliable source to cache: " + dataObject);
            return false;
        } else {
            LOG.log(DemoLevel.DEMO, "(NODE ) DataObject has already been cached. Adding locator.");
            addLocator(dataObject);
            return true;
        }
    }

    @Override
    public boolean contains(DataObject dataObject) {
        String hash = DatamodelUtils.getHash(dataObject);
        LOG.debug("Hash of dataobject is " + hash);
        if (hash == null) {
            return false;
        } else {
            return cached.contains(hash);
        }
    }

    private void rebuildCache() {
        File serverDir = new File(server.getDirectory());
        if (serverDir.isDirectory()) {
            File[] files = serverDir.listFiles();
            for (File f : files) {
                if (f.isFile()) {
                    if (f.getName().endsWith(".tmp")) {
                        f.delete();
                    } else {
                        LOG.debug("Adding '" + f.getName() + "' to cache");
                        cached.add(f.getName());
                    }
                }
            }
        }

    }

    private void addLocator(DataObject dataObject) {
        String hash = DatamodelUtils.getHash(dataObject);
        Attribute attribute = dataObject.getDatamodelFactory().createAttribute();
        attribute.setAttributePurpose(DefinedAttributePurpose.LOCATOR_ATTRIBUTE.toString());
        attribute.setIdentification(DefinedAttributeIdentification.HTTP_URL.getURI());
        attribute.setValue(server.getUrlForHash(hash));
        Attribute cacheMarker = dataObject.getDatamodelFactory().createAttribute();
        cacheMarker.setAttributePurpose(DefinedAttributePurpose.SYSTEM_ATTRIBUTE.getAttributePurpose());
        cacheMarker.setIdentification(DefinedAttributeIdentification.CACHE.getURI());
        cacheMarker.setValue("true");
        attribute.addSubattribute(cacheMarker);
        // Do not add the same locator twice
        if (!dataObject.getAttributes().contains(attribute)) {
            dataObject.addAttribute(attribute);
        }
    }

}