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.Collection;
020: import java.util.List;
021: import java.util.Properties;
022:
023: import org.objectweb.asm.Type;
024: import org.objectweb.jorm.api.PException;
025: import org.objectweb.jorm.metainfo.api.Class;
026: import org.objectweb.jorm.metainfo.api.ClassMapping;
027: import org.objectweb.jorm.metainfo.api.ClassRef;
028: import org.objectweb.jorm.metainfo.api.CompositeName;
029: import org.objectweb.jorm.metainfo.api.GenClassMapping;
030: import org.objectweb.jorm.metainfo.api.GenClassRef;
031: import org.objectweb.jorm.metainfo.api.Manager;
032: import org.objectweb.jorm.metainfo.api.MetaObject;
033: import org.objectweb.jorm.metainfo.api.NameDef;
034: import org.objectweb.jorm.metainfo.api.NameRef;
035: import org.objectweb.jorm.naming.api.PName;
036: import org.objectweb.jorm.naming.api.PNameCoder;
037: import org.objectweb.jorm.type.api.PType;
038: import org.objectweb.medor.filter.lib.ExpressionPrinter;
039: import org.objectweb.speedo.api.SpeedoException;
040: import org.objectweb.speedo.api.SpeedoRuntimeException;
041: import org.objectweb.speedo.generation.enhancer.pc.POVariableNames;
042: import org.objectweb.speedo.generation.jorm.JormMIMappingBuilder;
043: import org.objectweb.speedo.generation.lib.NamingRules;
044: import org.objectweb.speedo.mapper.api.JormFactory;
045: import org.objectweb.speedo.metadata.SpeedoClass;
046: import org.objectweb.speedo.metadata.SpeedoField;
047: import org.objectweb.speedo.metadata.SpeedoIdentity;
048: import org.objectweb.speedo.naming.api.MIBuilderHelper;
049: import org.objectweb.speedo.naming.api.NamingManager;
050: import org.objectweb.speedo.naming.api.UserId;
051: import org.objectweb.speedo.naming.api.UserIdFactory;
052: import org.objectweb.util.monolog.api.BasicLevel;
053:
054: /**
055: *
056: * @author S.Chassande-Barrioz
057: */
058: public class UserIdCompositeNamingManager extends NamingManagerHelper
059: implements NamingManager {
060:
061: private final static String COMPOSITE_USER_ID = "cuid";
062:
063: protected String getName() {
064: return COMPOSITE_USER_ID;
065: }
066:
067: // IMPLEMENTATION OF THE METHOD FROM THE NamingManager INTERFACE //
068: //---------------------------------------------------------------//
069: public boolean canManage(SpeedoClass sc) {
070: if (sc.identity.strategy == SpeedoIdentity.USER_ID) {
071: String objectidClass = sc.identity.objectidClass;
072: if (objectidClass == null && sc.generateObjectId()) {
073: objectidClass = NamingRules.generatedObjectIdName(sc
074: .getFQName());
075: }
076: return objectidClass != null;
077: }
078: return false;
079: }
080:
081: public Object encode(PName pn) throws PException {
082: if (pn instanceof UserIdFactory) {
083: return ((UserIdFactory) pn).getNewUserId();
084: }
085: return null;
086: }
087:
088: public PName decode(PNameCoder pnc, Object oid,
089: java.lang.Class clazz, JormFactory jf) throws PException {
090: if (oid instanceof UserId) {
091: //the oid is a UserId
092: if (pnc != null) {
093: //Use the pnc found by the clazz
094: return pnc.decodeAbstract(oid, null);
095: } else if (((UserId) oid).speedoGetPersistentClassName() != null) {
096: //No pnc but the class name is inside the UserId
097: ClassLoader cl = oid.getClass().getClassLoader();
098: if (cl == null) {
099: cl = jf.getClass().getClassLoader();
100: }
101: if (cl == null) {
102: cl = ClassLoader.getSystemClassLoader();
103: }
104: return jf.getPNamingContext(
105: ((UserId) oid).speedoGetPersistentClassName(),
106: cl).decodeAbstract(oid, null);
107: }
108: } else if (pnc != null && (oid instanceof String)
109: && (pnc.getNull() instanceof UserIdFactory)) {
110: //The oid is a String which must be the parameter of the constructor
111: java.lang.Class idclass = ((UserIdFactory) pnc.getNull())
112: .getNewUserId().getClass();
113: Object o = null;
114: try {
115: o = idclass.getConstructor(
116: new java.lang.Class[] { String.class })
117: .newInstance(new Object[] { (String) oid });
118: } catch (Exception e) {
119: throw new SpeedoRuntimeException(
120: "No constructor with a String "
121: + "parameter available on the identifier class: "
122: + idclass.getName());
123: }
124: //recall with the UserId
125: return decode(pnc, o, clazz, jf);
126: }
127:
128: return null;
129: }
130:
131: public boolean canProvidePBinder(Object hints,
132: ClassLoader classLoader) {
133: if (!super .canProvidePBinder(hints, classLoader)) {
134: return false;
135: }
136: String cn = getBinderClassNameFromHints(hints,
137: COMPOSITE_USER_ID);
138: if (cn == null) {
139: return false;
140: }
141: try {
142: classLoader.loadClass(cn);
143: return true;
144: } catch (ClassNotFoundException e) {
145: return false;
146: }
147: }
148:
149: public boolean canProvidePNamingContext(Object hints,
150: ClassLoader classLoader) {
151: if (!super .canProvidePNamingContext(hints, classLoader)) {
152: return false;
153: }
154: String cn = getPNCClassNameFromHints(hints, COMPOSITE_USER_ID);
155: if (cn == null) {
156: return false;
157: }
158: try {
159: classLoader.loadClass(getPNCClassNameFromHints(hints,
160: COMPOSITE_USER_ID));
161: return true;
162: } catch (ClassNotFoundException e) {
163: return false;
164: }
165: }
166:
167: public void defineClassIdentifierNameDef(NameDef nd, Class jc,
168: SpeedoClass sc, ClassMapping cm, MIBuilderHelper mibh,
169: JormMIMappingBuilder mb, Collection createdMOs)
170: throws SpeedoException, PException {
171: boolean debug = logger.isLoggable(BasicLevel.DEBUG);
172: if (debug) {
173: logger.log(BasicLevel.DEBUG,
174: "CompositeUserId: Filling the identifider name def: \n\t class="
175: + sc.getFQName());
176: }
177: SpeedoClass clazzWithIdField = sc.getAncestor();
178: if (clazzWithIdField == null) {
179: clazzWithIdField = sc;
180: }
181: List idFields = clazzWithIdField.getPKFields();
182: String objectidClass = clazzWithIdField.identity.objectidClass;
183: if (objectidClass == null && sc.generateObjectId()) {
184: objectidClass = NamingRules
185: .generatedObjectIdName(clazzWithIdField.getFQName());
186: clazzWithIdField.identity.oidClassAutoCalculated = true;
187: clazzWithIdField.identity.objectidClass = objectidClass;
188: }
189: Manager manager = (Manager) jc.getPackage().getParent();
190: //The user has specified an object id ==> use it for the namedef
191: CompositeName cn = manager.getCompositeName(objectidClass);
192: boolean cnNotDefined = (cn == null);
193: if (cnNotDefined) {
194: if (debug) {
195: logger.log(BasicLevel.DEBUG,
196: "\tCreate the composite name " + objectidClass);
197: }
198: cn = manager.createCompositeName(objectidClass);
199: createdMOs.add(cn);
200: }
201: NameRef nr = nd.createNameRef(cn);
202: for (int i = 0; i < idFields.size(); i++) {
203: SpeedoField pkField = (SpeedoField) idFields.get(i);
204: int size = PType.NOSIZE;
205: int scale = PType.NOSIZE;
206: if (pkField.columns != null && pkField.columns.length == 1) {
207: if (pkField.columns[0].length != -1) {
208: size = pkField.columns[0].length;
209: }
210: if (pkField.columns[0].scale != -1) {
211: scale = pkField.columns[0].scale;
212: }
213: }
214: if (cnNotDefined) {
215: cn.createCompositeNameField(pkField.name, mibh
216: .getPrimitivePType(Type.getType(pkField.type)),
217: size, scale);
218: }
219: nr.addProjection(pkField.name, pkField.name);
220: }
221: }
222:
223: public boolean needInheritanceDiscriminator(SpeedoClass sc)
224: throws SpeedoException {
225: return true;
226: }
227:
228: /**
229: * This internal method defines a NameDef based on on the PK fields of the
230: * Referenced class. This method manages ClassRef owned by a class or by
231: * a generic class. But this method does not mapped the fields (ex:
232: * no rdb mapping)
233: * @param nd is the namedef to fill
234: * @param cr is the JORM meta object representing the reference. This
235: * ClassRef can be owned by a Class or a GenClassRef.
236: * @param sf is the Speedo MetaObject representing the persistent field
237: * linked to this ClassRef. If the owner of the ClassRef is a simple class
238: * then this parameter represents the classRef too. If the owner of the
239: * ClassRef is a generic class, then this parameter represents the reference
240: * to the generic class (Collection, Map, ...).
241: * @param mibh is a helper for the management of the JORM meta info
242: * @param prefix is a prefix for the name of the field composing the
243: * identifier
244: */
245: private void defineClassReferenceNameDef(NameDef nd, ClassRef cr,
246: SpeedoField sf, MIBuilderHelper mibh, String prefix)
247: throws SpeedoException, PException {
248: Manager manager = mibh.getManager(cr);
249: SpeedoClass referencedClass = sf.moClass
250: .getSpeedoClassFromContext(cr.getMOClass().getFQName());
251: SpeedoClass clazzWithIdField = referencedClass.getAncestor();
252: if (clazzWithIdField == null) {
253: clazzWithIdField = referencedClass;
254: }
255: CompositeName cn = manager
256: .getCompositeName(clazzWithIdField.identity.objectidClass);
257: NameRef nr = nd.createNameRef(cn);
258: List idFields = clazzWithIdField.getPKFields();
259: for (int i = 0; i < idFields.size(); i++) {
260: SpeedoField pkField = (SpeedoField) idFields.get(i);
261: int size = PType.NOSIZE;
262: int scale = PType.NOSIZE;
263: if (pkField.columns != null && pkField.columns.length == 1) {
264: if (pkField.columns[0].length != -1) {
265: size = pkField.columns[0].length;
266: }
267: if (pkField.columns[0].scale != -1) {
268: scale = pkField.columns[0].scale;
269: }
270: }
271: // create a hidden field in the class corresponding to this
272: // composite Name field. The name is based on a prefix (ClassRef name)
273: String fieldName = prefix + pkField.name;
274: PType type = mibh.getPrimitivePType(Type
275: .getType(pkField.type));
276: if (logger.isLoggable(BasicLevel.DEBUG)) {
277: logger.log(BasicLevel.DEBUG, "\tField: name="
278: + fieldName + ", type=" + type.getJavaName());
279: }
280: mibh.createNameDefField(cr.getParent(), fieldName, type,
281: size, scale);
282: //define the projection between composite name fields and field used
283: // in NameRef
284: nr.addProjection(pkField.name, fieldName);
285: }
286: }
287:
288: public void defineClassReferenceNameDef(NameDef nd, ClassRef cr,
289: SpeedoField sf, SpeedoClass currentClass, ClassMapping cm,
290: MIBuilderHelper mibh, JormMIMappingBuilder mb)
291: throws SpeedoException, PException {
292: if (logger.isLoggable(BasicLevel.DEBUG)) {
293: logger.log(BasicLevel.DEBUG,
294: "CompositeUserId: Filling the name def of a ClassRef from a class: "
295: + "\n\tField: " + currentClass.getFQName()
296: + "#" + sf.name + "\n\ttarget class="
297: + sf.getClassName());
298: }
299: String prefix = mibh
300: .getNameDefFieldPrefix(cr, false, false, sf);
301: defineClassReferenceNameDef(nd, cr, sf, mibh, prefix);
302: mb.createClassRefNameDefMapping(cm, nd, sf);
303: }
304:
305: public void defineClassReferenceNameDef(NameDef nd, ClassRef cr,
306: SpeedoField sf, SpeedoClass currentClass,
307: GenClassMapping gcm, MIBuilderHelper mibh,
308: JormMIMappingBuilder mb) throws SpeedoException, PException {
309: if (logger.isLoggable(BasicLevel.DEBUG)) {
310: logger.log(BasicLevel.DEBUG,
311: "CompositeUserId: Filling the name def of a ClassRef from a class: "
312: + "\n\tField: " + currentClass.getFQName()
313: + "#" + sf.name + "\n\ttarget class="
314: + sf.getClassName());
315: }
316: String prefix = mibh.getNameDefFieldPrefix(cr, false, true, sf);
317: defineClassReferenceNameDef(nd, cr, sf, mibh, prefix);
318: mb.createClassRefNameDefMapping(gcm, nd, sf);
319: }
320:
321: private void defineGenClassNameDef(NameDef nd, GenClassRef gcr,
322: SpeedoField sf, MIBuilderHelper mibh, boolean isGCId)
323: throws SpeedoException, PException {
324: String prefix = mibh.getNameDefFieldPrefix(gcr, isGCId, isGCId,
325: sf);
326: Manager manager = mibh.getManager(gcr);
327: SpeedoClass clazzWithIdField = sf.moClass.getAncestor();
328: if (clazzWithIdField == null) {
329: clazzWithIdField = sf.moClass;
330: }
331: CompositeName cn = manager
332: .getCompositeName(clazzWithIdField.identity.objectidClass);
333: NameRef nr = nd.createNameRef(cn);
334: List idFields = clazzWithIdField.getPKFields();
335: for (int i = 0; i < idFields.size(); i++) {
336: SpeedoField pkField = (SpeedoField) idFields.get(i);
337: // create a hidden field in the class corresponding to this
338: // composite Name field. The name is based on a prefix (GenClassRef name)
339: String fieldName = prefix + pkField.name;
340: if (logger.isLoggable(BasicLevel.DEBUG)) {
341: logger.log(BasicLevel.DEBUG, "\tField: name="
342: + fieldName);
343: }
344: if (isGCId) {
345: PType type = mibh.getPrimitivePType(Type
346: .getType(pkField.type));
347: int size = PType.NOSIZE;
348: int scale = PType.NOSIZE;
349: if (pkField.columns != null
350: && pkField.columns.length == 1) {
351: if (pkField.columns[0].length != -1) {
352: size = pkField.columns[0].length;
353: }
354: if (pkField.columns[0].scale != -1) {
355: scale = pkField.columns[0].scale;
356: }
357: }
358: mibh.createNameDefField(gcr, fieldName, type, size,
359: scale);
360: }
361: //define the projection between composite name fields and field used
362: // in NameRef
363: nr.addProjection(pkField.name, fieldName);
364: }
365: }
366:
367: public void defineGenClassIdentifierNameDef(NameDef nd,
368: GenClassRef gcr, SpeedoField sf, SpeedoClass currentClass,
369: GenClassMapping gcm, MIBuilderHelper mibh,
370: JormMIMappingBuilder mb) throws SpeedoException, PException {
371: if (logger.isLoggable(BasicLevel.DEBUG)) {
372: logger.log(BasicLevel.DEBUG,
373: "CompositeUserId: Filling the name def identifier of a GenClassRef: "
374: + "\n\tField: " + currentClass.getFQName()
375: + "#" + sf.name);
376: }
377: defineGenClassNameDef(nd, gcr, sf, mibh, true);
378: mb.createGenClassIdentifierNameDefMapping(gcm, nd, sf, mibh);
379: }
380:
381: public void defineGenClassReferenceNameDef(NameDef nd,
382: GenClassRef gcr, SpeedoField sf, SpeedoClass currentClass,
383: ClassMapping cm, MIBuilderHelper mibh,
384: JormMIMappingBuilder mb) throws SpeedoException, PException {
385: if (logger.isLoggable(BasicLevel.DEBUG)) {
386: logger.log(BasicLevel.DEBUG,
387: "CompositeUserId: Filling the name def of a GenClassRef: "
388: + "\n\tField: " + currentClass.getFQName()
389: + "#" + sf.name);
390: }
391: defineGenClassNameDef(nd, gcr, sf, mibh, false);
392: }
393:
394: public String getPNameHints(SpeedoClass sc, NameDef nd) {
395: return "this." + POVariableNames.REFSTATE_FIELD_NAME;
396: }
397:
398: public Object[] getPNameHints2(SpeedoClass sc, NameDef nd) {
399: return new Object[] { PNH_REF_STATE };
400: }
401:
402: public String getGCPNameHints(SpeedoClass sc, NameDef nd) {
403: return "speedoPO.getPName()";
404: }
405:
406: /**
407: * Build a property value compsed such as this pattern
408: * userid,binder_class_name,pnc_class_name,class_name
409: * @param nd
410: * @param targetClass
411: * @param sourceMO
412: * @param key
413: * @param result
414: */
415: public void getJormNamingConfig(NameDef nd,
416: SpeedoClass targetClass, MetaObject sourceMO, String key,
417: Properties result) throws SpeedoException {
418: StringBuffer sb = new StringBuffer();
419: sb.append(COMPOSITE_USER_ID);
420: sb.append(HINTS_SEP);
421: String binderClassName = NamingRules.binderName(nd.getNameRef()
422: .getCompositeName().getFQName());
423: sb.append(binderClassName);
424: sb.append(HINTS_SEP);
425: String className = targetClass.getFQName();
426: SpeedoClass ancestor = targetClass.getAncestor();
427: if (sourceMO instanceof GenClassRef //For a Genclass ref or identifier
428: || (ancestor == null //No inheritance
429: && targetClass.jormclass.getSubClasses().isEmpty())) {
430: sb.append(binderClassName);
431: } else {
432: if (ancestor == null) {
433: ancestor = targetClass;
434: }
435: try {
436: logger.log(BasicLevel.DEBUG, "Class "
437: + targetClass.jormclass.getFQName()
438: + "\n"
439: + " NamedDef "
440: + nd.toString()
441: + "\n"
442: + " Filter "
443: + ExpressionPrinter.e2str(targetClass.jormclass
444: .getInheritanceFilter(nd)));
445: if (targetClass.jormclass.getSubClasses().isEmpty()) {
446: sb.append(binderClassName);
447: } else if (targetClass.jormclass
448: .detectFilterElementNotInPK(
449: targetClass.jormclass
450: .getInheritanceFilter(nd), nd)) {
451: //if has child(ren)
452: //and one of the fields of the filter is not in the primary key,
453: //use a PolymorphicPNC
454: logger.log(BasicLevel.DEBUG,
455: "Composite PName : assign a polymorphic PNC for the class"
456: + targetClass.jormclass.getFQName()
457: + ".");
458: sb.append(POLYMORPHIC_PNC);
459: } else {
460: //use a kfpnc
461: logger.log(BasicLevel.DEBUG,
462: "Composite PName : assign a KFPNC for the class"
463: + targetClass.jormclass.getFQName()
464: + ".");
465: sb.append(NamingRules.kfpncName(ancestor
466: .getFQName()));
467: }
468: } catch (Exception e) {
469: logger.log(BasicLevel.ERROR,
470: "Error while retrieving the inheritance filter of the namedef:"
471: + nd.toString());
472: throw new SpeedoException(
473: "Error while retrieving the inheritance filter of the namedef:"
474: + nd.toString(), e);
475: }
476: className = ancestor.getFQName();
477: }
478: sb.append(HINTS_SEP);
479: sb.append(className);
480: result.setProperty(key, sb.toString());
481: }
482:
483: }
|