001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.persistence.jdbc;
020:
021: import org.apache.commons.lang.StringUtils;
022: import org.apache.openjpa.jdbc.meta.ClassMapping;
023: import org.apache.openjpa.jdbc.meta.Discriminator;
024: import org.apache.openjpa.jdbc.meta.FieldMapping;
025: import org.apache.openjpa.jdbc.meta.MappingDefaultsImpl;
026: import org.apache.openjpa.jdbc.meta.ValueMapping;
027: import org.apache.openjpa.jdbc.meta.Version;
028: import org.apache.openjpa.jdbc.meta.strats.FlatClassStrategy;
029: import org.apache.openjpa.jdbc.meta.strats.NoneDiscriminatorStrategy;
030: import org.apache.openjpa.jdbc.meta.strats.NoneVersionStrategy;
031: import org.apache.openjpa.jdbc.meta.strats.NumberVersionStrategy;
032: import org.apache.openjpa.jdbc.meta.strats.SubclassJoinDiscriminatorStrategy;
033: import org.apache.openjpa.jdbc.meta.strats.ValueMapDiscriminatorStrategy;
034: import org.apache.openjpa.jdbc.meta.strats.VerticalClassStrategy;
035: import org.apache.openjpa.jdbc.schema.Column;
036: import org.apache.openjpa.jdbc.schema.Schema;
037: import org.apache.openjpa.jdbc.schema.Table;
038: import org.apache.openjpa.jdbc.sql.JoinSyntaxes;
039: import org.apache.openjpa.meta.JavaTypes;
040: import serp.util.Strings;
041:
042: /**
043: * Supplies default mapping information in accordance with JPA spec.
044: *
045: * @author Steve Kim
046: * @author Abe White
047: * @nojavadoc
048: */
049: public class PersistenceMappingDefaults extends MappingDefaultsImpl {
050:
051: private boolean _prependFieldNameToJoinTableInverseJoinColumns = true;
052:
053: public PersistenceMappingDefaults() {
054: setDefaultMissingInfo(true);
055: setStoreEnumOrdinal(true);
056: setOrderLists(false);
057: setAddNullIndicator(false);
058: setDiscriminatorColumnName("DTYPE");
059: }
060:
061: /**
062: * Whether to prepend the field name to the default name of inverse join
063: * columns within join tables. Defaults to true per spec, but set to false
064: * for compatibility with older versions of OpenJPA.
065: */
066: public boolean getPrependFieldNameToJoinTableInverseJoinColumns() {
067: return _prependFieldNameToJoinTableInverseJoinColumns;
068: }
069:
070: /**
071: * Whether to prepend the field name to the default name of inverse join
072: * columns within join tables. Defaults to true per spec, but set to false
073: * for compatibility with older versions of OpenJPA.
074: */
075: public void setPrependFieldNameToJoinTableInverseJoinColumns(
076: boolean val) {
077: _prependFieldNameToJoinTableInverseJoinColumns = val;
078: }
079:
080: @Override
081: public Object getStrategy(Version vers, boolean adapt) {
082: Object strat = super .getStrategy(vers, adapt);
083: ClassMapping cls = vers.getClassMapping();
084: if (strat != null
085: || cls.getJoinablePCSuperclassMapping() != null
086: || cls.getVersionField() != null)
087: return strat;
088:
089: if (vers.getMappingInfo().getColumns().isEmpty())
090: return NoneVersionStrategy.getInstance();
091: return new NumberVersionStrategy();
092: }
093:
094: @Override
095: public Object getStrategy(Discriminator disc, boolean adapt) {
096: Object strat = super .getStrategy(disc, adapt);
097: ClassMapping cls = disc.getClassMapping();
098: if (strat != null
099: || cls.getJoinablePCSuperclassMapping() != null
100: || disc.getMappingInfo().getValue() != null)
101: return strat;
102:
103: // don't use a column-based discriminator approach unless user has set
104: // a column explicitly or is using flat inheritance explicitly
105: if (!disc.getMappingInfo().getColumns().isEmpty())
106: return new ValueMapDiscriminatorStrategy();
107:
108: ClassMapping base = cls;
109: while (base.getMappingInfo().getHierarchyStrategy() == null
110: && base.getPCSuperclassMapping() != null)
111: base = base.getPCSuperclassMapping();
112:
113: strat = base.getMappingInfo().getHierarchyStrategy();
114: if (FlatClassStrategy.ALIAS.equals(strat))
115: return new ValueMapDiscriminatorStrategy();
116: if (VerticalClassStrategy.ALIAS.equals(strat)
117: && dict.joinSyntax != JoinSyntaxes.SYNTAX_TRADITIONAL)
118: return new SubclassJoinDiscriminatorStrategy();
119: return NoneDiscriminatorStrategy.getInstance();
120: }
121:
122: @Override
123: public String getTableName(ClassMapping cls, Schema schema) {
124: if (cls.getTypeAlias() != null)
125: return cls.getTypeAlias();
126: return Strings.getClassName(cls.getDescribedType()).replace(
127: '$', '_');
128: }
129:
130: @Override
131: public String getTableName(FieldMapping fm, Schema schema) {
132: // base name is table of defining type + '_'
133: String name = fm.getDefiningMapping().getTable().getName()
134: + "_";
135:
136: // if this is an assocation table, spec says to suffix with table of
137: // the related type. spec doesn't cover other cases; we're going to
138: // suffix with the field name
139: ClassMapping rel = fm.getElementMapping().getTypeMapping();
140: boolean assoc = rel != null && rel.getTable() != null
141: && fm.getTypeCode() != JavaTypes.MAP;
142: if (assoc)
143: name += rel.getTable().getName();
144: else
145: name += fm.getName();
146: return name.replace('$', '_');
147: }
148:
149: @Override
150: public void populateJoinColumn(FieldMapping fm, Table local,
151: Table foreign, Column col, Object target, int pos, int cols) {
152: // only use spec defaults with column targets
153: if (!(target instanceof Column))
154: return;
155:
156: // if this is a bidi relation, prefix with inverse field name, else
157: // prefix with owning entity name
158: FieldMapping[] inverses = fm.getInverseMappings();
159: String name;
160: if (inverses.length > 0)
161: name = inverses[0].getName();
162: else
163: name = fm.getDefiningMapping().getTypeAlias();
164: String targetName = ((Column) target).getName();
165: String tempName = null;
166: if ((name.length() + targetName.length()) >= dict.maxColumnNameLength)
167: tempName = name.substring(0, dict.maxColumnNameLength
168: - targetName.length() - 1);
169: // suffix with '_' + target column
170: if (tempName == null)
171: tempName = name;
172: name = tempName + "_" + targetName;
173: name = dict.getValidColumnName(name, foreign);
174: col.setName(name);
175: }
176:
177: @Override
178: public void populateForeignKeyColumn(ValueMapping vm, String name,
179: Table local, Table foreign, Column col, Object target,
180: boolean inverse, int pos, int cols) {
181: boolean elem = vm == vm.getFieldMapping().getElement()
182: && vm.getFieldMapping().getTypeCode() != JavaTypes.MAP;
183:
184: // if this is a non-inverse collection element key, it must be in
185: // a join table: if we're not prepending the field name, leave the
186: // default
187: if (!_prependFieldNameToJoinTableInverseJoinColumns && !inverse
188: && elem)
189: return;
190:
191: // otherwise jpa always uses <field>_<pkcol> for column name, even
192: // when only one col
193: if (target instanceof Column) {
194: if (elem)
195: name = vm.getFieldMapping().getName();
196:
197: if (isRemoveHungarianNotation())
198: name = removeHungarianNotation(name);
199:
200: name = dict.getValidColumnName(name, local);
201: col.setName(name + "_" + ((Column) target).getName());
202: }
203: }
204:
205: @Override
206: public void populateColumns(Version vers, Table table, Column[] cols) {
207: // check for version field and use its name as column name
208: FieldMapping fm = vers.getClassMapping()
209: .getVersionFieldMapping();
210: if (fm != null && cols.length == 1)
211: cols[0].setName(fm.getName());
212: else
213: super.populateColumns(vers, table, cols);
214: }
215: }
|