org.sakaiproject.search.index.impl.SegmentState.java Source code

Java tutorial

Introduction

Here is the source code for org.sakaiproject.search.index.impl.SegmentState.java

Source

/**********************************************************************************
 * $URL: https://source.sakaiproject.org/svn/search/trunk/search-impl/impl/src/java/org/sakaiproject/search/index/impl/SegmentState.java $
 * $Id: SegmentState.java 105078 2012-02-24 23:00:38Z ottenhoff@longsight.com $
 ***********************************************************************************
 *
 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 The Sakai Foundation
 *
 * Licensed under the Educational Community License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.opensource.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 **********************************************************************************/

package org.sakaiproject.search.index.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.search.index.SegmentInfo;

/**
 * @author ieb
 */

public class SegmentState {

    private static final String VERSION = "1.0";

    private static final Log log = LogFactory.getLog(SegmentState.class);

    private Map<String, FileRecord> fileRecords;

    private long timeStamp = System.currentTimeMillis();

    private String name;

    /**
     * @param timestampFile
     * @throws IOException
     * @throws IOException
     */
    public SegmentState(SegmentInfo segInfo, File timestampFile) throws IOException {
        name = segInfo.getName();
        if (timestampFile == null) {
            analyze(segInfo);
        } else {
            load(timestampFile);
        }
    }

    /**
     * @param timestampFile
     * @throws IOException
     */
    public void save(File checksumFile) throws IOException {
        File tmpFile = new File(checksumFile.getAbsolutePath() + ".tmp");
        FileWriter fw = null;
        try {
            fw = new FileWriter(tmpFile);

            fw.append(VERSION).append("\n");
            fw.append(String.valueOf(timeStamp)).append("\n");
            for (Iterator<FileRecord> i = fileRecords.values().iterator(); i.hasNext();) {
                FileRecord fr = i.next();
                fw.append(fr.path).append(";");
                fw.append(fr.checksum).append(";");
                fw.append(String.valueOf(fr.length)).append(";");
                fw.append(String.valueOf(fr.lastMod)).append(";\n");
            }

        } catch (IOException e) {
            throw new IOException();
        } finally {
            if (fw != null) {
                fw.close();
            }
        }
        if (!tmpFile.renameTo(checksumFile)) {
            log.warn("unable to rename " + tmpFile.getPath() + " to " + checksumFile.getPath());
        }
    }

    /**
     * @param timestampFile
     * @throws IOException
     */
    private void load(File checksumFile) throws IOException {
        fileRecords = new HashMap<String, FileRecord>();
        BufferedReader fr = new BufferedReader(new FileReader(checksumFile));
        String version = fr.readLine();
        if (VERSION.equals(version)) {
            String ts = fr.readLine();
            timeStamp = Long.parseLong(ts);
            for (String line = fr.readLine(); line != null; line = fr.readLine()) {
                String[] elements = line.split(";");
                FileRecord infr = new FileRecord();
                infr.path = elements[0];
                infr.checksum = elements[1];
                infr.length = Long.parseLong(elements[2]);
                infr.lastMod = Long.parseLong(elements[3]);
                fileRecords.put(infr.path, infr);
            }
        } else {
            log.warn("Segment (" + name + "): Unrecognized version number " + version);
        }
        fr.close();
    }

    /**
     * @param segInfo
     */
    public void analyze(SegmentInfo segInfo) {
        File[] files = segInfo.getSegmentLocation().listFiles();
        String basePath = segInfo.getSegmentLocation().getAbsolutePath();
        fileRecords = new HashMap<String, FileRecord>();
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            log.error("Segment (" + name + "): MD5 not available ", e);
        }
        byte[] buffer = new byte[4096];
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                try {
                    String echecksum = "none";
                    if (md5 != null) {
                        InputStream fin = new FileInputStream(files[i]);
                        int len = 0;
                        md5.reset();
                        while ((len = fin.read(buffer)) > 0) {
                            md5.update(buffer, 0, len);
                        }
                        fin.close();
                        char[] encoding = "0123456789ABCDEF".toCharArray();
                        byte[] checksum = md5.digest();
                        char[] hexchecksum = new char[checksum.length * 2];
                        for (int j = 0; j < checksum.length; j++) {
                            int lo = checksum[j] & 0x0f;
                            int hi = (checksum[j] >> 4) & 0x0f;
                            hexchecksum[j * 2] = encoding[lo];
                            hexchecksum[j * 2 + 1] = encoding[hi];
                        }
                        echecksum = new String(hexchecksum);
                    }
                    FileRecord fr = new FileRecord();
                    fr.checksum = echecksum;
                    fr.path = files[i].getAbsolutePath().substring(basePath.length());
                    fr.lastMod = files[i].lastModified();
                    fr.length = files[i].length();
                    fileRecords.put(fr.path, fr);
                } catch (Exception ex) {
                    log.error(
                            "Segment (" + name + "): Failed to generate checksum of " + files[i].getAbsolutePath(),
                            ex);
                }
            }
        }

    }

    public class FileRecord {

        public long length;

        public long lastMod;

        public String path;

        public String checksum = "none";

        /**
         * @param sfr
         * @return
         */
        public String diff(FileRecord sfr) {
            StringBuilder sb = new StringBuilder();
            if (sfr == null) {
                return "new file";

            }
            if (!path.equals(sfr.path)) {
                return "[not the same file]";
            }
            int mod = 0;
            if (!checksum.equals(sfr.checksum)) {
                sb.append("content changed,");
                mod++;
            }
            if (lastMod > sfr.lastMod) {
                sb.append("newer;");
                mod++;
            } else if (lastMod < sfr.lastMod) {
                sb.append("older;");
                mod++;
            } else {
                sb.append("same age;");
            }
            if (length > sfr.length) {
                sb.append("larger;");
                mod++;
            } else if (length < sfr.length) {
                sb.append("smaller;");
                mod++;
            } else {
                sb.append("same size;");
            }
            if (mod != 0) {
                return sb.toString();
            }
            return "identical";
        }

        /*
         * (non-Javadoc)
         * 
         * @see java.lang.Object#toString()
         */
        @Override
        public String toString() {
            return path + ";" + new Date(lastMod) + ";" + length + ";";
        }

    }

    /**
     * @return the timeStamp
     */
    public long getTimeStamp() {
        return timeStamp;
    }

    /**
     * @param timeStamp
     *        the timeStamp to set
     */
    public void setTimeStamp(long timeStamp) {
        this.timeStamp = timeStamp;
    }

    /**
     * Check the validity of this segment against the stored segment
     * 
     * @param message
     * @param logging
     * @param storedSegmentState
     */
    public boolean checkValidity(boolean logging, String message, SegmentState storedSegmentState) {
        if (storedSegmentState == null) {
            if (logging) {
                log.info("Segment (" + name
                        + "): The segment has no stored state, it may be new or it could be dammaged ");
            }
            return true;
        }
        StringBuilder sb = new StringBuilder();
        if (timeStamp > storedSegmentState.getTimeStamp()) {
            sb.append(" This Segment has been modified ").append(name).append("\n");
        }
        for (Iterator<FileRecord> i = fileRecords.values().iterator(); i.hasNext();) {
            FileRecord fr = i.next();
            FileRecord sfr = storedSegmentState.getFileRecord(fr.path);
            String differences = fr.diff(sfr);

            sb.append("   Checking [").append(fr).append("]==[").append(sfr).append("] ").append(differences)
                    .append("\n");
        }
        for (Iterator<FileRecord> i = storedSegmentState.iterator(); i.hasNext();) {
            FileRecord sfr = i.next();
            FileRecord fr = fileRecords.get(sfr.path);
            if (fr == null) {
                sb.append("   Dropped ").append("").append("\n");
            }
        }
        if (logging) {
            log.info("Segment (" + name + "): Checked " + name + "\n" + sb.toString());
        }
        return true;
    }

    /**
     * @return
     */
    private Iterator<FileRecord> iterator() {
        return fileRecords.values().iterator();
    }

    /**
     * @param path
     * @return
     */
    private FileRecord getFileRecord(String path) {
        return fileRecords.get(path);
    }

}