package pt.ist.fenixframework.backend; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pt.ist.fenixframework.Config; import pt.ist.fenixframework.ConfigError; import pt.ist.fenixframework.atomic.ContextFactory; import pt.ist.fenixframework.dml.CodeGenerator; /** * This class represents a feature that all DML code generators must implement: All {@link * pt.ist.fenixframework.dml.CodeGenerator} implementations should generate a class named {@link * pt.ist.fenixframework.backend.CurrentBackEndId} (see {@link * pt.ist.fenixframework.dml.CodeGenerator#generateBackEndId}) that implements this abstract class * and provides information about the current backend that is being used to manage the domain model. * This is also part of the support required for configuration by convention. * * @see pt.ist.fenixframework.FenixFramework */ public abstract class BackEndId { private static final Logger logger = LoggerFactory.getLogger(BackEndId.class); /** * This map holds generic parameters that each module may wish to add. It does not support * <code>null</code> values. */ private final Map<String, String> params = new ConcurrentHashMap<String, String>(); /** * Adds a parameter to the map of parameters. The typical usage of this method is during the * initialization of this class, to store parameters, e.g., a module may register that is * active by setting a key with a given value. */ protected final String setParam(String key, String value) { return this.params.put(key, value); } /** * Search for a parameter value given its key. * param key The parameter to lookup. * @return null if the corresponding key does not exist. */ public final String getParam(String key) { return this.params.get(key); } /** * Get the (unique) name of this {@link BackEnd}. The String returned by this method should * contain only valid characters in a filename (because it can be used for configuration by * convention (see {@link pt.ist.fenixframework.FenixFramework}). * * @see pt.ist.fenixframework.FenixFramework */ public abstract String getBackEndName(); /** * Get the Class instance that represents the default configuration class to use for this * backend. This class is used to instantite a {@link Config} instance is none is explicitly * indicated. */ public abstract Class<? extends Config> getDefaultConfigClass(); /** * Get the Class instance for the factory that creates {@link * pt.ist.fenixframework.atomic.AtomicContext}s. These contexts are backend-specific (thus the * backend provides the factory), because they control the logic required to execute a {@link * java.util.concurrent.Callable} within a transactional context. */ public abstract Class<? extends ContextFactory> getAtomicContextFactoryClass(); /** * Lookup via reflection the {@link pt.ist.fenixframework.backend.CurrentBackEndId} class and * return an instance of it. * * @throws ConfigError if the expected class does not exit, or it does not extend the BackEndId * class */ public static final BackEndId getBackEndId() throws ConfigError { Exception ex = null; try { Class<CurrentBackEndId> currentBackEndIdClass = (Class<CurrentBackEndId>)Class.forName(CurrentBackEndId.class.getName()); BackEndId beId = (BackEndId)currentBackEndIdClass.newInstance(); return beId; } catch (ClassNotFoundException e) { ex = e; } catch (InstantiationException e) { ex = e; } catch (IllegalAccessException e) { ex = e; } String message = "Missing required BackEndId: " + CodeGenerator.BACKEND_PACKAGE + "." + CodeGenerator.CURRENT_BACKEND_ID_CLASS; logger.error(message); throw new ConfigError(message); } }