org.xflatdb.xflat.db.ElementTable.java Source code

Java tutorial

Introduction

Here is the source code for org.xflatdb.xflat.db.ElementTable.java

Source

/* 
*   Copyright 2013 Gordon Burgett and individual contributors
*
*   Licensed under the Apache 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.apache.org/licenses/LICENSE-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.xflatdb.xflat.db;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import org.xflatdb.xflat.Cursor;
import org.xflatdb.xflat.DuplicateKeyException;
import org.xflatdb.xflat.KeyNotFoundException;
import org.xflatdb.xflat.Table;
import org.xflatdb.xflat.XFlatException;
import org.xflatdb.xflat.query.XPathQuery;
import org.xflatdb.xflat.query.XPathUpdate;
import org.jdom2.Attribute;
import org.jdom2.Element;
import org.xflatdb.xflat.XFlatConstants;

/**
 * This is the simple Table implementation for tables of JDOM Elements.
 * @author gordon
 */
public class ElementTable extends TableBase implements Table<Element> {

    ElementTable(String tableName) {
        super(tableName);
    }

    @Override
    public void insert(Element data) throws DuplicateKeyException {
        String id = getId(data);
        if (id == null) {
            id = generateNewId();
            setId(id, data);
        }

        //always clone incoming data
        final Element cData = data.clone();
        final String sId = id;

        this.doWithEngine(new EngineActionEx<Object, DuplicateKeyException>() {
            @Override
            public Object act(Engine engine) throws DuplicateKeyException {
                engine.insertRow(sId, cData);
                return null;
            }
        });

    }

    @Override
    public Element find(Object id) {

        final String sId = getId(id);
        return this.doWithEngine(new EngineAction<Element>() {
            @Override
            public Element act(Engine engine) {
                return engine.readRow(sId);
            }
        });
    }

    private Cursor<Element> queryTable(final XPathQuery query) {
        return this.doWithEngine(new EngineAction<Cursor<Element>>() {
            @Override
            public Cursor<Element> act(Engine engine) {
                return engine.queryTable(query);
            }
        });
    }

    @Override
    public Element findOne(XPathQuery query) {
        try (Cursor<Element> c = this.queryTable(query)) {
            Iterator<Element> i = c.iterator();
            if (i.hasNext()) {
                return i.next();
            }

            return null;
        } catch (Exception ex) {
            throw new XFlatException("Unable to close cursor", ex);
        }
    }

    @Override
    public Cursor<Element> find(XPathQuery query) {
        return this.queryTable(query);
    }

    @Override
    public List<Element> findAll(XPathQuery query) {
        try (Cursor<Element> c = this.queryTable(query)) {
            List<Element> ret = new ArrayList<>();
            for (Element e : c) {
                ret.add(e);
            }

            return ret;
        } catch (Exception ex) {
            throw new XFlatException("Unable to close cursor", ex);
        }
    }

    @Override
    public void replace(Element newValue) throws KeyNotFoundException {
        final String id = getId(newValue);
        if (id == null) {
            throw new KeyNotFoundException("Element has no ID");
        }

        //always clone incoming data
        final Element data = newValue.clone();

        this.doWithEngine(new EngineActionEx<Object, KeyNotFoundException>() {
            @Override
            public Object act(Engine engine) throws KeyNotFoundException {
                engine.replaceRow(id, data);
                return null;
            }
        });
    }

    @Override
    public boolean replaceOne(XPathQuery query, Element origValue) {
        Element e = this.findOne(query);
        if (e == null) {
            return false;
        }

        final String id = getId(e);
        setId(id, origValue);

        //always clone incoming data
        final Element newValue = origValue.clone();

        try {
            this.doWithEngine(new EngineActionEx<Object, KeyNotFoundException>() {
                @Override
                public Object act(Engine engine) throws KeyNotFoundException {
                    engine.replaceRow(id, newValue);
                    return null;
                }
            });
            return true;
        } catch (KeyNotFoundException ex) {
            //someone concurrently deleted this row, try again by identifying
            //a new row by the query.
            return replaceOne(query, origValue);
        }
    }

    @Override
    public boolean upsert(Element newValue) {

        //always clone incoming data
        final Element data = newValue.clone();

        final String id = getId(newValue);
        if (id == null) {
            while (true) {
                final String nId = generateNewId();
                setId(nId, newValue);

                try {
                    this.doWithEngine(new EngineActionEx<Object, DuplicateKeyException>() {
                        @Override
                        public Object act(Engine engine) throws DuplicateKeyException {
                            engine.insertRow(nId, data);
                            return null;
                        }
                    });
                    //inserted, return true
                    return true;
                } catch (DuplicateKeyException ex) {
                    //somehow our "new" ID already existed - try again
                }
            }
        } else {
            return this.doWithEngine(new EngineAction<Boolean>() {
                @Override
                public Boolean act(Engine engine) {
                    return engine.upsertRow(id, data);
                }
            });
        }
    }

    @Override
    public boolean update(Object id, final XPathUpdate update) throws KeyNotFoundException {
        final String sId = getId(id);
        return this.doWithEngine(new EngineActionEx<Boolean, KeyNotFoundException>() {
            @Override
            public Boolean act(Engine engine) throws KeyNotFoundException {
                return engine.update(sId, update);
            }
        });
    }

    @Override
    public int update(final XPathQuery query, final XPathUpdate update) {
        return this.doWithEngine(new EngineAction<Integer>() {
            @Override
            public Integer act(Engine engine) {
                return engine.update(query, update);
            }
        });
    }

    @Override
    public void delete(Object id) throws KeyNotFoundException {
        if (id == null) {
            throw new IllegalArgumentException("id cannot be null");
        }

        final String sId = getId(id);

        this.doWithEngine(new EngineActionEx<Object, KeyNotFoundException>() {
            @Override
            public Object act(Engine engine) throws KeyNotFoundException {
                engine.deleteRow(sId);
                return null;
            }
        });
    }

    @Override
    public int deleteAll(final XPathQuery query) {
        return this.doWithEngine(new EngineAction<Integer>() {
            @Override
            public Integer act(Engine engine) {
                return engine.deleteAll(query);
            }
        });
    }

    private String getId(Element element) {
        Attribute a = element.getAttribute("id", XFlatConstants.xFlatNs);
        if (a != null) {
            return a.getValue();
        }

        return null;
    }

    private void setId(String id, Element e) {
        e.setAttribute("id", id, XFlatConstants.xFlatNs);
    }

    private String generateNewId() {
        return (String) this.getIdGenerator().generateNewId(String.class);
    }

    private String getId(Object id) throws IllegalArgumentException {
        if (!(id instanceof String)) {
            throw new IllegalArgumentException("Tables of element always have string IDs");
        }
        String sId = (String) id;
        return sId;
    }

}