001: /**
002: * Copyright (C) 2001-2005 France Telecom R&D
003: */package org.objectweb.speedo.generation.jorm;
004:
005: import org.objectweb.jorm.api.PException;
006: import org.objectweb.jorm.compiler.api.JormCompilerConfigurator;
007: import org.objectweb.jorm.compiler.api.JormCompilerParameter;
008: import org.objectweb.jorm.compiler.lib.JormCompiler;
009: import org.objectweb.jorm.metainfo.api.Class;
010: import org.objectweb.jorm.metainfo.api.ClassProject;
011: import org.objectweb.jorm.metainfo.api.GenClassRef;
012: import org.objectweb.jorm.metainfo.api.Manager;
013: import org.objectweb.jorm.metainfo.api.Mapping;
014: import org.objectweb.jorm.metainfo.api.NameDef;
015: import org.objectweb.jorm.metainfo.api.TypedElement;
016: import org.objectweb.speedo.api.ExceptionHelper;
017: import org.objectweb.speedo.api.SpeedoException;
018: import org.objectweb.speedo.api.SpeedoProperties;
019: import org.objectweb.speedo.generation.api.SpeedoXMLError;
020: import org.objectweb.speedo.generation.lib.AbstractGeneratorComponent;
021: import org.objectweb.speedo.lib.Personality;
022: import org.objectweb.speedo.metadata.SpeedoClass;
023: import org.objectweb.speedo.metadata.SpeedoField;
024: import org.objectweb.speedo.metadata.SpeedoIdentity;
025: import org.objectweb.speedo.metadata.SpeedoXMLDescriptor;
026: import org.objectweb.util.monolog.api.BasicLevel;
027:
028: import java.util.ArrayList;
029: import java.util.Collection;
030: import java.util.Iterator;
031: import java.util.List;
032:
033: /**
034: * Build the JORM meta information
035: *
036: * @author S.Chassande-Barrioz
037: */
038: public class JormMIGenerator extends AbstractGeneratorComponent {
039: public final static String LOGGER_NAME = SpeedoProperties.LOGGER_NAME
040: + ".generation.jorm.migen";
041: /**
042: * Jorm classes intended for JORM generation
043: */
044: protected JormCompiler jormcompiler;
045:
046: public JormMIGenerator(Personality p) {
047: super (p);
048: }
049:
050: /**
051: * Instanciates and configures partialy a JormCompiler required for the
052: * .pd parsing and fetching a configured MIManager
053: */
054: public boolean init() throws SpeedoException {
055: if (scp.getXmldescriptor().isEmpty()) {
056: return false;
057: }
058: logger = scp.loggerFactory.getLogger(LOGGER_NAME);
059: jormcompiler = new JormCompiler();
060: JormCompilerParameter jcp = jormcompiler.getCompilerParameter();
061: JormCompilerConfigurator jcc = jormcompiler
062: .getCompilerConfigurator();
063: try {
064: jcc.configure();
065: jcp.loadConfFile(jcc.getGlobalJormcOptsFile(), jcc
066: .knownMappers());
067: jcc.setLoggerFactory(scp.loggerFactory);
068: int idx = scp.mapperName.indexOf('.');
069: if (idx == -1) {
070: jcc.removeMapper(scp.mapperName);
071: jcc.addSubMapper(scp.mapperName, "generic");
072: } else {
073: String actualmn = scp.mapperName.substring(0, idx);
074: jcc.removeMapper(actualmn);
075: jcc.addSubMapper(actualmn, scp.mapperName
076: .substring(idx + 1));
077: }
078: if (logger.isLoggable(BasicLevel.DEBUG)) {
079: logger.log(BasicLevel.DEBUG, "jormcOpts file:"
080: + jcc.getJormcOptsFile());
081: Iterator it = jcc.knownMappers();
082: while (it.hasNext()) {
083: String mapperName = (String) it.next();
084: logger.log(BasicLevel.DEBUG, mapperName
085: + " sub mappers: "
086: + jcc.getSubMappers(mapperName));
087: }
088: }
089: } catch (PException e) {
090: logger.log(BasicLevel.ERROR,
091: "Impossible to configure Jorm", ExceptionHelper
092: .getNested(e));
093: throw new SpeedoException("Impossible to configure Jorm", e);
094: }
095: scp.generatorsContext.put("jormcompiler", jormcompiler);
096: return true;
097: }
098:
099: public String getTitle() {
100: return "Building Jorm Meta Information...";
101: }
102:
103: public void process() throws SpeedoException {
104: try {
105: process2();
106: } catch (PException e) {
107: throw new SpeedoException("Error during Jorm generation", e);
108: }
109: }
110:
111: /**
112: * Performs the JORM Meta Information building.
113: */
114: public void process2() throws SpeedoException, PException {
115: if (scp.getXmldescriptor().isEmpty()) {
116: return;
117: }
118: // The list of .pd files specified by the user
119: Collection pdfiles = jormcompiler.getCompilerParameter()
120: .getInputFiles();
121: if (logger.isLoggable(BasicLevel.DEBUG)) {
122: for (Iterator it = pdfiles.iterator(); it.hasNext();)
123: logger.log(BasicLevel.DEBUG, "source file: "
124: + it.next());
125: }
126:
127: // The list of SpeedoClass requiring the JMI generation
128: ArrayList notFoundMOs = new ArrayList();
129: for (Iterator itDesc = scp.getXmldescriptor().values()
130: .iterator(); itDesc.hasNext();) {
131: SpeedoXMLDescriptor desc = (SpeedoXMLDescriptor) itDesc
132: .next();
133: List scs = desc.getSpeedoClasses();
134: for (int i = 0; i < scs.size(); i++) {
135: SpeedoClass sc = (SpeedoClass) scs.get(i);
136: String fn = sc.getJormFileName();
137: logger.log(BasicLevel.DEBUG, "looking for the file: "
138: + fn);
139: if (!pdfiles.contains(fn)) {
140: // No .pd file is availlable, add the SpeedoClass into the
141: // list
142: notFoundMOs.add(sc);
143: }
144: }
145: }
146:
147: // if .pd files are not specified by the user then the jorm meta
148: // information is generated
149: jormcompiler.setupLogger();
150: jormcompiler.setupMIManager();
151: if (!notFoundMOs.isEmpty()) {
152: JormMIBuilder jmib = new JormMIBuilder(jormcompiler
153: .getMIManager(), scp.nmf, logger);
154: jmib.createMI(notFoundMOs, scp.projectName, scp.mapperName);
155: }
156:
157: if (pdfiles.size() > 0) {
158: // parse the .pd files ==> Collection(jorm MetaObject)
159: isCompatible();
160: }
161: }
162:
163: /**
164: * Verifies that all persistent capable field for jdo is described in JORM.
165: *
166: * @exception org.objectweb.speedo.generation.api.SpeedoXMLError if JORM an JDO MetaData are not coherent
167: */
168: protected void isCompatible() throws SpeedoException {
169:
170: List except = new ArrayList();
171:
172: Manager manager = jormcompiler.getMIManager();
173: for (Iterator itDesc = scp.getXmldescriptor().values()
174: .iterator(); itDesc.hasNext();) {
175: SpeedoXMLDescriptor desc = (SpeedoXMLDescriptor) itDesc
176: .next();
177: List scs = desc.getSpeedoClasses();
178: for (int i = 0; i < scs.size(); i++) {
179: compareClass((SpeedoClass) scs.get(i), manager, except);
180: }
181: }
182: if (!except.isEmpty() && logger.isLoggable(BasicLevel.ERROR))
183: for (Iterator it = except.iterator(); it.hasNext();)
184: logger.log(BasicLevel.ERROR, it.next());
185: }
186:
187: protected void compareClass(SpeedoClass clas, Manager manager,
188: List except) throws SpeedoException {
189: debug = logger.isLoggable(BasicLevel.DEBUG);
190: if (debug) {
191: logger.log(BasicLevel.DEBUG,
192: "Verify the definition of the class "
193: + clas.getFQName());
194: }
195: Class classJorm = manager.getClass(clas.getFQName());
196: if (classJorm == null) {
197: throw new SpeedoException("Jorm description of the class '"
198: + clas.getFQName() + "' is not availlable");
199: }
200: NameDef pName = null;
201: SpeedoClass sc = clas;
202: while (sc.getSuperClassName() != null) {
203: SpeedoClass scl = sc;
204: sc = sc.moPackage.xmlDescriptor.smi.getSpeedoClass(sc
205: .getSuperClassName(), sc.moPackage);
206: if (sc == null) {
207: throw new SpeedoException("Class " + scl.getFQName()
208: + " not defined in the jorm meta information");
209: }
210: }
211: Class pclassJorm = manager.getClass(sc.getFQName());
212: pName = getClassNameDef(pclassJorm);
213:
214: if (classJorm == null) {
215: throw new SpeedoXMLError("Class '" + clas.name
216: + "' not defined in JORM metadata");
217: }
218:
219: // Comparison from JDO
220: clas.jormclass = classJorm;
221: for (Iterator efield = clas.fields.values().iterator(); efield
222: .hasNext();) {
223: SpeedoField field = (SpeedoField) efield.next();
224: String fieldName = field.name;
225:
226: // Fields with this persistent modifier shouldn't stay in JDO Metadata
227: if (field.persistenceStatus == SpeedoField.NONE)
228: continue;
229:
230: TypedElement tElem = classJorm.getTypedElement(fieldName);
231: if (tElem == null) {
232: throw new SpeedoXMLError(
233: "Field '"
234: + fieldName
235: + "' not defined in JORM metadata of the class '"
236: + clas.getFQName() + "'");
237: }
238:
239: // for application identity key fields have to be compared
240: if (field.primaryKey) {
241: boolean found = false;
242: for (Iterator it = pName.iterateField(); it.hasNext()
243: && !found;) {
244: found = fieldName.equals(it.next());
245: }
246: if (!found) {
247: throw new SpeedoXMLError(
248: "Field '"
249: + fieldName
250: + "' not defined in Class NameDef's Fields of the class '"
251: + clas.getFQName() + "'");
252: }
253: }
254:
255: if (tElem instanceof GenClassRef && field.jdoTuple == null)
256: throw new SpeedoXMLError(
257: "field '"
258: + fieldName
259: + "' should be a tuple in JDO metadata of the class '"
260: + clas.getFQName() + "'");
261: }
262:
263: // Comparison from JORM
264: for (Iterator jormfield = classJorm.getFields().iterator(); jormfield
265: .hasNext();) {
266: TypedElement te = (TypedElement) jormfield.next();
267: String fieldName = te.getName();
268: if (!clas.fields.containsKey(fieldName)
269: && !isContainerIdField(classJorm, te, clas))
270: throw new SpeedoXMLError("Field '" + fieldName
271: + "' of the class '" + clas.getFQName()
272: + "' is not defined in the '"
273: + clas.moPackage.xmlDescriptor.xmlFile
274: + "' file (found: " + clas.fields.keySet()
275: + ").");
276: }
277:
278: // for application identity key fields have to be compared
279: if (clas.getIdentityType() == SpeedoIdentity.USER_ID) {
280: SpeedoClass classWithId = clas;
281: while (classWithId.getSuperClassName() != null) {
282: classWithId = classWithId
283: .getSpeedoClassFromContext(classWithId
284: .getSuperClassName());
285: }
286: boolean found = false;
287: for (Iterator it = pName.iterateField(); it.hasNext()
288: && !found;) {
289: String fn = (String) it.next();
290: SpeedoField sf = (SpeedoField) classWithId.fields
291: .get(fn);
292: if (sf == null) {
293: logger
294: .log(
295: BasicLevel.WARN,
296: "Field "
297: + fn
298: + " defined in the identifier of "
299: + classWithId.name
300: + ".pd file but not availlable in the class (or .pd file).");
301: } else if (!sf.primaryKey) {
302: except
303: .add("Field "
304: + fn
305: + " defined in the "
306: + classWithId.name
307: + ".pd file but is not marked as a primary key field in the "
308: + classWithId.moPackage.xmlDescriptor.xmlFile
309: + " file.");
310: }
311: }
312: }
313: }
314:
315: private boolean isContainerIdField(Class clazz, TypedElement te,
316: SpeedoClass sc) throws SpeedoException {
317: return sc.identity.isDataStore()
318: && getClassNameDef(clazz).getNameRef().getProjection()
319: .containsValue(te.getName());
320: }
321:
322: private Mapping getMapping(Class clazz) throws SpeedoException {
323: ClassProject cp = clazz.getClassProject(scp.projectName);
324: if (cp == null) {
325: throw new SpeedoException(
326: "No classproject found for the class "
327: + clazz.getFQName() + " and the project "
328: + scp.projectName);
329: }
330: int idx = scp.mapperName.indexOf('.');
331: Mapping m = cp.getMapping(idx == -1 ? scp.mapperName
332: : scp.mapperName.substring(0, idx));
333: if (m == null) {
334: throw new SpeedoException("No mapping found for the class "
335: + clazz.getFQName() + ", the project "
336: + scp.projectName + " and the mapper "
337: + scp.mapperName);
338: }
339: return m;
340: }
341:
342: private NameDef getClassNameDef(Class clazz) throws SpeedoException {
343: return (NameDef) getMapping(clazz).getClassMapping()
344: .getIdentifierMapping().getLinkedMO();
345: }
346:
347: }
|