Not a problem at all to run my ideas through - I didn't want to burden
anyone with details if they weren't interested. Mind, I'm looking to do
no more than replace the hard-coded values with something the user can
easily change. Of course, a more extensive change may or may not be
under consideration, and I'll speak to that later.

(Mostly, my interest was in getting into the guts of things to see how
they work, and I personally find working on something real more
instructive than simply reading through lots of code. But that's just my
way, and I certainly had no intention of doing anything but discussing
my solution, and if anyone found it interesting, submitting it as a
potential patch. I would not consider the work wasted should it be
rejected, since I would have learned a good deal in the process.)

Here's how I see it (potentially) working:

The configuration information that is potentially configurable would be
represented in XML files. For MS SQL Server, for instance, the file
might look like this:

<?xml version="1.0" encoding="iso-8859-1"?>
<platform-config>
  <jdbc-subprotocols>
    <jdbc-subprotocol subprotocol="microsoft:sqlserver"
driver-class="com.microsoft.jdbc.sqlserver.SQLServerDriver"/>
    <jdbc-subprotocol subprotocol="sqlserver"
driver-class="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
    <jdbc-subprotocol subprotocol="sqljdbc"
driver-class="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
  </jdbc-subprotocols>
  <type-mappings>
    <type-mapping jdbc-type="ARRAY" database-type="IMAGE"/>
    <type-mapping jdbc-type="BIGINT" database-type="DECIMAL(19,0)"/>
    <type-mapping jdbc-type="BLOB" database-type="IMAGE"
target-jdbc-type="LONGVARBINARY"/>
    <type-mapping jdbc-type="CLOB" database-type="TEXT"
target-jdbc-type="LONGVARCHAR"/>
    <type-mapping jdbc-type="DATE" database-type="DATETIME"
target-jdbc-type="TIMESTAMP"/>
    <type-mapping jdbc-type="DISTINCT" database-type="IMAGE"/>
    <type-mapping jdbc-type="DOUBLE" database-type="FLOAT"
target-jdbc-type="FLOAT"/>
    <type-mapping jdbc-type="INTEGER" database-type="INT"/>
    <type-mapping jdbc-type="JAVA_OBJECT" database-type="IMAGE"
target-jdbc-type="LONGVARBINARY"/>
    <type-mapping jdbc-type="LONGVARBINARY" database-type="IMAGE"/>
    <type-mapping jdbc-type="LONGVARCHAR" database-type="TEXT"/>
    <type-mapping jdbc-type="NULL" database-type="IMAGE"
target-jdbc-type="LONGVARBINARY"/>
    <type-mapping jdbc-type="OTHER" database-type="IMAGE"
target-jdbc-type="LONGVARBINARY"/>
    <type-mapping jdbc-type="REF" database-type="IMAGE"
target-jdbc-type="LONGVARBINARY"/>
    <type-mapping jdbc-type="STRUCT" database-type="IMAGE"
target-jdbc-type="LONGVARBINARY"/>
    <type-mapping jdbc-type="TIME" database-type="DATETIME"
target-jdbc-type="TIMESTAMP"/>
    <type-mapping jdbc-type="TIMESTAMP" database-type="DATETIME"/>
    <type-mapping jdbc-type="BOOLEAN" database-type="BIT"
target-jdbc-type="BIT"/>
    <type-mapping jdbc-type="DATALINK" database-type="IMAGE"
target-jdbc-type="LONGVARBINARY"/>
  </type-mappings>
  <default-sizes>
    <default-size jdbc-type="CHAR" size="254"/>
    <default-size jdbc-type="VARCHAR" size="254"/>
    <default-size jdbc-type="BINARY" size="254"/>
    <default-size jdbc-type="VARBINARY" size="254"/>
  </default-sizes>
</platform-config>

You will note that comparison with the current MSSqlPlatform class makes
it perfectly clear that these are simply equivalents with XML markup. (I
haven't been through every Platform implementation yet, so this is still
subject to minor amendments, of course).

This could simplify matters so that with the following Betwixt-mapping
file:

<?xml version="1.0"?>
<betwixt-config>
  <class name="org.apache.ddlutils.platform.PlatformConfiguration">
    <element name="platform-config">
      <element name="jdbc-subprotocols">
        <element property="subprotocols" updater="addSubprotocol"/>
      </element>
      <element name="type-mappings">
        <element property="typeMappings" updater="addTypeMapping"/>
      </element>
      <element name="default-sizes">
        <element property="defaultSizes" updater="addDefaultSize"/>
      </element>
    </element>
  </class>
  <class name="org.apache.ddlutils.platform.Subprotocol">
    <element name="jdbc-subprotocol">
      <attribute name="subprotocol" property="subprotocol"/>
      <attribute name="driver-class" property="driverClass"/>
    </element>
  </class>
  <class name="org.apache.ddlutils.platform.TypeMapping">
    <element name="type-mapping">
      <attribute name="jdbc-type" property="jdbcType"/>
      <attribute name="database-type" property="databaseType"/>
      <attribute name="target-jdbc-type" property="targetJdbcType"/>
    </element>
  </class>
  <class name="org.apache.ddlutils.platform.DefaultSize">
    <element name="default-size">
      <attribute name="jdbc-type" property="jdbcType"/>
      <attribute name="size" property="size"/>
    </element>
  </class>
</betwixt-config>

It would be simple to read the files with only a couple of lines of
code:

    InputSource is = new
InputSource(getClass().getResourceAsStream(path));
    return new PlatformConfigurationIO().read(is);

with the PlatformConfigurationIO "read" method modeled after the one in
DatabaseIO. What is instantiated is simply a value object that can be
used to configure the MsSqlPlatform object, thus:

PlatformConfiguration pc = // however the PlatformConfiguration is
gotten
PlatformInfo info = getPlatformInfo();
// these are characteristics of the database and not configurable
info.setMaxIdentifierLength(128);
info.setNullAsDefaultValueRequired(false);
info.setPrimaryKeyEmbedded(true);
info.setForeignKeysEmbedded(false);
info.setIndicesEmbedded(false);
//info.setCommentPrefix("#");
// these are the configurable items
List typeMappings = pc.getTypeMappings();
if (typeMappings != null && ! typeMappings.isEmpty()) {
    Iterator iter = typeMappings.iterator();
    while (iter.hasNext()) {
        TypeMapping tm = (TypeMapping) iter.next();
        if (StringUtils.isNotBlank(tm.getTargetJdbcType())) {
            info.addNativeTypeMapping(tm.getJdbcType(), 
                tm.getDatabaseType(), tm.getTargetJdbcType());
        }
        else {
            // BIGINT will be mapped back to BIGINT by the model reader 
            info.addNativeTypeMapping(tm.getJdbcType(),
                tm.getDatabaseType());
        }
    }
}
List defaultSizes = pc.getDefaultSizes();
if (defaultSizes != null && ! defaultSizes.isEmpty()) {
    Iterator iter = defaultSizes.iterator();
    while (iter.hasNext()) {
        DefaultSize ds = (DefaultSize) iter.next();
        info.setDefaultSize(ds.getJdbcType(), ds.getSize());
    }
}
setSqlBuilder(new MSSqlBuilder(this));
setModelReader(new MSSqlModelReader(this));

You will note that I left the manner of obtaining this value object
unspecified above. My idea was to have a singleton factory that
statically loaded all the XML files it could find at runtime (it might
know about them, do Java discovery to get a list to look up, or simply
find them by a naming convention). It would be my idea, as you can see,
to acquire the XML files as classpath resources, so as to make it simple
for anyone to substitute for any of the files they like by simply
putting their replacements earlier on the classpath. This would probably
be made easiest (though it's a little restrictive) if the factory knew
the names of the files it was going to look up.

The subprotocol/JDBC drivers (currently static values) would be left off
in this version of the MSSqlPlatform. These, it seemed to me, would be
better suited to being loaded from the same factory and value object by
the PlatformUtils class. That is, rather than hard-coded, they would be
discovered, allowing any person to substitute whatever crazy driver they
had thought of (my first candidate, using SQL Server, was the jTDS
driver, which I frequently use). Hopefully, this would make it possible
(I haven't finished looking into this yet, however) for DdlUtils to
recognize more drivers and handle them automatically and correctly.

Finally, you will note that some aspects of the MSSqlPlatform are not
configurable: these are the aspects that have to do with the definition
of the database itself, how it works and what its limitations are. These
are not subject to configuration, as they are a part of the definition
of the platform itself, or so it seemed to me. Drivers, type-mappings,
and default JDBC type sizes are certainly something that might change
from one project to another, but while you're using SQL Server, these
things won't change.

There is still a good deal to do to bring any of this to life, but it
should be enough to at least indicate a direction. Naturally, I'm just
starting with this project, and I have no interest in stepping on toes.

As for breaking this up, it should be clear from this description that
it's all of a piece. I suppose I could hard-code the information into a
factory first and later alter the factory implementation to read XML
files, but the intermediate step would solve no actual problem (and
certainly wouldn't be one I'd normally take). However, all of this is
just initialization code: I would hope that no use case would be
affected. The classes will continue (by default) to contain the same
information and respond to the same APIs. Any changes should be, if I
understand how the classes would typically be used (perhaps a big if),
transparent.

After all, the whole point of DdlUtils, as I understand it, is to
encapsulate the differences between database DDL to the greatest degree
possible. Everything I'm working with has to do with the very sorts of
information that users would presumably not want to have to interact
with at all (except perhaps to insert a simple XML file to change some
default settings). Since that information is hidden within the
encapsulation of the tool, I hope it won't be thought that any of the
changes I suggest are in any way big ones.

If anyone has the idea of extending the functionality related to typing,
my solution may or may not fit into that, as it is intended literally as
a drop-in dynamic replacement for the current hard-coded values. It is
not intended to affect the interaction of the tool with anything. The
Ant tasks, for instance, would be completely unaffected, except that you
might want to alter the classpath slightly to pick up your replacement
mapping files before the DdlUtils JAR file.

I only foresee changes in those classes that have hard-coded information
currently (and of course you can't make them configurable without a
change, by definition). Possibly one or two refactorings might affect
the functionality of base classes transparently. Most of what I would
propose would be entirely new classes that only interact with the
current classes within encapsulation.

Obviously, an entirely different line of thought might be devoted to
making the tool sufficiently generic not to even have to know about
specific databases at all (in other words, all the information required
to make the tool work correctly would be in configuration information).
That's far more ambitious than I am suggesting here, if it's even
possible. However, it may be that this proposal is a small step in that
direction.

Thus my thoughts, and I look forward to any responses anyone may have. I
am perfectly open to even very different notions of how all this should
work. If there is a "DdlUtils way," I have no objection at all to
accommodating myself to it. For the moment, I have simply tried to see
how I might solve the problem of rendering the type-mappings and other
configurable facts of the Platform implementations in as simple and
drop-in a way as I could.

David Sills


-----Original Message-----
From: Thomas Dudziak [mailto:[EMAIL PROTECTED] 
Sent: Thursday, October 05, 2006 6:34 PM
To: ddlutils-dev@db.apache.org
Subject: Re: XML location?

On 10/5/06, David Sills <[EMAIL PROTECTED]> wrote:

> I have a question about file placement in DdlUtils. I am, as I said,
> working on a more-or-less drop-in replacement (there will certainly be
> some changes, but I'm trying to minimize them) for the present
> hard-coded platform configurations (particularly type-mappings, but
also
> other things, like drivers/subprotocols and default type sizes). I
plan
> on making the XML configuration files for each database type available
> as Classloader resources (so you can substitute for the default
> configuration for any database by simply placing another appropriately
> named configuration file earlier in the classpath). The next question
is
> where to store the default platform configuration files. I'm thinking
> src/xml (mostly because it's there), but if someone has a better idea,
> please do speak up.

David,
please run your ideas through the Dev list before implementing them,
just to make sure that they don't conflict with other pending
improvements or DdlUtils-usage scenarios of other projects. Also, I
have some already ideas regarding support of native types and type
mappings that are already quite thought through, so it would
definitely be helpful to discuss this before comitting to any
particular solution.
Another thing, it would be helpful if you could break your changes
into smaller, incremental pieces, as this makes it a lot easier to
incorportate.

cheers,
Tom

Reply via email to