org.wymiwyg.commons.prevamodel.PrevaGraph.java Source code

Java tutorial

Introduction

Here is the source code for org.wymiwyg.commons.prevamodel.PrevaGraph.java

Source

/*
 * Created on 1-lug-03
 * 
 * 
 * ====================================================================
 *
 * The WYMIWYG Software License, Version 1.0
 *
 * Copyright (c) 2002-2003 WYMIWYG  
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by WYMIWYG."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The name "WYMIWYG" or "WYMIWYG.org" must not be used to endorse 
 *    or promote products derived from this software without prior written 
 *    permission. For written permission, please contact wymiwyg@wymiwyg.org.
 *
 * 5. Products derived from this software may not be called  
 *    "WYMIWYG" nor may "WYMIWYG" appear in their names 
 *    without prior written permission of WYMIWYG.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 WYMIWYG OR ITS CONTRIBUTORS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of WYMIWYG.  For more
 * information on WYMIWYG, please see http://www.WYMIWYG.org/.
 *
 * This licensed is based on The Apache Software License, Version 1.1,
 * see http://www.apache.org/.
 */
package org.wymiwyg.commons.prevamodel;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.hp.hpl.jena.graph.BulkUpdateHandler;
import com.hp.hpl.jena.graph.Graph;
import com.hp.hpl.jena.graph.TransactionHandler;
import com.hp.hpl.jena.graph.Triple;
import com.hp.hpl.jena.graph.impl.SimpleBulkUpdateHandler;
import com.hp.hpl.jena.graph.impl.SimpleTransactionHandler;
import com.hp.hpl.jena.mem.GraphMem;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.shared.ReificationStyle;

/**
 * <p>PrevaGraph class.</p>
 *
 * @author reto
 * @version $Id: $Id
 */
public class PrevaGraph extends GraphMem {
    //private ModelCon modelCon = new ModelMem();
    private File directory;
    private int counter = 1;
    private static Log logger = LogFactory.getLog(PrevaGraph.class);

    /**
     * <p>Constructor for PrevaGraph.</p>
     *
     * @param directoryPath a {@link java.lang.String} object.
     * @param storeInterval a int.
     * @throws java.io.IOException if any.
     */
    public PrevaGraph(String directoryPath, int storeInterval) throws IOException {
        super(ReificationStyle.Standard);
        directory = new File(directoryPath);
        directory.mkdirs();
        long storeIntervalMilis = 60 * 1000 * storeInterval;
        //load previous stored model
        try {
            read();
        } catch (Exception e) {
            logger.error("restoring PrevaModel", e);
            throw new RuntimeException(e);
        }
        store();
        if (storeInterval > 0) {
            Thread storingThread = new StroringThread(this, storeIntervalMilis);
            storingThread.setDaemon(true);
            storingThread.start();
        }
    }

    /**
     * @param string
     * @param statement
     */
    private void log(String command, Triple triple) {
        Writer writer;
        synchronized (this) {
            try {
                writer = new FileWriter(new File(directory, "log-" + counter++ + "-" + command));
                writeStatement(triple, writer);
                writer.close();
            } catch (Exception e) {
                logger.error("Writing log " + e);
                throw new RuntimeException(e.toString());
            }
        }
    }

    /**
     * @param statement
     * @param writer
     */
    private void writeStatement(Triple triple, Writer writer) throws IOException {
        Graph stmtGraph = new GraphMem();
        stmtGraph.add(triple);
        Model stmtModel = ModelFactory.createModelForGraph(stmtGraph);
        stmtModel.write(writer, "N-TRIPLE");
    }

    /**
     * <p>removeLogs.</p>
     */
    public synchronized void removeLogs() {
        File[] logFiles = directory.listFiles(new FilenameFilter() {
            /**
             * @see java.io.FilenameFilter#accept(java.io.File,
             *          java.lang.String)
             */
            public boolean accept(File dir, String name) {
                return name.startsWith("log-");
            }
        });
        for (int i = 0; i < logFiles.length; i++) {
            logFiles[i].delete();
        }
        counter = 1;
    }

    /** {@inheritDoc} */
    public synchronized void performAdd(Triple triple) {
        super.performAdd(triple);
        if (logger.isDebugEnabled()) {
            try {
                throw new Exception("harmless debug-exception");
            } catch (Exception ex) {
                logger.debug("writing triple: " + triple, ex);
            }
        }
        log("add", triple);
    }

    /** {@inheritDoc} */
    public synchronized void performDelete(Triple triple) {
        super.performDelete(triple);
        log("delete", triple);
    }

    /**
     *  
     */
    private void read() throws IOException {
        final Set triples = new HashSet();
        File defaultStore = new File(directory, "store.rdf");
        File newStore = new File(directory, "store-new.rdf");
        if (defaultStore.exists()) {
            if (newStore.exists()) {
                newStore.delete();
            }
            BufferedReader in = new BufferedReader(new FileReader(defaultStore));
            String line = in.readLine();
            while (line != null) {
                triples.add(line);
                line = in.readLine();
            }
            in.close();
        } else {
            if (newStore.exists()) {
                newStore.renameTo(defaultStore);
            }
        }
        String[] logFiles = directory.list(new FilenameFilter() {
            /**
             * @see java.io.FilenameFilter#accept(java.io.File,
             *          java.lang.String)
             */
            public boolean accept(File dir, String name) {
                return name.startsWith("log-");
            }
        });
        Arrays.sort(logFiles, new Comparator() {
            public int compare(Object arg0, Object arg1) {
                return getLogNumber((String) arg0) - getLogNumber((String) arg1);
            }

            private int getLogNumber(String string) {
                String substring = string.substring(4);
                int endOfNumer = substring.indexOf('-');
                String numberString = substring.substring(0, endOfNumer);
                return Integer.parseInt(numberString);
            }
        });
        for (int i = 0; i < logFiles.length; i++) {
            File log = new File(directory, logFiles[i]);
            BufferedReader logIn = new BufferedReader(new FileReader(log));
            String entry = logIn.readLine();
            String nextLine = logIn.readLine();
            if (nextLine != null) {
                throw new RuntimeException(log + " is multiline");
            }
            if (entry == null) {
                logger.warn(log + " is empty, ignoring");
                continue;
            }
            logIn.close();
            if (logFiles[i].indexOf("add") != -1) {
                triples.add(entry);
            } else {
                triples.remove(entry);
            }
        }
        //Model model = ModelFactory.createModelForGraph(this);
        PipedReader pipedIn = new PipedReader();
        final PipedWriter pipedOut = new PipedWriter(pipedIn);
        new Thread() {
            public void run() {
                PrintWriter printOut = new PrintWriter(new BufferedWriter(pipedOut));
                Iterator iter = triples.iterator();
                while (iter.hasNext()) {
                    String element = (String) iter.next();
                    printOut.println(element);
                }
                printOut.close();
            }
        }.start();
        ModelFactory.createModelForGraph(this).read(pipedIn, "", "N-TRIPLE");
    }

    /**
     * store model and delete logs
     *
     * @author reto
     * @throws java.io.IOException if any.
     */
    public synchronized void store() throws IOException {
        long start = System.currentTimeMillis();
        synchronized (this) {
            //TODO set variable when file created instead of looking in dir
            String[] logFiles = directory.list(new FilenameFilter() {
                /**
                 * @see java.io.FilenameFilter#accept(java.io.File,
                 *          java.lang.String)
                 */
                public boolean accept(File dir, String name) {
                    return name.startsWith("log-");
                }
            });
            if (logFiles.length > 0) {
                logger.info("reducing disk representation of prevagraph to one file");
                Model model = ModelFactory.createModelForGraph(this);
                File newStore = new File(directory, "store-new.rdf");
                Writer writer = new FileWriter(newStore);
                model.write(writer, "N-TRIPLE");
                writer.close();
                File defaultStore = new File(directory, "store.rdf");
                if (defaultStore.exists()) {
                    defaultStore.delete();
                }
                newStore.renameTo(defaultStore);
                removeLogs();

            }
        }
        logger.info("log maintance too " + (System.currentTimeMillis() - start) + " ms");

    }

    /**
     * <p>getBulkUpdateHandler.</p>
     *
     * @see com.hp.hpl.jena.graph.Graph#getBulkUpdateHandler()
     * @return a {@link com.hp.hpl.jena.graph.BulkUpdateHandler} object.
     */
    public BulkUpdateHandler getBulkUpdateHandler() {
        return new SimpleBulkUpdateHandler(this);
        //return super.getBulkUpdateHandler();
    }

    /**
     * <p>getTransactionHandler.</p>
     *
     * @see com.hp.hpl.jena.graph.Graph#getTransactionHandler()
     * @return a {@link com.hp.hpl.jena.graph.TransactionHandler} object.
     */
    public TransactionHandler getTransactionHandler() {
        return new SimpleTransactionHandler();
    }
}

class StroringThread extends Thread {
    private static Log logger = LogFactory.getLog(StroringThread.class);
    WeakReference modelRef;
    long storeIntervalMilis;

    /**
     * <p>Constructor for StroringThread.</p>
     *
     * @param graph a {@link org.wymiwyg.commons.prevamodel.PrevaGraph} object.
     * @param storeIntervalMilis a long.
     */
    public StroringThread(PrevaGraph graph, long storeIntervalMilis) {
        modelRef = new WeakReference(graph);
        this.storeIntervalMilis = storeIntervalMilis;
    }

    /**
     * <p>run.</p>
     *
     * @see java.lang.Runnable#run()
     */
    public void run() {
        while (true) {
            try {
                Thread.sleep(storeIntervalMilis);
            } catch (InterruptedException e) {
            }
            PrevaGraph graph = (PrevaGraph) modelRef.get();
            if (graph == null)
                return;
            try {
                graph.store();
            } catch (IOException ex) {
                logger.error("storing: ", ex);
            }
            graph = null;
        }
    }
}