00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
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
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
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
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
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
00244
00245
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
00260 if (connection == null) {
00261 gcm.getPMapper().closeConnection(conn);
00262 }
00263 }
00264
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
00293
00294
00299 public Object getMemoryInstance() {
00300 return this;
00301 }
00302
00303
00304
00305
00306
00313 public void paAdd(PIndexedElem elem, Object conn) throws PException {
00314 pIndexedElems.add(elem);
00315 size++;
00316
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
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
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
00422
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
00450 listener.isLegalElement(gce);
00451 pIndexedElems.add(gce);
00452 }
00453 isModified = true;
00454 size++;
00455
00456 if (callListener) {
00457 listener.gcAdd(gce);
00458 }
00459 }
00460
00468 protected Object gcRemove(Object element, boolean callListener) throws PException {
00469
00470 GenClassElement gce = null;
00471 boolean found = false;
00472 int b = 0;
00473 int i = 0;
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;
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
00495 if (callListener) {
00496 listener.gcRemove(gce, false);
00497 }
00498 if (gce.hasBeenCreated) {
00499
00500 TraceEjb.genclass.log(BasicLevel.DEBUG, "Remove permanantly the element");
00501 pIndexedElems.remove(a - 1);
00502 if (i < deletedLength.length) {
00503
00504
00505 deletedLength[i]--;
00506 }
00507 } else {
00508
00509 gce.status = PIndexedElem.ELEM_DELETED;
00510
00511
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
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
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
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
00599 if (gce.pname == null || gce.pname.isNull()) {
00600 return null;
00601 }
00602 PName current = gce.pname;
00603
00604
00605 Object conn = (connection == null
00606 ? gcm.getPMapper().getConnection()
00607 : connection);
00608
00609
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
00617 if (connection == null) {
00618 gcm.getPMapper().closeConnection(conn);
00619 }
00620
00621
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
00634
00635
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
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
00654 TraceEjb.genclass.log(BasicLevel.DEBUG, "Clear permanantly an element");
00655 it.remove();
00656 }
00657 }
00658 }
00659
00660 size = 0;
00661 isModified = true;
00662
00663
00664
00665
00666 deletedLength = new int[pIndexedElems.size()];
00667 Arrays.fill(deletedLength, 0);
00668
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
00746 return tmp;
00747 }
00748 tmp++;
00749 }
00750
00751 return -1;
00752 }
00753
00754
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
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 }