org.datanucleus.store.rdbms.table.ClassView Maven / Gradle / Ivy
/**********************************************************************
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.datanucleus.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.datanucleus.ClassLoaderResolver;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.ClassMetaData;
import org.datanucleus.metadata.DiscriminatorMetaData;
import org.datanucleus.metadata.FieldPersistenceModifier;
import org.datanucleus.metadata.FieldRole;
import org.datanucleus.metadata.IdentityType;
import org.datanucleus.metadata.VersionMetaData;
import org.datanucleus.store.rdbms.exceptions.NoSuchPersistentFieldException;
import org.datanucleus.store.rdbms.RDBMSStoreManager;
import org.datanucleus.store.rdbms.exceptions.PersistentSuperclassNotAllowedException;
import org.datanucleus.store.rdbms.exceptions.ViewDefinitionException;
import org.datanucleus.store.rdbms.identifier.DatastoreIdentifier;
import org.datanucleus.store.rdbms.mapping.MappingConsumer;
import org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping;
import org.datanucleus.util.MacroString;
import org.datanucleus.util.NucleusLogger;
/**
* 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.
*/
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 RDBMSStoreManager storeMgr, final ClassMetaData cmd)
{
super(tableName, storeMgr);
this.cmd = cmd;
if (cmd.getIdentityType() == IdentityType.APPLICATION || cmd.getIdentityType() == IdentityType.DATASTORE)
{
throw new NucleusUserException(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(), null);
}
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.getMetaDataForManagedMemberAtRelativePosition(fieldNumber);
if (fmd.getPersistenceModifier() == FieldPersistenceModifier.PERSISTENT)
{
fieldMappings[fieldNumber] = storeMgr.getMappingManager().getMapping(this, fmd, clr, FieldRole.ROLE_FIELD);
}
else if (fmd.getPersistenceModifier() != FieldPersistenceModifier.TRANSACTIONAL)
{
throw new NucleusException(LOCALISER.msg("031006",
cmd.getFullClassName(), fmd.getName(), fmd.getPersistenceModifier())).setFatal();
}
}
if (NucleusLogger.DATASTORE_SCHEMA.isDebugEnabled())
{
NucleusLogger.DATASTORE_SCHEMA.debug(LOCALISER.msg("057023", this));
}
storeMgr.registerTableInitialized(this);
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 NucleusUserException(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