All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rs.data.file.storage.AbstractStorageStrategy Maven / Gradle / Ivy

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.storage;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.collections.CollectionUtils;

import rs.baselib.bean.BeanSupport;
import rs.baselib.lang.LangUtils;
import rs.data.api.IDaoFactory;
import rs.data.api.bo.IGeneralBO;

/**
 * Abstract implementation of a storage stratey.
 * @param  type of ID for Business Objects to be managed
 * @param  type of Business Object the strategy manages
 * @param  type of specifier, e.g. a file
 * @author ralph
 *
 */
public abstract class AbstractStorageStrategy, S> implements IStorageStrategy {

	/** ICache of transient properties per class */
	private static Map, Set> transientCache = new HashMap, Set>();

	/** The encoding used */
	private String encoding = Charset.defaultCharset().name();
	
	/** A factory reference */
	private IDaoFactory daoFactory;
	
	/**
	 * Constructor.
	 * @param daoFactory - the responsible DAO factory
	 */
	public AbstractStorageStrategy(IDaoFactory daoFactory) {
		setDaoFactory(daoFactory);
	}

	/**
	 * Returns the daoFactory.
	 * @return the daoFactory
	 */
	public IDaoFactory getDaoFactory() {
		return daoFactory;
	}

	/**
	 * Sets the daoFactory.
	 * @param daoFactory the daoFactory to set
	 */
	public void setDaoFactory(IDaoFactory daoFactory) {
		this.daoFactory = daoFactory;
	}

	/**
	 * {@inheritDoc}
	 * 

The default implementation returns the number of specifiers.

*/ @Override public int getObjectCount(Collection specifiers) throws IOException { return specifiers.size(); } /** * {@inheritDoc} *

The default implementation forwards to {@link #getObjectCount(Collection)}.

*/ @Override public int getDefaultObjectCount(Collection specifiers) throws IOException { return getObjectCount(specifiers); } /** * {@inheritDoc} *

The default implementation forwards to {@link #getList(Collection)}.

*/ @Override public Map getDefaultList(Collection specifiers) throws IOException { return getList(specifiers); } /** * Serializes the given value. * Collections, Maps and other non-serializable objects cannot be serialized by this method. * @param value value to be serialized * @return the serialized string or null if it cannot be serialized safely. Values encoded in BASE64 are * prefixed with "BASE64". * @throws IOException - the I/O exception when operating on a filesystem */ protected String serialize(Object value) throws IOException { if (value instanceof Number) { return value.toString(); } else if (value instanceof Boolean) { return value.toString(); } else if (value instanceof Enum) { return value.toString(); } else if (value instanceof String) { // encode only when out of sight characters boolean isClean = true; for (char c : ((String) value).toCharArray()) { if (c > '\u007f') { isClean = false; break; } } if (isClean) { return value.toString(); } return "BASE64:"+new String(Base64.encodeBase64(((String) value).getBytes(getEncoding())), StandardCharsets.UTF_8); } else if (value instanceof Serializable) { return "BASE64:"+LangUtils.serializeBase64(value); } return null; } /** * Unserializes the given value. * Collections, Maps and other non-serializable objects cannot be unserialized by this method. * @param className the expected class to be produced * @param value the serialized string. Values encoded in BASE64 must be prefixed with "BASE64". * @return the object (or null) * @throws IOException - the I/O exception when operating on a filesystem * @throws ClassNotFoundException - when class could not be found * @throws InstantiationException - when object cannot be instantiated * @throws IllegalAccessException - when constructor is not accessible * @throws InvocationTargetException - when constructor threw an exception * @throws NoSuchMethodException - when constructor does not exist */ @SuppressWarnings({ "unchecked", "rawtypes" }) protected Object unserialize(String className, String value) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { Class clazz = LangUtils.forName(className); if (Number.class.isAssignableFrom(clazz)) { return (Number)clazz.getConstructor(String.class).newInstance(value); } else if (Boolean.class.isAssignableFrom(clazz) ) { return Boolean.valueOf(value); } else if (clazz.isEnum()) { return Enum.valueOf((Class)clazz, value); } else if (String.class.isAssignableFrom(clazz)) { if (value.startsWith("BASE64:")) return Base64.decodeBase64(value.substring(7)); return value; } else if (Serializable.class.isAssignableFrom(clazz)) { return LangUtils.unserialize(value); } return null; } /** * Returns all properties as defined in the BO interface. * @param object the object * @return the names of all relevant interfaces */ @SuppressWarnings("unchecked") protected Collection getPropertyNames(Object object) { Set rc = transientCache.get(object.getClass()); if (rc == null) { Set transients = new HashSet(); Set nontransients = new HashSet(); // Collect all transient and persistent properties from interfaces for (Class clazz2 : object.getClass().getInterfaces()) { transients.addAll(BeanSupport.INSTANCE.getTransientProperties(clazz2)); nontransients.addAll(BeanSupport.INSTANCE.getNonTransientProperties(clazz2)); } // Make difference of both sets ; // Add all others to the return rc = new HashSet(CollectionUtils.subtract(nontransients, transients)); transientCache.put(object.getClass(), Collections.unmodifiableSet(rc)); } return rc; } /** * Returns all properties as defined in the BO interface. * @param object the object * @return the names of all relevant interfaces */ protected Collection getBeanPropertyNames(Object object) { return BeanSupport.INSTANCE.getNonTransientProperties(object); } /** * Returns the {@link #encoding}. * @return the encoding */ public String getEncoding() { return encoding; } /** * Sets the {@link #encoding}. * @param encoding the encoding to set */ public void setEncoding(String encoding) { this.encoding = encoding; } }