blob: 608c0a8d5d01ef1c5ba187cf9c2f1b52ab924f33 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.jdbc.meta;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.schema.ForeignKey;
import org.apache.openjpa.jdbc.schema.Table;
import org.apache.openjpa.lib.util.Localizer;
import serp.util.Strings;
/**
* Simple {@link ReverseCustomizer} that uses a properties file to
* to allow customization of basic class and field properties. The
* customizer uses the following keys:
* <ul>
* <li><i>&lt;table name&gt;.table-type</i>: Override the default type of the
* given table. Legal values are: <code>base, secondary,
* secondary-outer, association, subclass, none</code>. See
* the TABLE_XXX constants in {@link ReverseMappingTool} for descriptions.</li>
* <li><i>&lt;class name&gt;.rename</i>: Override the tool-generated class name
* with the given value. Use full class names, including package. Use a
* value of <code>none</code> to reject the class and leave the
* corresponding table unmapped.</li>
* <li><i>&lt;table name&gt;.class-name</i>: Assign the given fully-qualified
* class name to the type created from the given table. Use a value of
* <code>none</code> to prevent mapping this table. This property can be
* used in place of the <code>rename</code> property.
* <li><i>&lt;class name&gt;.identity</i>: Set this property to
* <code>datastore</code>, <code>builtin</code>, or the desired
* fully-qualified application identity class name to override the
* reverse mapping tool's default identity settings. If the class has been
* renamed, use the new name.</li>
* <li><i>&lt;class name&gt;.&lt;field name&gt;.rename</i>: Override the
* tool-generated field name with the given value. Use the field owner's
* full class name in the property key. The property value should be the
* new field name, without the preceding class name. Use a value of
* <code>none</code> to reject the generated mapping.</li>
* <li><i>&lt;table name&gt;.&lt;column name&gt;.field-name</i>: Assign the
* field name to use for the mapping of a particular column. If this is
* a multi-column mapping, any one of the columns can be used. Use a value
* of <code>none</code> to prevent the column (and associated columns)
* from being mapped. This property can be used in place of the
* <code>rename</code> property.
* <li><i>&lt;class name&gt;.&lt;field name&gt;.type</i>: The class name of
* the type to give the named field. Use full class names. If the field
* has been renamed, use the new name.</li>
* <li><i>&lt;class name&gt;.&lt;field name&gt;.value</i>: The initial value
* for the named field. The given string will be placed as-is in the
* generated Java code, so be sure to add quotes to strings, etc. If the
* field has been renamed, use the new name.</li>
* </ul> All keys are optional; if not specified, the customizer keeps the
* default value generated by the reverse mapping tool.
*/
public class PropertiesReverseCustomizer
implements ReverseCustomizer {
private static final Localizer _loc = Localizer.forPackage
(PropertiesReverseCustomizer.class);
protected ReverseMappingTool tool = null;
private Properties _props = null;
private Set _unaccessed = null;
public void setConfiguration(Properties props) {
_props = props;
_unaccessed = new TreeSet(props.keySet());
}
public void setTool(ReverseMappingTool tool) {
this.tool = tool;
}
public int getTableType(Table table, int defaultType) {
String type = getProperty(table.getName() + ".table-type");
if (type == null && table.getSchemaName() != null)
type = getProperty(table.getFullName() + ".table-type");
if (type == null)
return defaultType;
if ("none".equals(type))
return ReverseMappingTool.TABLE_NONE;
if ("base".equals(type))
return ReverseMappingTool.TABLE_BASE;
if ("secondary".equals(type))
return ReverseMappingTool.TABLE_SECONDARY;
if ("secondary-outer".equals(type))
return ReverseMappingTool.TABLE_SECONDARY_OUTER;
if ("association".equals(type))
return ReverseMappingTool.TABLE_ASSOCIATION;
if ("subclass".equals(type))
return ReverseMappingTool.TABLE_SUBCLASS;
throw new IllegalArgumentException(table.getName() + ".table-type: "
+ type);
}
public String getClassName(Table table, String defaultName) {
// check for a rename property or a table-naming property
String name = getProperty(defaultName + ".rename");
if (name == null) {
name = getProperty(table.getName() + ".class-name");
if (name == null && table.getSchemaName() != null)
name = getProperty(table.getFullName() + ".class-name");
}
if (name == null) {
if (tool.getLog().isTraceEnabled())
tool.getLog().trace(_loc.get("custom-no-class",
defaultName, table));
return defaultName;
}
if ("none".equals(name)) {
if (tool.getLog().isInfoEnabled())
tool.getLog().info(_loc.get("custom-rm-class",
defaultName, table));
return null;
}
if (tool.getLog().isInfoEnabled())
tool.getLog().info(_loc.get("custom-class", defaultName, name));
return name;
}
public void customize(ClassMapping cls) {
// customize identity type
String id = getProperty(cls.getDescribedType().getName()
+ ".identity");
if ("datastore".equals(id)) {
cls.setObjectIdType(null, false);
cls.setIdentityType(ClassMapping.ID_DATASTORE);
} else if ("builtin".equals(id)) {
cls.setObjectIdType(null, false);
cls.setIdentityType(ClassMapping.ID_APPLICATION);
} else if (id != null)
cls.setObjectIdType(tool.generateClass(id, null), false);
}
public String getClassCode(ClassMapping mapping) {
return null;
}
public void customize(FieldMapping field) {
String type = getProperty(field.getFullName(false) + ".type");
if (type != null)
field.setDeclaredType(Strings.toClass(type, null));
}
public String getFieldName(ClassMapping dec, Column[] cols, ForeignKey fk,
String defaultName) {
// check for a rename property or a column-naming property
String name = getProperty(dec.getDescribedType().getName() + "."
+ defaultName + ".rename");
for (int i = 0; name == null && i < cols.length; i++) {
name = getProperty(cols[i].getTableName() + "."
+ cols[i].getName() + "." + "field-name");
if (name == null && cols[i].getTable().getSchemaName() != null)
name = getProperty(cols[i].getTable().getFullName()
+ "." + cols[i].getName() + "." + "field-name");
}
if (name == null) {
if (tool.getLog().isTraceEnabled())
tool.getLog().trace(_loc.get("custom-no-field", defaultName,
dec));
return defaultName;
}
if ("none".equals(name)) {
if (tool.getLog().isInfoEnabled())
tool.getLog().info(_loc.get("custom-rm-field", defaultName,
dec));
return null;
}
if (tool.getLog().isInfoEnabled())
tool.getLog().info(_loc.get("custom-field", defaultName, dec,
name));
return name;
}
public String getInitialValue(FieldMapping field) {
return getProperty(field.getFullName(false) + ".value");
}
public String getDeclaration(FieldMapping field) {
return null;
}
public String getFieldCode(FieldMapping field) {
return null;
}
public boolean unmappedTable(Table table) {
return false;
}
public void close() {
if (!_unaccessed.isEmpty() && tool.getLog().isTraceEnabled())
tool.getLog().trace(_loc.get("custom-unused-props", _unaccessed));
}
/**
* Return the property value for the given key, or null if none.
*/
protected String getProperty(String key) {
String val = StringUtils.trimToNull(_props.getProperty(key));
_unaccessed.remove(key);
return val;
}
}