GenClassImpl.java

00001 /*
00002  * JOnAS: Java(TM) Open Application Server
00003  * Copyright (C) 1999 Bull S.A.
00004  * Contact: jonas-team@objectweb.org
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
00019  * USA
00020  *
00021  * Initial developer(s): Sebastien Chassande
00022  * Contributor(s):
00023  *
00024  * --------------------------------------------------------------------------
00025  * $Id: GenClassImpl.java,v 1.23 2004/09/06 14:42:24 joaninh Exp $
00026  * --------------------------------------------------------------------------
00027  */
00028 package org.objectweb.jonas_ejb.container.jorm;
00029 
00030 import java.util.ArrayList;
00031 import java.util.Arrays;
00032 import java.util.Iterator;
00033 import java.util.NoSuchElementException;
00034 import javax.ejb.EJBException;
00035 import org.objectweb.jonas_ejb.container.JEntityFactory;
00036 import org.objectweb.jonas_ejb.container.TraceEjb;
00037 import org.objectweb.jorm.api.PBinding;
00038 import org.objectweb.jorm.api.PClassMapping;
00039 import org.objectweb.jorm.api.PException;
00040 import org.objectweb.jorm.api.PExceptionProtocol;
00041 import org.objectweb.jorm.api.PGenClassAccessor;
00042 import org.objectweb.jorm.api.PIndexedElem;
00043 import org.objectweb.jorm.naming.api.PBinder;
00044 import org.objectweb.jorm.naming.api.PName;
00045 import org.objectweb.jorm.naming.api.PNameManager;
00046 import org.objectweb.jorm.naming.api.PExceptionNaming;
00047 import org.objectweb.util.monolog.api.BasicLevel;
00048 
00049 
00056 public abstract class GenClassImpl implements PGenClassAccessor {
00057 
00062     protected ArrayList pIndexedElems = null;
00063 
00078     protected int[] deletedLength = null;
00079 
00085     protected int size;
00086 
00090     protected boolean isModified = false;
00091 
00097     protected PClassMapping gcm = null;
00098 
00102     protected PBinding pb = null;
00103 
00110     protected GenClassListener listener = null;
00111 
00115     public GenClassImpl(PClassMapping gcm) {
00116         this();
00117         this.gcm = gcm;
00118     }
00119 
00125     public GenClassImpl() {
00126         pIndexedElems = new ArrayList(0);
00127         size = 0;
00128         deletedLength = new int[0];
00129         isModified = false;
00130     }
00131 
00138     public void setPClassMapping(PClassMapping gcm) {
00139         this.gcm = gcm;
00140     }
00141 
00145     public void reset() {
00146         pIndexedElems.clear();
00147         size = 0;
00148         deletedLength = new int[0];
00149         isModified = false;
00150     }
00151 
00157     public void setPBinding(PBinding pb) {
00158         this.pb = pb;
00159     }
00160 
00166     public PBinding gcGetPBinding() {
00167         return pb;
00168     }
00169 
00170     public void setListener(GenClassListener gcl) {
00171         listener = gcl;
00172     }
00173 
00174     public GenClassListener getListener() {
00175         return listener;
00176     }
00177 
00178     // IMPLEMENTATION OF THE Persitence lyfe cycle //
00179     //---------------------------------------------//
00180 
00181     public boolean gcIsModified() {
00182         return isModified;
00183     }
00184 
00191     public void read(PName pn, Object connection) throws PException {
00192         TraceEjb.genclass.log(BasicLevel.DEBUG, "PName=" + pn);
00193         if (pn == null || pn.isNull()) {
00194             reset();
00195             return;
00196         }
00197         if (pb == null) {
00198             throw new PExceptionProtocol("Impossible to read a persitent object withoout PBinding");
00199         }
00200         // Allocate a connection if needed
00201         Object conn = (connection == null
00202                        ? gcm.getPMapper().getConnection()
00203                        : connection);
00204         TraceEjb.genclass.log(BasicLevel.DEBUG, "Load the genclass");
00205         pb.bind(pn);
00206         pb.read(conn, this);
00207         pb.unbind();
00208         isModified = false;
00209 
00210         // close the connection opened localy
00211         if (connection == null) {
00212             gcm.getPMapper().closeConnection(conn);
00213         }
00214     }
00215 
00223     public void write(PName pn, Object connection) throws PException {
00224         TraceEjb.genclass.log(BasicLevel.DEBUG, "");
00225         //TraceEjb.genclass.log(BasicLevel.DEBUG, "begin"); printState();
00226         if (pn == null || pn.isNull()) {
00227             throw new PExceptionProtocol("Impossible to write a persitent object with a null PName: " + pn);
00228         }
00229         if (isModified) {
00230             // Allocate a connection if needed
00231             Object conn = (connection == null
00232                            ? gcm.getPMapper().getConnection()
00233                            : connection);
00234 
00235             if (pb == null) {
00236                 throw new PExceptionProtocol("Impossible to write a persitent object without PBinding");
00237             }
00238             TraceEjb.genclass.log(BasicLevel.DEBUG, "Store the genclass " + pn);
00239             pb.bind(pn);
00240             pb.write(conn, this);
00241             pb.unbind();
00242 
00243             // The data are written on the support, then the memory instance is
00244             // up to date. The element marked as removed must really be removed
00245             // from the list.
00246             isModified = false;
00247             int pos = 0;
00248             for (int i = 0; i < deletedLength.length; i++) {
00249                 pos += deletedLength[i];
00250                 pIndexedElems.remove(pos);
00251             }
00252             deletedLength = new int[0];
00253             for (Iterator it = pIndexedElems.iterator(); it.hasNext();) {
00254                 GenClassElement gce = (GenClassElement) it.next();
00255                 gce.status = PIndexedElem.ELEM_UNMODIFIED;
00256                 gce.hasBeenCreated = false;
00257             }
00258 
00259             // close the connection opened localy
00260             if (connection == null) {
00261                 gcm.getPMapper().closeConnection(conn);
00262             }
00263         }
00264         //TraceEjb.genclass.log(BasicLevel.DEBUG, "end"); printState();
00265     }
00266 
00267     public void doNotWrite(PObject po) {
00268         GenClassElement gce = null;
00269         for (Iterator it = pIndexedElems.iterator(); it.hasNext() && gce == null;) {
00270             gce = (GenClassElement) it.next();
00271             if (gce.value != null) {
00272                 if (po == gce.value) {
00273                     break;
00274                 }
00275             } else if (gce.pname != null && gce.pname.equals(po.getPName())) {
00276                 break;
00277             }
00278             gce = null;
00279         }
00280         if (gce == null) {
00281             throw new EJBException("Impossible to mark the element as written "
00282                                    + "because it does not  be found in the GenClass: "
00283                                    + po.getPName());
00284         }
00285         if (TraceEjb.genclass.isLoggable(BasicLevel.DEBUG)) {
00286             TraceEjb.genclass.log(BasicLevel.DEBUG,
00287                                   "assign ELEM_UNMODIFIED to " + po.getPName());
00288         }
00289         gce.status = PIndexedElem.ELEM_UNMODIFIED;
00290     }
00291 
00292     // IMPLEMENTATION OF THE PAccessor INTERFACE //
00293     //-------------------------------------------//
00294 
00299     public Object getMemoryInstance() {
00300         return this;
00301     }
00302 
00303 
00304     // IMPLEMENTATION OF THE PGenClassAccessor INTERFACE //
00305     //---------------------------------------------------//
00306 
00313     public void paAdd(PIndexedElem elem, Object conn) throws PException {
00314         pIndexedElems.add(elem);
00315         size++;
00316         //TraceEjb.genclass.log(BasicLevel.DEBUG, "printState"); printState();
00317     }
00318 
00323     public PIndexedElem createPIndexedElem() {
00324         return new GenClassElement(this);
00325     }
00326 
00331     public boolean paDeltaSupported() {
00332         return true;
00333     }
00334 
00340     public int paGetNbElem() {
00341         return pIndexedElems.size();
00342     }
00343 
00347     public Iterator paIterator() {
00348         return pIndexedElems.iterator();
00349     }
00350 
00358     public void paSetNbElem(int nbelem) {
00359         TraceEjb.genclass.log(BasicLevel.DEBUG, "nbElem: " + nbelem);
00360         if (nbelem == -1) {
00361             pIndexedElems.clear();
00362         } else {
00363             pIndexedElems = new ArrayList(nbelem);
00364         }
00365         deletedLength = new int[0];
00366         size = 0;
00367     }
00368 
00369 
00370     // METHODS USABLE FOR THE SUB CLASS //
00371     //----------------------------------//
00372 
00378     protected int gcGetRealIndex(int idx) {
00379         int a = idx;
00380         int i = 0;
00381         while (i < deletedLength.length && (a -= deletedLength[i]) >= 0) {
00382             i++;
00383         }
00384         return idx + i;
00385     }
00386 
00400     protected void gcAdd(PObject element, boolean callListener) {
00401         //TraceEjb.genclass.log(BasicLevel.DEBUG, "printState"); printState();
00402         int pos = 0;
00403         GenClassElement gce = null;
00404         int i = 0;
00405         while (i < deletedLength.length) {
00406             pos += deletedLength[i];
00407             gce = (GenClassElement) pIndexedElems.get(pos);
00408             if (gce.value == element) {
00409                 break;
00410             }
00411             pos++;
00412             i++;
00413         }
00414         if (i < deletedLength.length) {
00415             if (gce.hasBeenCreated) {
00416                 throw new EJBException("Internal error state: A deleted element has not been created");
00417             }
00418             TraceEjb.genclass.log(BasicLevel.DEBUG,
00419                                   "The element added was previously removed. i: " + i
00420                                   + "gce.pname: " + gce.pname);
00421             // The element was previously removed and added now.
00422             // - the status must be change to unmodified
00423             gce.status = PIndexedElem.ELEM_UNMODIFIED;
00424             if (deletedLength.length == 1) {
00425                 deletedLength = new int[0];
00426             } else {
00427                 int[] old = deletedLength;
00428                 deletedLength = new int[deletedLength.length - 1];
00429                 System.arraycopy(old, 0, deletedLength, 0, i);
00430                 if (i < deletedLength.length) {
00431                     System.arraycopy(old, i + 1,
00432                                      deletedLength, i,
00433                                      deletedLength.length - i - 1);
00434                     deletedLength[i] += old[i] + 1;
00435                 }
00436             }
00437         } else {
00438             if (TraceEjb.genclass.isLoggable(BasicLevel.DEBUG)) {
00439                 try {
00440                     TraceEjb.genclass.log(BasicLevel.DEBUG, "Add the element '"
00441                             + element.getPName().encodeString());
00442                 } catch (PExceptionNaming pExceptionNaming) {
00443                 }
00444             }
00445             gce = (GenClassElement) createPIndexedElem();
00446             gce.value = element;
00447             gce.status = PIndexedElem.ELEM_CREATED;
00448             gce.hasBeenCreated = true;
00449             // Check if the element is legal, before added it (fix bug #300521)
00450             listener.isLegalElement(gce);
00451             pIndexedElems.add(gce);
00452         }
00453         isModified = true;
00454         size++;
00455         //TraceEjb.genclass.log(BasicLevel.DEBUG, "printState"); printState();
00456         if (callListener) {
00457             listener.gcAdd(gce);
00458         }
00459     }
00460 
00468     protected Object gcRemove(Object element, boolean callListener) throws PException {
00469         //TraceEjb.genclass.log(BasicLevel.DEBUG, "printState"); printState();
00470         GenClassElement gce = null;
00471         boolean found = false;
00472         int b = 0; //The number of existing element since the last deleted element
00473         int i = 0; // Quantity of deleted elements before
00474         int a;
00475         for (a = 0; a < pIndexedElems.size() && !found; a++) {
00476             gce = (GenClassElement) pIndexedElems.get(a);
00477             if (gce.status == PIndexedElem.ELEM_DELETED) {
00478                 i++;
00479                 b = 0;
00480                 continue; //Do not search the element among the deleted elements
00481             }
00482             b++;
00483             if (gce.pname != null && gce.value == null) {
00484                 gce.value = gcDeref(gce.pname);
00485             }
00486             found = (element == null && gce.value == null)
00487                 || (element != null && element.equals(gce.value));
00488         }
00489         if (!found) {
00490             TraceEjb.genclass.log(BasicLevel.DEBUG, "Nothing to remove");
00491             return null;
00492         }
00493 
00494         // call listener before removing field
00495         if (callListener) {
00496             listener.gcRemove(gce, false);
00497         }
00498         if (gce.hasBeenCreated) {
00499             // Remove the element permanantly
00500             TraceEjb.genclass.log(BasicLevel.DEBUG, "Remove permanantly the element");
00501             pIndexedElems.remove(a - 1);
00502             if (i < deletedLength.length) {
00503                 //decrease the number of existing element until the next deletec
00504                 // element.
00505                 deletedLength[i]--;
00506             }
00507         } else {
00508             //Mark the element as removed
00509             gce.status = PIndexedElem.ELEM_DELETED;
00510 
00511             // add the entry in the deletedLength array
00512             TraceEjb.genclass.log(BasicLevel.DEBUG,
00513                                   "Add the entry in the deletedLength array: i:" + i + " / b:" + b + ")");
00514             int[] old = deletedLength;
00515             deletedLength = new int[old.length + 1];
00516             System.arraycopy(old, 0, deletedLength, 0, i);
00517             deletedLength[i] = b - 1;
00518             if (i < old.length) {
00519                 deletedLength[i + 1] = old[i] - b;
00520                 System.arraycopy(old, i + 1, deletedLength, i + 2, old.length - i - 1);
00521             }
00522         }
00523         isModified = true;
00524         size--;
00525         //TraceEjb.genclass.log(BasicLevel.DEBUG, "printState"); printState();
00526         return gce.value;
00527     }
00528 
00529     private static String toString(int[] t) {
00530         StringBuffer sb = new StringBuffer("[");
00531         for (int i = 0; i < t.length;) {
00532             sb.append(t[i]);
00533             i++;
00534             if (i < t.length) {
00535                 sb.append(',');
00536             }
00537         }
00538         sb.append(']');
00539         return sb.toString();
00540     }
00541 
00542     public int gcGetSize() {
00543         return size;
00544     }
00545 
00546     protected boolean gcContains(PObject element, Object connection)
00547         throws PException {
00548         //Open a connection if the parameter is null
00549         Object conn = (connection == null
00550                        ? gcm.getPMapper().getConnection()
00551                        : connection);
00552 
00553         boolean result = false;
00554         for (Iterator it = gcIterator(conn); !result && it.hasNext();) {
00555             Object o = it.next();
00556             result =  (element == null && o == null)
00557                 || (element != null && element.equals(o));
00558         }
00559 
00560         if (connection == null) {
00561             // close the localy opened connection
00562             gcm.getPMapper().closeConnection(conn);
00563         }
00564         if (TraceEjb.genclass.isLoggable(BasicLevel.DEBUG)) {
00565             try {
00566                 TraceEjb.genclass.log(BasicLevel.DEBUG, "Looking for the element '"
00567                         + element.getPName().encodeString()
00568                         + ". return " + result);
00569             } catch (PExceptionNaming pExceptionNaming) {
00570             }
00571         }
00572         return result;
00573     }
00574 
00575     protected Iterator gcIterator() throws PException {
00576         return gcIterator(null);
00577     }
00578 
00584     protected Iterator gcIterator(Object connection) throws PException {
00585         return new ElementIterator(this, connection);
00586     }
00587 
00596     protected PObject gcGetElement(GenClassElement gce, Object connection) throws PException {
00597         if (gce.pname != null && gce.value == null) {
00598             // Dereference the PName
00599             if (gce.pname == null || gce.pname.isNull()) {
00600                 return null;
00601             }
00602             PName current = gce.pname;
00603 
00604             // Allocate a connection if needed
00605             Object conn = (connection == null
00606                            ? gcm.getPMapper().getConnection()
00607                            : connection);
00608 
00609             // Resolve the pname
00610             Object res = current.resolve(conn);
00611             while (res != null && res instanceof PName && !res.equals(current)) {
00612                 current = (PName) res;
00613                 res = current.resolve(conn);
00614             }
00615 
00616             // close the connection opened localy
00617             if (connection == null) {
00618                 gcm.getPMapper().closeConnection(conn);
00619             }
00620 
00621             // Fetch a Local Object on the factory of the referenced bean
00622             gce.value = gcDeref(current);
00623         }
00624         return gce.value;
00625     }
00626 
00631     public void gcClear(boolean delete) {
00632         TraceEjb.genclass.log(BasicLevel.DEBUG, "Clear the gc");
00633         //TraceEjb.genclass.log(BasicLevel.DEBUG, "begin"); printState();
00634 
00635         // Call listener now because ejbRemove can still access fields.
00636         for (Iterator it = pIndexedElems.iterator(); it.hasNext();) {
00637             GenClassElement gce = (GenClassElement) it.next();
00638             if (gce.status != PIndexedElem.ELEM_DELETED) {
00639                 if (gce.pname != null && gce.value == null) {
00640                     gce.value = gcDeref(gce.pname);
00641                 }
00642                 TraceEjb.genclass.log(BasicLevel.DEBUG, "listener.gcRemove");
00643                 listener.gcRemove(gce, delete);
00644             }
00645         }
00646 
00647         // Mark all elements as DELETED or remove the created element.
00648         for (Iterator it = pIndexedElems.iterator(); it.hasNext();) {
00649             GenClassElement gce = (GenClassElement) it.next();
00650             if (gce.status != PIndexedElem.ELEM_DELETED) {
00651                 gce.status = PIndexedElem.ELEM_DELETED;
00652                 if (gce.hasBeenCreated) {
00653                     // Remove the element permanantly
00654                     TraceEjb.genclass.log(BasicLevel.DEBUG, "Clear permanantly an element");
00655                     it.remove();
00656                 }
00657             }
00658         }
00659         // update the virtual size
00660         size = 0;
00661         isModified = true;
00662 
00663         // As all elements are deleted, the 'deletedLength' contains only 0
00664         // numbers. The size of this array is the same as the size of the
00665         // pIndexedElems list.
00666         deletedLength = new int[pIndexedElems.size()];
00667         Arrays.fill(deletedLength, 0);
00668         //TraceEjb.genclass.log(BasicLevel.DEBUG, "end"); printState();
00669 
00670     }
00671 
00672     protected PObject gcDeref(PName pn) {
00673         JEntityFactory f = (JEntityFactory)
00674             ((PBinder) pn.getPNameManager()).getBinderClassMapping();
00675         if (f.getLocalHome() != null) {
00676             return ((PObjectHome) f.getLocalHome()).getPObject(pn);
00677         } else {
00678             return ((PObjectHome) f.getHome()).getPObject(pn);
00679         }
00680     }
00681 
00685     protected PName gcObject2ref(PObject value) throws PException {
00686         if (value != null) {
00687             Object conn = gcm.getPMapper().getConnection();
00688             PNameManager pnm = (PNameManager) gcm.getPNameCoder();
00689             PName pn = pnm.export(conn, value.getPName(), null);
00690             gcm.getPMapper().closeConnection(conn);
00691             return pn;
00692         } else {
00693             return gcm.getPNameCoder().getNull();
00694         }
00695     }
00696 
00697     public void printState() {
00698         if (!TraceEjb.genclass.isLoggable(BasicLevel.DEBUG)) {
00699             return;
00700         }
00701         TraceEjb.genclass.log(BasicLevel.DEBUG, "deletedLength: " + toString(deletedLength));
00702         TraceEjb.genclass.log(BasicLevel.DEBUG, "pIndexedElems.size():" + pIndexedElems.size());
00703         TraceEjb.genclass.log(BasicLevel.DEBUG, "isModified: " + isModified);
00704         TraceEjb.genclass.log(BasicLevel.DEBUG, "size:" + size);
00705         int  i = 0;
00706         for (Iterator it = pIndexedElems.iterator(); it.hasNext();) {
00707             GenClassElement gce = (GenClassElement) it.next();
00708             TraceEjb.genclass.log(BasicLevel.DEBUG, "GCE:" + i
00709                                   + " / status:" + gce.status
00710                                   + " / hasBeenCreated:" + gce.hasBeenCreated
00711                                   );
00712             TraceEjb.genclass.log(BasicLevel.DEBUG, "- pname:" + gce.pname);
00713             TraceEjb.genclass.log(BasicLevel.DEBUG, "- value:" + gce.value);
00714             i++;
00715         }
00716     }
00717 
00723     protected class ElementIterator implements Iterator {
00724 
00725         private int cursor = 0;
00726         private int next = 0;
00727         private GenClassImpl gc;
00728         private Object conn;
00729 
00730         public ElementIterator(GenClassImpl gc, Object connection) {
00731             this.gc = gc;
00732             conn = connection;
00733             reset();
00734         }
00735 
00736         public void reset() {
00737             cursor = -1;
00738             next = nextExist(cursor);
00739         }
00740 
00741         private int nextExist(int pos) {
00742             int tmp = pos + 1;
00743             while (tmp < pIndexedElems.size()) {
00744                 if (((GenClassElement) pIndexedElems.get(tmp)).status != PIndexedElem.ELEM_DELETED) {
00745                     //TraceEjb.genclass.log(BasicLevel.DEBUG, "nextExist("+pos+")="+tmp);
00746                     return tmp;
00747                 }
00748                 tmp++;
00749             }
00750             //TraceEjb.genclass.log(BasicLevel.DEBUG, "nextExist("+pos+")=-1");
00751             return -1;
00752         }
00753 
00754         // IMPLEMENTATION OF THE Iterator INTERFACE //
00755         //------------------------------------------//
00756 
00764         public boolean hasNext() {
00765             return next != -1;
00766         }
00767 
00774         public Object next() {
00775             if (next == -1) {
00776                 throw new NoSuchElementException();
00777             }
00778             cursor = next;
00779             try {
00780                 GenClassElement gce = (GenClassElement) pIndexedElems.get(cursor);
00781                 gc.gcGetElement(gce, conn);
00782                 //Caculate the next
00783                 next = nextExist(cursor);
00784                 return gce.value;
00785             } catch (PException e) {
00786                 next = -1;
00787                 TraceEjb.genclass.log(BasicLevel.ERROR, "Impossible to obtain value:", e);
00788                 throw new NoSuchElementException("Impossible to obtain value:" + e);
00789             }
00790         }
00791 
00792         public void remove() {
00793             try {
00794                 gcRemove(((GenClassElement) pIndexedElems.get(cursor)).value, true);
00795             } catch (PException e) {
00796                 throw new UnsupportedOperationException(e.getMessage());
00797             }
00798         }
00799     }
00800 }

Generated on Tue Feb 15 15:05:39 2005 for JOnAS by  doxygen 1.3.9.1