/* * #! * Ontopia Engine * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * 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. * !# */ package net.ontopia.persistence.proxy; import java.util.HashMap; import java.util.Map; import net.ontopia.utils.OntopiaRuntimeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * INTERNAL: A class descriptor-like class that is used by the RDBMS * proxy implementation to access the information it needs about the * object relational class descriptor in an optimized manner.<p> */ public class ClassInfo implements ClassInfoIF { // Define a logging category. static Logger log = LoggerFactory.getLogger(ClassInfo.class.getName()); protected RDBMSMapping mapping; protected ClassDescriptor cdesc; protected Class<?> klass; protected Class<?> klass_immutable; protected Map<String, FieldInfoIF> fields; protected FieldInfoIF identity_field; protected FieldInfoIF[] value_fields; protected FieldInfoIF[] o2o_fields; protected FieldInfoIF[] o2m_fields; protected FieldInfoIF[] m2m_fields; //! // FIXME: should extend these to support other tables //! protected String[] inline_columns; //! protected FieldInfoIF[] inline_fields; public ClassInfo(RDBMSMapping mapping, ClassDescriptor cdesc) { this.mapping = mapping; this.cdesc = cdesc; this.klass = cdesc.getDescriptorClass(); this.klass_immutable = cdesc.getImmutableDescriptorClass(); fields = new HashMap<String, FieldInfoIF>(); } /** * INTERNAL: Compile the information in the class descriptor to an * optimized form. Called from RDBSMapping, because calling it in * the constructor leads to never-ending recursion. */ void compile() { // compute identity fields identity_field = new IdentityFieldInfo(this, compileFieldInfos(this, cdesc.getIdentityFields())); // compute values fields value_fields = compileFieldInfos(this, cdesc.getValueFields()); // compute 1:1 value fields o2o_fields = FieldUtils.filterByCardinality(value_fields, FieldInfoIF.ONE_TO_ONE); // compute 1:M value fields o2m_fields = FieldUtils.filterByCardinality(value_fields, FieldInfoIF.ONE_TO_MANY); // compute M:M value fields m2m_fields = FieldUtils.filterByCardinality(value_fields, FieldInfoIF.MANY_TO_MANY); // compute lookup map FieldInfoIF finfo; for (int i=0; i < o2o_fields.length; i++) { finfo = o2o_fields[i]; fields.put(finfo.getName(), finfo); } for (int i=0; i < o2m_fields.length; i++) { finfo = o2m_fields[i]; fields.put(finfo.getName(), finfo); } for (int i=0; i < m2m_fields.length; i++) { finfo = m2m_fields[i]; fields.put(finfo.getName(), finfo); } } /** * INTERNAL: Returns the RDBMS specific object relational mapping * instance. */ public ObjectRelationalMappingIF getMapping() { return mapping; } public String getName() { return klass.getName(); } /** * INTERNAL: Return the descriptor class described by the * descriptor. */ public Class<?> getDescriptorClass() { return klass; } public Object createInstance(boolean immutable) throws Exception { if (immutable) return klass_immutable.newInstance(); else return klass.newInstance(); } /** * INTERNAL: Get the field info by name. */ public FieldInfoIF getFieldInfoByName(String name) { // System.out.println("WARN: should deprecate getFieldInfoByName or rename to getValueFieldInfoByName."); return fields.get(name); } /** * INTERNAL: Get the identity field infos. */ public FieldInfoIF getIdentityFieldInfo() { return identity_field; } /** * INTERNAL: Get the value field infos. */ public FieldInfoIF[] getValueFieldInfos() { return value_fields; } /** * INTERNAL: Get the 1:1 field infos. */ public FieldInfoIF[] getOne2OneFieldInfos() { return o2o_fields; } /** * INTERNAL: Get the 1:M field infos. */ public FieldInfoIF[] getOne2ManyFieldInfos() { return o2m_fields; } /** * INTERNAL: Get the M:M field infos. */ public FieldInfoIF[] getMany2ManyFieldInfos() { return m2m_fields; } public boolean isAbstract() { return cdesc.isAbstract(); } public boolean isIdentifiable() { return (cdesc.getType() == ClassInfoIF.TYPE_IDENTIFIABLE); } public boolean isAggregate() { return (cdesc.getType() == ClassInfoIF.TYPE_AGGREGATE); } public int getStructure() { return cdesc.getStructure(); } public String getMasterTable() { return cdesc.getMasterTable(); } //! /** //! * INTERNAL: Returns the fields stored in the specified table. //! */ //! public FieldInfoIF[] getFieldsInTable(String table) { //! return inline_fields; //! // return (FieldInfoIF[])fields_in_table.get(table); //! } //! //! /** //! * INTERNAL: Returns the columns stored in the specified table. //! */ //! public String[] getColumnsInTable(String table) { //! return inline_columns; //! // return (String[])columns_in_table.get(table); //! } /** * INTERNAL: Wraps the field descriptors in the appropriate field * info implementations. */ protected static FieldInfoIF[] compileFieldInfos(ClassInfoIF cinfo, FieldDescriptor[] fdescs) { FieldInfoIF[] finfos = new FieldInfoIF[fdescs.length]; // Loop over field descriptors and collect field info instances for (int i=0; i < fdescs.length; i++) { // log.info("Compiling field info: " + fdescs[i].getName()); finfos[i] = getFieldInfo(cinfo, fdescs[i], i); } return finfos; } /** * INTERNAL: Wraps the field descriptor in the appropriate field * info implementation. */ protected static FieldInfoIF getFieldInfo(ClassInfoIF cinfo, FieldDescriptor fdesc, int index) { // Loop over all subfield descriptors of the aggregate descriptor // log.debug("VC: " + fdesc.getName() + fdesc.isAggregateField()); if (fdesc.isPrimitiveField()) { return new PrimitiveFieldInfo(cinfo, fdesc, index); } else if (fdesc.isReferenceField()) { return new ReferenceFieldInfo(cinfo, fdesc, index); } else if (fdesc.isAggregateField()) { return new AggregateFieldInfo(cinfo, fdesc, index); } else throw new OntopiaRuntimeException("Unknown field type: " + fdesc); } public String toString() { return "<ClassInfo " + cdesc.getName() + ">"; } }