KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > dba > openbase > OpenBaseAdapter


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.dba.openbase;
21
22 import java.sql.PreparedStatement JavaDoc;
23 import java.sql.ResultSet JavaDoc;
24 import java.sql.Types JavaDoc;
25 import java.util.Iterator JavaDoc;
26
27 import org.apache.cayenne.CayenneRuntimeException;
28 import org.apache.cayenne.access.DataNode;
29 import org.apache.cayenne.access.trans.QualifierTranslator;
30 import org.apache.cayenne.access.trans.QueryAssembler;
31 import org.apache.cayenne.access.types.CharType;
32 import org.apache.cayenne.access.types.DefaultType;
33 import org.apache.cayenne.access.types.ExtendedTypeMap;
34 import org.apache.cayenne.dba.JdbcAdapter;
35 import org.apache.cayenne.dba.PkGenerator;
36 import org.apache.cayenne.dba.TypesMapping;
37 import org.apache.cayenne.map.DbAttribute;
38 import org.apache.cayenne.map.DbEntity;
39 import org.apache.cayenne.map.DbJoin;
40 import org.apache.cayenne.map.DbRelationship;
41 import org.apache.cayenne.map.DerivedDbEntity;
42 import org.apache.cayenne.query.Query;
43 import org.apache.cayenne.query.SQLAction;
44
45 /**
46  * DbAdapter implementation for <a HREF="http://www.openbase.com">OpenBase</a>.
47  * Sample <a target="_top" HREF="../../../../../../../developerguide/unit-tests.html">connection
48  * settings</a> to use with OpenBase are shown below:
49  *
50 <pre>
51 test-openbase.cayenne.adapter = org.apache.cayenne.dba.openbase.OpenBaseAdapter
52 test-openbase.jdbc.username = test
53 test-openbase.jdbc.password = secret
54 test-openbase.jdbc.url = jdbc:openbase://serverhostname/cayenne
55 test-openbase.jdbc.driver = com.openbase.jdbc.ObDriver
56 </pre>
57  *
58  * @author <a HREF="mailto:mkienenb@alaska.net">Mike Kienenberger</a>
59  * @author Andrus Adamchik
60  *
61  * @since 1.1
62  */

63 public class OpenBaseAdapter extends JdbcAdapter {
64
65     public OpenBaseAdapter() {
66         // init defaults
67
this.setSupportsUniqueConstraints(false);
68     }
69     
70     /**
71      * Uses special action builder to create the right action.
72      *
73      * @since 1.2
74      */

75     public SQLAction getAction(Query query, DataNode node) {
76         return query.createSQLAction(new OpenBaseActionBuilder(this, node
77                 .getEntityResolver()));
78     }
79
80     protected void configureExtendedTypes(ExtendedTypeMap map) {
81         super.configureExtendedTypes(map);
82
83         // Byte handling doesn't work on read...
84
// need special converter
85
map.registerType(new OpenBaseByteType());
86
87         map.registerType(new OpenBaseCharType());
88     }
89
90     public DbAttribute buildAttribute(
91         String JavaDoc name,
92         String JavaDoc typeName,
93         int type,
94         int size,
95         int scale,
96         boolean allowNulls) {
97
98         // OpenBase makes no distinction between CHAR and VARCHAR
99
// so lets use VARCHAR, since it seems more generic
100
if (type == Types.CHAR) {
101             type = Types.VARCHAR;
102         }
103
104         return super.buildAttribute(name, typeName, type, size, scale, allowNulls);
105     }
106
107     /**
108      * Returns word "go".
109      */

110     public String JavaDoc getBatchTerminator() {
111         return "go";
112     }
113
114     /**
115      * Returns null, since views are not yet supported in openbase.
116      */

117     public String JavaDoc tableTypeForView() {
118         // TODO: according to OpenBase docs views *ARE* supported.
119
return null;
120     }
121
122     /**
123      * Returns OpenBase-specific translator for queries.
124      */

125     public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) {
126         return new OpenBaseQualifierTranslator(queryAssembler);
127     }
128
129     /**
130       * Creates and returns a primary key generator. Overrides superclass
131       * implementation to return an
132       * instance of OpenBasePkGenerator that uses built-in multi-server primary key generation.
133       */

134     protected PkGenerator createPkGenerator() {
135         return new OpenBasePkGenerator();
136     }
137
138     /**
139       * Returns a SQL string that can be used to create database table
140       * corresponding to <code>ent</code> parameter.
141       */

142     public String JavaDoc createTable(DbEntity ent) {
143         // later we may support view creation
144
// for derived DbEntities
145
if (ent instanceof DerivedDbEntity) {
146             throw new CayenneRuntimeException(
147                 "Can't create table for derived DbEntity '" + ent.getName() + "'.");
148         }
149
150         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
151         buf.append("CREATE TABLE ").append(ent.getFullyQualifiedName()).append(" (");
152
153         // columns
154
Iterator JavaDoc it = ent.getAttributes().iterator();
155         boolean first = true;
156         while (it.hasNext()) {
157             if (first) {
158                 first = false;
159             }
160             else {
161                 buf.append(", ");
162             }
163
164             DbAttribute at = (DbAttribute) it.next();
165
166             // attribute may not be fully valid, do a simple check
167
if (at.getType() == TypesMapping.NOT_DEFINED) {
168                 throw new CayenneRuntimeException(
169                     "Undefined type for attribute '"
170                         + ent.getFullyQualifiedName()
171                         + "."
172                         + at.getName()
173                         + "'.");
174             }
175
176             String JavaDoc[] types = externalTypesForJdbcType(at.getType());
177             if (types == null || types.length == 0) {
178                 throw new CayenneRuntimeException(
179                     "Undefined type for attribute '"
180                         + ent.getFullyQualifiedName()
181                         + "."
182                         + at.getName()
183                         + "': "
184                         + at.getType());
185             }
186
187             String JavaDoc type = types[0];
188             buf.append(at.getName()).append(' ').append(type);
189
190             // append size and precision (if applicable)
191
if (TypesMapping.supportsLength(at.getType())) {
192                 int len = at.getMaxLength();
193                 int scale = TypesMapping.isDecimal(at.getType()) ? at.getScale() : -1;
194
195                 // sanity check
196
if (scale > len) {
197                     scale = -1;
198                 }
199
200                 if (len > 0) {
201                     buf.append('(').append(len);
202
203                     if (scale >= 0) {
204                         buf.append(", ").append(scale);
205                     }
206
207                     buf.append(')');
208                 }
209             }
210
211             if (at.isMandatory()) {
212                 buf.append(" NOT NULL");
213             }
214             else {
215                 buf.append(" NULL");
216             }
217         }
218
219         buf.append(')');
220         return buf.toString();
221     }
222
223     /**
224      * Returns a SQL string that can be used to create
225      * a foreign key constraint for the relationship.
226      */

227     public String JavaDoc createFkConstraint(DbRelationship rel) {
228         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
229
230         // OpendBase Specifics is that we need to create a constraint going
231
// from destination to source for this to work...
232

233         DbEntity sourceEntity = (DbEntity) rel.getSourceEntity();
234         DbEntity targetEntity = (DbEntity) rel.getTargetEntity();
235         String JavaDoc toMany = (!rel.isToMany()) ? "'1'" : "'0'";
236
237         // TODO: doesn't seem like OpenBase supports compound joins...
238
// need to doublecheck that
239

240         int joinsLen = rel.getJoins().size();
241         if (joinsLen == 0) {
242             throw new CayenneRuntimeException(
243                 "Relationship has no joins: " + rel.getName());
244         }
245         else if (joinsLen > 1) {
246             // ignore extra joins
247
}
248
249         DbJoin join = (DbJoin) rel.getJoins().get(0);
250
251         buf
252             .append("INSERT INTO _SYS_RELATIONSHIP (")
253             .append("dest_table, dest_column, source_table, source_column, ")
254             .append("block_delete, cascade_delete, one_to_many, operator, relationshipName")
255             .append(") VALUES ('")
256             .append(sourceEntity.getFullyQualifiedName())
257             .append("', '")
258             .append(join.getSourceName())
259             .append("', '")
260             .append(targetEntity.getFullyQualifiedName())
261             .append("', '")
262             .append(join.getTargetName())
263             .append("', 0, 0, ")
264             .append(toMany)
265             .append(", '=', '")
266             .append(rel.getName())
267             .append("')");
268
269         return buf.toString();
270     }
271
272     // OpenBase JDBC driver has trouble reading "integer" as byte
273
// this converter addresses such problem
274
static class OpenBaseByteType extends DefaultType {
275         OpenBaseByteType() {
276             super(Byte JavaDoc.class.getName());
277         }
278
279         public Object JavaDoc materializeObject(ResultSet JavaDoc rs, int index, int type)
280             throws Exception JavaDoc {
281
282             // read value as int, and then narrow it down
283
int val = rs.getInt(index);
284             return (rs.wasNull()) ? null : new Byte JavaDoc((byte) val);
285         }
286     }
287
288     static class OpenBaseCharType extends CharType {
289         OpenBaseCharType() {
290             super(false, true);
291         }
292
293         public void setJdbcObject(
294             PreparedStatement JavaDoc st,
295             Object JavaDoc val,
296             int pos,
297             int type,
298             int precision)
299             throws Exception JavaDoc {
300
301             // These to types map to "text"; and when setting "text" as object
302
// OB assumes that the object is the actual CLOB... weird
303
if (type == Types.CLOB || type == Types.LONGVARCHAR) {
304                 st.setString(pos, (String JavaDoc) val);
305             }
306             else {
307                 super.setJdbcObject(st, val, pos, type, precision);
308             }
309         }
310     }
311 }
312
Popular Tags