/*******************************************************************************
* Copyright (c) 1998, 2008 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
* 05/16/2008-1.0M8 Guy Pelletier
* - 218084: Implement metadata merging functionality between mapping files
* 06/20/2008-1.0 Guy Pelletier
* - 232975: Failure when attribute type is generic
* 09/23/2008-1.1 Guy Pelletier
* - 241651: JPA 2.0 Access Type support
******************************************************************************/
package org.eclipse.persistence.internal.jpa.metadata.accessors.mappings;
import java.lang.annotation.Annotation;
import java.util.Map;
import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.internal.jpa.metadata.MetadataLogger;
import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.ClassAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataAccessibleObject;
import org.eclipse.persistence.internal.jpa.metadata.columns.ColumnMetadata;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.DirectMapMapping;
import org.eclipse.persistence.mappings.converters.Converter;
/**
* INTERNAL:
* A basic collection accessor.
*
* @author Guy Pelletier
* @since TopLink 11g
*/
public class BasicMapAccessor extends BasicCollectionAccessor {
private ColumnMetadata m_keyColumn;
private String m_keyConverter;
private String m_valueConverter;
private boolean m_keyContextProcessing;
/**
* INTERNAL:
* Used for OX mapping.
*/
public BasicMapAccessor() {
super("<basic-map>");
}
/**
* INTERNAL:
*/
public BasicMapAccessor(Annotation basicMap, MetadataAccessibleObject accessibleObject, ClassAccessor classAccessor) {
super(basicMap, accessibleObject, classAccessor);
m_keyColumn = new ColumnMetadata((Annotation) MetadataHelper.invokeMethod("keyColumn", basicMap), accessibleObject, getAttributeName());
Annotation keyConvert = (Annotation) MetadataHelper.invokeMethod("keyConverter", basicMap);
m_keyConverter = (String) MetadataHelper.invokeMethod("value", keyConvert);
Annotation valueConvert = (Annotation) MetadataHelper.invokeMethod("valueConverter", basicMap);
m_valueConverter = (String)MetadataHelper.invokeMethod("value", valueConvert);
setValueColumn(new ColumnMetadata((Annotation) MetadataHelper.invokeMethod("valueColumn", basicMap), accessibleObject, getAttributeName()));
setFetch((Enum) MetadataHelper.invokeMethod("fetch", basicMap));
}
/**
* INTERNAL:
*/
@Override
protected ColumnMetadata getColumn(String loggingCtx) {
if (loggingCtx.equals(MetadataLogger.VALUE_COLUMN)) {
return super.getColumn(loggingCtx);
} else {
return (m_keyColumn == null) ? new ColumnMetadata(getAccessibleObject(), getAttributeName()) : m_keyColumn;
}
}
/**
* INTERNAL:
*/
@Override
protected String getDefaultCollectionTableName() {
if (m_keyColumn != null && m_keyColumn.getTable() != null && ! m_keyColumn.getTable().equals("")) {
return m_keyColumn.getTable();
} else {
return super.getDefaultCollectionTableName();
}
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public ColumnMetadata getKeyColumn() {
return m_keyColumn;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public String getKeyConverter() {
return m_keyConverter;
}
/**
* INTERNAL:
* Return the reference class for this accessor.
*/
@Override
public Class getReferenceClass() {
if (m_keyContextProcessing) {
return getAccessibleObject().getMapKeyClass(getDescriptor());
} else {
return getReferenceClassFromGeneric();
}
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public String getValueConverter() {
return m_valueConverter;
}
/**
* INTERNAL:
* A BasicMap always has a Convert specified. They are defaulted within
* the BasicMap annotation. This will be used to log warning messages when
* ignoring JPA converters for lob, temporal, enumerated and serialized.
*/
@Override
protected boolean hasConvert() {
return true;
}
/**
* INTERNAL:
*/
@Override
public void initXMLObject(MetadataAccessibleObject accessibleObject) {
super.initXMLObject(accessibleObject);
// Initialize single ORMetadata objects.
initXMLObject(m_keyColumn, accessibleObject);
// Make sure the attribute name is set on the key column if one is
// set through XML.
if (m_keyColumn != null) {
m_keyColumn.setAttributeName(getAttributeName());
}
}
/**
* INTERNAL:
* Returns true if the given class is a valid basic map type.
*/
protected boolean isValidBasicMapType(Class cls) {
return cls.equals(Map.class);
}
/**
* INTERNAL:
* The processing of JPA converters for a basic map has been disabled, since
* we will not know which part of the map (key or value) to apply the JPA
* converter. See isLob, isTemporal and isEnumerated calls for log warning
* details.
*/
@Override
public void process() {
if (isValidBasicMapType(getRawClass())) {
// Initialize our mapping.
DirectMapMapping mapping = new DirectMapMapping();
// Process common direct collection metadata. This must be done
// before any field processing since field processing requires that
// the collection table be processed before hand.
process(mapping);
// Process the fetch type
if (usesIndirection()) {
mapping.useTransparentMap();
} else {
mapping.dontUseIndirection();
mapping.useMapClass(java.util.Hashtable.class);
}
// Process the key column (we must process this field before the call
// to processConverter, since it may set a field classification)
mapping.setDirectKeyField(getDatabaseField(mapping.getReferenceTable(), MetadataLogger.MAP_KEY_COLUMN));
// Process a converter for the key column of this mapping.
processMappingConverter(mapping, m_keyConverter);
// Process the value column (we must process this field before the call
// to processConverter, since it may set a field classification)
mapping.setDirectField(getDatabaseField(mapping.getReferenceTable(), MetadataLogger.VALUE_COLUMN));
// Process a converter for value column of this mapping.
processMappingConverter(mapping, m_valueConverter);
// process properties
processProperties(mapping);
} else {
throw ValidationException.invalidTypeForBasicMapAttribute(getAttributeName(), getRawClass(), getJavaClass());
}
}
/**
* INTERNAL:
* Process a convert value to apply a specified EclipseLink converter
* (Converter, TypeConverter, ObjectTypeConverter) to the given mapping.
*
* This method is called in second stage processing and should only be
* called on accessors that have a @Convert specified.
*/
@Override
public void processConvert() {
DatabaseMapping mapping = getDescriptor().getMappingForAttributeName(getAttributeName());
m_keyContextProcessing = true;
processConvert(mapping, m_keyConverter);
m_keyContextProcessing = false;
processConvert(mapping, m_valueConverter);
}
/**
* INTERNAL:
*/
@Override
public void setConverter(DatabaseMapping mapping, Converter converter) {
if (m_keyContextProcessing) {
((DirectMapMapping) mapping).setKeyConverter(converter);
} else {
((DirectMapMapping) mapping).setValueConverter(converter);
}
}
/**
* INTERNAL:
*/
@Override
public void setConverterClassName(DatabaseMapping mapping, String converterClassName) {
if (m_keyContextProcessing) {
((DirectMapMapping) mapping).setKeyConverterClassName(converterClassName);
} else {
((DirectMapMapping) mapping).setValueConverterClassName(converterClassName);
}
}
/**
* INTERNAL:
*/
@Override
public void setFieldClassification(DatabaseMapping mapping, Class classification) {
if (m_keyContextProcessing) {
((DirectMapMapping) mapping).setDirectKeyFieldClassification(classification);
} else {
super.setFieldClassification(mapping, classification);
}
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public void setKeyColumn(ColumnMetadata keyColumn) {
m_keyColumn = keyColumn;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public void setKeyConverter(String keyConverter) {
m_keyConverter = keyConverter;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public void setValueConverter(String valueConverter) {
m_valueConverter = valueConverter;
}
}