/* * 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.openjpa.lib.util.StringUtil; 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.ClassUtil; import org.apache.openjpa.lib.util.Localizer; /** * 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><table name>.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><class name>.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><table name>.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><class name>.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><class name>.<field name>.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><table name>.<column name>.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><class name>.<field name>.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><class name>.<field name>.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(ClassUtil.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 = StringUtil.trimToNull(_props.getProperty(key)); _unaccessed.remove(key); return val; } }