001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999-2005 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: JormFactory.java 6894 2005-06-06 13:41:09Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas_ejb.container.jorm;
025:
026: import org.objectweb.jonas_ejb.container.JContainer;
027: import org.objectweb.jonas_ejb.container.JEntityFactory;
028: import org.objectweb.jonas_ejb.container.JEntitySwitch;
029: import org.objectweb.jonas_ejb.container.TraceEjb;
030: import org.objectweb.jonas_ejb.deployment.api.EjbRelationshipRoleDesc;
031: import org.objectweb.jonas_ejb.deployment.api.EntityCmp2Desc;
032: import org.objectweb.jonas_ejb.deployment.api.EntityDesc;
033: import org.objectweb.jonas_ejb.lib.JormType;
034: import org.objectweb.jorm.api.PBinding;
035: import org.objectweb.jorm.api.PClassMapping;
036: import org.objectweb.jorm.api.PClassMappingCtrl;
037: import org.objectweb.jorm.api.PException;
038: import org.objectweb.jorm.api.PMapCluster;
039: import org.objectweb.jorm.api.PMapper;
040: import org.objectweb.jorm.api.PMappingCallback;
041: import org.objectweb.jorm.facility.naming.basidir.BasidBinder;
042: import org.objectweb.jorm.naming.api.PBinder;
043: import org.objectweb.jorm.naming.api.PExceptionNaming;
044: import org.objectweb.jorm.naming.api.PName;
045: import org.objectweb.jorm.naming.api.PNameCoder;
046: import org.objectweb.jorm.naming.api.PNamingContext;
047: import org.objectweb.util.monolog.api.BasicLevel;
048:
049: import javax.ejb.EJBException;
050: import javax.ejb.EntityBean;
051:
052: import java.io.Serializable;
053: import java.util.Iterator;
054:
055: /**
056: * This class is an extension of the JEntityFactory class. It initializes the
057: * persitant class (the bean) in the jorm mapper. This class is abstract in
058: * order to be extended by the PClassMapping generated for the Bean.
059: *
060: * @author Sebastien Chassande-Barrioz
061: */
062: public abstract class JormFactory extends JEntityFactory implements
063: PClassMapping, PClassMappingCtrl {
064:
065: protected int relNonInit;
066: protected boolean mapped;
067: protected PMapper mapper = null;
068: protected EntityCmp2Desc ecd = null;
069:
070: /**
071: * Class used for EntitySwitch (binding class)
072: */
073: private Class bindingClass = null;
074:
075: /**
076: * constructor
077: */
078: public JormFactory() {
079: super ();
080: }
081:
082: protected abstract void setMapper(String mapperName)
083: throws PException;
084:
085: public abstract Object getConnection(Object hints)
086: throws PException;
087:
088: public abstract void releaseConnection(Object conn)
089: throws PException;
090:
091: /**
092: * Initialization of the factory. This is called just after the newInstance()
093: * from the JContainer (addBean method)
094: */
095: public void init(EntityDesc ed, JContainer c, String mapperName) {
096: if (TraceEjb.isDebugFactory()) {
097: TraceEjb.factory.log(BasicLevel.DEBUG, ed.getEjbName());
098: }
099:
100: // First, call the super in order to have the access to the datasource
101: // and the beanNaming
102: super .init(ed, c);
103: ecd = (EntityCmp2Desc) ed;
104: try {
105: setMapper(mapperName);
106: } catch (PException e) {
107: throw new EJBException(
108: "JormFactory cannot create the mapper", e);
109: }
110:
111: //----------------------- JORM INITIALIZATION -----------------------//
112: if (TraceEjb.isDebugFactory()) {
113: TraceEjb.factory.log(BasicLevel.DEBUG,
114: "Jorm initialisation");
115: }
116: PBinder binder = null;
117: Class binderClass = null;
118: int binderCT = 0;
119: try {
120: // Instanciate the binder
121: binderClass = c.getClassLoader().loadClass(
122: ecd.getJormBinderClassName());
123: binder = (PBinder) binderClass.newInstance();
124: if (ecd.hasPrimaryKeyField()) {
125: binderCT = JormType.getCodingType(ecd.getCmpFieldDesc(
126: ecd.getPrimaryKeyFieldName()).getFieldType(),
127: true);
128: ((BasidBinder) binder).setCodingType(binderCT);
129: } else {
130: // TODO:
131: // - take the initial values of the primary key
132: // - put them into the generated binder (use a PNG)
133: }
134: if (TraceEjb.isDebugFactory()) {
135: TraceEjb.factory
136: .log(BasicLevel.DEBUG, "binder "
137: + ecd.getJormBinderClassName()
138: + "instanciated");
139: }
140:
141: // Link the binder and the PClassMapping
142: binder.setPClassMapping(this );
143: setPBinder(binder);
144: setClassPNameCoder(binder);
145: if (TraceEjb.isDebugFactory()) {
146: TraceEjb.factory.log(BasicLevel.DEBUG,
147: "binder linked to the mapping");
148: }
149:
150: } catch (Exception e) {
151: TraceEjb.factory.log(BasicLevel.ERROR,
152: "Impossible to create the binder", e);
153: throw new EJBException(
154: "Impossible to create the binder: bean:"
155: + ecd.getEjbName(), e);
156: }
157:
158: // for each reference assignes the PNamingcontext if it is possible.
159: relNonInit = 0;
160: try {
161: for (Iterator it = ecd.getEjbRelationshipRoleDescIterator(); it
162: .hasNext();) {
163: EjbRelationshipRoleDesc rsr = (EjbRelationshipRoleDesc) it
164: .next();
165: String source = rsr.getSourceBean().getEjbName();
166: String target = rsr.getTargetBean().getEjbName();
167: JormFactory pcm2 = source.equals(target) ? this
168: : (JormFactory) c.getBeanFactory(target);
169: if (TraceEjb.isDebugFactory()) {
170: TraceEjb.factory.log(BasicLevel.DEBUG,
171: "treatement of the relation "
172: + rsr.getRelation().getName()
173: + ": current-bean="
174: + ecd.getEjbName()
175: + ", source-bean=" + source
176: + ", dest-bean=" + target
177: + ", cmr-field="
178: + rsr.getCmrFieldName());
179: }
180: if (rsr.hasCmrField()) {
181: PClassMapping gcm = null;
182: //Multivalued relation
183: if (rsr.isTargetMultiple()) {
184: // Instanciate a GenClassMapping and link it
185: gcm = newGCMInstance(mapperName);
186: gcm.init((PMappingCallback) mapper, null);
187: setGenClassMapping(rsr.getCmrFieldName(), gcm);
188: if (TraceEjb.isDebugFactory()) {
189: TraceEjb.factory.log(BasicLevel.DEBUG,
190: "assign a GenClassMapping for the CMR "
191: + rsr.getCmrFieldName()
192: + " / gcm=" + gcm);
193: }
194:
195: PBinder gcmBinder = null;
196: try {
197: gcmBinder = (PBinder) binderClass
198: .newInstance();
199: } catch (Exception e) {
200: TraceEjb.factory.log(BasicLevel.ERROR,
201: "Impossible to create the binder of the GCM bean: "
202: + ecd.getEjbName()
203: + " / CMR: "
204: + rsr.getCmrFieldName(), e);
205: throw new EJBException(
206: "Impossible to create the binder of the GCM bean: "
207: + ecd.getEjbName()
208: + " / CMR: "
209: + rsr.getCmrFieldName(), e);
210: }
211: if (ecd.hasPrimaryKeyField()) {
212: ((BasidBinder) gcmBinder)
213: .setCodingType(binderCT);
214: } else {
215: // TODO: (not so important)
216: // - take the initial values of the primary key
217: // - put them into the generated binder (use a PNG)
218: }
219: gcm.setPBinder(gcmBinder);
220: gcmBinder.setPClassMapping(gcm);
221: setPNameCoder(rsr.getCmrFieldName(),
222: (PNameCoder) gcmBinder);
223: }
224:
225: // As the bean with which the current bean is in relation
226: // may be not load, the test of pcm2!=null is needed
227: if (pcm2 != null) {
228: if (TraceEjb.isDebugFactory()) {
229: TraceEjb.factory.log(BasicLevel.DEBUG,
230: "Pnc Assignement");
231: }
232: if (rsr.isTargetMultiple()) {
233: ((PClassMappingCtrl) gcm)
234: .setPNameCoder((PNameCoder) pcm2
235: .getPBinder());
236: } else {
237: setPNameCoder(rsr.getCmrFieldName(),
238: (PNameCoder) pcm2.getPBinder());
239: }
240: if (pcm2.isPrefetch()) {
241: initGenClassPrefetch(gcm, pcm2);
242: }
243: } else {
244: relNonInit++;
245: if (TraceEjb.isDebugFactory()) {
246: TraceEjb.factory.log(BasicLevel.DEBUG,
247: "the Pnc is not reachable currently. relNonInit="
248: + relNonInit);
249: }
250: // The PNamingContext has not been set.
251: }
252: }
253: EjbRelationshipRoleDesc rsr2 = rsr
254: .getOppositeRelationshipRole();
255: if (pcm2 != null && rsr2.hasCmrField() && pcm2 != this ) {
256: // This case appears when the scheduling of the bean adding
257: // in the container is bad (or cyclic relation): A bean has
258: // been load and have a relation to current bean. We must
259: // therfore set the naming context on the PClassMapping of
260: // the first bean for the opposite CMR field
261: if (TraceEjb.isDebugFactory()) {
262: TraceEjb.factory.log(BasicLevel.DEBUG,
263: "later Pnc assignement of the opposite CMR field: "
264: + rsr2.getCmrFieldName());
265: }
266: pcm2.configurePnc(rsr2.getCmrFieldName(),
267: (PNamingContext) getPBinder(), this , rsr2
268: .isTargetMultiple());
269: }
270: }
271: } catch (EJBException e) {
272: throw e;
273: } catch (Exception e) {
274: TraceEjb.factory
275: .log(
276: BasicLevel.ERROR,
277: "Impossible to assign the naming context to the PClassMapping",
278: e);
279: throw new EJBException(
280: "Impossible to assign the naming context to the PClassMapping",
281: e);
282: }
283: mapped = false;
284: if (relNonInit == 0) {
285: mapClass();
286: }
287:
288: // load the binding class
289: String cn = ((EntityCmp2Desc) dd).getJormBindingClassName();
290: try {
291: bindingClass = getContainer().getClassLoader()
292: .loadClass(cn);
293: } catch (ClassNotFoundException e) {
294: String err = "Impossible to load binding class '" + cn
295: + "'.";
296: TraceEjb.factory.log(BasicLevel.ERROR, err, e);
297: throw new EJBException(err, e);
298: }
299:
300: }
301:
302: /**
303: * @return mapper
304: */
305: public PMapper getMapper() {
306: return mapper;
307: }
308:
309: /**
310: * It assignes the PNamingContext which manages a relation.
311: * @param n
312: * @param pnc
313: * @param isMultiple
314: */
315: public void configurePnc(String n, PNamingContext pnc,
316: JormFactory target, boolean isMultiple) throws PException {
317: if (isMultiple) {
318: PClassMappingCtrl gcm = (PClassMappingCtrl) getGenClassMapping(n);
319: gcm.setPNameCoder(pnc);
320: if (target.isPrefetch()) {
321: //Initializes the genclass prefetching too
322: initGenClassPrefetch((PClassMapping) gcm, target);
323: }
324:
325: } else {
326: setPNameCoder(n, pnc);
327: }
328: relNonInit--;
329: if (TraceEjb.isDebugFactory()) {
330: TraceEjb.factory
331: .log(BasicLevel.DEBUG,
332: "PNamingContext assigned, relNonInit="
333: + relNonInit);
334: }
335: if (relNonInit == 0) {
336: mapClass();
337: }
338: }
339:
340: private void mapClass() {
341: if (mapped) {
342: throw new EJBException("The class is already mapped");
343: }
344:
345: try {
346: // Map the user class into the mapper
347: mapper.map(this );
348: // Drop or Create tables, depending on what is in the DD
349: PMapCluster pmapclust = mapper
350: .getPMapCluster(getClassName());
351: if (pmapclust.isDefined()) {
352: switch (ecd.getCleanupPolicy()) {
353: case EntityDesc.CLEANUP_REMOVEDATA:
354: pmapclust.createMappingStructures(false);
355: pmapclust.deleteData();
356: break;
357: case EntityDesc.CLEANUP_REMOVEALL:
358: pmapclust.deleteMappingStructures();
359: pmapclust.createMappingStructures(true);
360: break;
361: case EntityDesc.CLEANUP_NONE:
362: break;
363: case EntityDesc.CLEANUP_CREATE:
364: pmapclust.createMappingStructures(false);
365: break;
366: default:
367: throw new EJBException("Unknown cleanup policy: "
368: + ecd.getCleanupPolicy());
369: }
370: } else {
371: // nothing in the JOnAS case because that means several beans have
372: // common structure due to the CMR. Then the last element of the
373: // PMapCluster should really apply your data action.
374: }
375: mapped = true;
376: if (TraceEjb.isDebugFactory()) {
377: TraceEjb.factory.log(BasicLevel.DEBUG, getClassName()
378: + " is mapped");
379: }
380: } catch (PException pe) {
381: Exception e = pe;
382: while ((e instanceof PException)
383: && ((PException) e).getNestedException() != null) {
384: e = ((PException) e).getNestedException();
385: }
386: TraceEjb.factory.log(BasicLevel.ERROR,
387: "Impossible to map the class on the rdb mapper", e);
388: throw new EJBException(
389: "Impossible to map the class on the rdb mapper", e);
390: }
391: }
392:
393: public void stop() {
394: super .stop();
395: try {
396: mapper.unmap(getClassName());
397: mapped = false;
398: } catch (PException e) {
399: TraceEjb.factory.log(BasicLevel.ERROR,
400: "Impossible to unmap the class " + getClassName(),
401: e);
402: }
403: }
404:
405: /**
406: * This method is overrided in order to specify the JEntityContext class
407: * which must be instanciated.
408: * Create a new instance of the bean and its EntityContext
409: * In case of CMP, the bean class is derived to manage entity persistence.
410: */
411: protected org.objectweb.jonas_ejb.container.JEntityContext createNewContext(
412: EntityBean bean) {
413: return new org.objectweb.jonas_ejb.container.jorm.JEntityContext(
414: this , bean);
415: }
416:
417: public JEntitySwitch getJEntitySwitch() {
418: Object result = null;
419: try {
420: result = bindingClass.newInstance();
421: } catch (Exception e) {
422: TraceEjb.factory.log(BasicLevel.ERROR,
423: "Impossible to create a new JEntitySwitch as specified in BeanNaming: "
424: + bindingClass.getName(), e);
425: return super .getJEntitySwitch();
426: }
427: try {
428: ((PBinding) result).init(this );
429: } catch (PException e) {
430: TraceEjb.factory.log(BasicLevel.ERROR,
431: "Impossible to initialized the new JEntitySwitch as specified in BeanNaming: "
432: + bindingClass.getName(), e);
433: }
434: return (JEntitySwitch) result;
435: }
436:
437: /**
438: * Create a GenClassMapping
439: * @param mapperName name of the mapper
440: */
441: protected PClassMapping newGCMInstance(String mapperName)
442: throws Exception {
443: int idx = mapperName.indexOf(".");
444: String mn = (idx != -1) ? mapperName.substring(0, idx)
445: : mapperName;
446: return (PClassMapping) Class.forName(
447: "org.objectweb.jorm.mapper." + mn + ".genclass."
448: + Character.toUpperCase(mn.charAt(0))
449: + mn.substring(1, mn.length())
450: + "GenClassMapping").newInstance();
451: }
452:
453: /**
454: * Encode PK in case of CMP2
455: * @return String representation of the PName
456: */
457: public Serializable encodePK(Serializable pk) {
458: try {
459: return (Serializable) ((PName) pk).encodeString();
460: } catch (PExceptionNaming e) {
461: TraceEjb.factory.log(BasicLevel.ERROR,
462: "impossible to serialize PK" + e);
463: return pk;
464: }
465: }
466:
467: /**
468: * Decode String to a PName
469: * @return PName matching the String
470: */
471: public Serializable decodePK(Serializable strpk) {
472: try {
473: return getPBinder().decodeString((String) strpk);
474: } catch (PExceptionNaming e) {
475: TraceEjb.factory.log(BasicLevel.ERROR,
476: "impossible to deserialize PK" + e);
477: return strpk;
478: }
479: }
480:
481: /**
482: * It initializes the prefetching of a genclassMapping with the
483: * PClassMapping of the target class of the multivalued CMR.
484: * @param gcm is the GenClassMapping to initialized
485: * @param targetPCM is the PClassMapping of the target class
486: */
487: protected abstract void initGenClassPrefetch(PClassMapping gcm,
488: PClassMapping targetPCM);
489: }
|