Home » apache-openjpa-1.1.0-source » org.apache.openjpa.jdbc » meta » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one
    3    * or more contributor license agreements.  See the NOTICE file
    4    * distributed with this work for additional information
    5    * regarding copyright ownership.  The ASF licenses this file
    6    * to you under the Apache License, Version 2.0 (the
    7    * "License"); you may not use this file except in compliance
    8    * with the License.  You may obtain a copy of the License at
    9    *
   10    * http://www.apache.org/licenses/LICENSE-2.0
   11    *
   12    * Unless required by applicable law or agreed to in writing,
   13    * software distributed under the License is distributed on an
   14    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   15    * KIND, either express or implied.  See the License for the
   16    * specific language governing permissions and limitations
   17    * under the License.    
   18    */
   19   package org.apache.openjpa.jdbc.meta;
   20   
   21   import java.sql.SQLException;
   22   import java.util.HashMap;
   23   import java.util.Map;
   24   
   25   import org.apache.openjpa.jdbc.schema.Column;
   26   import org.apache.openjpa.jdbc.schema.ColumnIO;
   27   import org.apache.openjpa.jdbc.schema.ForeignKey;
   28   import org.apache.openjpa.jdbc.schema.Index;
   29   import org.apache.openjpa.jdbc.schema.Schemas;
   30   import org.apache.openjpa.jdbc.schema.Table;
   31   import org.apache.openjpa.jdbc.schema.Unique;
   32   import org.apache.openjpa.jdbc.sql.Row;
   33   import org.apache.openjpa.jdbc.sql.Select;
   34   import org.apache.openjpa.kernel.OpenJPAStateManager;
   35   import org.apache.openjpa.lib.util.Localizer;
   36   import org.apache.openjpa.meta.JavaTypes;
   37   import org.apache.openjpa.meta.ValueMetaDataImpl;
   38   import org.apache.openjpa.util.InternalException;
   39   import org.apache.openjpa.util.MetaDataException;
   40   
   41   /**
   42    * Standalone {@link ValueMapping} implementation.
   43    *
   44    * @author Abe White
   45    * @since 0.4.0
   46    */
   47   public class ValueMappingImpl
   48       extends ValueMetaDataImpl
   49       implements ValueMapping {
   50   
   51       private static final Localizer _loc = Localizer.forPackage
   52           (ValueMappingImpl.class);
   53   
   54       private ValueMappingInfo _info;
   55       private ValueHandler _handler = null;
   56       private ClassMapping[] _typeArr = null;
   57   
   58       private Column[] _cols = Schemas.EMPTY_COLUMNS;
   59       private ColumnIO _io = null;
   60       private ForeignKey _fk = null;
   61       private Map _targetFKs = null;
   62       private Index _idx = null;
   63       private Unique _unq = null;
   64       private int _join = JOIN_FORWARD;
   65       private boolean _criteria = false;
   66       private int _poly = POLY_TRUE;
   67   
   68       /**
   69        * Constructor. Supply owning mapping.
   70        */
   71       public ValueMappingImpl(FieldMapping owner) {
   72           super(owner);
   73           _info = owner.getMappingRepository().newMappingInfo(this);
   74           _info.setUseClassCriteria(owner.getMappingRepository().
   75               getMappingDefaults().useClassCriteria());
   76       }
   77       
   78       /**
   79        * Constructor for deserialization.
   80        */
   81       protected ValueMappingImpl() {
   82           super();
   83       }
   84   
   85       public ValueMappingInfo getValueInfo() {
   86           return _info;
   87       }
   88   
   89       public ValueHandler getHandler() {
   90           return _handler;
   91       }
   92   
   93       public void setHandler(ValueHandler handler) {
   94           _handler = handler;
   95       }
   96   
   97       public MappingRepository getMappingRepository() {
   98           return (MappingRepository) getRepository();
   99       }
  100   
  101       public FieldMapping getFieldMapping() {
  102           return (FieldMapping) getFieldMetaData();
  103       }
  104   
  105       public ClassMapping getTypeMapping() {
  106           return (ClassMapping) getTypeMetaData();
  107       }
  108   
  109       public ClassMapping getDeclaredTypeMapping() {
  110           return (ClassMapping) getDeclaredTypeMetaData();
  111       }
  112   
  113       public ClassMapping getEmbeddedMapping() {
  114           return (ClassMapping) getEmbeddedMetaData();
  115       }
  116   
  117       public FieldMapping getValueMappedByMapping() {
  118           return (FieldMapping) getValueMappedByMetaData();
  119       }
  120   
  121       public Column[] getColumns() {
  122           if (_cols.length != 0)
  123               return _cols;
  124           if (_fk != null)
  125               return _fk.getColumns();
  126           if (getValueMappedBy() != null)
  127               return getValueMappedByMapping().getColumns();
  128           return _cols;
  129       }
  130   
  131       public void setColumns(Column[] cols) {
  132           if (cols == null)
  133               cols = Schemas.EMPTY_COLUMNS;
  134           _cols = cols;
  135       }
  136   
  137       public ColumnIO getColumnIO() {
  138           if (_cols.length == 0 && _fk == null && getValueMappedBy() != null)
  139               return getValueMappedByMapping().getColumnIO();
  140           return (_io == null) ? ColumnIO.UNRESTRICTED : _io;
  141       }
  142   
  143       public void setColumnIO(ColumnIO io) {
  144           _io = io;
  145       }
  146   
  147       public ForeignKey getForeignKey() {
  148           if (_fk == null && getValueMappedBy() != null)
  149               return getValueMappedByMapping().getForeignKey();
  150           return _fk;
  151       }
  152   
  153       public void setForeignKey(ForeignKey fk) {
  154           _fk = fk;
  155           if (fk == null)
  156               _join = JOIN_FORWARD;
  157       }
  158   
  159       public ForeignKey getForeignKey(ClassMapping target) {
  160           if (_fk == null && getValueMappedBy() != null)
  161               return getValueMappedByMapping().getForeignKey(target);
  162           if (target == null)
  163               return _fk;
  164           if (_fk == null && _cols.length == 0)
  165               return null;
  166   
  167           // always use least-derived joinable type
  168           for (ClassMapping sup = target; sup != null;
  169               sup = sup.getJoinablePCSuperclassMapping()) {
  170               if (sup == getTypeMetaData())
  171                   return _fk;
  172               target = sup;
  173           }
  174   
  175           synchronized (this) {
  176               if (_targetFKs != null) {
  177                   Object cachedFK = _targetFKs.get(target);
  178                   if (cachedFK != null)
  179                       return (ForeignKey) cachedFK;
  180               } else
  181                   _targetFKs = new HashMap();
  182   
  183               ForeignKey newfk = (_join == JOIN_FORWARD)
  184                   ? newForwardForeignKey(target) : newInverseForeignKey(target);
  185               _targetFKs.put(target, newfk);
  186               return newfk;
  187           }
  188       }
  189   
  190       /**
  191        * Create a forward foreign key to the given target.
  192        */
  193       private ForeignKey newForwardForeignKey(ClassMapping target) {
  194           Table table;
  195           Column[] cols;
  196           if (_fk == null) {
  197               table = _cols[0].getTable();
  198               cols = _cols;
  199           } else {
  200               table = _fk.getTable();
  201               cols = _fk.getColumns();
  202           }
  203   
  204           // gather target cols before adding foreign key to table in case
  205           // there is an error while looking for a target col
  206           Column[] tcols = new Column[cols.length];
  207           for (int i = 0; i < cols.length; i++) {
  208               if (cols[i].getTargetField() != null)
  209                   tcols[i] = getEquivalentColumn(cols[i], target,
  210                       cols[i].getTargetField());
  211               else if (_fk != null)
  212                   tcols[i] = getEquivalentColumn(_fk.getPrimaryKeyColumn
  213                       (cols[i]).getName(), target, true);
  214               else if (cols[i].getTarget() != null)
  215                   tcols[i] = getEquivalentColumn(cols[i].getTarget(), target,
  216                       true);
  217               else
  218                   tcols[i] = getEquivalentColumn(cols[i].getName(), target,
  219                       false);
  220           }
  221   
  222           ForeignKey newfk = table.addForeignKey();
  223           newfk.setJoins(cols, tcols);
  224           if (_fk != null) {
  225               cols = _fk.getConstantColumns();
  226               for (int i = 0; i < cols.length; i++)
  227                   newfk.joinConstant(cols[i], _fk.getConstant(cols[i]));
  228   
  229               cols = _fk.getConstantPrimaryKeyColumns();
  230               for (int i = 0; i < cols.length; i++)
  231                   newfk.joinConstant(_fk.getPrimaryKeyConstant(cols[i]),
  232                       getEquivalentColumn(cols[i].getName(), target, true));
  233           }
  234           return newfk;
  235       }
  236   
  237       /**
  238        * Return the given mapping's equivalent to the given column, using the
  239        * target field.
  240        */
  241       private Column getEquivalentColumn(Column col, ClassMapping target,
  242           String fieldName) {
  243           fieldName = fieldName.substring(fieldName.indexOf('.') + 1);
  244           FieldMapping field = target.getFieldMapping(fieldName);
  245           if (field == null)
  246               throw new MetaDataException(_loc.get("no-equiv-field",
  247                   new Object[]{ this, target, fieldName, col }));
  248   
  249           Column[] cols = field.getColumns();
  250           if (cols.length != 1)
  251               throw new MetaDataException(_loc.get("bad-equiv-field",
  252                   new Object[]{ this, target, fieldName, col }));
  253   
  254           return cols[0];
  255       }
  256   
  257       /**
  258        * Return the given mapping's equivalent of the given column.
  259        */
  260       private Column getEquivalentColumn(String colName, ClassMapping target,
  261           boolean explicit) {
  262           // if there was no explicit target, use single pk column
  263           if (!explicit) {
  264               for (ClassMapping cls = target; cls != null;
  265                   cls = cls.getJoinablePCSuperclassMapping()) {
  266                   if (cls.getTable() != null) {
  267                       if (cls.getPrimaryKeyColumns().length == 1)
  268                           return cls.getPrimaryKeyColumns()[0];
  269                       break;
  270                   }
  271               }
  272           }
  273   
  274           Column ret;
  275           for (ClassMapping cls = target; cls != null;
  276               cls = cls.getJoinablePCSuperclassMapping()) {
  277               if (cls.getTable() != null) {
  278                   ret = cls.getTable().getColumn(colName);
  279                   if (ret != null)
  280                       return ret;
  281               }
  282           }
  283   
  284           throw new MetaDataException(_loc.get("no-equiv-col", this, target,
  285               colName));
  286       }
  287   
  288       /**
  289        * Return an inverse foreign key from the given related type to our table.
  290        */
  291       private ForeignKey newInverseForeignKey(ClassMapping target) {
  292           FieldMapping field = getFieldMapping();
  293           FieldMapping mapped = field.getMappedByMapping();
  294           if (mapped == null)
  295               throw new MetaDataException(_loc.get("cant-inverse", this));
  296   
  297           mapped = target.getFieldMapping(mapped.getIndex());
  298           if (mapped == null || mapped.getTypeCode() != JavaTypes.PC)
  299               throw new MetaDataException(_loc.get("no-equiv-mapped-by",
  300                   this, target, field.getMappedBy()));
  301           return mapped.getForeignKey();
  302       }
  303   
  304       public int getJoinDirection() {
  305           if (_fk == null && getValueMappedBy() != null)
  306               return getValueMappedByMapping().getJoinDirection();
  307           return _join;
  308       }
  309   
  310       public void setJoinDirection(int direction) {
  311           _join = direction;
  312       }
  313   
  314       public void setForeignKey(Row row, OpenJPAStateManager rel)
  315           throws SQLException {
  316           if (rel != null)
  317               row.setForeignKey(getForeignKey((ClassMapping) rel.getMetaData()),
  318                   _io, rel);
  319           else if (_fk != null)
  320               row.setForeignKey(_fk, _io, null);
  321           else {
  322               for (int i = 0; i < _cols.length; i++) {
  323                   if (_io == null || (row.getAction() == Row.ACTION_INSERT
  324                       && _io.isInsertable(i, true))
  325                       || (row.getAction() != Row.ACTION_INSERT
  326                       && _io.isUpdatable(i, true)))
  327                       row.setNull(_cols[i]);
  328               }
  329           }
  330       }
  331   
  332       public void whereForeignKey(Row row, OpenJPAStateManager rel)
  333           throws SQLException {
  334           if (rel != null)
  335               row.whereForeignKey(getForeignKey((ClassMapping)
  336                   rel.getMetaData()), rel);
  337           else if (_fk != null)
  338               row.whereForeignKey(_fk, null);
  339           else
  340               for (int i = 0; i < _cols.length; i++)
  341                   row.whereNull(_cols[i]);
  342       }
  343   
  344       public ClassMapping[] getIndependentTypeMappings() {
  345           ClassMapping rel = getTypeMapping();
  346           if (rel == null)
  347               return ClassMapping.EMPTY_MAPPINGS;
  348           if (_poly != POLY_TRUE) {
  349               if (!rel.isMapped())
  350                   return ClassMapping.EMPTY_MAPPINGS;
  351               if (_typeArr == null)
  352                   _typeArr = new ClassMapping[]{ rel };
  353               return _typeArr;
  354           }
  355           return rel.getIndependentAssignableMappings();
  356       }
  357   
  358       public int getSelectSubclasses() {
  359           ClassMapping rel = getTypeMapping();
  360           if (rel == null || !rel.isMapped())
  361               return -1;
  362   
  363           switch (_poly) {
  364               case POLY_FALSE:
  365                   return (_criteria) ? Select.SUBS_NONE : Select.SUBS_EXACT;
  366               case POLY_TRUE:
  367                   ClassMapping[] assign = rel.getIndependentAssignableMappings();
  368                   if (assign.length != 1 || assign[0] != rel)
  369                       return -1;
  370                   // no break
  371               case POLY_JOINABLE:
  372                   return (_criteria) ? Select.SUBS_JOINABLE
  373                       : Select.SUBS_ANY_JOINABLE;
  374               default:
  375                   throw new InternalException();
  376           }
  377       }
  378   
  379       public Unique getValueUnique() {
  380           return _unq;
  381       }
  382   
  383       public void setValueUnique(Unique unq) {
  384           _unq = unq;
  385       }
  386   
  387       public Index getValueIndex() {
  388           return _idx;
  389       }
  390   
  391       public void setValueIndex(Index idx) {
  392           _idx = idx;
  393       }
  394   
  395       public boolean getUseClassCriteria() {
  396           if (_fk == null && getValueMappedBy() != null)
  397               return getValueMappedByMapping().getUseClassCriteria();
  398           return _criteria;
  399       }
  400   
  401       public void setUseClassCriteria(boolean criteria) {
  402           _criteria = criteria;
  403       }
  404   
  405       public int getPolymorphic() {
  406           return _poly;
  407       }
  408   
  409       public void setPolymorphic(int poly) {
  410           _poly = poly;
  411       }
  412   
  413       public void refSchemaComponents() {
  414           for (int i = 0; i < _cols.length; i++)
  415               _cols[i].ref();
  416           if (_fk != null) {
  417               _fk.ref();
  418               _fk.refColumns();
  419           }
  420   
  421           ClassMapping embed = getEmbeddedMapping();
  422           if (embed != null)
  423               embed.refSchemaComponents();
  424       }
  425   
  426       public void mapConstraints(String name, boolean adapt) {
  427           _unq = _info.getUnique(this, name, adapt);
  428           _idx = _info.getIndex(this, name, adapt);
  429       }
  430   
  431       public void clearMapping() {
  432           _handler = null;
  433           _cols = Schemas.EMPTY_COLUMNS;
  434           _unq = null;
  435           _idx = null;
  436           _fk = null;
  437           _join = JOIN_FORWARD;
  438           _info.clear();
  439           setResolve(MODE_MAPPING | MODE_MAPPING_INIT, false);
  440       }
  441   
  442       public void syncMappingInfo() {
  443           if (getValueMappedBy() != null)
  444               _info.clear();
  445           else {
  446               _info.syncWith(this);
  447               ClassMapping embed = getEmbeddedMapping();
  448               if (embed != null)
  449                   embed.syncMappingInfo();
  450           }
  451       }
  452   
  453       public void copyMappingInfo(ValueMapping vm) {
  454           setValueMappedBy(vm.getValueMappedBy());
  455           setPolymorphic(vm.getPolymorphic());
  456           _info.copy(vm.getValueInfo());
  457   
  458           ClassMapping embed = vm.getEmbeddedMapping();
  459           if (embed != null && getEmbeddedMapping() != null) {
  460               FieldMapping[] tmplates = embed.getFieldMappings();
  461               FieldMapping[] fms = getEmbeddedMapping().getFieldMappings();
  462               if (tmplates.length == fms.length)
  463                   for (int i = 0; i < fms.length; i++)
  464                       fms[i].copyMappingInfo(tmplates[i]);
  465           }
  466       }
  467   
  468       public boolean resolve(int mode) {
  469           int cur = getResolve();
  470           if (super.resolve(mode))
  471               return true;
  472           ClassMapping embed = getEmbeddedMapping();
  473           if (embed != null)
  474               embed.resolve(mode);
  475           if ((mode & MODE_MAPPING) != 0 && (cur & MODE_MAPPING) == 0)
  476               resolveMapping();
  477           if ((mode & MODE_MAPPING_INIT) != 0 && (cur & MODE_MAPPING_INIT) == 0)
  478               initializeMapping();
  479           return false;
  480       }
  481   
  482       /**
  483        * Setup mapping. Our handler will already have been set by our owning
  484        * field.
  485        */
  486       private void resolveMapping() {
  487           // mark mapped columns
  488           Column[] cols;
  489           int insertFlag;
  490           if (_fk != null) {
  491               cols = _fk.getColumns();
  492               insertFlag = Column.FLAG_FK_INSERT;
  493           } else {
  494               cols = getColumns();
  495               insertFlag = Column.FLAG_DIRECT_INSERT;
  496           }
  497           ColumnIO io = getColumnIO();
  498           for (int i = 0; i < cols.length; i++) {
  499               if (io.isInsertable(i, false))
  500                   cols[i].setFlag(insertFlag, true);
  501               if (io.isUpdatable(i, false))
  502                   cols[i].setFlag(insertFlag, true);
  503           }
  504       }
  505   
  506       /**
  507        * Prepare mapping for runtime use.
  508        */
  509       private void initializeMapping() {
  510           if (_fk == null)
  511               return;
  512   
  513           // if our fk cols are direct mapped by other values, make them
  514           // non-nullable
  515           Column[] cols = _fk.getColumns();
  516           for (int i = 0; i < cols.length; i++) {
  517               if (cols[i].getFlag(Column.FLAG_DIRECT_INSERT))
  518                   newIO().setNullInsertable(i, false);
  519               if (cols[i].getFlag(Column.FLAG_DIRECT_UPDATE))
  520                   newIO().setNullUpdatable(i, false);
  521           }
  522   
  523           // if anything maps our constant fk cols, make them read only
  524           int len = cols.length;
  525           cols = _fk.getConstantColumns();
  526           for (int i = 0; i < cols.length; i++) {
  527               if (cols[i].getFlag(Column.FLAG_DIRECT_INSERT)
  528                   || cols[i].getFlag(Column.FLAG_FK_INSERT))
  529                   newIO().setInsertable(len + i, false);
  530               if (cols[i].getFlag(Column.FLAG_DIRECT_UPDATE)
  531                   || cols[i].getFlag(Column.FLAG_FK_UPDATE))
  532                   newIO().setUpdatable(len + i, false);
  533           }
  534       }
  535   
  536       /**
  537        * Return the column I/O information, creating it if necessary.
  538        */
  539       private ColumnIO newIO() {
  540           if (_io == null)
  541               _io = new ColumnIO();
  542           return _io;
  543       }
  544   }

Save This Page
Home » apache-openjpa-1.1.0-source » org.apache.openjpa.jdbc » meta » [javadoc | source]