blob: b84ed1f862b5e560deed4f769b920e00a3117e28 [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.empire.db;
// Java
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Set;
import org.apache.empire.commons.Options;
import org.apache.empire.commons.StringUtils;
import org.apache.empire.data.Column;
import org.apache.empire.db.exceptions.DatabaseNotOpenException;
import org.apache.empire.db.expr.set.DBSetExpr;
import org.apache.empire.exceptions.InvalidArgumentException;
import org.apache.empire.exceptions.ItemNotFoundException;
import org.apache.empire.exceptions.ObjectNotValidException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
/**
* This is the base class for all database columns that have a physical representation.
* i.e. either table or view columns (DBTableColumn oder DBViewColumn)
* <p>
* The column object describes a database column and thus provides metadata.
* Other non data model specific metadata may be added through attributes.
*
* @see org.apache.empire.db.DBTableColumn
* @see org.apache.empire.db.DBView.DBViewColumn
*
*
*/
public abstract class DBColumn extends DBColumnExpr
implements Column
{
private final static long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(DBColumn.class);
/**
* Read only column (Boolean)
*/
// private static final String DBCOLATTR_READONLY = "readonly";
/**
* Read only column (Boolean)
*/
public static final String DBCOLATTR_SINGLEBYTECHARS = "singleByteChars";
// basic data
protected final transient DBRowSet rowset;
protected final String name;
protected String comment;
private Boolean quoteName = null;
/**
* Constructs a DBColumn object and set the specified parameters to this object.
*
* @param rowset the rowset (i.e. Table or View) that this column belongs to
* @param name the column name
*/
protected DBColumn(DBRowSet rowset, String name)
{
this.rowset = rowset;
this.name = name;
this.comment = null;
}
/**
* Gets an identifier for this RowSet Object
* @return the rowset identifier
*/
public String getId()
{
return rowset.getId()+"."+name;
}
/**
* returns a rowset by its identifier
* @param columnId the id of the column
* @return the DBColumn object
*/
public static DBColumn findById(String columnId)
{
int i = columnId.lastIndexOf('.');
if (i<0)
throw new InvalidArgumentException("columnId", columnId);
// rowset suchen
String rsid = columnId.substring(0, i);
DBRowSet rset = DBRowSet.findById(rsid);
// column suchen
String colname = columnId.substring(i+1);
DBColumn col = rset.getColumn(colname);
if (col==null)
throw new ItemNotFoundException(columnId);
return col;
}
/**
* Custom serialization for transient rowset.
*/
private void writeObject(ObjectOutputStream strm) throws IOException
{
if (rowset==null)
{ // No rowset
strm.writeObject("");
strm.defaultWriteObject();
return;
}
// write dbid and rowset-name
String dbid = rowset.getDatabase().getId();
String rsname = rowset.getName();
strm.writeObject(dbid);
strm.writeObject(rsname);
if (log.isDebugEnabled())
log.debug("Serialization: writing DBColumn "+dbid+"."+rsname);
strm.defaultWriteObject();
}
/**
* Custom serialization for transient rowset.
*/
private void readObject(ObjectInputStream strm) throws IOException, ClassNotFoundException,
SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException
{
String dbid = String.valueOf(strm.readObject());
if (StringUtils.isNotEmpty(dbid))
{ // Find Rowset
String rsname = String.valueOf(strm.readObject());
if (log.isDebugEnabled())
log.debug("Serialization: reading DBColumn "+dbid+"."+rsname);
// find database
DBDatabase db = DBDatabase.findById(dbid);
if (db==null)
throw new ClassNotFoundException(dbid);
// find database
DBRowSet srs = db.getRowSet(rsname);
if (srs==null)
throw new ClassNotFoundException(dbid+"."+rsname);
// set final field
Field f = DBColumn.class.getDeclaredField("rowset");
f.setAccessible(true);
f.set(this, srs);
f.setAccessible(false);
}
// read the rest
strm.defaultReadObject();
}
@Override
public boolean equals(Object other)
{
if (other==this)
return true;
if (rowset==null)
return super.equals(other);
if (other instanceof DBColumn)
{ // Rowset and name must match
DBColumn c = (DBColumn) other;
if (rowset.equals(c.getRowSet())==false)
return false;
// check for equal names
return StringUtils.compareEqual(name, c.getName(), true);
}
return false;
}
@Override
public int hashCode()
{
if (rowset==null || name==null)
return super.hashCode();
// rowset and name
return rowset.hashCode()+name.hashCode();
}
/**
* Returns the size of the column.
*
* @return Returns the size of the column
*/
@Override
public abstract double getSize();
/**
* Returns true if the column is required.
*
* @return Returns true if the column is required
*/
@Override
public abstract boolean isRequired();
/**
* Returns true if column is a columns value is an automatically generated value
*
* @return true if column is auto-generated
*/
@Override
public abstract boolean isAutoGenerated();
/**
* Returns true if the column is read-only.
*
* @return Returns true if the column is read-only
*/
@Override
public abstract boolean isReadOnly();
/**
* Checks if the given value is a valid value for this column
* If not, an exception is thrown
*/
@Override
public abstract Object validate(Object value);
/**
* @deprecated use validate() instead
*/
@Deprecated
public final void checkValue(Object value)
{
validate(value);
}
@Override
public abstract Element addXml(Element parent, long flags);
/**
* @return the current DBDatabase object
*/
@Override
public DBDatabase getDatabase()
{
return (rowset!=null ? rowset.getDatabase() : null);
}
/**
* @see org.apache.empire.db.DBExpr#addReferencedColumns(Set)
*/
@Override
public void addReferencedColumns(Set<DBColumn> list)
{
list.add(this);
}
/**
* Adds the colunm name to the SQL-Command. <br>
* This can be either a qualified or unqualified name depending on the context.
*
* @param buf the SQL statment
* @param context the current SQL-Command context
*/
@Override
public void addSQL(StringBuilder buf, long context)
{
// Append rowset alias
if ((context & CTX_FULLNAME) != 0)
{ // Fully Qualified Name
buf.append(rowset.getAlias());
buf.append(".");
}
// Append the name
DBDatabaseDriver driver = getDatabase().getDriver();
if (driver==null)
throw new DatabaseNotOpenException(getDatabase());
if (quoteName==null)
quoteName = driver.detectQuoteName(name);
// Append the name
driver.appendElementName(buf, name, quoteName.booleanValue());
}
/**
* Returns this object.
*
* @return this object
*/
@Override
public DBColumn getUpdateColumn()
{
return this;
}
/**
* Always returns false since DBColumns cannot be aggregates.
*
* @return false
*/
@Override
public boolean isAggregate()
{
return false;
}
/**
* Returns DBTable, DBQuery or DBView object.
*
* @return the DBTable, DBQuery or DBView object
*/
public DBRowSet getRowSet()
{
return rowset;
}
/**
* Returns the column name.
*
* @return the column name
*/
@Override
public String getName()
{
return name;
}
/**
* Returns the full qualified column name.
*
* @return the full qualified column name
*/
public String getFullName()
{
if (rowset==null)
throw new ObjectNotValidException(this);
return rowset.getFullName()+"."+name;
}
/**
* returns the qualified alias name for this column
*/
public String getAlias()
{
if (rowset==null)
throw new ObjectNotValidException(this);
String rsName = rowset.getName();
if (StringUtils.isEmpty(rsName))
return name;
return rsName + "_" + name;
}
/**
* returns an expression that renames the column with its alias name
*/
public DBColumnExpr qualified()
{
return this.as(getAlias());
}
/**
* @see DBColumnExpr#getAttribute(String)
*/
@Override
public Object getAttribute(String name)
{
return (attributes != null ? attributes.get(name) : null);
}
/**
* @see DBColumnExpr#getOptions()
*/
@Override
public Options getOptions()
{
return options;
}
/**
* Returns true if an enum type has been set for this column
* <P>
* @return eturns true if an enum type has been set for this column
*/
public final boolean isEnum()
{
return (getEnumType()!=null);
}
/**
* Returns the enum type for this column
* <P>
* @return the enum type
*/
@Override
@SuppressWarnings("unchecked")
public Class<Enum<?>> getEnumType()
{
return (attributes!=null ? (Class<Enum<?>>)getAttribute(COLATTR_ENUMTYPE) : null);
}
/**
* Creates and returns a sql-expression that maps enum values by name or ordinal to their string representation
*
* @return a DBDecodeExpr object
*/
public DBColumnExpr decodeEnum()
{
return super.decodeEnum(getEnumType(), null);
}
/**
* Creates and returns a sql-expression that maps enum values from name to ordinal
*
* @return a DBDecodeExpr object
*/
public DBColumnExpr decodeSort(boolean defaultToEnd)
{
if (getDataType().isNumeric())
{
log.warn("Unnecessary decode for numeric column");
return this;
}
return super.decodeSort(getEnumType(), defaultToEnd);
}
/**
* Creates and returns a new DBSetExpr object.
*
* @see org.apache.empire.db.expr.set.DBSetExpr
* @param value the Object value
* @return the new DBSetExpr object
*/
public DBSetExpr to(Object value)
{
return new DBSetExpr(this, value);
}
/**
* Override the toString method.
*
* @return the table name and the column name (e.g. CUSTOMER.ID)
*/
@Override
public String toString()
{
if (rowset==null)
return name;
return rowset.getName()+"."+name;
}
/**
* Returns a comment describing the column in the data scheme.
*
* @return Returns the comment.
*/
public String getComment()
{
return comment;
}
/**
* Sets a comment describing the current column.
*
* @param comment the column comment
*/
public void setComment(String comment)
{
this.comment = comment;
}
}