rs.data.file.dao.AbstractFileDAO Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of data-file Show documentation
Show all versions of data-file Show documentation
Library for file-based data access
The newest version!
/*
* This file is part of RS Library (Data File Library).
*
* RS Library is free software: you can redistribute it
* and/or modify it under the terms of version 3 of the GNU
* Lesser General Public License as published by the Free Software
* Foundation.
*
* RS Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with RS Library. If not, see
* .
*/
package rs.data.file.dao;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.HierarchicalConfiguration;
import org.apache.commons.configuration2.ex.ConfigurationException;
import rs.baselib.configuration.ConfigurationUtils;
import rs.data.api.IDaoFactory;
import rs.data.api.IDaoMaster;
import rs.data.api.bo.IGeneralBO;
import rs.data.file.bo.AbstractFileBO;
import rs.data.file.storage.AbstractStorageStrategy;
import rs.data.file.storage.IStorageStrategy;
import rs.data.file.storage.XmlStorageStrategy;
import rs.data.file.util.DefaultFilenameStrategy;
import rs.data.file.util.IFilenameStrategy;
import rs.data.file.util.IKeyGenerator;
import rs.data.file.util.LongKeyGenerator;
import rs.data.impl.dao.AbstractGeneralDAO;
import rs.data.util.CID;
import rs.data.util.IDaoIterator;
/**
* Abstract implementation of file-based DAOs.
* @author ralph
*
*/
public abstract class AbstractFileDAO, C extends IGeneralBO> extends AbstractGeneralDAO {
/** The key for the data directory as stored in DAO Master */
public static final String PROPERTY_DATA_DIR = "dataDir";
/** The key for the suffix as stored in DAO Master */
public static final String PROPERTY_DATA_SUFFIX = "dataSuffix";
/** The key for the prefix as stored in DAO Master */
public static final String PROPERTY_DATA_PREFIX = "dataPrefix";
/** The Key Generator */
private IKeyGenerator keyGenerator;
/** The filename strategy */
private IFilenameStrategy filenameStrategy;
/** The storage strategy */
private IStorageStrategy storageStrategy;
/**
* Constructor.
*/
public AbstractFileDAO() {
setKeyGenerator(createKeyGenerator());
setFilenameStrategy(createFilenameStrategy());
setStorageStrategy(createStorageStrategy());
}
/**
* Creates a default key generation strategy (for numbers only!).
* Descendants shall override this method or configure their DAO through XML.
* @return the default strategy in case of numbers or null
* @see #configure(Configuration)
*/
@SuppressWarnings("unchecked")
protected IKeyGenerator createKeyGenerator() {
if (Long.class.isAssignableFrom(getKeyClass())) {
return (IKeyGenerator)new LongKeyGenerator();
}
return null;
}
/**
* Sets the {@link #filenameStrategy}.
* The method instantiates a {@link DefaultFilenameStrategy} with properties from the DAO Master.
* @return filename strategy for this DAO
* @see #PROPERTY_DATA_DIR
* @see #PROPERTY_DATA_PREFIX
* @see #PROPERTY_DATA_SUFFIX
*/
protected IFilenameStrategy createFilenameStrategy() {
String dataDir = null;
String prefix = null;
String suffix = null;
IDaoMaster daoMaster = getDaoMaster();
if (daoMaster != null) {
dataDir = daoMaster.getProperty(PROPERTY_DATA_DIR);
prefix = daoMaster.getProperty(PROPERTY_DATA_PREFIX);
suffix = daoMaster.getProperty(PROPERTY_DATA_SUFFIX);
}
if (dataDir == null) dataDir = IFilenameStrategy.DEFAULT_DATA_DIR;
if (suffix == null) suffix = IFilenameStrategy.DEFAULT_DATA_SUFFIX;
Class ifClass = getBoInterfaceClass();
String simpleName = getClass().getSimpleName();
if (ifClass != null) {
simpleName = ifClass.getSimpleName();
}
return new DefaultFilenameStrategy(new File(dataDir, simpleName), prefix, suffix);
}
/**
* Creates a storage strategy, here a XML strategy.
* Descendants shall override this method if they do not wish to store their data in XML files
* or use the configuration method.
* @return the storage strategy.
* @see #configure(Configuration)
*/
protected IStorageStrategy createStorageStrategy() {
return new XmlStorageStrategy(getFactory());
}
/**
* {@inheritDoc}
* This method also updates the storage strategy.
*/
@SuppressWarnings("rawtypes")
@Override
public void setFactory(IDaoFactory factory) {
super.setFactory(factory);
IStorageStrategy storageStrategy = getStorageStrategy();
if (storageStrategy instanceof AbstractStorageStrategy) {
((AbstractStorageStrategy)storageStrategy).setDaoFactory(factory);
}
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
public void configure(Configuration cfg) throws ConfigurationException {
super.configure(cfg);
try {
Configuration subConfig = ((HierarchicalConfiguration>)cfg).configurationAt("keyGenerator(0)");
setKeyGenerator((IKeyGenerator)ConfigurationUtils.load(subConfig, true));
} catch (Exception e) {
// Ignore
}
try {
Configuration subConfig = ((HierarchicalConfiguration>)cfg).configurationAt("filenameStrategy(0)");
setFilenameStrategy((IFilenameStrategy)ConfigurationUtils.load(subConfig, true));
} catch (Exception e) {
// Ignore
}
try {
Configuration subConfig = ((HierarchicalConfiguration>)cfg).configurationAt("storageStrategy(0)");
setStorageStrategy((IStorageStrategy)ConfigurationUtils.load(subConfig, true));
} catch (Exception e) {
// Ignore
}
}
/**
* Returns the keyGenerator.
* @return the keyGenerator
*/
public IKeyGenerator getKeyGenerator() {
return keyGenerator;
}
/**
* Sets the keyGenerator.
* @param keyGenerator the keyGenerator to set
*/
public void setKeyGenerator(IKeyGenerator keyGenerator) {
this.keyGenerator = keyGenerator;
}
/**
* Returns the {@link #filenameStrategy}.
* @return the filenameStrategy
*/
public IFilenameStrategy getFilenameStrategy() {
return filenameStrategy;
}
/**
* Sets the filenameStrategy.
* @param filenameStrategy the filenameStrategy to set
*/
public void setFilenameStrategy(IFilenameStrategy filenameStrategy) {
this.filenameStrategy = filenameStrategy;
}
/**
* Returns the {@link #storageStrategy}.
* @return the storageStrategy
*/
public IStorageStrategy getStorageStrategy() {
return storageStrategy;
}
/**
* Sets the {@link #storageStrategy}.
* @param storageStrategy the storageStrategy to set
*/
public void setStorageStrategy(IStorageStrategy storageStrategy) {
this.storageStrategy = storageStrategy;
}
/**
* Returns the file that shall have the object with given key.
* @param key key of business object
* @return the file for this object
* @throws IOException the I/O exception when creating the file
*/
protected File getFile(K key) throws IOException {
// Forward to filename strategy
return getFilenameStrategy().getFile(key);
}
/**
* {@inheritDoc}
*/
@Override
public int getObjectCount() {
try {
return getStorageStrategy().getObjectCount(getFilenameStrategy().getFiles());
} catch (IOException e) {
throw new RuntimeException("Cannot get object count", e);
}
}
/**
* {@inheritDoc}
*/
@Override
public int getDefaultObjectCount() {
try {
return getStorageStrategy().getDefaultObjectCount(getFilenameStrategy().getFiles());
} catch (IOException e) {
throw new RuntimeException("Cannot get default object count", e);
}
}
/**
* {@inheritDoc}
*/
@Override
public C findBy(K id) {
C rc = getCached(new CID(getBoInterfaceClass(), id));
if (rc == null) try {
File file = getFilenameStrategy().getFile(id);
if (!file.canRead()) return null;
rc = _load(id, file);
} catch (IOException e) {
return null;
}
return (C)rc;
}
/**
* {@inheritDoc}
*/
@Override
public void refresh(C object) {
try {
getStorageStrategy().refresh(object, getFilenameStrategy().getFile(object.getId()));
} catch (Exception e) {
throw new RuntimeException("Cannot load file", e);
}
}
/**
* Loads the business object from the given file.
* @param id - the ID of the object to load
* @param file file to load from
* @return the business object
*/
protected C _load(K id, File file) {
C rc = newInstance();
try {
getStorageStrategy().load(rc, id, file);
} catch (Exception e) {
throw new RuntimeException("Cannot load file", e);
}
addCached(rc);
return rc;
}
/**
* {@inheritDoc}
* The sortBy argument will be ignored
*/
@Override
public List findAll(int firstResult, int maxResults, String sortBy) {
try {
return load(getStorageStrategy().getList(getFilenameStrategy().getFiles()), firstResult, maxResults, sortBy);
} catch (IOException e) {
throw new RuntimeException("Cannot load objects", e);
}
}
/**
* {@inheritDoc}
* The sortBy argument will be ignored
*/
@Override
public List findDefaultAll(int firstResult, int maxResults, String sortBy) {
try {
return load(getStorageStrategy().getDefaultList(getFilenameStrategy().getFiles()), firstResult, maxResults, sortBy);
} catch (IOException e) {
throw new RuntimeException("Cannot load objects", e);
}
}
/**
* Load the files given and return the objects.
* @param files files to be loaded
* @param firstResult first result index (-1 for not set)
* @param maxResults maximum number of results (-1 for not limited)
* @param sortBy - the order clauses, e.g. {@code column1 ASC, column2, column3 DESC}
* The sortBy argument will be ignored
* @return loaded objects
*/
protected List load(Map files, int firstResult, int maxResults, String sortBy) {
List rc = new ArrayList();
int i = 0;
for (Map.Entry entry : files.entrySet()) {
boolean doLoad = true;
if (firstResult > i) doLoad = false;
if (rc.size() == maxResults) doLoad = false;
if (doLoad) {
rc.add((C)_load(entry.getKey(), entry.getValue()));
}
}
return rc;
}
/**
* {@inheritDoc}
* The sortBy argument will be ignored
*/
@Override
public IDaoIterator iterateAll(int firstResult, int maxResults, String sortBy) {
try {
return iterate(getStorageStrategy().getList(getFilenameStrategy().getFiles()), firstResult, maxResults, sortBy);
} catch (IOException e) {
throw new RuntimeException("Cannot load objects", e);
}
}
/**
* {@inheritDoc}
* The sortBy argument will be ignored
*/
@Override
public IDaoIterator iterateDefaultAll(int firstResult, int maxResults, String sortBy) {
try {
return iterate(getStorageStrategy().getDefaultList(getFilenameStrategy().getFiles()), firstResult, maxResults, sortBy);
} catch (IOException e) {
throw new RuntimeException("Cannot load objects", e);
}
}
/**
* {@inheritDoc}
*/
@Override
public int deleteAll() {
return delete(findAll());
}
/**
* {@inheritDoc}
*/
@Override
public int deleteDefaultAll() {
return delete(findDefaultAll());
}
/**
* Deletes the objects in the given collection.
* @param objects objects to be deleted
* @return number of objects deleted
*/
protected int delete(List objects) {
int cnt = 0;
for (C object : objects) {
delete(object);
cnt++;
}
return cnt;
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
protected void _create(C object) {
K id = getNewId();
((B)object).setId(id);
try {
File file = getFilenameStrategy().getFile(id);
getStorageStrategy().save(object, file);
} catch (IOException e) {
throw new RuntimeException("Cannot create object", e);
}
}
/**
* Returns a new Id.
* @return the generated new ID
*/
protected K getNewId() {
K rc = null;
IKeyGenerator generator = getKeyGenerator();
IFilenameStrategy nameStrategy = getFilenameStrategy();
while (rc == null) {
rc = generator.getNewId();
try {
File f = nameStrategy.getFile(rc);
if (f.exists()) {
rc = null;
}
} catch (IOException e) {
throw new RuntimeException("Cannot generate new key", e);
}
}
return rc;
}
/**
* {@inheritDoc}
*/
@Override
protected void _save(C object) {
try {
File file = getFilenameStrategy().getFile(object.getId());
getStorageStrategy().save(object, file);
} catch (IOException e) {
throw new RuntimeException("Cannot save object", e);
}
}
/**
* {@inheritDoc}
*/
@Override
protected void _delete(C object) {
try {
File file = getFile(object.getId());
if (file.exists() && !file.delete()) {
throw new RuntimeException("Cannot delete file: "+file.getAbsolutePath());
}
} catch (IOException e) {
throw new RuntimeException("Cannot delete object: "+object.getId(), e);
}
}
/**
* Creates the appropriate iterator for the given collection and index restrictions.
* @param files files to be delivered
* @param firstResult first index to be returned
* @param maxResults max number of results
* @param sortBy - the order clauses, e.g. {@code column1 ASC, column2, column3 DESC}
* The sortBy argument will be ignored
* @return iterator
*/
protected IDaoIterator iterate(Map files, int firstResult, int maxResults, String sortBy) {
return new FileDaoIterator(files, firstResult, maxResults, sortBy);
}
/**
* DAO Iterator for file based objects.
* @author ralph
*
*/
public class FileDaoIterator implements IDaoIterator {
/** Iterator */
private Iterator> files;
/** Maximum number of files to be returned */
private int maxResults;
/** Sort by string */
@SuppressWarnings("unused")
private String sortBy;
/** Number of files already returned */
private int delivered;
/**
* Constructor.
* @param files files to iterate over
* @param firstResult first index to be returned
* @param maxResults max number of results
* @param sortBy - the order clauses, e.g. {@code column1 ASC, column2, column3 DESC}
* The sortBy argument will be ignored
*/
public FileDaoIterator(Map files, int firstResult, int maxResults, String sortBy) {
this.files = files.entrySet().iterator();
this.maxResults = maxResults;
this.sortBy = sortBy;
// Skip results
while ((firstResult > 0) && this.files.hasNext()) {
this.files.next();
firstResult--;
}
this.delivered = 0;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
return ((maxResults < 0) || (delivered < maxResults)) && files.hasNext();
}
/**
* {@inheritDoc}
*/
@Override
public C next() {
if (!hasNext()) throw new IllegalArgumentException("No more objects!");
Map.Entry entry = files.next();
K id = entry.getKey();
File file = entry.getValue();
return _load(id, file);
}
/**
* {@inheritDoc}
*/
@Override
public void remove() {
throw new IllegalArgumentException("Not supported");
}
/**
* {@inheritDoc}
*/
@Override
public void close() {
// Nothing to do
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy