001: /**
002: * Copyright (C) 2001-2004 France Telecom R&D
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */package org.objectweb.speedo.naming.lib;
018:
019: import java.util.ArrayList;
020: import java.util.Collection;
021: import java.util.Iterator;
022: import java.util.Map;
023: import java.util.Properties;
024:
025: import org.objectweb.jorm.api.PClassMapping;
026: import org.objectweb.jorm.api.PException;
027: import org.objectweb.jorm.api.PMapper;
028: import org.objectweb.jorm.metainfo.api.Class;
029: import org.objectweb.jorm.metainfo.api.ClassMapping;
030: import org.objectweb.jorm.metainfo.api.ClassRef;
031: import org.objectweb.jorm.metainfo.api.CompositeName;
032: import org.objectweb.jorm.metainfo.api.GenClassMapping;
033: import org.objectweb.jorm.metainfo.api.GenClassRef;
034: import org.objectweb.jorm.metainfo.api.Manager;
035: import org.objectweb.jorm.metainfo.api.MetaObject;
036: import org.objectweb.jorm.metainfo.api.NameDef;
037: import org.objectweb.jorm.metainfo.api.NameRef;
038: import org.objectweb.jorm.metainfo.api.PrimitiveElement;
039: import org.objectweb.jorm.metainfo.api.ScalarField;
040: import org.objectweb.jorm.naming.api.PBinder;
041: import org.objectweb.jorm.naming.api.PName;
042: import org.objectweb.jorm.naming.api.PNameCoder;
043: import org.objectweb.jorm.naming.api.PNamingContext;
044: import org.objectweb.jorm.type.api.PType;
045: import org.objectweb.medor.expression.api.Expression;
046: import org.objectweb.medor.expression.api.ExpressionException;
047: import org.objectweb.medor.expression.lib.BasicOperand;
048: import org.objectweb.medor.expression.lib.BasicParameterOperand;
049: import org.objectweb.medor.expression.lib.DivideBy;
050: import org.objectweb.medor.expression.lib.Round;
051: import org.objectweb.perseus.cache.api.CacheManager;
052: import org.objectweb.speedo.api.SpeedoException;
053: import org.objectweb.speedo.generation.jorm.JormMIMappingBuilder;
054: import org.objectweb.speedo.generation.lib.NamingRules;
055: import org.objectweb.speedo.mapper.api.JormFactory;
056: import org.objectweb.speedo.metadata.SpeedoClass;
057: import org.objectweb.speedo.metadata.SpeedoColumn;
058: import org.objectweb.speedo.metadata.SpeedoField;
059: import org.objectweb.speedo.naming.api.MIBuilderHelper;
060: import org.objectweb.speedo.naming.api.NamingManager;
061: import org.objectweb.speedo.pm.api.POManagerFactoryItf;
062: import org.objectweb.util.monolog.api.BasicLevel;
063: import org.objectweb.util.monolog.api.Logger;
064:
065: /**
066: * Defines a common implementation of NamingManager for identifier based on
067: * a single long or java.lang.Long field.
068: *
069: * @author S.Chassande-Barrioz
070: */
071: public abstract class CommonLongIdNamingManager extends
072: NamingManagerHelper {
073:
074: /**
075: * @return the name of the composite name (JORM object) corresponding the
076: * identifier.
077: */
078: protected abstract String getLongIdName();
079:
080: /**
081: * @return the default name of the identifier field.
082: */
083: protected abstract String getLongIdLid();
084:
085: /**
086: * @return the default jorm type of the identifier field.
087: */
088: protected abstract PType getFieldType();
089:
090: /**
091: * @return the default java type of the identifier field.
092: */
093: protected abstract java.lang.Class getJavaFieldType();
094:
095: /**
096: * @return the operand (Medor object) used for computing the class identifier
097: */
098: protected abstract BasicOperand getBasicOperand();
099:
100: /**
101: * Checks if the field type is the one expected
102: * @param type is the field type as a string.
103: * @return true if this the right type.
104: */
105: protected abstract boolean checkFieldType(String type);
106:
107: /**
108: * @return the mapper used
109: */
110: public abstract PMapper getMapper();
111:
112: /**
113: * @return a new PBinder for managing GenClass identifier.
114: */
115: public abstract PBinder newGenClassPBinder() throws PException;
116:
117: /**
118: * @param className is the class name of the persistent class
119: * @param conn is the connection to the underlying persistent support.
120: * @return a new PBinder for managing class identifier.
121: */
122: public abstract PBinder newClassPBinder(String className,
123: Object conn) throws PException;
124:
125: /**
126: * @return a new PBinder for managing class reference.
127: */
128: public abstract PNamingContext newClassPNamingContext()
129: throws PException;
130:
131: /**
132: * @return the class of the PName used by this naming.
133: */
134: public abstract java.lang.Class getPNameClass();
135:
136: /**
137: * @return the class of the PBinder used by this naming.
138: */
139: public abstract java.lang.Class getPBinderClass();
140:
141: /**
142: * @return the class of the IdManager used by this naming.
143: */
144: public abstract java.lang.Class getLongIdManagerClass();
145:
146: /**
147: * @return the class of the PNamingContext used by this naming.
148: */
149: public abstract java.lang.Class getPNamingContextClass();
150:
151: /**
152: * Decodes a string value into a PName.
153: * @param pnc is the PNameCoder able to decode the string
154: * @param idStr is the string representation of an identifier
155: * @return a PName
156: */
157: protected abstract PName decodeLong(PNameCoder pnc, String idStr)
158: throws PException;
159:
160: /**
161: * Encodes a PName into a value.
162: * @param pn is the PName to encode
163: * @return the encoded PName
164: */
165: public abstract Object encode(PName pn) throws PException;
166:
167: /**
168: * @return Returns the bINDER_FOR_GENCLASS.
169: */
170: protected abstract String getBinderForGenClass();
171:
172: /**
173: * @return Returns the bINDER_FOR_CLASS.
174: */
175: protected abstract String getBinderForClass();
176:
177: /**
178: * @return Returns the hIDDEN_LID_FIELD_NAME.
179: */
180: protected abstract String getHiddenLidFieldName();
181:
182: public void init() throws PException {
183: if (getMapper() != null) {
184: return;
185: }
186: if (mapper == null) {
187: throw new PException("No mapper assigned");
188: }
189: setPMapper(mapper);
190: mapper = null;
191: }
192:
193: // IMPLEMENTATION OF THE METHOD FROM THE NamingManager INTERFACE //
194: //---------------------------------------------------------------//
195: public void setPmf(POManagerFactoryItf pmf) {
196: }
197:
198: public boolean supportPNamingcontext() {
199: return true;
200: }
201:
202: public abstract boolean canManage(SpeedoClass sc);
203:
204: public boolean canProvidePBinder(Object hints,
205: ClassLoader classLoader) {
206: return getBinderClassNameFromHints(hints, getName()) != null;
207: }
208:
209: public boolean canProvidePNamingContext(Object hints,
210: ClassLoader classLoader) {
211: return getPNCClassNameFromHints(hints, getName()) != null;
212: }
213:
214: public PName decode(PNameCoder pnc, Object oid,
215: java.lang.Class clazz, JormFactory jf) throws PException {
216: if (oid instanceof String) {
217: String stroid = (String) oid;
218: int idx = stroid.indexOf(SEP);
219: if (pnc != null) {
220: if (getPBinderClass().isInstance(pnc)
221: || getLongIdManagerClass().isInstance(pnc)) {
222: String idStr = stroid;
223: if (idx != -1) {
224: //The oid contains the class name
225: idStr = stroid.substring(idx + SEP.length());
226: }
227: return decodeLong(pnc, idStr);
228:
229: } else {
230: //The pnc is not a well known pnc, then the oid cannot be managed
231: return null;
232: }
233: } else {
234: //No pnc specified
235: if (idx != -1) {
236: //The oid contains the class name
237: String fqcn = stroid.substring(0, idx);
238: ClassLoader cl = getClass().getClassLoader();
239: if (cl == null) {
240: cl = ClassLoader.getSystemClassLoader();
241: }
242: try {
243: pnc = jf.getPNamingContext(fqcn, cl);
244: } catch (Exception e) {
245: return null;
246: }
247: if (getPBinderClass().isInstance(pnc)
248: || getPNamingContextClass().isInstance(pnc)) {
249: return decodeLong(pnc, stroid.substring(idx
250: + SEP.length()));
251: } else {
252: return null;
253: }
254: } else {
255: //The oid cannot be managed
256: return null;
257: }
258: }
259: }
260: return null;
261: }
262:
263: public void setLogger(Logger logger) {
264: this .logger = logger;
265: }
266:
267: public String getPNameHints(SpeedoClass sc, NameDef nd) {
268: return "null";
269: }
270:
271: public Object[] getPNameHints2(SpeedoClass sc, NameDef nd) {
272: return new Object[] { PNH_NULL_VALUE };
273: }
274:
275: public NamingManager.NamingField[] getNamingfields(SpeedoClass sc) {
276: SpeedoField sf;
277: try {
278: sf = sc.getUniquePKField();
279: } catch (SpeedoException e) {
280: sf = null;
281: }
282: if (sf != null) {
283: return new NamingManager.NamingField[] { new NamingManager.NamingField(
284: sf.name, getJavaFieldType(), getLongIdLid(),
285: getFieldType()) };
286: } else {
287: return null;
288: }
289: }
290:
291: public void defineClassIdentifierNameDef(NameDef nd, Class jc,
292: SpeedoClass sc, ClassMapping cm, MIBuilderHelper mibh,
293: JormMIMappingBuilder mb, Collection createdMOs)
294: throws SpeedoException, PException {
295: SpeedoField pkField = fetchUniqueLongPKField(sc);
296: PrimitiveElement lid;
297: String lidname;
298: if (pkField == null) {
299: if (sc.identity.columns == null) {
300: logger.log(BasicLevel.WARN,
301: "No mapping information for the identifier of the class '"
302: + sc.getFQName() + "'.");
303: lidname = getHiddenLidFieldName();
304: } else {
305: lidname = sc.identity.columns[0].column.name;
306: }
307: // create an hidden identifier field
308: lid = mibh.createNameDefField(sc.jormclass, lidname,
309: getFieldType());
310: } else {
311: //The identifier is mapped over a persistent field
312: lidname = pkField.name;
313: lid = mibh.getPrimitiveField(sc.jormclass, lidname);
314: if (lid == null) {
315: throw new SpeedoException(mibh.getErrorMessage(sc,
316: sc.jormclass, null)
317: + " Impossible to get the field '"
318: + lidname
319: + "'");
320: }
321: }
322: Manager manager = mibh.getManager(jc);
323: CompositeName cn = getLongIdCompositeName(manager);
324: NameRef nr = nd.createNameRef(cn);
325: nr.addProjection(getLongIdLid(), lid.getName());
326: if (sc.jormclass.getSuperClasses().isEmpty()) {
327: // define the inheritance filter permiting to determine the class
328: // since an identifier (some bits are reserved for class
329: // identification)
330: Expression expr = new Round(new DivideBy(
331: new BasicParameterOperand(getFieldType(),
332: getLongIdLid()), getBasicOperand()));
333: try {
334: expr.compileExpression();
335: } catch (ExpressionException e) {
336: throw new SpeedoException(
337: "Impossible to compile the filter of longid naming",
338: e);
339: }
340: sc.jormclass.setInheritanceFilter(nd, expr);
341: // assign a default value to each sub classes. The real value
342: // is computed at runtime from the database content.
343: assignDummyKeyToFamilly(sc.jormclass, nd);
344: }
345: if (pkField == null) {
346: mb.createClassIdentifierNameDefMapping(cm, nd, sc, mibh);
347: }
348: }
349:
350: public boolean needInheritanceDiscriminator(SpeedoClass sc)
351: throws SpeedoException {
352: return false;
353: }
354:
355: public void defineClassReferenceNameDef(NameDef nd, ClassRef cr,
356: SpeedoField sf, SpeedoClass currentClass, ClassMapping cm,
357: MIBuilderHelper mibh, JormMIMappingBuilder mb)
358: throws SpeedoException, PException {
359: String lidname = mibh.getNameDefFieldPrefix(cr, false, false,
360: sf)
361: + getHiddenLidFieldName();
362: SpeedoClass referencedClass = sf.moClass
363: .getSpeedoClassFromContext(cr.getMOClass().getFQName());
364: //get the composite name
365: Manager manager = mibh.getManager(cr);
366: CompositeName cn = getLongIdCompositeName(manager);
367: NameRef nr = nd.createNameRef(cn);
368: //create the hidden field
369: mibh
370: .createNameDefField(cr.getParent(), lidname,
371: getFieldType());
372: //define translation betwen the composite name field and the hidden field
373: nr.addProjection(getLongIdLid(), lidname);
374: //map the created hidden field in the ClassMapping
375: mb.createClassRefNameDefMapping(cm, nd, sf);
376: }
377:
378: public void defineClassReferenceNameDef(NameDef nd, ClassRef cr,
379: SpeedoField sf, SpeedoClass currentClass,
380: GenClassMapping gcm, MIBuilderHelper mibh,
381: JormMIMappingBuilder mb) throws SpeedoException, PException {
382: String lidname = mibh
383: .getNameDefFieldPrefix(cr, false, true, sf)
384: + getHiddenLidFieldName();
385: SpeedoClass referencedClass = sf.moClass
386: .getSpeedoClassFromContext(cr.getMOClass().getFQName());
387: //get the composite name
388: Manager manager = mibh.getManager(cr);
389: CompositeName cn = getLongIdCompositeName(manager);
390: NameRef nr = nd.createNameRef(cn);
391: //create the hidden field
392: mibh
393: .createNameDefField(cr.getParent(), lidname,
394: getFieldType());
395: //define translation betwen the composite name field and the hidden field
396: nr.addProjection(getLongIdLid(), lidname);
397: //map the created hidden field in the GenClassMapping
398: mb.createClassRefNameDefMapping(gcm, nd, sf);
399: }
400:
401: public void defineGenClassIdentifierNameDef(NameDef nd,
402: GenClassRef gcr, SpeedoField sf, SpeedoClass currentClass,
403: GenClassMapping gcm, MIBuilderHelper mibh,
404: JormMIMappingBuilder mb) throws SpeedoException, PException {
405: String lidname = mibh
406: .getNameDefFieldPrefix(gcr, true, true, sf)
407: + getHiddenLidFieldName();
408: mibh.createNameDefField(gcr, lidname, getFieldType());
409: //Gen class identifier is based on basid
410: nd.setFieldName(lidname);
411: //map the created hidden field in the GenClassMapping
412: mb.createGenClassIdentifierNameDefMapping(gcm, nd, sf, mibh);
413: }
414:
415: public void defineGenClassReferenceNameDef(NameDef nd,
416: GenClassRef gcr, SpeedoField sf, SpeedoClass currentClass,
417: ClassMapping cm, MIBuilderHelper mibh,
418: JormMIMappingBuilder mb) throws SpeedoException, PException {
419: SpeedoField pkfield = sf.moClass.getUniquePKField();
420: String fn;
421: if (pkfield == null) {
422: fn = getHiddenLidFieldName();
423: } else {
424: fn = pkfield.name;
425: }
426: //Gen class reference is based on basid
427: nd.setFieldName(fn);
428: }
429:
430: private CompositeName getLongIdCompositeName(Manager manager) {
431: CompositeName cn = manager.getCompositeName(getLongIdName());
432: if (cn == null) {
433: cn = manager.createCompositeName(getLongIdName());
434: ScalarField cnf = cn.createCompositeNameField(
435: getLongIdLid(), getFieldType(), PType.NOSIZE,
436: PType.NOSIZE);
437: cnf.setIsAutoCalculated(true);
438: }
439: return cn;
440: }
441:
442: private void assignDummyKeyToFamilly(
443: org.objectweb.jorm.metainfo.api.Class clazz, NameDef nd) {
444: clazz.setInheritanceNamingKey(nd, "0");
445: for (Iterator it = clazz.getSubClasses().iterator(); it
446: .hasNext();) {
447: assignDummyKeyToFamilly(
448: ((org.objectweb.jorm.metainfo.api.Class) it.next()),
449: nd);
450: }
451: }
452:
453: private SpeedoField fetchUniqueLongPKField(SpeedoClass tsc)
454: throws SpeedoException {
455: Iterator it = tsc.fields.values().iterator();
456: SpeedoField sf = null;
457: ArrayList al = null;
458: while (it.hasNext()) {
459: SpeedoField _sf = (SpeedoField) it.next();
460: if (_sf.primaryKey) {
461: if (sf != null) {
462: if (al == null) {
463: al = new ArrayList();
464: }
465: al.add(_sf.name);
466: } else {
467: sf = _sf;
468: }
469: }
470: }
471: if (al != null) {
472: al.add(sf);
473: throw new SpeedoException(
474: "Impossible to use an auto incremented identifier if "
475: + "several fields have been marked as primary-key "
476: + al + " in the class '" + tsc.getFQName()
477: + "'.");
478: }
479: if (sf != null) {
480: String t = sf.type();
481:
482: if (!checkFieldType(t)) {
483: throw new SpeedoException(
484: "Impossible to use an auto incremented identifier: "
485: + "the field type of '" + sf.name
486: + "' is '" + sf.type() + "' and '"
487: + getFieldType().getJavaName()
488: + "' is expected (class '"
489: + tsc.getFQName() + "'.");
490: }
491: }
492: return sf;
493: }
494:
495: public void getJormNamingConfig(NameDef nd,
496: SpeedoClass targetClass, MetaObject sourceMO, String key,
497: Properties result) {
498:
499: StringBuffer sb = new StringBuffer();
500: sb.append(getName());
501: sb.append(NamingManagerHelper.HINTS_SEP);
502: boolean isGCR = sourceMO instanceof GenClassRef;
503: String binderInfo = (isGCR ? getBinderForGenClass()
504: : getBinderForClass());
505: sb.append(binderInfo);
506:
507: SpeedoClass ancestor = targetClass.getAncestor();
508: String ancestorClassName;
509: String pncClassName;
510: if (!isGCR //For a Genclass ref or genclass identifier
511: && (ancestor != null // has supper class
512: || !targetClass.jormclass.getSubClasses().isEmpty()) // has sub class
513: ) {
514: if (ancestor == null) {
515: ancestor = targetClass;
516: }
517: ancestorClassName = ancestor.getFQName();
518: pncClassName = NamingRules.kfpncName(ancestorClassName);
519: } else {
520: ancestorClassName = targetClass.getFQName();
521: pncClassName = binderInfo;
522: }
523: //specify the pnc className
524: sb.append(NamingManagerHelper.HINTS_SEP);
525: sb.append(pncClassName);
526:
527: //specify the className of the ancestor
528: sb.append(NamingManagerHelper.HINTS_SEP);
529: sb.append(ancestorClassName);
530: result.setProperty(key, sb.toString());
531: }
532:
533: public PBinder getPBinder(String className, String hints,
534: ClassLoader classLoader, byte mappingStructureRule,
535: Map cn2binder, Map cn2pnc) throws PException {
536: init();
537: String binderInfo = getBinderClassNameFromHints(hints,
538: getName());
539: return getPBinder(className, binderInfo);
540: }
541:
542: public PNamingContext getPNamingContext(String className,
543: String hints, ClassLoader classLoader,
544: byte mappingStructureRule, Map cn2binder, Map cn2pnc,
545: Manager miManager, PClassMapping pcm) throws PException {
546: init();
547: String[] tokens = NamingManagerHelper.getTokens(hints);
548: PNamingContext pnc = null;
549: if (tokens[NamingManagerHelper.BINDER_IDX]
550: .equals(tokens[NamingManagerHelper.PNC_IDX])) {
551: //The binder must be used as PNamingContext
552: pnc = (PNamingContext) cn2binder.get(className);
553: if (pnc == null) {
554: //instanciate the binder/PNC
555: pnc = (PNamingContext) getPBinder(className,
556: tokens[NamingManagerHelper.BINDER_IDX]);
557: //register the binder/PNC as binder
558: cn2binder.put(className, pnc);
559: }
560: return pnc;
561: } else {
562: boolean register = false;
563: if (!tokens[NamingManagerHelper.PCLASS_IDX]
564: .equals(className)) {
565: //The PNC of THE ancestor must be used
566: pnc = (PNamingContext) cn2pnc
567: .get(tokens[NamingManagerHelper.PCLASS_IDX]);
568: if (pnc == null) {
569: register = true;
570: }
571: }
572: if (pnc == null) {
573: //instanciate the PNC
574: pnc = newClassPNamingContext();
575: if (register) {
576: cn2pnc.put(tokens[NamingManagerHelper.PCLASS_IDX],
577: pnc);
578: }
579: }
580: }
581: return pnc;
582: }
583:
584: protected PBinder getPBinder(String className, String binderInfo)
585: throws PException {
586: if (binderInfo.startsWith(getBinderForGenClass())) {
587: return newGenClassPBinder();
588: } else if (binderInfo.startsWith(getBinderForClass())) {
589: return newClassPBinder(className, null);
590: } else {
591: throw new PException("Bad binder info: " + binderInfo);
592: }
593: }
594:
595: public void setCache(CacheManager cache) {
596: }
597:
598: public SpeedoColumn[] getDefaultColumn(SpeedoClass sc) {
599: return new SpeedoColumn[] { new SpeedoColumn(
600: getHiddenLidFieldName()) };
601: }
602: }
|