/*-
* Copyright (C) 2008 Erik Larsson
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.catacombae.storage.fs;
import java.util.HashMap;
import java.util.Map;
import org.catacombae.storage.io.DataLocator;
/**
* A factory for creating FileSystemHandlers. By setting attributes in the
* factory, you affect how new FileSystemHandlers are created.
*
* @author <a href="http://www.catacombae.org/" target="_top">Erik Larsson</a>
*/
public abstract class FileSystemHandlerFactory {
/**
* This instance holds the create attributes for the current factory.
* Subclasses can access this instance directly to query for relevant
* attribute definitions and their values.
*/
protected final Attributes createAttributes;
protected FileSystemHandlerFactory() {
this.createAttributes = new Attributes(getSupportedStandardAttributes(),
getSupportedCustomAttributes());
}
/**
* Returns the file system recognizer for the current file system type.
*
* @return the file system recognizer for the current file system type.
*/
public abstract FileSystemRecognizer getRecognizer();
/**
* Creates a new file system handler from the data pointed to by the
* supplied DataLocator.
*
* @param data locator of the file system data.
* @return a newly created file system handler.
*/
public abstract FileSystemHandler createHandler(DataLocator data);
public abstract FileSystemHandlerInfo getHandlerInfo();
public abstract FileSystemCapability[] getCapabilities();
public boolean hasCapability(FileSystemCapability c) {
for(FileSystemCapability cur : getCapabilities()) {
if(cur == c)
return true;
}
return false;
}
/**
* Creates a new instance of this particular factory subclass.
* @return a new instance of this particular factory subclass.
*/
public abstract FileSystemHandlerFactory newInstance();
/**
* Returns the attributes that are used to create new file system handlers.
* By changing values in this structure, you affect how new handlers are
* created.
*
* @return the attributes that are used to create new file system handlers.
*/
public Attributes getCreateAttributes() {
return createAttributes;
}
/**
* Returns the standard create attributes supported by this implementation.
* IMPORTANT: Implementors can set the default values for their supported
* standard attributes <b>only in this method</b>. Setting them somewhere
* else will be pointless and without effect.
*
* @return the standard create attributes supported by this implementation.
*/
public abstract StandardAttribute[] getSupportedStandardAttributes();
/**
* Returns the custom create attributes supported by this implementation.
*
* @return the custom create attributes supported by this implementation.
*/
public abstract CustomAttribute[] getSupportedCustomAttributes();
/**
* Returns the custom attribute by the name <code>name</code>, if supported
* by the implementation. Returns <code>null</code> if not supported.
*
* @param name the name of the requested custom attribute.
* @return the custom attribute by the name <code>name</code> if supported,
* and <code>null</code> otherwise.
*/
public CustomAttribute getCustomAttribute(String name) {
for(CustomAttribute attr : getSupportedCustomAttributes()) {
if(attr.getName().equals(name))
return attr;
}
return null;
}
/**
* Returns whether or not this standard attribute is supported by the
* implementation.
*
* @param attr the standard attribute to query.
* @return whether or not <code>attr</code> is supported.
*/
public boolean isSupported(StandardAttribute attr) {
for(StandardAttribute sa : getSupportedStandardAttributes()) {
if(sa == attr)
return true;
}
return false;
}
/**
* Sets the default value of this standard attribute. Factory implementors
* can call this method to override the default value for an attribute, in
* order to better suit their implementation.<br>
* <b>This method must only be called from within
* <code>getSupportedStandardAttributes()</code>!</b>
*
* @param defaultValue the new default value for this standard attribute.
*/
protected void setStandardAttributeDefaultValue(StandardAttribute attr,
Object defaultValue) {
attr.setDefaultValue(defaultValue);
}
/**
* Creates a new CustomAttribute, for implementor-defined attributes
* that are not general, but specific to the current implementation.
*
* @param iType the type of the custom attribute.
* @param iName the name of the custom attribute. This should typically
* be written in C constants-style, like
* <code>A_NEW_CUSTOM_ATTRIBUTE</code>, to fit in with the general
* aesthetic approach. ;-)
* @param iDescription a description of the attribute.
* @param iDefaultValue the default newValue of the attribute.
* @return a new CustomAttribute object, created from the given parameters.
*/
protected static CustomAttribute createCustomAttribute(AttributeType iType,
String iName, String iDescription, Object iDefaultValue) {
//System.err.println("createCustomAttribute(" + iType + ", " + iName + ", " + iDescription + ", " + iDefaultValue + "); invoked");
CustomAttribute createdCustomAttribute =
new CustomAttribute(iType, iName, iDescription, iDefaultValue);
//System.err.println("Returning a custom attribute: " + createdCustomAttribute);
return createdCustomAttribute;
}
public class Attributes {
private final Map<StandardAttribute, Object> standardCreateAttributeMap =
new HashMap<StandardAttribute, Object>();
private final Map<CustomAttribute, Object> customCreateAttributeMap =
new HashMap<CustomAttribute, Object>();
private Attributes(StandardAttribute[] iSupportedStandardAttributes,
CustomAttribute[] iSupportedCustomAttributes) {
// Add the supported standard attributes to the list
for(StandardAttribute sa : iSupportedStandardAttributes) {
standardCreateAttributeMap.put(sa, sa.getDefaultValue());
}
// Add the custom attributes to the list
for(CustomAttribute ca : iSupportedCustomAttributes) {
customCreateAttributeMap.put(ca, ca.getDefaultValue());
}
}
public final Boolean getBooleanAttribute(StandardAttribute attr) {
return getBooleanAttribute(attr.getType(), standardCreateAttributeMap.get(attr));
}
public final Long getIntegerAttribute(StandardAttribute attr) {
return getIntegerAttribute(attr.getType(), standardCreateAttributeMap.get(attr));
}
public final String getStringAttribute(StandardAttribute attr) {
return getStringAttribute(attr.getType(), standardCreateAttributeMap.get(attr));
}
public final Boolean getBooleanAttribute(CustomAttribute attr) {
return getBooleanAttribute(attr.getType(), customCreateAttributeMap.get(attr));
}
public final Long getIntegerAttribute(CustomAttribute attr) {
return getIntegerAttribute(attr.getType(), customCreateAttributeMap.get(attr));
}
public final String getStringAttribute(CustomAttribute attr) {
return getStringAttribute(attr.getType(), customCreateAttributeMap.get(attr));
}
public void setBooleanAttribute(StandardAttribute attr, Boolean value) {
setAttribute(attr, value, standardCreateAttributeMap.get(attr));
}
public void setIntegerAttribute(StandardAttribute attr, Integer value) {
setAttribute(attr, value, standardCreateAttributeMap.get(attr));
}
public void setStringAttribute(StandardAttribute attr, String value) {
setAttribute(attr, value, standardCreateAttributeMap.get(attr));
}
public void setBooleanAttribute(CustomAttribute attr, Boolean value) {
setAttribute(attr, value, customCreateAttributeMap.get(attr));
}
public void setIntegerAttribute(CustomAttribute attr, Integer value) {
setAttribute(attr, value, customCreateAttributeMap.get(attr));
}
public void setStringAttribute(CustomAttribute attr, String value) {
setAttribute(attr, value, customCreateAttributeMap.get(attr));
}
private final Boolean getBooleanAttribute(AttributeType type, Object value) {
if(type != AttributeType.BOOLEAN) {
throw new IllegalArgumentException("Tried to get BOOLEAN value " +
"from " + type + " type!");
}
else if(value == null) {
throw new IllegalArgumentException("Attribute is not supported " +
"by this implementation!");
}
else {
if(value instanceof Boolean) {
return (Boolean) value;
}
else {
throw new RuntimeException("INTERNAL ERROR: Kick the coder " +
"for inserting " + value.getClass() + " values in a " +
"BOOLEAN attribute.");
}
}
}
private final Long getIntegerAttribute(AttributeType type, Object value) {
if(type != AttributeType.INTEGER) {
throw new IllegalArgumentException("Tried to get INTEGER value " +
"from " + type + " type!");
}
else if(value == null) {
throw new IllegalArgumentException("Attribute is not supported " +
"by this implementation!");
}
else {
if(value instanceof Long) {
return (Long) value;
}
else if(value instanceof Number) {
return ((Number) value).longValue();
}
else {
throw new RuntimeException("INTERNAL ERROR: Kick the coder " +
"for inserting " + value.getClass() + " values in an " +
"INTEGER attribute.");
}
}
}
private final String getStringAttribute(AttributeType type, Object value) {
if(type != AttributeType.STRING) {
throw new IllegalArgumentException("Tried to get STRING value " +
"from " + type + " type!");
}
else if(value == null) {
throw new IllegalArgumentException("Attribute is not supported " +
"by this implementation!");
}
else {
if(value instanceof String) {
return (String) value;
}
else {
throw new RuntimeException("INTERNAL ERROR: Kick the coder " +
"for inserting " + value.getClass() + " values in a " +
"STRING attribute.");
}
}
}
private void setAttribute(StandardAttribute attr, Object newValue,
Object oldValue) {
if(!attr.getType().isValidValue(newValue)) {
throw new IllegalArgumentException("Invalid value type (" +
newValue.getClass() + ") for attribute (" + attr + ")!");
}
else if(oldValue == null) {
throw new IllegalArgumentException("Attribute " + attr + " is not supported " +
"by this implementation!");
}
else {
standardCreateAttributeMap.put(attr, newValue);
}
}
private void setAttribute(CustomAttribute attr, Object newValue,
Object oldValue) {
if(!attr.getType().isValidValue(newValue)) {
throw new IllegalArgumentException("Invalid value type (" +
newValue.getClass() + ") for attribute (" + attr + ")!");
}
else if(oldValue == null) {
throw new IllegalArgumentException("Attribute " + attr + " is not supported " +
"by this implementation!");
}
else {
customCreateAttributeMap.put(attr, newValue);
}
}
}
/**
* This enum defines the valid attribute types that can be used to create
* new custom attributes or change existing standard or custom attributes.
*/
public static enum AttributeType {
BOOLEAN(Boolean.class),
INTEGER(Byte.class, Short.class, Integer.class, Long.class),
STRING(String.class);
private final Class[] valueSuperClasses;
private AttributeType(Class... iValueSuperClasses) {
this.valueSuperClasses = iValueSuperClasses;
}
/**
* Returns whether or not the supplied newValue is valid for this type.<br>
* Example: For a BOOLEAN AttributeType only a java.lang.Boolean
* is a valid newValue type. For an INTEGER AttributeType all the standard
* integer-values are valid (java.lang.Byte, java.lang.Short,
* java.lang.Integer, java.lang.Long... BigInteger is not supported).
*
* @param value the value to check for validity.
* @return whether or not the supplied value is valid for this type.
*/
public boolean isValidValue(Object value) {
for(Class c : valueSuperClasses)
if(c.isInstance(value))
return true;
return false;
}
}
/**
* This enum defines the standard attributes that are defined for creating
* new FileSystemHandlers. They may or may not be supported by the
* implementation. You can find out which standard attributes are supported
* by the current factory by calling
* <code>getSupportedStandardAttributes()</code>.
*/
public enum StandardAttribute {
/**
* Boolean attribute which can be applied to file systems with an
* internal caching mechanism. Default newValue for this standard attribute
* is <code>false</code>.
*/
CACHING_ENABLED(AttributeType.BOOLEAN, new Boolean(false));
private final AttributeType type;
private Object defaultValue;
private StandardAttribute(AttributeType iType, Object iDefaultValue) {
this.type = iType;
setDefaultValue(iDefaultValue);
}
/**
* Returns the type of this standard attribute.
* @return the type of this standard attribute.
*/
public AttributeType getType() {
return type;
}
/**
* Returns the default newValue for this standard attribute.
* @return the default newValue for this standard attribute.
*/
public Object getDefaultValue() {
return defaultValue;
}
/**
* Sets the default newValue of this standard attribute. Factory
* implementors can override this default newValue specific to their
* implementation as this enum is instance-bound and not static.<br>
* <b>This method must only be called from within
* <code>getSupportedStandardAttributes()</code>!</b>
*
* @param iDefaultValue the new default newValue for this standard
* attribute.
*/
private void setDefaultValue(Object iDefaultValue) {
if(!type.isValidValue(iDefaultValue))
throw new IllegalArgumentException("Illegal default value!");
else
this.defaultValue = iDefaultValue;
}
}
/**
* This class represents a custom create attribute that a file system
* implementor may want to be able to specify when creating a
* FileSystemHandler. Example:
* <pre>
* CustomAttribute debugAttribute = new CustomAttribute(AttributeType.BOOLEAN,
* "DEBUG_ENABLED", "Controls if debug mode should be used.", false);
* CustomAttribute outfileAttribute = new CustomAttribute(AttributeType.STRING,
* "DEBUG_OUTPUTFILE", "Controls which outputfile should be used for debug.",
* "C:\\Temp\\debug.log");
* </pre>
*/
public static final class CustomAttribute {
private final AttributeType type;
private final String name;
private final String description;
private final Object defaultValue;
/**
* Creates a new CustomAttribute, for implementor-defined attributes
* that are not general, but specific to the current implementation.
*
* @param iType the type of the custom attribute.
* @param iName the name of the custom attribute. This should typically
* be written in C constants-style, like
* <code>A_NEW_CUSTOM_ATTRIBUTE</code>, to fit in with the general
* aesthetic approach. ;-)
* @param iDescription a description of the attribute.
* @param iDefaultValue the default newValue of the attribute.
*/
private CustomAttribute(AttributeType iType, String iName,
String iDescription, Object iDefaultValue) {
// Input check...
if(iType == null)
throw new IllegalArgumentException("An attribute must have a type.");
if(iName == null)
throw new IllegalArgumentException("An attribute must have a name.");
if(iDescription == null)
throw new IllegalArgumentException("An attribute must have a description.");
if(iDefaultValue == null)
throw new IllegalArgumentException("An attribute must have a default value.");
else if(!iType.isValidValue(iDefaultValue))
throw new IllegalArgumentException("Illegal default value!");
this.type = iType;
this.name = iName;
this.description = iDescription;
this.defaultValue = iDefaultValue;
}
/**
* Returns the type of this custom attribute.
*
* @return the type of this custom attribute.
*/
public AttributeType getType() {
return type;
}
/**
* Returns the name of this custom attribute.
*
* @return the name of this custom attribute.
*/
public String getName() {
return name;
}
/**
* Returns a brief description of this custom attribute.
*
* @return a brief description of this custom attribute.
*/
public String getDescription() {
return description;
}
/**
* Returns the default newValue for this custom attribute.
*
* @return the default newValue for this custom attribute.
*/
public Object getDefaultValue() {
return defaultValue;
}
/**
* Sets the default newValue of this custom attribute. Factory
* implementors can ovveride this default newValue specific to their
* implementation as this enum is instance-bound and not static.
*
* @param iDefaultValue the new default newValue for this custom
* attribute.
*/
/* // Not needed here
protected void setDefaultValue(Object iDefaultValue) {
if(!type.isValidValue(iDefaultValue))
throw new IllegalArgumentException("Illegal default newValue!");
else
this.defaultValue = iDefaultValue;
}
* */
}
}