/**********************************************************************
Copyright (c) 2002 Kelly Grizzle (TJDO) and others. All rights reserved.
Licensed 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.
Contributors:
2003 Andy Jefferson - replaced TableMetadata with identifier and java name
2003 Andy Jefferson - coding standards
2004 Andy Jefferson - merged with JDOView
2004 Andy Jefferson - split out CorrespondentColumnsMapping
2005 Andy Jefferson - reworked to implement DatastoreClass and generate mappings correctly
...
**********************************************************************/
package org.jpox.store.rdbms.table;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import org.jpox.ClassLoaderResolver;
import org.jpox.exceptions.JPOXException;
import org.jpox.exceptions.JPOXUserException;
import org.jpox.metadata.AbstractMemberMetaData;
import org.jpox.metadata.ClassMetaData;
import org.jpox.metadata.DiscriminatorMetaData;
import org.jpox.metadata.FieldPersistenceModifier;
import org.jpox.metadata.IdentityType;
import org.jpox.metadata.VersionMetaData;
import org.jpox.store.exceptions.NoSuchPersistentFieldException;
import org.jpox.store.mapped.DatastoreClass;
import org.jpox.store.mapped.DatastoreIdentifier;
import org.jpox.store.mapped.mapping.JavaTypeMapping;
import org.jpox.store.mapped.mapping.MappingConsumer;
import org.jpox.store.rdbms.RDBMSManager;
import org.jpox.store.rdbms.exceptions.PersistentSuperclassNotAllowedException;
import org.jpox.store.rdbms.exceptions.ViewDefinitionException;
import org.jpox.util.MacroString;
/**
* Representation of an SQL View for a Class.
* Requires that the class use "nondurable" identity.
* Since a view is read-only, many methods throw exceptions that the operation is
* not supported.
*
* @version $Revision: 1.43 $
**/
public class ClassView extends ViewImpl implements DatastoreClass
{
/** Class MetaData for the class mapping to this view. */
private final ClassMetaData cmd;
/** Definition of the view. */
private final MacroString viewDef;
/** DDL statement for creating the view **/
private String createStatementDDL;
/** Mappings for the fields of this class to map to the View. */
private JavaTypeMapping[] fieldMappings;
/**
* Constructor for class view.
* @param tableName The name of the view.
* @param storeMgr The RDBMS manager managing this view
* @param cmd The metadata for the class represented by this view.
*/
public ClassView(final DatastoreIdentifier tableName, final RDBMSManager storeMgr, final ClassMetaData cmd)
{
super(tableName, storeMgr);
this.cmd = cmd;
if (cmd.getIdentityType() == IdentityType.APPLICATION || cmd.getIdentityType() == IdentityType.DATASTORE)
{
throw new JPOXUserException(LOCALISER.msg("031005", cmd.getFullClassName(), cmd.getIdentityType()));
}
else if (cmd.getIdentityType() == IdentityType.NONDURABLE)
{
// Do nothing. We need this type
}
// We expect a flat class here to map to a view.
if (cmd.getPersistenceCapableSuperclass() != null)
{
throw new PersistentSuperclassNotAllowedException(cmd.getFullClassName());
}
// Extract the view definition from MetaData
String viewImpStr = cmd.getValueForExtension("view-imports");
String viewDefStr = null;
if (dba.getVendorID() != null)
{
viewDefStr = cmd.getValueForExtension("view-definition" + '-' + dba.getVendorID());
}
if (viewDefStr == null)
{
viewDefStr = cmd.getValueForExtension("view-definition");
}
if (viewDefStr == null)
{
throw new ViewDefinitionException(cmd.getFullClassName(), viewDefStr);
}
viewDef = new MacroString(cmd.getFullClassName(), viewImpStr, viewDefStr);
}
/**
* Method to initialise the view. Generates the mappings for all fields in
* the class to map to this view.
* @param clr The ClassLoaderResolver
*/
public void initialize(final ClassLoaderResolver clr)
{
assertIsUninitialized();
int fieldCount = cmd.getNoOfManagedMembers();
fieldMappings = new JavaTypeMapping[fieldCount];
for (int fieldNumber = 0; fieldNumber < fieldCount; ++fieldNumber)
{
AbstractMemberMetaData fmd = cmd.getMetaDataForManagedMemberAtPosition(fieldNumber);
if (fmd.getPersistenceModifier() == FieldPersistenceModifier.PERSISTENT)
{
fieldMappings[fieldNumber] = dba.getMappingManager().getMapping(this, fmd, dba, clr, JavaTypeMapping.MAPPING_FIELD);
}
else if (fmd.getPersistenceModifier() != FieldPersistenceModifier.TRANSACTIONAL)
{
throw new JPOXException(LOCALISER.msg("031006",
cmd.getFullClassName(), fmd.getName(), fmd.getPersistenceModifier())).setFatal();
}
}
state = TABLE_STATE_INITIALIZED;
}
/**
* Post initilize. For things that must be set after all classes have been initialized before
* @param clr the ClassLoaderResolver
*/
public void postInitialize(final ClassLoaderResolver clr)
{
assertIsInitialized();
createStatementDDL = viewDef.substituteMacros(new MacroString.MacroHandler()
{
public void onIdentifierMacro(MacroString.IdentifierMacro im)
{
storeMgr.resolveIdentifierMacro(im, clr);
}
public void onParameterMacro(MacroString.ParameterMacro pm)
{
throw new JPOXUserException(LOCALISER.msg("031009", cmd.getFullClassName(), pm));
}
}, clr
);
}
/**
* Accessor for a mapping for the ID. A view row doesn't have an id as such.
* @return The ID mapping.
*/
public JavaTypeMapping getIDMapping()
{
// Just return the first mapping that we have (since we have no "id" and this is used for "count(this)" queries so doesnt matter)
// If there are other situations that would come through here then we would need to cater for those better
for (int i=0;i<fieldMappings.length;i++)
{
if (fieldMappings[i] != null)
{
return fieldMappings[i];
}
}
return null;
}
/**
* Accessor for the base datastore class (table) managing the given field.
* Returns null since we dont manage things the same with views.
* @param fmd MetaData for the field
* @return The base table.
*/
public DatastoreClass getBaseDatastoreClassWithField(AbstractMemberMetaData fmd)
{
return null;
}
/**
* Accessor for the supertable for this table.
* @return The supertable
**/
public DatastoreClass getSuperDatastoreClass()
{
return null;
}
/**
* Accessor for any secondary tables for this table.
* @return Secondary tables (if any)
*/
public Collection getSecondaryDatastoreClasses()
{
return null;
}
/**
* Accessor for the datastore identity id mapping.
* Returns null since we dont use datastore identity for views.
* @return Datastore identity ID mapping
*/
public JavaTypeMapping getDataStoreObjectIdMapping()
{
return null;
}
/**
* Accessor for whether this table manages the specified class
* @param className Name of the class
* @return Whether it is managed by this table
*/
public boolean managesClass(String className)
{
// We dont manage classes as such so just return false
return false;
}
/**
* Accessor for the MetaData for the named field
* @param fieldName Name of the field
* @return MetaData for the field
*/
public AbstractMemberMetaData getFieldMetaData(String fieldName)
{
return cmd.getMetaDataForMember(fieldName);
}
/**
* Accessor for the identity type in use.
* @return The identity type
*/
public IdentityType getIdentityType()
{
return cmd.getIdentityType();
}
/**
* Accessor for whether this is a base datastore class (root in a hierarchy).
* Returns true since we dont use inheritance in views.
* @return Whether this is the base datastore class (table)
*/
public boolean isBaseDatastoreClass()
{
return true;
}
/**
* Accessor for whether the object ID is attributed in the datastore.
* Returns false since we dont use such things on views.
* @return Whether it is attributed in the datastore.
*/
public boolean isObjectIDDatastoreAttributed()
{
return false;
}
public void provideDatastoreIdMappings(MappingConsumer consumer)
{
}
public void provideDiscriminatorMappings(MappingConsumer consumer)
{
}
public void provideMappingsForFields(MappingConsumer consumer, AbstractMemberMetaData[] fieldNumbers, boolean includeSecondaryTables)
{
}
public void provideNonPrimaryKeyMappings(MappingConsumer consumer)
{
}
public void providePrimaryKeyMappings(MappingConsumer consumer)
{
}
public void provideVersionMappings(MappingConsumer consumer)
{
}
public void provideExternalMappings(MappingConsumer consumer, int mappingType)
{
}
/**
* Method to provide all unmapped datastore fields (columns) to the consumer.
* @param consumer Consumer of information
*/
public void provideUnmappedDatastoreFields(MappingConsumer consumer)
{
}
/**
* Accessor for the type of the class being represented by this view.
* @return The name of the class being represented here
*/
public String getType()
{
return cmd.getFullClassName();
}
/**
* Accessor for the mapping for the specified field/property.
* @param fmd Metadata for the field/property
* @return The Mapping for the field.
*/
public JavaTypeMapping getFieldMapping(AbstractMemberMetaData fmd)
{
assertIsInitialized();
JavaTypeMapping m = fieldMappings[fmd.getAbsoluteFieldNumber()];
if (m == null)
{
throw new NoSuchPersistentFieldException(cmd.getFullClassName(), fmd.getAbsoluteFieldNumber());
}
return m;
}
/**
* Accessor for the mapping for the specified field only in this datastore class.
* @param mmd Metadata of the field/property
* @return The Mapping for the field (or null if not present here)
*/
public JavaTypeMapping getFieldMappingInDatastoreClass(AbstractMemberMetaData mmd)
{
return getFieldMapping(mmd);
}
/**
* Accessor for the field mapping for the specified field name.
* @param fieldName Name of the field
* @return The Java type mapping for the field
*/
public JavaTypeMapping getFieldMapping(String fieldName)
{
assertIsInitialized();
int rfn = cmd.getRelativePositionOfMember(fieldName);
if (rfn < 0)
{
throw new NoSuchPersistentFieldException(cmd.getFullClassName(), fieldName);
}
return getFieldMapping(cmd.getMetaDataForManagedMemberAtPosition(rfn));
}
/**
* Method to return the necessary SQL create statements for this table.
* @param props Properties for controlling the creation of views
* @return The SQL create statements.
*/
protected List getSQLCreateStatements(Properties props)
{
assertIsInitialized();
ArrayList stmts = new ArrayList();
StringTokenizer tokens = new StringTokenizer(createStatementDDL, ";");
while (tokens.hasMoreTokens())
{
stmts.add(tokens.nextToken());
}
return stmts;
}
/**
* Accessor for Discriminator MetaData
* @return Returns the Discriminator MetaData.
*/
public final DiscriminatorMetaData getDiscriminatorMetaData()
{
return null; // No discriminators for Views
}
/**
* Accessor for the discriminator mapping specified .
* @return The mapping for the discriminator datastore field
**/
public JavaTypeMapping getDiscriminatorMapping(boolean allowSuperclasses)
{
return null; // No discriminators for Views
}
/**
* Accessor for Version MetaData
* @return Returns the Version MetaData.
*/
public final VersionMetaData getVersionMetaData()
{
return null; // No versions for Views
}
/**
* Accessor for the version mapping specified .
* @return The mapping for the version datastore field
**/
public JavaTypeMapping getVersionMapping(boolean allowSuperclasses)
{
return null; // No versions for Views
}
public JavaTypeMapping getExternalMapping(AbstractMemberMetaData fmd, int mappingType)
{
throw new JPOXException("N/A").setFatal();
}
public AbstractMemberMetaData getMetaDataForExternalMapping(JavaTypeMapping mapping, int mappingType)
{
throw new JPOXException("N/A").setFatal();
}
}