/* * #! * 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.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import net.ontopia.utils.OntopiaRuntimeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * INTERNAL: Class used for holding object relational mapping class * declarations. It is used by the ObjectRelationalMapping class.<p> * * A class descriptor contains information about object classes * defined in object relational mappings. Class descriptors consists * of a set of field descriptors.<p> */ public class ClassDescriptor { // Define a logging category. static Logger log = LoggerFactory.getLogger(ClassDescriptor.class.getName()); protected ObjectRelationalMapping mapping; protected Class<?> klass; protected Class<?> klass_immutable; protected String[] identity_fields = new String[0]; protected boolean isabstract; protected int type; protected int structure; protected String master_table; protected Class<?>[] extends_classes = new Class<?>[0]; protected Class<?>[] interfaces = new Class<?>[0]; protected List<FieldDescriptor> fdescs_list; protected Map<String, FieldDescriptor> fdescs; public ClassDescriptor(Class<?> klass, Class<?> klass_immutable, ObjectRelationalMapping mapping) { this.klass = klass; this.klass_immutable = klass_immutable; this.mapping = mapping; fdescs_list = new ArrayList<FieldDescriptor>(); fdescs = new HashMap<String, FieldDescriptor>(); } /** * INTERNAL: Gets the object relational mapping that the class * descriptor belongs to. */ public ObjectRelationalMapping getMapping() { return mapping; } /** * INTERNAL: Returns the name of the descriptor class (the mapped class). */ public String getName() { return klass.getName(); } /** * INTERNAL: Returns the descriptor class. */ public Class<?> getDescriptorClass() { return klass; } /** * INTERNAL: Returns the immutable descriptor class. */ public Class<?> getImmutableDescriptorClass() { return klass_immutable; } /** * INTERNAL: Returns an array containing the fields that are * identity fields.<p> * * An identity field is the field that together represents the * identity, or primary key, of instances of the class.<p> */ public FieldDescriptor[] getIdentityFields() { FieldDescriptor[] result = new FieldDescriptor[identity_fields.length]; for (int i=0; i < identity_fields.length; i++) { result[i] = getFieldByName(identity_fields[i]); if (result[i] == null) throw new OntopiaRuntimeException("Unknown identity field: " + identity_fields[i]); } return result; } /** * INTERNAL: Returns an array containing the fields that are value * fields, i.e. not identity fields. */ public FieldDescriptor[] getValueFields() { List<FieldDescriptor> id_fields = Arrays.asList(getIdentityFields()); Collection<FieldDescriptor> result = new ArrayList<FieldDescriptor>(); for (FieldDescriptor fdesc : getFieldDescriptors()) { if (!id_fields.contains(fdesc)) result.add(fdesc); } return FieldUtils.toFieldDescriptorArray(result); } /** * INTERNAL: Returns an array containing the fields that are of * primitive types. */ public FieldDescriptor[] getPrimitiveFields() { Collection<FieldDescriptor> result = new ArrayList<FieldDescriptor>(); for (FieldDescriptor fdesc : getFieldDescriptors()) { if (fdesc.isPrimitiveField()) result.add(fdesc); } return FieldUtils.toFieldDescriptorArray(result); } /** * INTERNAL: Returns an array containing the fields that references * other mapped objects. */ public FieldDescriptor[] getReferenceFields() { Collection<FieldDescriptor> result = new ArrayList<FieldDescriptor>(); for (FieldDescriptor fdesc : getFieldDescriptors()) { if (fdesc.isReferenceField()) result.add(fdesc); } return FieldUtils.toFieldDescriptorArray(result); } /** * INTERNAL: Returns an array containing the fields that are * aggregate objects. Aggregate objects are composite objects that * don't have explicit identity. */ public FieldDescriptor[] getAggregateFields() { if (isAggregate()) return getFieldDescriptors(); Collection<FieldDescriptor> result = new ArrayList<FieldDescriptor>(); for (FieldDescriptor fdesc : getFieldDescriptors()) { if (fdesc.isAggregateField()) result.add(fdesc); } return FieldUtils.toFieldDescriptorArray(result); } /** * INTERNAL: Returns the field names of the identity fields. */ String[] getIdentityFieldNames() { return identity_fields; } /** * INTERNAL: Sets the field names of the identity fields. */ void setIdentityFieldNames(String[] identity_fields) { this.identity_fields = identity_fields; } /** * INTERNAL: Returns the class type. */ public int getType() { return type; } /** * INTERNAL: Sets the class type. This is can either be * ClassInfoIF.TYPE_IDENTIFIABLE or ClassInfoIF.TYPE_AGGREGATE. */ public void setType(int type) { // TODO: PRIMITIVE not yet supported. if (type != ClassInfoIF.TYPE_IDENTIFIABLE && type != ClassInfoIF.TYPE_AGGREGATE) throw new IllegalArgumentException("Invalid argument: " + type); this.type = type; } public boolean isAggregate() { return (type == ClassInfoIF.TYPE_AGGREGATE); } /** * INTERNAL: Returns the class structure. */ public int getStructure() { return structure; } /** * INTERNAL: Sets the class structure. This is can either be * ClassInfoIF.STRUCTURE_OBJECT or ClassInfoIF.STRUCTURE_COLLECTION. */ public void setStructure(int structure) { // TODO: MAP not yet supported. if (structure != ClassInfoIF.STRUCTURE_OBJECT && structure != ClassInfoIF.STRUCTURE_COLLECTION) throw new IllegalArgumentException("Invalid argument: " + structure); this.structure = structure; } /** * INTERNAL: Sets the abstract flag. The default is that the * descriptor class is non-abstract (i.e. concrete). */ public void setAbstract(boolean isabstract) { this.isabstract = isabstract; } /** * INTERNAL: Returns true if the descriptor class is mapped as an * abstract class. */ public boolean isAbstract() { return isabstract; } /** * INTERNAL: Returns the name of the master table in which the class * is stored. */ public String getMasterTable() { return master_table; } /** * INTERNAL: Sets the name of the master table in which the class is * stored. */ public void setMasterTable(String master_table) { this.master_table = master_table; } /** * INTERNAL: Returns the descriptor classes that this descriptor * class extends. (Not implemented) */ public Class[] getExtends() { return extends_classes; } /** * INTERNAL: Sets the descriptor classes that this descriptor class * extends. (Not implemented) */ public void setExtends(Class[] extends_classes) { this.extends_classes = extends_classes; } protected Map<String, FieldDescriptor> getFieldDescriptorMap() { Map<String, FieldDescriptor> all_fields = new HashMap<String, FieldDescriptor>(); populateExtendsMap(all_fields); return all_fields; } protected void populateExtendsMap(Map<String, FieldDescriptor> _fdescs) { for (Class<?> extends_classe : extends_classes) { getMapping().getDescriptorByClass(extends_classe).populateExtendsMap(_fdescs); } // Add my own _fdescs.putAll(this.fdescs); } /** * INTERNAL: Gets the interfaces that this descriptor class * implement. */ public Class[] getInterfaces() { return interfaces; } /** * INTERNAL: Sets the interfaces that this descriptor class * implement. */ public void setInterfaces(Class[] interfaces) { this.interfaces = interfaces; } /** * INTERNAL: Returns all the field descriptors of this class * descriptor. */ public FieldDescriptor[] getFieldDescriptors() { // Return local field definitions return FieldUtils.toFieldDescriptorArray(fdescs_list); // FIXME: add real support for inheritance // Note: the ordering of fields is important // Class[] _extends = getExtends(); // if (_extends != null && _extends.length > 0) { // // Populate field definitions from parents // return FieldUtils.toFieldDescriptorArray(getFieldDescriptorMap().values()); // } // else { // // Return local field definitions // return FieldUtils.toFieldDescriptorArray(fdescs.values()); // } } /** * INTERNAL: Gets all the field names of this class descriptor. */ public String[] getFieldNames() { return FieldUtils.toStringArray(getFieldDescriptorMap().keySet()); } /** * INTERNAL: Gets the field descriptor representing the field with * the given name. */ public FieldDescriptor getFieldByName(String field_name) { return getFieldDescriptorMap().get(field_name); } /** * INTERNAL: Adds the field descriptor to the class descriptor. */ public void addField(FieldDescriptor fdesc) { // Put on ordered list fdescs_list.add(fdesc); // Add to lookup map fdescs.put(fdesc.getName(), fdesc); } // /** // * INTERNAL: Utility method that returns the field descriptors // * representing the fields in the input array. // */ // public FieldDescriptor[] getFieldDescriptors(String[] fields) { // FieldDescriptor[] fdescs = new FieldDescriptor[fields.length]; // for (int i=0; i < fields.length; i++) { // FieldDescriptor fdesc = getFieldByName(fields[i]); // if (fdesc == null) // throw new OntopiaRuntimeException("No field descriptor with the name " + fields[i]); // fdescs[i] = fdesc; // } // return fdescs; // } @Override public String toString() { return "<ClassDescriptor " + getName() + ">"; } }